3232from __future__ import annotations
3333
3434from dataclasses import dataclass , field
35- from typing import TYPE_CHECKING , Any , Callable , Dict , List , Optional , Type , Union
35+ from typing import TYPE_CHECKING , Callable , Dict , List , Optional , Type , TypeVar , Union , cast
36+
37+ # Python 3.11+ has dataclass_transform in typing, earlier versions need typing_extensions
38+ try :
39+ from typing import dataclass_transform
40+ except ImportError :
41+ try :
42+ from typing_extensions import dataclass_transform
43+ except ImportError :
44+ # Fallback: no-op decorator if not available
45+ def dataclass_transform (** kwargs ): # type: ignore[misc]
46+ def decorator (cls_or_fn ): # type: ignore[no-untyped-def]
47+ return cls_or_fn
48+
49+ return decorator
50+
3651
3752import numpy as np
3853from beartype import beartype
3954
55+ # TypeVar for preserving class type through decorators
56+ _T = TypeVar ("_T" )
57+
4058from cyecca .dsl .context import (
4159 execute_algorithm_method ,
4260 execute_equations_method ,
4765)
4866from cyecca .dsl .equations import ArrayEquation , Assignment , Equation , WhenClause
4967from cyecca .dsl .instance import ModelInstance
50- from cyecca .dsl .types import DType , Shape , SubmodelField , Var , VarKind
68+ from cyecca .dsl .types import DType , NumericValue , Shape , SubmodelField , Var , VarKind
69+ from cyecca .dsl .variables import SymbolicVar
5170
71+ # For IDE autocomplete: Real/Integer/Boolean/String return SymbolicVar for type checking
72+ # but Var at runtime. This allows m.theta to autocomplete as SymbolicVar.
5273if TYPE_CHECKING :
53- pass
74+ _VarReturn = SymbolicVar
75+ else :
76+ _VarReturn = Var
5477
5578
5679# =============================================================================
@@ -114,7 +137,7 @@ def var(
114137 protected : bool = False ,
115138 # Connector prefixes (Modelica MLS Ch. 9)
116139 flow : bool = False ,
117- ) -> Var :
140+ ) -> _VarReturn :
118141 """
119142 Declare a variable in a Cyecca model.
120143
@@ -231,7 +254,7 @@ def Real(
231254 protected : bool = False ,
232255 # Connector
233256 flow : bool = False ,
234- ) -> Var :
257+ ) -> _VarReturn :
235258 """
236259 Declare a Real (floating-point) variable.
237260
@@ -326,7 +349,7 @@ def Integer(
326349 constant : bool = False ,
327350 # Visibility
328351 protected : bool = False ,
329- ) -> Var :
352+ ) -> _VarReturn :
330353 """
331354 Declare an Integer variable.
332355
@@ -408,7 +431,7 @@ def Boolean(
408431 constant : bool = False ,
409432 # Visibility
410433 protected : bool = False ,
411- ) -> Var :
434+ ) -> _VarReturn :
412435 """
413436 Declare a Boolean variable.
414437
@@ -480,7 +503,7 @@ def String(
480503 constant : bool = False ,
481504 # Visibility
482505 protected : bool = False ,
483- ) -> Var :
506+ ) -> _VarReturn :
484507 """
485508 Declare a String variable.
486509
@@ -536,7 +559,7 @@ def String(
536559
537560
538561@beartype
539- def submodel (model_class : Type , ** overrides : Any ) -> SubmodelField :
562+ def submodel (model_class : Type , ** overrides : NumericValue ) -> SubmodelField :
540563 """
541564 Declare a submodel (nested model) with optional parameter overrides.
542565
@@ -547,7 +570,7 @@ def submodel(model_class: Type, **overrides: Any) -> SubmodelField:
547570 ----------
548571 model_class : Type
549572 The model class to instantiate as a submodel
550- **overrides : Any
573+ **overrides : NumericValue
551574 Parameter value overrides. The parameter names must match
552575 parameters defined in the submodel class.
553576
@@ -575,8 +598,9 @@ def submodel(model_class: Type, **overrides: Any) -> SubmodelField:
575598# =============================================================================
576599
577600
601+ @dataclass_transform (field_specifiers = (Real , Integer , Boolean , String , var ))
578602@beartype
579- def model (cls : Type [Any ]) -> Type [Any ]:
603+ def model (cls : Type [_T ]) -> Type [_T ]:
580604 """
581605 Decorator to convert a class into a Cyecca model.
582606
@@ -670,6 +694,8 @@ class ModelClass(ModelInstance):
670694 __name__ = cls .__name__
671695 __qualname__ = cls .__qualname__
672696 __module__ = cls .__module__
697+ # Copy annotations from original class for IDE autocomplete
698+ __annotations__ = getattr (cls , "__annotations__" , {})
673699
674700 _equations_methods = equations_methods
675701 _initial_equations_methods = initial_equations_methods
@@ -704,16 +730,17 @@ def get_algorithm(self) -> List[Assignment]:
704730
705731 ModelClass ._dsl_metadata = metadata
706732
707- return ModelClass
733+ return cast ( Type [ _T ], ModelClass )
708734
709735
710736# =============================================================================
711737# @function decorator - Modelica functions (Ch. 12)
712738# =============================================================================
713739
714740
741+ @dataclass_transform (field_specifiers = (Real , Integer , Boolean , String , var ))
715742@beartype
716- def function (cls : Type [Any ]) -> Type [Any ]:
743+ def function (cls : Type [_T ]) -> Type [_T ]:
717744 """
718745 Decorator to convert a class into a Cyecca function.
719746
@@ -787,8 +814,9 @@ def get_function_metadata(self) -> FunctionMetadata:
787814# =============================================================================
788815
789816
817+ @dataclass_transform (field_specifiers = (Real , Integer , Boolean , String , var ))
790818@beartype
791- def block (cls : Type [Any ]) -> Type [Any ]:
819+ def block (cls : Type [_T ]) -> Type [_T ]:
792820 """
793821 Decorator to convert a class into a Cyecca block.
794822
@@ -832,8 +860,9 @@ def block(cls: Type[Any]) -> Type[Any]:
832860# =============================================================================
833861
834862
863+ @dataclass_transform (field_specifiers = (Real , Integer , Boolean , String , var ))
835864@beartype
836- def connector (cls : Type [Any ]) -> Type [Any ]:
865+ def connector (cls : Type [_T ]) -> Type [_T ]:
837866 """
838867 Decorator to convert a class into a Cyecca connector.
839868
0 commit comments