1

I defined the following types:

KRPCTypes = typing.Union[int, bytes, list, "KRPCDict"]
KRPCDict = typing.Dict[bytes, KRPCTypes]

When I run mypy, I get the following error:

error: Invalid type "test.KRPCDict"

Here is the complete minimal code that reproduces the error:

import typing

KRPCTypes = typing.Union[int, bytes, list, "KRPCDict"]
KRPCDict = typing.Dict[bytes, KRPCTypes]

Thanks!

Bora M. Alper
  • 3,538
  • 1
  • 24
  • 35
  • Apparently mypy does not support recursive types yet: https://github.com/python/mypy/issues/731 (Quoting the lead developer: "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." [on 2015; but it seems it's still not implemented]) – Bora M. Alper Jun 14 '17 at 17:31
  • What about the string-literal-based version: `Tree_Type = TypeVar('Tree_Type', bound='Tree')` and `Tree = Dict[str, Union[Tree_Type, str]]` (for a tree of str-paths→str)? I didn't test too deeply but as far as I tested, this worked. – Alfe Jan 08 '18 at 12:37

1 Answers1

2

Unfortunately, mypy, and the Python typing ecosystem, currently doesn't support recursive types.

You can find the issue for it here: https://github.com/python/mypy/issues/731 (though you should ignore some of the posts in the middle because they were posted by people who ended up having an unrelated issue).

The main blocker in the thread (e.g. "we should implement structural subtyping first") is under active development and hopefully should become a part of at least mypy in the next few months, so perhaps it might be worth reviving the discussion.

The current workaround many people tend to use (especially when trying to type JSON, which your types resemble) is to manually expand the recursive type to the desired level and eventually bottom out with Any. For example:

from typing import Union, Dict, List, Any

KRPCTypes = Union[int, bytes, list, Dict[bytes, Union[int, bytes, list, Any]]]
KRPCDict = Dict[bytes, KRPCTypes]

Incidentally, you may want to use typing.List[T] and specify what type the list is supposed to contain -- if you do just list, it defaults to typing.List[Any], which is less precise then it could be.

An alternate approach may be to use the experimental TypedDict type, which lets you define the exact types and structure of a given dictionary. This is less useful in that TypedDict can't represent every single kind of KRPCDict, but does come in handy if you expect to handle only a finite number of different kinds of KRPCDict types.

There's no documentation regarding TypedDict yet (the devs want to work out all the major bugs first before publicizing it), but if you want to try tinkering with it, I wrote an example of how you would use it at the bottom of this (largely unrelated) answer.

Michael0x2a
  • 58,192
  • 30
  • 175
  • 224