#type-hinting

1 messages Β· Page 6 of 1

soft matrix
#

and that means you need to typing.cast?

slender timber
#

I have modified enum class's new function to do that

slender timber
soft matrix
#

ok maybe you want to use some kind of fake field function here or Annotated

slender timber
#

Fake field function?

soft matrix
#

it might be too hacky actually thinking about it

slender timber
#

Or annotated right?

#

How will Annotated work with dict key for example?

rustic gull
#

I have a decorator that can be applied to a property. Can I type hint my decorator to only accept properties with a particular return type?

brazen jolt
#

currently, properties aren't generic, so you can't do that unless you'd instead use some custom generic property implementation and work with that in your code

#

as an example, you could do this: ```py
from typing import Generic, TypeVar, Optional, Callable, Any

T = TypeVar("T")

class Property(property, Generic[T]):
"""Generic implementation of a property.

Allows us to provide type annotations on top of builtin properties.
"""

def __init__(
        self,
        fget: Optional[Callable[[Any], Any]] = None,
        fset: Optional[Callable[[Any, Any], None]] = None,
        fdel: Optional[Callable[[Any], None]] = None,
        doc: Optional[str] = None,
) -> None:
    super().__init__(fget, fset, fdel, doc)

def __get__(self, obj: Any, objtype=None) -> T:
    return super().__get__(obj, objtype)

def __set__(self, obj: Any, value: T) -> None:
    super().__set__(obj, value)

def __delete__(self, obj: Any) -> None:
    super().__delete__(obj)
tranquil turtle
rustic gull
#

And big thanks for the example code, that looks exactly like what I'm looking forπŸ‘

oblique urchin
#

yes, that's right

brazen jolt
#

yes, __init__ doesn't return anything

#

although in many cases, you can just not type-hint the return type

#

type-checkers will infer it

#

you generally shouldn't type-hint it

#

you could do ```py
class Foo:
def init(self: Foo):
...

trim tangle
#

Well, actually there's Self

rustic gull
#

Beat me to it haha

trim tangle
#

Don't beat yourSelf up

brazen jolt
#

lol

rustic gull
#

Only python 11 though, which is currently in the release candidate stage

rustic gull
brazen jolt
#

yeah, Self is a thing and it's quite nice, but nevertheless, you generally won't need to type-hint self at all, type-checkers will infer it

brazen jolt
trim tangle
#

beat me to it

rustic gull
#

Oh I thought it was only added to typing_extensions in 11 πŸ˜…

brazen jolt
#

it's a module you can install which allows you to use some typing features that aren't yet in typing, basically a bunch of backports

#

!pypi typing_extensions

rough sluiceBOT
rustic gull
#

Thanks, I use it for NotRequired :)

brazen jolt
rustic gull
#

I see, makes sense πŸ‘

brazen jolt
#

if something gets added to typing_extensions, you'll be able to use it all the way down from 3.7

soft matrix
#

What is reveal_type(powers)?

chrome hinge
#

If I have a Generic[T] type, and a method of the form (self: MyType[T], fun: Callable[[T], V]) -> MyType[V], I can annotate this as:

def map(self: "MyClass[T]", fun: Callable[[T], V]) -> "MyClass[V]":

But what if I also want, for subclasses of MyClass, this method to return the specific subtype self is, and not MyClass? Something like (self: Self[T], ...) -> Self[V] - except that Self isn't subscriptable.

brazen jolt
chrome hinge
#

why does that always happen whenever I'm trying to type something in python
Thanks!

soft matrix
#

that doesnt look unknown

trim tangle
#

it's partially unknown because of the Any, I guess

chrome hinge
#

Can I make a generic alias of sorts, something like Predicate[T] = Callable[[T], bool] except, well, syntactically correct?

#

oh,

Predicate: TypeAlias = Callable[[T],bool]

works

trim tangle
#

yep

trim tangle
soft matrix
brazen jolt
trim tangle
#

i have no idea

brazen jolt
#

ah

#

lol

trim tangle
#

I suppose one could make a callable protocol

soft matrix
#

you cant do it with a typealias but you can do it with an actual subclass cant you?

brazen jolt
trim tangle
#

and, well, callable is just an example, you could have a different type alias

#

hmmm, is it possible to make a type alias with two parameters that ignores the first one?

#

interesting

from random import choice
from typing_extensions import Never

def f(x: tuple[Never, int, str]):
    p = choice([0, 1, 2])
    
    if isinstance(x, tuple):
        reveal_type(x[p])
#

I'd hope that tuple[Never, int, str] would be reduced to Never πŸ˜”

gritty merlin
chrome hinge
#

Is there any way to represent something like Rust's

fn sum(nums: Vec<T>, start: V) -> T
where T: Add<T, Output=T>, V:Add<T, Output=T>

?
The problem here is requiring the bound of V to contain T, an unrelated typevar. I'm trying this:

SumDefaultT = TypeVar("SumDefaultT", bound = SupportsAdd[SupportsSumWithDefaultT,SupportsSumWithDefaultT])

and getting "TypeVar bound type cannot be generic" from pylance.

fierce ridge
#

not 100% sure what the rust version says, but it seems equivalent to just writing SupportsAdd[..] in the function signature

#

you can also create a type alias SumDefaultT: TypeAlias = SupportsAdd[...]

#

or maybe you need to create a typevar just with bound=SupportsAdd and parameterize the typevar

soft matrix
#

you cant parameterise a typevar

fierce ridge
#

oh dang right

#

so is that not possible to express then?

soft matrix
#

pythons add operator is really hard to type

#

i remember theres a gist somewhere here that does it most of the way

fierce ridge
#

you would have a similar problem trying to type a Mapping i think

graceful nova
#

how to say a function returns str or None?

def f() -> ?:
  pass
buoyant swift
#

Optional[str]

#

or str | None

brisk heart
# soft matrix i remember theres a gist somewhere here that does it most of the way

This?

from typing import Protocol, overload

T_contra = TypeVar('T_contra', contravariant=True)
T_co = TypeVar('T_co', covariant=True)

class SupportsAdd(Protocol[T_contra, T_co]):
    def __add__(self, x: T_contra) -> T_co: ...

class SupportsRAdd(Protocol[T_contra, T_co]):
    def __radd__(self, x: T_contra) -> T_co: ...

@overload
def add(x: SupportsAdd[T_contra, T_co], y: T_contra) -> T_co: ...
@overload
def add(x: T_contra, y: SupportsRAdd[T_contra, T_co]) -> T_co: ...

def add(x, y):
    return x + y
soft matrix
#

maybe

rustic gull
#

Does anyone know of a type hint i can use to accept any type that supports iteration and len? Basically the intersection of Sized and Iterable

tranquil turtle
rustic gull
#

haha, good point :P Many thanks!

rare scarab
#

not very soon, we'll be able to do SizedIterable = Iterable & Sized

slender timber
#

can we type hint an optional argument as just None in a typing.overload?

#

or remove it entirely?

rare scarab
#

you can remove it

real musk
#

Is there a type hint for "supports comparison operators"? (e.g. Ord)
In my argmin function, mypy requests Union[SupportsDunderLT, SupportsDunderGT], but I can't find SupportsDunderLT, SupportsDunderGT or Ord in the typing library or collections.abc library.

soft matrix
#

It's probably from _typeshed

rare scarab
#
from typing import TYPE_CHECKING
if TYPE_CHECKING:
  from _typeshed import SupportsRichComparison

def sortit(lst: list, *, key: "SupportsRichComparison" | None = None): ...
rough sluiceBOT
#

stdlib/_typeshed/__init__.pyi line 69

SupportsRichComparison: TypeAlias = SupportsDunderLT[Any] | SupportsDunderGT[Any]```
real musk
#

Huh. So I have to pip install typeshed to get that to work properly? Shame.
I found a workaround by just doing Ord = int which is incorrect but hopefully communicates what I meant to any human who might read it (unlikely to be anybody since this is a personal project)

trim tangle
#

the two possibilities have an intersection πŸ™‚

rare scarab
oblique urchin
rare scarab
#

I assume mypy clones the git repo when bundling?

soft matrix
#

it just has a copy of the stubs cause the _typeshed.pyi file is included in typeshed

trim tangle
#

that gets tricky real fast πŸ™‚

#

What kinds of errors does it catch that type checkers wouldn't?

#

although, I guess, it lets you annotate parameters with extra checks

slender timber
#
def hex2rgb(hex: str) -> tuple[float, float, float]:
    rgb = hex[1:]

    if len(rgb) == 6:
        red, green, blue = rgb[0:2], rgb[2:4], rgb[4:6]
    elif len(rgb) == 3:
        red, green, blue = rgb[0] * 2, rgb[1] * 2, rgb[2] * 2
    else:
        raise ValueError(f"Invalid value {hex} provided for rgb color.")

    return tuple(float(int(v, 16)) / 255 for v in (red, green, blue))

pyright is smart enough, but mypy? meh

Incompatible return value type (got "Tuple[float, ...]", expected "Tuple[float, float, float]")
#

its right in front of mypy that the return value will have 3 floats

#

why is it so dumb

dull lance
#

Well, this might be a workaround xD

r, g, b = (float(int(v, 16)) / 255 for v in (red, green, blue))
return r, g, b
slender timber
#

seriously 🀨

dull lance
#

but yeah in general I find that pyright is much better at type inference than mypy

slender timber
#

mypy should die a horrible death for its sins

slender timber
#

is there a SupportsStr protocol?

oblique urchin
slender timber
#

why isn't this automatically inferred though

#

I event tried using Unpack

soft matrix
oblique urchin
slender timber
#

whose eric

soft matrix
#

eric is one of the primary maintainers of pyright

slender timber
#

hmm

trim tangle
#

On one hand, it sucks. On the other hands, there's enough clutches and special cases πŸ˜„

torpid yarrow
#

is Type[Union[A, B]] equivalent to Union[Type[A], Type[B]]?

oblique urchin
torpid yarrow
oblique urchin
torpid yarrow
#

So if I want to recreate Type[Union[...]] I can just use a typevar?

#

Because I have a union of 10-15 types that I would really like to shorten ```py
Union[Type[A] | Type[B] | Type[C] | Type[D] | Type[E] | Type[F] | Type[G] | Type[H] | Type[I] | Type[J]]

