Protocol
with nominal typing. I want to be able to say that, for example,T
is a <something>, but it also has a specific structure. Here's a gist with an example of what I mean. https://gist.github.com/tomplex/9b63c39649ddebdfb1f05991a3199d22
ignore_missing_imports
to the config file so that some of the errors can be suppressed?
from typing import Any, List
def foo(x: List[Any]):
pass
foo(x=list(range(3)) + list("abc"))
sscce.py:8: error: Argument 1 to "list" has incompatible type "str"; expected "Iterable[int]"
sscce.py:8: note: Following member(s) of "str" have conflicts:
sscce.py:8: note: Expected:
sscce.py:8: note: def __iter__(self) -> Iterator[int]
sscce.py:8: note: Got:
sscce.py:8: note: def __iter__(self) -> Iterator[str]
Found 1 error in 1 file (checked 1 source file)
How do I fix this?
itertools.chain
🤔
not sure if it can be called a bug, it is technically right in that you can't add list[int] and list[str]
OTOH the type inference could be more magical and realize that you want list[Any] in the end so mypy could allow it
you could also cast the values to list[Any], foo(x=cast(list[Any], list(range(3))) + cast(list[Any], list("abc")))
so that mypy doesn't try to infer the list[str] and list[int], but that is uglier
?
?
it is technically right in that you can't add list[int] and list[str]
?
... has incompatible type "Dict[str, Tuple[str, Iterable[Sequence[object]], str]]"; expected "Optional[Union[Mapping[str, Union[SupportsRead[Union[str, bytes]], str, bytes]], Mapping[str, Tuple[Optional[str], Union[SupportsRead[Union[str, bytes]], str, bytes]]], Mapping[str, Tuple[Optional[str], Union[SupportsRead[Union[str, bytes]], str, bytes], str]], Mapping[str, Tuple[Optional[str], Union[SupportsRead[Union[str, bytes]], str, bytes], str, MutableMapping[str, str]]]]]"
To me this seems compatible. Is this a bug?
Success: no issues found in 1 source file
Is there some way to represent a tuple, which has, say, two int
s and maybe something else following? I.e. I have code:
BAD_LIST = [
(1, 2, 'I am bad'),
(4, 5),
]
Mypy tells me this is list[tuple[object, ...]]
, so if I went on to processing it:
PROCESS_BAD = [(x[1], range(x[0]), ['something' for _ in range(x[1])])
for x in BAD_LIST]
Mypy complains about me using object
as an argument to range
.
BAD_LIST: list[tuple[int, int, object] | tuple[int,int]] = [...]
, but for more complex types of data this is does not scale. (Of course, mypy could be silenced…)
Hey all, I have a code base that uses mypy and it's great. We use a bunch of enum.Enum
s too, and they're also great.
We have a bunch of places that need to map each member of an enum to some other value (e.g. a descriptive bit of text). Some approaches:
MyEnum.X.fact
: this doesn't scale (multiple mappings leads to a huge enum definition), doesn't work for enums in external packages, and leads to poor code architecture (e.g. putting values for human facing display into a "plain old data" enum's definition).facts: dict[MyEnum, str] = {MyEnum.X: "foo"}
: it's easy for that to get out of sync, where a member is added to the enum but not the dictionaries (e.g. maybe there's a MyEnum.Y
too). (Dynamic check or test for exhaustiveness can work, but isn't quite as nice.)def fact(val: MyEnum) -> str
containing if val is MyEnum.X: return "foo"
elif val is MyEnum.Y: ...
with a else: _: NoReturn = val
'type assert' at the end: really verbose. Is there a way to make 2 work better, by annotating it to be total (has an element for every key)? That is, type hint for a dict with enum or Literal
keys that is total?
This is something like TypeScript's Record
, or generalising TypedDict
to use str
keys. (I've also asked this last week at https://stackoverflow.com/q/72022403/1256624 with additional explanation/code, and internet points for the best answer :) )
TypedDict
as I expect? https://mypy-play.net/?mypy=latest&python=3.10&gist=bb4f4cbc03a8ccd1aac5c0a1c5e1d83b
'foo'
to be the deduced return type, not object
.
This program typechecks:
from typing import TypedDict
class A(TypedDict, total=False):
foo: str
class B(TypedDict, total=False):
foo: str
bar: str
def f(a: A, b: B):
a.update(b)
a: A = {}
b: B = {'foo': 'a', 'bar': 'b'}
f(a, b)
print(a)
It outputs {'foo': 'a', 'bar' : 'b'}
. I recon this is a bug.
Hi, I work on a large monolithic Python codebase at a corporation. I’m looking for advice on improving our mypy performance. Our codebase has many packages (with interdependencies)—some portions are typed. Like Dropbox, we have tangling issues, with large SCCs (strongly connected components) of >100 modules.
I’ve tried out remote caching and dmypy (great for dev iteration loop), as suggested in “Our journey to type checking 4 million lines of Python” —both have helped, thank you! However, mypy still processes a large amount of “unused” code. In general, we would like mypy to gather as much type information as possible from external dependencies (e.g. another package), but only perform “expensive” analysis internally. Though I understand that isn’t always possible with Python.
I’ve gathered some profiles of mypy runs—with py-spy and a custom profiling harness (with mypyc disabled). About 70% of runtime is spent in mypy.build.process_stale_scc
, 20% in mypy.build.process_fresh_modules
, and <10% in mypy.build.State.__init__
. Most of process_stale_scc
’s runtime is spent processing large SCCs. I’ve also noticed that even with a “remote cache” provided, process_stale_scc
can be called on an unchanged SCC. Can an unchanged SCC with cached data be stale? Or perhaps there is a caching configuration issue?
I appreciate all the performance work y’all have done so far! And don’t necessarily expect mypy to perform well in this use case—“untangling” and dependency management are the long term fixes. That said, do y’all have additional recommendations for improving performance? Could we configure mypy to only gather basic type information from external dependencies?
I'm trying to subclass io.TextIOBase
. Consider the following minimal example:
from io import TextIOBase
from typing import Optional
class MyTextIOBase(TextIOBase):
def readline(self, n:Optional[int]=-1) -> str:
return "foo\n"
def read(self, size:Optional[int]=1) -> str:
return "foo"
MyPy gives the following error for line 5: 'Return type "str" of "readline" incompatible with return type "bytes" in supertype "IOBase"'.
The return type of readline()
in IOBase
is indeed bytes
but I'm subclassing TextIOBase
where the return type of readline()
is str
. Why is MyPy looking at IOBase
? Moreover, for read()
no error is given, while this has the same return type.
I have a problem where mypy
does not detect a typing issue in our code. Trying to simplyfy the example here:
def set_score(self, score: float) -> None:
self._score_update_time = time.time()
self._score = score
def init_data(self) -> None:
self.set_score(self.get_data('score'))
def get_data(self, key: str) -> str | dict | None:
return ....
My IDE Pycharm warns me with Expected type 'float', got 'str | dict | None' instead
, which is what I would assume.
mypy
stays silent and does not catch that potential bug.
[mypy]
warn_return_any = True
warn_unused_configs = True
strict = True
ignore_missing_imports = True
pretty = False
check_untyped_defs =
What am I missing here?
I am still struggling to make this work as expected. This is a semi large codebase with about 10 modules in the src-root. Each of them containing sub modules with sub-sub modules etc.
My goal is to just type check everything because the plan is to add type annotations throughout the whole code. Now it looks like different ways of calling mypy
giving me different outputs.
For example:
One module is called operations
containing a monitor_operation.py
(besides others).
Calling mypy -p operations
returns with Found 176 errors in 27 files (checked 33 source files)
Calling mypy -p operations.monitor_operation
returns with Found 68 errors in 6 files (checked 1 source file)
which on the fist glance might make sense.
However, the call operations
lacks some errors which appear only when explicitly checking the monitor_operation
with the latter call.
Same for just running mypy src/
(Which is what I actually want)Found 171 errors in 38 files (checked 133 source files)
What is going on here? Why is running mypy
running on a bigger scope finding less errors than calling it on only a module?
Could somebody explain why this gives me an error with mypy?
import asyncio
from contextvars import copy_context
async def run_task() -> None:
pass
def main() -> None:
copy_context().run(asyncio.create_task, run_task())
The error:
blaa.py:10: error: Argument 2 to "run" of "Context" has incompatible type "Coroutine[Any, Any, None]"; expected "Union[Generator[Any, None, _T], Coroutine[Any, Any, _T]]" [arg-type]
If I change the return type to Any
, it passes without error. Anything else? An error.
Anyone have experience with typing use of optionally async APIs?
I have a lot of success with the pattern:
result = maybe_async_func() # e.g. int | Awaitable[int]
if inspect.isawaitable(result):
result = await result # Awaitable[int] -> int
# at this point, `result` should be known to be `int`
but I haven't figured out the best way to annotate for mypy to understand the type of result
.
mypy --strict finds no issues in the following program:
from typing import Optional
class C:
def __init__(self) -> None:
self.x: Optional[int] = 0
def foo(c: C) -> None:
c.x = None
def bar(c: C) -> int:
if c.x is not None:
foo(c)
return c.x
return 0
c: C = C()
x: int = bar(c)
print(isinstance(x, int)) # prints False
Is this something that can be considered to be a bug? Or is it an inherent limitation of type narrowing?
Hi! I'm trying to achieve something... basically TLDR is there a way to hint mypy that YieldType
is the same as SendType
in Generator
?
from typing import Generator, Union
Gen = Generator
def fun() -> Gen:
a = yield ' str '
print(a.strip())
b = yield 123
b += 456
print(b)
c = yield "bad"
c += 1111 # I want mypy to flag this as an error
def run(g: Gen) -> None:
# this function simply bounces value yielded by the generator back
last_sent = None
while True:
try:
x = g.send(last_sent) # type: ignore[arg-type]
except StopIteration:
break
else:
last_sent = x
run(fun())
https://mypy-play.net/?mypy=latest&python=3.10&gist=8c685b8459f3ce43c67bfdc0fe8eaca0
^^ this type checks, but misses the error on line 15 (not surprising since it's basically Any
)
I could type Gen like this:
T = Union[int, str]
Gen = Generator[T, T, None]
but then I basically have to do casts/instance checks every time since mypy doesn't know which member of Union
I receive back from run
class AbstractManagerClass(ABC):
@abstractmethod
def __init__(self, var1: str, config_manager: <What to write here for a concrete AbstractConfigManager type?>) -> None:
"""
Constructor
"""
super().__init__()
self.v = var1
self.config_manager = config_manager
# .....
class AbstractConfigManager(ABC):
# some other abstract stuff
serialize
is incompatible with supertype" error for this code:GraphQLScalarSerializer = Callable[[Any], Any]
class ScalarType:
serialize: Optional[GraphQLScalarSerializer] = None
class DateTimeScalar(ScalarType):
@staticmethod
def serialize(value: datetime) -> str:
return value.isoformat()[:23] + "Z"
Dear friendly helpers.
I'm struggling with some mypy/typing problems:
X = TypeVar("X", bound=Union[str,int])
def a(x: X) -> X:
if isinstance(x, str):
return x
return x
mypy complains: error: Incompatible return value type (got "str", expected "X")
Is that a bug (For bound=str
this works) or if not, how can I fix this?