-
Notifications
You must be signed in to change notification settings - Fork 25
Open
Labels
category: bugerrors in the code or code behaviorerrors in the code or code behaviorpriority: lowalternative solution already working and/or relevant to only specific user(s)alternative solution already working and/or relevant to only specific user(s)topic: extensionissues related to extensions or dynamic class generationissues related to extensions or dynamic class generation
Description
What happened?
If you try to define a neurodata_type that references itself, e.g.
sample = NWBGroupSpec(
neurodata_type_def="Sample",
neurodata_type_inc="NWBDataInterface",
doc="Description of the sample that was studied.",
groups=[
NWBGroupSpec(
quantity="*",
neurodata_type_inc="Sample",
doc="sample",
)
],
)
then when you run get_class
you get a RecursionError
:
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
Cell In [1], line 1
----> 1 from ndx_biosample import Sample
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/ndx_biosample/__init__.py:27
22 load_namespaces(ndx_biosample_specpath)
24 # TODO: import your classes here or define your class using get_class to make
25 # them accessible at the package level
26 #BaseType = get_class('BaseType', 'ndx-biosample')
---> 27 Sample = get_class('Sample', 'ndx-biosample')
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:649, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
647 def func_call(*args, **kwargs):
648 pargs = _check_args(args, kwargs)
--> 649 return func(**pargs)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/pynwb/__init__.py:185, in get_class(**kwargs)
162 """
163 Parse the YAML file for a given neurodata_type that is a subclass of NWBContainer and automatically generate its
164 python API. This will work for most containers, but is known to not work for descendants of MultiContainerInterface
(...)
182
183 """
184 neurodata_type, namespace = getargs('neurodata_type', 'namespace', kwargs)
--> 185 return __TYPE_MAP.get_dt_container_cls(neurodata_type, namespace)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:645, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
643 def func_call(*args, **kwargs):
644 pargs = _check_args(args, kwargs)
--> 645 return func(args[0], **pargs)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:518, in TypeMap.get_dt_container_cls(self, **kwargs)
516 if cls is None and autogen: # dynamically generate a class
517 spec = self.__ns_catalog.get_spec(namespace, data_type)
--> 518 self.__check_dependent_types(spec, namespace)
519 parent_cls = self.__get_parent_cls(namespace, data_type, spec)
520 attr_names = self.__default_mapper_cls.get_attr_names(spec)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:544, in TypeMap.__check_dependent_types(self, spec, namespace)
542 if isinstance(spec, GroupSpec):
543 for child_spec in (spec.groups + spec.datasets + spec.links):
--> 544 __check_dependent_types_helper(child_spec, namespace)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:531, in TypeMap.__check_dependent_types.<locals>.__check_dependent_types_helper(spec, namespace)
529 if isinstance(spec, (GroupSpec, DatasetSpec)):
530 if spec.data_type_inc is not None:
--> 531 self.get_dt_container_cls(spec.data_type_inc, namespace) # TODO handle recursive definitions
532 if spec.data_type_def is not None: # nested type definition
533 self.get_dt_container_cls(spec.data_type_def, namespace)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:645, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
643 def func_call(*args, **kwargs):
644 pargs = _check_args(args, kwargs)
--> 645 return func(args[0], **pargs)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:518, in TypeMap.get_dt_container_cls(self, **kwargs)
516 if cls is None and autogen: # dynamically generate a class
517 spec = self.__ns_catalog.get_spec(namespace, data_type)
--> 518 self.__check_dependent_types(spec, namespace)
519 parent_cls = self.__get_parent_cls(namespace, data_type, spec)
520 attr_names = self.__default_mapper_cls.get_attr_names(spec)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:544, in TypeMap.__check_dependent_types(self, spec, namespace)
542 if isinstance(spec, GroupSpec):
543 for child_spec in (spec.groups + spec.datasets + spec.links):
--> 544 __check_dependent_types_helper(child_spec, namespace)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:531, in TypeMap.__check_dependent_types.<locals>.__check_dependent_types_helper(spec, namespace)
529 if isinstance(spec, (GroupSpec, DatasetSpec)):
530 if spec.data_type_inc is not None:
--> 531 self.get_dt_container_cls(spec.data_type_inc, namespace) # TODO handle recursive definitions
532 if spec.data_type_def is not None: # nested type definition
533 self.get_dt_container_cls(spec.data_type_def, namespace)
[... skipping similar frames: docval.<locals>.dec.<locals>.func_call at line 645 (735 times), TypeMap.__check_dependent_types at line 544 (734 times), TypeMap.__check_dependent_types.<locals>.__check_dependent_types_helper at line 531 (734 times), TypeMap.get_dt_container_cls at line 518 (734 times)]
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:518, in TypeMap.get_dt_container_cls(self, **kwargs)
516 if cls is None and autogen: # dynamically generate a class
517 spec = self.__ns_catalog.get_spec(namespace, data_type)
--> 518 self.__check_dependent_types(spec, namespace)
519 parent_cls = self.__get_parent_cls(namespace, data_type, spec)
520 attr_names = self.__default_mapper_cls.get_attr_names(spec)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:544, in TypeMap.__check_dependent_types(self, spec, namespace)
542 if isinstance(spec, GroupSpec):
543 for child_spec in (spec.groups + spec.datasets + spec.links):
--> 544 __check_dependent_types_helper(child_spec, namespace)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:531, in TypeMap.__check_dependent_types.<locals>.__check_dependent_types_helper(spec, namespace)
529 if isinstance(spec, (GroupSpec, DatasetSpec)):
530 if spec.data_type_inc is not None:
--> 531 self.get_dt_container_cls(spec.data_type_inc, namespace) # TODO handle recursive definitions
532 if spec.data_type_def is not None: # nested type definition
533 self.get_dt_container_cls(spec.data_type_def, namespace)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:645, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
643 def func_call(*args, **kwargs):
644 pargs = _check_args(args, kwargs)
--> 645 return func(args[0], **pargs)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/build/manager.py:517, in TypeMap.get_dt_container_cls(self, **kwargs)
515 cls = self.__get_container_cls(namespace, data_type)
516 if cls is None and autogen: # dynamically generate a class
--> 517 spec = self.__ns_catalog.get_spec(namespace, data_type)
518 self.__check_dependent_types(spec, namespace)
519 parent_cls = self.__get_parent_cls(namespace, data_type, spec)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:645, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
643 def func_call(*args, **kwargs):
644 pargs = _check_args(args, kwargs)
--> 645 return func(args[0], **pargs)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/spec/namespace.py:316, in NamespaceCatalog.get_spec(self, **kwargs)
314 if namespace not in self.__namespaces:
315 raise KeyError("'%s' not a namespace" % namespace)
--> 316 return self.__namespaces[namespace].get_spec(data_type)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:645, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
643 def func_call(*args, **kwargs):
644 pargs = _check_args(args, kwargs)
--> 645 return func(args[0], **pargs)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/spec/namespace.py:148, in SpecNamespace.get_spec(self, **kwargs)
146 """Get the Spec object for the given data type"""
147 data_type = getargs('data_type', kwargs)
--> 148 spec = self.__catalog.get_spec(data_type)
149 if spec is None:
150 raise ValueError("No specification for '%s' in namespace '%s'" % (data_type, self.name))
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:644, in docval.<locals>.dec.<locals>.func_call(*args, **kwargs)
643 def func_call(*args, **kwargs):
--> 644 pargs = _check_args(args, kwargs)
645 return func(args[0], **pargs)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:616, in docval.<locals>.dec.<locals>._check_args(args, kwargs)
613 """Parse and check arguments to decorated function. Raise warnings and errors as appropriate."""
614 # this function was separated from func_call() in order to make stepping through lines of code using pdb
615 # easier
--> 616 parsed = __parse_args(
617 loc_val,
618 args[1:] if is_method else args,
619 kwargs,
620 enforce_type=enforce_type,
621 enforce_shape=enforce_shape,
622 allow_extra=allow_extra,
623 allow_positional=allow_positional
624 )
626 parse_warnings = parsed.get('future_warnings')
627 if parse_warnings:
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/site-packages/hdmf/utils.py:221, in __parse_args(validator, args, kwargs, enforce_type, enforce_shape, allow_extra, allow_positional)
218 try:
219 # check for duplicates in docval
220 names = [x['name'] for x in validator]
--> 221 duplicated = [item for item, count in collections.Counter(names).items()
222 if count > 1]
223 if duplicated:
224 raise ValueError(
225 'The following names are duplicated: {}'.format(duplicated))
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/collections/__init__.py:593, in Counter.__init__(self, iterable, **kwds)
582 '''Create a new, empty Counter object. And if given, count elements
583 from an input iterable. Or, initialize the count from another mapping
584 of elements to their counts.
(...)
590
591 '''
592 super().__init__()
--> 593 self.update(iterable, **kwds)
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/collections/__init__.py:670, in Counter.update(self, iterable, **kwds)
662 # The regular dict.update() operation makes no sense here because the
663 # replace behavior results in the some of original untouched counts
664 # being mixed-in with all of the other counts for a mismash that
665 # doesn't have a straight-forward interpretation in most counting
666 # contexts. Instead, we implement straight-addition. Both the inputs
667 # and outputs are allowed to contain zero and negative counts.
669 if iterable is not None:
--> 670 if isinstance(iterable, _collections_abc.Mapping):
671 if self:
672 self_get = self.get
File ~/opt/miniconda3/envs/conda_py3.9/lib/python3.9/abc.py:119, in ABCMeta.__instancecheck__(cls, instance)
117 def __instancecheck__(cls, instance):
118 """Override for isinstance(instance, cls)."""
--> 119 return _abc_instancecheck(cls, instance)
RecursionError: maximum recursion depth exceeded in comparison
Steps to Reproduce
see above
Traceback
see above
Operating System
macOS
Python Executable
Conda
Python Version
3.9
Package Versions
No response
Code of Conduct
- I agree to follow this project's Code of Conduct
- Have you checked the Contributing document?
- Have you ensured this bug was not already reported?
Metadata
Metadata
Assignees
Labels
category: bugerrors in the code or code behaviorerrors in the code or code behaviorpriority: lowalternative solution already working and/or relevant to only specific user(s)alternative solution already working and/or relevant to only specific user(s)topic: extensionissues related to extensions or dynamic class generationissues related to extensions or dynamic class generation