K = TypeVar("K", bound=Union[A, B, C, D, E, F, G, H, I, J])
Type[K]

dire bobcat
#

in python 3.10+, what is from __future__ import annotations used for?

#

from __future__ import annotations was previously scheduled to become mandatory in Python 3.10, but the Python Steering Council twice decided to delay the change (announcement for Python 3.10; announcement for Python 3.11). No final decision has been made yet. See also PEP 563 and PEP 649.

slender timber
#

delayed evaluation of type annotations

dire bobcat
#

I know it encases typehints in quotes, but how is that useful for 3.10

slender timber
#
def a(k: Klass): ...  # Used above
class Klass: ...    # Defined below
fierce ridge
#

is there any active proposal to add type hints for a "const" variable and/or attribute? something like this:

x: Const[float] = 3.5

class Thing:
    y: Const[ClassVar[int]] = 12
    z: Const[str]

    def __init__():
        z = "hello"  # Can be assigned exactly once, in __init__

thing = Thing()

x = 4.5  # Error
Thing.y = 11  # Error
thing.z = "bye"  # Error
soft matrix
#

this doesnt that look that different from Final

brisk hedge
#

I think only the "assign once in init" is different

slender timber
#

The dataclass InitVar can be repurposed for this purpose. Its similar to C# readonly

fierce ridge
#

oh hey it works with mypy too

#

i'm ok with it not checking inside instance methods

#

preventing assignment from outside is good enough

#

thanks for the tip!

#

it would be interesting if there was something like a module-global attribute you could set that would enable Final by default for all attributes not annotated as Mutable or something like that

deep saddle
#

what?

#

is this not valid? x: Base | other_thing = Base()

deep saddle
#

because these are both of the same type, Base

oblique urchin
#

you are assigning a dict[str, Base] to a dict[str, Base | something]

#

dict is invariant in its value type

#

so you get an error

deep saddle
#

gotcha

#

I as the programmer know that the first one is a subset of the second one, is there a way to indicate this to pylance?

#

this is my current setup

cleaners.py: ```py
class Base:
pass

class Dictionary(Base):
def init(self, structure: dict[typing.Any, dict | Base]):
pass

other_file.py ```py
from . import cleaners

class Options:
    def __init__(self, url: dict[str, cleaners.Base] | cleaners.Base | None):
        if isinstance(url, dict):
            x = cleaners.Dictionary(url)```
#

the typing of the arguments is correct in both of these places, I don't want to change the argument type itself

oblique urchin
#

use Mapping instead of dict, it's covariant in the value type

little hare
#

invariance why

deep saddle
trim tangle
fervent sierra
#

Is it possible to configure pyright so that it produces an error when a public instance variable is not declared at the top level of the class? I'm looking for something stricter than reportUninitializedInstanceVariable, which still allows instance variables to be "declared" inside __init__ via assignment

devout barn
#

Is it possible to set custom rules for pyright?

trim tangle
devout barn
#

For example, I want to make it so that no variables have a name that starts with a, so I would make a node visitor that visits Name blocks with Store context and appropriately raise problems, is there a way to integrate this to existing solutions such as pylance?

#

I think this can be done in the case of mypy, but I specifically wanted to do this with pylance

trim tangle
#

but no, pyright doesn't support plugins

slender timber
#

How can I get this working?

@overload
def subdict(self, select: Callable[[AnyEvent], bool], repeat: Literal[1]) -> EventDict: ...

@overload
def subdict(self, select: Callable[[AnyEvent], bool | None], repeat: int) -> Iterator[EventDict]: ...
#

ok so this worked

@overload
def subdict(self, select: Callable[[AnyEvent], bool], repeat: Literal["dont"]) -> EventDict: ...

@overload
def subdict(self, select: Callable[[AnyEvent], bool | None], repeat: int) -> Iterator[EventDict]: ...

but how do I avoid re-annotating the impl function again?

trim tangle
#

can you show the implementation?

#

what is the method supposed to do?

slender timber
# trim tangle can you show the implementation?
    @overload
    def subdict(
        self, select: Callable[[AnyEvent], bool], repeat: Literal["dont"]
    ) -> EventDict:
        ...

    @overload
    def subdict(
        self, select: Callable[[AnyEvent], bool | None], repeat: int
    ) -> Iterator[EventDict]:
        ...

    def subdict(self, select: Any, repeat: int | Literal["dont"] = "dont"):
        """Yields EventDict(s) till ``select`` and ``repeat`` are satisfied.

        Args:
            select: Called for every event in this dictionary by iterating over
                a chained, sorted list. Returns True if event must be included.
                Once it returns False, rest of them are ignored and resulting
                EventDict is returned. Return None to skip an event.
            repeat: Use -1 for infinite iterations. Defaults to "dont".
        """
        el: list[IndexedEvent] = []

        if repeat == "dont":
            for ie in chain.from_iterable(self.dct.values()):
                if select(ie.e):
                    el.append(ie)
            return EventDict(self, el)

        for ie in chain.from_iterable(self.dct.values()):
            if not repeat:
                return

            result = select(ie.e)
            if result:
                el.append(ie)
            elif result is False:
                yield EventDict(self, el)
                el = []
                repeat -= 1
#

I am also getting type annotation errors for the return type of impl function

trim tangle
#

well that's not correct, the function returns an iterator in any case

slender timber
#

huh

trim tangle
# slender timber huh
import random

def foo():
    if random.random() > 0.5:
        return 42
    else:
        yield from [1, 2, 3]

hmm = foo()
print(hmm)

what do you expect in the output?

slender timber
#

a number

#

or an iterator

trim tangle
#

Do you know what return does in a generator function?

#

Like

def foo():
    yield 1
    return 2
slender timber
#

because yield returns an Iterator which requires next to get the next value

#

now i am confused

slender timber
#

or do I need to call next(foo())

trim tangle
#

A function is a generator function if it has a yield in it. It doesn't conditionally return a generator or a non-generator

#

So this is a generator function which yields zero elements:

def empty():
    if False:
        yield "delicious"
trim tangle
#

one searches for a single event, another one searches for multiple events

slender timber
#

i am confused about what I name them πŸ˜…

trim tangle
#

can you explain what it does?

slender timber
#

that's why I made one

trim tangle
#

Well, you can avoid function naming entirely if your program consists of a single main() function πŸ™‚

slender timber
#

well behavior of the method is decided by repeat

slender timber
trim tangle
#

sure

slender timber
#

ahh well forgot to include IndexedEvent

#
@dataclass(order=True)
class IndexedEvent:
    r: int
    """Root index of occurence of :attr:`e`."""

    e: AnyEvent = field(compare=False)
    """The indexed event."""
trim tangle
#

I don't see how it preserves insertion order

slender timber
#

the r attribute of IndexedEvent preserves insertion order

#

so when all the dict values are chained together they can be sorted by using r as the key

trim tangle
#

And why do you need to preserve insertion order?

#

hmm wait

slender timber
#

ahh god

#

pls don't make me explain that again πŸ˜₯

#

it will take a good 30 mins πŸ˜₯

trim tangle
#

well, there may be a tool that saves you from explaining everything every time

#

I think it's called "documentation" πŸ˜›

slender timber
#

but tldr - I want a dict-like "lookup" with list-like "insertion / deletion" with a hierarchy such that whenever a child dict is modified it modifies all its parents

slender timber
trim tangle
#

can you show an example maybe?

slender timber
#

damn

#

i need to find old messages i posted

trim tangle
slender timber
#

Ok, so lets begin with my ted talk πŸ˜›

trim tangle
#

Maybe you want a collections.OrderedDict?

slender timber
#

If there's a list like this:

lst = [Event(A, 1), Event(B, 1), Event(A, 2)]

and I create an EventDict, say ed out of it whose attr dct looks like this:

dct = {A: (0, [Event(A, 1)), (2, Event(A, 2))], 2: [(1, Event(B, 1)]}

where the tuple represents an IndexedEvent.
Observe that the keys are nothing but "event IDs" (i.e. the first arg of Event).
and first member of tuple (a.k.a. root index) represents index of that event in lst.

If I modify the dict like append or delete (its a dict but by looking the keys are just for lookup, so its actually as good as a list)

ed.insert(0, Event(B, 2))

I use the root index to keep the "real" order. Once I want to reconstruct the dict into a list I just chain all values of the dict and sort by the root index.

lst = [Event(B, 2), Event(A, 1), Event(B, 1), Event(A, 2)]
#

@trim tangle

#

its like a tree, list, and dict all in one whatever idc πŸ˜›

#

please reply now, that really takes time to type

trim tangle
#

it sounds exactly like what you want

#

it's used by HTTP libraries to store HTTP headers, which are ordered and indexed by header name

slender timber
#

can i reconstruct the list with the order?

#

multidict doesn't allow for mutable views (MultiDict.getall returns a list, which unfortunately doesn't mirror back the changes like additions or removals into the parent dict)

#

so no

trim tangle
slender timber
fathom crown
#

what's the difference between tuple[int] and tuple[int, int]?

trim tangle
fathom crown
#

ohh

#

can we use those for checks like let's say

def check(bar: tuple[int, int]):
    # instead of doing this
    if isinstance(bar, tuple) and len(bar) == 2:
        ...
    # do (something like) this 
    if type(bar) == tuple[int, int]:
        ...
oblique urchin
fathom crown
#

ah i see

trim tangle
#

yeah runtime checks aren't really a thing

rare scarab
#

though pydantic likes to pretend

#

it's more of an input validator and coercer

trim tangle
#

yeah, for pure data coming from JSON it is possible

#

it's more of a parser really

slender timber
#

how to type hint a very generic decorator so that it doesn't erase the type annotation of the function it decorates?

#

type hint it in such a way that input and output type annotations should be same

rare scarab
#

You could use a function typevar

#
Func = TypeVar("Func", bound=Callable[..., Any])

def foo(func: Func) -> Func:
  def decorator(*args, **kwargs):
    return foo(*args, **kwargs)
  return decorator
#

otherwise there's ```py
P = ParamSpec("P")
R = TypeVar("R")

def foo(func: Callable[P, R]) -> Callable[P, R]:
...

soft matrix
#

Callable[P, R] erases the type info though

#

if hkt existed it wouldnt πŸ˜”

rustic gull
#

If I use exec to make some functions type checkers are in the dark even if there's type hints right?

soft matrix
#

yes

#

