@@ -1834,4 +1834,169 @@ class Child(Parent):
18341834
18351835 # This works (because Child is subclass of incorrectly-resolved Child)
18361836 child = Child (ref = Child )
1837- assert child .ref is Child # Works (accidentally correct)
1837+ assert child .ref is Child # Works (accidentally correct)
1838+
1839+ def test__regression__type_annotation__expected_behavior_after_fix (self ):
1840+ # Documents what SHOULD work after the bug is fixed
1841+
1842+ class Animal (Type_Safe ):
1843+ name : str = ''
1844+
1845+ class Dog (Animal ):
1846+ breed : str = ''
1847+
1848+ class AnimalRegistry (Type_Safe ):
1849+ animal_type : Type [Animal ] = None
1850+
1851+ class DogRegistry (AnimalRegistry ):
1852+ animal_type : Type [Dog ] # Should auto-default to Dog
1853+
1854+ # After fix, this should work:
1855+ # with DogRegistry() as _:
1856+ # assert _.animal_type is Dog # Auto-assigned default
1857+
1858+ # Currently:
1859+ with DogRegistry () as _ :
1860+ #assert _.animal_type is None # BUG: inherits None
1861+ assert _ .animal_type is Dog
1862+
1863+ def test__regression__type_annotation__workaround_comparison (self ):
1864+ # Compare buggy vs workaround patterns
1865+
1866+ class Processor (Type_Safe ):
1867+ pass
1868+
1869+ class FastProcessor (Processor ):
1870+ pass
1871+
1872+ class Config_Base (Type_Safe ):
1873+ processor_type : Type [Processor ] = None
1874+
1875+ # BUGGY: No explicit value
1876+ class Config_Fast_Buggy (Config_Base ):
1877+ processor_type : Type [FastProcessor ]
1878+
1879+ # WORKAROUND: Explicit value
1880+ class Config_Fast_Fixed (Config_Base ):
1881+ processor_type : Type [FastProcessor ] = FastProcessor
1882+
1883+ # Buggy version gets None
1884+ #assert Config_Fast_Buggy().processor_type is None # BUG
1885+ assert Config_Fast_Buggy ().processor_type is FastProcessor
1886+
1887+ # Workaround version gets correct value
1888+ assert Config_Fast_Fixed ().processor_type is FastProcessor # Works
1889+
1890+
1891+ def test__regression__type_annotation__subclass_redeclaration__no_auto_default (self ):
1892+ # Bug: When a subclass re-declares a Type[T] annotation with a more specific type,
1893+ # Type_Safe should auto-assign the type as the default value.
1894+ # Instead, it inherits the parent's None value.
1895+ #
1896+ # Root cause: In Type_Safe__Step__Class_Kwargs.process_annotation(),
1897+ # hasattr(base_cls, var_name) returns True (from parent),
1898+ # so handle_undefined_var() is never called to calculate default.
1899+
1900+ class Base_Node (Type_Safe ):
1901+ value : str = ''
1902+
1903+ class Extended_Node (Base_Node ):
1904+ extra : int = 0
1905+
1906+ class Base_Types (Type_Safe ):
1907+ node_type : Type [Base_Node ] = None # Explicit None default
1908+
1909+ class Extended_Types (Base_Types ):
1910+ node_type : Type [Extended_Node ] # Re-declared with specific type, no explicit value
1911+
1912+ # Base class works as expected
1913+ with Base_Types () as _ :
1914+ assert _ .node_type is None # Explicit None default
1915+
1916+ # BUG: Subclass should auto-assign Extended_Node as default
1917+ with Extended_Types () as _ :
1918+ #assert _.node_type is None # BUG: inherits parent's None
1919+ assert _ .node_type is Extended_Node
1920+ # EXPECTED: _.node_type should be Extended_Node
1921+
1922+ def test__regression__type_annotation__subclass_redeclaration__with_explicit_value_works (self ):
1923+ # Document that explicit value assignment DOES work (workaround)
1924+
1925+ class Base_Node (Type_Safe ):
1926+ value : str = ''
1927+
1928+ class Extended_Node (Base_Node ):
1929+ extra : int = 0
1930+
1931+ class Base_Types (Type_Safe ):
1932+ node_type : Type [Base_Node ] = None
1933+
1934+ class Extended_Types__Fixed (Base_Types ):
1935+ node_type : Type [Extended_Node ] = Extended_Node # Explicit assignment works
1936+
1937+ # This workaround works correctly
1938+ with Extended_Types__Fixed () as _ :
1939+ assert _ .node_type is Extended_Node # Works with explicit value
1940+
1941+ def test__regression__type_annotation__multiple_type_fields (self ):
1942+ # Bug affects multiple Type[T] fields
1943+
1944+ class Model_Node (Type_Safe ):
1945+ pass
1946+
1947+ class Model_Edge (Type_Safe ):
1948+ pass
1949+
1950+ class Simple_Node (Model_Node ):
1951+ pass
1952+
1953+ class Simple_Edge (Model_Edge ):
1954+ pass
1955+
1956+ class Base_Model_Types (Type_Safe ):
1957+ node_model_type : Type [Model_Node ] = None
1958+ edge_model_type : Type [Model_Edge ] = None
1959+
1960+ class Simple_Model_Types (Base_Model_Types ):
1961+ node_model_type : Type [Simple_Node ] # Re-declared, no explicit value
1962+ edge_model_type : Type [Simple_Edge ] # Re-declared, no explicit value
1963+
1964+ # BUG: Both fields inherit None instead of auto-assigning the type
1965+ with Simple_Model_Types () as _ :
1966+ # assert _.node_model_type is None # BUG: should be Simple_Node
1967+ # assert _.edge_model_type is None # BUG: should be Simple_Edge
1968+ assert _ .node_model_type is Simple_Node
1969+ assert _ .edge_model_type is Simple_Edge
1970+
1971+ def test__regression__type_annotation__deep_inheritance_chain (self ):
1972+ # Bug affects deeper inheritance chains
1973+
1974+ class Node_L0 (Type_Safe ):
1975+ pass
1976+
1977+ class Node_L1 (Node_L0 ):
1978+ pass
1979+
1980+ class Node_L2 (Node_L1 ):
1981+ pass
1982+
1983+ class Types_L0 (Type_Safe ):
1984+ node_type : Type [Node_L0 ] = None
1985+
1986+ class Types_L1 (Types_L0 ):
1987+ node_type : Type [Node_L1 ] # Re-declare for L1
1988+
1989+ class Types_L2 (Types_L1 ):
1990+ node_type : Type [Node_L2 ] # Re-declare for L2
1991+
1992+ # All levels inherit None instead of auto-assigning
1993+ with Types_L0 () as _ :
1994+ assert _ .node_type is None # Correct (explicit None)
1995+
1996+ with Types_L1 () as _ :
1997+ #assert _.node_type is None # BUG: should be Node_L1
1998+ assert _ .node_type is Node_L1
1999+
2000+ with Types_L2 () as _ :
2001+ #assert _.node_type is None # BUG: should be Node_L2
2002+ assert _ .node_type is Node_L2
0 commit comments