This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author ncoghlan
Recipients Pavol Lisy, THRlWiTi, Victor.Varvariuc, barry, brett.cannon, eric.snow, ncoghlan, serhiy.storchaka
Date 2017-04-22.07:52:42
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1492847562.87.0.468112521566.issue30024@psf.upfronthosting.co.za>
In-reply-to
Content
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.
History
Date User Action Args
2017-04-22 07:52:42ncoghlansetrecipients: + ncoghlan, barry, brett.cannon, THRlWiTi, eric.snow, serhiy.storchaka, Victor.Varvariuc, Pavol Lisy
2017-04-22 07:52:42ncoghlansetmessageid: <1492847562.87.0.468112521566.issue30024@psf.upfronthosting.co.za>
2017-04-22 07:52:42ncoghlanlinkissue30024 messages
2017-04-22 07:52:42ncoghlancreate