-
-
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
TypedDict keys reuse? #4128
Comments
This is currently not possible. We will probably need the |
We now have a |
Another4 request for this appeared, see #8186, so raising priority to normal. |
(Just to clarify, we can start from only supporting final names for individual keys, which should be pretty easy.) |
@ilevkivskyi I agree that we can just support final names for keys first, at least for NamedTuple, as stated at the end of PEP-591:
It is sometimes useful to have different types on the same label as well:
|
is there any update on this issue when Final is used? This seems last updated about two years ago I would expect this to be legal:
|
Let me know if you'd like me to remove this and create a separate issue if it's off scope. This falls under the canopy of Allow all "typed fields" / keyed data structures to reuse their typings. e.g. Scenario: Typed exports from dataclassAssume my case, I want to offer users ability to export a typed tuple and dict from my #!/usr/bin/env python
import dataclasses
from typing import NamedTuple, TypedDict, get_type_hints
class DetailsDict(TypedDict):
name: str
age: int
address: str
class DetailsTuple(NamedTuple):
name: str
age: int
address: str
@dataclasses.dataclass
class Details:
name: str
age: int
address: str
def to_dict(self) -> DetailsDict:
# return dataclasses.asdict(self, dict_factory=DetailsDict)
return DetailsDict(**dataclasses.asdict(self))
def to_tuple(self) -> DetailsTuple:
# return dataclasses.astuple(self, tuple_factory=DetailsTuple)
return DetailsTuple(*dataclasses.astuple(self))
john = Details(name="John", age=25, address="123 Address St")
print(john)
print(john.to_dict())
print(john.to_tuple())
print(get_type_hints(john))
print(get_type_hints(john.to_dict))
print(get_type_hints(john.to_tuple)) Output:
Why would a user want to reuse dict/tuple/etc?
ProblemWe have to redeclare the same field annotations for dict, tuple, and dataclass SolutionWe need a way to reuse the field typings across the different keyed data structures. |
class CreateArgs(TypedDict):
first_name: str
last_name: str
external_id: str
address: str
city: str
phone: str
zip: str
email: str
state: str
class UpdateArgs(TypedDict, total=False):
first_name: str
last_name: str
external_id: str
address: str
city: str
phone: str
zip: str
email: str
state: str type CreateArgs = {
first_name: string;
last_name: string;
external_id: string;
address: string;
city: string;
phone: string;
zip: string;
email: string;
state: string;
};
type UpdateArgs = Partial<CreateArgs>; For me it's not about compliance, neither an open-source library. |
This commit will enable mypy strict mode, and update code accordingly. Type annotations are not used at runtime. The standard library `typing` module includes a `TYPE_CHECKING` constant that is `False` at runtime, but `True` when conducting static type checking prior to runtime. Type imports will be included under `if TYPE_CHECKING:` conditions. These conditions will be ignored when calculating test coverage. https://docs.python.org/3/library/typing.html The Python standard library `logging.config` module uses type stubs. The typeshed types for the `logging.config` module are used solely for type-checking usage of the `logging.config` module itself. They cannot be imported and used to type annotate other modules. For this reason, dict config types will be vendored into a module in the inboard package. https://github.com/python/typeshed/blob/main/stdlib/logging/config.pyi The ASGI application in `inboard.app.main_base` will be updated to ASGI3 and type-annotated with `asgiref.typing`. Note that, while Uvicorn uses `asgiref.typing`, Starlette does not. The type signature expected by the Starlette/FastAPI `TestClient` therefore does not match `asgiref.typing.ASGIApplication`. A mypy `type: ignore[arg-type]` comment will be used to resolve this difference. https://asgi.readthedocs.io/en/stable/specs/main.html Also note that, while the `asgiref` package was a runtime dependency of Uvicorn 0.17.6, it was later removed from Uvicorn's runtime dependencies in 0.18.0 (encode/uvicorn#1305, encode/uvicorn#1532). However, `asgiref` is still used to type-annotate Uvicorn, so any downstream projects like inboard that type-check Uvicorn objects must also install `asgiref`. Therefore, `asgiref` will be added to inboard's development dependencies to ensure that type checking continues to work as expected. A Uvicorn options type will be added to a new inboard types module. The Uvicorn options type will be a `TypedDict` with fields corresponding to arguments to `uvicorn.run`. This type can be used to check arguments passed to `uvicorn.run`, which is how `inboard.start` runs Uvicorn. Uvicorn 0.17.6 is not fully type-annotated, and Uvicorn does not ship with a `py.typed` marker file until 0.19.0. It would be convenient to generate types dynamically with something like `getattr(uvicorn.run, "__annotations__")` (Python 3.9 or earlier) or `inspect.get_annotations(uvicorn.run)` (Python 3.10 or later). https://docs.python.org/3/howto/annotations.html It could look something like this: ```py UvicornOptions = TypedDict( # type: ignore[misc] "UvicornOptions", inspect.get_annotations(uvicorn.run), total=False, ) ``` Note the `type: ignore[misc]` comment. Mypy raises a `misc` error: `TypedDict() expects a dictionary literal as the second argument`. Unfortunately, `TypedDict` types are not intended to be generated dynamically, because they exist for the benefit of static type checking (python/mypy#3932, python/mypy#4128, python/mypy#13940). Furthermore, prior to Uvicorn 0.18.0, `uvicorn.run()` didn't enumerate keyword arguments, but instead accepted `kwargs` and passed them to `uvicorn.Config.__init__()` (encode/uvicorn#1423). The annotations from `uvicorn.Config.__init__()` would need to be used instead. Even after Uvicorn 0.18.0, the signatures of the two functions are not exactly the same (encode/uvicorn#1545), so it helps to have a static type defined. There will be some other differences from `uvicorn.run()`: - The `app` argument to `uvicorn.run()` accepts an un-parametrized `Callable` because Uvicorn tests use callables (encode/uvicorn#1067). It is not necessary for other packages to accept `Callable`, and it would need to be parametrized to pass mypy strict mode anyway. For these reasons, `Callable` will not be accepted in this type. - The `log_config` argument will use the new inboard dict config type instead of `dict[str, Any]` for stricter type checking.
I may be in a need of the following - two
TypeDict
s with the same keys, one of them created withtotal=False
:Is there a way to reuse the keys instead of having to repeat the
{'name': str, 'age': int, address: str}
fragment twice?I can't do
Because
(which is quite reasonable, tried that on the off chance it'd work)
The text was updated successfully, but these errors were encountered: