Message292111
Expanding on Serhiy's answer: the ModuleNotFoundError for "import sys.path" comes from IMPORT_NAME, not from any of the subsequent attribute lookups.
That difference is visible in the bytecode:
>>> dis("import sys.path as path")
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (None)
6 IMPORT_NAME 0 (sys.path)
9 LOAD_ATTR 1 (path)
12 STORE_NAME 1 (path)
15 LOAD_CONST 1 (None)
18 RETURN_VALUE
For "import sys.path as path", the given module name is "sys.path", and the "from list" entry on the stack is None. This fails before it even reaches the `LOAD_ATTR` line, since "sys.path" isn't an importable module. Changing LOAD_ATTR to IMPORT_FROM would thus have no effect on its behaviour.
>>> dis("from sys import path")
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (('path',))
6 IMPORT_NAME 0 (sys)
9 IMPORT_FROM 1 (path)
12 STORE_NAME 1 (path)
15 POP_TOP
16 LOAD_CONST 2 (None)
19 RETURN_VALUE
For "from sys import path", the given module name is "sys", and the "from list" entry on the stack is a tuple containing the string "path". This works, since "sys" is importable *and* it has a "path" attribute.
Hence why Serhiy's suggestion is such an elegant fix, since the only cases where the LOAD_ATTR vs IMPORT_FROM distinction matters will be those where:
1. The submodule exists, so both "import a.b" and "from a import b" will work for the IMPORT_NAME step
2. It's a circular import, so even though "a.b" exists in sys.modules, it won't be accessible as an attribute of "a" yet
Getting the tests and any related documentation updates right will actually be harder than the code change. |
|
Date |
User |
Action |
Args |
2017-04-22 07:52:42 | ncoghlan | set | recipients:
+ ncoghlan, barry, brett.cannon, THRlWiTi, eric.snow, serhiy.storchaka, Victor.Varvariuc, Pavol Lisy |
2017-04-22 07:52:42 | ncoghlan | set | messageid: <1492847562.87.0.468112521566.issue30024@psf.upfronthosting.co.za> |
2017-04-22 07:52:42 | ncoghlan | link | issue30024 messages |
2017-04-22 07:52:42 | ncoghlan | create | |
|