Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Remove ModuleType.__getattr__ - #6357

Closed
JukkaL wants to merge 1 commit into
python:masterfrom
JukkaL:fix-module-type
Closed

Remove ModuleType.__getattr__#6357
JukkaL wants to merge 1 commit into
python:masterfrom
JukkaL:fix-module-type

Conversation

@JukkaL

@JukkaL JukkaL commented Nov 22, 2021

Copy link
Copy Markdown
Contributor

This caused false negatives for mypy -- mypy would consider that any
module would have any attribute. The method also does not exist at
runtime.

I've also updated builtins.__import__, importlib.__import__, and
importlib.import_module to return Any. I don't have a strong
opinion on this change, but this arguably minimizes the impact of the
removal, and maintains the return types of these functions consistent.

Also, it could be argued that since arbitrary objects can be stuffed
into sys.modules (and I've heard people actually suggest taking
advantage of this), the Any type best reflects this.

There may be other reasonable ways to deal with module objects, but I
think that adding ModuleType.__getattr__ regresses things too much.

This caused false negatives for mypy -- mypy would consider that any
module would have any attribute. The method also does not exist at
runtime.

I've also updated `builtins.__import__`, `importlib.__import__`, and
`importlib.import_module` to return `Any`. I don't have a strong
opinion on this change, but this arguably minimizes the impact of the
removal, and maintains the return types of these functions consistent.

Also, it could be argued that since arbitrary objects can be stuffed
into `sys.modules` (and I've heard people actually suggest taking
advantage of this), the `Any` type best reflects this.

There may be other reasonable ways to deal with module objects, but I
think that adding `ModuleType.__getattr__` regresses things too much.
@github-actions

Copy link
Copy Markdown
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

