@@ -383,7 +383,84 @@ def handle_optional_attribute_type(
383
383
_SpockNotOptionalError
384
384
385
385
"""
386
- print ("hi" )
386
+ raise _SpockNotOptionalError (
387
+ f"Parameter `{ attr_space .attribute .name } ` within `{ attr_space .config_space .name } ` is of "
388
+ f"type `{ type (attr_space .attribute .type )} ` which seems to be unsupported -- "
389
+ f"are you missing an @spock decorator on a base python class?"
390
+ )
391
+
392
+
393
+ class RegisterListCallableField (RegisterFieldTemplate ):
394
+ """Class that registers callable types
395
+
396
+ Attributes:
397
+ special_keys: dictionary to check special keys
398
+
399
+ """
400
+
401
+ def __init__ (self ):
402
+ """Init call to RegisterSimpleField
403
+
404
+ Args:
405
+ """
406
+ super (RegisterListCallableField , self ).__init__ ()
407
+
408
+ def _convert (self , val ):
409
+ str_field = str (val )
410
+ module , fn = str_field .rsplit ("." , 1 )
411
+ try :
412
+ call_ref = getattr (importlib .import_module (module ), fn )
413
+ except Exception as e :
414
+ raise _SpockValueError (
415
+ f"Attempted to import module { module } and callable { fn } however it could not be found on the current "
416
+ f"python path: { e } "
417
+ )
418
+ return call_ref
419
+
420
+ def _recurse_callables (self , val : List ):
421
+ attr_list = []
422
+ for sub in val :
423
+ if isinstance (sub , list ) or isinstance (sub , List ):
424
+ attr_list .append (self ._recurse_callables (sub ))
425
+ else :
426
+ attr_list .append (self ._convert (sub ))
427
+ return attr_list
428
+
429
+ def handle_attribute_from_config (
430
+ self , attr_space : AttributeSpace , builder_space : BuilderSpace
431
+ ):
432
+ """Handles setting a simple attribute when it is a spock class type
433
+
434
+ Args:
435
+ attr_space: holds information about a single attribute that is mapped to a ConfigSpace
436
+ builder_space: named_tuple containing the arguments and spock_space
437
+
438
+ Returns:
439
+ """
440
+ # These are always going to be strings... cast just in case
441
+ attr_list = []
442
+ for val in builder_space .arguments [attr_space .config_space .name ][
443
+ attr_space .attribute .name
444
+ ]:
445
+ if isinstance (val , list ) or isinstance (val , List ):
446
+ attr_list .append (self ._recurse_callables (val ))
447
+ else :
448
+ attr_list .append (self ._convert (val ))
449
+ attr_space .field = attr_list
450
+
451
+ def handle_optional_attribute_type (
452
+ self , attr_space : AttributeSpace , builder_space : BuilderSpace
453
+ ):
454
+ """Not implemented for this type
455
+
456
+ Args:
457
+ attr_space: holds information about a single attribute that is mapped to a ConfigSpace
458
+ builder_space: named_tuple containing the arguments and spock_space
459
+
460
+ Raises:
461
+ _SpockNotOptionalError
462
+
463
+ """
387
464
raise _SpockNotOptionalError (
388
465
f"Parameter `{ attr_space .attribute .name } ` within `{ attr_space .config_space .name } ` is of "
389
466
f"type `{ type (attr_space .attribute .type )} ` which seems to be unsupported -- "
@@ -640,6 +717,19 @@ def handle_optional_attribute_type(
640
717
self ._attr_type (attr_space ).__name__
641
718
] = attr_space .field
642
719
720
+ @classmethod
721
+ def _find_list_callables (cls , typed ):
722
+ out = False
723
+ if hasattr (typed , "__args__" ) and not isinstance (
724
+ typed .__args__ [0 ], _SpockVariadicGenericAlias
725
+ ):
726
+ out = cls ._find_list_callables (typed .__args__ [0 ])
727
+ elif hasattr (typed , "__args__" ) and isinstance (
728
+ typed .__args__ [0 ], _SpockVariadicGenericAlias
729
+ ):
730
+ out = True
731
+ return out
732
+
643
733
@classmethod
644
734
def recurse_generate (cls , spock_cls , builder_space : BuilderSpace ):
645
735
"""Call on a spock classes to iterate through the attrs attributes and handle each based on type and optionality
@@ -668,6 +758,10 @@ def recurse_generate(cls, spock_cls, builder_space: BuilderSpace):
668
758
(attribute .type is list ) or (attribute .type is List )
669
759
) and _is_spock_instance (attribute .metadata ["type" ].__args__ [0 ]):
670
760
handler = RegisterList ()
761
+ elif (
762
+ (attribute .type is list ) or (attribute .type is List )
763
+ ) and cls ._find_list_callables (attribute .metadata ["type" ]):
764
+ handler = RegisterListCallableField ()
671
765
# Enums
672
766
elif isinstance (attribute .type , EnumMeta ) and _check_iterable (
673
767
attribute .type
0 commit comments