well pyanalyze might be able to handle it

#

but i dont think anything else could

oblique urchin
soft matrix
#

but generally doing so isnt recommended anyway

oblique urchin
#

well, dataclasses does it πŸ™‚

#

but agree it's not something you should frequently do

soft matrix
#

dataclasses have an actual typing representation now tbf

fierce ridge
rustic gull
#

I just decided to print them and copy paste instead of exec thanks

trim tangle
fierce ridge
tranquil turtle
#

!e

from __future__ import annotations
from typing import TypeVar

import ctypes

flags_offset = 21 * ctypes.sizeof(ctypes.c_size_t)
py_tpflags_basetype = 1 << 10

CT = TypeVar('CT', bound=type)

def final(cls: CT) -> CT:
    ctypes.c_size_t.from_address(id(cls) + flags_offset).value ^= py_tpflags_basetype
    return cls

@final
class X: ...

class Y(X): ...
rough sluiceBOT
#

@tranquil turtle :x: Your 3.11 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 18, in <module>
003 | TypeError: type 'X' is not an acceptable base type
trim tangle
#

I thought you meant, like, disallowing append on a const list

fierce ridge
#

oh yeah no

#

i think javascript has the same "hole" in its const annotation

#

the variable is "constant", not the value therein

soft matrix
#

yeah i was just about to say isnt this something you can still do in js

trim tangle
#

because, well, it's generally undecidable

#

simplest case: the attribute is of an abstract type -- you literally don't know if a given method is mutating it

rare scarab
#

Though typescript has as const for literals. It's not enforced at runtime, but the type checker does

slender timber
#

I think the benefits of true consts only really apply to compiled languages

#

Is a constant in Python (variable which is never changed) inlined everywhere its used?

trim tangle
#

Well, we're talking about a different thing I think

karmic zealot
#

Oh I didn't see this channel!
I've compromised with a different solution but would like to do what I discussed here:
#help-burrito message

Would appreciate it if someone wanted to take a look

slender timber
#

My test suit nosedived into taking 6 seconds for what took 0.8-1 πŸ’€

tranquil turtle
karmic zealot
#

Yeah that’s a different solution for my compromise but how would I do this with config_class

tranquil turtle
#
class BaseClass:
    def __init_subclass__(cls):
        cls._config_cls = typing.get_annotations()['config']

class MyClass(BaseClass):
    config: SomeConfig
    # _config_cls = SomeConfig # will be assigned at MyClass class creation time
    def __init__(self):
        self.config = self._config_cls.from_env()
tranquil turtle
deft merlin
#

how do I fix this??
im trying to add a [str, str] key value pair to dict[str, Any]

buoyant swift
#

i think params is a dict[str, dict[str, Any]]

deft merlin
#

aha, i c the problem, thanks :D

strong chasm
#

question: what is the general type-hint for AST nodes?
browsing the source for ast apparently they all subclass ast.AST but pycharm still complains

strong chasm
#

thanks, so i'm guessing it's the .pyi stubs that are wrongly generated

oblique urchin
#

pycharm's type checker is spotty sometimes

rare scarab
#

If it works in mypy, maybe open a bug report on youtrack

wispy hazel
#

Any idea what may cause mypy to complain about the same types?

>>> "Incompatible return value type (got "Optional[List[StatementLine]]", expected "Optional[List[StatementLine]]")mypy(error)"

Couldn't replicate this with simpler objects.

oblique urchin
wispy hazel
#

