4
4
5
5
import copy
6
6
import dataclasses
7
+ import functools
7
8
import inspect
8
9
import typing
9
10
from abc import ABC , abstractmethod
25
26
get_origin ,
26
27
)
27
28
29
+ import pydantic .v1
30
+ import pydantic .v1 .fields
31
+
28
32
import reflex .state
29
33
from reflex .base import Base
30
34
from reflex .compiler .templates import STATEFUL_COMPONENT
@@ -73,19 +77,19 @@ class BaseComponent(Base, ABC):
73
77
"""
74
78
75
79
# The children nested within the component.
76
- children : list [BaseComponent ] = []
80
+ children : list [BaseComponent ] = pydantic . v1 . Field ( default_factory = list )
77
81
78
82
# The library that the component is based on.
79
- library : str | None = None
83
+ library : str | None = pydantic . v1 . Field ( default_factory = lambda : None )
80
84
81
85
# 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 )
83
87
84
88
# 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 )
86
90
87
91
# The tag to use when rendering the component.
88
- tag : str | None = None
92
+ tag : str | None = pydantic . v1 . Field ( default_factory = lambda : None )
89
93
90
94
@abstractmethod
91
95
def render (self ) -> dict :
@@ -262,52 +266,56 @@ class Component(BaseComponent, ABC):
262
266
"""A component with style, event trigger and other props."""
263
267
264
268
# The style of the component.
265
- style : Style = Style ( )
269
+ style : Style = pydantic . v1 . Field ( default_factory = Style )
266
270
267
271
# 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
+ )
269
275
270
276
# The alias for the tag.
271
- alias : str | None = None
277
+ alias : str | None = pydantic . v1 . Field ( default_factory = lambda : None )
272
278
273
279
# 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 )
275
281
276
282
# A unique key for the component.
277
- key : Any = None
283
+ key : Any = pydantic . v1 . Field ( default_factory = lambda : None )
278
284
279
285
# The id for the component.
280
- id : Any = None
286
+ id : Any = pydantic . v1 . Field ( default_factory = lambda : None )
281
287
282
288
# The class name for the component.
283
- class_name : Any = None
289
+ class_name : Any = pydantic . v1 . Field ( default_factory = lambda : None )
284
290
285
291
# Special component props.
286
- special_props : list [Var ] = []
292
+ special_props : list [Var ] = pydantic . v1 . Field ( default_factory = list )
287
293
288
294
# 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 )
290
296
291
297
# components that cannot be children
292
- _invalid_children : list [str ] = []
298
+ _invalid_children : ClassVar [ list [str ] ] = []
293
299
294
300
# only components that are allowed as children
295
- _valid_children : list [str ] = []
301
+ _valid_children : ClassVar [ list [str ] ] = []
296
302
297
303
# only components that are allowed as parent
298
- _valid_parents : list [str ] = []
304
+ _valid_parents : ClassVar [ list [str ] ] = []
299
305
300
306
# props to change the name of
301
- _rename_props : dict [str , str ] = {}
307
+ _rename_props : ClassVar [ dict [str , str ] ] = {}
302
308
303
309
# custom attribute
304
- custom_attrs : dict [str , Var | Any ] = {}
310
+ custom_attrs : dict [str , Var | Any ] = pydantic . v1 . Field ( default_factory = dict )
305
311
306
312
# When to memoize this component and its children.
307
313
_memoization_mode : MemoizationMode = MemoizationMode ()
308
314
309
315
# 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
+ )
311
319
312
320
def add_imports (self ) -> ImportDict | list [ImportDict ]:
313
321
"""Add imports for the component.
@@ -412,16 +420,14 @@ def __init_subclass__(cls, **kwargs):
412
420
if field .name not in props :
413
421
continue
414
422
415
- field_type = types .value_inside_optional (
416
- types .get_field_type (cls , field .name )
417
- )
418
-
419
423
# Set default values for any props.
420
- if types . _issubclass ( field_type , Var ) :
424
+ if field . type_ is Var :
421
425
field .required = False
422
426
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 :
425
431
field .required = False
426
432
427
433
# Ensure renamed props from parent classes are applied to the subclass.
@@ -432,6 +438,23 @@ def __init_subclass__(cls, **kwargs):
432
438
inherited_rename_props .update (parent ._rename_props )
433
439
cls ._rename_props = inherited_rename_props
434
440
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
+
435
458
def _post_init (self , * args , ** kwargs ):
436
459
"""Initialize the component.
437
460
@@ -472,13 +495,10 @@ def _post_init(self, *args, **kwargs):
472
495
)
473
496
if key in component_specific_triggers :
474
497
# Event triggers are bound to event chains.
475
- field_type = EventChain
498
+ is_var = False
476
499
elif key in props :
477
500
# 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
482
502
else :
483
503
continue
484
504
@@ -493,7 +513,7 @@ def determine_key(value: Any):
493
513
return key
494
514
495
515
# Check whether the key is a component prop.
496
- if types . _issubclass ( field_type , Var ) :
516
+ if is_var :
497
517
try :
498
518
kwargs [key ] = determine_key (value )
499
519
@@ -565,9 +585,15 @@ def determine_key(value: Any):
565
585
"&" : style ,
566
586
}
567
587
588
+ fields_style = self .get_fields ()["style" ]
589
+
568
590
kwargs ["style" ] = Style (
569
591
{
570
- ** self .get_fields ()["style" ].default ,
592
+ ** (
593
+ fields_style .default_factory ()
594
+ if fields_style .default_factory
595
+ else fields_style .default
596
+ ),
571
597
** style ,
572
598
** {attr : value for attr , value in kwargs .items () if attr not in fields },
573
599
}
@@ -779,7 +805,7 @@ def validate_children(children: tuple | list):
779
805
# Validate all the children.
780
806
validate_children (children )
781
807
782
- children = [
808
+ children_normalized = [
783
809
(
784
810
child
785
811
if isinstance (child , Component )
@@ -792,10 +818,10 @@ def validate_children(children: tuple | list):
792
818
for child in children
793
819
]
794
820
795
- return cls ._create (children , ** props )
821
+ return cls ._create (children_normalized , ** props )
796
822
797
823
@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 :
799
825
"""Create the component.
800
826
801
827
Args:
@@ -805,8 +831,26 @@ def _create(cls: Type[T], children: list[Component], **props: Any) -> T:
805
831
Returns:
806
832
The component.
807
833
"""
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 )
810
854
return comp
811
855
812
856
def add_style (self ) -> dict [str , Any ] | None :
@@ -991,8 +1035,8 @@ def validate_child(child: Any):
991
1035
validate_child (c )
992
1036
993
1037
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 ] )
996
1040
997
1041
if isinstance (child , Match ):
998
1042
for cases in child .match_cases :
@@ -1769,7 +1813,7 @@ def get_args_spec(key: str) -> types.ArgsSpec | Sequence[types.ArgsSpec]:
1769
1813
type_ = props_types [key ]
1770
1814
1771
1815
# Handle event chains.
1772
- if types . _issubclass ( type_ , EventActionsMixin ) :
1816
+ if type_ is EventHandler :
1773
1817
inspect .getfullargspec (component_fn ).annotations [key ]
1774
1818
self .props [camel_cased_key ] = EventChain .create (
1775
1819
value = value , args_spec = get_args_spec (key ), key = key
0 commit comments