From cd3d7ca78e7e29c01202481b44d8292bf481b668 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Tue, 3 Sep 2024 00:54:38 -0700 Subject: [PATCH] model update --- .../pydantic/core/v2_2_0/core_nwb_base.py | 17 +++- .../pydantic/core/v2_2_0/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_2_0/core_nwb_device.py | 17 +++- .../pydantic/core/v2_2_0/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_2_0/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_2_0/core_nwb_file.py | 26 +++++- .../pydantic/core/v2_2_0/core_nwb_icephys.py | 26 +++++- .../pydantic/core/v2_2_0/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_2_0/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_2_0/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_2_0/core_nwb_ophys.py | 17 +++- .../core/v2_2_0/core_nwb_retinotopy.py | 43 +++++---- .../models/pydantic/core/v2_2_0/namespace.py | 17 +++- .../pydantic/core/v2_2_1/core_nwb_base.py | 17 +++- .../pydantic/core/v2_2_1/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_2_1/core_nwb_device.py | 17 +++- .../pydantic/core/v2_2_1/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_2_1/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_2_1/core_nwb_file.py | 26 +++++- .../pydantic/core/v2_2_1/core_nwb_icephys.py | 26 +++++- .../pydantic/core/v2_2_1/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_2_1/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_2_1/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_2_1/core_nwb_ophys.py | 17 +++- .../core/v2_2_1/core_nwb_retinotopy.py | 43 +++++---- .../models/pydantic/core/v2_2_1/namespace.py | 17 +++- .../pydantic/core/v2_2_2/core_nwb_base.py | 17 +++- .../pydantic/core/v2_2_2/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_2_2/core_nwb_device.py | 17 +++- .../pydantic/core/v2_2_2/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_2_2/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_2_2/core_nwb_file.py | 26 +++++- .../pydantic/core/v2_2_2/core_nwb_icephys.py | 26 +++++- .../pydantic/core/v2_2_2/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_2_2/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_2_2/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_2_2/core_nwb_ophys.py | 17 +++- .../core/v2_2_2/core_nwb_retinotopy.py | 17 +++- .../models/pydantic/core/v2_2_2/namespace.py | 17 +++- .../pydantic/core/v2_2_4/core_nwb_base.py | 17 +++- .../pydantic/core/v2_2_4/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_2_4/core_nwb_device.py | 17 +++- .../pydantic/core/v2_2_4/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_2_4/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_2_4/core_nwb_file.py | 26 +++++- .../pydantic/core/v2_2_4/core_nwb_icephys.py | 26 +++++- .../pydantic/core/v2_2_4/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_2_4/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_2_4/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_2_4/core_nwb_ophys.py | 20 ++++- .../core/v2_2_4/core_nwb_retinotopy.py | 17 +++- .../models/pydantic/core/v2_2_4/namespace.py | 17 +++- .../pydantic/core/v2_2_5/core_nwb_base.py | 17 +++- .../pydantic/core/v2_2_5/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_2_5/core_nwb_device.py | 17 +++- .../pydantic/core/v2_2_5/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_2_5/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_2_5/core_nwb_file.py | 26 +++++- .../pydantic/core/v2_2_5/core_nwb_icephys.py | 26 +++++- .../pydantic/core/v2_2_5/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_2_5/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_2_5/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_2_5/core_nwb_ophys.py | 20 ++++- .../core/v2_2_5/core_nwb_retinotopy.py | 17 +++- .../models/pydantic/core/v2_2_5/namespace.py | 17 +++- .../pydantic/core/v2_3_0/core_nwb_base.py | 17 +++- .../pydantic/core/v2_3_0/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_3_0/core_nwb_device.py | 17 +++- .../pydantic/core/v2_3_0/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_3_0/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_3_0/core_nwb_file.py | 21 ++++- .../pydantic/core/v2_3_0/core_nwb_icephys.py | 26 +++++- .../pydantic/core/v2_3_0/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_3_0/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_3_0/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_3_0/core_nwb_ophys.py | 20 ++++- .../core/v2_3_0/core_nwb_retinotopy.py | 17 +++- .../models/pydantic/core/v2_3_0/namespace.py | 17 +++- .../pydantic/core/v2_4_0/core_nwb_base.py | 17 +++- .../pydantic/core/v2_4_0/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_4_0/core_nwb_device.py | 17 +++- .../pydantic/core/v2_4_0/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_4_0/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_4_0/core_nwb_file.py | 21 ++++- .../pydantic/core/v2_4_0/core_nwb_icephys.py | 36 +++++--- .../pydantic/core/v2_4_0/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_4_0/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_4_0/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_4_0/core_nwb_ophys.py | 20 ++++- .../core/v2_4_0/core_nwb_retinotopy.py | 17 +++- .../models/pydantic/core/v2_4_0/namespace.py | 17 +++- .../pydantic/core/v2_5_0/core_nwb_base.py | 17 +++- .../pydantic/core/v2_5_0/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_5_0/core_nwb_device.py | 17 +++- .../pydantic/core/v2_5_0/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_5_0/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_5_0/core_nwb_file.py | 21 ++++- .../pydantic/core/v2_5_0/core_nwb_icephys.py | 36 +++++--- .../pydantic/core/v2_5_0/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_5_0/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_5_0/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_5_0/core_nwb_ophys.py | 20 ++++- .../core/v2_5_0/core_nwb_retinotopy.py | 17 +++- .../models/pydantic/core/v2_5_0/namespace.py | 17 +++- .../core/v2_6_0_alpha/core_nwb_base.py | 17 +++- .../core/v2_6_0_alpha/core_nwb_behavior.py | 17 +++- .../core/v2_6_0_alpha/core_nwb_device.py | 17 +++- .../core/v2_6_0_alpha/core_nwb_ecephys.py | 17 +++- .../core/v2_6_0_alpha/core_nwb_epoch.py | 26 +++++- .../core/v2_6_0_alpha/core_nwb_file.py | 21 ++++- .../core/v2_6_0_alpha/core_nwb_icephys.py | 36 +++++--- .../core/v2_6_0_alpha/core_nwb_image.py | 72 ++++++++++----- .../core/v2_6_0_alpha/core_nwb_misc.py | 22 ++++- .../core/v2_6_0_alpha/core_nwb_ogen.py | 17 +++- .../core/v2_6_0_alpha/core_nwb_ophys.py | 20 ++++- .../core/v2_6_0_alpha/core_nwb_retinotopy.py | 17 +++- .../pydantic/core/v2_6_0_alpha/namespace.py | 17 +++- .../pydantic/core/v2_7_0/core_nwb_base.py | 17 +++- .../pydantic/core/v2_7_0/core_nwb_behavior.py | 17 +++- .../pydantic/core/v2_7_0/core_nwb_device.py | 17 +++- .../pydantic/core/v2_7_0/core_nwb_ecephys.py | 17 +++- .../pydantic/core/v2_7_0/core_nwb_epoch.py | 26 +++++- .../pydantic/core/v2_7_0/core_nwb_file.py | 21 ++++- .../pydantic/core/v2_7_0/core_nwb_icephys.py | 36 +++++--- .../pydantic/core/v2_7_0/core_nwb_image.py | 72 ++++++++++----- .../pydantic/core/v2_7_0/core_nwb_misc.py | 22 ++++- .../pydantic/core/v2_7_0/core_nwb_ogen.py | 17 +++- .../pydantic/core/v2_7_0/core_nwb_ophys.py | 20 ++++- .../core/v2_7_0/core_nwb_retinotopy.py | 17 +++- .../models/pydantic/core/v2_7_0/namespace.py | 17 +++- .../hdmf_common/v1_1_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_1_0/hdmf_common_table.py | 77 +++++++++++----- .../pydantic/hdmf_common/v1_1_0/namespace.py | 17 +++- .../hdmf_common/v1_1_2/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_1_2/hdmf_common_table.py | 77 +++++++++++----- .../pydantic/hdmf_common/v1_1_2/namespace.py | 17 +++- .../hdmf_common/v1_1_3/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_1_3/hdmf_common_table.py | 86 +++++++++++------- .../pydantic/hdmf_common/v1_1_3/namespace.py | 17 +++- .../hdmf_common/v1_2_0/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_2_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_2_0/hdmf_common_table.py | 86 +++++++++++------- .../pydantic/hdmf_common/v1_2_0/namespace.py | 17 +++- .../hdmf_common/v1_2_1/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_2_1/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_2_1/hdmf_common_table.py | 86 +++++++++++------- .../pydantic/hdmf_common/v1_2_1/namespace.py | 17 +++- .../hdmf_common/v1_3_0/hdmf_common_base.py | 17 +++- .../v1_3_0/hdmf_common_resources.py | 17 +++- .../hdmf_common/v1_3_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_3_0/hdmf_common_table.py | 86 +++++++++++------- .../pydantic/hdmf_common/v1_3_0/namespace.py | 17 +++- .../hdmf_common/v1_4_0/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_4_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_4_0/hdmf_common_table.py | 86 +++++++++++------- .../pydantic/hdmf_common/v1_4_0/namespace.py | 17 +++- .../hdmf_common/v1_5_0/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_5_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_5_0/hdmf_common_table.py | 88 ++++++++++++------- .../pydantic/hdmf_common/v1_5_0/namespace.py | 17 +++- .../hdmf_common/v1_5_1/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_5_1/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_5_1/hdmf_common_table.py | 88 ++++++++++++------- .../pydantic/hdmf_common/v1_5_1/namespace.py | 17 +++- .../hdmf_common/v1_6_0/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_6_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_6_0/hdmf_common_table.py | 88 ++++++++++++------- .../pydantic/hdmf_common/v1_6_0/namespace.py | 17 +++- .../hdmf_common/v1_7_0/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_7_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_7_0/hdmf_common_table.py | 88 ++++++++++++------- .../pydantic/hdmf_common/v1_7_0/namespace.py | 17 +++- .../hdmf_common/v1_8_0/hdmf_common_base.py | 17 +++- .../hdmf_common/v1_8_0/hdmf_common_sparse.py | 17 +++- .../hdmf_common/v1_8_0/hdmf_common_table.py | 88 ++++++++++++------- .../pydantic/hdmf_common/v1_8_0/namespace.py | 17 +++- .../v0_1_0/hdmf_experimental_experimental.py | 17 +++- .../v0_1_0/hdmf_experimental_resources.py | 17 +++- .../hdmf_experimental/v0_1_0/namespace.py | 17 +++- .../v0_2_0/hdmf_experimental_experimental.py | 17 +++- .../v0_2_0/hdmf_experimental_resources.py | 17 +++- .../hdmf_experimental/v0_2_0/namespace.py | 17 +++- .../v0_3_0/hdmf_experimental_experimental.py | 17 +++- .../v0_3_0/hdmf_experimental_resources.py | 17 +++- .../hdmf_experimental/v0_3_0/namespace.py | 17 +++- .../v0_4_0/hdmf_experimental_experimental.py | 17 +++- .../v0_4_0/hdmf_experimental_resources.py | 17 +++- .../hdmf_experimental/v0_4_0/namespace.py | 17 +++- .../v0_5_0/hdmf_experimental_experimental.py | 17 +++- .../v0_5_0/hdmf_experimental_resources.py | 17 +++- .../hdmf_experimental/v0_5_0/namespace.py | 17 +++- .../linkml/core/v2_2_0/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_2_1/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_2_2/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_2_4/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_2_5/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_3_0/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_4_0/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_5_0/core.nwb.image.yaml | 25 ++++++ .../core/v2_6_0_alpha/core.nwb.image.yaml | 25 ++++++ .../linkml/core/v2_7_0/core.nwb.image.yaml | 25 ++++++ 201 files changed, 4394 insertions(+), 881 deletions(-) diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_base.py index db6e75c..e746c6d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_base.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_behavior.py index 31bf322..a6848de 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_device.py index bf15387..77f3252 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ecephys.py index 7a99a15..095da94 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_epoch.py index 7475c41..1c7071c 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_2_0.core_nwb_base import TimeSeries -from ...hdmf_common.v1_1_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -168,7 +188,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_file.py index e03f10b..bd10fab 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_file.py @@ -24,7 +24,12 @@ from ...core.v2_2_0.core_nwb_icephys import IntracellularElectrode, SweepTable from ...core.v2_2_0.core_nwb_misc import Units from ...core.v2_2_0.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_2_0.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_1_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -35,7 +40,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -54,6 +59,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -505,7 +525,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_icephys.py index be3a0ab..667bc6f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_icephys.py @@ -26,7 +26,12 @@ from ...core.v2_2_0.core_nwb_base import ( TimeSeriesSync, ) from ...core.v2_2_0.core_nwb_device import Device -from ...hdmf_common.v1_1_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -37,7 +42,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +61,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -897,7 +917,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_image.py index 73b924f..afd8481 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_image.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -84,17 +99,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -107,17 +121,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -130,17 +151,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_misc.py index f83925f..fbde138 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_2_0.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_1_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -443,7 +459,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -557,7 +573,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ogen.py index 853250a..89f02c0 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ophys.py index 6ce44c7..5f89bc4 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_ophys.py @@ -39,7 +39,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -58,6 +58,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_retinotopy.py index ab2f91e..fc034dc 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/core_nwb_retinotopy.py @@ -31,7 +31,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +50,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -166,17 +181,16 @@ class RetinotopyImage(GrayscaleImage): ) field_of_view: List[float] = Field(..., description="""Size of viewing area, in meters.""") format: str = Field(..., description="""Format of image. Right now only 'raw' is supported.""") + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImagingRetinotopy(NWBDataInterface): @@ -306,17 +320,16 @@ class ImagingRetinotopyFocalDepthImage(RetinotopyImage): ) field_of_view: List[float] = Field(..., description="""Size of viewing area, in meters.""") format: str = Field(..., description="""Format of image. Right now only 'raw' is supported.""") + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) # Model rebuild diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/namespace.py index 710c80c..c7c2358 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_0/namespace.py @@ -149,7 +149,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -168,6 +168,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_base.py index 635f77a..06b0763 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_base.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_behavior.py index c0a675b..1b14f72 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_device.py index 1da62bb..339f3e5 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ecephys.py index 25525e8..0abefd4 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_epoch.py index 247b667..2eae6a3 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_2_1.core_nwb_base import TimeSeries -from ...hdmf_common.v1_1_2.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_2.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -168,7 +188,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_file.py index 49ebbf0..80125a3 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_file.py @@ -24,7 +24,12 @@ from ...core.v2_2_1.core_nwb_icephys import IntracellularElectrode, SweepTable from ...core.v2_2_1.core_nwb_misc import Units from ...core.v2_2_1.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_2_1.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_1_2.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_2.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -35,7 +40,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -54,6 +59,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -505,7 +525,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_icephys.py index 34a9d42..9e5c172 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_icephys.py @@ -26,7 +26,12 @@ from ...core.v2_2_1.core_nwb_base import ( TimeSeriesSync, ) from ...core.v2_2_1.core_nwb_device import Device -from ...hdmf_common.v1_1_2.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_2.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -37,7 +42,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +61,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -897,7 +917,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_image.py index 0824778..9903c33 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_image.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -84,17 +99,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -107,17 +121,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -130,17 +151,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_misc.py index ecd0946..898d566 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_2_1.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_1_2.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -443,7 +459,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -557,7 +573,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ogen.py index 1577358..5aa8d0f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ophys.py index ca843fc..8c0234c 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_ophys.py @@ -39,7 +39,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -58,6 +58,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_retinotopy.py index 69e47a3..96dfdd0 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/core_nwb_retinotopy.py @@ -31,7 +31,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +50,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -166,17 +181,16 @@ class RetinotopyImage(GrayscaleImage): ) field_of_view: List[float] = Field(..., description="""Size of viewing area, in meters.""") format: str = Field(..., description="""Format of image. Right now only 'raw' is supported.""") + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImagingRetinotopy(NWBDataInterface): @@ -306,17 +320,16 @@ class ImagingRetinotopyFocalDepthImage(RetinotopyImage): ) field_of_view: List[float] = Field(..., description="""Size of viewing area, in meters.""") format: str = Field(..., description="""Format of image. Right now only 'raw' is supported.""") + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) # Model rebuild diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/namespace.py index 5dd8a41..a152e89 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_1/namespace.py @@ -149,7 +149,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -168,6 +168,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_base.py index dd580be..3052a7f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_base.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_behavior.py index bb900e7..9f00490 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_device.py index dbb96bf..5b492f5 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ecephys.py index 5749b00..8bfcbc5 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_epoch.py index 6e766ad..685a3e1 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_2_2.core_nwb_base import TimeSeries -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -168,7 +188,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_file.py index 3824ab2..93a273e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_file.py @@ -24,7 +24,12 @@ from ...core.v2_2_2.core_nwb_icephys import IntracellularElectrode, SweepTable from ...core.v2_2_2.core_nwb_misc import Units from ...core.v2_2_2.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_2_2.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -35,7 +40,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -54,6 +59,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -505,7 +525,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_icephys.py index 9d4a696..89f98be 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_icephys.py @@ -26,7 +26,12 @@ from ...core.v2_2_2.core_nwb_base import ( TimeSeriesSync, ) from ...core.v2_2_2.core_nwb_device import Device -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -37,7 +42,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +61,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -897,7 +917,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_image.py index fec53fa..c050722 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_image.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -84,17 +99,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -107,17 +121,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -130,17 +151,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_misc.py index 5c32d21..ed39a48 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_2_2.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_1_3.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -443,7 +459,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -557,7 +573,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ogen.py index 8c1e21d..630218f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ophys.py index b7ed446..4456b5e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_ophys.py @@ -39,7 +39,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -58,6 +58,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_retinotopy.py index f92004d..6669e29 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/namespace.py index 536af15..a962b02 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_2/namespace.py @@ -152,7 +152,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -171,6 +171,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_base.py index 82fa6ff..ca4642a 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_base.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_behavior.py index e14c8d5..031a527 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_device.py index 09cf60b..b6a0790 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ecephys.py index 25a0a42..ce573c0 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_epoch.py index 3cd5078..38ab101 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_2_4.core_nwb_base import TimeSeries -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -168,7 +188,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_file.py index 0542071..ba6e4b9 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_file.py @@ -25,7 +25,12 @@ from ...core.v2_2_4.core_nwb_icephys import IntracellularElectrode, SweepTable from ...core.v2_2_4.core_nwb_misc import Units from ...core.v2_2_4.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_2_4.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -36,7 +41,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -55,6 +60,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -481,7 +501,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_icephys.py index 8f20762..9a6ad6e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_icephys.py @@ -26,7 +26,12 @@ from ...core.v2_2_4.core_nwb_base import ( TimeSeriesSync, ) from ...core.v2_2_4.core_nwb_device import Device -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -37,7 +42,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +61,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -897,7 +917,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_image.py index 850e89f..a30fe3b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_image.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -84,17 +99,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -107,17 +121,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -130,17 +151,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_misc.py index 22fc753..dca9ee9 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_2_4.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_1_3.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -443,7 +459,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -557,7 +573,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ogen.py index 50d25ad..79e484e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ophys.py index 1a0bf16..a7f6886 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_ophys.py @@ -31,6 +31,7 @@ from ...core.v2_2_4.core_nwb_image import ImageSeries, ImageSeriesExternalFile from ...hdmf_common.v1_1_3.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -373,7 +389,7 @@ class PlaneSegmentation(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_retinotopy.py index 111a502..d0b4129 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/namespace.py index 10795d3..ddb8793 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_4/namespace.py @@ -159,7 +159,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -178,6 +178,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_base.py index 5012a43..0157a3e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_base.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_behavior.py index e7c936a..711219e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_device.py index 5d308f9..077b62b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ecephys.py index 4e993f0..aa674e7 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_epoch.py index bd7e37e..fd13aa2 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_2_5.core_nwb_base import TimeSeries -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -168,7 +188,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_file.py index 1998de2..7603841 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_file.py @@ -25,7 +25,12 @@ from ...core.v2_2_5.core_nwb_icephys import IntracellularElectrode, SweepTable from ...core.v2_2_5.core_nwb_misc import Units from ...core.v2_2_5.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_2_5.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -36,7 +41,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -55,6 +60,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -481,7 +501,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_icephys.py index 5a57663..754e05d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_icephys.py @@ -26,7 +26,12 @@ from ...core.v2_2_5.core_nwb_base import ( TimeSeriesSync, ) from ...core.v2_2_5.core_nwb_device import Device -from ...hdmf_common.v1_1_3.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_1_3.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -37,7 +42,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +61,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -897,7 +917,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_image.py index 7f20c3a..9210d64 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_image.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -84,17 +99,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -107,17 +121,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -130,17 +151,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_misc.py index 36c0f1e..e97da8b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_2_5.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_1_3.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -443,7 +459,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -557,7 +573,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ogen.py index 294866b..476bec4 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ophys.py index 4860989..c32e213 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_ophys.py @@ -31,6 +31,7 @@ from ...core.v2_2_5.core_nwb_image import ImageSeries, ImageSeriesExternalFile from ...hdmf_common.v1_1_3.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -375,7 +391,7 @@ class PlaneSegmentation(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_retinotopy.py index 6f05814..8da471b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/namespace.py index 5f82379..724c1e6 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_2_5/namespace.py @@ -159,7 +159,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -178,6 +178,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_base.py index 34bb4c6..b18e626 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_base.py @@ -23,7 +23,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -42,6 +42,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_behavior.py index ef00827..758ac17 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_device.py index 26e327b..2eb59fb 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ecephys.py index 7092c13..1a708c9 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_epoch.py index d5015fe..74265d3 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_3_0.core_nwb_base import TimeSeries -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_5_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -168,7 +188,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_file.py index 2000dfd..5954c68 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_file.py @@ -25,7 +25,7 @@ from ...core.v2_3_0.core_nwb_icephys import IntracellularElectrode, SweepTable from ...core.v2_3_0.core_nwb_misc import Units from ...core.v2_3_0.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_3_0.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData +from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, ElementIdentifiers, VectorData metamodel_version = "None" @@ -36,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -55,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -481,7 +496,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_icephys.py index aad3631..54b3ae9 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_icephys.py @@ -26,7 +26,12 @@ from ...core.v2_3_0.core_nwb_base import ( TimeSeriesSync, ) from ...core.v2_3_0.core_nwb_device import Device -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_5_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -37,7 +42,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +61,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -899,7 +919,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_image.py index fb2bc82..63577ef 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_image.py @@ -23,7 +23,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -42,6 +42,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -85,17 +100,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -108,17 +122,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -131,17 +152,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_misc.py index 8d984db..0560527 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_3_0.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -455,7 +471,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -601,7 +617,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ogen.py index 2e49cf9..22f7adc 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ophys.py index 29cac39..ab3cdbc 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_ophys.py @@ -31,6 +31,7 @@ from ...core.v2_3_0.core_nwb_image import ImageSeries, ImageSeriesExternalFile from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -384,7 +400,7 @@ class PlaneSegmentation(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_retinotopy.py index d58860e..07097bb 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/namespace.py index b5ffa4b..97dfca3 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_3_0/namespace.py @@ -162,7 +162,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -181,6 +181,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_base.py index b557e8c..2cb8f77 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_base.py @@ -36,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -55,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_behavior.py index c96aee7..8444b65 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_device.py index ebf61b7..b468f9a 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ecephys.py index bfe65b3..6153aad 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_epoch.py index 603c5d3..1967963 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_4_0.core_nwb_base import TimeSeries -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_5_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -168,7 +188,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_file.py index 186458d..c337990 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_file.py @@ -33,7 +33,7 @@ from ...core.v2_4_0.core_nwb_icephys import ( from ...core.v2_4_0.core_nwb_misc import Units from ...core.v2_4_0.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_4_0.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData +from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, ElementIdentifiers, VectorData metamodel_version = "None" @@ -44,7 +44,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +63,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -489,7 +504,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_icephys.py index aa2accc..29932a6 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_icephys.py @@ -31,6 +31,7 @@ from ...hdmf_common.v1_5_0.hdmf_common_table import ( AlignedDynamicTable, DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -906,7 +922,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -943,7 +959,7 @@ class IntracellularElectrodesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -989,7 +1005,7 @@ class IntracellularStimuliTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1035,7 +1051,7 @@ class IntracellularResponsesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1101,7 +1117,7 @@ class IntracellularRecordingsTable(AlignedDynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1150,7 +1166,7 @@ class SimultaneousRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1238,7 +1254,7 @@ class SequentialRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1317,7 +1333,7 @@ class RepetitionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1398,7 +1414,7 @@ class ExperimentalConditionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_image.py index 5d1e5d8..4cf5fd4 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_image.py @@ -23,7 +23,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -42,6 +42,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -85,17 +100,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -108,17 +122,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -131,17 +152,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_misc.py index 6c06a17..f83ca9e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_4_0.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -455,7 +471,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -601,7 +617,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ogen.py index 07100b3..35b5c3c 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ophys.py index 0d335ca..48afbe4 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_ophys.py @@ -31,6 +31,7 @@ from ...core.v2_4_0.core_nwb_image import ImageSeries, ImageSeriesExternalFile from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -384,7 +400,7 @@ class PlaneSegmentation(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_retinotopy.py index a42a469..5973f2e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/namespace.py index 4bc04cd..dd7a197 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_4_0/namespace.py @@ -175,7 +175,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -194,6 +194,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_base.py index 3a2170a..2b9db4d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_base.py @@ -47,7 +47,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -66,6 +66,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_behavior.py index d4e6a03..4eb79e6 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_device.py index 16f07fc..60821f8 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ecephys.py index 343564a..237a995 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_epoch.py index 2fafb90..0f5f803 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_5_0.core_nwb_base import TimeSeriesReferenceVectorData -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_5_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -177,7 +197,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_file.py index 039eb68..c47be55 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_file.py @@ -34,7 +34,7 @@ from ...core.v2_5_0.core_nwb_icephys import ( from ...core.v2_5_0.core_nwb_misc import Units from ...core.v2_5_0.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_5_0.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData +from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, ElementIdentifiers, VectorData metamodel_version = "None" @@ -45,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -64,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -492,7 +507,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_icephys.py index bef122c..c4ae637 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_icephys.py @@ -31,6 +31,7 @@ from ...hdmf_common.v1_5_0.hdmf_common_table import ( AlignedDynamicTable, DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -907,7 +923,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +960,7 @@ class IntracellularElectrodesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -990,7 +1006,7 @@ class IntracellularStimuliTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1036,7 +1052,7 @@ class IntracellularResponsesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1102,7 +1118,7 @@ class IntracellularRecordingsTable(AlignedDynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1151,7 +1167,7 @@ class SimultaneousRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1239,7 +1255,7 @@ class SequentialRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1318,7 +1334,7 @@ class RepetitionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1399,7 +1415,7 @@ class ExperimentalConditionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_image.py index 21e5d0a..c0b1daf 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_image.py @@ -29,7 +29,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -48,6 +48,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -91,17 +106,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -114,17 +128,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -137,17 +158,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_misc.py index 6be8f5c..293403f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_5_0.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -455,7 +471,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -601,7 +617,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ogen.py index 5d3e9ff..b26a59d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ophys.py index fef5a92..c72f71d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_ophys.py @@ -31,6 +31,7 @@ from ...core.v2_5_0.core_nwb_image import ImageSeries, ImageSeriesExternalFile from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -384,7 +400,7 @@ class PlaneSegmentation(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_retinotopy.py index e399448..c9c3d85 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/namespace.py index 5692d11..fd08f03 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_5_0/namespace.py @@ -176,7 +176,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -195,6 +195,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_base.py index c4d356f..f0f66dd 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_base.py @@ -47,7 +47,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -66,6 +66,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_behavior.py index 07f5165..05cece8 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_device.py index c1a89c4..d05fe5d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ecephys.py index d83d650..e8d05f3 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_epoch.py index 46da361..82e2b83 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_6_0_alpha.core_nwb_base import TimeSeriesReferenceVectorData -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_5_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -177,7 +197,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_file.py index 6c39f8e..5e58bec 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_file.py @@ -34,7 +34,7 @@ from ...core.v2_6_0_alpha.core_nwb_icephys import ( from ...core.v2_6_0_alpha.core_nwb_misc import Units from ...core.v2_6_0_alpha.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_6_0_alpha.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, VectorData +from ...hdmf_common.v1_5_0.hdmf_common_table import DynamicTable, ElementIdentifiers, VectorData metamodel_version = "None" @@ -45,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -64,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -492,7 +507,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_icephys.py index 8142b53..55d4c8f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_icephys.py @@ -31,6 +31,7 @@ from ...hdmf_common.v1_5_0.hdmf_common_table import ( AlignedDynamicTable, DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -907,7 +923,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +960,7 @@ class IntracellularElectrodesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -990,7 +1006,7 @@ class IntracellularStimuliTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1036,7 +1052,7 @@ class IntracellularResponsesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1102,7 +1118,7 @@ class IntracellularRecordingsTable(AlignedDynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1151,7 +1167,7 @@ class SimultaneousRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1239,7 +1255,7 @@ class SequentialRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1318,7 +1334,7 @@ class RepetitionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1399,7 +1415,7 @@ class ExperimentalConditionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_image.py index e0506e9..cfe8a10 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_image.py @@ -29,7 +29,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -48,6 +48,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -91,17 +106,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -114,17 +128,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -137,17 +158,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_misc.py index ee349a1..94272fc 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_6_0_alpha.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -455,7 +471,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -601,7 +617,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ogen.py index 5565ce8..2a6b4e7 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ophys.py index 76d0e67..f2cfdd4 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_ophys.py @@ -31,6 +31,7 @@ from ...core.v2_6_0_alpha.core_nwb_image import ImageSeries, ImageSeriesExternal from ...hdmf_common.v1_5_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -483,7 +499,7 @@ class PlaneSegmentation(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_retinotopy.py index b3017f1..404fbda 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/namespace.py index a6c0e87..5d523c9 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_6_0_alpha/namespace.py @@ -178,7 +178,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -197,6 +197,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_base.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_base.py index 961bfd4..d58b849 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_base.py @@ -47,7 +47,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -66,6 +66,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_behavior.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_behavior.py index 43c1936..1e1712a 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_behavior.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_behavior.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_device.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_device.py index 3867744..0209d51 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_device.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_device.py @@ -21,7 +21,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -40,6 +40,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ecephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ecephys.py index 89eeeb0..9d1ddde 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ecephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ecephys.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_epoch.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_epoch.py index 95178b0..488863b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_epoch.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_epoch.py @@ -20,7 +20,12 @@ from pydantic import ( ) from ...core.v2_7_0.core_nwb_base import TimeSeriesReferenceVectorData -from ...hdmf_common.v1_8_0.hdmf_common_table import DynamicTable, VectorData, VectorIndex +from ...hdmf_common.v1_8_0.hdmf_common_table import ( + DynamicTable, + ElementIdentifiers, + VectorData, + VectorIndex, +) metamodel_version = "None" @@ -31,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -50,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -177,7 +197,7 @@ class TimeIntervals(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_file.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_file.py index fe7fabd..f627329 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_file.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_file.py @@ -34,7 +34,7 @@ from ...core.v2_7_0.core_nwb_icephys import ( from ...core.v2_7_0.core_nwb_misc import Units from ...core.v2_7_0.core_nwb_ogen import OptogeneticStimulusSite from ...core.v2_7_0.core_nwb_ophys import ImagingPlane -from ...hdmf_common.v1_8_0.hdmf_common_table import DynamicTable, VectorData +from ...hdmf_common.v1_8_0.hdmf_common_table import DynamicTable, ElementIdentifiers, VectorData metamodel_version = "None" @@ -45,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -64,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -500,7 +515,7 @@ class ExtracellularEphysElectrodes(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_icephys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_icephys.py index 9e72812..f1a0a50 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_icephys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_icephys.py @@ -31,6 +31,7 @@ from ...hdmf_common.v1_8_0.hdmf_common_table import ( AlignedDynamicTable, DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -907,7 +923,7 @@ class SweepTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +960,7 @@ class IntracellularElectrodesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1002,7 +1018,7 @@ class IntracellularStimuliTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1048,7 +1064,7 @@ class IntracellularResponsesTable(DynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1114,7 +1130,7 @@ class IntracellularRecordingsTable(AlignedDynamicTable): ..., description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1163,7 +1179,7 @@ class SimultaneousRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1251,7 +1267,7 @@ class SequentialRecordingsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1330,7 +1346,7 @@ class RepetitionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -1411,7 +1427,7 @@ class ExperimentalConditionsTable(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_image.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_image.py index d98ffe1..51da971 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_image.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_image.py @@ -29,7 +29,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -48,6 +48,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -91,17 +106,16 @@ class GrayscaleImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": {"array": {"dimensions": [{"alias": "x"}, {"alias": "y"}]}} + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBImage(Image): @@ -114,17 +128,24 @@ class RGBImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 3 r_g_b"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b", "exact_cardinality": 3}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class RGBAImage(Image): @@ -137,17 +158,24 @@ class RGBAImage(Image): ) name: str = Field(...) + value: Optional[NDArray[Shape["* x, * y, 4 r_g_b_a"], float]] = Field( + None, + json_schema_extra={ + "linkml_meta": { + "array": { + "dimensions": [ + {"alias": "x"}, + {"alias": "y"}, + {"alias": "r_g_b_a", "exact_cardinality": 4}, + ] + } + } + }, + ) resolution: Optional[float] = Field( None, description="""Pixel resolution of the image, in pixels per centimeter.""" ) description: Optional[str] = Field(None, description="""Description of the image.""") - value: Optional[ - Union[ - NDArray[Shape["* x, * y"], float], - NDArray[Shape["* x, * y, 3 r_g_b"], float], - NDArray[Shape["* x, * y, 4 r_g_b_a"], float], - ] - ] = Field(None) class ImageSeries(TimeSeries): diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_misc.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_misc.py index 31c081b..007cb43 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_misc.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_misc.py @@ -24,6 +24,7 @@ from ...core.v2_7_0.core_nwb_ecephys import ElectrodeGroup from ...hdmf_common.v1_8_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -37,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -455,7 +471,7 @@ class DecompositionSeriesBands(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -601,7 +617,7 @@ class Units(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ogen.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ogen.py index 5eb87cf..a321489 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ogen.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ogen.py @@ -28,7 +28,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -47,6 +47,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ophys.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ophys.py index 3f8d8eb..a3bbf68 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ophys.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_ophys.py @@ -31,6 +31,7 @@ from ...core.v2_7_0.core_nwb_image import ImageSeries, ImageSeriesExternalFile from ...hdmf_common.v1_8_0.hdmf_common_table import ( DynamicTable, DynamicTableRegion, + ElementIdentifiers, VectorData, VectorIndex, ) @@ -44,7 +45,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +64,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -483,7 +499,7 @@ class PlaneSegmentation(DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_retinotopy.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_retinotopy.py index 909aaf3..6d1a2d2 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_retinotopy.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/core_nwb_retinotopy.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/namespace.py index 9256d2f..e2c6018 100644 --- a/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/core/v2_7_0/namespace.py @@ -179,7 +179,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -198,6 +198,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_sparse.py index c71894e..59cf857 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_sparse.py @@ -20,7 +20,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -39,6 +39,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_table.py index f1ee937..f6fb96e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/hdmf_common_table.py @@ -44,7 +44,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +63,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -96,10 +111,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -498,6 +513,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -529,9 +546,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -749,14 +770,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -796,6 +822,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -837,7 +870,7 @@ class Index(Data): ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex(0)+1]. The second vector is at VectorData[VectorIndex(0)+1:VectorIndex(1)+1], and so on. """ @@ -850,7 +883,7 @@ class VectorData(VectorDataMixin): description: str = Field(..., description="""Description of what these vectors represent.""") -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. """ @@ -865,7 +898,7 @@ class VectorIndex(VectorIndexMixin): ) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -877,13 +910,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -913,7 +946,7 @@ class Container(ConfiguredBaseModel): name: str = Field(...) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). Apart from a column that contains unique identifiers for each row there are no other required datasets. Users are free to add any number of VectorData objects here. Table functionality is already supported through compound types, which is analogous to storing an array-of-structs. DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. For example, DynamicTable was originally developed for storing trial data and spike unit metadata. Both of these use cases are expected to produce relatively small tables, so the spatial locality of multiple datasets present in a DynamicTable is not expected to have a significant performance impact. Additionally, requirements of trial and unit metadata tables are sufficiently diverse that performance implications can be overlooked in favor of usability. """ @@ -928,7 +961,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/namespace.py index 1a6e22f..e9c0f5a 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_0/namespace.py @@ -36,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -55,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_sparse.py index bd66832..59dc4e8 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_sparse.py @@ -20,7 +20,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -39,6 +39,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_table.py index 6d78742..05581fb 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/hdmf_common_table.py @@ -44,7 +44,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +63,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -96,10 +111,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -498,6 +513,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -529,9 +546,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -749,14 +770,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -796,6 +822,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -837,7 +870,7 @@ class Index(Data): ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex(0)+1]. The second vector is at VectorData[VectorIndex(0)+1:VectorIndex(1)+1], and so on. """ @@ -850,7 +883,7 @@ class VectorData(VectorDataMixin): description: str = Field(..., description="""Description of what these vectors represent.""") -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. """ @@ -865,7 +898,7 @@ class VectorIndex(VectorIndexMixin): ) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -877,13 +910,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -913,7 +946,7 @@ class Container(ConfiguredBaseModel): name: str = Field(...) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). Apart from a column that contains unique identifiers for each row there are no other required datasets. Users are free to add any number of VectorData objects here. Table functionality is already supported through compound types, which is analogous to storing an array-of-structs. DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. For example, DynamicTable was originally developed for storing trial data and spike unit metadata. Both of these use cases are expected to produce relatively small tables, so the spatial locality of multiple datasets present in a DynamicTable is not expected to have a significant performance impact. Additionally, requirements of trial and unit metadata tables are sufficiently diverse that performance implications can be overlooked in favor of usability. """ @@ -928,7 +961,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/namespace.py index 786e141..1dbfe1b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_2/namespace.py @@ -36,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -55,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_sparse.py index 09ea0f1..6e16e46 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_sparse.py @@ -20,7 +20,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -39,6 +39,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_table.py index b7aabf3..e0ce3e1 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/hdmf_common_table.py @@ -44,7 +44,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -63,6 +63,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -96,10 +111,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -498,6 +513,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -529,9 +546,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -749,14 +770,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -796,6 +822,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -837,7 +870,7 @@ class Index(Data): ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex(0)+1]. The second vector is at VectorData[VectorIndex(0)+1:VectorIndex(1)+1], and so on. """ @@ -848,17 +881,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. """ @@ -876,7 +902,7 @@ class VectorIndex(VectorIndexMixin): ) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -888,13 +914,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -932,7 +958,7 @@ class Container(ConfiguredBaseModel): name: str = Field(...) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). Apart from a column that contains unique identifiers for each row there are no other required datasets. Users are free to add any number of VectorData objects here. Table functionality is already supported through compound types, which is analogous to storing an array-of-structs. DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. For example, DynamicTable was originally developed for storing trial data and spike unit metadata. Both of these use cases are expected to produce relatively small tables, so the spatial locality of multiple datasets present in a DynamicTable is not expected to have a significant performance impact. Additionally, requirements of trial and unit metadata tables are sufficiently diverse that performance implications can be overlooked in favor of usability. """ @@ -947,7 +973,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/namespace.py index 1458d9b..bed51d1 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_1_3/namespace.py @@ -36,7 +36,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -55,6 +55,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_base.py index aa2b460..02db015 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_sparse.py index a0a70de..31d5909 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_sparse.py @@ -20,7 +20,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -39,6 +39,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_table.py index 5d66a65..3232dbf 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -927,7 +953,7 @@ class VocabData(VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -942,7 +968,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/namespace.py index f56d638..538cb3a 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_0/namespace.py @@ -35,7 +35,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -54,6 +54,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_base.py index 7476a40..8bd7526 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_sparse.py index c2222d1..f430892 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_table.py index c319712..e6e72ea 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -927,7 +953,7 @@ class VocabData(VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -942,7 +968,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/namespace.py index f8a0d6f..b6d2dde 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_2_1/namespace.py @@ -35,7 +35,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -54,6 +54,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_base.py index d484652..b0a5b1f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_resources.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_resources.py index 8f8f711..83e7be1 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_resources.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_resources.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_sparse.py index 4d93c70..28e5990 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_table.py index a6e652d..de1ea05 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -927,7 +953,7 @@ class VocabData(VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -942,7 +968,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/namespace.py index dcb742c..6e4f626 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_3_0/namespace.py @@ -37,7 +37,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -56,6 +56,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_base.py index f47e8ca..b74a6dc 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_sparse.py index af8cc73..e32e04f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_table.py index 3e947f4..f6f0ea5 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -901,7 +927,7 @@ class DynamicTableRegion(DynamicTableRegionMixin, VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -916,7 +942,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/namespace.py index b110f2d..2cad381 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_4_0/namespace.py @@ -29,7 +29,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -48,6 +48,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_base.py index 2412f82..1d3106d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_sparse.py index 21258d8..a60b286 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_table.py index a77379b..6570cc0 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -901,7 +927,7 @@ class DynamicTableRegion(DynamicTableRegionMixin, VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -916,7 +942,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +970,7 @@ class AlignedDynamicTable(AlignedDynamicTableMixin, DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/namespace.py index d5c14d9..c8a084c 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_0/namespace.py @@ -30,7 +30,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -49,6 +49,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_base.py index f3c24b4..af3eb2b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_sparse.py index fce455b..1c5dcff 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_table.py index 8066977..dfede77 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -901,7 +927,7 @@ class DynamicTableRegion(DynamicTableRegionMixin, VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -916,7 +942,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +970,7 @@ class AlignedDynamicTable(AlignedDynamicTableMixin, DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/namespace.py index 442efe7..91fdf29 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_5_1/namespace.py @@ -30,7 +30,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -49,6 +49,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_base.py index d53c4b5..408b90c 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_sparse.py index d60f430..aee2271 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_table.py index 3589ee4..bccbdeb 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -901,7 +927,7 @@ class DynamicTableRegion(DynamicTableRegionMixin, VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -916,7 +942,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +970,7 @@ class AlignedDynamicTable(AlignedDynamicTableMixin, DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/namespace.py index f9dd0a8..a30f739 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_6_0/namespace.py @@ -30,7 +30,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -49,6 +49,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_base.py index 7872584..4df3ea5 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_sparse.py index e21dca7..6dea1d7 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_table.py index c5c62cf..e2c046c 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -901,7 +927,7 @@ class DynamicTableRegion(DynamicTableRegionMixin, VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -916,7 +942,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +970,7 @@ class AlignedDynamicTable(AlignedDynamicTableMixin, DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/namespace.py index a3f0b14..7e281c4 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_7_0/namespace.py @@ -30,7 +30,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -49,6 +49,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_base.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_base.py index 8b4d98f..89e73ca 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_base.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_base.py @@ -19,7 +19,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -38,6 +38,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_sparse.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_sparse.py index 4da904e..9e95ec9 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_sparse.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_sparse.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_table.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_table.py index 7ed76ee..491923c 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_table.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/hdmf_common_table.py @@ -46,7 +46,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -65,6 +65,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} @@ -98,10 +113,10 @@ class VectorDataMixin(BaseModel, Generic[T]): # redefined in `VectorData`, but included here for testing and type checking value: Optional[T] = None - def __init__(self, value: Optional[NDArray] = None, **kwargs): - if value is not None and "value" not in kwargs: - kwargs["value"] = value - super().__init__(**kwargs) + # def __init__(self, value: Optional[NDArray] = None, **kwargs): + # if value is not None and "value" not in kwargs: + # kwargs["value"] = value + # super().__init__(**kwargs) def __getitem__(self, item: Union[str, int, slice, Tuple[Union[str, int, slice], ...]]) -> Any: if self._index: @@ -500,6 +515,8 @@ class DynamicTableMixin(BaseModel): else: # add any columns not explicitly given an order at the end colnames = model["colnames"].copy() + if isinstance(colnames, np.ndarray): + colnames = colnames.tolist() colnames.extend( [ k @@ -531,9 +548,13 @@ class DynamicTableMixin(BaseModel): if not isinstance(val, (VectorData, VectorIndex)): try: if key.endswith("_index"): - model[key] = VectorIndex(name=key, description="", value=val) + to_cast = VectorIndex else: - model[key] = VectorData(name=key, description="", value=val) + to_cast = VectorData + if isinstance(val, dict): + model[key] = to_cast(**val) + else: + model[key] = VectorIndex(name=key, description="", value=val) except ValidationError as e: # pragma: no cover raise ValidationError.from_exception_data( title=f"field {key} cannot be cast to VectorData from {val}", @@ -751,14 +772,19 @@ class AlignedDynamicTableMixin(BaseModel): model["categories"] = categories else: # add any columns not explicitly given an order at the end - categories = [ - k - for k in model - if k not in cls.NON_COLUMN_FIELDS - and not k.endswith("_index") - and k not in model["categories"] - ] - model["categories"].extend(categories) + categories = model["categories"].copy() + if isinstance(categories, np.ndarray): + categories = categories.tolist() + categories.extend( + [ + k + for k in model + if k not in cls.NON_CATEGORY_FIELDS + and not k.endswith("_index") + and k not in model["categories"] + ] + ) + model["categories"] = categories return model @model_validator(mode="after") @@ -798,6 +824,13 @@ class AlignedDynamicTableMixin(BaseModel): return self +class ElementIdentifiersMixin(VectorDataMixin): + """ + Mixin class for ElementIdentifiers - allow treating + as generic, and give general indexing methods from VectorData + """ + + linkml_meta = LinkMLMeta( { "annotations": { @@ -812,7 +845,7 @@ linkml_meta = LinkMLMeta( ) -class VectorData(VectorDataMixin): +class VectorData(VectorDataMixin, ConfiguredBaseModel): """ An n-dimensional dataset representing a column of a DynamicTable. If used without an accompanying VectorIndex, first dimension is along the rows of the DynamicTable and each step along the first dimension is a cell of the larger table. VectorData can also be used to represent a ragged array if paired with a VectorIndex. This allows for storing arrays of varying length in a single cell of the DynamicTable by indexing into this VectorData. The first vector is at VectorData[0:VectorIndex[0]]. The second vector is at VectorData[VectorIndex[0]:VectorIndex[1]], and so on. """ @@ -823,17 +856,10 @@ class VectorData(VectorDataMixin): name: str = Field(...) description: str = Field(..., description="""Description of what these vectors represent.""") - value: Optional[ - Union[ - NDArray[Shape["* dim0"], Any], - NDArray[Shape["* dim0, * dim1"], Any], - NDArray[Shape["* dim0, * dim1, * dim2"], Any], - NDArray[Shape["* dim0, * dim1, * dim2, * dim3"], Any], - ] - ] = Field(None) + value: Optional[T] = Field(None) -class VectorIndex(VectorIndexMixin): +class VectorIndex(VectorIndexMixin, ConfiguredBaseModel): """ Used with VectorData to encode a ragged array. An array of indices into the first dimension of the target VectorData, and forming a map between the rows of a DynamicTable and the indices of the VectorData. The name of the VectorIndex is expected to be the name of the target VectorData object followed by \"_index\". """ @@ -857,7 +883,7 @@ class VectorIndex(VectorIndexMixin): ] = Field(None) -class ElementIdentifiers(Data): +class ElementIdentifiers(ElementIdentifiersMixin, Data, ConfiguredBaseModel): """ A list of unique identifiers for values within a dataset, e.g. rows of a DynamicTable. """ @@ -869,13 +895,13 @@ class ElementIdentifiers(Data): name: str = Field( "element_id", json_schema_extra={"linkml_meta": {"ifabsent": "string(element_id)"}} ) - value: Optional[NDArray[Shape["* num_elements"], int]] = Field( + value: Optional[T] = Field( None, json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_elements"}]}}}, ) -class DynamicTableRegion(DynamicTableRegionMixin, VectorData): +class DynamicTableRegion(DynamicTableRegionMixin, VectorData, ConfiguredBaseModel): """ DynamicTableRegion provides a link from one table to an index or region of another. The `table` attribute is a link to another `DynamicTable`, indicating which table is referenced, and the data is int(s) indicating the row(s) (0-indexed) of the target array. `DynamicTableRegion`s can be used to associate rows with repeated meta-data without data duplication. They can also be used to create hierarchical relationships between multiple `DynamicTable`s. `DynamicTableRegion` objects may be paired with a `VectorIndex` object to create ragged references, so a single cell of a `DynamicTable` can reference many rows of another `DynamicTable`. """ @@ -901,7 +927,7 @@ class DynamicTableRegion(DynamicTableRegionMixin, VectorData): ] = Field(None) -class DynamicTable(DynamicTableMixin): +class DynamicTable(DynamicTableMixin, ConfiguredBaseModel): """ A group containing multiple datasets that are aligned on the first dimension (Currently, this requirement if left up to APIs to check and enforce). These datasets represent different columns in the table. Apart from a column that contains unique identifiers for each row, there are no other required datasets. Users are free to add any number of custom VectorData objects (columns) here. DynamicTable also supports ragged array columns, where each element can be of a different size. To add a ragged array column, use a VectorIndex type to index the corresponding VectorData type. See documentation for VectorData and VectorIndex for more details. Unlike a compound data type, which is analogous to storing an array-of-structs, a DynamicTable can be thought of as a struct-of-arrays. This provides an alternative structure to choose from when optimizing storage for anticipated access patterns. Additionally, this type provides a way of creating a table without having to define a compound type up front. Although this convenience may be attractive, users should think carefully about how data will be accessed. DynamicTable is more appropriate for column-centric access, whereas a dataset with a compound type would be more appropriate for row-centric access. Finally, data size should also be taken into account. For small tables, performance loss may be an acceptable trade-off for the flexibility of a DynamicTable. """ @@ -916,7 +942,7 @@ class DynamicTable(DynamicTableMixin): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, @@ -944,7 +970,7 @@ class AlignedDynamicTable(AlignedDynamicTableMixin, DynamicTable): description="""The names of the columns in this table. This should be used to specify an order to the columns.""", ) description: str = Field(..., description="""Description of what is in this dynamic table.""") - id: VectorData[NDArray[Shape["* num_rows"], int]] = Field( + id: ElementIdentifiers = Field( ..., description="""Array of unique identifiers for the rows of this dynamic table.""", json_schema_extra={"linkml_meta": {"array": {"dimensions": [{"alias": "num_rows"}]}}}, diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/namespace.py index 78035be..b5fab8b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_common/v1_8_0/namespace.py @@ -30,7 +30,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -49,6 +49,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_experimental.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_experimental.py index c5848aa..b168c99 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_experimental.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_experimental.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_resources.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_resources.py index 5d0a97e..f44da2b 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_resources.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/hdmf_experimental_resources.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/namespace.py index 3389dc8..03d52ee 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_1_0/namespace.py @@ -38,7 +38,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -57,6 +57,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_experimental.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_experimental.py index a840dc1..12d022e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_experimental.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_experimental.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_resources.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_resources.py index 8690772..691cfa5 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_resources.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/hdmf_experimental_resources.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/namespace.py index 8b52b45..a15c9b3 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_2_0/namespace.py @@ -39,7 +39,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -58,6 +58,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_experimental.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_experimental.py index 4fdfb37..aa98c17 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_experimental.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_experimental.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_resources.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_resources.py index 1324db1..5aec913 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_resources.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/hdmf_experimental_resources.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/namespace.py index c4b9cd8..747571d 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_3_0/namespace.py @@ -39,7 +39,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -58,6 +58,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_experimental.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_experimental.py index 43eab2a..430676e 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_experimental.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_experimental.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_resources.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_resources.py index 172b75b..0e38714 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_resources.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/hdmf_experimental_resources.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/namespace.py index 14fcb96..50252af 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_4_0/namespace.py @@ -40,7 +40,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -59,6 +59,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_experimental.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_experimental.py index a18965f..6f62e2f 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_experimental.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_experimental.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_resources.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_resources.py index 712c32e..8e802e2 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_resources.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/hdmf_experimental_resources.py @@ -22,7 +22,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -41,6 +41,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/namespace.py b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/namespace.py index b4c0f3a..84b1442 100644 --- a/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/namespace.py +++ b/nwb_models/src/nwb_models/models/pydantic/hdmf_experimental/v0_5_0/namespace.py @@ -40,7 +40,7 @@ class ConfiguredBaseModel(BaseModel): model_config = ConfigDict( validate_assignment=True, validate_default=True, - extra="forbid", + extra="allow", arbitrary_types_allowed=True, use_enum_values=True, strict=False, @@ -59,6 +59,21 @@ class ConfiguredBaseModel(BaseModel): else: raise KeyError("No value or data field to index from") + @field_validator("*", mode="wrap") + @classmethod + def coerce_value(cls, v: Any, handler) -> Any: + """Try to rescue instantiation by using the value field""" + try: + return handler(v) + except Exception as e1: + try: + if hasattr(v, "value"): + return handler(v.value) + else: + return handler(v["value"]) + except Exception as e2: + raise e2 from e1 + class LinkMLMeta(RootModel): root: Dict[str, Any] = {} diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_0/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_0/core.nwb.image.yaml index 6920484..9019ee0 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_0/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_0/core.nwb.image.yaml @@ -22,6 +22,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -32,6 +39,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -42,6 +58,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_1/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_1/core.nwb.image.yaml index 7f406bc..785ebbb 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_1/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_1/core.nwb.image.yaml @@ -22,6 +22,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -32,6 +39,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -42,6 +58,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_2/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_2/core.nwb.image.yaml index 1e11ca4..9b619e3 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_2/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_2/core.nwb.image.yaml @@ -22,6 +22,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -32,6 +39,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -42,6 +58,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_4/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_4/core.nwb.image.yaml index 4beec01..1db1fba 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_4/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_4/core.nwb.image.yaml @@ -22,6 +22,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -32,6 +39,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -42,6 +58,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_5/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_5/core.nwb.image.yaml index 4218d3b..3a7025a 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_2_5/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_2_5/core.nwb.image.yaml @@ -22,6 +22,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -32,6 +39,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -42,6 +58,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_3_0/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_3_0/core.nwb.image.yaml index bbbcfce..7659152 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_3_0/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_3_0/core.nwb.image.yaml @@ -23,6 +23,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -33,6 +40,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -43,6 +59,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_4_0/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_4_0/core.nwb.image.yaml index ac28a30..a72ef59 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_4_0/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_4_0/core.nwb.image.yaml @@ -23,6 +23,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -33,6 +40,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -43,6 +59,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_5_0/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_5_0/core.nwb.image.yaml index 0f6efd9..b6ca2c0 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_5_0/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_5_0/core.nwb.image.yaml @@ -23,6 +23,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -33,6 +40,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -43,6 +59,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_6_0_alpha/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_6_0_alpha/core.nwb.image.yaml index 45bd0a3..cc3d8bb 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_6_0_alpha/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_6_0_alpha/core.nwb.image.yaml @@ -23,6 +23,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -33,6 +40,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -43,6 +59,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries diff --git a/nwb_models/src/nwb_models/schema/linkml/core/v2_7_0/core.nwb.image.yaml b/nwb_models/src/nwb_models/schema/linkml/core/v2_7_0/core.nwb.image.yaml index cac5d73..e465501 100644 --- a/nwb_models/src/nwb_models/schema/linkml/core/v2_7_0/core.nwb.image.yaml +++ b/nwb_models/src/nwb_models/schema/linkml/core/v2_7_0/core.nwb.image.yaml @@ -23,6 +23,13 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + range: numeric tree_root: true RGBImage: name: RGBImage @@ -33,6 +40,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b + exact_cardinality: 3 + range: numeric tree_root: true RGBAImage: name: RGBAImage @@ -43,6 +59,15 @@ classes: name: name range: string required: true + value: + name: value + array: + dimensions: + - alias: x + - alias: y + - alias: r_g_b_a + exact_cardinality: 4 + range: numeric tree_root: true ImageSeries: name: ImageSeries