no, just this one (it's a NamedTuple)

soft matrix
wispy hazel
#

not really. I've tried quite a few combinations to replicate this, but no success, I was wondering if there was a known setup that would cause this type of behavior

#

now thinking about it again, my best bet is that this is related to the cache, since this is an intermittent issue, and hard to replicate

trim tangle
#

at least the imports

#

oh wait, intermittent

#

yeah that's what you get when you solve a declarative task in a very imperative way πŸ™‚

soft matrix
#

That's different

slender timber
#

Is parsing Annotated types slow?

oblique urchin
fierce ridge
#

wow mypy v0.981 is a huuuge improvement

#

finally going through the release blog post

#

really exciting stuff in here

#

callable attributes, recursive type aliases, typeddict kwargs

#

also "implicit" abstract methods in protocols is a feature that i didn't even know i wanted until right now

rare scarab
#

Have a link?

fierce ridge
#

i've lately started putting a link to the changelog for every dependency in my projects

brisk heart
#

I can finally remove the majority of my type ignores

slender timber
slender timber
#

Is mypy really this dumb

trim tangle
#

the top one will accept name=42 while the bottom one won't

fathom river
#

what's the use of Concatenate?

trim tangle
fathom river
#

oh, so it's like used to "append" any other additional types to a Callable?

oblique urchin
#

prepend only, but yes

fathom river
#

ah, I see, thank you!

slender timber
#

Why does a TypeVar need us to type a name twice? Can't object.__set_name__ be used by it?

rare scarab
#

that only works for object attributes

slender timber
#

Does it?

rare scarab
#

I think

slender timber
#

It takes an instance and a name arg

rare scarab
#

!e ```py

am I doing this right?

class a:
def set_name(self, obj, n):
print(n)

x = a()

class b:
c = a()

rough sluiceBOT
#

@rare scarab :white_check_mark: Your 3.11 eval job has completed with return code 0.

c
slender timber
#

Not inatance, it takes owner

#

Hmm, sad

summer berry
#

There is a PEP that proposes to add new syntax for type variables

slender timber
#

It should work for modules too ig since modules are nothing but objects after all

rare scarab
#

it's owner, not instance.

slender timber
#

yes

#

Can we allow overriding methods to have different arg names if we prefix the arg names with two underscores?

#

Have seen that quite a lot in typeshed.pyi

rare scarab
#

you could also make it positional only using /

#
def foo(a, b, /, c):...
oblique urchin
#

the double underscore thing means the argument is positional-only

#

it's a hack for parsers that don't support the / syntax from PEP 570

rare scarab
#

or for python versions that don't support /

#

was that 3.8 or 3.9?

oblique urchin
#

!pep 570

rough sluiceBOT
#
**PEP 570 - Python Positional-Only Parameters**
Status

Final

Python-Version

3.8

Created

20-Jan-2018

Type

Standards Track

oblique urchin
#

3.8

slender timber
#

It was * before instead of / wasn't it?

rare scarab
#
  • is for kwonly args
slender timber
#

It just came like itself, like how / is just a single symbol

pastel egret
#

* makes things after it keywords only, / makes things before it positional only.

slender timber
#

Like (a, *, b)

slender timber
pastel egret
#

No.

#

In def func(a, *, b) you can still do func(a=..., b=...).

slender timber
#

Oh positional only means you can't pass them by kwargs at all?

pastel egret
#

Yeah.

rare scarab
#
def func(a, /, *, b): ...

func("a", b="b")
pastel egret
#

Which is useful because def func(spam, /, **kwargs) can accept func("eggs", eggs=4, kwargs=6) - since it's positional, that's not ambiguous.

slender timber
#

What is the advantage of * and /

pastel egret
#

Something like dict.update() needs that to ensure all possible keywords are still valid.

slender timber
#

Caller should be smart enough

rare scarab
#

example with dict.update. d.update(d2, x=y) is not valid (I think). You can make sure this doesn't happen by using * and / (though it's technically kwargs)

pastel egret
#

* is useful to force passing by keywords, to avoid being able to call a function like func("first", "second", 2, -1, True, False) - it's very unobvious what all those parameters mean. If you have to pass by keyword it's more clear.

slender timber
#

It sometimes happens to me as well, I get confused whether I should pass by kwarg or not

#

Enforcing it can be a good thing

#

But is this a type hint feature or python feature?

pastel egret
#

Python feature.

oblique urchin
slender timber
#

Hm

pastel egret
#

As seen above / was added in 3.8.

slender timber
#

Yea

#

Why can't TypedDict be use as type param?

#

Will it be ever possible

oblique urchin
slender timber
#

I want to use TypedDict for ctor kwargs, making it a typevar will help to avoid casting it from a plain dict everytime

oblique urchin
#

!pep 692

rough sluiceBOT
#
**PEP 692 - Using TypedDict for more precise \*\*kwargs typing**
Status

Draft

Python-Version

3.12

Created

29-May-2022

Type

Standards Track

slender timber
#

Because in child classes I can't change the type and even if I do it still gets detected as Any

soft matrix
#

anyone know how to use param spec with pyre?

#

i actually cant figure out how to make the revealed type show anything useful

#

i also cant figure out why this doesnt work

#

even with pyre_extensions

fierce ridge
#

does it not support ParamSpec?

south topaz
#

isnt it Callable[P, int] not Callable[[P], int, maybe thats why it expects P to be a type

fierce ridge
#

hah, normally gobot is correcting me on my misuses of paramspec

soft matrix
#

Maybe trying to do this stuff at 1 o'clock isn't a good idea

slender timber
#

I am trying to build dataclasses like classes for binary structs. (PEP593 inspired)
which look like this:

@dataclasses.dataclass    # Get all the dataclass goodies bundled
class MyStruct(Struct):
    int1: u8
    bool1: b00l

Impl: https://paste.pythondiscord.com/ixorizawar
However only basic types work, I need to work on the Enum (adapter / converter) for example.
I don't know what type hinting stuff I should use to make it work like this (I think __class_getitem__ might be useful):

class MyEnum(enum.IntEnum):
    A = 1

@dataclasses.dataclass    # Get all the dataclass goodies bundled
class MyStruct(Struct):
    int1: u8
    bool1: b00l
    enum_u8: Enum[u8, MyEnum]

such that enum_u8 will get parsed as u8 and returned as MyEnum?
Should I make use of the attrs package for the conversion part (dunno how, but should I?)

#

I am even thinking if I could just use an int like an annotated type int[bytes=1, endian="little"] so that, the types like u8 etc aren't needed and it looks more Pythonic?

#

also if there's by any chance a maintained library already doing what I am trying to do, please let me know

oblique urchin
#

for that maybe add another decorator that wraps or stacks on top of dataclass

slender timber
oblique urchin
slender timber
#

oh

#

yea that makes sense

#

how to detect annotated types by isinstance, the docs mention something about it, but i think it checks forT of Annotated[T, x]

soft matrix
#

Generic enum breaks the behaviour

#

You can't then access members by name dynamically using getitem

pure sonnet
#

any way i can do this?

T = TypeVar("T")
U = TypeVar("U")
V = Union[T, U]

class Vec(Generic[V]):
  def __new__(cls, *args, **kwargs):
    # how can i know which variant the Vec is?
    ...

vec = Vec[T]()
acoustic thicket
#

i dont understand the intent behind

T = TypeVar("T")
U = TypeVar("U")
V = Union[T, U]

class Vec(Generic[V]):
soft matrix
#

one day 🀞youll be able to just do ```py
class Vec[V]:
def new(cls, *args, **kwargs) -> Self:
type_param: type[V] = V.value

or something
pure sonnet
trim tangle
pure sonnet
#
vec1 = Vec[T]()
vec2 = Vec[U]()
trim tangle
#

and, well, Vec[T]() isn't valid on its own because T doesn't mean anything

pure sonnet
#

vec1's inner buffer stores smth else

trim tangle
#

hm?

pure sonnet
#

T typevar

#
from __future__ import annotations

from array import array
from typing import Union
from typing import Generic
from typing import TypeVar


b = TypeVar("b", bound=int)    # 'b' signed integer     1
B = TypeVar("B", bound=int)    # 'B' unsigned integer   1
u = TypeVar("u", bound=int)    # 'u' Unicode character  2 (see note)
h = TypeVar("h", bound=int)    # 'h' signed integer     2
H = TypeVar("H", bound=int)    # 'H' unsigned integer   2
i = TypeVar("i", bound=int)    # 'i' signed integer     2
I = TypeVar("I", bound=int)    # 'I' unsigned integer   2
l = TypeVar("l", bound=int)    # 'l' signed integer     4
L = TypeVar("L", bound=int)    # 'L' unsigned integer   4
q = TypeVar("q", bound=int)    # 'q' signed integer     8 (see note)
Q = TypeVar("Q", bound=int)    # 'Q' unsigned integer   8 (see note)
f = TypeVar("f", bound=float)  # 'f' floating point     4
d = TypeVar("d", bound=float)  # 'd' floating point     8

T = Union[b, B, u, h, H, i, I, l, L, q, Q, f, d]

class Vec(Generic[T]):
    def __new__(cls, *args, **kwargs) -> Vec[T]:
        return super().__new__(cls)

    def __init__(self, len_: int) -> None:
        self.__buffer = array()
        self.__len = 0

    @classmethod
    def new(cls) -> Vec[T]:
        return cls()


v = Vec[]
#

cursed ik

trim tangle
#

That's now how typevars are supposed to be used

#

A typevar is for linking two types together

brisk hedge
#

you want a type alias

#

(or a newtype)

trim tangle
#

Yeah a newtype would work

#

hmm

brisk hedge
#

Type variables are used for polymorphism, which in this case means that b could stand for any type that's "at least an integer", rather than a specific signed integer type

pure sonnet
#

im asumming i can do

#
vec = Vec(dtype=smth)
#

instead

trim tangle
#

You probably want something like

@dataclass(frozen=True)
class ElementType(Generic[T]):
    code: str
    size: int
    python_type: type[T]

u8 = ElementType("b", 1, int)
u16 = ElementType("H", 1, int)

``` and then you can call `Vec(42, u8)`
pure sonnet
#

ooooo

trim tangle
#

maybe you could show how you'd actually use the class?

pure sonnet
#

i like that yeah yeah

#

have no ideas yet

#

just fcking around, finding out stuff

#

experrimenting

brisk hedge
pure sonnet
#

i dont see why not

brisk hedge
#

though ideally you'd want it to be more like

class Vec(Generic[T]):
  @classmethod
  def new(cls, dtype: Dtype & ElementType[T]): ...
#

if you want to be able to handle inputs

#

like telling vec.append(1) apart from vec.append(1.2)

tranquil turtle
pure sonnet
#

alr thanks

tranquil turtle
#

in some place i have this code:

@classmethod
@functools.cache
def __class_getitem__(cls: TT, key: T) -> TT:
    assert not isinstance(key, tuple), 'tuple parametrization is not implemented'
    if isinstance(key, TypeVar):
        return cls
        # return types.GenericAlias(cls, key)  # type: ignore[return-value]

    key_name = key.__name__ if hasattr(key, '__name__') else ''.join(filter(str.isalnum, repr(key)))  # type: ignore[attr-defined]
    return types.new_class(  # type: ignore[return-value]
        f'{cls.__name__}_{key_name}',
        (cls,),
        None,
        lambda ns: ns.update({'__generic_type__': key}),
    )

it creates subclass with class variable __generic_type__, and i can get it from instance if i want
in this case i have almost no overhead on instance creating time

#
# pseudocode:
>>> X[int]
<class 'X_int'>
>>> x = X[int]()
<'X_int' instance>
>>> x.__generic_type__
<class 'int'>
pure sonnet
#

i love this

rare scarab
#

What if key is a tuple?

#

X[A, B]

pure sonnet
#

ah

tranquil turtle
rare scarab
#

It kind of reminds me of a java TypeToken

soft matrix
#

This is unnecessary

#

You can already get the generic alias

tranquil turtle
#

i love __slots__, so i have no space for __orig_class__ attr

rare scarab
#

Tried this? ```py
def class_getitem(cls, key):
class X(cls):
generic_type = key
X.name += "_" + keyname
return X

tranquil turtle
rare scarab
#

but it uses familiar syntax

tranquil turtle
#

i dont care, it is implementation detail

pure sonnet
tranquil turtle
#

it is almost the same as class statement and types.new_class

#

i just chose one of three options

pure sonnet
#

ah i see

pure sonnet
tranquil turtle
#

cool

pure sonnet
#
def __class_getitem__(cls, key):
    key_name = getattr(key, "__name__", "".join(filter(str.isalnum, repr(key))))
    return type(f"{cls.__name__}_{key_name}", (cls,), {"__generic_type__": key})
#

this is good

tranquil turtle
pure sonnet
#

i will keep that in mind

tranquil turtle
#
T = TypeVar('T')
TT = TypeVar('TT', bound=type)
class GenericMixin(Generic[T]):
    __slots__ = ()
    __generic_type__: type[T]
    # __generic_type__: ClassVar[type[T]] # mypy is angry about this

    @classmethod
    @functools.cache
    def __class_getitem__(cls: TT, key: T) -> TT:
        assert not isinstance(key, tuple), 'tuples not implemented'
        if isinstance(key, TypeVar):
            return cls # should i return types.GenericAlias instead?
            # return types.GenericAlias(cls, key)  # type: ignore[return-value]

        key_name = getattr(key, '__name__', ''.join(filter(str.isalnum, repr(key))))

        return types.new_class(  # type: ignore[return-value]
            f'{cls.__name__}_{key_name}',
            (cls,),
            None,
            lambda ns: ns.update(
                {
                    '__generic_type__': key,
                    '__module__': cls.__module__,
                }
            ),
        )
``` complete code
soft matrix
tranquil turtle
# soft matrix __orig_class__ is hardly that big right?

it is hard to access generic attr from __orig_class__
you should do self.__orig_class__.__origin__.__args__[0]
im my case i can do self.__generic_type__

nice bonus: it is faster and dont require extra space in __slots__

soft matrix
tranquil turtle
#

bruh, my bad πŸ˜„

#

why ClassVar[...] cannot contain typevars?

PEP 526:

Note that a ClassVar parameter cannot include any type variables, regardless of the level of nesting: ClassVar[T] and ClassVar[List[Set[T]]] are both invalid if T is a type variable.

it is not true, sometimes it does make sense and it is useful

trim tangle
#

which yes, might be useful, but currently there's no way to restrict it to that

#

or maybe you have something different in mind?

soft matrix
#

there was talk of removing that in the last typing meeting

tranquil turtle
near mural
#

Hi! I'd like to make the Result enum from rust in python. And I have I problem: how can I type hint value?

class Result(Generic[T, E]):
    success: bool
    value: T if success else E

(please ping me)

near mural
tranquil turtle
#
class Result(Generic[T, E]):
    value: T | E

class Ok(Result[T, Any]):
    value: T

class Err(Result[Any, E]):
    value: E

``` in this case you dont need `success` at all
tranquil turtle
trim tangle
#

This is better than a single class because it plays nicely with match

near mural
#

Ok. Thanks!

tranquil turtle
soft matrix
trim tangle
#

Python doesn't have sealed classes so that's not very useful

thick stream
#

How do I hint

{1: [[2000, 981], [2060, 981], [2120, 981], [2180, 981]],
 2: [[2000, 1037], [2060, 1037], [2120, 1037], [2180, 1037]],
 3: [[2000, 1093], [2060, 1093], [2120, 1093], [2180, 1093]],
 4: [[2000, 1149], [2060, 1149], [2120, 1149], [2180, 1149]],
 5: [[2000, 1205], [2060, 1205], [2120, 1205], [2180, 1205]],
 6: [[2000, 1261], [2060, 1261], [2120, 1261], [2180, 1261]],
 7: [[2000, 1317], [2060, 1317], [2120, 1317], [2180, 1317]]}

I'm trying to do this, but it's highlighting that there's a problem.

 dict[int:list[[int,int]]]
#

nvm...

dict[int:list[list[int,int]]]
soft matrix
#

you need to use a , not :

thick stream
#

oh?

acoustic thicket
#

yeah

#

its a funny coincidence that its valid syntax in the first place, lol

trim tangle
#

you'll have to use tuples instead of lists though

#

although that looks like a strange structure. what does it represent?

#

It would probably be better if you introduced some kind of dataclass, because a 2-tuple doesn't mean anything

thick stream
#

@trim tangle it's representing row and columns of pixels.

soft matrix
#

whats the default type for an unknown TypeVarTuple? i was under the impression it was *tuple[Any, ...] but im being told by eric its *tuple[()] but i cant see either mentioned in pep 646

soft matrix
slender timber
#

I am beginning to think, what Annotated tries to achieve can already be done by descriptors, why was it created when descriptors exist?

#

Anyways the metadata of Annotated is used at runtime, so descriptors can do stuff like "ValueRange" etc

trim tangle
#

I think that can be used with discord.py for example to specify a converter for each argument

slender timber
#

Could might as well be int

#

Or a custom class called U8 deriving from int?

#

Or just a NewType?

trim tangle
agile jolt
#

Just wanted someone to double check in case I am going mad but when updating an old existing type hint of the below to 3.10

def _parse_args(
        self, to_parse: str, /
    ) -> tuple[
        Dict[str, Dict[str, Union[int, str, List[str], None, Dict[str, Union[int, str]], Dict[str, int | list[str]]]]],
        Dict[str, str],
    ]:

It would simply become

tuple[dict[str, dict[str, int | str | list[str] | None | dict[str, int | str | list[str]]]], dict[str, str]]:

Or am I missing something?

trim tangle
#

You should probably introduce some dataclasses at least

tranquil turtle
trim tangle
#

I don't think it's going to make it better

soft matrix
#

you should probably use a TypedDict at the very least if possible

blazing nest
#

Thanks, I don't entirely hate it

slender timber
#

Just... why?

#

Should I use __call__ instead and return the Annotated type?

torpid yarrow
slender timber
#

@soft matrix are there any TypedDict available for type.__new__'s ns (namespace) arg?

soft matrix
soft matrix
slender timber
#

How to get the enclosing class's (analogous to owner class in descriptors) type hint in __class_getitem__ or should I use a descriptor for that?

blazing nest
#

I am a bit confused by that term overall

void panther
#

Say I have an union like SomeGeneric[Literal["a"], int] | SomeGeneric[Literal["b"], str], is there any way to have a function take the literal string and return the appropriate type that's paired in the generic?

trim tangle
#

Can you provide more context?

void panther
# trim tangle Can you provide more context?

I'm working with a lib that does something like this

class PipelineAction:
    name: str

    def chain(self, other_action): 0
        # chains another action with its own name

    def run(self): 0
        # run all chained actions and map their values to names specified by name

    def get_by_name(self, name: str): 0
        # get a value by name from all the chained actions
    
    def create_value(self) -> SomeType: 0
        # called by run to create the value

but currently the types from create_value just get lost when get_by_name is used to extract the value

heady flicker
#

This is such a strange way to write defaults

rare scarab
#

What is up with the 0 return type?

heady flicker
#

I also thought that it's return type at first but look closer: it's the body

rare scarab
#

... or pass would be better suited for that.

heady flicker
#

Actually no. Docstrings would be perfect

rare scarab
#

I've been working in typescript, which uses : as the return type indicator

heady flicker
#

Because he has a comment for each one function anyways, he can use docstrings for the body

rare scarab
#

unless it's a function type declaration, then it's =>

slender timber
#

does pyright not understand @no_type_check

rare scarab
#

you should use # type: ignore

#

is that from pycharm?

soft matrix
#

no its a typing function

rare scarab
#

decorator?

#

!d typing.no_type_check

rough sluiceBOT
#

@typing.no_type_check```
Decorator to indicate that annotations are not type hints.

This works as class or function [decorator](https://docs.python.org/3/glossary.html#term-decorator). With a class, it applies recursively to all methods defined in that class (but not to methods defined in its superclasses or subclasses).

This mutates the function(s) in place.
rare scarab
#

I intentionally don't support no_type_check. There are many ways to address type errors, and all of them are better than disabling type checking for entire functions.

#

Consider using typing.Annotation instead?

slender timber
#

Ok so I have this dependency which provides type hints (of a class) only for __new__ and not __init__, atleast as of latest release
This is a mistake dev fixed probably in latest commit, but till then I have to opt out of type checks

rare scarab
#

then use # type: ignore

slender timber
#

It doesn't stop pyright from complaining where the class is used

rare scarab
#

What's the dependency?

slender timber
#

construct-typed Adapter class

#

construct-typing is package name ig

#

lemme check

rare scarab
#

!pip construct-typing

rough sluiceBOT
slender timber
#

yes

rare scarab
#

last commit to the file Adapter is in was May last year

slender timber
#

no it was yesterday

rough sluiceBOT
#

construct-stubs/core.pyi line 187

class Adapter(```
slender timber
#

but it seems like there's no provision for extra args

#

which I need

rare scarab
#

Oh, I was looking in the wrong folder

#

You could pip install the repo

#

pip install git+https://github.com/timrid/construct-typing

slender timber
#

i generally hesitate installing ultra bleeding edge versions like that

rare scarab
#

then you'll have to deal with pyright errors until an update comes

slender timber
#

but anyways the Adapter ctor is type hinted to not take any extra args

rough sluiceBOT
#

construct-stubs/core.pyi lines 190 to 192

def __init__(
    self, subcon: Construct[SubconParsedType, SubconBuildTypes]
) -> None: ...```
rare scarab
slender timber
#

That doesn't allow for more args

rare scarab
slender timber
#

are we allowed to change ctor signature?

#

in type-safe world

rare scarab
#

with overridden, yes, as long as you can call the original (though that's optional)

slender timber
#

hmm then yea

#

time to go bleeding edge

rare scarab
#

only temporarially (:p)

slender timber
#

i did the pip install it didn't install in the venv

rare scarab
#

add -U

slender timber
#

I did

#

-U is --upgrade right

rare scarab
#

yes.

#

what was the pip output?

slender timber
#

hangon

#
Collecting git+https://github.com/timrid/construct-typing
  Cloning https://github.com/timrid/construct-typing to c:\users\\appdata\local\temp\pip-req-build-ix8lxspx
  Running command git clone --filter=blob:none --quiet https://github.com/timrid/construct-typing 'C:\Users\\AppData\Local\Temp\pip-req-build-ix8lxspx'
  Resolved https://github.com/timrid/construct-typing to commit e10938f30838a13f27cae3c0ff5865ee4606b847
  Preparing metadata (setup.py) ... done
Requirement already satisfied: construct==2.10.67 in f:\prog\python\pyflp\venv\lib\site-packages (from construct-typing==0.5.2) (2.10.67)
#

@rare scarab

rare scarab
#

add -f

slender timber
#

didn't work

#

ok i uninstalled and reinstalled

#

it worked

#

weird pip issues

rustic gull
#

What even is type-hinting

proud brook
#

Hinting types of objects

rustic gull
#

m nice

proud brook
#

Mainly for those who read the code and type checkers

green gale
proud brook
#

You also get attribute suggestions if your editor has intellisence

rare scarab
#
def foo(s): ...
``` what type is s?
rustic gull
#

LOL thats funny, i have seen people use this and kinda followed it but dident even know what it was.

( i turned off ping)

rustic gull
rustic gull
#

LAMO

proud brook
blazing cobalt
#

I want to make a CLI wrapper for pyright to give --quiet output like pytest. Anyone know which libraries would help? Rich and an option parser? Is there something already made for doing this?

tranquil turtle
#

Why there is no Sized in bases?

oblique urchin
#

though I don't understand that comment, there's actually a PR right now to change it

rough sluiceBOT
#

stdlib/typing.pyi line 328

class Sized(Protocol, metaclass=ABCMeta):```
`stdlib/typing.pyi` line 456
```pyi
# Implement Sized (but don't have it as a base class).```
tranquil turtle
#

isnt is easier to just add Sized to bases? What was the reason to not add it to bases?

soft matrix
#

Is there anything in the git blame?

tranquil turtle
#
GitHub

Instead define abstract len in affected classes.

Fixes #2655 without breaking
https://github.com/rominf/ordered-set-stubs/issues/1

GitHub

#2602 caused this to behave differently in mypy Python 2 and 3 modes: reveal_type(['a', {'b'}]) In Python 2 mode it shows this: Revealed type is 'builtins.li...

atomic lodge
#

Hey guys. How can I correctly type hint things in my project when I use mysql.connect which does not seem to use type hints in its own code. My current approach for the connection and cursor objects looks like this

from mysql.connector import MySQLConnection
from mysql.connector.cursor import CursorBase

db: MySQLConnection = MySQLConnection(**db_config)
cursor: CursorBase = db.cursor()

Whereas for the other objects, mostly just results of the fetch*() methods, I inspected what I would get as a result and just set a type hint for my variable based on that whilst also adding a # type: ignore so that my linter wouldn't keep bothering me because all it knows is that the fetch*() methods all return None, which they don't always do, e.g.

cursor.execute("SHOW TABLES FROM table")
tables: list[tuple[str]] = cursor.fetchall() #type: ignore

But especially this part feels very prone to errors. Is there any better way? Thanks in advance.

buoyant swift
#

that seems difficult, since the type system can't really know how many columns a specific table would have. the type of the return differs based on a string, so the type system wouldn't be able to do anything, i think. as far as manually doing it, i have no idea

fierce ridge
#

you might need to create a "shell" around the untyped library using typing.cast, assert, isinstance, and other "type-narrowing" functionality

empty hull
#

How can I correctly type new attributes that I add to a log record using get/setLogRecordFactory?

#

I tried this but it fails

paper salmon
#

is it possible to provide types for generic methods when subclassing? ```py
E = TypeVar('E')
T = TypeVar('T')
S_co = TypeVar('S_co', bound='PageSource', covariant=True)
V_contra = TypeVar('V_contra', bound='PaginatorView', contravariant=True)

class PageOption(Generic[S_co]): ...
class PageSourceProto(Protocol[T, S_co, V_contra]):
def get_page(self, index: int) -> T: ...
def get_page_options(self, view: V_contra, page: T) -> list[PageOption[S_co]]: ...
def format_page(self, view: V_contra, page: T) -> str: ...
class PageSource(PageSourceProto[T, S_co, V_contra], Generic[T, S_co, V_contra]): ...
class ListPageSource(PageSource[list[E], S_co, V_contra], Generic[E, S_co, V_contra]): ...

Intended usage:

class MyPageSource(ListPageSource[str, PageSource, PaginatorView]):
def format_page(self, view, page):
# view should be inferred as PaginatorView,
# and page inferred as list[str]
return '\n'.join(page)``` The idea is that PageSource and ListPageSource are base classes with partial implementations of PageSourceProto. Users are meant to subclass one of them and provide the types in inheritance so users don't need to manually typehint the protocol methods. Is this possible? Or should I not be doing this at all?

fierce ridge
empty hull
#

Yes, I could've directly made the class with added annotations but I chose what I did

fierce ridge
#

so yeah i think your best option would be to actually subclass LogRecord here

#

or write a protocol that covers both LogRecord and your mixin

#

i've always wanted a way to construct a protocol from an existing concrete class

empty hull
#

Same

soft matrix
#

I'm not a big fan of adding special casing to the type system

fierce ridge
#

my use case is: someone writes a custom class, i want to use "any class that is compatible with that class", but without re-writing their entire class

tranquil turtle
#
x: Protocol[SomeClass] = OtherClass()
# or
x: Implements[SomeClass] = OtherClass()
tranquil turtle
slender timber
#

How is isinstance different from the second

#

If it isn't why does it exist

blazing nest
tranquil turtle
# slender timber If it isn't why does it exist

type(x) is X checks that x is instance of exact X, not of subclass of X
issubclass(type(x), X) checks that type(x) is subclass of X (note: X is subclass of X)
isinstance(x, X) checks that x.__class__ is subclass of X

usually type(x) and x.__class__ are the same, but in very rare case, if you define __class__ property in your class, x.__class__ wont be equal type(x)

slender timber
#

Til that type(x) is X isn't the same as isinstance

#

Well it makes sense

#

How is X a subclass of X?

#

Its the same clas

tranquil turtle
#

!e bool is subclass of int

x = True
print(type(x) is int) # False
print(isinstance(x, int)) # True

print()

print(issubclass(bool, int)) # True
print(issubclass(int, int)) # True, because issubclass(X, X) is always true
rough sluiceBOT
#

@tranquil turtle :white_check_mark: Your 3.11 eval job has completed with return code 0.

001 | False
002 | True
003 | 
004 | True
005 | True
tranquil turtle
# slender timber How is X a subclass of X?

its convenient
very often you need instance of some type, so it is ok to have that exact type or its subclass
so, isinstance(x, X) is true, iff x is instance of exact X or of subclass of X

otherwise, you should do these checks: isinstace(x, X) or type(x) is X or issubclass(cls, X) or cls is X
i think we should go to #offtop channel

paper salmon
#

not what i hoped for but at least i know my typevar/generic stuff isnt messed up

soft matrix
paper salmon
#

its in context to the subclass

soft matrix
#

Oh ic

blazing nest
#

It's similar to TypeScript I guess, where a lot of things can be inferred by having the library do most of the typing work

#

Do we have inference in cases like these in Python? ```python
def add_callback(func: Callable[[int], object]) -> None:
...

add_callback(lambda var: var + 1)

paper salmon
#

with some testing it seems mypy can infer it for inline lambdas but not for functions or lambdas assigned to a variable

soft matrix
#

Pyright seems to do it

brittle socket
#

It doesn't 😒

#

Ah but mp.pool.Pool does πŸ™‚

soft matrix
#

what does it say about mp.Pool?

oblique urchin
#

fun fact mp.Pool is a function

#

or a bound method to be precise

rough sluiceBOT
#

stdlib/multiprocessing/pool.pyi line 71

class Pool:```
rare scarab
#

so is it ```py
def Pool(*args, **kwargs):
return pool.Pool(*args, **kwargs)

#

Ah, it's from a context var

fierce ridge
#

TIL on that

dull lance
#

How can I bound a ParamSpec so that Callable[P, Any] only accepts functions that only have keyword arguments?

#

I'm trying to write a decorator that only operates on such functions, but I also want to type hint that the signature of the output function is the same as that of the input function

oblique urchin
#

maybe you can bind a TypeVar (not a ParamSpec) to a callable protocol that accept **kwargs: Any

dull lance
#

That didn't work, **kwargs only matches functions that accept any keyword arguments, but won't match those that have specific keyword arguments Nvm, it was just me not type hinting the return types correctly

void panther
#

Is there a reason why the typevars of stdlib collections that need washables aren't bound to Hashable?

tranquil turtle
#

because there is no Hashable type actually

oblique urchin
#

seems like the main thing was that mypy thought types weren't Hashable

slender timber
#

how to override base class instance method arg type in child class?

soft matrix
#

There isn't a safe way to do that

#

Assuming it's not a subclass of the type

trim tangle
#

or an example

void panther
oblique urchin
slender timber
#

I am beginning to believe that inheritance is actually bad

#

Composition requires way less thinking than inheritance

trim tangle
slender timber
#

no it wont

trim tangle
#

it will

soft matrix
#

they arent subclasses

trim tangle
#

well, if Child inherits from Base it does

slender timber
#

don't take the type hints literally

trim tangle
#

uhh

slender timber
#

in my case they are different enum subclasses

trim tangle
#

is it a metaphor? πŸ˜„

#

well can you show the real code?

slender timber
#

but I have a huge hierarchy of classes using my custom enum class already

#

and there's an another enum class which is not a base class of my custom enum class

#

hence the incompatibility

soft matrix
#

cant you annotate the superclass as taking the superclass of the 2 enums?

#

and hence make it safe for lsp?

trim tangle
slender timber
#

I can but I just think its not worth the effort and wrote another class, it will do too many changes, break a few things

soft matrix
#

that should be safe πŸ€”

slender timber
#

not like that

trim tangle
#

what is it then?

slender timber
#
class MyEnumMeta(enum.EnumMeta):
    ...

class MyEnum(int, enum.Enum, metaclass=MyEnumMeta):
    ...

class AnotherEnum(enum.IntEnum):
    ...

class Base:
    def ins(self, id: MyEnum):
        ...

class SomeDistantChild(Base):
    def ins(self, id: AnotherEnum):
        ...
trim tangle
#

Well, MyEnum and AnotherEnum are not related at all

soft matrix
#

composition isnt gonna save you from this, this is still unsafe

slender timber
#

I made SomeDistantChild not base off of Base

slender timber
#

but it proved to be a wrong idea anyway

#

and now I have 2 copies of almost same classes

opal dagger
#

Hello, I'm wondering if python has a library or a future spec that could read types from the available docstring.

I think the docstrings are more verbose that basic type annotations and could provide both documentation and type hinting.

oblique urchin
#

however, docstrings come in many formats. the value of type annotations is that they're definitely machine-readable

#

for example, type checkers would not necessarily know what "any" means in your example

opal dagger
oblique urchin
#

I'd advise against including types in docstrings since they're redundant with the annotations

trim tangle
#

yeah, they are guaranteed to de-synchronize πŸ™‚

opal dagger
#

i have more type hints than docstrings. But when looking to document stuff for others it'd be nice to access type info. like someObject.__annotations__ only shows the return type

soft matrix
#

It shouldn't only show the return type if you annotate the other parameters

lucid quiver
#

Can someone help me to understand why the type narrowing not working?

soft matrix
#

Can you give an example where you think it's not working?

lucid quiver
#

class TSessionParams(TypedDict):
    type: Literal["snmp"]
    host: "str"
    port: int


class TSnmpSessionParamsV1V2c(TSessionParams):
    version: Literal["v1"] | Literal["v2c"]
    community: str


class TSnmpSessionParamsV3Base(TSessionParams):
    version: Literal["v3"]
    username: str


class TSnmpSessionParamsV3NoAuthNoPriv(TSnmpSessionParamsV3Base):
    security: Literal["noAuthNoPriv"]


class TSnmpSessionParamsV3AuthNoPriv(TSnmpSessionParamsV3Base):
    security: Literal["authNoPriv"]
    auth_protocol: Literal["md5"] | Literal["sha"]
    auth_key: str


class TSnmpSessionParamsV3AuthPriv(TSnmpSessionParamsV3Base):
    security: Literal["authPriv"]
    auth_protocol: Literal["md5"] | Literal["sha"]
    auth_key: str
    priv_protocol: Literal["des"] | Literal["aes"]
    priv_key: str


TSnmpSessionParamsV3 = (
    TSnmpSessionParamsV3NoAuthNoPriv
    | TSnmpSessionParamsV3AuthNoPriv
    | TSnmpSessionParamsV3AuthPriv
)

TSnmpSessionParams = TSnmpSessionParamsV1V2c | TSnmpSessionParamsV3


This is the definition

#
class SnmpSession(Session):

    def __init__(self, parameters: "TSnmpSessionParams") -> None:
        super().__init__(parameters)
        credentials: V1 | V2C | V3
        match parameters["version"]:
            case SnmpVersion.V1:
                credentials = V1(parameters["community"])
            case SnmpVersion.V2C:
                credentials = V2C(parameters["community"])
            case SnmpVersion.V3:
                credentials = V3(username=parameters["username"])
                match parameters["security"]:
                    case V3Security.NO_AUTH_NO_PRIV:
                        ...
                    case V3Security.AUTH_NO_PRIV:
                        credentials.auth = Auth(
                            key=parameters["auth_key"].encode(),
                            method=parameters["auth_protocol"],
                        )
                    case V3Security.AUTH_PRIV:
                        credentials.auth = Auth(
                            key=parameters["auth_key"].encode(),
                            method=parameters["auth_protocol"],
                        )
                        credentials.priv = Priv(
                            key=parameters["priv_key"].encode(),
                            method=parameters["priv_protocol"],
                        )
                        
#

when i am using match pattern, it does not narrow it, but when i am using if statement it does

#
src/connections/sessions/snmp_session.py:47: note: Revealed type is "TypedDict('connections._types.TSnmpSessionParamsV1V2c', {'type': Literal['snmp'], 'host': builtins.str, 'port': builtins.int, 'version': Union[Literal['v1'], Literal['v2c']], 'community': builtins.str})"
src/connections/sessions/snmp_session.py:50: note: Revealed type is "Union[TypedDict('connections._types.TSnmpSessionParamsV1V2c', {'type': Literal['snmp'], 'host': builtins.str, 'port': builtins.int, 'version': Union[Literal['v1'], Literal['v2c']], 'community': builtins.str}), TypedDict('connections._types.TSnmpSessionParamsV3NoAuthNoPriv', {'type': Literal['snmp'], 'host': builtins.str, 'port': builtins.int, 'version': Literal['v3'], 'username': builtins.str, 'security': Literal['noAuthNoPriv']}), TypedDict('connections._types.TSnmpSessionParamsV3AuthNoPriv', {'type': Literal['snmp'], 'host': builtins.str, 'port': builtins.int, 'version': Literal['v3'], 'username': builtins.str, 'security': Literal['authNoPriv'], 'auth_protocol': Union[Literal['md5'], Literal['sha']], 'auth_key': builtins.str}), TypedDict('connections._types.TSnmpSessionParamsV3AuthPriv', {'type': Literal['snmp'], 'host': builtins.str, 'port': builtins.int, 'version': Literal['v3'], 'username': builtins.str, 'security': Literal['authPriv'], 'auth_protocol': Union[Literal['md5'], Literal['sha']], 'auth_key': builtins.str, 'priv_protocol': Union[Literal['des'], Literal['aes']], 'priv_key': builtins.str})]"
#

this is what reveal_type shows

#

I am missing something?

soft matrix
#

the TypedDicts might need to be @final

#

ugh sorry

lucid quiver
#

yeah kinda weird

slender timber
slender timber
#

How can I remove the self cast of pl_event here?

pl_event = None

if ...:
    pl_event = ...

for ... in ...:
    items = []
    for i, item in enumerate(pl_event or []):
        pl_event = cast(PlaylistEvent, pl_event)
#

isn't it obvious that the loop won't happen at all if a [] is enumerated?

tranquil turtle
#

you can add assert pl_event or put entire for-loop or its body into if pl_event:

slender timber
#

the code above is simplified

tranquil turtle
#
pl_event = None

if ...:
    pl_event = ...

for ... in ...:
    items = []
    for i, item in enumerate(pl_event or []):
        assert pl_event # <--- add this
        # pl_event = cast(PlaylistEvent, pl_event) # cast no longer needed
slender timber
#

i never add any assert in production code, maybe I can just use

if pl_event is None:
    ...

# rest of the code...
#

but why is this not automatically inferred?

oblique urchin
#

type checkers would need to know quite a bit about runtime behavior to infer this

tranquil turtle
#

I don't quite understand what I want to say or suggest, but here is some idea:

# there is a lot of important parts missing

class Falsy(Protocol):
    def __bool__(self) -> Literal[False]: ...

class Truthy(Protocol):
    def __bool__(self) -> Literal[True]: ...

TruthyIterable = Truthy & Iterable # or class TruthyIterable(Truthy, Iterable, Protocol): ...
FalsyIterable = Falsy & Iterable
T = TypeVar('T', bound=TruthyIterable | FalsyIterable)
G = TypeVar('G')

# then special-case iteration over FalsyIterable in type-checker such that code inside it become unreachable
for i in FalsyIterable():
    # unreachable, not type-checked

# iterables are narrowed inside for-loop body
it = SomeIt() # maybe empty
for i in it:
    reveal_type(it) # TruthyIterable & SomeIt


def enumerate(it: T) -> T: ...
def map(f: ..., it: T) -> T: ...
@overload
def range(n: Literal[0]) -> FalsyIterable: ...
def reversed(it: T) -> T: ...
@overload
def sorted(it: FalsyIterable, ...) -> list[Any] & Falsy: ...
@overload
def sum(it: FalsyIterable, start: G = ...) -> G: ...
@overload
def max(it: FalsyIterable, default: G, key=...) -> G: ...
@overload
def len(it: FalsyIterable) -> Literal[0]: ...
@overload
def any(it: FalsyIterable) -> Literal[False]: ...
@overload
def all(it: FalsyIterable) -> Literal[True]: ...

class tuple:
    @overload
    def __bool__(self: tuple[()]) -> Falsy: ...

class str:
    @overload
    def __bool__(self: Literal['']) -> Falsy: ...

class bytes:
    @overload
    def __bool__(self: Literal[b'']) -> Falsy: ...

@overload
def filter(f: ..., it: FalsyIterable) -> FalsyIterable: ...
@overload
def filter(f: Callable[[Any], Falsy], it: Iterable) -> FalsyIterable: ...
@overload
def filter(f: ..., it: Iterable) -> Iterable: ...

lucid quiver
#

has incompatible type "TEndpointParams"; expected "Dict[str, Any]"

class TEndpointParams(TypedDict):
    host: "str"
    port: int
#

mypy you're crazy

soft matrix
#

its not

#

you cant delete keys from a TypedDict but you can for a dict

lucid quiver
#

I am sending typedict to function who get dict[str,Any]

#

i dont see how typedict and dict is not the same

#

so should i use Mapping instead?

#

Mapping seems to solve it

soft matrix
#

yeah TypedDict is compatible with Mapping

trim tangle
#

subtyping is sometimes mind-bending πŸ™‚

lucid quiver
#

yeah kinda hard

#

I cant understand why type narrowing not wokring for a union of types

soft matrix
#

same typeddict issue?

#

are the classes decorated as final and are you using pyright?

lucid quiver
#

yeah same issue as before

#

using vscode with pylance (he is using pyright behind the scenes to me knowledge)

soft matrix
#

this looks like a pyright bug if it works with if but not match

lucid quiver
#

but mypy complains

soft matrix
#

mypy doesnt support final typeddicts yet

#

or it doesnt perform narrowing on them atm

lucid quiver
#

I am wondering is anyone know about a package who can make Json-Schema as typing?

rare scarab
#

You'd need a mypy plug-in.

#

Though there's probably one that turns it into typeddicts

#

!pip json-schema-codegen

rough sluiceBOT
rustic gull
#

Should I use the LiteralString type hint over str?

tranquil turtle
#

in general, no

rare scarab
#

do it if the code you use it with is vulnerable to an injection attack, like an sql query or shell command

rustic lagoon
#

am i expecting too much from the type hints here?

from typing import Callable, TypeVar

from typing_extensions import reveal_type

A = TypeVar("A")
B = TypeVar("B")
C = TypeVar("C")
D = TypeVar("D")


def bifunc(
    left: Callable[[A], B], right: Callable[[C], D]
) -> Callable[[tuple[A, C]], tuple[B, D]]:
    return lambda args: (left(args[0]), right(args[1]))


def left(left: Callable[[A], B]) -> Callable[[tuple[A, C]], tuple[B, C]]:
    return bifunc(left, lambda x: x)


def right(right: Callable[[C], D]) -> Callable[[tuple[A, C]], tuple[A, D]]:
    return bifunc(lambda x: x, right)


if __name__ == "__main__":
    some_tuple = (3, "k")
    other_tuple = left(lambda x: x + 3)(some_tuple)
    reveal_type(other_tuple) # Pyright: Type of "other_tuple" is "tuple[Unknown, Literal['k']]"
#

I feel like it should be able to infer the type of the left item in the tuple

#

since the constraints on it should come from the argument applied to the function returned from left

#

even if i directly annotate the type of the function returned by left, pyright is not able to figure out the lambda argument types

if __name__ == "__main__":
    some_tuple = (3, "k")
    # Pyright: Operator "+" not supported for types "A@left" and "Literal[1]"
    # Β Β Operator "+" not supported for types "object*" and "Literal[1]" when expected type is "int"
    # Pyright: Return type of lambda is unknown
    l_fn: Callable[[tuple[int, str]], tuple[int, str]] = left(lambda x: x + 1)
    other_tuple = l_fn(some_tuple)
    reveal_type(other_tuple)  # Pyright: Type of "other_tuple" is "tuple[int, str]"
rare scarab
#

What's the type of left?

#

Hmm..

rustic lagoon
#

left returns a function over pairs that applies the first item in the pair to the passed function and returns a pair with the result and the other element of the pair

fierce ridge
#

@rustic lagoon under mypy, it can't figure out the type of the lambda

rustic lagoon
#

it's annoying how this does not type check sad

if __name__ == "__main__":

    def double(x: int) -> int:
        return x * 2

    words = ["foo", "bar", "baz"]

    double_word_zip = map(left(double), zip(range(10), words))

    print(list(double_word_zip))  # [(0, 'foo'), (2, 'bar'), (4, 'baz')]
fierce ridge
#

idk about map, that might have other issues

#

the function name and parameter name being the same might get really funky

#

i didn't even consider that python would allow that

#

i assume the parameter name takes precedence

rustic lagoon
#

yeah, but that can just get changed

rustic lagoon
#

i obviously can't expect python to be haskell, but those types should be possible to infer

module Main where

bifunc :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)
bifunc fl fr = \(l, r) -> (fl l, fr r)

left :: (a -> b) -> (a, c) -> (b, c)
left lf = bifunc lf id

right :: (a -> b) -> (c, a) -> (c, b)
right rf = bifunc id rf

main :: IO ()
main =
  let someTuple = (3, "k")
      otherTuple = left (\x -> x + 3) someTuple -- otherTuple :: (Integer, String)
      words = ["foo", "bar", "baz"]
      doubleWordZip = map (left (\x -> x * 2)) $ zip [0 ..] words -- doubleWordZip :: [(Integer, String)]
   in print otherTuple >> print doubleWordZip
#

this is obvrioulsy not idiomatic nor good haskell, but i just wanted it to shadow the python code as closely as possible

fierce ridge
#

well yeah, hindley-milner vs. whatever the fuck python is

fossil nest
#

any ideas why this occurs?

#

.host is clearly a string

#

so why does pylance flag it

trail kraken
#

Can the parent object be None?

fossil nest
#

ahh it could be

#

interesting

#

thank you

#

im not really sure what circumstance would result in a None address but still it could be None πŸ₯΄

#

might edit the starlette module code to remove this error since ive never encountered a None address before

#

hence my confusion

green gale
fossil nest
green gale
#

what's the function?

#

if you look at the source code

#

you'll probably get an idea

fossil nest
#

this is what i changed it too

    @property
    def client(self) -> Address:
        # client is a 2 item tuple of (host, port), None or missing
        host_port = self.scope.get("client")
        return Address(*host_port)

but i dont see a scenario where the address is None, if i ever encounter it then of course ill change it back to the original code

#

this is what it was before:

    @property
    def client(self) -> typing.Optional[Address]:
        # client is a 2 item tuple of (host, port), None or missing
        host_port = self.scope.get("client")
        if host_port is not None:
            return Address(*host_port)
        return None
trail kraken
#

Consider asserting that it is not None if you do not want to deal with the possibility.

young cloak
#

Is anyone aware of a way of checking if dict[Enum, T] contains elements for every member of Enum?

#

Pretty sure it would need a plugin.

slender timber
#

Could use a TypedDict instead of Enum

#

Or

young cloak
#

Typedicts only take strings as keys no?

slender timber
#

Dunno

#

I found TypedDicts really partially implemented

young cloak
#

But the best I could come up with was instead of writing the dicts as literals, use a metaclass to inject a classmethod map(cls, member1: T, member2: T, ...) -> Dict[Enum T] into every enum and write a plugin to type check that.

#

which worked

#

but i'm not very familiar with mypy plugins, and if there's a simpler way of doing it.

trail kraken
#

I am curious how this is used.

young cloak
#

[deleted]

#

very rough draft of what I was going for

trail kraken
#

The match-case statement might be of use here.

young cloak
#

Not sure id like to rewrite all of my simple dicts as function-wrapped match statements.

trail kraken
#

Would have quite a overhead as well.

#

Only skimmed the article, but it explains the situation well, I think.

cunning raven
#

I still kinda dont understand what the ellipisis is for in those parameters in overloaded functions/methods.

#


from typing import overload


@overload
def foo(x: int = ...) -> None: ...

# whatever comes next
hallow flint
#

it means "there is a default value for this parameter". so it means foo() is a valid call, as is foo(123)

#

with overloads in particular, it can help disambiguate what happens when nothing is passed in:

@overload
def foo(x: int = ...) -> int: ...
@overload
def foo(x: str) -> str: ...

^ here type checkers know that foo() will return an int
but if you have:

@overload
def foo(x: int) -> int: ...
@overload
def foo(x: str = ...) -> str: ...

then type checkers will know that foo() returns a str

lucid quiver
#

is there a way to make this typing work?


class A:
    async def test(self) -> None:
        return None

class B(A):
    ...

class TClassMapper(TypedDict):
    a: NotRequired['A']
    b: NotRequired['B']


g: TClassMapper = {}

async def test_typing():

    for x in g.values():
        await g[x].test() #type is object
    if 'a' in g:
        await g['a'].test() #type is correct
#

when iterating over the TypeDict instance the type of the value is object

soft matrix
#

you could make it final

lucid quiver
#

what to make final?

soft matrix
#

TClassMapper

lucid quiver
#

final is not supported with TypeDict

#

@final cannot be used with TypedDict [misc]mypy(error)

#

according to the error i get

soft matrix
#

oh youre using mypy

#

yeah well youre out of luck then

#

works with pyright

lucid quiver
#

any idea how to setup pyright with vscode?

soft matrix
#

should be installed if you install the python extension

#

you just need to set the typechecking mode to basic

lucid quiver
#

vscode still complains about the type being object

cunning raven
soft matrix
trail kraken
#

Been a while since I have used it. What does values() do?

slender timber
lucid quiver
slender timber
lucid quiver
#

well more correctly View

slender timber
#

Yes

trail kraken
#

So it contains value if we did d[key] = value?

soft matrix
trail kraken
#

I assume d[value] does not usually make sense?

soft matrix
#

im not sure tbh

#

maybe @trim tangle has more insight as to why this doesnt work

trail kraken
#

Oh. I'm slow. We are trying to get mypy to error on it?

soft matrix
#

no pyright shows that the type of .values() is dict_values[str, object] not dict_values[str, A | B] as it should be

#

when decorated with final

lucid quiver
#

I will use cast for now

trail kraken
#

Ah. We want ValueType to automatically be a Union of the given value types?

lucid quiver
#

yeah

soft matrix
#

this isnt supported so dict_values[str, union] wont be

cunning raven
#

Because if i foo() it'd check the first overloaded function

#

None is annotated in the return

#

But then would it approve the second one too?

#

If we pass nothing, means that x is set by default

#

Which would annotate return to int

tranquil turtle
#

typecheckers must use the first matching overload
so
foo() is None
foo(1) is int
foo('') is error

also, if you are not in stubs, you should provide actual implementation for function (without @overload)

fossil nest
#

we can discuss pydantic here right? I have a websocket connection, different kinds of JSON messages can be sent through and they can be distinguished by the type field like so:

{
    "type": "some-type-here",
    "data": {}
}

how can i use pydantic to automatically serialise the message based on the type
this is what i have but... it sucks basically (it works but i dont think its the best way)

class EventType(str, Enum):
    CONNECT = "connect"
    DISCONNECT = "disconnect"

class EventData(BaseModel):
    pass

class ConnectData(EventData):
    username: str

class DisconnectData(EventData):
    username: str

class EventRequest(BaseModel):
    type: EventType
    data: EventData

    @validator("data", pre=True)
    def valid_data(cls, value, values):
        match values["type"]:
            case EventType.CONNECT:
                value = ConnectData(**value)
            case EventType.DISCONNECT:
                value = DisconnectData(**value)
        return value

then i can just parse the recieved message to an EventRequest
i know this Connect and Disconnect models are the same here, this is just an example. is this really the best way to do this?

hallow flint
rare scarab
#

Is there a simple way to type this? ```py

async def compose(payload, *funcs):
for func in funcs:
payload = await func(payload)
return payload

#

payload should be the first function's arg, the last function should be the return type

rare scarab
#

Hm.. can I not have multiple overloads where the difference is the length of the *args unpack? ```py
@overload
async def compose(
payload: T1,
*funcs: Unpack[
tuple[
Callable[[T1], Awaitable[T2]],
Callable[[T2], Awaitable[T3]],
Callable[[T3], Awaitable[T4]],
Callable[[T4], Awaitable[T5]],
]
],
) -> T5:
...

#

That's what I get for trying to be fancy.

hallow flint
rough sluiceBOT
#

stdlib/builtins.pyi line 1700

def __new__(```
rare scarab
#

Yeah, I ended up doing that

brisk hedge
rare scarab
#

Does mypy fully support dataclass_transform yet?

rare scarab
#

Once sqlalchemy is at 2.0, I'll be happy

oblique urchin
fossil nest
#

is using type hints from the typing module bad/deprecated?
should we be using types or collections instead?

hallow flint
#

you can use if TYPE_CHECKING to simulate some use cases of dataclass_transform

#

if you’re using python 3.9 and newer, i’d prefer using the types in collections.abc

fossil nest
#

3.11 for me :)

