11from __future__ import annotations
22from abc import ABC
3- from typing import get_type_hints , get_origin , get_args , TypeVar , Tuple , Type
3+ from typing import get_type_hints , get_origin , get_args , TypeVar , Tuple , Type , Generic
44from types import UnionType , NoneType
55from . import io_safe
6- from . sessions import SessionFileFull , SessionFileKey , SessionFileWhere , SessionDirFull , SessionDirWhere
6+ from .sessions import SessionFileFull , SessionFileKey , SessionFileWhere , SessionDirFull , SessionDirWhere
77
88
99
1212
1313
1414def get_type_hints_excluding_internals (cls ):
15- type_hints = {}
15+ """
16+ Get type hints of the class, excluding double dunder variables.
17+ """
1618 for var_name , var_type in get_type_hints (cls ).items ():
1719 if var_name .startswith ("__" ) and var_name .endswith ("__" ):
1820 continue
19- type_hints [var_name ] = var_type
20- return type_hints
21-
22-
23-
21+ yield var_name , var_type
2422
2523
2624
@@ -29,26 +27,31 @@ def fill_object_from_dict_using_type_hints(obj, cls, data: dict):
2927 Attributes of obj are set using the data dict.
3028 The type hints of the class cls are used to determine which attributes to set.
3129 """
32- for var_name , var_type in get_type_hints_excluding_internals (cls ).items ():
30+ for var_name , var_type in get_type_hints_excluding_internals (cls ):
31+ var_type_args = get_args (var_type )
32+ var_type_origin = get_origin (var_type )
3333 # Check if variable is nullable (e.g. email: str | None)
34- nullable = get_origin (var_type ) is UnionType and NoneType in get_args (var_type )
3534 # When it is not nullable but not in the data, raise an error
3635 if var_name not in data :
37- print ( var_name , get_origin ( var_type ), get_args ( var_type ))
36+ nullable = var_type_origin is UnionType and NoneType in var_type_args
3837 if not nullable :
3938 raise RuntimeError (f"Missing variable '{ var_name } ' in { cls .__name__ } ." )
40- else :
41- continue
39+ continue
4240 # When it is a list, fill the list with the items
43- if get_origin ( var_type ) is list and len (arg := get_args ( var_type ) ) == 1 :
44- item_type = arg [0 ]
41+ if var_type_origin is list and len (var_type_args ) == 1 :
42+ item_type = var_type_args [0 ]
4543 setattr (obj , var_name , [item_type .from_dict (x ) for x in data [var_name ]])
4644 else :
4745 setattr (obj , var_name , data .get (var_name , None ))
4846 return obj
4947
5048
5149
50+ def fill_dict_from_object_using_type_hints (cls , obj ):
51+ raise NotImplementedError
52+
53+
54+
5255
5356
5457########################################################################################
@@ -58,22 +61,24 @@ def fill_object_from_dict_using_type_hints(obj, cls, data: dict):
5861
5962
6063
61- class FileDictModel (ABC ):
64+ class FileDictModel (ABC , Generic [ T ] ):
6265 """
6366 A file base refers to a file that is stored in the database.
6467 At the top level the file must contain a dictionary with strings as keys.
6568 """
6669
6770 __file__ = None
68- __item_model__ : T = None
71+ __item_model__ : Type [ T ]
6972
7073 @classmethod
7174 def get_at_key (cls , key ) -> T :
7275 """
7376 Gets an item by key.
7477 The data is partially read from the __file__.
7578 """
76- return cls .__item_model__ .partial_read_by_key (key )
79+ data = io_safe .partial_read (cls .__file__ , key )
80+ res : T = cls .__item_model__ .from_key_value (key , data )
81+ return res
7782
7883 @classmethod
7984 def session_at_key (cls , key ):
@@ -85,7 +90,7 @@ def items(cls) -> list[Tuple[str, T]]:
8590 Gets all items as a list of tuples (key, ORM model of value).
8691 """
8792 data = io_safe .read (cls .__file__ )
88- return [(k , cls .__item_model__ (k , v )) for k , v in data .items ()]
93+ return [(k , cls .__item_model__ . from_key_value (k , v )) for k , v in data .items ()]
8994
9095 @classmethod
9196 def session (cls ):
@@ -109,8 +114,6 @@ def get_where(cls, where: callable) -> list[Tuple[str, T]]:
109114 """
110115 return [(k , v ) for k , v in cls .items () if where (v )]
111116
112- # Not Implemented:
113- # - select by filter callback (file_where): Not implemented because no performance advantage.
114117
115118
116119
@@ -123,11 +126,6 @@ def from_key_value(cls: Type[T2], key, value) -> T2:
123126 obj .__key__ = key
124127 return obj
125128
126- @classmethod
127- def read_by_key (cls , key ) -> T :
128- data = io_safe .partial_read (cls .__file__ , key )
129- return cls .from_key_value (key , data )
130-
131129 @classmethod
132130 def session (cls , key ):
133131 def partial_func (x ):
@@ -152,7 +150,6 @@ def to_dict(self) -> dict:
152150
153151
154152
155-
156153########################################################################################
157154# Scenario 2:
158155# Add in a later version of DDB
0 commit comments