Similarly, but perhaps not _exactly_ the same issue, something like this could also open up the ability to assign a variable with a "smaller" `TypedDict` type to one that's "larger". Not being able to do this has caused me to bang my head against the wall a lot in the past, and I even implemented a special method + mypy plugin to allow me to do so, which feels very clunky. e.g. ``` class APIData(TypedDict, open=True): id: int name: str class ServiceData(TypedDict, total=False): id: int name: str title: str ... api_data: APIData = {'id': 5, 'name': 'Jenn'} service_data: ServiceData = api_data # This errors with the existing API, but with `open=True` or a similar option, maybe not. ``` On Thu, Mar 5, 2020 at 1:22 PM Brett Cannon <brett@python.org> wrote:
On Thu, Mar 5, 2020 at 2:13 AM Elazar <elazarg@gmail.com> wrote:
בתאריך יום ה׳, 5 במרץ 2020, 5:40, מאת Shantanu Jain < hauntsaninja@gmail.com>:
One workaround is to nest the unknowable part of the dictionary: ``` class ErrorOnly(TypedDict): error: str data: Dict[str, Any] ```
PEP 589 says:
The use of a key that is not known to exist should be reported as an error, even if this wouldn't necessarily generate a runtime type error. These are often mistakes, and these may insert values with an invalid type if structural subtyping hides the types of certain items. For example, d['x'] = 1 should generate a type check error if 'x' is not a valid key for d (which is assumed to be a TypedDict type).
The disallowing typos / dumb mistakes makes sense. I guess the point about structural subtyping is if you had: ``` class SecretError(ErrorOnly): details: int ``` You wouldn't be able to prevent: ``` def f(e: ErrorOnly) -> None: e['details'] = 'something bad happened here'
f(secret_error) ```
That can be solved by making it explicit somehow, an "open dict".
class Error(TypedDict): error: str ... # ellipsis
Or
class Error(TypedDict, open=True): error: str
Or some other syntax. Then forbid inheritance from such open dicts (or allow inheriting types to only have `Any` values, and forbid removal of values).
Yeah, I was looking for something like this "open dict" idea. Basically I want the type system to express that I guarantee some key(s), but others may exist and you can use them but you need to do an appropriate check before trying to access them.
-Brett
Elazar
On Wed, 4 Mar 2020 at 17:45, Guido van Rossum <guido@python.org> wrote:
OK, that's unfortunate. There's a good reason for this very strict behavior of TypedDict, although I always forget what it is (maybe careful reading of PEP 589 would reveal it -- perhaps it's just due to mutability / variance, i.e. the same reason you can't pass a subclass of List to a function taking a List).
On Wed, Mar 4, 2020 at 5:04 PM Brett Cannon <brett@python.org> wrote:
Quick proof-of-concept code:
from typing import TypedDict
class ErrorOnly(TypedDict): error: str
def get_error() -> ErrorOnly: return {"error": "something bad happened", "details": "some stuff" }
def process_error(err: ErrorOnly) -> str: return err["error"]
process_error(get_error())
Result was an error on get_error():
A.py:7: error: Extra key 'details' for TypedDict "ErrorOnly" Found 1 error in 1 file (checked 1 source file)
On Wed, Mar 4, 2020 at 4:14 PM Guido van Rossum <guido@python.org> wrote:
When you try the TypedDict, what error do you get? (I think totality should be true BTW.)
On Wed, Mar 4, 2020 at 16:12 Brett Cannon <brett@python.org> wrote:
> Looking at TypedDict it seems that it does not like the idea of > superfluous keys existing in a dict. In my case I have a REST call > returning JSON for an error and all I'm guaranteed is to get an "error" > key. But there may be extra keys that provide more details about the > specific error. Unfortunately I don't know the exhaustive list of keys so I > can't use a TypedDict with `totality == False` to try to be complete. > > I can't think of any way to somehow say "require/expect this one > key, but other keys are OK". Am I missing anything that would let me do > this? > _______________________________________________ > Typing-sig mailing list -- typing-sig@python.org > To unsubscribe send an email to typing-sig-leave@python.org > https://mail.python.org/mailman3/lists/typing-sig.python.org/ > -- --Guido (mobile)
-- --Guido van Rossum (python.org/~guido) *Pronouns: he/him **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...> _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
_______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/
_______________________________________________
Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/