|
13 | 13 | from pydantic import ( |
14 | 14 | ConfigDict, TypeAdapter, BeforeValidator, AfterValidator, InstanceOf, |
15 | 15 | PlainValidator, PlainSerializer, ValidationError, ValidationInfo, |
16 | | - WithJsonSchema, Field, field_validator, field_serializer, computed_field, model_validator) |
| 16 | + WithJsonSchema, Field, field_validator, computed_field, model_validator) |
17 | 17 | from pydantic.dataclasses import dataclass |
18 | 18 | from pydantic.fields import FieldInfo |
19 | 19 | from pydantic.json_schema import SkipJsonSchema, PydanticJsonSchemaWarning |
@@ -74,12 +74,19 @@ def eval_bytes(obj: Any) -> Any: |
74 | 74 | return obj |
75 | 75 |
|
76 | 76 |
|
77 | | -Slice = Annotated[ |
78 | | - Union[ # these are the same base types (slice) but with different validators |
79 | | - InstanceOf[slice], # accept existing slices as is |
80 | | - # anything convertible to a len-3 tuple, with 'NoneType' conversion, can be a slice |
81 | | - Annotated[slice, ValidateAs(tuple[SafeAny, SafeAny, SafeAny], lambda tup: slice(*tup))]], |
82 | | - BeforeValidator(eval_bytes), |
| 77 | +def preprocess_intslice(obj: Any) -> Any: |
| 78 | + obj = eval_bytes(obj) |
| 79 | + if isinstance(obj, slice): |
| 80 | + obj = (obj.start, obj.stop, obj.step) |
| 81 | + return obj |
| 82 | + |
| 83 | + |
| 84 | +IntSlice = Annotated[ |
| 85 | + slice, |
| 86 | + # anything convertible to a len-3 tuple of int or None, with 'NoneType' conversion, can be interpreted as a slice |
| 87 | + ValidateAs(tuple[SafeOptional[int], SafeOptional[int], SafeOptional[int]], lambda tup: slice(*tup)), |
| 88 | + BeforeValidator(preprocess_intslice), |
| 89 | + # serialize as a tuple |
83 | 90 | PlainSerializer(lambda sl: (sl.start, sl.stop, sl.step)), |
84 | 91 | WithJsonSchema(TypeAdapter(tuple[Any, Any, Any]).json_schema()) |
85 | 92 | ] |
@@ -206,41 +213,6 @@ def validation_wrapper(cls, value: Any, handler, info: ValidationInfo) -> Any: |
206 | 213 |
|
207 | 214 | return value |
208 | 215 |
|
209 | | - |
210 | | - @classmethod |
211 | | - def _ser_numpy_scalar_helper(cls, value: Any, seen: frozenset[int] = frozenset()) -> Any: |
212 | | - """Recursive helper for ser_numpy_number""" |
213 | | - if id(value) in seen: # avoid cycles, keep track of objects in path from here to root |
214 | | - return value |
215 | | - else: |
216 | | - seen = seen.union({id(value)}) |
217 | | - |
218 | | - if isinstance(value, tuple): |
219 | | - return tuple(cls._ser_numpy_scalar_helper(v, seen) for v in value) |
220 | | - |
221 | | - if isinstance(value, list): |
222 | | - return [cls._ser_numpy_scalar_helper(v, seen) for v in value] |
223 | | - |
224 | | - if isinstance(value, slice): |
225 | | - return slice(*(cls._ser_numpy_scalar_helper(v, seen) for v in (value.start, value.stop, value.step))) |
226 | | - |
227 | | - if isinstance(value, Mapping): |
228 | | - return { |
229 | | - cls._ser_numpy_scalar_helper(key, seen): cls._ser_numpy_scalar_helper(val, seen) |
230 | | - for key, val in value.items() |
231 | | - } |
232 | | - |
233 | | - if isinstance(value, np.generic): |
234 | | - return value.item() |
235 | | - |
236 | | - return value |
237 | | - |
238 | | - |
239 | | - @field_serializer('*', mode='wrap') |
240 | | - def ser_numpy_scalar(self, value: Any, handler) -> Any: |
241 | | - """Convert numpy scalars, which pydantic doesn't know how to deal with""" |
242 | | - return handler(self._ser_numpy_scalar_helper(value)) |
243 | | - |
244 | 216 |
|
245 | 217 | def replace(self: GPSelf, warn_unused=True, **changes) -> GPSelf: |
246 | 218 | """Create a GroupParams object with the given fields replaced""" |
@@ -717,7 +689,7 @@ class MotionParams(GroupParams): |
717 | 689 | strides: tuple[int, ...] = (96, 96) # how often to start a new patch in pw-rigid registration |
718 | 690 | upsample_factor_grid: int = 4 # motion field upsampling factor during FFT shifts |
719 | 691 | use_cuda: bool = False # flag for using a GPU |
720 | | - indices: tuple[Slice, ...] = (slice(None), slice(None)) # part of FOV to be corrected |
| 692 | + indices: tuple[IntSlice, ...] = (slice(None), slice(None)) # part of FOV to be corrected |
721 | 693 |
|
722 | 694 |
|
723 | 695 | def _compute_splits_from_data(self) -> Optional[int]: |
|
0 commit comments