Skip to content

openpyxl - missing subpackages when importing main module #14246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Andrej730 opened this issue Jun 9, 2025 · 4 comments
Closed

openpyxl - missing subpackages when importing main module #14246

Andrej730 opened this issue Jun 9, 2025 · 4 comments

Comments

@Andrej730
Copy link
Contributor

Andrej730 commented Jun 9, 2025

Consider the snippet below - it shows typing errors, though works fine on runtime.

Related file - https://github.com/python/typeshed/blob/main/stubs/openpyxl/openpyxl/__init__.pyi

import openpyxl

# "cell" is not a known attribute of module "openpyxl"
print(openpyxl.cell)
# "utils" is not a known attribute of module "openpyxl"
print(openpyxl.utils)
@Avasam
Copy link
Collaborator

Avasam commented Jun 10, 2025

Runtime doesn't do anything special either: https://foss.heptapod.net/openpyxl/openpyxl/-/blob/branch/default/openpyxl/__init__.py?ref_type=heads

I don't think this is a stub issue, but rather type-checkers not exposing implicit submodule access ? (I remember this being a thing, but can't find a reference off the top of my head)

import openpyxl.cell
import openpyxl.utils

print(openpyxl.cell)
print(openpyxl.utils)

@AlexWaygood
Copy link
Member

There's nothing typeshed can do here. In general, submodules aren't automatically available just because you've imported the top-level module:

Python 3.13.1 (main, Jan  3 2025, 12:04:03) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import importlib
>>> importlib.resources
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    importlib.resources
AttributeError: module 'importlib' has no attribute 'resources'

But they are cached as an attribute on their parent module as soon as they are imported anywhere:

>>> import importlib
>>> importlib.resources
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    importlib.resources
AttributeError: module 'importlib' has no attribute 'resources'
>>> import importlib.resources
>>> importlib.resources
<module 'importlib.resources' from '/Users/alexw/.pyenv/versions/3.13.1/lib/python3.13/importlib/resources/__init__.py'>

Some module deep down in openpyxl somewhere is importing openpyxl.cell, which is (as a side effect of that import) causing the openpyxl.cell submodule to be cached as an attribute on the top-level openpyxl module. All this happens as an implicit side effect of one of these imports happening here: https://foss.heptapod.net/openpyxl/openpyxl/-/blob/branch/default/openpyxl/__init__.py?ref_type=heads#L5-10.

Whether or not a type checker chooses to model this implicit side effect of some submodule imports is up to the type checker in question. I think mypy just assumes that all submodules are always available on the parent module, which avoids false positives at the cost of lots of false negatives. Ty currently assumes that submodules are never available on the parent module unless they've been explicitly imported in a given scope, but we plan on partially changing that.

@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Jun 10, 2025
@brianschubert
Copy link
Contributor

brianschubert commented Jun 10, 2025

I think mypy just assumes that all submodules are always available on the parent module, which avoids false positives at the cost of lots of false negatives.

In a way, mypy does model submodule import side effects, in so far as it only considers a submodule to be available if it got analyzed, which means it needs to have been either directly requested or found by following an import. For local code where mypy analyzes everything, that makes all submodules appear available, but for installed code found via following imports, mypy gets a little closer to reality. But only little, since it still follows stub file / if TYPE_CHECKING imports, which often touch many more modules than actually get imported at runtime. There's been some issues on the mypy tracker about this in the past, e.g. python/mypy#18153.

@Andrej730
Copy link
Contributor Author

Sorry, I've completely overlooked that those attributes are coming from implicit imports - I've seen uses of openpyxl.utils in a bunch of code and assumed it was explicitly imported in __init__.py. Totally agree it's not a stub problem and I actually like that type checkers typically do not precisely model implicit imports emphasizing on how fragile they can be.

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

No branches or pull requests

4 participants