#type-hinting
1 messages Β· Page 73 of 1
@trim tangle You suggested a protocol but I'm having some trouble. Would appreciate advice.
I'm just gonna accept that the slice overload shouldn't be there for now.
Not sure if my protocol approach is correct but at least it works with a tuple.
Maybe make T covariant?
HashableSequence[C] isn't a subtype of HashableSequence[B] because ``HashableSequence` is invariant
https://peps.python.org/pep-0593/ where is valuerange from?
It is just an example usage, ValueRange doesnt actually exists
Yeah, that fixes it. At one point pyright was telling me to make it covariant, and later it said it should be invariant, and now covariant doesn't complain. Not sure what changes I made since then to make it stop complaining about covariance.
Granted, I'm still not sure if a Sequence requires slicing or not.
According to typeshed it does
Thanks. I tried to look for that but had trouble finding it.
good day guys, what is the shortcut for this please?
as i type my command, it shows this, but ctrl+space shows a different hint.
How to tell a generic type is a subclass of some existing class?
probably T = TypeVar("T", bound=SuperClass)
yes
Quick question
class Base(object):
def method(self, argument: int) -> None:
...
class Derived(Base):
def method(self, argument: str) -> None:
...
Is it bad practice to have methods of the same name but different signatures on a derived class and its base?
Type checkers will complain about it. It violates the Liskov Substitution Principle
Pyright complains for me even if just reorder keyword-only arguments π
that would be a bug
Doesnt seem like it does π€
I remember it complaining so whenever I make a new project I automatically disable it
From when? I testing on a really old version of pyright xD
Also something to do with adding/removing keyword arguments even when **kwargs are already present
like 2 months ago at least
Humm, maybe they started complaining after whatever release I am testing with
In fact
just testing this with latest
class Foo:
def bar(self, *, a: int, b: str) -> None: ...
def baz(self, a: int = ..., b: str = ...) -> None: ...
class SubFoo(Foo):
def bar(self, *, b: str, a: int) -> None: ...
def baz(self, b: str = ..., a: int = ...) -> None: ...
and I get no erros
Which is weird since I should get an error on baz
do you have the right checks on?
I just did pyright file.py, do I have to enable some special flag?
I usually use mypy x)
you need reportIncompatibleMethodOverride to be on
or just --strict on the command line?
Ohh, I thought it just had everything on when running via cli
I tried that, it doesnt seem to have a strict flag like mypy
Aha, I got the error now, thank you
{
"strict": ["**"]
}
Luckily no bug reports came from missing that
Is there a way to annotate the return type of a base class method in the subclass? e.g. (something like the way @unkempt plover works)
What do you mean?
simplified version
class Base:
ec: Callable[[WebDriver], Any] #override in subclass
def __call__(self, driver: WebDriver) -> Any:
return self.ec(driver)
class Element(Base):
def __init__(self, locator, description: str):
super().__init__(description)
self.locator = locator
self.ec: Callable[[WebDriver], Union[bool, WebElement]] = EC.visibility_of_element_located(locator)
## I want to type hint that __call__ will return Union[bool, WebElement]
each subclass has a callable 'expected condition' ec that can return various things.. but the base class annotates Any. I'm curious if I can override the annotation in the subclass.
my hunch is the only way to do that is to completely override the method
you could make the base class generic
You would have to overwrite it directly otherwise, but you dont have to completely override it, annotating it should be enough
I think this is the best solution ^
I feel like I'm about to have my mind blown. How exactly do you do that?
__call__: Callable[[WebDriver], Union[bool, WebElement]] :P
annotation goes in the class body, but yeah generics would be better
wait.. you can just do that ?
Yup, it is just a name like any other, and I think now both mypy and pyright agree on self being omitted
just like you can at runtime do __call__ = lambda self: 5
I dunno why I didn't realize that was possible in the subclass as an override annotation
So I'll admit to knowing just enough about generics to know what you mean but not enough to feel confident in creating them.
@oblique urchin like this?
class Base(Generic[T]):
ec: Callable[[WebDriver], T] #override in subclass
def __call__(self, driver: WebDriver) -> T:
return self.ec(driver)
I think so, but I didn't really look at your use case closely, and callable instance fields are a can of worms with mypy
^^ that's what I'm afraid of. I barely feel confident in creating a standard generic
So (in theory) how would the subclass declare what T is?
class Child(Base[int]):
oh... neat
This can be a violation of open-closed principle. Best if the derived accepts argument of Union[str, int] instead.
Oh, good call
import tkinter as tk
from tkinter import filedialog, text
import os
root = tk.Tk()
canvas = tk.Canvas(root, height=700, width=700, bg="#263D42")
canvas.pack()
frame = tk.Frame(root, bg="white")
frame.place(relwidth=0.8, relheight=0.8, relx=0.1, rely=0.1)
root.mainloop()
is my scriot so far but it says tkinter cant be found or doesnt exist
I don't think this is type-hinting related, check out #βο½how-to-get-help for more general help
k
My API returns a response object like this
{
"response_code": "0",
"response_message": "Success",
"response": ...
}
Where response can be whatever response the api url returns. If one URL returns List[int] how do I generic'ify this object with TypedDict?
Something like ResponseWrapper[List[int]] kinda
So you would like a generic typed dict?
Yes, I want to make that object into a TypedDict but accept a generic and have "response" as T
you're in luck, 3.11 will have that
and typing-extensions will have it too if someone picks up https://github.com/python/typing/issues/1174
I'm spoiled from typescript, coming to python as req for this project at my work
Thank you
Is there anything I can use for now? Or just wait
I think it already has, at least it didnt throw a runtime error
oh, on what version?
4.2.0
of Python
Oh, 3.10, I thought you meant typing-extension versoin
oh nice, I thought it might be only on earlier versions of Python
I guess we forgot to disallow this in typing-extensions π
It probably wont be long before Pyright has it, I wouldn't be suprised if there is support for it in less then a week given the speed stuff happens there
https://github.com/microsoft/pyright/commit/74406b976dcc0889180030c119d059a1fbcd6257 seems like he did some of it
When I have a callable where the return doesn't matter am I supposed to use Any or object? I've noticed that I rarely use object and have Any everywhere instead
Actually it's similar in many other projects too
I think its a matter of semantics
As an example
class Thing():
attribute : None | str
def __init__(self, attribute: typing.Optional[str] = ''):
if isinstance(attribute, str):
self.attribute = attribute
else:
self.attribute = None
As a argument, attribute is optional
As an attribute through, attribute is not optional per say, it can just take on one of two types
So I find Any to be better in terms of intent. It means "this can return anything" whereas object says "this will return an object"
Which, naturally, an object will always be returned so it doesn't help much
Hmm... If you do that you might accidentally use that return value and do something nasty to it.
In TypeScript there's a void type just for this purpose.
Any type fits it, but you can't really use it.
I think you should use object because the type checker will catch an accidental use of the return value
I mean, I think it really comes down to what the callable actually returns
There aren't too many situations in which something really can return anything β __getattr__ comes to mind
But generally a callable is going to serve a purpose, and return something by definition
This example is unrelated
This is why we have Argspecs
I think ashlen is talking about accepting a callable argument
Yes, that's what I thought. However I generally see Any
I was unsure as to whether it's some unspoken rule
That's what I'm getting at. That callable is going to have a return type implicit to it and it should be possible to capture and forward that return type using the right generics
Any just turns off the type checker. You can do
x: Any
x += [{}]
x.get_out_of_here()
And the type checker thinks this is 100% ok.
So you should avoid using Any - in most cases object is more suitable
If it's some sort of callback, maybe just have it return None?
Ooh, I saw that too at places
but that seems even worse considering it's an arbitrary limitation
If it's a return type then I can understand but I don't like using it in parameters
Ohhhhh Python β€οΈ
Such a beautiful language
A many-layered onion wrapped in a finely tuned machine, wrapped in a song
Welp, now the question is whether there's any point in me refactoring my code to add as many objecs to my typehints
What exactly is the situation?
Can you tell more about your use case maybe? I think we may be talking about different things
def register(self callback: typing.Callable[..., typing.Any?]) -> None:
self.callbacks.append(callback)
The return doesn't matter at all to the event manager, it just needs to call the thing
None is limiting, Any is too arbitrary, object is too weird
from collections.abc import Callable
from typing import Concatenate, ParamSpec, TypeVar
P = ParamSpec('P')
R = TypeVar('R')
def register(self callback: typing.Callable[P, R]) -> None:
self.callbacks.append(callback)
Actually
I think using a typevar only once is illegal
If you don't need to capture and then forward the return type (example to follow) then you don't even bother using a parameterization of Callable
So its just
def register(self, callback: typing.Callable) -> None:
self.callbacks.append(callback)
I too thought object was weird at first. But it's the right type if you don't care what it is
Also, does the callback accept any possible arguments? π€
(Not very relevant but you might want to look at generics/ParamSpec in the future)
I recommend object if the return type is from the user or you don't know what it is
I use object for all user-provided callbacks. This way, if I do end up using it then it is catched by the type checker or I am forced to do sufficient isinstance() checks.
Wouldn't you use parameterization with an argspec and return typevar for this?
!e
Speaking of isinstance checks and LSP...
import yarl
print(yarl.URL("http://127.0.0.1").with_port(True))
@trim tangle :white_check_mark: Your eval job has completed with return code 0.
http://127.0.0.1:True
Apparently, if you communicate over this port you can only transmit truthful indormation π
If I returned what the user returned yes - but in this case it's stored in an attribute on my class.
I don't use the generics of it
Absolutely not. I want my project to be type-complete
What about the ... then?
If you want stricter typing, you might want to be more specific about the parameters
There's some dependency injection stuff going on
So while it technically takes in no arguments the function can be defined with multiple
Well, it's more of a tradeoff. Sometimes you could be more specific about the type, but that makes it more complex, especially for people who don't use typing at all.
I think typing.Callable is the same as typing.Callable[..., Any] but I might be wrong
Does it get transformed somehow perhaps?
Idk but I have my project type-complete and I ain't about to throw that away
If you can represent the transformations in typing that would be fab
I suppose? Not in a too consistent of a way
using a plain Callable is equally type complete as using Callable [..., Any]
Well, it should be
Idk whether pyright whines about it
Well in that case, if the callbacks really can take in any amount of arguments, they can only be typed as such
.
What do you mean by type-complete?
Something pyright made up
Ah
Well, I suppose there isn't a lot of benefit from typing if the library is dealing with very dynamic things and is often using Any
Pyrigjr still complains with --verifytypes about the ambiguity
Sure, it's the same thing, but the --verifytypes is extremely specifically about being explicit about public-facing types
btw guys idk if this is a pyright specific question but how the heck can I use the python wrapper for pyright without having it reinstall pyright ever time
It adds like 10s to my CI
Do you really need the python package in the CI? Maybe just run node? I suppose that might be faster
I don't know how you're running the CI but you should be able to cache container layers, right?
if I use npx it also reinstalls so idk
And it'd probs be a pain to get venvs working
Oh yeah that should be possible, I already use prettier in one of my workflows
so I have a hacky decorator that modify a function's signature, e.g. inject a default value
def inject_default(**kwargs):
def wrapper(func):
func.__kwdefaults__ = func.__kwdefaults__ or {}
func.__kwdefaults__.update(kwargs)
return func
return wrapper
@inject_default(a = 2)
def func(*, a: int):
return a + 1
is there any way to reflect that modification to type checker (pylance)?
Nope π
PS1 = ParamSpec('PS1')
PS2 = ParamSpec('PS2')
R = TypeVar('R')
def inject_default(**kwargs: PS1) -> Callable[[Callable[PS2, R]], Callable[Unpack[PS1, PS2], R]]:
def wrapper(func):
func.__kwdefaults__ = func.__kwdefaults__ or {}
func.__kwdefaults__.update(kwargs)
return func
return wrapper # type: ignore
@inject_default(a = 2)
def func(*, a: int) -> int:
return a + 1
``` idk how to use ParamSpec π
ParamSpec cant help here, the best it can do is maintain the same signature post "decoration"
dont think any type system in the world would be able to help here tbh
I'm looking through pydantic but I still don't understand what kind of magic did it use to display **data as field1: type1 = default1, ...
how do i correctly type hint an argument that is either a tuple of strings or an empty tuple? ()
tuple[str, ...]
bc length of 0 does fall under: "To specify a variable-length tuple of homogeneous type, use literal ellipsis"
?
if so, makes sense. was probably overthinking this
right, tuple[str, ...] is a tuple of any number of strings, and 0 is a number

Python Enhancement Proposals (PEPs)
oh so it's _dataclass_transform_ that does magic
thanks for the answer
Hello, everyone
Could anyone help me check something in pyright, please? I reported a bug which always happens for me but doesn't for the main pyright developer, but I can't figure out if something is wrong strictly on my end. I've tried all sorts of new, untouched environments, to no avail: the error is always there.
This is the issue: https://github.com/microsoft/pyright/issues/3431
And this is the code that I wanted someone to run through pyright 1.1.244 for me:
# pyright: strict, reportUninitializedInstanceVariable=error
from dataclasses import dataclass
@dataclass
class MyClass:
# error: Instance variable "y" is not initialized in the class body or __init__ method (reportUninitializedInstanceVariable)
y: int
Alternatively, if anyone has any idea of what could be causing the issue for me (and not for the main dev), I'd highly appreciate any hints =)
Yeah I get the same error, this does look like a bug
Thanks a lot!
oh, you even went the extra mile commented on the github issue =) Thanks!
Can someone explain what this means? And how to approach fixing it?
Expression of type "List[Self@Map]" cannot be assigned to return type "list[Map]"
TypeVar "_T@list" is invariant
Type "Self@Map" cannot be assigned to type "Map"
Map is the class I'm currently in
@classmethod
async def random(cls, amount: int) -> list[Map]:
"""Fetch a random amount of Map documents.
Args:
amount (int): Number of documents to fetch.
Returns:
List[Map]: List of Map documents.
"""
return (
await cls.find()
.aggregate([{"$sample": {"size": amount}}], projection_model=cls)
.to_list()
)
What i think is going on is that the random function returns a list of objects whose types are exactly Map, and not any subclass of Map
But the methods that you're using (maybe it's find or aggregate or to_list) return list[Self], which means they will return a list of objects whose type is that of whatever subclass has been used to invoke those methods
If you don't need to be able to modify that list, you might be able to get away by returning just a Sequence[Map], since a Sequence is covariant with the element type
Alternatively, maybe you could also return a list[Self] in the random function, in the same way that find seems to be doing it. I'm not sure if the Self type is already stabilized, but if it isn't I think the syntax would be something like:
T = TypeVar("T")
class MyClass:
async def random(cls: Type[T], amount: int) -> list[T]:
...
Thank you for the clear explanation! I wont be modifying the list so I used Sequence and it worked.
No more yelling from my type checker :-)
Self is stable (from typing_extensions import Self)
What does this error mean?
from collections.abc import Callable
class Wrap(Callable): # Argument to class must be a base class
# - Pyright
def __call__(self):
...
works fine during runtime
seems like a bug. It probably treats Callable as exclusively a special form
Interestingly pyright doesn't complain about inheriting from Union, which I'm pretty sure doesn't work at runtime
If I have a function that basically just wraps a method of an instance attribute but provides an argument or two (like functools.partial but on a method of an instance attribute). Is there a good way to typehint that without having to rewrite the entire signature again and again?
My best idea is a protocol class
Could you provide an example? I am not sure what you mean by method of an instance attribute
Perhaps you're looking for the new ParamSpec?
class CommonCommand:
interaction: Interaction
def shortcut(self, *args, **kwargs):
return await interaction.respond(type, *args, **kwargs)
I think yes, just don't know how to get it to work for what I need to do
In this *args, **kwargs, and the return type are all the same as Interaction.respond, just don't know how to typehint that without duplicating the entire signature
Do you have control over the Interaction class?
Yes but actually no
You'd need to make the command generic, probably also the interaction class.
I wrote the library
Yeah, you would need to make Interaction generic over the P ParamSpec and return of the method respond, then use those in the shortcut method, I think that would work
Hmm
I am double checking, I am not too sure
π
Honestly I'm probably just going to add the methods to Interaction, only issue is uh, I still don't want to duplicate the signature
And if possible would like to avoid making another one of my classes Generic
Could potentially also make Interaction here a protocol.
Hmm
Honestly I don't know enough to know how that would help
I'm just going to copypasta honestly
It'll get the job done I maintain the lib anyway and aren't planning any breaking changes to this so yeah
Unless I can find an easy solution
Then I can remove my other copypastas
Yeah if all you want is just copy the signature that should be the easiest, not sure how this can be achieved for on class in isolation
The signature is not even dependent on instantiation right?
I've already done it a couple times and it's always annoying when I change things, but I think I'm done with those types of changes now so I don't think my lib's going to change it
Nope?
It is just a TypeOf kind of operation you want
Sure?
It's like, uh
class Interaction:
async def respond(self, type: InteractionType, *, embeds: list[Embed], content: str) -> None:
...
class CommonCommand:
def __init__(self, interaction: Interaction) -> None:
self.interaction: Interaction = interaction
async def alias_respond(self, *, embeds: list[Embed], content: str) -> None:
return await self.interaction.respond(InteractionType.SUPER_LONG_NAME, embeds=embeds, content=content)
But with six or ten arguments instead of just embeds and content
from typing import *
P = ParamSpec('P')
R = TypeVar('R')
R_co = TypeVar('R_co', covariant=True)
class ProtoInteraction(Protocol[P, R_co]):
async def respond(self, type: object, *args: P.args, **kwargs: P.kwargs) -> R_co: ...
class Interaction:
async def respond(self, type: object, *, embeds: list[float], content: str) -> None: ...
class CommonCommand(Generic[P, R]):
def __init__(self, interaction: ProtoInteraction[P, R]) -> None:
self.interaction: ProtoInteraction[P, R] = interaction
async def alias_respond(self, *args: P.args, **kwargs: P.kwargs) -> R: ...
foo = CommonCommand(Interaction())
reveal_type(foo.alias_respond) # Type of "foo.alias_respond" is "(..., embeds: list[float], content: str) -> Coroutine[Any, Any, None]"
I think this does it? Not too sure what (..., embeds: list[float], content: str) means
the ... part x)
@clever bridge
I think it does
class RespondAlias(Protocol):
def __call__(
self,
*,
content: Missing[str] = quarrel.MISSING,
embeds: Missing[list[quarrel.Embed]] = quarrel.MISSING,
# allowed_mentions: Missing[AllowedMentions] = MISSING,
ephemeral: Missing[bool] = quarrel.MISSING,
# attachments: Missing[Attachment] = MISSING,
tts: Missing[bool] = quarrel.MISSING,
grid: Missing[quarrel.Grid] = quarrel.MISSING,
choices: Missing[list[Choice]] = quarrel.MISSING,
# modal: Missing[Modal] = MISSING,
) -> None:
...
class CommonCommand:
async def respond_with_message(self, *args: Any, **kwargs: Any) -> None: # type: ignore
return await self.interaction.respond(
quarrel.InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE, *args, **kwargs
)
respond_with_message: RespondAlias
This seems to work too
Ignore the indentation
Anywho, thank you for the help! I need to sleep before I fall over now so night! π
Ah it means kw only after it
How to typehint "an iterable of strings with a length of 20" or something like that?
You can call iter then next will work 20 times?
Something that returns 20 strings at a time is possible but what I just described isn't
The best way to express that would be to use Annotated
Only thing I can think of is tuple[str, str, str, ...repeat20times], but that's obviously not working for iterables in general
why do you need that?
why specifically 20, that is?
what's the benefit over just Iterable[str]?
Actually, it should be "an iterable of an object (let's say Foo) with a length below 20", useful if you're making a request to an API which limits objects sent
You cannot apply length constraints to types in python
Best you can do is tag types with a length param
Which I donβt think would be very useful here
Yeah that's not possible. That will need to be a runtime check.
Not everything needs to be specified at compile-time, especially very dynamic things that depend on business rules and user input.
You can do that in some languages (like Agda) but the costs are diminishing in most programs
I dont think you need dependent types for that, https://github.com/pschanely/CrossHair might give you somewhat the ability to do that, it uses a SMT solver under the hood, so if it anything like liquid haskell you should be able to give length constaints to your hearths desire
*hearths desire as long as it can find a solution x)
validating the length of an iterator is not that easy
Humm well Idk how the library works, but since it is an api call they would probably need to postulate that to CrossHair and then it should be able to use that as a tag that can be worked on
I am not sure though
is symbolic execution really that different from dependent types? π€
From my understanding symbolic execution gives you refinement types, which are a sort of dependent types but without the overhead that comes with them
Humm, the documentation is rather poor, but it seems it can do it
def gets_iterable() -> List[int]:
return list(range(30))
def uses_iterable(it: List[int]):
'''
pre: len(it) <= 20
'''
return None
def main():
'''
post: __return__ == None
'''
uses_iterable(gets_iterable())
return None
/tmp/main.py:19: error: PreconditionFailed: Precondition "len(it) <= 20" was not satisfied before calling "uses_iterable" for any inputmain()
i have a function that takes a dictionary(TypedDict) as a input and returns a new dictionary(TypedDict) that extends over the previous one by adding some keys in it. my static type checker is throwing out errors when i am annotating the copy of the copy of the dictionary with the second TypedDict. how do i resolve this
why cant i send screenshots here?
https://discord.com/channels/267624335836053506/696888596006830201 please help here
TypedDicts aren't currently valid bounds (atleast in mypy) afaik this isn't expressible in a good way without an intersection type
how do i define a intersection type then?
to be more explicit, what is an intersection type?
however mentions the proposed semantics of them
cool, so i cant deal with this anyhow?
i can only #pyright: ignore the error then?
oh actually ignore everything ive said
just do ValidatedDoc(valid=True, exceptions=[], **doc)
that should work
Interesting that pyright can figure out the class name from type() class construction, but doesn't detect the parameters/functions passed into it as __dict__
is this a wontfix problem for pyright, or is it a bug?
I'd bet it is a wontfix. Pyright probably does no special-casing for type() construction
Probably a wontfix, I am surprised that this even works x) It would be nice if pyright had it though, not for that but for capturing kwargs
Although, I guess it may be able to do something with dataclass_transform?
Technically that dictionary argument can be interpreted kind of like attrs/pydantic/dataclasses does kwargs?
Might be a stretch π€·ββοΈ
its not figuring out the name from the string there is it?
isnt it just using the name of the variable?
well, if the string is named anything else except what the variable is named, it shows Type[_] so it does seem to do something with it
weird
huh
must just use the same thing as TypeVars?
it was probably just the playground being slow
yeah, Foo is working too now in my environment
so, the name seems to get picked up from the string properly
name = "A" + "B"
TestCls = type(name, (), {})
reveal_type(TestCls) # "Type[AB]"
Good job pyright x)
I tried giving a typeddict as the namespace param to see if it work but you cant give it because it expects a dict[str, Any]
How can i type re.match.groupdict() dictionary? docs say it now support '[]' but i found nothing that can be useful.
can you show more code (as text) perhaps?
the return value of groupdict is a dict (dict[str, str | Any] as you can see), the documentation about Match and Pattern isn't very relevant
oh then i will directly create a instance of LinkedDoc
what is LinkedDoc?
a type
gimme a min
ill be copyinh pasting code
linked_doc = i.split(":")[1].strip()
reg = re.compile(
r"^(?P<doc_no>-?\d+)\/(?P<doc_year>\d+)\s*of\s*SRO\s*(?P<sro_code>\d+)$"
)
searched = reg.match(linked_doc)
if not searched:
raise ValueError(
f"could not parse doc field for revoking doc, {repr(linked_doc)} does not conform to the format that the regex {reg.pattern} matches on. If this appears frequently, try adjusting the regex or check if the input data is really a valid format"
)
temp_data_dict["revokes_docs"].append(searched.groupdict()) # type: ignore
this is the code block
class LinkedDoc(TypedDict):
"""Represents a linked document"""
doc_no: int
doc_year: int
sro_code: int
the type LinkedDoc a TypedDict
ah, well in that case you might want to just do a # type: ignore.
type checkers aren't that smart
i.e. they can't inspect regular expressions
Hmmm wait, the type is not quite right. all attributes of the dict will be strings, not integers @livid cypress
yep yep got that
i did this
...append(
LinkedDoc(
**dict(
map(
lambda x: (str(x[0]), int(x[1])),
searched.groupdict().items(),
)
)
)
)
and the error was gone
what else can i do instead of that?
# type: ignore
that was what i was doing earlier
encountered an error deep down where this code block was a dependancy
thought of fixing it in a better way
haha
Another option would be to make a dataclass
@dataclass(frozen=True)
class LinkedDoc(TypedDict):
doc_no: int
doc_year: int
sro_code: int
then do ```py
.append(LinkedDoc(
doc_no=int(searched["doc_no"]),
doc_year=int(searched["doc_year"]),
sro_code=int(searched["sro_coe"]),
))
generally, if you have a fixed set of fields, a dataclass is better
TypedDict is more for specifying existing APIs that use dictionaries
aha that makes sense
The reason the error is gone is because this code confuses type checkers to the point where they give up
shouldve used dataclasses haha
ignore all this for a moment, what is that re.Match thing though?
what does [] mean
re.Match is the object that re.match and re.search return
i know the slicing use and it being used as generic type acceptor
but how do i use it here?
!e
import re
print(re.match(r"(foo)(bar)", "foobar"))
@trim tangle :white_check_mark: Your eval job has completed with return code 0.
<re.Match object; span=(0, 6), match='foobar'>
you're already using this object in your code
but you don't need an explicit type annotation
Unrelated to typing, but I would remove this docstring ```py
"""Represents a linked document"""
[] means that you can do re.Match[str] to mean "a match on a str pattern"
!e
because I believe you can match on bytes as well
import re
print(re.match(b"(foo)(bar)", b"foobar"))
@trim tangle :white_check_mark: Your eval job has completed with return code 0.
<re.Match object; span=(0, 6), match=b'foobar'>
yep
damn
if opcode == GatewayOpcode.DISPATCH: β Condition will always evaluate to False since the types "Literal[0]" and "Literal[GatewayOpcode.DISPATCH]" have no overlap
where GatewayOpcode is an enum.IntEnum subclass
pyright strict, works in repl
>>> from enum import IntEnum
>>> class MyEnum(IntEnum):
... h = 0
...
>>> 0 == MyEnum.h
True
That does sound like a bug although I'm not sure where
Yeah it's a bug in pyright and not in typeshed afaict
Anyone give me the proper way to typehint that a function returns a list of tuples, pleeeease??
-> list[tuple[some_type, some_other_type]]
thanks, I tried that and got
def google(self, query, max_results = 10, lang = "en", proxies = {}) -> list[tuple[str, str]]:
TypeError: 'type' object is not subscriptable
upgrade to 3.9 or use from typing import List, Tuple instead
right right, I'm using 3.10 .. had a dumb moment and forgot the imports, thank you
on 3.10 you can just use list and tuple lowercase
I don't know why but I keep getting that TypeError when I do it that way
either you're not using 3.10 or you're shadowing the list and/or tuple name
I'm definitely using python 3.10.4, but I have to import and use the uppercase
I'm using list and dict now
would it have somethng to do with the language server it's configured to use in my IDE?
I use vscode and the jedi lang server, and I can't use matchcase with jedi, only if I change the language server to pylance can I use matchcase
add print(__import__('sys').version_info) to your script
it printed this ->
sys.version_info(major=3, minor=8, micro=10, releaselevel='final', serial=0)
I don't know what it means
It means you're running your program in 3.8
3.8.10 to be precise
Try running python3.10 script_name.py
Maybe you aren't activating a venv then
I use pipenv on this project, and just activated the venv
get the same sys info response
and I can use matchcase, which is 3.10 but only if I change my language server from jedi to pylance
The language server doesn't effect how your code runs
no, but it effects how the ide plugins take your code
and I can't use matchcase from 3.10 without changing my language server because jedi hasn't updated their engine or something like that
if I use it with jedi I get red files that I couldn't run if I wanted to
hey all, I'm trying to type a function that receives a response object (doing web scraping), and I'm not sure how to type the input parameter. the parameter is a response object from requests, when I do type(res) I get <class 'requests.models.Response'> does that mean I should add the following annotation in the function signature? def normalize_response(res: requests.models.Response) -> list: or how should I do it exactly?
As long as that is the only type of object it's receiving that looks good to me! Though you should specify the type of the items in the returned list.
awesome, I'll do that. thx @leaden oak
Pycharm bug?
Since you're on 3.10, yeah.
Hm, where can I follow the progress on generic typed dictionaries?
Runtime support is in 3.11. There is an issue on python/typing for typing-extensions support. Type checkers all have their own process, I think pyright already supports it
Yup
from typing import *
from typing_extensions import TypedDict
T = TypeVar('T')
class A(TypedDict, Generic[T]):
foo: T
c: A[int] = {'foo': 42}
e: A[int] = {'foo': '42'} # "str" is incompatible with "int" (reportGeneralTypeIssues)
Ah, I see
Then I suppose I am waiting on runtime support on older versions (if possible π¬)
Does this not mean it is essentially supported at runtime through typing_extnestions?
...: a: int
...:
Traceback (most recent call last):
File "/main_instance_shell/jelle/venv3.9/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3397, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-21-eac8c22158fe>", line 1, in <cell line: 1>
class TD(TypedDict, Generic[T]):
File "/main_instance_shell/jelle/venv3.9/lib/python3.9/typing.py", line 1947, in __new__
raise TypeError('cannot inherit from both a TypedDict type '
TypeError: cannot inherit from both a TypedDict type and a non-TypedDict base class
which version of typing-extensions?
4.2.0
Python 3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing_extensions import TypedDict
>>>
>>> from typing import Generic
>>>
>>> class A(TypedDict, Generic): ...
...
>>>
interesting, I was on 4.1.1 but it indeed works on 4.2. Not sure what we did to make it work
π awesome!
def foo():
async def wrapper() -> int:
return 1
return wrapper
How do I type foo?
typing has Callable used to refer to function types
!d typing.Callable (bot is case sensitive)
typing.Callable```
Callable type; `Callable[[int], str]` is a function of (int) -> str.
The subscription syntax must always be used with exactly two
values: the argument list and the return type. The argument list
must be a list of types or an ellipsis; the return type must be
a single type...
Callable[[], Coroutine[]]? or what i'm confused since the docs have parameters and my functions don't
Callable without arguments is fine, but at least one of the arguments in question would apparently be Awaitable
https://stackoverflow.com/a/71132186
pylance's type linter set to strict-mode does not yell at this:
from typing import Callable, Awaitable
def func() -> Callable[[], Awaitable[int]]:
async def wrapper()-> int:
return 1
return wrapper
it doesn't like just def func() -> Callable:, but that's why it's called strict mode. other devs will be fine
def wrapper() -> Callable[P, Awaitable[T]]:?
the stackoverflow is for a decorator, which isn't quite what you're doing, but it does have the form returning await functions. the P and T are just generic variables and not relevant to your case
maybe it's not the best example
nextcore/gateway/shard.py: error: Name "IdentifyConnectionProperties" is not defined [name-defined]
mypy v0.950
Theres no line number... and that class doesn't exist in that file at all.. however iirc it does exist in https://github.com/Bluenix2/discord-typings which I use.
seems to not error on pyright however
hello everyone! Is there anyone with knowledge of machine learning?
I want to learn about logic implementation with machine learning in python
this is the type hinting channel, you want #data-science-and-ml
Why is every mypy issue like that π
alright seems to be fixed by removing the final wrapper around a typed dict... weird. This should not be happening?
Might be due to the fact that mypy doesnt support final typed dicts? The message wouldnt not be that in that case though so not sure
There is a different error for them usually, however it seems to be defined in a unusual way (https://github.com/Bluenix2/discord-typings/blob/main/discord_typings/gateway.py#L44-L53) so mypy maybe doesn't catch it? Not sure.
discord_typings/gateway.py lines 44 to 53
# The leading dollar sign makes this an invalid attribute in Python so we need
# to use this way of defining typed dicts.
IdentifyConnectionProperties = final(TypedDict(
'IdentifyConnectionProperties',
{
'$os': str,
'$browser': str,
'$device': str
}
))```
that looks like it would really confuse mypy
though I don't see the "name not defined" error: https://mypy-play.net/?mypy=latest&python=3.10&gist=c11c8d4e1450b73e370903e47f97353d
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
it just sees it as a normal function call
I think it's a Callable[[], Coroutine[NoReturn, object, Literal[1]]
func()().send(None) raises StopIteration(1)
Callable[[], Awaitable[int]] would be more practical
Depends what it's used for
What a shame, 'cus that's just how decorators work. There's no other way as far as I know.
How do I type hint for instance of a class?
def repo_path(repo, *path):
return os.path.join(repo.gitdir, *path)
``` Here, `repo` is an instance of a class `GitRepository`. How do I typehint it?
does repo: GitRepository not work?
PyRight gives this error
even though GitRepository is defined
Well if the type checker is complaining: no, no it isn't.
The issue isn't how you have written, it is how you define GitRepository. Can you show where that is?
alright. silly mistake, It was defined below this function definition
I moved the function below and it does not complain
it wasn't the problem this time, but in future cases: your pyright error is the same error it gives if you use a class as a type hint inside the same class.
from __future__ import annotations fixes that problem via forward references
For declaring a function argument to only accept say 2 different string values, would you still annotate that argument with Literal['str1', 'str2'] or is there a better way to do so?
If the return is of the same type for both strings yes, otherwise an overload
an enum
It depends β’οΈ
Consider making an Enum
Sometimes there are more options, like the Strategy or Adapter pattern.
Maybe tell more about your function?
I had thought about using an enum first but thought it was easier to just use strings. I'm making a decorator which checks an instance attribute against the argument passed in and either raises an error or passes on with the function
Can you show the code?
Sure
def pipeline(name: Literal["non_biological", "biological"]):
if name not in ("non_biological", "biological"):
raise ValueError(f"{name} is not one of ('non_biological', 'biological')")
def decorator(func):
def wrapper(self, *args, **kwargs):
if name != self.pipeline:
raise FunctionNotCompatibleError(func.__name__)
ret = func(self, *args, **kwargs)
return ret
return wrapper
return decorator
You don't need to check name and raise the ValueError. The reason you're using the type hints is so that the compiler checks that for you
And since it's a decorator, you will probably know the value of name in compile time anyway
Also, it might be the case that you just need two different classes, one that does non_biological pipelines, and another that does bilogical pipelines. then you can just have each class have the methods that it supports, undecorated =)
Thanks. Will remove the name checking. We currently have it with two different classes but there is a lot of duplicated code between them with some minor differences which is why we are adding them all into one class and marking the differences if we can't make subtle changes to the functions to accompany both
Why not use good old inheritance?
Something I'm working on. With that thought though, I have a class with most of the shared functions and I am subclassing that with just a pipeline class. The idea here was to use that decorator to distinguish between the two different pipeline methods. Would it be better to subclass them into the two different pipelines and then have a final pipeline class which subclasses both of those since we want just 1 class.
βββ β Biological
/
Shared Pipeline
\ /
Non-biological
I mean, if you need to have all the functionality in a single class then I am not sure what the benefit is of having a Biological and Non.. if you are only going to use the Pipeline class
One thing I would suggest though it also make the Pipeline class generic over the two options
That would give you two types with the same class, which is kind of what you are doing via the decorators
from __future__ import annotations
from typing import *
T = TypeVar('T', Literal['biological'], Literal['non_biological'])
class Pipeline(Generic[T]):
def __init__(self, pipeline: T):
self.pipeline = pipeline
def bio_method(self: Pipeline[Literal['biological']]): ...
def nonbio_method(self: Pipeline[Literal['non_biological']]): ...
bio = Pipeline('biological')
nonbio = Pipeline('non_biological')
bio.bio_method()
bio.nonbio_method() # Erros
nonbio.bio_method() # Erros
nonbio.nonbio_method()
That way if you have a function that accepts just on type of pipeline, you can mark as doing so
Interesting. I've not played around with generics yet but this sounds like a decent alternative to the decorator. Thank you
You might want to combine both as this only gives you a type warning, while the decorator only gives you a runtime warning
That is, if you want the runtime checking
you can go with Protocol typing for this, if the Pipeline is requiring the classes that are not using inheritance to implement functions it can use
like this
your protocol would just define the interaction/method calls it would make to the two objects "bio" and "non_bio" from the pipeline
although with this, you'd be passing off most of the execution to the "bio" and "non_bio" class, unless they have generic way of processing in the pipeline
Idk how mypy and pyright play with protocol typing tho
@verbal spoke just had a good idea and suggested this. As it is cleaner imo.
Only thing is the your "pipeline" class will require you to pass in the "Bio" or "NonBio" each time
class Foo:
def __init__(self) -> None:
self.allowed: set[str] = {} # Cannot assign member "allowed" for type "Foo"
``` Is this supposed to be happening?
Ah, doing ```py
class Foo:
def init(self) -> None:
self.allowed: set[str] = set()
yep, {} is a dictionary π
I get burnt by this often
why doesn't mypy let me use types.AsyncGeneratorType as the return type for an async generator function?
https://mypy-play.net/?mypy=latest&python=3.10&gist=2b1354a121b1d5c10f6eea967319fec9
The mypy Playground is a web service that receives a Python program with type hints, runs mypy inside a sandbox, then returns the output.
Accidentally posted in the wrong channel
class typing.AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra])```
An async generator can be annotated by the generic type
`AsyncGenerator[YieldType, SendType]`. For example:
```py
async def echo_round() -> AsyncGenerator[int, float]:
sent = yield 0
while sent >= 0.0:
rounded = await round(sent)
sent = yield rounded
```...
Nope typing.AsyncGenerator defines __anext__ as () -> Awaitable
ah
I've been thinking about this and I am not sure whether that should change.
An AsyncIterator can rightfully have it defined as Awaitable, but for an AsyncGenerator we should be able to know that it is a Coroutine
Hello! I tried using a type alias as an annotation and flake8 flagged it as invalid syntax. I had it typed (and working) like so:
async def say(ctx: cctx | sctx | Channel,
description: str,
components: ActionRow | Button | SelectMenu | list[ActionRow] |
list[Button] | list[SelectMenu] | None = None,
hidden: bool = False) -> Message:
"""Post a message in an Embed."""```
However, that long components type union is repeated all over the place and I wanted to save myself the copy-pasting, so I tried doing this:
```py
Components = ActionRow | Button | SelectMenu | list[ActionRow] | list[Button] | list[SelectMenu] | None
async def say(ctx: cctx | sctx | Channel,
description: str,
components: Components = None,
hidden: bool = False) -> Message:
"""Post a message in an Embed."""```
Flake8 doesn't like this, though, and marks `components: Components` as an invalid syntax (E999). I also tried
```py
Components: TypeAlias = ActionRow | Button | SelectMenu | list[ActionRow] | list[Button] | list[SelectMenu] | None```
and
```py
Components = TypeVar("Components", ActionRow, Button, SelectMenu, list[ActionRow], list[Button], list[SelectMenu], None```
but flake8 flags them the same way. Am I doing something wrong, or is my linter mistaken?
I don't see the error, try running python on the file and it should give you a more precise SyntaxError
... LOL! The terminal returned this:sh File "C:\path\to\file.py", line 75 components: = None, ^ SyntaxError: invalid syntax
Which hinted me towards my classic problem of forgetting to hit CTRL+S in VSCode to refresh the linting.
Clearly I'm picking up some habits from doing Java on IntelliJ.
Thanks, Jelle!
Note that you can enable auto-save if you wish to π
O_O WHAT that's AMAZING I'm Googling this RIGHT NOW
AsyncGenerator is the abc for things that want to implement that interface types.AsyncGeneratorType is the concrete type of what async def async_gen_fn(): yield returns
So I think it's a mypy bug that it gets rejected
Isnt that just as much of a bug as this though?
import types
def foo() -> types.FunctionType:
def bar(): ...
return bar # error: Incompatible return value type (got "Callable[[], Any]", expected "FunctionType")
I think most types from the types modules arent "supported"
Humm a few actually worked
from types import *
class A:
def foo(): ...
def foo():
yield
a1: NoneType = None # Error
a2: FunctionType = foo # Error
a3: GeneratorType = foo() # Ok
a4: CodeType = foo.__code__ # Ok
a5: MethodType = A().foo # Error
a6: BuiltinFunctionType = len # Error
a7: WrapperDescriptorType = object.__str__ # Error
a8: MethodWrapperType = object().__str__ # Error
a10: NotImplementedType = NotImplemented # Ok
a9: MethodDescriptorType = str.join # Error # Ok
a11: ClassMethodDescriptorType = dict.__dict__['fromkeys']
a12: GetSetDescriptorType = A.__dict__['__dict__'] # Ok
a13: MemberDescriptorType = type.__dict__['__itemsize__'] # Error
hey guys, not sure this is the right channel for that question,
but anyone might know how can i convert a google.cloud.pubsub_v1.types.PullResponse into a python dict or json?
This isn't really the right channel but since it's probably a protobuf use google.protobuf.json_format.MessageToJson/Dict
hmm ok, thanks ill look into that π
As far as I understand, there's a lot of types in the typing module that can be considered "internal compiler stuff", and are by design not recognized by the type checkers (e.g.: here's the author of pydev talking about MethodType: https://github.com/microsoft/pyright/issues/2524#issuecomment-958184499)
If they are not mentioned in any PEP, they are probably not for use by normal code.
Yeah most of them I dont see how any value would be added by supporting them in real code
Other then for consistency, one is not wrong to expect those to work Imo, but then you have stuff like types.UnionType, and types.GenericAlias which start breaking things
unrelated
What is the point of Any | None?, I see in typeshed but in mypy Any just absorbs None
some people think Any | None is not the same as Any
i dont really see the distinction
exposes the None to the user and signifies it is a special value
Yeah I guess it does have some value for documentation
but in mypy Any just absorbs None
It is interesting that in Pyright, it does not absorb it instantly like mypy, but if you do ais Nonecheck then it goes away
def foo() -> Any | None: ...
a = foo()
reveal_type(a) # Type of "a" is "Any | None"
if a is None:
reveal_type(a) # Type of "a" is "Any | None"
else:
reveal_type(a) # Type of "a" is "Any"
if a is None:
reveal_type(a) # Type of "a" is "Any"
I definitely think Any should absorb None, in the python type system
that's a very weird choice by pyright imho
Any is not a top type; it's literally anything, so None of course falls into that
some other languages use Any for their top type, and if you also have nullability then technically Any is not actually the top type, but rather Any | None is the top type
but in python that still wouldn't apply because the language doesn't really treat None as special in that regard.
None is still an object, so object | None still doesn't make sense, it's the same as object
I personally like the feature. It gives some clear default for arbitrary objects
without it I'd have to raise n catch exceptions which just makes it annoying
I mean it's a nice feature, just not consistent with python
In e.g. Kotlin, Any is almost the top type: the actual top type is Any?. That works because null is a special built in thing.
If you wanted to pretend python is like that in your static type system, I could live with it, but only in the context of object. Not Any.
Hmm well... an operation P is allowed on A | B iff P is allowed on A and P is allowed on B.
Suppose that P doesn't work with None. Then P also doesn't work on Something | None, including Any. Therefore, Any | None is not the same as Any
I guess that's the rationale π€·
if you want Any, just annotate as Any
A U B is surely the same as A if B is a subset of A. But Any doesn't really follow set theory rules because Any is both a subtype and supertype of any other type.
using TypeVarTuple, is it possible to correctly type builtins.zip now?
Ohhh yeah you are right, from the perspective of using the type Any | None it is different from Any, only when it comes to "what is acceptable" that it is the same
Actually, it even breaks transitivity... if P is allowed on A and B is a subtype of A, then P is allowed on B. Well, an arbitrary operation P is allowed on Any, and every type is a subtype of Any, so any operation would be allowed on any type to be consistent.
I don't know if you can apply these rules to Any though can you?
it needs a Map operator which was in a draft version of the pep but removed for fear of it getting too big
maybe one day we'll get it
if foo():
x = get_any() # Any
else:
x = None # None
# -> x: Any | None
x += 1
``` should this be allowed?
No it should not, I said I agree with you :P
it'd be ideal if it collapsed to Any by default but still allowed Any | None when stated explicitly
This part, I guess it does but it just sounds like a bit of a 2 + infinity == infinity so 2 = 0 because of how Any works
Is there something like a typescript compiler for typed python that goes through and verifies everything and then spits out a plain py script?
What would be the use in that? In Python type hints can have runtime effects unlike typescript
Can it? I didnβt know. The hinting seems weak compared to TS
Annotating at module level adds those hints to the __annotations__ global dictionary, in functions to the function.__annotations__ and same for classes. Many libraries make use of those hints to make autoconvertion of data types and probably for other stuff as well
Just in the stdlib there is the @functools.singledispatch deco that does runtime overloading based on annotations
if you're talking about TS's type system, yeah, Python's type system not nearly as advanced
I think the annotations are here to stay for a long time
I you want a backend language with a strong type system, well, pick a language with a strong type system π
It does make you wonder, what would have happened had python gone the typescript route π€
I have been using types in python since they came out, but never to much effect. I recently learned typescript and was amazed
I was blown away by typescript as well
my favourite so far is turning snake_case to camelCase and back on the type level
Maybe it would be even worse? I remember Eric saying that less then 2% (not exactly) of VSCode users use static typing, so imagine if instead of turning on a setting you would have to install a compiler and then manage builds and so on, maybe even less people would be using static typing
so less attention, less features?
Vscode also doesnβt really complain if you ignore typing, and few beginner tutorials use typing. I think most people donβt even know it exists
Yeah it ignores until you turn on the strict option, but that is what I am saying, there is not much friction and yet most dont use it
So imagine if you had to install a whole different program just to compile python to get the static typing
@trim tangle err that's the thing, you can't apply these rules to Any
Any | None doesn't really make any sense because if a function returns Any and that function returns None, then that's already ok
I think the problem is not when you try to fit that type into a hole, but specifically when you ask what members the union of the two types has, and in the case of Any | None, when you take the Union of the members you are only left with the members of None
from typing import Generic, TypeVar, get_args
T = TypeVar("T")
V = TypeVar("U")
class MyClass(Generic[T, V]):
def __new__(cls):
print(get_args(cls))
MyClass[int, str]()
```Output ```py
()
```I know this seems a bit weird but my use case makes use of something similar to this, I don't understand why the `__new__` function's `cls` arg which is the class itself never has the type arguments, it always returns `()` empty tuple , is there a way such that its possible to have the type arguments of the class that is called in the `__new__` function ?
Generics are generally erased at runtime. You could use __class_getitem__ or a custom metaclass to save them somewhere
Why do you want this though?
i was planning to make something like a function that could use generics, I would use a decorator to wrap, something like:
@generics(T, V)
def myfn(w: T, x: V, types = ()): #types is the tuple of generic arguments, I know this doesnt have any use but just curious to play with it
pass
``` then i can do:
```py
myfn[int, str](2, "ok")
doing the same
You can actually get them from orig_class
Oh wait not in new sorry
this is the worst take I've ever heard https://fastapi.tiangolo.com/python-types/#using-union-or-optional
fastapi had a new release an hour ago and they added this along with other features
this isnt that bad a take imo

