#type-hinting
1 messages ยท Page 52 of 1
You can totally do this with ParamSpec and pyright
but pyright isn't written in python ๐ฅฒ
Also kind of suprised it even works at all, I thought type checkers didn't check for that type of dynamicness inside of function bodies?
hmmm
FuncT = TypeVar('FuncT', bound=Callable[..., T])
class gevent_coroutine(Generic[FuncT]):
def __init__(self, fn: FuncT):
self.__call__ = fn
this carries the type across but it also breaks uh
like handling the self/cls argument
Isn't that because your decorators are in the wrong order?
fails in both orders
Ah no, just tried it. MyPy doesn't care
why are you using gevent in the first place :)?
this codebase is old
At runtime if @gevent_coroutine was innermost then you would need to supply the cls argument when running. Because before it has been wrapped in a classmethod you are intercepting the function afaik.
Yeah, when you have staticmethod you don't have any argument so it plays nicely
a channel for typehinting lol
Yeah? And?
how do i type hint a fixed size list?
like Tuple[int, int] but i want list instead of tuple: List[int, int] does not work
You can't
The whole point of lists is to be dynamically sized. If you need a fixed sized list, then use a tuple instead
you're right, however i can't assign tuple item, so it's not exactly what i need. but i think it's okay to recreate the tuple instead of assigning it's item, since i have only 2 item inside it
!e ```python
from sys import getsizeof
print(getsizeof(list()))
print(getsizeof(tuple()))
@blazing nest :white_check_mark: Your eval job has completed with return code 0.
001 | 56
002 | 40
Tuples are also smaller ๐
How can I type hint an argument that has to be an int that is more than or equals to 10?
That's not supported by the type system
๐ฆ
you can do it with TypeGuard!
(kinda)
from typing import TypeGuard
class IntegerAtLeast10(int):
@classmethod
def check(cls: type[IntegerAtLeast10], x: int) -> TypeGuard[IntegerAtLeast10]:
return x >= 10
x: int
y: int
z: IntegerAtLeast10
# OK
x = 20
if IntegerAtLeast10.check(x):
z = x
# Not OK
y = 20
if y >= 10:
z = y
unfortunately i'm not aware of any way to make this parameterizable, e.g. you can't have class IntegerAtLeast[10] or class IntegerAtLeast[Literal[10]], because you aren't allowed to write class IntegerAtLeast(int, Generic[I]) such that I is Literal[<any integer>]
btw, did y'all know that asyncio.gather returns a list even though the type hint says it returns a tuple?
Typing hacks, volume 3
...why does it do that
So that each returned element has the correct type
is it like map where they try to capture the heterogeneity by overloading 1, 2, 3, etc. until they give up around 5?
Yep
alas
hey I thought we went up to like 8
lol what
stdlib/builtins.pyi line 1084
class map(Iterator[_S], Generic[_S]):```
If you have a use case for mapping 32 iterables at once, I'd love to see it
probably not explicitly, but i bet someone out there somewhere has done some trickery with *-unpacking that results in such a thing
For zip maybe, but map? In any case that wouldn't match an explicit overload with 32 args anyway
true
unless it was a length-32 tuple where the length was known statically somehow ๐
isnt typing gather one of the reason guido wants pep 646?
I think map and zip are more of a motivation. gather() would still not work because we don't have a way to type heterogeneous lists
what if Tuple had a generalization to "fixed-size heterogenous sequences"
What does that change now?
!pep 646
typing_hack_volumes: Literal[2] = 8 # type: ignore
Hmmmm well now it should be ```py
typing_hack_volumes: Literal[2] = 9 # type: ignore
HACK
we should make are-we-typescript-yet.com and cache NO with a TTL of like a decade
for legal reasons this is a joke
Why doesn't this work?
_F = TypeVar("_F", bound=Callable[..., Any])
Works fine, what are you using it for?
Sorry, it was an issue with my linter, it works fine.
is there a compiler that optimises based off of hinting or am i tripping
cython or mypyc are your best options if you want to compile stuff based off of annotations
i mean, we should be. js has more or less all the same issues as python when it comes to static typing
I don't think I understood you
i mean that typescript solves many problems that also need to be solved in python, if you want static types in python
ah
yeah
I meant that as a comment about typescript having this nice feature
random thought: what if the typing module wasn't in the stdlib?
type checkers are (somewhat) incompatible anyway
so mypy could make its own type language that's convenient to implement, pyright would make one etc.
just like in JS there were flow and typescript and something else
Sounds like pretty nasty fragmentation
in the end the JS community converged on one option
which won because of the free market competition
there's no reason a type checker couldn't write their own typing alternative or their own typing-extensions that is only supported by that type checker
i think having it in the stdlib makes a lot of sense
imagine if flow and typescript could use the same core system of basic types
flow would probably still be in use today if you could write code that ran under both systems
pyre/mypy_extensions both exist
Yes, there's nothing stopping type checkers from implementing their own extensions
And we already have typing-extensions where we can put things without being bound to the stdlib release cycle
I feel stupid for asking, but is using __future__ to use the | (PEP604) in type hinting a legit method?
from __future__ import annotations
@dataclass
class Puppy:
breed: str | None
adoption_date: datetime.date
...
i'm not on 3.10 yet and using the method shown above doesn't give me any errors/warnings on my IDE, but i'm curious on whether there's a better way
currently on 3.9.X, not planning on using anything earlier than 3.8.X
if you you dont have future annotations you need to use a forward reference and quote the "str | None" part
That's fine to do
dw about forward references then
yippee! thanks 
it's fine as long as you don't evaluate the annotations at runtime
could you explain?
are you referring to PEP563?
Oh wait dataclass types aren't collected at runtime
typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)```
Return a dictionary containing type hints for a function, method, module or class object.
This is often the same as `obj.__annotations__`. In addition, forward references encoded as string literals are handled by evaluating them in `globals` and `locals` namespaces. If necessary, `Optional[t]` is added for function and method annotations if a default value equal to `None` is set. For a class `C`, return a dictionary constructed by merging all the `__annotations__` along `C.__mro__` in reverse order.
The function recursively replaces all `Annotated[T, ...]` with `T`, unless `include_extras` is set to `True` (see [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated "typing.Annotated") for more information). For example:
on your Pet class
I actually prefer explicit forward references
It makes it clear that "this will be defined in the future" or that "I am not actually importing this".
hmm what do you mean in this context?
Making the annotations strings can get annoying sometimes
I searched far and wide, but couldn't find how to get a mypy.types.ProperType representing int... Should be easy, right?
Found it, ctx.api.named_type
does mypy not support pattern matching? https://mypy-play.net/?mypy=0.910&python=3.10&gist=1b16892db797752b49344ba83ebcf3a4
No, there's a PR for it that's close to being ready
Is there a way to enable all mypy checks instead of having something like this in the pyproject.toml
toml [tool.mypy] check_untyped_defs = true disallow_any_generics = true ignore_missing_imports = true no_implicit_optional = true no_implicit_reexport = true show_error_codes = true strict_equality = true warn_redundant_casts = true warn_return_any = true warn_unreachable = true warn_unused_configs = true
strict = true maybe?
although it turns on some other checks that can be annoying to say the least ...
I usually do strict = true and show_error_codes = true
worth noting __future__.annotations breaks pydantic too
Any idea what's the fix?
Aside from not using it
There is none lmao
If you're using __future__.annotations because of a circular import, then there is no fix other than a restructuring of the project.
I use it because I'm using stuff like dict[str, str] and I want the project to be compatible with 3.8+
well, that will just fail at runtime
pydantic has to evaluate the actual expressions in the annotations
so if you want to use pydantic, just do Dict[str, str] (or maybe use Mapping[str, str] if you don't actually need a dict)
Is it possible to fix that in future?
From pydantic devs side
I mean they're trying to of course, but you literally need to eval() code
How about Python core side?
Like fix the conflict between eval() and __future__.annotations
So lemme get this straight
from __future__ import annotations fails when using pydantic?
So like
This code works?
from __future__ import annotations
from pydantic import BaseModel
class A(BaseModel):
a: dict[str, str]
In 3.8+
Pydantic will evaluate the annotations at runtime
And that doesn't work at runtime on 3.8
I'm pretty sure from __future__ import annotations converts that dict[str, str] to an understandable for 3.8+ code
@pliant horizon all from __future__ import annotations does is defer the evaluation of annotations
It doesn't automatically transform dict[str, str] into Dict[str, str] or anything like that.
Is there any method not to use deprecated code for a 3.8+ compatible project?
I don't think so, just use Dict
But that's deprecated
Not in 3.8
You can do some gross compatibility stuff
Use Dict until it is removed. When it is, drop support for 3.8 and use dict
Is it beneficial to just force the lib users to use 3.9+?
Like if sys.version_info > (3, 8):
Dict = dict
else: from typing import Dict
Probably yes
Tbh I still don't understand how this is "deferring" it. All it does it literally convert it to strings lmao
Well unless you use the code that Gobot showed, you kind of don't have a choice
It's going to be years into the future until this stuff is removed in newer versions.
And at that point, 3.8 will be deprecated
So just use deprecated code until 3.8 bites the dust then
Yes
Yup, that's how compatibility sadly works ๐
I think most a lot of libraries have switched to 3.9+ already haven't they?
Atleast numpy and astropy are
I'm developing a discord API wrapper and I want the most possible count of users
Oh? So 3.8 is on another major version?
I'm personally concerned with making people have to stick on a version I think having to support older versions of python just ends up being a pain
If people don't want to update they just shouldn't use whatever I'm writing
from PEP 585:
The deprecated functionality will be removed from the typing module in the first Python version released 5 years after the release of Python 3.9.0.
...so they're going to be removed in 2025
Me too, just upgrade
Like is it that hard
for beginners and people who aren't professional programmers it might be hard
I already ditched 3.9 and using 3.10
Yeah that's true..
I don't think I've ever heard someone turn down something because it doesn't support a certain version really
And there's my contributors telling me the lib has to support 3.8+ because most people use it
for example, repl.it is on python 3.8
Yeah but it's discouraged to code discord bots on replit
Now that's not a great idea imo, 3.9 is used by a LOT of people and 3.10 isn't so common yet
doesn't mean people don't do it
I don't think that argument holds.
Beginners usually download the most recent version, by the point a package doesn't support that version you literally have to wait years
Hmm, that puts it into perspective
I've seen how people struggle with installing Python on windows
So @green gale @trim tangle if you were me
Would you make a huge discord API wrapper 3.8+ or 3.9+?
3.9+
but yeah, most people will be fine with 3.9
So just use 3.9 code then?
If all you need is nicer type annotations I'd stick with 3.8
if you don't need to inspect the annotations, then yes, that will work
I'm actually not sure how often you really need dict[K, V] and list[T] and not Mapping[K, V]/MutableMapping[K, V] and Sequence[T]/MutableSequence[T]/Iterable[T].
No it doesn't
Look, the type is a string
I mean the same sort of argument applies to that you should be using the ones from collections.abc, but again that only works in 3.9+
Welp, they all got deprecated in 3.9
Yeah, they'll be removed from typing in 2025
so when you drop support for 3.8 you'll have to import them from collections.abc
- it will be there until 2025
- upgrading is not that hard
- many people still use 3.8
Third one is a concern
over time they'll stop using 3.8
OK fair
You can look at the numbers yourself and decide if they are worth it
They are on pypi somewhere
Important to know is that the numbers are heavilty affected by CI
yeah, just fork the CAD program you're using and update it to 3.10 ๐
It isn't THAT hard tbh
On large codebases that have barely been touched in a decade and that were written by someone else, it absolutely is
And without any test suite, of course.
how many of these aliases are actually being used?
I would just make a module type_aliases or something if you're concerned about updating the code
# main.py
if sys.version > (3,8):
from type_aliases import *
# type_aliases.py
Dict = dict
List = list
voila, no more deprecated code ๐
dict, set, list collections.abc.Mapping
iirc
what's the difference between collections.abc and typing
typing is the general module for type annotation stuff
before 3.9, you weren't able to do e.g. collections.abc.Mapping[str, int]
so now the Mapping in typing is deprecated because we don't need two different things for the same annotation
typing still has useful stuff like Union, Generic and TypeVar
but if you want something from this list: https://www.python.org/dev/peps/pep-0585/#implementation don't use typing if you're targeting 3.9+
so then why are stuff getting deprecated from typing
Not everything from typing is deprecated. Just the stuff in the list above.
Now you can do list[int] so typing.List doesn't serve any purpose
i really liked Dict and List instead of dict and list ngl ๐
oh btw
What about this
https://www.python.org/dev/peps/pep-0585/#implementation
Seemingly the code should run fine
Yes, the code runs fine because the annotation just becomes a string. You can put any expression there.
!e
from __future__ import annotations
def f(x: 1 + "2"):
...
@trim tangle :warning: Your eval job has completed with return code 0.
[No output]
Oh so that's useless when developing a lib
I shouldn't use them because then the user can insert a str instead of the typehint
That what you mean?
!e
With the future-import, type annotations become strings at runtime. For example:
def f(x: int) -> list:
...
print(f.__annotations__)
@trim tangle :white_check_mark: Your eval job has completed with return code 0.
{'x': <class 'int'>, 'return': <class 'list'>}
it only applies in the file the import is in, the lib's users won't be influenced by it (and can't influence your lib).
The only case when you'd care about it is if you inspect annotations at runtime
!e
But here they are strings:
from __future__ import annotations
def f(x: int) -> list:
...
print(f.__annotations__)
@trim tangle :white_check_mark: Your eval job has completed with return code 0.
{'x': 'int', 'return': 'list'}
!e
from __future__ import annotations
def a(x: list[int]):
return 0
a("dfsf")
@pliant horizon :warning: Your eval job has completed with return code 0.
[No output]
there won't be any errors even without the future import, python doesn't enforce types through typehints
So, what's the point of typehints?
Documentation and static checkers
Is there any strict mode?
No, you'd have to use some 3rd party lib that inspects annotations at runtime, but that often ends up conflicting with the syntax of typehints to be functional
How do I idiot-proof that code then?
Annotations were originally meant for many purposes, not just type-checking. There are tools that enforce the types at runtime, but the whole point of static typing is that type errors are caught before runtime.
@pliant horizon There are tools like beartype that do runtime checking. But you fundamentally can't check some things at runtime.
For example, how do you know if a function conforms to Callable[[int], str]?
checking at runtime would do unnecessary checks 99% of the time as they'll only happen during development
that is also true, although I guess you could have some debug flag
I'm pretty sure C++ would kick your butt if you tried assigning something else other than the type
c++ also doesn't do it at runtime
C++ doesn't do that when the program runs. It does that during compilation.
That's what type checkers, such as mypy and pyright, do in Python.
So like, do I have an option to force people to provide that type?
Like something that does it during interpertation
I haven't researched this space, but there are libraries like beartype and enforce-typing that help with that
Are they worth using?
I don't know, haven't used them
why do you want these checks?
I don't want people to be idiots tbh
I want the app to raise error if someone's messing up
so you want to fail as soon as you get the wrong type?
then I guess you can try beartype and share how it goes ๐
Some things you won't really be able to automate to be nice.
but most you probably can
Is it a wrong practice?
no, it's a good thing
well, from the perspective of the library user
really it depends as with all things
it will hurt performance for everyone so that some people dont mess up
hello! Due to Python runtime requirements I have had to reimplement contextlib.nullcontext. Functionally I know what I am doing, but in terms of typing I haven't used TypeVar before. I wanted to check that I was using it in the right way (before it gets stuck in my memory):
import contextlib
from typing import Iterator, TypeVar
T = TypeVar("T")
@contextlib.contextmanager
def nullcontext(enter_result: T) -> Iterator[T]:
yield enter_result
with nullcontext(123) as value:
print(value)
yeah thats correct
thank you!
https://github.com/python/typeshed/blob/98dde9c36453e53ee163c60001f3308d948c8b45/stdlib/contextlib.pyi#L106 is how the nullcontext in the stdlib is type hinted
might be helpful.
Ah of course, good idea, thanks!
For that definition, note that typing self is a special case, here it's used in the overload to indicate the generic value with different init arguments.
Is it possible to narrow the type of TypedDict field when subclassing? For context I'm trying to use the following:
class FileResult(TypedDict):
type: Literal["nothing-changed", "reformatted", "failed"]
src: str
class NothingChangedResult(FileResult):
type: Literal["nothing-changed"]
class ReformattedResult(FileResult):
type: Literal["reformatted"]
dst: str
class FailedResult(FileResult):
type: Literal["failed"]
error: str
message: str
but mypy isn't too happy about it
diff_shades/results.py:23: error: Overwriting TypedDict field "type" while extending [misc]
diff_shades/results.py:27: error: Overwriting TypedDict field "type" while extending [misc]
diff_shades/results.py:32: error: Overwriting TypedDict field "type" while extending [misc]
Changing a field type of a parent TypedDict class in a subclass is not allowed. Example:
https://www.python.org/dev/peps/pep-0589/#inheritance
... I guess not :'(
What you could do is move the parent type to another subclass - maybe UnknownResult, and cast/maybe use TypeGuard.
Can you not just make the literal on the FileResult and instead just make it str?
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
Can you just # type: ignore?
unless I'm totally misreading your suggestion ^^
No that's what I meant
Hmm I guess I could try that, I'm just worried that since it's erroring on that, it won't narrow the type when I do:
result: FileResult
if result["type"] == "reformatted":
reveal_type(result) # ReformattedResult
although now I come to think about it, this might not be supported anyway
That doesn't work no
ah ok
What you need is typing.TypeGuard.
personally,I've used both beartype and typeguard in justuse, I'd say typeguard is much simpler to integrate. @frank glade @rustic gull may have thoughts as well
i wished typeguard worked, it seemed really cool at first
typeguard has an easy import hook, beartype doesn't :\
but the tracebacks are unwieldy
TypeGuard would definitely work here, but the function call required makes it less than ideal
I'll think it over with the ideas and thoughts suggested, thanks!
Indeed. Otherwise you could cast it.
if you have more complex stuff, consider icontract in addition

it would be cool to collect some use cases that the "runtime type info" does make possible besides purely declaring the types
was __class_getitem__ added specifically to support type hints?
I asked about this on typing-sig, apparently it's because dicts are mutable, and that it would only make sense on a "frozen" typeddict
(i suggested TypedDict(frozen=True) as possible syntax)
yep
class FooBar(TypedDict):
x: Literal["foo", "bar"]
class Bar(FooBar):
x: Literal["bar"]
def f(d: FooBar):
d["x"] = "foo"
d: Bar = ...
f(d) # oops
Is it right to type annotate return as following:
def do_something() -> Union[Tuple[str, str], None]:
"""
Returns a Tuple or None
"""
or we could also do following using Optional, and not explicitly mention None:
def do_something() -> Optional[Tuple[str, str]]:
"""
Returns a Tuple or None
"""
They're equivalent ^^
!d typing.Optional
typing.Optional```
Optional type.
`Optional[X]` is equivalent to `X | None` (or `Union[X, None]`).
Note that this is not the same concept as an optional argument, which is one that has a default. An optional argument with a default does not require the `Optional` qualifier on its type annotation just because it is optional. For example:
```py
def foo(arg: int = 0) -> None:
...
``` On the other hand, if an explicit value of `None` is allowed, the use of `Optional` is appropriate, whether the argument is optional or not. For example...
yep
ok thank you (:
typing.Union[X, None] actually returns typing.Optional[X].
!eval
import typing
X = typing.TypeVar("X")
huh = typing.Union[None, X]
print(huh)
@leaden oak :white_check_mark: Your eval job has completed with return code 0.
typing.Optional[~X]
Looking at the current implementation, actually Optional returns Union[x, None] and then Union's repr code special-case shows Optional.
X | None stays like that however.
In any case all three syntaxes are entirely equivalent.
Yes this is the case, I've done runtime introspection and Optional[X] will show up as Union[X, NoneType]
I feel like I am managing to get the typing wrong every time I'm using a feature I haven't used before
@overload
def filter_results(
file_results: Dict[str, FileResult], type: ResultTypes
) -> Dict[str, FileResult]:
...
@overload
def filter_results(
file_results: List[FileResult], type: ResultTypes
) -> List[FileResult]:
...
def filter_results(file_results, type):
reveal_type(file_results)
if isinstance(file_results, list):
return [result for result in file_results if result.type == type]
else:
return {file: result for file, result in file_results if results.type == type}
what did I do wrong here ๐ฆ
Well, you are supposed to annotate the last version too, but this annotation is to specify what the implementation receives and returns - so Union[Dict[...], List[...]]
ah, is the example in the pep wrong then?
@overload
def utf8(value: None) -> None:
pass
@overload
def utf8(value: bytes) -> bytes:
pass
@overload
def utf8(value: unicode) -> bytes:
pass
def utf8(value):
<actual implementation>
https://www.python.org/dev/peps/pep-0484/#function-method-overloading
The type checker checks all the overloads are compatible with the implementation signature.
or is that only for stub files?
In stubs you have no implementation.
No it is correct, but your implementation function won't have any type checking
That looks right, why do you think it's wrong?
Though you should indeed annotate the implementation
yeah I forgot about that lol
Yep, since it's unannotated the type checker ignores the content.
Reading the pep suggested otherwise, but I guess that's more a type checker specific thing instead :p
That example should probably be:
def utf8(value: Union[bytes, Unicode, None]) -> Optional[bytes]:
Your type checker will be able to enforce your overloads on users calling your code afaik. But your implementation won't be type checked because there are no types
Yep.
got it, thanks!
That's a weird example could be better as:
@overload
def utf8(value: None) -> None:
pass
@overload
def utf8(value: bytes | unicode) -> bytes:
pass
def utf8(value: bytes | unicode | None) -> bytes | None:
<actual implementation>
The typechecker should tell you if overloads are redundant and fold them into a union
i wish you didn't have to write out the union'ed types in the implementation
Mixing def and match together would be cool
definitely. or at least generalize the match destructuring syntax to = and function signatures
hm... not sure about the syntax.
def distance(p1 : Point(x1, y1), p2 : Point(x2, y2)) -> float:
...
why is subprocess.Popen subscriptable? what is the passed type for?
Whether the stdout is bytes or str
guys, how can I write this typescript generic statement in python?
export type Options<K, V, C = K> {}
``` can I do typevar = typevar in python?
No, typevar defaults aren't supported
one sec, can I share my use case?
Sure, but it's not going to change the fact that this currently isn't supported
There's an open issue for it in python/typing
If somebody advocates for it and pushes a PEP through, it'll probably be received positively
KT = TypeVar("KT")
VT = TypeVar("VT")
CT = TypeVar("CT")
class SomeClass(Generic[KT, VT, CT]):
def some_func(self, arg: KT) -> CT:
"""this func might be overridden to return something, but returns the same arg by default."""
return arg
```here, mypy throws an error:
Incompatible return value type (got "KT", expected "CT")
@oblique urchin do bounds have to do anything wth this?
Mypy is right there, KT and CT are different types after all
so, what could I do here? The value might be the same or different type?
Can't think of a typesafe way to do this
this typescript library does this, I was looking into it!
https://github.com/graphql/dataloader/blob/master/src/index.js#L17
src/index.js line 17
export type Options<K, V, C = K> = {```
You could make some_func abstract, then put this some_func implementation in a subclass, which is defined like this:
class DefaultSomeClass(Generic[KT, VT], SomeClass[KT, VT, KT]):
...
seems like kind of a niche use case for adding new syntax, but i can see why that'd be nice. i wish you could properly inherit from protocols instead of having to mess with ABCs
A neat article about type hints and their usefulness this channel might enjoy https://sethmlarson.dev/blog/2021-10-18/tests-arent-enough-case-study-after-adding-types-to-urllib3
wow this channel seems to have masters of python in it
while not GolfScore.isdigit() or int(GolfScore)< 18 or int(GolfScore) > 150:
AttributeError: 'int' object has no attribute 'isdigit'
Does anyone know what this error mean?
what does Generic[KT, VT] mean
@pliant prism This doesn't have anything to do with type hints. If you have a general question, see #โ๏ฝhow-to-get-help and claim a help channel.
@drowsy plinth What parts of type hinting are you already familiar with?
class Person:
def __init__(self,name:str,age:int,gpa:union[int,float],courses:list):
that is as far as i know
Generic is how you let a type have type parameters, like list or dict.
there is alot for me to learn
In the code you listed, it has allowed union[int,float] to have parameters
(but union is a bit special)
Union is a special form, it's different
is not union become switched to | in patch 3.10?
is there any decorators or magic methods i should search to learn more how to use
i know ```py
@staticmethod
@classmethod
@overload < notmuch about
This is the minimal example of a generic type:
from typing import Generic, TypeVar
T = TypeVar("T")
class Box(Generic[T]):
def __init__(self, initial_value: T):
self._value = initial_value
def set(self, value: T) -> None:
self._value = value
def get(self) -> T:
return self._value
def increment_box(box: Box[int]) -> None:
x = box.get()
box.set(x + 1)
box = Box(41)
box.increment_box()
You can hover over different variables in your IDE to see what type everything is
okay thank you
It doesn't impact the runtime in any way, it's just a type hinting thing
well, mypy doesn't tell you when your comment is outdated ๐
what does the -> None: mean?
it means that the function returns None
ah its a type hint thing
yes
it's basicaly a method to set or increment
yes i understand now
how do you inherent a private instance attribute from a class to another tho
woow
Okay thanks alot @blazing nest @trim tangle
No explicit re-export is probably the closest to private
In reference to modules?
When talking about attributes then name mangling is probably the most closest to being private because of the pain necessary to access it.
Just not re-exporting and adding a leading _ is scary enough for modules though yeah
I mean the mypy feature
Where else can I find type hints other than typing and abc (Abstract Base Classes)
What do you mean by "find type hints"? Any type can be used in type hints
Oh like type hinting modules
The runtime typing code is generally permissive in what it allows so that future enhancements to the type system are easier
typing_extensions has some stuff too although chances are that everything that isn't in your current version's typing will be present in a newer version
Oh, I'm currently on 3.9.7
eh, there's typeguard that is only present in typing since 3.10 for one
not sure how useful that'd be for you, but typing_extensions does still have recent additions
Can someone help me Im trying to make the user input choose what multiples they want to know
@vivid sphinx If you have a question, you generally should see #โ๏ฝhow-to-get-help. This channel is for discussing type hints.
When I try to assign a dict value using
self.relationship_id = inRelationship["relationship_id"]
and self.relationship_id is defined as
relationship_id: str
I get an incompatable error Incompatible types in assignment (expression has type "Union[str, Optional[List[PropertyModel]]]", variable has type "str")
My dict has either key value pairs with both values being of type str, or an optional key, value pair that could be a list.
I'm using mypy in vs code
I understood Union to be for when there could be two options, and my Union has str as a type.
What am I missing
I ended up having to put an if isinstance statement to check it was str for it to work
I wonder what generics in Python are used for
Also confused what are overloads in Python
yeah, but you can't assign y: str | other; x: str = y
in case y was other, x's type would become incorrect
generics are used for collections containers functions and things
functors?
Forgot to send this here, but this is cool!
https://mail.python.org/archives/list/python-dev@python.org/thread/SZLWVYV2HPLU6AH7DOUD7DWFUGBJGQAY/
!pep 649
what would be the best way to implement deferred evaluation of subscriptions to types in mypy?
cause i was using api.type to get the current type thats being analysed but when subscripting a generic the subscription is understandably called before the type that i want info (the full name) about is created
Is it possible to specify the keys in a dict like in Typescript e.g.
Interface DataInterface { myData: str; }
TypedDict is what you're looking for
is there some way to write a typevar such that it resolves to a union?
a : List[T]
b : List[T]
in this example, i expect that a and b might be heterogenous (and could contain anything), but i want a and b to contain the same mix of things
actual use case:
@contextmanager
def multicontext(
*unnamed_contexts: ContextManager[_T], **named_contexts: ContextManager[_T]
) -> Generator[Dict[str | int, _T], None, None]:
"""Enter multiple contexts in a single `with` statement."""
contexts: Dict[str | int, ContextManager[_T]] = {
# Unnamed contexts are numbered sequentially: `{0: ctx1, 1: ctx2, ...}`
**dict(enumerate(unnamed_contexts)),
# Named contexts are used as-is
**named_contexts,
}
with ExitStack() as stack:
yield {
label: stack.enter_context(context) for label, context in contexts.items()
}
i want the _T to be "whatever the user provided", even if that's several different types
any idea what could be happening here?
something with pydantic? it is running on python 3.8
maybe the bad line is actually in the ??? which is not very helpful....
It's likely trying to eval() the dict[str, str]
oh, I couldn't make out that there was a generic in there. thanks
does this not work on 3.8?
I guess with Dict it might?
yes, you need Dict or 3.9
PEP 585 added support for dict[str, str] but that's only in 3.9
You can use from __future__ import annotations or "dict[str, str]"
You say you expect, but does that mean it will be the same?
Meaning, i want to allow a to be heterogeneous, and enforce that b has the same mix of types
Wait so you want Union[int, str] and Union[str, int, float] to be correct?
Maybe with a TypeVarTuple, I'm pretty sure you can stick those into Union (if your type checker supports a drafted feature)
Union[Unpack[Ts]] in theory
Union[*Ts] if optimistic for the future
I want b = f(a) such that if a : int | str then b : int | str
Now, keep in mind that you can't really tell whether the user intended the type to be T | U or to be V (common parent of T & U)
in this case I can't assume that the types in the union have a common parent, other than objectof course
#type-hinting message my actual code is here, but maybe this whole idea is misguided
ideally I would like to be able to statically map keyword arguments to keys in the result, if they are known statically, but that seems like too much to ask for
T = TypeVar('T', bound='Union')
def f(a: T) -> T:
...
Why doesn't work for you?
indeed, considering the function could be passed any kwargs whatsoever
Yeah if they do f(**something) then if something isn't a TypedDict the best it can do is say "any other key has the same key type as something"
(i know that none of this is currently supported)
Are you sure that works? It doesn't make sense to me
Why?
Huh? Union is essentially a contravariant inner join of types, creating a new type
This is a union of boxes:
Which creates this new box
No?
Sure. But a TypeVar bound is meant to be a type. Union isn't a type, but a special form. Mypy doesn't actually allow you to pass a Union if you create a TypeVar like that: https://mypy-play.net/?mypy=latest&python=3.10&gist=1a7cf5aa4c864513231e7c13902d5f01
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
Huh? Wouldn't it become Union[Any, ...] (even though that's not accepted syntax)
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
Ah, you have to be explicit with your Union[Any] typing
Looks like it turns into <nothing> which is an empty Union
Yeah, @fierce ridge just add the [Any] part and it works https://mypy-play.net/?mypy=latest&python=3.10&gist=1a7cf5aa4c864513231e7c13902d5f01
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
Union[Any] is just Any; it lets you pass a non-union type if you use that as a bound
Hmm, you right
Also I realize now that when I changed some stuff and ran it that didn't change the gist so I just pasted the same gist 2 times
Yes that's confusing ๐
how can i make type a type hinting like that
class EstimatedDiameterDetails(TypedDict):
estimated_diameter_max: float
estimated_diameter_min: float
class EstimatedDiameter(TypedDict):
kilometers: EstimatedDiameterDetails
meters: EstimatedDiameterDetails
miles: EstimatedDiameterDetails
feet: EstimatedDiameterDetails
class Asteroid(TypedDict):
links: Dict[str, str]
id: str
neo_reference_id: str
name: str
nasa_jpl_url: str
absolute_magnitude_h: float
estimated_diameter: EstimatedDiameter
is_potentially_hazardous_asteroid: bool
a: Asteroid
a["estimated_diameter"]["make something that makes autocomplete match 'kilometers', 'meters', etc"]
From the type system's perspective that should already work. If your IDE doesn't do the autocompletion, that's something for the IDE to fix
If i recall correctly pyright (vscode's default for python) recently made an improvement for TypedDict key autocompletion
yep, pyright does that
yeah, pyright did this for me
autocomplete is working now, at least when you try to create a dict
to access too, probably
ty
in a class that inherits TypedDict, how can i say that a key can exist or not? like, supposing something like this:
class Book(TypedDict):
next_page: int # next page may dont exist, considering you're in the last page
previous_page: int # same thing for previous page
how can i say that these keys may not exist?
Not yet supported. You need to wait for https://www.python.org/dev/peps/pep-0655/
class Book(TypedDict, total=False)
Keep in mind this will make all of the keys optional
oh ok
Oh right, you can actually do that for the whole TypedDict
And with inheritance you can make some keys required and others not required
yeah, thats not what i want, ig ill need to wait for pep 655
So if you need a mix of optional & required keys, you have to make a total=False class and subclass it with a normal TypedDict
It's kind of a gross code pattern but whatever
im pretty sure pyright already has support for 655
Are you sure? It's not even in typing-extensions yet
yeah
it can even be imported (not at run time from typing exts)
https://github.com/microsoft/pyright#type-checking-features its the last thing there
Oh interesting, I guess they put it in their private copy of typeshed
must have
packages/pyright-internal/typeshed-fallback/stdlib/typing_extensions.pyi line 125
Required: _SpecialForm = ...```
I mean I usually import from typing_extensions in a TYPE_CHECKING block regardless
So I'm adding type hinting to a function where an argument expects a list that contains at least one element, and the elements in it can only be specific values like so:
def foo(args = ["one", "two"]):
# do things with args
How would I go about type hinting this list of literals where not all elements need to be present?
List[Literal["one", "two"]]. You can't express that the list must have at least one element though
And invariance may make such a type a pain to use
Wouldn't that expect a list with explicitly those two elements, rather than one or the other or both?
And I'm willing to just have that length check in inside the function itself
Would it be something dumb like List[Optional[Literal["one"]], Optional[Literal["two"]]]
What are valid inputs for that argument?
I don't quite get it
List[Literal["one", "two"]] would allow [], ["one"], ["two"], ["two", "two", "one", "two"], ["one", "one"] etc.
Let me expand the available values for the args argument
def foo(args: list = ["one", "two", "three"]):
if len(args) == 0:
raise IndexError("List has no elements")
if "one" in args:
# do specific action
if "two" in args:
# different action
I could attempt to remove any duplicate entries like you posted by doing args = list(set(args))
Just wanting to make sure that only specific elements can exist in this list
@tawny flame you could accept a set
That could also work
So args: set[Literal["one", "two"]] would do it?
yep
or use enum.IntFlag ```py
class Args(IntFlag):
ONE = 1
TWO = 2
THREE = 4
you'll be able to do Args.ONE | Args.THREE and such
so illegal arguments will never pass type checking
(which is sort of the holy grail of static typing)
may I ask why pyright is a bit wonky here?
It's probably not re exported
You'll need to change the import of cvtColor to an import as
ah
Or you need a py.typed
Oh I meant in cv2/init.py
And you need py.types files so type checkers know your code is typed
new Pyright update improves type narrowing with generics ```py
from typing import Sequence, Union, List
def f(x: Union[List[int], Sequence[str]]):
if isinstance(x, list):
reveal_type(x)
else:
reveal_type(x)
pyright gives the types `list[int] | list[str]` and `Sequence[str]`
whereas mypy gives the types `list[int] | list[Any]` and `Sequence[str]`
is this a release or dev branch?
ah, 7 hours ago, presumably the 1.1.181 release. Time to update, nice.
yeah, release
if pyright ever gets some sort of plugin system, it's probably going to be a better choice for production than mypy
import math
#****************************AR*EA*****************************#
b = input("Base Here: ")
h = input("Altezza Here: ")
#****************************AR*EA*****************************#
#**************************PERI*M*ETRO************************#
h2 = math.pow(h)
b2 = math.pow(b)
t = b2 + h2
t2 = math.sqrt(t)
t3 = b * h
#**************************PERI*M*ETRO************************#
#****************************TOT*ALE**************************#
print(str("Area: "+ t3))
print(str("Perimetro: "+ t2))
#****************************TOT*ALE**************************#
whats wrong with this code "/
:/
it has errors i tried to fix
@agile cliff Is this somehow related to type hinting?
If not, you should see #โ๏ฝhow-to-get-help and claim a help channel for your question.
@azure niche You don't need any special package for type-hinting. But if you want static analysis, you'll need a tool like mypy or pyright.
Alternatively, you can install the tool into your editor. What editor are you using?
vsc
Although Im trying to type hint here, but it seems to error
Snake is a class defined below
I love how you have a SQL db icon as your head
@azure niche It will fail at runtime. You need to do snake: "Snake" if you want a forward reference
btw, did you set "Pylance > type checking" to basic in the settings?
nope
you should, otherwise it doesn't report most type errors
Would var: list[int] mean that it is a list that is filled with ints
Yes
guessed it :0
[1, 2, 3] is ok, [] is ok, [True] is ok
yes
well i need ti make this to itn
its a loop that makes string as output
and i need number of that output
@rustic gull You should see #โ๏ฝhow-to-get-help and claim a help channel
like this is a simple question, i dont want to bother the help channels
Help channels are fine for all kinds of questions. There is little cost to opening a help channel.
The topical channels each have their own topic. For example, this channel is about type hinting - discussions about type hints go here. But not questions about networking or graphics.
i know that dont worry
Converting between the basic types is usually out of type-hinting's realm as it focuses specifically on type annotations and the ecosystem around it (unless you're talking about how to convert types in a type-safe manner)
this seems to not work sometimes?
like def func(x: "List[MyType]"=8): didn't work iirc
I believe I had to use
def func(x: typing.ForwardRef("List[MyType]")=6):
Maybe List["MyType"]?
hu, that did work...
Yeah
You only put the forward reference bit in quotes ig
No need to put List in quotes since that's in the scope
Also 3.9 you can do list[x] instead of typing.List[x] so if you're 3.9+ I'd change that
ForwardRef should never be used in a type annotation, it's just an internal helper
oh oops
!d typing.get_type_hints
typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)```
Return a dictionary containing type hints for a function, method, module or class object.
This is often the same as `obj.__annotations__`. In addition, forward references encoded as string literals are handled by evaluating them in `globals` and `locals` namespaces. If necessary, `Optional[t]` is added for function and method annotations if a default value equal to `None` is set. For a class `C`, return a dictionary constructed by merging all the `__annotations__` along `C.__mro__` in reverse order.
The function recursively replaces all `Annotated[T, ...]` with `T`, unless `include_extras` is set to `True` (see [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated "typing.Annotated") for more information). For example:
ahhhhhhh i need to use globals and locals
OH.
Note
get_type_hints() does not work with imported type aliases that include forward references. Enabling postponed evaluation of annotations (PEP 563) may remove the need for most forward references.
why not? what does that mean
But 563 makes all annotations forward references
they're technically different iirc
it makes them ForwardRef objects though right?
No, just strings.
r there any modules which could help to perform type checking within code??
like
smth like tiz
def func(arg: int): if type(arg) != int: raise NotImplementedError()
but it's goin to take a lot of effort
r there any modules?
There's beartype and pydantic which both provide decorators for automatically doing that to functions.
does beartype support overloaded typing?
Not yet, since the @overload decorator right now causes all the overloads to be discarded. But there's a solution planned.
i wonder how u always hv the names of the modules needed for a certain purpose n all the stack n github links lmao ๐
thx a lot
oh wow u actually commented on it lmao
umm...
@pastel egret can ya summarise the whole thing
it's a bit way too long...
Add a replacement @beartype.overload decorator you use instead, which does store off the overloads for use, and is still treated correctly by static type checkers.
also ๐
i m sry but i don't quite understand
It's not implemented yet.
huh
from typing import Union
from beartype import beartype
@beartype.overload
def func(arg: int) -> int: ...
@beartype.overload
def func(arg: str) -> str: ...
@beartype.overload
def func(arg: Union[int, str]) -> Union[int, str]: ...
def func(arg: Union[int, str]): ...
is it like tat??
ps i m still not quite familar with overload
Yeah.
this doesnt look like a case for overloads
you should probably be using a type var with constraints
Traceback (most recent call last):
File "c:/Users/babario/OneDrive/Desktop/Projects/test.py", line 4, in <module>
@beartype.overload
AttributeError: 'function' object has no attribute 'overload'
As I said it's not implemented yet so it wouldn't work...
T = TypeVar("T", int, str)
@beartype
def func(arg: T) -> T:
# actual impl
this should work for now
wat does the 'T' in TypeVar thingy do
oh
i see
ya right
k
understood alr
could i possibly change the error msg in beartype tho?
@pastel egret
@soft matrix
the error when you fail to pass a type check?
idk how youd do it apart from add another decorator to catch the error as the function is called
ive never actually worked with beartype
oh
example pls..?
have you never written a decorator?
!tag decorators
Decorators
A decorator is a function that modifies another function.
Consider the following example of a timer decorator:
>>> import time
>>> def timer(f):
... def inner(*args, **kwargs):
... start = time.time()
... result = f(*args, **kwargs)
... print('Time elapsed:', time.time() - start)
... return result
... return inner
...
>>> @timer
... def slow(delay=1):
... time.sleep(delay)
... return 'Finished!'
...
>>> print(slow())
Time elapsed: 1.0011568069458008
Finished!
>>> print(slow(3))
Time elapsed: 3.000307321548462
Finished!
More information:
โข Corey Schafer's video on decorators
โข Real python article
Why would you want to catch it? A type error like that is a programming mistake, either a bad value was passed that must be fixed or the type hint should be changed to accept it.
ok...
i think they want to make the error clearer
ya
but idk what the error actually looks like
huh
tiz is the original error
beartype.roar.BeartypeCallHintPepParamException: @beartyped func() parameter arg="1.0" violates type hint ~A, as "1.0" not int or str.```
im assuming you passed a float there not a str
ya
If you really want to change it I guess except beartype.roar.BeartypeCallHintPepParamException: then raise your own error @undone carbon
But yeah, I'd say that error is fine myself
thx
๐
we got hit by this too
its really annoting because it's a long warning that takes about half a page of output
can't be avoided afaik and it always showsit
it's just complaining if you use List instead of list ๐
most things now complain about that
seems unhelpful :p
It's trying to warn you that the code will break in 2025.
https://github.com/beartype/beartype#what-does-this-mean
You can just filter out the warnings call in your application before importing things.
that's correct
that's why it's annoying the name of the warning changed
from Deprecation to Deprecated or vise-versa
but its not a showstopper of course
Hello. I'm a bit stuck on something and wondering if someone could help me out.
I'm writing an event bus system, and more specifically the function used to subscribe to receive notifications of certain events. I have a base event type: py class Event(ABC): ... And the subscribe function will look something like this: py def subscribe( event_type: ..., callback: Callable[[...], None] ) -> None: ... I'm just not sure what to put in place of the two ...s to make this function generic. The event_type should be a type, specifically a subtype of Event. The callback should accept an object of this type (or a subtype) as its first and only argument.
EventT = TypeVar("EventT", bound=Event)
and then def subscribe(event_type: Type[Event], callback: Callable[[Event], None]) -> None: ...
Hmmm has anyone encountered this?
https://github.com/microsoft/pyright/discussions/2487
That's what I was looking for. Thanks very much! ๐
I think I fixed this in typeshed recently
I got really excited when I learned that AsyncContextManager and ContextManager are monads, and then this 
ooh cool, that seems like it fixes it
do you know if I can somehow pull this?
I think pyright has its own copy of typeshed somewhere in its bowels
Normally they're pretty quick at updating though, kind of surprised this change isn't in yet
I assume it was sunday yesterday ๐
Sounds like it should be in pyright 1.1.181
oh, I'm using pylance
maybe it lags
yeah, I'm a dummy
pyright 1.181 doesn't show any errors
i just realized beartype doesn't support custom classes ๐ฉ
In what way?
beartype.roar.BeartypeDecorWrappeeException: <class '__main__.Label'> unsupported, as classes currently unsupported by @beartype.
Ahh. You can't yet directly decorate classes, but you can decorate the methods I think.
how long has beartype been under dev?? is it a new thing??
It's new yes.
any thing in typing module tat says like Something[int, str] means int or str or None?
You want typing.Union, or in 3.9+ int | str | None.
3.10+..?
with the future import it works in 3.9 too, ig
i m using 3.8 ๐
i found tat Optional[int] basically means int or None but optional cant accept multiple arg -- any ideas?
Use Union[int, str, None].
is this general discussion or am i allowed to ask for help with some mypy errors i'm stuck with
both
i can't for the life of me figure out why mypy suddenly doesn't like me importing this:
from types import UnionType```
tells me `Module "types" has no attribute "UnionType"; maybe "FunctionType"?`
it was introduced in 3.10, i've ensured i'm using 3.10, even added `--python-version=3.10` in the mypy linting arguments in vscode
as well as type hinting with `OptionalStr = str | None` (tells me `OptionalStr is not a valid type` when i type hint one of my function params with it)
i've literally had no problem with these two for the past few days, but tonight i have no idea what i did for mypy to start throwing me these errors
i can import union just fine, i need UnionType
later in my code i check function annotations programmatically and i need to match UnionTypes to go through each type inside of it
since str | None for example produces a UnionType
(taking annotations from func.__annotations__)
i m pretty sure it's Union not UnionType but tiz guy can help @pastel egret ig
def foo(x: str | int):
pass
print(type(foo.__annotations__["x"])) # <class 'types.UnionType'>
@crimson raft does tiz help?
no, the issue isn't the functionality part of my code
it's mypy throwing an error saying UnionType doesn't exist when i'm using 3.10 and types.UnionType exists
there's also this, which mypy tells me OptionalString is not a valid type
def help(self, cmd_name: OptionalString = None) -> None:
OptionalString = str | None
i guess u could use a help channel, discussion channels normally take longer for some1 2 ans
yeah i did earlier and got not response lel
i'm fine waiting here if more people who know about type checking look in here rather than help channels
just ask gain n try rephrasing your question
i could workaround and go back to typing.Union for both of my errors and check the underlying type of that but it's not really what i'd like to do
since i had this working perfectly fine for 2-3 days until tonight for some odd reason
changed nothing about the typing, mypy just started complaining although i'm definitely using 3.10 & mypy is installed under 3.10
Sounds like it could be a mypy or typeshed bug.
lol u r finally here
Ok it's defined in typeshed:
https://github.com/python/typeshed/blob/master/stdlib/types.pyi#L395
stdlib/types.pyi line 395
class UnionType:```
@crimson raft
well i don't know what to do with that information lol
sure it's defined, and it was defined for the past 2 days for me 
Either the copy of typeshed bundled in mypy is missing it, perhaps mypy is failing to handle sys.version_info >= (3, 10), or there's something else. Did you update mypy or something?
i did not
but i've reinstalled it in case it was some bug
is there any way i can debug the sys version for mypy?
OptionalString = str | None
def foo(x: OptionalString = None) -> None:
pass```
cause this is an example of my other issue
this should be a valid type alias in 3.10
but it gives me:
uh, i guess installing the latest git version of mypy seemed to solve it?
awkward.
just ping him
why does mypy gimme tiz error List or tuple expected as variable arguments? @pastel egret
For what line of code?
like
def foo(layout: Any, widget: Any, coords=Optional[Tuple[int, int]]) -> None:
layout.addWidget(widget, *coords)
smth like tat
not really sure how to shorten @pastel egret
nvm
solved it maself
I would recommend the use of typing.get_origin() instead. Then you can do is typing.Union
At least how I've done it Infernum
Didn't know they added UnionType though, that's interesting
I'm pretty sure mypy doesn't support type aliases using the new syntax yet
hey, just wondering, whats the difference between func.__annotations__ and typing.get_type_hints(func)?
!d typing.get_type_hints
typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)```
Return a dictionary containing type hints for a function, method, module or class object.
This is often the same as `obj.__annotations__`. In addition, forward references encoded as string literals are handled by evaluating them in `globals` and `locals` namespaces. If necessary, `Optional[t]` is added for function and method annotations if a default value equal to `None` is set. For a class `C`, return a dictionary constructed by merging all the `__annotations__` along `C.__mro__` in reverse order.
The function recursively replaces all `Annotated[T, ...]` with `T`, unless `include_extras` is set to `True` (see [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated "typing.Annotated") for more information). For example:
This only works correctly on 3.10 afaik
It doesn't evaluate on any other version
Also personally the Annotated[T, ...] is a deal-breaker for me
Just use typing extensions
I think what happened is that it got renamed from types.Union to types.UnionType somewhere late in 3.10 development (like the RCs). The last mypy release might have had its typeshed cut before we fixed the name in typeshed.
get_type_hints does a bunch of processing, most notably evaluating forward references
the recommended way to get annotations going forward is to use inspect.get_annotations cause it isn't as opinionated as get_type_hints
SQLResult = tuple
SQLResults = list[SQLResult]
def execute(
self, query: str, *args, fetch_all: bool = True
) -> SQLResults | SQLResult:
with self.connection as cursor:
result: Cursor = cursor.execute(query, args)
if fetch_all:
return result.fetchall()
return result.fetchone()
def get_rows_by_table_name(self, table_name: str) -> SQLResults:
return self.execute(f"SELECT * FROM {table_name}") # Incompatible return value type (got "Union[List[Tuple[Any, ...]], Tuple[Any, ...]]", expected "List[Tuple[Any, ...]]")```
am i doing something wrong here? thought i was able to do this
will look into this, ty
you need to check the type of the return for that to work
ah really it doesn't infer that i'm inherently passing True ?
well ok you could use overloads to make this work
@overload
def execute(
self, query: str, *args, fetch_all: Literal[True] = ...
) -> SQLResults: ...
@overload
def execute(
self, query: str, *args, fetch_all: Literal[False] = ...
) -> SQLResult: ...
def execute(
self, query: str, *args, fetch_all: bool = True
) -> SQLResults | SQLResult:
with self.connection as cursor:
result: Cursor = cursor.execute(query, args)
if fetch_all:
return result.fetchall()
return result.fetchone()
notice how the return type changes based on the literal value of fetch_all
!d typing.overload
@typing.overload```
The `@overload` decorator allows describing functions and methods that support multiple different combinations of argument types. A series of `@overload`-decorated definitions must be followed by exactly one non-`@overload`-decorated definition (for the same function/method). The `@overload`-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-`@overload`-decorated definition, while the latter is used at runtime but should be ignored by a type checker. At runtime, calling a `@overload`-decorated function directly will raise [`NotImplementedError`](https://docs.python.org/3/library/exceptions.html#NotImplementedError "NotImplementedError"). An example of overload that gives a more precise type than can be expressed using a union or a type variable:
mypy should support PEP 613 on latest master
any way I could write this better? Union[Gallery, List[Gallery], Shelf]
i think Union[Gallery, List[Gallery]] is an anti-pattern in a lot of cases
oh cool
how to use variadic tuples?
i have this code:
T = TypeVar('T')
class DataClass(Generic[T]):
def read(self, buf: Buffer) -> T: pass
def write(self, buf: Buffer, obj: T) -> None: pass
class Sequence(DataClass[tuple[T, ...]]): # what to write here?
def __init__(self, *dclss: DataClass[T]) -> None: pass # what to write here: `*dclss: ???`
def read(self, buf: Buffer) -> tuple[T, ...]: pass
def write(self, buf: Buffer, obj: tuple[T, ...]) -> None: pass
s = Sequence( # mypy error: Cannot infer type argument 1 of "Sequence"
DataClass[int](),
DataClass[str](),
DataClass[bytes](),
)
# I expects:
s: Sequence[tuple[int, str, bytes]]
s.read(...) # -> tuple[int, str, bytes]
x: tuple[int, str, bytes] = (0, '', b'')
s.write(..., x)
# I got:
reveal_type(s) # Sequence[Any]
reveal_type(s.read(...)) # tuple[Any]
# this is ok:
s2 = Sequence(
DataClass[int](), # same types
DataClass[int](),
DataClass[int](),
)
reveal_type(s2) # Sequence[int]
reveal_type(s2.read(...)) # tuple[int]
I dont know how to use variadic tuples such as (int, str, bytes) so that mypy doesnt go crazy
ok, thanks :(
does mypy supports it?
wdym by anti pattern?
bad practice?
or common mistake?
a sign of possible bad or confusing design
what should I use then?
it depends - why do you want to support both cases?
most of the time, the List[Foo] version is just a list comprehension over a list of Foos
if nothing else, it's probably a better idea to have Sequence[Foo] (from collections.abc), which allows the user to pass in a tuple, ordereddict, numpy array, whatever
so I'm better off just typehinting it as a list
why is that?
or prolly I misunderstood
it really depends on the specifics of your application
but it's rare that your code requires a list specifically
often you just need an Iterable
if you explain what the function does and why you wanted Foo | list[Foo], maybe i can give more specific advice
What's the difference between this and singledispatch from functools
singledispatch operates at runtime, overload doesn't actually change how your function behaves - it's used to tell a type checker how it does behave (using if isinstance(...) or something), so it can follow along.
as stated over here
i will hv to drop <3.9
or remove the error:
BeartypeDecorHintPep585DeprecationWarning: PEP 484 type hint typing.Tuple[int, int] deprecated by PEP 585 scheduled for removal in the first Python version released after October 5th, 2025. To resolve this, either drop Python < 3.9 support and globally replace this hint by the equivalent PEP 585 type hint (e.g., "typing.List[int]" by "list[int]")
by doin these
Hide warnings. The middle-finger way is to just squelch all deprecation warnings with an ignore warning filter targeting the BeartypeDecorHintPep484DeprecationWarning category. On the one hand, this will still fail in 2025 or 2026 with fiery explosions and thus only constitutes a temporary workaround at best. On the other hand, this has the obvious advantage of preserving Python < 3.9 support with minimal to no refactoring costs. The two ways to do this have differing tradeoffs depending on who you want to suffer most โ your developers or your userbase:
# Do it globally for everyone, whether they want you to or not!
# This is the "Make Users Suffer" option.
from beartype.roar import BeartypeDecorHintPep484DeprecationWarning
from warnings import filterwarnings
filterwarnings("ignore", category=BeartypeDecorHintPep484DeprecationWarning)
...
# Do it locally only for you! (Hope you like increasing your
# indentation level in every single codebase module.)
# This is the "Make Yourself Suffer" option.
from beartype.roar import BeartypeDecorHintPep484DeprecationWarning
from warnings import catch_warnings, filterwarnings
with catch_warnings():
filterwarnings("ignore", category=BeartypeDecorHintPep484DeprecationWarning)
...
umm
can someone explain to me?
i honestly dun understand wat is happening
How can I check if an object matches a type?
In general Python? isinstance
Like ```py
check_type(typing.List[int], [1])
True
check_type(typing.List[int], ["foo"])
False```
!e py print(isinstance([1], list[int]))
@solid light :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 1, in <module>
003 | TypeError: isinstance() argument 2 cannot be a parameterized generic
Hmm, not sure
How is this a bad work-around if it will work for several years?
That only works on 3.9, that's the thing
Unfortunately the various typing classes won't actually do runtime checks. You have to do it manually - in this case the simplest way would be all(isinstance(x, int) for x in somelist).
they used to but i dont think they liked the runtime complexity for it
Thanks
In general that's impossible. Like, how do you check if an object is Callable[[int], str]?
But you can write a function with a few special cases. Or steal some (gnarly) code from pydantic or dataclass-factory
Also, you can't really check if an object is List[int]. What if you save it and someone adds a string to it later?
copy it :^)
Check if an object is Callable[Ps, T] by simply making a new copy of the universe and applying any side-effects to that universe
Thanks, got it ๐
I have a TypeVar that looks like this: ```python
C = TypeVar('C', bound='Callable[[Event], Coroutine]')
But I need `Callable[[EventSubclass], Coroutine]` to be able to be passed here
The issue is that if I make it covariant my decorator that takes this callable and returns it again doesn't work
If I make it contravariant then I can't return it
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
can you make the Event be the typevar?
E = TypeVar('E', bound='Event')
C = TypeVar('C', bound=Callable[[E], Coroutine])
idk if this works
also what exactly does the decorator return? maybe you want to have it return a concrete type anyway
Well it returns the same function
ah ok, that's what i was wondering
Hmm, doesn't seem like it https://mypy-play.net/?mypy=latest&python=3.10&gist=0cc2d7fa8deeccee6451e9fbee832c8f
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
i tried that and it didnt work
is it common to reuse the same TypeVar in unrelated function definitions?
sure. usually you'd define it in one module and only use it there though
welcome to the club buddy
oh god
kill it with fire
I mean, I'd argue it's Python's fault
I don't know other languages that require declaring typevars like that
i agree that TypeVar is not ideal
okay, I admit - in this case I'm just lazy ๐
But it's pretty easy (one line) to just declare it when you need it. Having lots of obscure names like RX3 in your interface is going to be confusing for users
def func[T <= SupportsAbs](x: T) -> int: ... when?
when you write a PEP ๐
Pradeep had a slide proposing this at the typing summit earlier this year. I think everyone involved in typing will think it's an improvement, but somebody actually needs to push it through.
yeah wasnt that with <T> though?
Also, it will require new syntax, so it may be hard sell to the steering councl
Maybe, I don't care too much for the precise syntax
it's also easier to extend to selecting an overload at runtime
like you could write func[float](2.0) but func<float>(2.0) would be backward incompatible
yeah, rn it would mean (func < float) and (float > 2.0)
neither are syntax errors though so thats atleast good
how do you make the second one work, though?
the angle brackets one? that would require some really weird __lt__ implementation
yeah
or a parser hack
I'm not sure you can make it threadsafe, generator-safe etc.
I'm actually not sure how to make typevars on the fly and maintain type annotations being available at runtime...
and also not make it ugly
def foo(x: list[T := TypeVar("T")]) -> T: would work today ๐
though I think there was talk of disallowing walrus in type annotations
class Base[T]:
...
class Child[T, S](Base[T]):
...
```this is kinda gross with the subclass
anyways ill put this on the long list of peps that will never happen
"in Python 3.28 we decided to take the Go path and removed all generics!"
Someone just asked how to get started adding types to a project I work on so it occurred to me to offer if anyone is interested or wants practice with this: https://github.com/bpython/bpython/issues/892#issuecomment-953232840
Is there a way to typehint type aliases? e.g., we have a lot of stuff like this for some business logic (to help with knowing what values exactly are being passed around where):
# I really want this docstring to show up when someone hovers over the below type alias
SomeBusinessLogicType = float