slender timber
#

mypy is really going wacky over my codebase

#

its really slow

#

detects wrong types, and is quite slow

#

codebase isn't very big, 200kb combined

#

that's with all the comments, docstrings and license headers

eager vessel
slender timber
#

which is quite big ig

eager vessel
#

What are your settings for mypy?

rough sluiceBOT
#

pyproject.toml lines 62 to 66

[tool.mypy]
python_version = "3.7"
enable_incomplete_features = true
ignore_missing_imports = true
warn_no_return = false```
rough sluiceBOT
#

pyproject.toml lines 98 to 103

[tool.pyright]
ignore = ["./venv"]
reportPrivateUsage = false
reportMissingTypeStubs = false
venvPath = "."
venv = "venv"```
eager vessel
#

I have a pretty small project with 3k LOC, it takes 7 seconds for mypy to check it, that's without cache

slender timber
#

oh well its pylance - pyright that hangs as well\

#

type checkers should use rust coz blazing fast

eager vessel
#

It's easier to use python, plus iirc some parts of mypy use cython or c, I don't remember and I might be completely wrong

#
doctor@main MINGW64 /c/dev/help/PyFLP (master)
$ pdm run where mypy
C:\dev\help\PyFLP\.venv\Scripts\mypy.exe

doctor@main MINGW64 /c/dev/help/PyFLP (master)
$ pdm run mypy .
Success: no issues found in 24 source files
#