i think making sure that people are aware what optional actually means is a good thing
I wouldn't recommend they use Union[..., None] though
well yeah but when you tell people to not use Optional at all it's something completely different
Here's my opinions:
T | None>Optional[T]>Union[T, None]T | U | None>Union[T, U, None]|Optional[Union[T, U]]
idk unless the ? null op pep gets accepted i dont think theres much to be said as the 3.10 syntax is what youre meant to use
That's isn't to say that you shouldn't teach about Union[T, None] == Optional[T]
personally I use type aliases so often that I rarely even get to use Optional[Union[T, U]]
wonder when that problem last came up for me
Yeah but when I need to represent that typing I rather just but it in a Union together
oh yeah for sure
i also agree with your list, but i seriously think being more explicit here with members of your team is a good thing
It's not often, but the few times I needed to type it that's what I went with
Yeah, I agree it's not about personal preference or personal consistency: you need to be consistent across the project
well the actual proper solution is upgrading to 3.10 of course but I can say with confidence that I'll never use Union[T, None] in any project of mine that has to support 3.8
you know I feel like they recommend Union[T, None] over Optional[T] because of how many beginners get confused by it. I know there have been dozens of warnings littered around the docs just for that
yeah its cause the naming is very ambiguous especially in python
Just finished that whole thread, makes me think: what if...
Eh, T | None is IMO better than any explicit name - we just mean "or it can be none", and this is a direct and concise way to say so.
I have personally seen a pretty experienced colleague get confused as to what Optional means (at least from past code, they were using weird aliases like Optional[Union[str, None]]).
But I don't think it's a good idea to just not teach Optional (unless you're targeting 3.10+, which might be reasonable in the near-ish future) because it will appear in other libraries as well. It's not that hard to remember just: "Optional[T] means exactly Union[T, None]"
In fact, the repr of Union[T, None] is Optional[T]
!e
from typing import Union
print(Union[str, None])
@trim tangle :white_check_mark: Your eval job has completed with return code 0.
typing.Optional[str]
I have written a short FAQ just in case someone is confused, https://decorator-factory.github.io/typing-tips/pitfalls/optional-is-not-optional
But "Optional[T] means exactly Union[T, None]" should be enough for most cases, at least if someone hasn't remembered "Optional means <something completely unrelated>"
Ah you're decorator-factory?
https://github.com/MagicStack/uvloop/pull/466 can you try my patch for uvloop? I think it fixes your issue
Fixes #414
the I couldn't get the original MRE from the issue https://gist.github.com/decorator-factory/6b5276ab5fb87f4c009f1d22dc4b20a9 to always fail - it seems to be intermittent. However th...
Yeah sorry I've seen that, I'm just lazy
I'll try it out
i wonder how people could get confused about it, it seems pretty obvious from the name optional
If I tell you I have a function that takes an argument of type int and an optional str, I think if you have no prior knowledge it is not hard to see how one would be surprised that in order to call the function you would have to do fun(42, None)
That's because "optional" already has a meaning in Python, i.e. an optional argument
i think Nullable would've been a good name
maybe Noneable, though that doesnt quite have the same ring to it
I think just having Union on it's own would have been fine
that's true, and that might be a reasonable style guide
but Optional is here to stay
well, until people switch to 3.10
what about just | None
That's the 3.10 approach
ah
| None works on 3.7 (but not for pydantic)
They could probably make it work with a thing that parses the strings before evaling them
forbiddenfruit 
hi all
I have a function that return a, b, c, d when I want to get a i can do function()[0] is there a way i can do function()[a] or something along these lines ?
not sure it it is the right channel her thought
you can look into dictionaries, but no, this isn't the right channel, check #βο½how-to-get-help
You can return your namedtuple instead of tuple:
return YourNamedTupleForResult(a,b,c,d)
f().a = a
f().b = b
...
thanks for the answer . I truly appreciate it ! that would do !
I want to backport the slots kwarg of dataclasses, how do I use dataclass_transforms() to tell the type checker that slots will be set?
I see that slots is mentioned in the PEP, but my decorator's sole purpose is adding slots so I won't have that parameter: ```python
def _add_slots(...): ... # Backport of _add_slots from dataclasses' internals
@dataclass_transform()
def backport_slots(cls: Type[T]) -> Type[T]:
return _add_slots(cls)
Do I need to enforce using the decorator with parenthesis such that I can have slots: bool = True?
Is there a need for mypy when python 3.6 introduce type hinting or are the two completely different things?
MyPy is what checks your types
type annotations don't really do anything, they're like comments
you can do x: int = "foo" and it will work.
the purpose of mypy, pyright and other tools is to look at these annotations and find mistakes
Ohhh I see, thank you
What would be the way to validate the strucure or schema of a json/dict type?
Could I maybe use type hinting for this purpose?
If you use a library that interprets the typehints, then yes.
!pypi pydantic
Looks like there is no way to make it default slots to true
Not sure why that matters
Because then I could do:
def backport_slots(*, slots: bool= True) -> Callable[[ClsT], ClsT]:
def inner(cls: ClsT) -> ClsT:
...
return inner
I haven't really gotten as far as to fully test this yet
I don't think that would be enough under PEP 681 to make type checkers see that slots defaults to True
Why so? Isn't it statically determinable?
I don't think PEP 681 asks that they look at the argument defaults, though you're right that they could
that's why there's a few params to dataclass_transform like order_by_default=
sorry order_default
Wow what a shame, so it forces the defaults of dataclasses? ```python
from typing import Callable, TypeVar
from typing_extensions import dataclass_transform
@dataclass_transform()
def test(init: bool = False) -> Callable[[type], type]:
def inner(cls: type) -> type:
return cls
return inner
@test()
class ABC:
a: int
_ = ABC() # Argument missing for parameter "a"
xyz = ABC(123)
That was my takeaway, that you did @dataclass_transform() and the parameters of the decorator function defined the behaviour it supported π€
Actually- no that was a Pyright bug difference then? Mypy actually passes this with Too many arguments for "ABC"
mypy doesn't support dataclass_transform at all
Oh lol
I ran it through Mypy's playground and it passed how I wanted to... but I didn't realize it did nothing 
Should I aim for zero errors on mypy? God, this is tough!
If you're starting to type a completely untyped codebase, there's an option to not check functions which are not annotated
or maybe you have a different situation?
Oh, I started with basic type hints on everything months before using mypy. Now there's just lots of fiddly incompatible types and return value errors
I see, I think it's not a good idea to use type annotations without a type checker. If an annotation is incorrect, it only confuses the reader (and also autocompletion and type checkers)
but yeah, ideally mypy should be quiet
Yeah I definitely learned my lesson for the next project π¦
I've got it from 90 something down to 31 errors. Will keep going
Maybe don't think of it as pleasing mypy. These are actually inaccurate annotations, right?
what editor are you using, by the way?
Yes, it is all correct suggestions from mypy. Just fussy and safe. Like my logic is generally ok accepting the return as either str or None, but the annotation is just "-> str"
VSCode
I would suggest using the Pylance extension. It's much more interactive than mypy, and I like its logic better
Yeah I'm using Pylance. Don't see where its giving me annotation warnings though?
You should set this setting to 'basic'
you might want to turn off the mypy extension if you have it
you can set it to 'strict' as well, but i don't recommend it. the strict-mode type checker hates just about everything, including some things that you can't fix. the python files for numpy, for example, are seas of red in strict mode
No was just invoking with cli for now
Even in "basic" it is complaining about stuff in the requests lib in my venv
what's the error?
Ah nice. I am reading that pylance uses pyright under the hood somewhere
yeah, pylance is basically the name of the extension while pyright is the language server
pyright can do some other things, but it is mainly a type checker
Great, thank you
Huh, do you have no .gitignore? I think Pyright reads that one, as I don't get this issue.
pyright doesn't respect gitignore, but pylance might
Ah interesting. I do have .venv in .gitignore, but its the parent dir, outside of the vscode project dir. That might explain it (i'm using Git outside vscode)
I'm not sure if pylance actually picks up on gitignore, since I haven't used vscode for a while now, but it's quite possible, try adding a gitignore and see what happens, or just move to the parent folder in your case
def __init__(self, comitclient: Comit, entity: str, currency: str, reconcile: str = 'fresh') -> None:
self.reconcile_mode = reconcile
base_balance_url = f'/accounting/balances/{entity}/{currency}'
if self.reconcile_mode == 'fresh':
balance_url = f'{base_balance_url}/reconcile'
mock_file = 'treasury_balances_reconcile.html'
elif self.reconcile_mode == 'last_saved':
balance_url = f'{base_balance_url}'
mock_file = 'treasury_balances_last_saved.html'
I default the reconcile arg to fresh so I know that if statement will always at least match. But now I'm getting pylance "possibly unbound" warnings for the balance_url var. I don't think I need an else statement here, but I guess its not truly safe
What's the best practice here?
well, what if the user changes the reconcile to "abc"?
That user is me! I would never do something so stupid
well, pyright doesn't know that
Instead of taking reconcile as str, make it accept Literal['fresh', 'last_saved']
Oh, like an enum, but defined in the annotations?
you can tell pyright that the variable is of literal type of 2 different strings
well, kind of, not really
literal is a special thing and may cause issues sometimes
def my_func(x: Literal["abcd"]):
...
x = "abc"
x += "d"
my_func(x) # pyright wouldn't like this
issue is that pyright won't actually run your code for you, and so it can't always know what a string will be in the end
so Literal only really work if you use it directly
my_func("abcd")
It would, pyright does some literal operations
well, perhaps but it was just an example and many type-checkers wouldn't know this
But yeah it mostly would not
if you did something more complex, it certainly wouldn't work
and even with this, you really shouldn't rely on that logic, even with pyright
only use literals when the parameter will truly be passed in directly as that literal value
also, literals are limited to only bools, strings, numbers probably also bytes but don't quote me on that
oh and enums too
but yeah, if you can't rely on the variable being passed as a literal thing, don't use them
instead, do something like this: ```py
def my_func(x: str = "one"):
if x == "one"
foo = 1
elif x == "two":
foo = 2
else:
raise Exception
print(foo)
Ah Jesus. I kept resisting the else because I didn't need to set something. Forgot about just raising an Exception π€¦ββοΈ
yeah, it's a nice way to stop the execution there, I'd recommend a ValueError to convey that that the passed value was something unexpected
enums tho
can you make a TypeGuard for a Literal?
I don't see why you couldn't
obviously, enums would probably be the best option here
from typing import Literal, TypeGuard
def is_abcd(x: str) -> TypeGuard[Literal['abcd']]:
return x == 'abcd'
x: Literal['abcd']
if is_abcd(result := input()):
x = result
mypy allowed this
nice
so you could do assert is_abcd(x) and run with python -O if you need
instead of cast which is always hideously ugly
true, but I'm not sure this is better than a single cast, or an else statement with exception
and again, enums would certainly be the best and simplest here
especially since you can do class MyEnum(str, Enum) and get literal strings as enum members
Hi, I have a problem with mypy, but it seems like a bug :
Here, this typing works well : ```py
from typing import Literal
def foo() -> Literal[0]:
return 0
bar: Literal[0, 1] = foo()
BUT, here there is an error with incompatible types : ```py
from typing import Literal
def foo() -> list[Literal[0]]:
return [0]
bar: list[Literal[0, 1]] = foo()
Anyone know how to fix this ?
test.py:6: error: Incompatible types in assignment (expression has type "List[Literal[0]]", variable has type "List[Literal[0, 1]]")
It is because of list invariance
yeah, you can't set a list of some type to be a list of a subtype
this is because if you could, you could append elements that are not of that type anymore
i.e.: ```py
def foo(animal_list: list[Animal]):
animal_list.append(Dog())
my_list: list[Cat] = [Cat(), Cat()]
foo(my_list)
passing my_list, being a list of just cats to the foo function which expects a list of animals, no matter if those animals are cats, or dogs, or anything else quickly becomes an issue because lists are mutable
that means you can edit the object after it was passed into a function, by for example adding a dog into that list, and since in that function, it's seen as a list of animals, that's allowed, but after that, you're now left with a list typed as a list of cats, with a dog in it
hm ok I think I understand
but so what should I do in that case ?
you could use an immutable sequence
Both frames need to be the same but I couldn't do it anyway. what is the problem ?
def foo() -> list[Dog]:
return [Dog(), Dog()]
out: typing.Sequence[Animal] = foo()
Sequence is a protocol that's a subtype of list, however it doesn't allow mutability
you could also copy the list
this probably isn't the channel you wanted to post this into, check #βο½how-to-get-help
but I want my list "bar" to be edited (with 0 and 1)
so by copying the list on definition will avoid the problem ?
yes, if you copy the list, it's simply a new list containing elements of some type, but that new list can be typed as a list containing elements of some supertype, since you can't alter the old list anymore, it's a new instance at that point
It is the opposite, that is why you can assign list[T] to a Sequence[T]
*oh yeah sorry, it's a supertype
hm by using .copy() it keep the old type hinting for the object
I have to do something like [x for x in foo()], that's not really good
but I guess I will just make the foo function return a list with Literal[0, 1], because the object it return will be able to have 1 in the futur (event if it is only 0 at creation)
you'd probably need to cast it manually with copying
using list comprehention is indeed not a good solution
from typing import cast
x: list[int] = [1, 2, 3]
y: list[float] = cast(list[float], x.copy())
oh yes I can use cast
thx
or you could make your function return list[Any]
x: list[Any] = [1, 2, 3]
y: list[float] = x
that way, this wouldn't actually cause any issues
I think I will make my function return list[Literal[0, 1]]
because the object it return will never get other things than 0 and 1
that's also an option yeah
even if the object it return contain only 0
I got it, the typing describes what the object (the list) can contain, and not what it contains when the function returns it
well, with immutable types, this wouldn't be an issue, but because lists are mutable, they need to be invariant otherwise issues would arise quickly
but if you were using something immutable, like a tuple, you could easily do exactly what you want
def foo() -> tuple[Literal[0], ...]:
return (0, )
x: tuple[Literal[0, 1], ...] = foo() # fine
yes, because even if x can contain 0 and 1, the object returned will not be able to change, so there is no risk that something else than 0 will be present in the tuple
this may be a better solution for you, if you don't need mutability
How would you type annotate a class from within it
For example, when trying to return the subclass that would inherit your class
class Base(abc.ABC):
@abc.abstractmethod
def new(self, x) -> Self:
x = self.something_with_x(x)
return Self(x)
class Vector(Base):
pass
shell = Vector()
position = shell.new(5) # Here, position is an instance of Vector
The example might be a bit wonky
I've heard in 3.11 there will be typing.Self
i have some repetitive piece of code could you give me tips to make it smaller
def get_lang():
mydivs = soup.select_one('.galleries_info')
txt_div = mydivs.get_text
the_list = []
the_final_list = []
soup2 = BeautifulSoup(str(txt_div), 'html.parser')
for i in soup2.find_all('a', class_="tag btn btn-primary"):
the_main = (i.get('href')).split('/')
if the_main[1] == 'language': #{the changing part}
the_list.append((the_main[2].split('-')))
for i in the_list:
the_perfect_list.append(' '.join(i))
return the_final_list
def get_tags():
mydivs = soup.select_one('.galleries_info')
txt_div = mydivs.get_text
the_list = []
the_perfect_list = []
soup2 = BeautifulSoup(str(txt_div), 'html.parser')
for i in soup2.find_all('a', class_="tag btn btn-primary"):
the_main = (i.get('href')).split('/')
if the_main[1] == 'tag': #{the changing part}
the_list.append((the_main[2].split('-')))
for i in the_list:
the_perfect_list.append(' '.join(i))
return the_perfect_list
You can use typing_extensions
!pypi typing_extensions
Oh
Thanks a lot mate!
How would i go about typehinting an 2D array of 6 lists containing 6 ints
if 6 is constant, the best you can do is a nested tuple
You can't specify the length of a list, no
if not, there isn't a way
List[List[int, int, int, int, int, int]]
That is not legal
This gives me TypeError: Too many parameters for typing.List; actual 6, expected 1
Yeah
hmm okay
As people have suggested, Tuples can define their lengths,~~ but maybe python's native array can already handle a TypeVarTuple to statically-type its shape?~~
Nevermind, https://github.com/python/typeshed/blob/eadb35e6200dd34173ec226431f43456ccfae04b/stdlib/array.pyi#L18 it's not there yet
Hmm well i think it could be used in some cases
is there some indication on what version of pyright is running on the pyright playground? @trim tangle
you can inspect responses from POST /pyright in the network tab in devtools
it's pretty ancient
hmm
is this open to be used in some other apps?
also, you could update the version, lol
understandable
sure, it's basically free for me
(I haven't paid a single cent so far)
is it a github deployed page?
is there some rate limit?
nope
if it is, you could probably make a github workflow to automatically update the version of pyright
well it's complicated
the actual pyright diagnostics are run as a cloud function written in Node.js, and the rest is what's in the repo
But if you send me 1 million requests I will have to pay 16 roubles (I'll send you an invoice
)
lol, that probably won't happen
well, you have a lot of time until I'll be able to send an invoice
because of some crazy asshole
anyway...
yeah I was planning to renovate the playground for a while but honestly I'm a bit burn out by work and stuff right now
the best way would probably be the "serverless container" thing, which lets you run a whole container in a serverless way, like a lambda but better
well, if the version won't get auto-updated, it'd be nice if it was shown on the page directly instead of having to inspect the response from that post request
can't argue with that
have you considered using the python wrapper that automatically handles node.js in the background and is simply a pip dependency?
nah I think it's extra complexity
I did that because I wanted to scale the expensive stuff without buying an expensive VPS. But I didn't know about Serverless Containers back then
how would it be more complex? you don't really need to worry about almost anything that happens in the background and since you just seem to be using a subprocess to run pyright with temporary files, it seems like an easier option to just list pyright in pyproject.toml and let poetry take care of installation
Is this good?
Optional[List[str]]``` or not
maybe, what are you using it for?
What do you guys recommend me to do.
the annotation itself is valid if that's what you're asking about
def some_func(my_list: Optional[List[str]] = None) -> None:
...```
nope.
Maybe there's pretty much a readable option?
i don't know.
Optional[List[str]] is probably the best option in terms of readability
list[str] | None in 3.10+
you can also do Union[List[str], None], or on newer python versions: List[str] | None
no, i use 3.8
then I think optional is the best way to go
Thanks. π
pretty sure this would even handle installing npm for you to obtain pyright
Accepting a list specifically is very strange. If you pass in a tuple, will the function crash and burn?
Maybe you need typing.Sequence or Collection or Iterable?
Maybe you could show the function?
thx. Yeah you're right.
Btw do you know displaying python code within docstrings?, i haven't found the channel for this, quick example
def add(n1: int, n2: int) -> int:
"""
Example:
print(add(2, 2))
# 4
"""
return n1 + n2
Pycharm does really show it in a very bad.
Like giving extra spaces or everything joined
Is there an off-the-shelf library that includes getting all functions/callables declared in a specific file? Especially if filtered by type hints?
I know inspect exists, but I'd like to use something that wraps that if possible.
and the three "`"
didn't work.
if you just want list of all callables in a file, why not simply: [name for name in dir(abc) if callable(getattr(abc, name))], callable is a built-in function
you could do the same with inspect.isfunction if you wanted only functions per-se, since callable just returns anything that can be called
but that's probably something that doesn't need an entire library around it
I think I'll probably need to get inspect involved at some point for what I want to do.
this is a good point though, ty. I can probably start off with this for now and check for for callables that aren't types
why not just inspect.isfunction though? that will automatically exclude classes
or do you want to catch methods of each class?
there's not much else to type-hint other than variables and functions, classes don't need type-hinting, they're their own types, and in most cases, variables also don't need type-hinting since they're often inferred from the value they're set to a = "abc" => a is a string
also, the more you use python, the lesser the difference between variables and something like a function/class becomes
def foo():
return 5
x = foo
x() # 5
in this case, x could be typed as Callable[[], int]
yeah, python is very dynamic in it's nature, classes are also treated like this, and even modules
!e
def foo():
return 5
x = foo
print(x is foo)
print(id(x) == id(foo))
@cunning raven :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | True
They from the same memory location.
you can even construct a class manually: ```py
MyClass = type("MyClass", (), {"x": lambda self: 1})
MyClass().x() # 1
i don't like that.
this it's actually pretty beneficial, since it saves a lot of memory
if you don't need to duplicate an object, you shouldn't be doing it
you can always use copy.deepcopy though
π
Oh i forgot about this.
hm, though I'm not actually sure if it would work for function objects
yeah it wouldn't
but it doesn't make a lot of sense to copy functions like this, why would you ever need that
well, you should generally use an Optional
from typing import Optional
def func(x: Optional[int] = None):
...
but there is an option to disable the need for this in pyright
yes
pyright can infer that from it being set to = None
this was actually pyright's default behavior for a long time
it only started to require the Optional type-hint recently
yes
I mean, some people
explicitly setting the type-hint as Optional is a pretty good practice though
that only depends on how your function works internally
if this variable is holding something like an amount, then perhaps it could make sense
but 0 may be passed in intentionally in some cases, and maybe the default behavior should be something else
this is the pyright's setting you can toggle to disable the Optional requirement
always use None
NoReturn is for an infinite cycle or something like that
it's a function that never stops executing
so it never reaches the point of returning a value
maybe mention typing_extensions.Never as a less confusing name for NoReturn?
(will be typing.Never in 3.11)
what's the difference between them?
will NoReturn get deprecated in it's favor?
the name doesn't make people think it means something else π
type checkers are supposed to treat them the same
no concrete plans, I'd discourage people from using NoReturn in a few years once 3.11 is widespread
like: "You might be familiar with never in TypeScript. NoReturn is the same thing. In fact, in Python 3.11 NoReturn will be renamed to Never to reduce the confusion. If you're not on 3.11 yet, you can use Never from typing_extensions."
Cross-posting possible mypy/typing_extensions bug with Self type from #python-discussion #python-discussion message
mypy doesn't support Self
oh alright, for some reason I thought it did
what does the Never type hint mean? when i hover over a particular variable in vscode it shows (parameter) to: Never
the code is ```py
x = x if isinstance(x, (list, typing.Sequence)) else [x]
It's the empty type, it means the branch cannot be taken
it seems to fix it, thank you π
is there something like a typevar for types? something like this ```py
class A:
pass
class B(A):
pass
this part doesn't seem right
TA = TypeVar('TA', bound=A)
cls: Type[TA] = B
x: TA = cls()```
cls: type[A] = B
Type variables are for linking two types inside a function or a class, you don't have that here.
I'm trying to do something in a class ```py
class A:
pass
class B(A):
pass
TA = TypeVar('TA', bound=A)
class Thing:
def init(self, cls: type[TA]):
self.cls = cls
def get(self, data) -> TA:
return self.cls(data)```
class Thing(Generic[TA]):
Yeah
- You need a
Generic - You don't need a
type[A], you need aCallable[[], TA]
why Callable[[], TA] is better than type[TA]?
I have a tutorial on generics:
https://decorator-factory.github.io/typing-tips/tutorials/generics/generic-types/
Why require a type? It's more flexible
it isnt more flexible if you want to get a class, not an instance factory
Well, the example shows that they need a factory
class Thing(Generic[TA]):
def __init__(self, cls: Callable[[], TA]):
self.cls = cls
print(cls.mro()) # error
yes, youre right, in this example Callable[[], TA] is better
but in general i prefer type[TA]
huh so callable or type both work fine?
I think if Map is introduced you can do (tuple[*Ts]) -> list[Map[Union, Ts]] or something for typing foo
You need to explicitly allow None
value: float | None = None
No
That's going to evaluate to just float
At runtime atleast
Yep
But that should be the same as float | None because of the way that type checkers treat float (it's a subtype of int)
It is you just need to turn on
Fun
Whichever you prefer
you'll need overloads then
from typing import overload, Literal
@overload
def foo(x: Literal[1], y: int) -> None:
...
@overload
def foo(x: Literal[2], y: str) -> None:
...
def foo(x: Literal[1, 2], y: object) -> None:
# implementation
Yeah overloads won't help here
You need conditional types
Well i guess they help with the signature
assuming winreg.SetValueEx has overloads defined, you should then be able to get away with something like the above with the implementation like: ```py
if x == 1:
x = cast(Literal[1], x)
winreg.SetValueEx(...)
elif x == 2:
x = cast(Literal[2], x)
winreg.SetValueEx(...)
yeah, the implementation needs to then use conditional types
which can be very annoying with literals
you could also type-ignore that call internally, and just have overloads defined on your method so people use it correctly
it may be possible that pyright can handle this upcast automatically?
I doubt it though
What are overloads?
i've seen it in discord.py resource code
overloads allow you to type a function to have a different signature depending on the input arguments, it is not supposed to have any runtime effect though
@overload
def foo(a: Literal[True]) -> Literal[1]: ...
@overload
def foo(a: Literal[False]) -> Literal[0]: ...
def foo(a: bool) -> int:
return int(a)
reveal_type(foo(True)) # Literal[1]
reveal_type(foo(False)) # Literal[0]
But it can have runtime effects, so it depends how a library uses it, at runtime it just returns the function unchanged with no side effects (prior to 3.11) but if used in a class with some magic it can have runtime effects if a library makes it so via metaclass magic, maybe that is the case with discordpy
Actually my bad, it doesnt return the function, it just returns a dummy function that then gets redefined by the implementation
Dpy doesn't do anything with overloads
Ah alright, I said maybe because I wouldnt put it past them doing that xD
@hearty shell thank you so much.
I've got an async context manager and factory method classmethod as such:
class User:
def __init__(self, security_cookie: str, proxies: dict = None):
self.__roblosecurity = security_cookie
self.__proxies = proxies
async def __aenter__(self, *args, **kwargs) -> None:
"""
Context manager version of User.create
"""
pass
async def __aexit__(self, *args, **kwargs) -> None:
await self.close()
@classmethod
async def create(cls, *args, **kwargs) -> Self:
"""
Factory method creation of User object
Initializes the user class, checking the cookie's validity in the process
"""
self = User(*args, **kwargs)
return self
How do I go about adding parameter hints in __aenter__ for the context manager and also in create to match __init__ parameters so that it appears in IDE suggestions?
I'm aware I can just change the parameters of __aenter__ and create themselves, but I feel like there's probably a more pythonic way to just have them just pull from what's required by __init__ but I don't know how. Any ideas? Tag on response please.
See how it says *args **kwargs due to it being the params for classmethod create, but I want it to show me the params for User.__init__ somehow.
I'm using VSCode, for reference.
I guess you can do
from typing import *
P = ParamSpec('P')
T = TypeVar('T')
def method_args_of(
init: Callable[Concatenate[Any, P], None]
) -> Callable[[Callable[[Any], T]], Callable[Concatenate[Any, P], T]]:
...
class User:
def __init__(self, security_cookie: str, proxies: dict | None = None) -> None:
self.__roblosecurity = security_cookie
self.__proxies = proxies
@classmethod
@method_args_of(__init__)
async def create(cls, *args, **kwargs) -> Self: ...
reveal_type(User.create) # Type of "User.create" is "(security_cookie: str, proxies: dict[Unknown, Unknown] | None = ...) -> Coroutine[Any, Any, User]"
I dont know if I would call this "more pythonic" though
Your method_args_of return None, you should return lambda x: x instead
thoughts on this?
status_flag: int[range(0, 4)] = 1
dont ask me why, i couldnt tell you
thoughts as in? If this should be supported?
is it good? is it stupid? will it work?
idk why i did it, i just did it to define a int variable that has a range of 0-4
linter isnt giving me an error
It might just not be on or in a mode where it just ignores incorrect type signatures
But this is definitely not supported
this is the return Generator[Literal[2, 0], None, None]
It is also a runtime exception as int does not support []
it doesnt?
its not giving me any errors and im using pylance
status_flag: int[0, 4] = 1
!e int["foo"]
@hearty shell :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: 'type' object is not subscriptable
