44
55import copy
66import dataclasses
7+ import functools
78import inspect
89import typing
910from abc import ABC , abstractmethod
2526 get_origin ,
2627)
2728
29+ import pydantic .v1
30+ import pydantic .v1 .fields
31+
2832import reflex .state
2933from reflex .base import Base
3034from reflex .compiler .templates import STATEFUL_COMPONENT
@@ -73,19 +77,19 @@ class BaseComponent(Base, ABC):
7377 """
7478
7579 # The children nested within the component.
76- children : list [BaseComponent ] = []
80+ children : list [BaseComponent ] = pydantic . v1 . Field ( default_factory = list )
7781
7882 # The library that the component is based on.
79- library : str | None = None
83+ library : str | None = pydantic . v1 . Field ( default_factory = lambda : None )
8084
8185 # List here the non-react dependency needed by `library`
82- lib_dependencies : list [str ] = []
86+ lib_dependencies : list [str ] = pydantic . v1 . Field ( default_factory = list )
8387
8488 # List here the dependencies that need to be transpiled by Next.js
85- transpile_packages : list [str ] = []
89+ transpile_packages : list [str ] = pydantic . v1 . Field ( default_factory = list )
8690
8791 # The tag to use when rendering the component.
88- tag : str | None = None
92+ tag : str | None = pydantic . v1 . Field ( default_factory = lambda : None )
8993
9094 @abstractmethod
9195 def render (self ) -> dict :
@@ -262,52 +266,56 @@ class Component(BaseComponent, ABC):
262266 """A component with style, event trigger and other props."""
263267
264268 # The style of the component.
265- style : Style = Style ( )
269+ style : Style = pydantic . v1 . Field ( default_factory = Style )
266270
267271 # A mapping from event triggers to event chains.
268- event_triggers : dict [str , EventChain | Var ] = {}
272+ event_triggers : dict [str , EventChain | Var ] = pydantic .v1 .Field (
273+ default_factory = dict
274+ )
269275
270276 # The alias for the tag.
271- alias : str | None = None
277+ alias : str | None = pydantic . v1 . Field ( default_factory = lambda : None )
272278
273279 # Whether the import is default or named.
274- is_default : bool | None = False
280+ is_default : bool | None = pydantic . v1 . Field ( default_factory = lambda : False )
275281
276282 # A unique key for the component.
277- key : Any = None
283+ key : Any = pydantic . v1 . Field ( default_factory = lambda : None )
278284
279285 # The id for the component.
280- id : Any = None
286+ id : Any = pydantic . v1 . Field ( default_factory = lambda : None )
281287
282288 # The class name for the component.
283- class_name : Any = None
289+ class_name : Any = pydantic . v1 . Field ( default_factory = lambda : None )
284290
285291 # Special component props.
286- special_props : list [Var ] = []
292+ special_props : list [Var ] = pydantic . v1 . Field ( default_factory = list )
287293
288294 # Whether the component should take the focus once the page is loaded
289- autofocus : bool = False
295+ autofocus : bool = pydantic . v1 . Field ( default_factory = lambda : False )
290296
291297 # components that cannot be children
292- _invalid_children : list [str ] = []
298+ _invalid_children : ClassVar [ list [str ] ] = []
293299
294300 # only components that are allowed as children
295- _valid_children : list [str ] = []
301+ _valid_children : ClassVar [ list [str ] ] = []
296302
297303 # only components that are allowed as parent
298- _valid_parents : list [str ] = []
304+ _valid_parents : ClassVar [ list [str ] ] = []
299305
300306 # props to change the name of
301- _rename_props : dict [str , str ] = {}
307+ _rename_props : ClassVar [ dict [str , str ] ] = {}
302308
303309 # custom attribute
304- custom_attrs : dict [str , Var | Any ] = {}
310+ custom_attrs : dict [str , Var | Any ] = pydantic . v1 . Field ( default_factory = dict )
305311
306312 # When to memoize this component and its children.
307313 _memoization_mode : MemoizationMode = MemoizationMode ()
308314
309315 # State class associated with this component instance
310- State : Type [reflex .state .State ] | None = None
316+ State : Type [reflex .state .State ] | None = pydantic .v1 .Field (
317+ default_factory = lambda : None
318+ )
311319
312320 def add_imports (self ) -> ImportDict | list [ImportDict ]:
313321 """Add imports for the component.
@@ -412,16 +420,14 @@ def __init_subclass__(cls, **kwargs):
412420 if field .name not in props :
413421 continue
414422
415- field_type = types .value_inside_optional (
416- types .get_field_type (cls , field .name )
417- )
418-
419423 # Set default values for any props.
420- if types . _issubclass ( field_type , Var ) :
424+ if field . type_ is Var :
421425 field .required = False
422426 if field .default is not None :
423- field .default = LiteralVar .create (field .default )
424- elif types ._issubclass (field_type , EventHandler ):
427+ field .default_factory = functools .partial (
428+ LiteralVar .create , field .default
429+ )
430+ elif field .type_ is EventHandler :
425431 field .required = False
426432
427433 # Ensure renamed props from parent classes are applied to the subclass.
@@ -432,6 +438,23 @@ def __init_subclass__(cls, **kwargs):
432438 inherited_rename_props .update (parent ._rename_props )
433439 cls ._rename_props = inherited_rename_props
434440
441+ def __init__ (self , ** kwargs ):
442+ """Initialize the custom component.
443+
444+ Args:
445+ **kwargs: The kwargs to pass to the component.
446+ """
447+ console .deprecate (
448+ "component-direct-instantiation" ,
449+ reason = "Use the `create` method instead." ,
450+ deprecation_version = "0.7.2" ,
451+ removal_version = "0.8.0" ,
452+ )
453+ super ().__init__ (
454+ children = kwargs .get ("children" , []),
455+ )
456+ self ._post_init (** kwargs )
457+
435458 def _post_init (self , * args , ** kwargs ):
436459 """Initialize the component.
437460
@@ -472,13 +495,10 @@ def _post_init(self, *args, **kwargs):
472495 )
473496 if key in component_specific_triggers :
474497 # Event triggers are bound to event chains.
475- field_type = EventChain
498+ is_var = False
476499 elif key in props :
477500 # Set the field type.
478- field_type = types .value_inside_optional (
479- types .get_field_type (type (self ), key )
480- )
481-
501+ is_var = field .type_ is Var if (field := fields .get (key )) else False
482502 else :
483503 continue
484504
@@ -493,7 +513,7 @@ def determine_key(value: Any):
493513 return key
494514
495515 # Check whether the key is a component prop.
496- if types . _issubclass ( field_type , Var ) :
516+ if is_var :
497517 try :
498518 kwargs [key ] = determine_key (value )
499519
@@ -565,9 +585,15 @@ def determine_key(value: Any):
565585 "&" : style ,
566586 }
567587
588+ fields_style = self .get_fields ()["style" ]
589+
568590 kwargs ["style" ] = Style (
569591 {
570- ** self .get_fields ()["style" ].default ,
592+ ** (
593+ fields_style .default_factory ()
594+ if fields_style .default_factory
595+ else fields_style .default
596+ ),
571597 ** style ,
572598 ** {attr : value for attr , value in kwargs .items () if attr not in fields },
573599 }
@@ -779,7 +805,7 @@ def validate_children(children: tuple | list):
779805 # Validate all the children.
780806 validate_children (children )
781807
782- children = [
808+ children_normalized = [
783809 (
784810 child
785811 if isinstance (child , Component )
@@ -792,10 +818,10 @@ def validate_children(children: tuple | list):
792818 for child in children
793819 ]
794820
795- return cls ._create (children , ** props )
821+ return cls ._create (children_normalized , ** props )
796822
797823 @classmethod
798- def _create (cls : Type [T ], children : list [ Component ], ** props : Any ) -> T :
824+ def _create (cls : Type [T ], children : Sequence [ BaseComponent ], ** props : Any ) -> T :
799825 """Create the component.
800826
801827 Args:
@@ -805,8 +831,26 @@ def _create(cls: Type[T], children: list[Component], **props: Any) -> T:
805831 Returns:
806832 The component.
807833 """
808- comp = cls .construct (id = props .get ("id" ), children = children )
809- comp ._post_init (children = children , ** props )
834+ comp = cls .construct (id = props .get ("id" ), children = list (children ))
835+ comp ._post_init (children = list (children ), ** props )
836+ return comp
837+
838+ @classmethod
839+ def _unsafe_create (
840+ cls : Type [T ], children : Sequence [BaseComponent ], ** props : Any
841+ ) -> T :
842+ """Create the component without running post_init.
843+
844+ Args:
845+ children: The children of the component.
846+ **props: The props of the component.
847+
848+ Returns:
849+ The component.
850+ """
851+ comp = cls .construct (id = props .get ("id" ), children = list (children ))
852+ for prop , value in props .items ():
853+ setattr (comp , prop , value )
810854 return comp
811855
812856 def add_style (self ) -> dict [str , Any ] | None :
@@ -991,8 +1035,8 @@ def validate_child(child: Any):
9911035 validate_child (c )
9921036
9931037 if isinstance (child , Cond ):
994- validate_child (child .comp1 )
995- validate_child (child .comp2 )
1038+ validate_child (child .children [ 0 ] )
1039+ validate_child (child .children [ 1 ] )
9961040
9971041 if isinstance (child , Match ):
9981042 for cases in child .match_cases :
@@ -1769,7 +1813,7 @@ def get_args_spec(key: str) -> types.ArgsSpec | Sequence[types.ArgsSpec]:
17691813 type_ = props_types [key ]
17701814
17711815 # Handle event chains.
1772- if types . _issubclass ( type_ , EventActionsMixin ) :
1816+ if type_ is EventHandler :
17731817 inspect .getfullargspec (component_fn ).annotations [key ]
17741818 self .props [camel_cased_key ] = EventChain .create (
17751819 value = value , args_spec = get_args_spec (key ), key = key
0 commit comments