77
88
99class Type_Safe__List (Type_Safe__Base , list ):
10- expected_type : Type
10+ expected_type : Type = None # Class-level default
1111
12- def __init__ (self , expected_type , * args ):
12+ def __init__ (self , expected_type = None , * args ):
1313 super ().__init__ (* args )
14- self .expected_type = expected_type
14+ self .expected_type = expected_type or self .__class__ .expected_type
15+ if self .expected_type is None :
16+ raise ValueError (f"{ self .__class__ .__name__ } requires expected_type" )
1517
1618 def __contains__ (self , item ):
1719 if super ().__contains__ (item ): # First try direct lookup
@@ -43,37 +45,55 @@ def __repr__(self):
4345 def __enter__ (self ): return self
4446 def __exit__ (self , type , value , traceback ): pass
4547
46- def append (self , item ):
47- from osbot_utils .type_safe .Type_Safe import Type_Safe # to prevent circular imports
48+ def _validate_and_convert_item (self , item ): # Validate and convert an item to the expected type."
49+ from osbot_utils .type_safe .Type_Safe import Type_Safe
4850
49- if type (self .expected_type ) is type and issubclass (self .expected_type , Type_Safe ) and type (item ) is dict : # Handle Type_Safe objects from dicts
51+ if type (self .expected_type ) is type and issubclass (self .expected_type , Type_Safe ) and type (item ) is dict :
5052 item = self .expected_type .from_json (item )
51- elif type (self .expected_type ) is type and issubclass (self .expected_type , Type_Safe__Primitive ): # Handle Type_Safe__Primitive conversions (str -> Safe_Str, etc.)
53+ elif type (self .expected_type ) is type and issubclass (self .expected_type , Type_Safe__Primitive ):
5254 if not isinstance (item , self .expected_type ):
5355 try :
5456 item = self .expected_type (item )
5557 except (ValueError , TypeError ) as e :
56- # Re-raise with more context about what failed
5758 raise TypeError (f"In Type_Safe__List: Could not convert { type (item ).__name__ } to { self .expected_type .__name__ } : { e } " ) from None
5859
59- elif hasattr (self .expected_type , '__bases__' ) and any (base .__name__ == 'Enum' for base in self .expected_type .__bases__ ): # Handle Enums
60-
60+ elif hasattr (self .expected_type , '__bases__' ) and any (base .__name__ == 'Enum' for base in self .expected_type .__bases__ ):
6161 if isinstance (self .expected_type , type ) and issubclass (self .expected_type , Enum ):
6262 if isinstance (item , str ):
63- if item in self .expected_type .__members__ : # Try to convert string to enum
63+ if item in self .expected_type .__members__ :
6464 item = self .expected_type [item ]
6565 elif hasattr (self .expected_type , '_value2member_map_' ) and item in self .expected_type ._value2member_map_ :
6666 item = self .expected_type ._value2member_map_ [item ]
6767
68- try : # Now validate the (possibly converted) item
68+ try :
6969 self .is_instance_of_type (item , self .expected_type )
7070 except TypeError as e :
7171 raise TypeError (f"In Type_Safe__List: Invalid type for item: { e } " ) from None
7272
73+ return item
74+
75+ def append (self , item ):
76+ item = self ._validate_and_convert_item (item )
7377 super ().append (item )
7478
79+ def __setitem__ (self , index , item ):
80+ item = self ._validate_and_convert_item (item )
81+ super ().__setitem__ (index , item )
82+
83+ def __iadd__ (self , items ):
84+ for item in items :
85+ self .append (item )
86+ return self
87+
88+ def insert (self , index , item ):
89+ item = self ._validate_and_convert_item (item )
90+ super ().insert (index , item )
7591
76- def json (self ): # Convert the list to a JSON-serializable format.
92+ def extend (self , items ):
93+ for item in items :
94+ self .append (item )
95+
96+ def json (self ): # Convert the list to a JSON-serializable format.
7797 from osbot_utils .type_safe .Type_Safe import Type_Safe # Import here to avoid circular imports
7898
7999 result = []
@@ -84,12 +104,56 @@ def json(self): # Convert the list to a JSON-serializable format.
84104 result .append (item .__to_primitive__ ())
85105 elif isinstance (item , (list , tuple , frozenset )):
86106 result .append ([x .json () if isinstance (x , Type_Safe ) else serialize_to_dict (x ) for x in item ])
87- #result.append([x.json() if isinstance(x, Type_Safe) else x for x in item]) # BUG here
88107 elif isinstance (item , dict ):
89108 result .append (serialize_to_dict (item )) # leverage serialize_to_dict since that method already knows how to handle
90- #result.append({k: v.json() if isinstance(v, Type_Safe) else v for k, v in item.items()})
91109 elif isinstance (item , type ):
92110 result .append (class_full_name (item ))
93111 else :
94112 result .append (serialize_to_dict (item )) # also Use serialize_to_dict for unknown types (so that we don't return a non json object)
95- return result
113+ return result
114+
115+ def copy (self ):
116+ # Return a copy of the same subclass type
117+ result = self .__class__ (expected_type = self .expected_type )
118+ for item in self :
119+ result .append (item )
120+ return result
121+
122+ def __add__ (self , other ):
123+ # Handle list1 + list2 - returns new instance of same subclass
124+ result = self .__class__ (expected_type = self .expected_type )
125+ for item in self :
126+ result .append (item )
127+ for item in other :
128+ result .append (item ) # Validates each item
129+ return result
130+
131+ def __radd__ (self , other ):
132+ # Handle list + type_safe_list - returns new instance of same subclass
133+ result = self .__class__ (expected_type = self .expected_type )
134+ for item in other :
135+ result .append (item ) # Validates each item
136+ for item in self :
137+ result .append (item )
138+ return result
139+
140+ def __mul__ (self , n ):
141+ # Handle list * n - returns new instance of same subclass
142+ result = self .__class__ (expected_type = self .expected_type )
143+ for _ in range (n ):
144+ for item in self :
145+ result .append (item )
146+ return result
147+
148+ def __rmul__ (self , n ):
149+ # Handle n * list - same as __mul__
150+ return self .__mul__ (n )
151+
152+ def __imul__ (self , n ):
153+ # Handle list *= n - modifies in place, type already correct
154+ items = list (self )
155+ self .clear ()
156+ for _ in range (n ):
157+ for item in items :
158+ self .append (item )
159+ return self
0 commit comments