Skip to content
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

bug: strict = true is incompatible with per-module configuration #11401

Open
adriangb opened this issue Oct 28, 2021 · 8 comments
Open

bug: strict = true is incompatible with per-module configuration #11401

adriangb opened this issue Oct 28, 2021 · 8 comments
Labels
bug mypy got something wrong topic-configuration Configuration files and flags

Comments

@adriangb
Copy link
Contributor

adriangb commented Oct 28, 2021

To Reproduce

Create the following file structure:

my_module/__init__.py
tests/__init__.py
mypy.ini

Both my_module/__init__.py and tests/__init__.py contain:

def untyped():
    ...

Which should trigger an error when run with strict but otherwise pass.

In mypy.ini:

[mypy]
strict = true
[mypy-tests.*]
strict = false

That is, I want strict mode in my source code but not my tests.

Then I run this using mypy .

Expected Behavior

I expect to get an error for my source code but not my tests:

my_module/__init__.py:1: error: Function is missing a return type annotation
my_module/__init__.py:1: note: Use "-> None" if function does not return a value

Actual Behavior

I get an error for both my source code and tests.
It seems like strict = False in the per module section is ignored.

tests/__init__.py:1: error: Function is missing a return type annotation
tests/__init__.py:1: note: Use "-> None" if function does not return a value
my_module/__init__.py:1: error: Function is missing a return type annotation
my_module/__init__.py:1: note: Use "-> None" if function does not return a value

If I add an explicit allow_untyped_defs = True to the mypy-tests.* section:

[mypy]
strict = true
[mypy-tests.*]
strict = false
allow_untyped_defs = True

That seems to be processed fine (I now get no errors for my tests but still get errors for my source).
So I believe the config file is valid, mypy is picking up that the options only apply to tests.*.

I also tried flipping the enable/disable:

[mypy]
strict = false
[mypy-my_module.*]
strict = true

But I get the same result.

This also seems to be the case with pyproject.toml configs.

@adriangb adriangb added the bug mypy got something wrong label Oct 28, 2021
@adriangb adriangb changed the title strict is incompatible with per-module configuration bug: strict = true is incompatible with per-module configuration Oct 28, 2021
@alicederyn
Copy link

I tried inserting all the flags that mypy --help suggested would be turned on by strict by hand, and found that warn_redundant_casts and warn_unused_configs are global, which may be the source of the issue.

Possible solutions:

  • update the documentation to specify that strict is a global-only option
  • change the behaviour of strict when placed in a per-module configuration block
  • extend those two flags so they can be placed in a per-module configuration block

I have absolutely no idea how hard either of those last two options might be, so updating the docs seems like a good option.

@JelleZijlstra JelleZijlstra added the topic-configuration Configuration files and flags label Mar 21, 2022
@sshishov
Copy link

Same here. We tried to move slowly to strict = true mode per module which has been "migrated" but cannot do it due to this limitation

@cal-pratt
Copy link

Any update on this? Was also hoping to use this strategy to onboard a larger project with proper type hinting.

@DylanLukes
Copy link

This also presents an issue when type-checking tests where looser type checking might be desirable on account of dependencies lacking types... For example, those which make use of decorators (e.g. @pytest.fixture):

tests/conftest.py:36: error: Untyped decorator makes function "my_fixture" untyped [misc]

[[tool.mypy.overrides]]
module = ["tests.*"]
strict = false

Throwing this into consideration, although this isn't a blocking issue for me personally as I can just be (somewhat) more specific (e.g. disable_error_code = ["misc"]).

@cal-pratt
Copy link

Throwing this into consideration, although this isn't a blocking issue for me personally as I can just be (somewhat) more specific (e.g. disable_error_code = ["misc"]).

That's what I ended up having to do for my main application packages I haven't gotten around to yet. The namespace package is configured to be strict=True and then there are dozen sub-packages where I have disable_error_code listing about 9 or so error codes... 🤷

@vbraun
Copy link

vbraun commented Aug 2, 2023

The workaround for the "slowly migrating untyped code" use case is to expand the --strict options and apply them per-module, with the exception of the two that must be global:

[mypy]

# must be global, likely pass when migrating untyped code
warn_unused_configs = True
warn_redundant_casts = True

[mypy-app.foo.*,app.bar.*]
# Turn on strict type checking for select modules
#
# The intention is to migrate all modules over time; Add modules to this section as you fix them.
# 
# These are all "mypy --strict" options listed in
# https://mypy.readthedocs.io/en/stable/existing_code.html#introduce-stricter-options
# with the exception of warn_redundant_casts and warn_unused_configs,
# which are global

# Start off with these
# warn_unused_configs = True <-- can only be set globally
# warn_redundant_casts = True <-- can only be set globally
warn_unused_ignores = True

# Getting these passing should be easy
strict_equality = True
strict_concatenate = True

# Strongly recommend enabling this one as soon as you can
check_untyped_defs = True

# These shouldn't be too much additional work, but may be tricky to
# get passing if you use a lot of untyped libraries
disallow_subclassing_any = True
disallow_untyped_decorators = True
disallow_any_generics = True

# These next few are various gradations of forcing use of type annotations
disallow_untyped_calls = True
disallow_incomplete_defs = True
disallow_untyped_defs = True

# This one isn't too hard to get passing, but return on investment is lower
no_implicit_reexport = True

# This one can be tricky to get passing if you use a lot of untyped libraries
warn_return_any = True

This is strict in app.foo, app.bar and not strict in the rest of app.

@sshishov
Copy link

sshishov commented Nov 7, 2023

Hello guys,

It has been 3 years ago since this issue was opened and for the maintainers who understand the code... is it really so difficult to fix this issue and not frustrate people? Because of this issue, the proper adoption and DRY solution for the code is impossible.

Either you duplicate all strict parameters like @vbraun suggested (and fingers crossed that they will not be updated, though it is stated in the docs that it is mutable without any notification).
Or you should not adopt mypy at all as a lot of packages just do not have types, or not strict and we are using these third party libraries everywhere in our code.

How to handle this situation? Probably we will go with solution provided by @vbraun , but it is not DRY and error prone in case the set of strict parameters will be updated.

Best regards,
Sergei

@max-sixty
Copy link

It has been 3 years ago since this issue was opened and for the maintainers who understand the code... is it really so difficult to fix this issue and not frustrate people? Because of this issue, the proper adoption and DRY solution for the code is impossible.

Is there a PR?

If PRs are being ignored, then it's arguably worth pestering.

But there's no duty for anyone to add the features you want — "you've had three years to do the work I asked for" is not helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-configuration Configuration files and flags
Projects
None yet
Development

No branches or pull requests

8 participants