pylint (https://github.com/pycqa/pylint.git)
- pylint/checkers/utils.py:326: error: unused "type: ignore" comment
- pylint/checkers/utils.py:326: error: Module has no attribute "__iter__" (not iterable)  [attr-defined]

isort (https://github.com/pycqa/isort.git)
- isort/_future/__init__.py:9: error: unused "type: ignore" comment
- isort/_future/__init__.py:10: error: unused "type: ignore" comment
- isort/output.py:504: error: unused "type: ignore" comment
- isort/output.py:516: error: unused "type: ignore" comment
- isort/output.py:523: error: unused "type: ignore" comment

pip (https://github.com/pypa/pip.git)
- src/pip/_internal/locations/__init__.py:58: error: unused "type: ignore" comment
- src/pip/_internal/network/session.py:106: error: unused "type: ignore" comment

sphinx (https://github.com/sphinx-doc/sphinx.git)
- sphinx/util/typing.py:228: error: unused "type: ignore" comment
- sphinx/util/typing.py:428: error: unused "type: ignore" comment
- sphinx/util/inspect.py:433: error: unused "type: ignore" comment
- sphinx/util/inspect.py:436: error: unused "type: ignore" comment
- sphinx/util/inspect.py:439: error: unused "type: ignore" comment
- sphinx/util/docutils.py:52: error: unused "type: ignore" comment
- sphinx/util/docutils.py:53: error: unused "type: ignore" comment
- sphinx/util/docutils.py:67: error: unused "type: ignore" comment
- sphinx/util/docutils.py:81: error: unused "type: ignore" comment
- sphinx/util/docutils.py:95: error: unused "type: ignore" comment
- sphinx/util/docutils.py:110: error: unused "type: ignore" comment
- sphinx/domains/python.py:1452: error: unused "type: ignore" comment
- sphinx/writers/manpage.py:110: error: unused "type: ignore" comment
- sphinx/testing/util.py:126: error: unused "type: ignore" comment
- sphinx/testing/util.py:127: error: unused "type: ignore" comment
+ sphinx/ext/napoleon/__init__.py:467: error: unused "type: ignore" comment
- sphinx/util/compat.py:29: error: unused "type: ignore" comment

graphql-core (https://github.com/graphql-python/graphql-core.git)
+ tests/pyutils/test_inspect.py:24: error: unused "type: ignore" comment
+ tests/pyutils/test_inspect.py:28: error: unused "type: ignore" comment
+ tests/pyutils/test_inspect.py:33: error: unused "type: ignore" comment
+ tests/pyutils/test_inspect.py:37: error: unused "type: ignore" comment
+ tests/pyutils/test_inspect.py:42: error: unused "type: ignore" comment
+ tests/pyutils/test_inspect.py:46: error: unused "type: ignore" comment

kornia (https://github.com/kornia/kornia.git)
+ kornia/testing/__init__.py:16: error: Module has no attribute "util"  [attr-defined]

python-chess (https://github.com/niklasf/python-chess.git)
- chess/engine.py:122: error: unused "type: ignore" comment
- chess/engine.py:123: error: unused "type: ignore" comment
- chess/engine.py:1209: error: unused "type: ignore" comment

core (https://github.com/home-assistant/core.git)
- homeassistant/components/http/forwarded.py:91: error: unused "type: ignore" comment
- homeassistant/auth/mfa_modules/__init__.py:136: error: unused "type: ignore" comment
- homeassistant/auth/providers/__init__.py:145: error: unused "type: ignore" comment
- homeassistant/config.py:648: error: unused "type: ignore" comment
- homeassistant/config.py:651: error: unused "type: ignore" comment
- homeassistant/config.py:662: error: unused "type: ignore" comment
- homeassistant/config.py:672: error: unused "type: ignore" comment
- homeassistant/config.py:673: error: unused "type: ignore" comment
- homeassistant/config.py:753: error: unused "type: ignore" comment
- homeassistant/config.py:895: error: unused "type: ignore" comment
- homeassistant/setup.py:241: error: unused "type: ignore" comment
- homeassistant/setup.py:246: error: unused "type: ignore" comment
- homeassistant/helpers/check_config.py:161: error: unused "type: ignore" comment
- homeassistant/config_entries.py:310: error: unused "type: ignore" comment
- homeassistant/config_entries.py:449: error: unused "type: ignore" comment
- homeassistant/config_entries.py:488: error: unused "type: ignore" comment
- homeassistant/config_entries.py:525: error: unused "type: ignore" comment
- homeassistant/helpers/condition.py:929: error: unused "type: ignore" comment
- homeassistant/helpers/condition.py:977: error: unused "type: ignore" comment
- homeassistant/helpers/script.py:260: error: unused "type: ignore" comment
- homeassistant/helpers/script.py:262: error: unused "type: ignore" comment
- homeassistant/helpers/script.py:269: error: unused "type: ignore" comment
- homeassistant/helpers/reload.py:81: error: unused "type: ignore" comment
- homeassistant/helpers/reload.py:82: error: unused "type: ignore" comment
- homeassistant/components/device_tracker/legacy.py:241: error: unused "type: ignore" comment
- homeassistant/components/device_tracker/legacy.py:246: error: unused "type: ignore" comment
- homeassistant/components/device_tracker/legacy.py:251: error: unused "type: ignore" comment
- homeassistant/components/device_tracker/legacy.py:256: error: unused "type: ignore" comment
- homeassistant/components/notify/legacy.py:61: error: unused "type: ignore" comment
- homeassistant/components/notify/legacy.py:66: error: unused "type: ignore" comment

streamlit (https://github.com/streamlit/streamlit.git)
- lib/streamlit/script_runner.py:432: error: unused "type: ignore" comment
- lib/streamlit/script_runner.py:439: error: unused "type: ignore" comment

aiohttp (https://github.com/aio-libs/aiohttp.git)
- aiohttp/connector.py:1306: error: unused "type: ignore" comment
- aiohttp/web_runner.py:181: error: unused "type: ignore" comment
- aiohttp/pytest_plugin.py:244: error: unused "type: ignore" comment

edgedb (https://github.com/edgedb/edgedb.git)
- edb/server/pgconnparams.py:75: error: unused "type: ignore" comment

werkzeug (https://github.com/pallets/werkzeug.git)
- src/werkzeug/_reloader.py:20: error: unused "type: ignore" comment
+ tests/test_wrappers.py:856: error: Function is missing a return type annotation

@AlexWaygood

Copy link
Copy Markdown
Member

(As the person who introduced this change), I don't have a strong opinion on what the return type of builtins.__import__, importlib.__import__, and
importlib.import_module should be, as long as they remain consistent 🙂

@JelleZijlstra

Copy link
Copy Markdown
Member

Could mypy instead be changed so that if an object is a specific, known module, it ignores the __getattr__? I feel like that would still give a better overall system than returning Any from all the import_module-like functions.

@AlexWaygood

Copy link
Copy Markdown
Member

A slightly more "out there" suggestion, but —something else I was wondering about a few weeks ago, when we discussed this last, was whether type-checkers could be special-cased to recognise that the return type of __import__("collections") (for example) will be, well, the literal collections module. There doesn't seem to be that much difference between the following two snippets in terms of the information available to mypy, but the inferred type is obviously quite different, and it doesn't seem to me like something that's solveable in the stubs:

(1)

import collections as c
reveal_type(c.deque())  # Revealed type is "collections.deque[<nothing>]"

(2)

c = __import__("collections")
reveal_type(c.deque())  # Revealed type is "Any"

But I appreciate that this probably isn't the right place to discuss the feasibility of that idea.

@JelleZijlstra

Copy link
Copy Markdown
Member

I imagine most cases where people call these functions the argument is going to be dynamic.

@AlexWaygood

AlexWaygood commented Nov 22, 2021

Copy link
Copy Markdown
Member

I imagine most cases where people call these functions the argument is going to be dynamic.

No, you're right. I thought I remembered there being more instances in the diff here where people were just __import__ as a one-liner way to import a module and immediately access an object from the module. But it seems I misremembered — so, that idea of mine obviously shouldn't be a priority.

@JukkaL

JukkaL commented Nov 22, 2021

Copy link
Copy Markdown
Contributor Author

Could mypy instead be changed so that if an object is a specific, known module, it ignores the __getattr__?

I'll have a look. If this is straightforward to implement, I'll abandon this PR.

JukkaL added a commit to python/mypy that referenced this pull request Nov 23, 2021
python/typeshd#6302 added `__getattr__`, but we don't want to always
use it, as it can result in undefined references to module attributes
being undetected.

This is an alternative to python/typeshed#6357.

Tested manually with a recent typeshed.
JukkaL added a commit to python/mypy that referenced this pull request Nov 23, 2021
python/typeshd#6302 added `__getattr__`, but we don't want to always
use it, as it can result in undefined references to module attributes
being undetected.

This is an alternative to python/typeshed#6357.

Tested manually with a recent typeshed.
@JukkaL

JukkaL commented Nov 23, 2021

Copy link
Copy Markdown
Contributor Author

The issue was actually very simple to work around in mypy, so this PR is no longer needed (python/mypy#11597).

@JukkaL JukkaL closed this Nov 23, 2021
@JukkaL
JukkaL deleted the fix-module-type branch November 23, 2021 11:33
tushar-deepsource pushed a commit to DeepSourceCorp/mypy that referenced this pull request Jan 20, 2022
)

python/typeshd#6302 added `__getattr__`, but we don't want to always
use it, as it can result in undefined references to module attributes
being undetected.

This is an alternative to python/typeshed#6357.

Tested manually with a recent typeshed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants