Skip to content
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 for default types in TypedDict #6131

Open
rra opened this issue Jan 3, 2019 · 16 comments
Open

Support for default types in TypedDict #6131

rra opened this issue Jan 3, 2019 · 16 comments

Comments

@rra
Copy link
Contributor

rra commented Jan 3, 2019

This problem arose from trying to type the environ argument for a WSGI application. There are specific keys of the environ dict that have non-str types, and then all the other keys are HTTP_ variables (or server-defined variables, which can be ignored for this purpose) with type str (or Text, depending on the version of Python).

I would like to get stronger typing on environ than Dict[str, Any], but there isn't a way to do that with TypedDict currently because the set of possible keys is unbounded (the client can send any HTTP header).

Ideally, I'd like to be able to do something like:

EnvironDict = TypedDict("EnvironDict", {
    "wsgi.version": Tuple[int, int],
    "wsgi.input": IO[str],
# ...
}, default_type=str, total=False)

and have this mean that any key is allowed in the dictionary and all unknown keys get a value type of str.

@ilevkivskyi
Copy link
Member

Thanks for the proposal! Unfortunately, I don't think we will have time to work on this in short term, but we may raise priority if this request will appear again.

Also a random note: same functionality is available for protocols using __getattr__().

@JukkaL
Copy link
Collaborator

JukkaL commented Jan 3, 2019

We'd need a way to represent this using the class-based syntax as well.

@JelleZijlstra
Copy link
Member

In class-based syntax this could plausibly be supported as:

class EnvironDict(TypedDict, total=False, default_type=str):
    version: Tuple[int, int]

@DMR-coding
Copy link

I have a usecase this would be extremely helpful for as well, in the context of a physical modeling app. We have EXTREMELY large dictionaries of physical properties passed to models. They're mostly floating point measurements except for a small minority of values that are strings or nested dicts. Using a default type of float and only specifying the exceptions could improve concision by hundreds of lines.

@gu1p
Copy link

gu1p commented Oct 7, 2019

Please make this happen

@oren0e
Copy link

oren0e commented Jan 11, 2021

I join the requests - it will be super convenient if I could write:

class MyClass(TypedDict):
    a: int = 1
    b: int = 10
    v: Optional[int] = None

@gvanrossum
Copy link
Member

If anyone has a specific proposal to solve this please post to typing-sig.

@simon-liebehenschel
Copy link

@oren0e Why not just use the typing.NamedTuple then? https://docs.python.org/3/library/typing.html#typing.NamedTuple

class Employee(NamedTuple):
    name: str
    id: int = 3

@hellmrf
Copy link

hellmrf commented Sep 28, 2021

@oren0e Why not just use the typing.NamedTuple then? https://docs.python.org/3/library/typing.html#typing.NamedTuple

@AIGeneratedUsername, NamedTuples aren't supposed to work like dicts at runtime. See the following example.

from typing import NamedTuple, TypedDict, Optional


class EmployeeTuple(NamedTuple):
    name: str
    age: Optional[int] = 18


class EmployeeDict(TypedDict):
    name: str
    age: int


def show_employee(age: int, name: str) -> None:
    print(f"{name} is {age} years old.")


empdict = EmployeeDict(name='Alice', age=18)
emptup = EmployeeTuple(name='Bob')


show_employee(**empdict) # "Alice is 18 years old." Works as expected.
show_employee(*emptup) # "18 is Bob years old." Doesn't work.
show_employee(**emptup) # TypeError: show_employee() argument after ** must be a mapping, not EmployeeTuple

@fellnerse
Copy link

Is this going to be implemented? Feels a bit weird missing default values here

@gvanrossum
Copy link
Member

If you want this you should ask on the typing tracker https://github.com/python/typing/discussions

@fellnerse
Copy link

fellnerse commented Apr 28, 2022

Thanks, maybe it would make sense to close this issue here then
Here is the discussion at python typing: python/typing#1165

@adam-grant-hendry
Copy link

adam-grant-hendry commented Jun 14, 2022

> I join the requests - it will be super convenient if I could write: > > ```python > class MyClass(TypedDict): > a: int = 1 > b: int = 10 > v: Optional[int] = None > ```

You might be able to get away with using the Annotated type here, though that was not its intended purpose as stated in PEP 593 and the word "annotated" itself would be a misnomer:

from typing import Annotated, Optional

class MyClass(TypedDict):
    a: Annotated[int, 1]
    b: Annotated[int, 10]
    v: Annotated[Optional[int], None]

NOTE: Variables can't be used in the class definition unless its a type alias, so you can't simply write

DefaultArg = Annotated

and use that because you have to specify the indeces to Annotated to make it an alias (e.g.

`DefaultIntArg = Annotated[int, 1]  # defeats the purpose

so you have to use "Annotated" for now.

Apologies, the discussion is at python/typing#1165

@tommyjcarpenter
Copy link

I started migrating all TypedDicts to dataclasses due to this issue, as dataclasses support this feature.

@gvanrossum
Copy link
Member

I started migrating all TypedDicts to dataclasses due to this issue, as dataclasses support this feature.

Good for you. A coding style using dataclasses is much more readable than one using dictionaries as records.

@jzazo
Copy link

jzazo commented Oct 16, 2022

I started migrating all TypedDicts to dataclasses due to this issue, as dataclasses support this feature.

Hi @tommyjcarpenter, how would you do that? How do you add a default type for undefined attributes in a dataclass? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests