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

B006: ignore when type hints suggests immutability. #362

Open
randolf-scholz opened this issue Mar 2, 2023 · 4 comments
Open

B006: ignore when type hints suggests immutability. #362

randolf-scholz opened this issue Mar 2, 2023 · 4 comments

Comments

@randolf-scholz
Copy link

randolf-scholz commented Mar 2, 2023

When passing configurations to functions, it is quite annoying to have to do the whole Optional[Mapping[str, Any]] = None dance. It would be nice if it was possible to allow mutable defaults, when the type hints indicate immutability. (possibly via some --strict/--non-strict flag.)

from collections.abc import *

def foo(
    configA: Mapping[str, Any] = {},         # needn't raise B006
    configB: MutableMapping[str, Any] = {},  # should raise B006
    configC: dict[str, Any] = {},            # should raise B006
    seqA: Sequence[str] = [],                # needn't raise B006
    seqB: MutableSequence[str] = [],         # should raise B006
    seqC: list[str] = [],                    # should raise B006
    setA: Set[str] = set(),                  # needn't raise B006
    setB: MutableSet[str] = set(),           # should raise B006
    setB: set[str] = set(),                  # should raise B006
): ...

The reasoning is that the type checker should catch mutable behavior, and the benefit is obviously shorter function bodies that avoid the configA = {} if configA is None else configA boilerplate.

@randolf-scholz
Copy link
Author

Hm, it is more complicated: When the container itself holds mutable objects, things can still go bad:

from collections.abc import Mapping

def function(arg: Mapping[str, list[int]] = {"foo": []}) -> Mapping[str, list[int]]:
    arg["foo"].append(1)
    print(arg)
    return arg

function()
function()

I don't think flake8 has the capabilities to check for immutability in this case as one would need to evaluate the type hints recursively. I.e. the above example would be ok if list[int] were replaced with Sequence[int], then mypy would catch the bug.

@randolf-scholz randolf-scholz closed this as not planned Won't fix, can't repro, duplicate, stale Mar 2, 2023
@stalkerg
Copy link

Can you re-open this? It's still a case from a performance point of view if you really know that your placeholder will be read only.

@randolf-scholz
Copy link
Author

@stalkerg I can reopen it, though personally I have found that like 95% of my needs are satisfied by either

  • Sequence[T] = ()
  • Mapping[K, V] = EMPTY_MAP

Where I use a module level constant EMPTY_MAP: Final[Mapping[K,V]] = types.MappingProxyType({}).
Possibly in the future this can be replaced by frozenmap() if PEP 603 comes to fruition.

@stalkerg
Copy link

@randolf-scholz thanks! It also seems like PEP 603 is promising.

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

2 participants