I prefer frozen datatypes as they prevent accidental modification of data that isn’t supposed to be modified.
Often I have to move around datas in dicts (i.e. read from a json).
To have this data properly typed I used TypedDict.
But I can’t set the TypedDict to “ReadOnly”.
Currently I do something like this
from typing import TypedDict
import json
import types
class Data(TypedDict):
foo: str
bar: int
def read_data() -> Data:
with open("file.json", "r") as f:
return cast(Data, types.MappingProxyType(json.load(f)))
Which works fine to prevent runtime modification of data. But I would like the TypeChecker to understand as well, that setting data is invalid.
Would it make sense to introduce a TypedMapping to Python which is basically a TypedDict but without the __setitem__ method and del methods.
If yes would it also make sense to create a class methods for TypedDict like TypeDict.from_typed_mapping(DataMapping) and TypedMapping.from_typed_dict(Data)?
This would help to only define larger TypedDicts and use them in different contexts.
Also this could help to write the types for types.MappingProxyType. Because as I user I would expect that if I insert a TypedDict inside it, a TypedMapping is detected by the type checker.
I am aware that a Mapping[str, str] is different of dict[str, str] as Mapping[str, str] can contain SubclassOfStr("a") wheras dict[str, str] can’t. That might be worth to consider.
Thanks for the hint.
Yes it goes in the direction. But having a lot of attributes that could be cumbersome.
I am thinkinng more of
from typing import TypedDict, ReadOnly
import json
import types
class Data(TypedDict):
foo: str
bar: int
# super many other arguments
def read_data() -> ReadOnly[Data]:
with open("file.json", "r") as f:
data = cast(Data, json.load(f))
return types.MappingProxyType(data)
Important here
I have runtime safe read only behaviour (the PEP explicitly states it only changes the type behaviour)
correct typing of types.MappingProxyType if handed in a TypedDict
Unfortunately that opens up more issues, like, what about nested TypedDicts, should we recurse into them and mark them ReadOnly too? What about lists and other mutable collections?
It’s certainly possible to solve this problem but I think it will be through a more generic type transformation system rather than cherry-picking simple cases.
I would expect such a type would conform with the runtime types, therefore mutable values would likely be allowed. For myself, I just want some way to return a MappingProxyType with typed information for each key.
Whether this is with a specific TypedMappingProxyType, a generic TypedMapping, or marking all the keys of a TypedDict ReadOnly, doesn’t matter too much to me. (Though I’m guessing the last option won’t work because of the inheritance behaviour in PEP 705).
Using types.MappingProxyType on any dict does not care about nested mutables, so shouldn’t ReadOnly (or what ever).
The thing you suggesting sound more like a freeze which converts all mutables to immutables.
PEPs going in this direction have been rejected so far, so there is no runtime representation of this atm in the Standard Lib.
So why should I need a typing representation for this?
Basically I want be able to express types.MappingProxyType(typed_dict) properly for a TypeChecker.
I could also imaging just adding a .as_mapping_proxy_type property to TypedDict.
So this would be:
def read_data() -> Data.as_mapping_proxy_type:
with open("file.json", "r") as f:
data = cast(Data, json.load(f))
return types.MappingProxyType(data)
But reading PEP 705 again I already see this example:
blur["members"] = ["Damon Albarn"] # Type check error: "members" is read-only
blur["members"].append("Damon Albarn") # OK: list is mutable
So actually I would like to propose only ReadOnly[AnyTypedDict] that return a modified AnyTypedDict with all attributes being marked as ReadOnly.
Actually unsing ReadOnly on the complete TypedDict was discarded by PEP 705 saying:
This would naturally want to be defined for a wider set of types than just TypedDict subclasses, and also raises questions about whether and how it applies to nested types. We decided to keep the scope of this PEP narrower.
I guess the question for nested types is answered using above and I would argue that other will types already could want it to be defined for.