-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support recursive types #731
Comments
If (or when) mypy will have structural subtyping, recursive types would also be useful there. |
My current plan is to postpone recursive types until simple structural subtyping is in and reconsider them later. After thinking about them more they are going to increase complexity a lot of I haven't seen much evidence for them being needed that often. |
If I'm understanding this issue right, I'm running into it for classes that want a fluent interface. So for example, if I want callers to do something like this: myfoo.add(bar).add(baz).finish() Then the definition of the class Foo:
def add(self, x) -> Foo: # Python chokes on this line!
# do stuff
return self Another place where Python commonly does |
@oconnor663 Try: class Foo:
def add(self, x) -> 'Foo':
# do stuff
return self |
Ah, thank you. |
@kirbyfan64, do you know if there are standard functions anywhere that understand this convention? Like, if I wanted to introspect a couple functions and compare the types of their arguments, should I handle the |
@oconnor663 I don't think there's anything like that. If you're introspecting the functions via a decorator, you could try accessing the caller's globals and locals. |
You're aware of typing.get_type_hints(obj) There used to be an instance() implementation in typing.py but Mark Shannon On Fri, Oct 16, 2015 at 9:37 AM, Ryan Gonzalez notifications@github.com
--Guido van Rossum (python.org/~guido) |
@gvanrossum that's exactly what I was looking for, thanks. Sorry for the n00b questions today, but awesome that all this is supported. |
Mypy should detect missing string literal escapes (see #948). |
Going back to the original point on the issue, I found a case in the stdlib where this would be needed; the type for def isinstance(o: object, t: Union[type, Tuple[type, ...]]) -> bool: ... but it should actually be: ClassInfo = Union[type, Tuple['ClassInfo', ...]]
def isinstance(o: object, t: ClassInfo) -> bool: ... Because according to https://docs.python.org/3/library/functions.html#isinstance the tuples can be nested. I found an actual example of this while typechecking |
Mypy doesn't support recursive types yet, so we can't properly express TSerializable nested structures. For now, we just disable type checking in the appropriate locations. python/mypy#731
I have come across this while trying to define a generic JSON type:
So consider this a +1 for supporting this use case. |
@srittau JSON needs to be Any because it is recursive and you can give json.loads a custom JSONEncoder class: _PlainJSON = Union[Dict[str, "_PlainJSON"], List["_PlainJSON"], str, int, float, bool, None]
_T = TypeVar('_T')
JSON = Union[_PlainJSON, _T, Dict[str, "JSON"], List["JSON"]]
def loads(data: str, cls: Type[JSONEncoder[_T]]) -> JSON: ... of course recursive types and |
The following pattern seems to be good enough for my purposes. The boilerplate is tolerable for me.
|
Latest version of pattern. We use this example at Legalese for interacting with SMT solvers (the SMTLIB language). I found that I ended up forgetting to use the typed
|
Already supported in current Mypy: python/mypy#731. The definition of DumperKey was wrong anyway, in a way causing mypy to crash: see python/mypy#14000.
It appears that v0.990/v0.991 may not have addressed the entirety of the challenge that is recursive/cyclic types: #14219 |
For those reading in posterity:
So with |
It doesn't work in this case: from collections.abc import Sequence
from typing import TypeAlias
FloatVector: TypeAlias = Sequence[float]
FloatTensor: TypeAlias = FloatVector | Sequence["FloatTensor"]
rejected_float_vector: FloatVector = "ok" # OK: rejected
accepted_float_tensor: FloatTensor = [[[3.14]]] # OK: accepted
rejected_float_vector1: FloatTensor = object() # OK: rejected
rejected_float_vector2: FloatTensor = "fail" # FAIL: accepted https://mypy-play.net/?mypy=latest&python=3.12&flags=strict&gist=da0434e6062956cfd667a9e8c8bd3ff9 |
@jorenham Thanks for the report! Can you please open a new issue? |
@jorenham Beware that this EDIT: we would need inductive types. If Tensor = Sequence[float] | Map[Sequence, Tensor] |
In numpy the current maximum number of dimensions is 64, so that would indeed be possible. But in order to keep error messages from getting to long, and the type-checking from becoming to slow, I decided to go for this concise yet "broader" approach instead. |
This made me realize that some of the numpy array-like type aliases in |
The following in particular would be useful:
The text was updated successfully, but these errors were encountered: