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)
_______________________________________________
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/