Opened 7 years ago
Last modified 7 years ago
#28241 closed Bug
module_has_submodule behavior in Python 3 — at Initial Version
Reported by: | tkhyn | Owned by: | nobody |
---|---|---|---|
Component: | Utilities | Version: | 1.11 |
Severity: | Normal | Keywords: | module_loading python3 |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Hello,
Porting a django project from python 2.7 to 3.6, I noticed an issue with utils.module_loading.module_has_submodule
. At some stage my project makes use of
autodiscover_modules('module.submodule')
to try and discover modules that are nested in my app.
I'm using django 1.11.1, but this bug probably also affects 1.8 as the code of module_has_submodule
is the same.
So here we go, with python 2.7 we have the expected behavior (taking contenttypes as an example app):
python2.7 >>> from django.utils.module_loading import module_has_submodule >>> from django.contrib import contenttypes >>> module_has_submodule('invalid_module.submodule') False >>> module_has_submodule('checks') True >>> module_has_submodule('checks.submodule') False
But, with python 3.6
python3.6 >>> from django.utils.module_loading import module_has_submodule >>> from django.contrib import contenttypes >>> module_has_submodule('invalid_module.submodule') File "<console>", line 1, in <module> File "d:\dev\.env\buildout\eggs\django-1.11.1-py3.6.egg\django\utils\module_loading.py", line 79, in module_has_submodule return importlib_find(full_module_name, package_path) is not None File "D:\dev\.env\venv\buildout\lib\importlib\util.py", line 88, in find_spec parent = __import__(parent_name, fromlist=['__path__']) ModuleNotFoundError: No module named 'django.contrib.contenttypes.invalid_module' >>> module_has_submodule('checks') True >>> module_has_submodule('checks.submodule') File "<console>", line 1, in <module> File "d:\dev\.env\buildout\eggs\django-1.11.1-py3.6.egg\django\utils\module_loading.py", line 79, in module_has_submodule return importlib_find(full_module_name, package_path) is not None File "D:\dev\.env\venv\buildout\lib\importlib\util.py", line 89, in find_spec return _find_spec(fullname, parent.__path__) AttributeError: module 'django.contrib.contenttypes.checks' has no attribute '__path__'
From the replies I got on the python bug tracker (http://bugs.python.org/issue30436) the AttributeError
will be converted to ModuleNotFoundError
only in Python 3.7, but that behavior is apparently not expected to be fixed in previous versions.
We'll definitely need to catch ModuleNotFoundError
, and to have a proper fix for python < 3.7 we'll need to:
- either catch
AttributeError
as well. The problem I see isAttributeError
is too broad and may result in 'false catches'
- or convert a dotted path to [package, name] (basically do what
find_spec
actually does) but detect if the module has a
__path__
attribute before callingfind_spec
so that it can not raise exceptions
What are your thoughts ?