@slender timber πŸ€·β€β™‚οΈ

eager vessel
#

It runs fine

slender timber
#

yes ik

#

there are no issues

eager vessel
#

It's pretty fast too

slender timber
#

the "issues" it shows are due to glitchy behavious

eager vessel
#

A couple of seconds

slender timber
eager vessel
#

Wdym by "in vscode"? πŸ€”

slender timber
#

and i have enabled pyright and mypy both, maybe thats conflicting?

eager vessel
#

I usually just run mypy from time to time manually

slender timber
#

from python extension

#

like how pyright works through pylance

eager vessel
#

Idk, as I said I just run it manually and in CI

slender timber
#

that is slow

eager vessel
#

?

slender timber
#

the ide analysis

#

and at times the lsp server just crashes

#

need to reopen vscode

soft matrix
#

you can restart the lsp from within vsc

slender timber
#

but why does this happen

#

it also happens when i use the lib as a dependancy

#

does using too many type hints cause this?

tranquil turtle
#

Im using pyright lsp in sublime text. And sometimes it crashes and i should restart sublime to fix it. It happens on startup time of sublime or randomly later.

soft matrix
slender timber
#

pre-release of pylance?

#

or mypy

soft matrix
#

pyright

slender timber
#

ok

sick notch
#

Anyone has an idea of what happened here?

