mirror of
https://github.com/p2p-ld/nwb-linkml.git
synced 2024-11-10 00:34:29 +00:00
coercion for extra columns passed as arrays
This commit is contained in:
parent
cebb21993d
commit
92d28baedd
14 changed files with 463 additions and 66 deletions
|
@ -227,6 +227,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -263,11 +289,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
@ -361,7 +391,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -412,7 +442,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -424,7 +454,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
|
|
@ -136,7 +136,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -187,7 +187,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -199,7 +199,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -405,6 +405,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -441,11 +467,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -136,7 +136,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -187,7 +187,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -199,7 +199,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -405,6 +405,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -441,11 +467,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -136,7 +136,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -187,7 +187,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -199,7 +199,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -405,6 +405,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -441,11 +467,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class VectorIndexMixin(BaseModel):
|
||||||
if self.target is None:
|
if self.target is None:
|
||||||
return self.value[item]
|
return self.value[item]
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self._getitem_helper(item)
|
return self._getitem_helper(item)
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -188,7 +188,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
this being a subclass of ``VectorData``
|
this being a subclass of ``VectorData``
|
||||||
"""
|
"""
|
||||||
if self._index:
|
if self._index:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
# index returns an array of indices,
|
# index returns an array of indices,
|
||||||
# and indexing table with an array returns a list of rows
|
# and indexing table with an array returns a list of rows
|
||||||
return self.table[self._index[item]]
|
return self.table[self._index[item]]
|
||||||
|
@ -200,7 +200,7 @@ class DynamicTableRegionMixin(BaseModel):
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
raise ValueError(f"Dont know how to index with {item}, need an int or a slice")
|
||||||
else:
|
else:
|
||||||
if isinstance(item, int):
|
if isinstance(item, (int, np.integer)):
|
||||||
return self.table[self.value[item]]
|
return self.table[self.value[item]]
|
||||||
elif isinstance(item, (slice, Iterable)):
|
elif isinstance(item, (slice, Iterable)):
|
||||||
if isinstance(item, slice):
|
if isinstance(item, slice):
|
||||||
|
@ -406,6 +406,32 @@ class DynamicTableMixin(BaseModel):
|
||||||
model["colnames"].extend(colnames)
|
model["colnames"].extend(colnames)
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def cast_extra_columns(self):
|
||||||
|
"""
|
||||||
|
If extra columns are passed as just lists or arrays, cast to VectorData
|
||||||
|
before we resolve targets for VectorData and VectorIndex pairs.
|
||||||
|
|
||||||
|
See :meth:`.cast_specified_columns` for handling columns in the class specification
|
||||||
|
"""
|
||||||
|
# if columns are not in the specification, cast to a generic VectorData
|
||||||
|
for key, val in self.__pydantic_extra__.items():
|
||||||
|
if not isinstance(val, (VectorData, VectorIndex)):
|
||||||
|
try:
|
||||||
|
if key.endswith("_index"):
|
||||||
|
self.__pydantic_extra__[key] = VectorIndex(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.__pydantic_extra__[key] = VectorData(
|
||||||
|
name=key, description="", value=val
|
||||||
|
)
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError(
|
||||||
|
f"field {key} cannot be cast to VectorData from {val}"
|
||||||
|
) from e
|
||||||
|
return self
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def resolve_targets(self) -> "DynamicTableMixin":
|
def resolve_targets(self) -> "DynamicTableMixin":
|
||||||
"""
|
"""
|
||||||
|
@ -442,11 +468,15 @@ class DynamicTableMixin(BaseModel):
|
||||||
|
|
||||||
@field_validator("*", mode="wrap")
|
@field_validator("*", mode="wrap")
|
||||||
@classmethod
|
@classmethod
|
||||||
def cast_columns(
|
def cast_specified_columns(
|
||||||
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
cls, val: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
If columns are supplied as arrays, try casting them to the type before validating
|
If columns *in* the model specification are supplied as arrays,
|
||||||
|
try casting them to the type before validating.
|
||||||
|
|
||||||
|
Columns that are not in the spec are handled separately in
|
||||||
|
:meth:`.cast_extra_columns`
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return handler(val)
|
return handler(val)
|
||||||
|
|
|
@ -211,7 +211,7 @@ def test_dynamictable_region_ragged():
|
||||||
name="table",
|
name="table",
|
||||||
description="a table what else would it be",
|
description="a table what else would it be",
|
||||||
id=np.arange(len(spike_idx)),
|
id=np.arange(len(spike_idx)),
|
||||||
timeseries=spike_times,
|
timeseries=spike_times_flat,
|
||||||
timeseries_index=spike_idx,
|
timeseries_index=spike_idx,
|
||||||
)
|
)
|
||||||
region = DynamicTableRegion(
|
region = DynamicTableRegion(
|
||||||
|
@ -242,3 +242,10 @@ def test_dynamictable_append_column():
|
||||||
|
|
||||||
def test_dynamictable_append_row():
|
def test_dynamictable_append_row():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamictable_extra_coercion():
|
||||||
|
"""
|
||||||
|
Extra fields should be coerced to VectorData and have their
|
||||||
|
indexing relationships handled when passed as plain arrays.
|
||||||
|
"""
|
||||||
|
|
Loading…
Reference in a new issue