Skip to content

Commit 873589b

Browse files
committed
fixed couple issues with Type_Safe__Fast_Create__Cache
added final Hypothsis_H which captures a number of powerful benchmarks (including a comparison with the original Python, dataclass and Pydantic data sets)
1 parent 46c2fee commit 873589b

16 files changed

+2713
-7
lines changed

osbot_utils/type_safe/type_safe_core/fast_create/Type_Safe__Fast_Create__Cache.py

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# ═══════════════════════════════════════════════════════════════════════════════
1212

13-
from typing import Any, Dict, Set, Type
13+
from typing import Any, Dict, Set, Type, get_type_hints, get_origin
1414
from osbot_utils.type_safe.Type_Safe__Primitive import Type_Safe__Primitive
1515
from osbot_utils.type_safe.type_safe_core.collections.Type_Safe__Dict import Type_Safe__Dict
1616
from osbot_utils.type_safe.type_safe_core.collections.Type_Safe__List import Type_Safe__List
@@ -31,12 +31,14 @@
3131

3232
class Type_Safe__Fast_Create__Cache: # Schema generation and caching
3333

34-
schema_cache : Dict[Type, Schema__Type_Safe__Fast_Create__Class] # Class -> Schema mapping
35-
generating : Set[Type] # Guards against recursion
34+
schema_cache : Dict[Type, Schema__Type_Safe__Fast_Create__Class] # Class -> Schema mapping
35+
type_hints_cache : Dict[Type, Dict[str, Type]] # Class -> type hints mapping
36+
generating : Set[Type] # Guards against recursion
3637

3738
def __init__(self):
38-
self.schema_cache = {} # Regular dict - classes persist
39-
self.generating = set() # Recursion guard
39+
self.schema_cache = {} # Regular dict - classes persist
40+
self.type_hints_cache = {} # Cache for get_type_hints results
41+
self.generating = set() # Recursion guard
4042

4143
def __enter__(self):
4244
return self
@@ -61,6 +63,7 @@ def warm_cache(self, cls: Type) -> None: #
6163

6264
def clear_cache(self) -> None: # Clear all cached schemas (for testing)
6365
self.schema_cache.clear()
66+
self.type_hints_cache.clear()
6467
self.generating.clear()
6568

6669
def is_generating(self, cls: Type) -> bool: # Check if schema generation in progress
@@ -76,6 +79,7 @@ def generate_schema(self, cls: Type) -> Schema__Type_Safe__Fast_Create__Class:
7679
try:
7780
template = cls() # Create template to get defaults
7881
template_dict = template.__dict__.copy()
82+
type_hints = self.get_type_hints_safe(cls) # Get type annotations
7983

8084
fields = []
8185
static_dict = {}
@@ -86,7 +90,8 @@ def generate_schema(self, cls: Type) -> Schema__Type_Safe__Fast_Create__Class:
8690
if name.startswith('_'): # Skip private attributes
8791
continue
8892

89-
field = self.classify_field(name, value)
93+
type_hint = type_hints.get(name) # Get annotation for this field
94+
field = self.classify_field(name, value, type_hint)
9095
fields.append(field)
9196

9297
if field.mode == FIELD_MODE__STATIC:
@@ -104,8 +109,14 @@ def generate_schema(self, cls: Type) -> Schema__Type_Safe__Fast_Create__Class:
104109
finally:
105110
self.generating.discard(cls) # Remove from generating set
106111

107-
def classify_field(self, name: str, value: Any) -> Schema__Type_Safe__Fast_Create__Field: # Classify field by its value type
112+
def classify_field(self, name: str, value: Any, type_hint: Type = None) -> Schema__Type_Safe__Fast_Create__Field: # Classify field by its value type
108113
if self.is_immutable(value):
114+
# Check if None value has a Type_Safe type hint (On_Demand pattern)
115+
if value is None and type_hint is not None:
116+
if self.is_type_safe_type_hint(type_hint): # Type hint is a Type_Safe class
117+
return Schema__Type_Safe__Fast_Create__Field(name = name ,
118+
mode = FIELD_MODE__NESTED,
119+
nested_class = type_hint )
109120
return Schema__Type_Safe__Fast_Create__Field(name = name ,
110121
mode = FIELD_MODE__STATIC ,
111122
static_value = value )
@@ -141,6 +152,32 @@ def is_nested_type_safe(self, value: Any) -> bool: #
141152
return False
142153
return True
143154

