Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,43 @@ Platform configuration

This option may only be set in the global section (``[mypy]``).

.. note::

**Using multiple Python versions in a monorepo**

Mypy currently supports only **one global target Python version** per run.
The configuration option :confval:`python_version` can be set **only in the
global section** of the configuration file. This means that a single
invocation of mypy cannot type-check different parts of a monorepo using
different Python versions.

If your project contains directories or packages that target different
Python versions, you can use one of the following workarounds:

* **Run mypy multiple times**, selecting a different version for each
directory.

Example::

mypy --python-version=3.9 src/py39_package
mypy --python-version=3.11 backend/py311

* **Use separate configuration files**, each specifying its own
``python_version``.

Example::

mypy --config-file=mypy_py39.ini src/py39_package
mypy --config-file=mypy_py311.ini backend/

* **Use an external build/monorepo tool** (such as Pants, Bazel, or a CI
pipeline) to orchestrate multiple mypy invocations automatically.

This documentation update clarifies the current limitation and addresses
:issue:`16944`.

Comment on lines +472 to +474
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this part is necessary.



.. confval:: platform

:type: string
Expand Down
3 changes: 2 additions & 1 deletion mypy/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def current_full_target(self) -> str:
"""Return the current target (may be a class)."""
assert self.module
if self.function:
return self.function.fullname
return self.function.fullname or ""
if self.classes:
return self.classes[-1].fullname
return self.module
Expand All @@ -60,6 +60,7 @@ def module_scope(self, prefix: str) -> Iterator[None]:
self.module = prefix
self.classes = []
self.function = None
self.functions = [] # reset the function stack when entering a new module
self.ignored = 0
yield
assert self.module
Expand Down
18 changes: 18 additions & 0 deletions mypy/test/test_scope_behavior.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and other changes) don't seem related? Did you accidentally include them on this branch?

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from mypy.nodes import FuncDef, SymbolTable, TypeInfo
from mypy.scope import Scope


def test_scope_module_and_function_behavior() -> None:
scope = Scope()
with scope.module_scope("mod1"):
assert scope.current_module_id() == "mod1"
# simulate function
fake_func = FuncDef("f", None, None, None, None)
with scope.function_scope(fake_func):
assert "f" in scope.current_full_target()
# simulate class inside function
fake_class = TypeInfo(SymbolTable(), "C", None)
with scope.class_scope(fake_class):
assert "C" in scope.current_full_target()
# leaving function restores module
assert scope.current_full_target() == "mod1"
17 changes: 17 additions & 0 deletions test-data/unit/issue_scope.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[case testScopeOptionalIntResolution]
from typing import Optional

x: Optional[int] = None
y: Optional[int] = None

def f() -> None:
x = 1
y = 1
class C:
reveal_type(x) # should be int
reveal_type(y) # should be Optional[int]
x = 2

[out]
note: Revealed type is "builtins.int"
note: Revealed type is "Union[builtins.int, None]"
Loading