acoustic thicket
#

pycharm's typechecker being wonky as usual, i think

#

does this error too

def foo(col_name: str) -> bool:
    return "index" not in col_name
... = pd.read_excel(..., usecols=foo)
sick notch
#

lemme check

#

yes

sick notch
tranquil turtle
#

Try this:

#                    vvv pos-only arg
def foo(col_name: str, /) -> bool: ...
slender timber
#

how to completely exclude a library from mypy and pyright

#
import untyped_lib   # type: ignore

this work?

fierce ridge
fierce ridge
#

no idea, don't really use it

#

probably though

rare scarab
#

Pyright bug? (It should be an AsyncGenerator)

soft matrix
#

yeah that does look like a bug

#

whats the type of foo()?

rare scarab
#

Hm... Maybe it's just pylance.

#

foo() is just that yield

past summit
#

I'm a bit oblivious in the art of type hinting. But how would i go about hinting an iterable containing 2 iterables. With both 5 elements.

#

How detailed should i even go, should i just settle with defining it as a list or.

trim tangle
#

so tell more about what you're doing

rare scarab
#

tuple is the only iterable type that supports heterogeneous types

trim tangle
#

or like Gather().add(a_foo()).add(a_bar()).add(a_baz()).join()

rare scarab
#

So basically copying the javascript promise api

trim tangle
#

hm?

#

well, the only advantage here is to allow for ParamSpec

class Gather(Generic[Unpack[P]]):
    ...

    def add(self, other: Awaitable[T]) -> Gather[Unpack[P], T]: ...
#

In JavaScript you have Promise.all which is well-typed in TS πŸ˜›

rare scarab
#

a promise api actually would be useful for the compose function I made yesterday.

tranquil turtle
past summit
# trim tangle Depends on the context, as always πŸ™‚

def __init__(self, board: pygame.Surface, pieces: list[list[pygame.Surface]]): Basically board is a surface, and pieces contain all the surfaces for all the ches pieces for both colors so [[5 surfaces for white], [5 for black]]