python / python/mypy

Mypy doesn't recognize relative imports as module names

Open
#10,967 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug topic-runtime-semantics
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Bug Report

Mypy doesn't seem to recognize a relative import as a module-type.

To Reproduce

Given a sample package with the following structure

my_pkg/
├── __init__.py
└── my_module.py

__init__.py:

import types
from typing import List

from .my_module import *

__all__ = []
submodules: List[types.ModuleType] = [my_module]
for submodule in submodules:
    __all__.extend(submodule.__all__)

my_module.py:

__all__ = ["my_var"]

my_var = "hello!"

mypy output:

$ mypy my_pkg/
my_pkg/__init__.py:7: error: Name "my_module" is not defined
my_pkg/__init__.py:9: error: Module has no attribute "__all__"
Found 2 errors in 1 file (checked 2 source files)

Expected Behavior

I expected to see no errors, as the python is valid code.

Your Environment

  • Mypy version used: 0.910
  • Mypy command-line flags: None
  • Mypy configuration options from mypy.ini (and other config files): None
  • Python version used: 3.8.10
  • Operating system and version: Ubuntu 20.04.2

Additional Info
Because the above is an odd pattern, I'd like to explain it.

Imagine I started with an app and a single module, my_module. I'd then use access the module inside the app like so

from my_app import my_module

print(my_module.my_var)

Now, as time goes on, my_module grows increasingly complex, so I decide to split up my_module into a package, my_pkg. Unfortunately, we now have to change our imports in the app:

from my_app.my_pkg import my_module

This isn't desirable, because any code that was using my_module now has to change its imports. To combat this, I name my_pkg the same name as my_module and include the above snippet of code in the __init__.py. Now, to the application, the fact that my_module was split into a package is completely abstracted and the import syntax remains the same:

from my_app import my_pkg

print(my_pkg.my_var)

Note, my_pkg would be have the same name as the original module.

I don't necessarily care that mypy doesn't deal with my above code well, but I do care that the desired behavior is supported by mypy somehow. If there is a better way to do what I've explained, I am all ears.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproducer in my_pkg/init.py and my_pkg/my_module.py, then run mypy my_pkg/ to confirm the reported errors. Trace how the relative import and wildcard import are interpreted, and define done as correctly recognizing the module and its __all__ without errors, or documenting the supported alternative.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.