155+
def is_type_safe_type_hint(self, type_hint: Type) -> bool: # Check if type hint is a Type_Safe class
156+
from osbot_utils.type_safe.Type_Safe import Type_Safe # Circular dependency
157+
if type_hint is None:
158+
return False
159+
if get_origin(type_hint) is not None: # Skip generic types like Optional[X]
160+
return False
161+
if not isinstance(type_hint, type): # Must be a class
162+
return False
163+
if not issubclass(type_hint, Type_Safe): # Must be Type_Safe subclass
164+
return False
165+
if issubclass(type_hint, Type_Safe__Primitive): # Skip primitives
166+
return False
167+
if issubclass(type_hint, (Type_Safe__List, Type_Safe__Dict, Type_Safe__Set)): # Skip collections
168+
return False
169+
return True
170+
171+
def get_type_hints_safe(self, cls: Type) -> Dict[str, Type]: # Get type hints with caching
172+
if cls in self.type_hints_cache:
173+
return self.type_hints_cache[cls]
174+
try:
175+
hints = get_type_hints(cls)
176+
except Exception: # Some classes fail get_type_hints
177+
hints = {}
178+
self.type_hints_cache[cls] = hints
179+
return hints
180+
144181
# ═══════════════════════════════════════════════════════════════════════════
145182
# Factory Function Generation
146183
# ═══════════════════════════════════════════════════════════════════════════
@@ -168,6 +205,12 @@ def get_factory_func(self, value: Any): #
168205
if isinstance(value, set):
169206
return set
170207

208+
# Handle when value is a class/type itself
209+
if isinstance(value, type): # Value IS a class
210+
captured_type = value # Capture for lambda
211+
return lambda: captured_type # Return class itself (not instance)
212+
213+
171214
value_type = type(value) # Default: use type constructor
172215
return lambda: value_type()
173216

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Hypothesis H: Production Performance Benchmarks
2+
3+
**Status**: ✅ Complete
4+
**Depends On**: Hypothesis G (wiring in Type_Safe)
5+
6+
---
7+
8+
## Hypothesis
9+
10+
> Using `Type_Safe__Config` context manager with `fast_create=True` and/or `skip_validation=True` provides significant performance improvements over default Type_Safe behavior.
11+
12+
---
13+
14+
## Three Comparisons
15+
16+
| Test File | Baseline | Target | Expected Improvement |
17+
|-----------|----------|--------|---------------------|
18+
| `test_perf__Hypothesis_H__fast_create.py` | Default Type_Safe | `fast_create=True` | 50-85% |
19+
| `test_perf__Hypothesis_H__skip_validation.py` | Default `__setattr__` | `skip_validation=True` | 50-80% |
20+
| `test_perf__Hypothesis_H__fast_create_skip_validation.py` | Default Type_Safe | Both flags | 60-90% |
21+
22+
---
23+
24+
## Benchmark Categories
25+
26+
### Object Creation (A series)
27+
- A_01: Empty class
28+
- A_02: Primitives only (str, int, bool, float)
29+
- A_03: With collections (List, Dict)
30+
- A_04: Many fields (10 fields)
31+
- A_05: One nested Type_Safe
32+
- A_06: Three nested Type_Safe
33+
- A_07: Deep nested (3 levels)
34+
- A_08: MGraph-like (complex structure)
35+
36+
### Batch Creation (B series)
37+
- B_01-B_04: x10 objects of various complexity
38+
39+
### Attribute Assignment (C series) - skip_validation only
40+
- C_01-C_04: x100 objects, x400 assignments
41+
42+
### Create + Modify (D series) - combined test only
43+
- D_01-D_04: Real-world patterns (create then modify)
44+
45+
---
46+
47+
## Usage
48+
49+
```python
50+
# Run individual benchmark
51+
pytest test_perf__Hypothesis_H__fast_create.py -v
52+
53+
# All benchmarks
54+
pytest test_perf__Hypothesis_H*.py -v
55+
```
56+
57+
---
58+
59+
## Key Findings
60+
61+
| Scenario | Improvement | Notes |
62+
|----------|-------------|-------|
63+
| Simple classes | 30-50% | Less validation to skip |
64+
| Nested classes | 50-70% | Recursive creation overhead eliminated |
65+
| Complex (MGraph-like) | 70-85% | Maximum benefit |
66+
| Batch x10 | Scales linearly | 10x objects = 10x savings |
67+
| setattr bypass | 60-80% | Direct `object.__setattr__` |
68+
69+
---
70+
71+
## Prerequisites
72+
73+
1. ✅ Hypothesis G complete (fast_create infrastructure)
74+
2. ✅ Type_Safe.__init__ wired to check config
75+
3. ✅ Type_Safe.__setattr__ wired to check config
76+
4. ✅ All 117 integration tests passing
77+
78+
---
79+
80+
## Related Files
81+
82+
- **Detailed Debrief**: `Hypothesis_H__debrief_on_Type_Safe_changes.md`
83+
- **Integration Tests**: `test_Type_Safe__Fast_Create__*.py` (5 files, 117 tests)
84+
- **Performance Tests**: `test_perf__Hypothesis_H__*.py` (3 files)

0 commit comments

Comments
 (0)