mirror of
https://github.com/p2p-ld/numpydantic.git
synced 2024-11-12 17:54:29 +00:00
convert from poetry to pdm, remove linkml parts
This commit is contained in:
parent
1bb34ed2e0
commit
21dd796f09
16 changed files with 348 additions and 4135 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -158,3 +158,4 @@ cython_debug/
|
|||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
.pdm-python
|
|
@ -1,10 +0,0 @@
|
|||
# linkml
|
||||
|
||||
```{toctree}
|
||||
:caption: LinkML
|
||||
|
||||
ndarraygen
|
||||
pydanticgen
|
||||
template
|
||||
```
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
# ndarraygen
|
||||
|
||||
```{eval-rst}
|
||||
.. automodule:: numpydantic.linkml.ndarraygen
|
||||
:members:
|
||||
```
|
|
@ -1,6 +0,0 @@
|
|||
# pydanticgen
|
||||
|
||||
```{eval-rst}
|
||||
.. automodule:: numpydantic.linkml.pydanticgen
|
||||
:members:
|
||||
```
|
|
@ -1,6 +0,0 @@
|
|||
# template
|
||||
|
||||
```{eval-rst}
|
||||
.. automodule:: numpydantic.linkml.template
|
||||
:members:
|
||||
```
|
|
@ -2,21 +2,9 @@
|
|||
|
||||
Type and shape validation and serialization for numpy arrays in pydantic models
|
||||
|
||||
This package was picked out of [nwb-linkml](https://github.com/p2p-ld/nwb-linkml/), a
|
||||
translation of the [NWB](https://www.nwb.org/) schema language and data format to
|
||||
linkML and pydantic models. It's in a hurried and limited form to make it
|
||||
available for a LinkML hackathon, but will be matured as part of `nwb-linkml` development
|
||||
as the primary place this logic exists.
|
||||
|
||||
It does two primary things:
|
||||
- **Provide types** - Annotations (based on [npytyping](https://github.com/ramonhagenaars/nptyping))
|
||||
for specifying numpy arrays in pydantic models, and
|
||||
- **Generate models from LinkML** - extend the LinkML pydantic generator to create models that
|
||||
that use the [linkml-arrays](https://github.com/linkml/linkml-arrays) syntax
|
||||
|
||||
|
||||
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 2
|
||||
:caption: Contents
|
||||
|
@ -24,7 +12,6 @@ It does two primary things:
|
|||
|
||||
overview
|
||||
ndarray
|
||||
linkml
|
||||
hooks
|
||||
todo
|
||||
```
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
# ruff: noqa: E402
|
||||
# ruff: noqa: F401
|
||||
from numpydantic.linkml.ndarraygen import (
|
||||
ArrayFormat,
|
||||
LinkMLDataArray,
|
||||
LinkMLNDArray,
|
||||
NWBLinkMLArraylike,
|
||||
)
|
|
@ -1,189 +0,0 @@
|
|||
"""
|
||||
Isolated generator for array classes
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from linkml_runtime.linkml_model import ClassDefinition, SlotDefinition
|
||||
|
||||
from numpydantic.maps import flat_to_nptyping
|
||||
|
||||
|
||||
class ArrayFormat(ABC):
|
||||
"""
|
||||
Metaclass for different LinkML array source formats
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def is_array(cls, cls_: ClassDefinition) -> bool:
|
||||
"""Check whether a given class matches one of our subclasses definitions"""
|
||||
return any([subcls.check(cls_) for subcls in cls.__subclasses__()])
|
||||
|
||||
@classmethod
|
||||
def get(cls, cls_: ClassDefinition) -> type["ArrayFormat"]:
|
||||
"""Get matching ArrayFormat subclass"""
|
||||
for subcls in cls.__subclasses__():
|
||||
if subcls.check(cls_):
|
||||
return subcls
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def check(cls, cls_: ClassDefinition) -> bool:
|
||||
"""Method for array format subclasses to check if they match a given source class"""
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def make(cls, cls_: ClassDefinition) -> str:
|
||||
"""
|
||||
Make an annotation string from a given array format source class
|
||||
"""
|
||||
|
||||
|
||||
class LinkMLNDArray(ArrayFormat):
|
||||
"""
|
||||
Tentative linkml-arrays style NDArray
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def check(cls, cls_: ClassDefinition) -> bool:
|
||||
"""Check if linkml:NDArray in implements"""
|
||||
return "linkml:NDArray" in cls_.implements
|
||||
|
||||
@classmethod
|
||||
def make(cls, cls_: ClassDefinition) -> str:
|
||||
"""Make NDArray"""
|
||||
raise NotImplementedError("Havent implemented NDArrays yet!")
|
||||
|
||||
|
||||
class LinkMLDataArray(ArrayFormat):
|
||||
"""
|
||||
Tentative linkml-arrays style annotated array with indices
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def check(cls, cls_: ClassDefinition) -> bool:
|
||||
"""Check if linkml:DataArray in implements"""
|
||||
return "linkml:DataArray" in cls_.implements
|
||||
|
||||
@classmethod
|
||||
def make(cls, cls_: ClassDefinition) -> str:
|
||||
"""Make DataArray"""
|
||||
raise NotImplementedError("Havent generated DataArray types yet!")
|
||||
|
||||
|
||||
class NWBLinkMLArraylike(ArrayFormat):
|
||||
"""
|
||||
Ye Olde nwb-linkml Arraylike class
|
||||
|
||||
Examples:
|
||||
|
||||
TimeSeries:
|
||||
is_a: Arraylike
|
||||
attributes:
|
||||
num_times:
|
||||
name: num_times
|
||||
range: AnyType
|
||||
required: true
|
||||
num_DIM2:
|
||||
name: num_DIM2
|
||||
range: AnyType
|
||||
required: false
|
||||
num_DIM3:
|
||||
name: num_DIM3
|
||||
range: AnyType
|
||||
required: false
|
||||
num_DIM4:
|
||||
name: num_DIM4
|
||||
range: AnyType
|
||||
required: false
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def check(cls, cls_: ClassDefinition) -> bool:
|
||||
"""Check if class is Arraylike"""
|
||||
return cls_.is_a == "Arraylike"
|
||||
|
||||
@classmethod
|
||||
def make(cls, cls_: ClassDefinition) -> str:
|
||||
"""Make Arraylike annotation"""
|
||||
return cls._array_annotation(cls_)
|
||||
|
||||
@classmethod
|
||||
def _array_annotation(cls, cls_: ClassDefinition) -> str:
|
||||
"""
|
||||
Make an annotation for an NDArray :)
|
||||
|
||||
Args:
|
||||
cls_:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
# if none of the dimensions are optional, we just have one possible array shape
|
||||
if all([s.required for s in cls_.attributes.values()]): # pragma: no cover
|
||||
return cls._make_npytyping_range(cls_.attributes)
|
||||
# otherwise we need to make permutations
|
||||
# but not all permutations, because we typically just want to be able to exlude the last possible dimensions
|
||||
# the array classes should always be well-defined where the optional dimensions are at the end, so
|
||||
requireds = {k: v for k, v in cls_.attributes.items() if v.required}
|
||||
optionals = [(k, v) for k, v in cls_.attributes.items() if not v.required]
|
||||
|
||||
annotations = []
|
||||
if len(requireds) > 0:
|
||||
# first the base case
|
||||
annotations.append(cls._make_npytyping_range(requireds))
|
||||
# then add back each optional dimension
|
||||
for i in range(len(optionals)):
|
||||
attrs = {**requireds, **{k: v for k, v in optionals[0 : i + 1]}}
|
||||
annotations.append(cls._make_npytyping_range(attrs))
|
||||
|
||||
# now combine with a union:
|
||||
union = "Union[\n" + " " * 8
|
||||
union += (",\n" + " " * 8).join(annotations)
|
||||
union += "\n" + " " * 4 + "]"
|
||||
return union
|
||||
|
||||
@classmethod
|
||||
def _make_npytyping_range(cls, attrs: dict[str, SlotDefinition]) -> str:
|
||||
# slot always starts with...
|
||||
prefix = "NDArray["
|
||||
|
||||
# and then we specify the shape:
|
||||
shape_prefix = 'Shape["'
|
||||
|
||||
# using the cardinality from the attributes
|
||||
dim_pieces = []
|
||||
for attr in attrs.values():
|
||||
shape_part = (
|
||||
str(attr.maximum_cardinality) if attr.maximum_cardinality else "*"
|
||||
)
|
||||
|
||||
# do this with the most heinous chain of string replacements rather than regex
|
||||
# because i am still figuring out what needs to be subbed lol
|
||||
name_part = (
|
||||
attr.name.replace(",", "_")
|
||||
.replace(" ", "_")
|
||||
.replace("__", "_")
|
||||
.replace("|", "_")
|
||||
.replace("-", "_")
|
||||
.replace("+", "plus")
|
||||
)
|
||||
|
||||
dim_pieces.append(" ".join([shape_part, name_part]))
|
||||
|
||||
dimension = ", ".join(dim_pieces)
|
||||
|
||||
shape_suffix = '"], '
|
||||
|
||||
# all dimensions should be the same dtype
|
||||
try:
|
||||
dtype = flat_to_nptyping[list(attrs.values())[0].range]
|
||||
except KeyError as e: # pragma: no cover
|
||||
warnings.warn(str(e), stacklevel=2)
|
||||
range = list(attrs.values())[0].range
|
||||
return f"List[{range}] | {range}"
|
||||
suffix = "]"
|
||||
|
||||
slot = "".join([prefix, shape_prefix, dimension, shape_suffix, dtype, suffix])
|
||||
return slot
|
|
@ -1,652 +0,0 @@
|
|||
"""
|
||||
Patched subclass of :class:`linkml.generators.PydanticGenerator` to generate NDArrays
|
||||
swiped from ``nwb-linkml``.
|
||||
|
||||
Since this is an override of the full generator originally intended for a specific format,
|
||||
this is a bit more involved than the isolated ndarray type generator. The most relevant
|
||||
parts here are:
|
||||
- The :class:`.ArrayCheck` class, which is used to determine when an array needs to be generated -
|
||||
Use this to hook into nonstandard array formats that don't match the usual ``implements`` pattern
|
||||
|
||||
|
||||
"""
|
||||
import sys
|
||||
from copy import copy
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
|
||||
from jinja2 import Template
|
||||
from linkml.generators import PydanticGenerator as BasePydanticGenerator
|
||||
from linkml.generators.common.type_designators import (
|
||||
get_type_designator_value,
|
||||
)
|
||||
from linkml.utils.ifabsent_functions import ifabsent_value_declaration
|
||||
from linkml_runtime.linkml_model.meta import (
|
||||
Annotation,
|
||||
ClassDefinition,
|
||||
ClassDefinitionName,
|
||||
ElementName,
|
||||
SchemaDefinition,
|
||||
SlotDefinition,
|
||||
SlotDefinitionName,
|
||||
)
|
||||
from linkml_runtime.utils.compile_python import file_text
|
||||
from linkml_runtime.utils.formatutils import camelcase, underscore
|
||||
from linkml_runtime.utils.schemaview import SchemaView
|
||||
|
||||
# from nwb_linkml.maps import flat_to_nptyping
|
||||
from pydantic import BaseModel
|
||||
|
||||
from numpydantic.linkml.ndarraygen import ArrayFormat
|
||||
from numpydantic.linkml.template import default_template
|
||||
|
||||
|
||||
def module_case(name: str) -> str:
|
||||
"""
|
||||
Returns name that can be used as a python module, used for
|
||||
referring to generated pydantic and linkml models.
|
||||
|
||||
Replaces with underscores:
|
||||
- -
|
||||
- .
|
||||
"""
|
||||
return name.replace("-", "_").replace(".", "_").replace("/", ".").lower()
|
||||
|
||||
|
||||
def version_module_case(name: str) -> str:
|
||||
"""
|
||||
:func:`.module_case` except ensure that it starts with "v"
|
||||
"""
|
||||
name = module_case(name)
|
||||
if not name.startswith("v"):
|
||||
name = "v" + name
|
||||
return name
|
||||
|
||||
|
||||
class LinkML_Meta(BaseModel):
|
||||
"""Extra LinkML Metadata stored as a class attribute"""
|
||||
|
||||
tree_root: bool = False
|
||||
|
||||
|
||||
def linkml_classvar(cls: ClassDefinition) -> SlotDefinition:
|
||||
"""A class variable that holds additional linkml attrs"""
|
||||
slot = SlotDefinition(name="linkml_meta")
|
||||
slot.annotations["python_range"] = Annotation(
|
||||
"python_range", "ClassVar[LinkML_Meta]"
|
||||
)
|
||||
meta_fields = {k: getattr(cls, k, None) for k in LinkML_Meta.model_fields}
|
||||
meta_field_strings = [f"{k}={v}" for k, v in meta_fields.items() if v is not None]
|
||||
meta_field_string = ", ".join(meta_field_strings)
|
||||
slot.annotations["fixed_field"] = Annotation(
|
||||
"fixed_field", f"Field(LinkML_Meta({meta_field_string}), frozen=True)"
|
||||
)
|
||||
|
||||
return slot
|
||||
|
||||
|
||||
@dataclass
|
||||
class PydanticGenerator(BasePydanticGenerator):
|
||||
SKIP_ENUM: tuple[str] = ("FlatDType",)
|
||||
# SKIP_SLOTS=('VectorData',)
|
||||
SKIP_SLOTS: tuple[str] = ("",)
|
||||
SKIP_CLASSES: tuple[str] = ("",)
|
||||
INJECTED_FIELDS: tuple[str] = (
|
||||
'hdf5_path: Optional[str] = Field(None, description="The absolute path that this object is stored in an NWB file")',
|
||||
'object_id: Optional[str] = Field(None, description="Unique UUID for each object")',
|
||||
)
|
||||
# SKIP_CLASSES=('VectorData','VectorIndex')
|
||||
split: bool = True
|
||||
schema_map: dict[str, SchemaDefinition] | None = None
|
||||
versions: dict = None
|
||||
"""See :meth:`.LinkMLProvider.build` for usage - a list of specific versions to import from"""
|
||||
pydantic_version = "2"
|
||||
|
||||
def _locate_imports(
|
||||
self, needed_classes: list[str], sv: SchemaView
|
||||
) -> dict[str, list[str]]:
|
||||
"""
|
||||
Given a list of class names, find the python modules that need to be imported
|
||||
"""
|
||||
imports = {}
|
||||
|
||||
# These classes are not generated by pydantic!
|
||||
skips = ("AnyType",)
|
||||
|
||||
for cls in needed_classes:
|
||||
if cls in skips: # pragma: no cover
|
||||
continue
|
||||
# Find module that contains class
|
||||
module_name = sv.element_by_schema_map()[ElementName(cls)]
|
||||
# Don't get classes that are defined in this schema!
|
||||
if module_name == self.schema.name:
|
||||
continue
|
||||
schema_name = module_name.split(".")[0]
|
||||
if (
|
||||
self.versions
|
||||
and schema_name != self.schema.name.split(".")[0]
|
||||
and schema_name in self.versions
|
||||
):
|
||||
version = version_module_case(self.versions[schema_name])
|
||||
if self.split:
|
||||
local_mod_name = (
|
||||
"..."
|
||||
+ module_case(schema_name)
|
||||
+ "."
|
||||
+ version
|
||||
+ "."
|
||||
+ module_case(module_name)
|
||||
)
|
||||
else: # pragma: no cover
|
||||
local_mod_name = (
|
||||
"..."
|
||||
+ module_case(schema_name)
|
||||
+ "."
|
||||
+ version
|
||||
+ "."
|
||||
+ "namespace"
|
||||
)
|
||||
|
||||
else:
|
||||
local_mod_name = "." + module_case(module_name)
|
||||
if local_mod_name not in imports:
|
||||
imports[local_mod_name] = [camelcase(cls)]
|
||||
else:
|
||||
imports[local_mod_name].append(camelcase(cls))
|
||||
return imports
|
||||
|
||||
def _get_namespace_imports(self, sv: SchemaView) -> dict[str, list[str]]:
|
||||
"""
|
||||
Get imports for namespace packages. For these we import all
|
||||
the tree_root classes, ie. all the classes that are top-level classes
|
||||
rather than nested classes
|
||||
"""
|
||||
all_classes = sv.all_classes(imports=True)
|
||||
needed_classes = []
|
||||
for clsname, cls in all_classes.items():
|
||||
if cls.is_a != "Arraylike":
|
||||
needed_classes.append(clsname)
|
||||
|
||||
imports = self._locate_imports(needed_classes, sv)
|
||||
return imports
|
||||
|
||||
def _get_class_imports(
|
||||
self,
|
||||
cls: ClassDefinition,
|
||||
sv: SchemaView,
|
||||
all_classes: dict[ClassDefinitionName, ClassDefinition],
|
||||
class_slots: dict[str, list[SlotDefinition]],
|
||||
) -> list[str]:
|
||||
"""Get the imports needed for a single class"""
|
||||
needed_classes = []
|
||||
needed_classes.append(cls.is_a)
|
||||
# get needed classes used as ranges in class attributes
|
||||
for slot in class_slots[cls.name]:
|
||||
if slot.name in self.SKIP_SLOTS: # pragma: no cover
|
||||
continue
|
||||
if slot.range in all_classes:
|
||||
needed_classes.append(slot.range)
|
||||
# handle when a range is a union of classes
|
||||
if slot.any_of:
|
||||
for any_slot_range in slot.any_of:
|
||||
if any_slot_range.range in all_classes:
|
||||
needed_classes.append(any_slot_range.range)
|
||||
|
||||
return needed_classes
|
||||
|
||||
def _get_imports(
|
||||
self,
|
||||
sv: SchemaView,
|
||||
local_classes: list[ClassDefinition],
|
||||
class_slots: dict[str, list[SlotDefinition]],
|
||||
) -> dict[str, list[str]]:
|
||||
# import from local references, rather than serializing every class in every file
|
||||
if not self.split:
|
||||
# we are compiling this whole thing in one big file so we don't import anything
|
||||
return {}
|
||||
if "is_namespace" in sv.schema.annotations and sv.schema.annotations[
|
||||
"is_namespace"
|
||||
]["value"] in ("True", True):
|
||||
return self._get_namespace_imports(sv)
|
||||
|
||||
all_classes = sv.all_classes(imports=True)
|
||||
# local_classes = sv.all_classes(imports=False)
|
||||
needed_classes = []
|
||||
# find needed classes - is_a and slot ranges
|
||||
|
||||
for cls in local_classes:
|
||||
# get imports for this class
|
||||
needed_classes.extend(
|
||||
self._get_class_imports(cls, sv, all_classes, class_slots)
|
||||
)
|
||||
|
||||
# remove duplicates and arraylikes
|
||||
needed_classes = [
|
||||
cls for cls in set(needed_classes) if cls is not None and cls != "Arraylike"
|
||||
]
|
||||
needed_classes = [
|
||||
cls for cls in needed_classes if sv.get_class(cls).is_a != "Arraylike"
|
||||
]
|
||||
|
||||
imports = self._locate_imports(needed_classes, sv)
|
||||
|
||||
return imports
|
||||
|
||||
def _get_classes(self, sv: SchemaView) -> list[ClassDefinition]:
|
||||
if self.split:
|
||||
classes = sv.all_classes(imports=False).values()
|
||||
else:
|
||||
classes = sv.all_classes(imports=True).values()
|
||||
|
||||
# Don't want to generate classes when class_uri is linkml:Any, will
|
||||
# just swap in typing.Any instead down below
|
||||
classes = [
|
||||
c
|
||||
for c in list(classes)
|
||||
if c.is_a != "Arraylike" and c.class_uri != "linkml:Any"
|
||||
]
|
||||
|
||||
return classes
|
||||
|
||||
def _get_class_slots(
|
||||
self, sv: SchemaView, cls: ClassDefinition
|
||||
) -> list[SlotDefinition]:
|
||||
slots = []
|
||||
for slot_name in sv.class_slots(cls.name):
|
||||
if slot_name in self.SKIP_SLOTS:
|
||||
continue
|
||||
slots.append(sv.induced_slot(slot_name, cls.name))
|
||||
return slots
|
||||
|
||||
def _build_class(self, class_original: ClassDefinition) -> ClassDefinition:
|
||||
class_def: ClassDefinition
|
||||
class_def = copy(class_original)
|
||||
class_def.name = camelcase(class_original.name)
|
||||
if class_def.is_a:
|
||||
class_def.is_a = camelcase(class_def.is_a)
|
||||
class_def.mixins = [camelcase(p) for p in class_def.mixins]
|
||||
if class_def.description:
|
||||
class_def.description = class_def.description.replace('"', '\\"')
|
||||
return class_def
|
||||
|
||||
def _check_anyof(
|
||||
self, s: SlotDefinition, sn: SlotDefinitionName, sv: SchemaView
|
||||
) -> None: # pragma: no cover
|
||||
# Confirm that the original slot range (ignoring the default that comes in from
|
||||
# induced_slot) isn't in addition to setting any_of
|
||||
if len(s.any_of) > 0 and sv.get_slot(sn).range is not None:
|
||||
base_range_subsumes_any_of = False
|
||||
base_range = sv.get_slot(sn).range
|
||||
base_range_cls = sv.get_class(base_range, strict=False)
|
||||
if base_range_cls is not None and base_range_cls.class_uri == "linkml:Any":
|
||||
base_range_subsumes_any_of = True
|
||||
if not base_range_subsumes_any_of:
|
||||
raise ValueError("Slot cannot have both range and any_of defined")
|
||||
|
||||
def sort_classes(
|
||||
self, clist: list[ClassDefinition], imports: dict[str, list[str]]
|
||||
) -> list[ClassDefinition]:
|
||||
"""
|
||||
sort classes such that if C is a child of P then C appears after P in the list
|
||||
|
||||
Overridden method include mixin classes
|
||||
|
||||
Modified from original to allow for imported classes
|
||||
"""
|
||||
# unnest imports
|
||||
imported_classes = []
|
||||
for i in imports.values():
|
||||
imported_classes.extend(i)
|
||||
|
||||
clist = list(clist)
|
||||
clist = [c for c in clist if c.name not in self.SKIP_CLASSES]
|
||||
slist = [] # type: list[ClassDefinition]
|
||||
while len(clist) > 0:
|
||||
can_add = False
|
||||
for i in range(len(clist)):
|
||||
candidate = clist[i]
|
||||
can_add = False
|
||||
if candidate.is_a:
|
||||
candidates = [candidate.is_a] + candidate.mixins
|
||||
else:
|
||||
candidates = candidate.mixins
|
||||
if not candidates:
|
||||
can_add = True
|
||||
|
||||
else:
|
||||
if set(candidates) <= set(
|
||||
[p.name for p in slist] + imported_classes
|
||||
):
|
||||
can_add = True
|
||||
|
||||
if can_add:
|
||||
slist = slist + [candidate]
|
||||
del clist[i]
|
||||
break
|
||||
if not can_add: # pragma: no cover
|
||||
raise ValueError(
|
||||
f"could not find suitable element in {clist} that does not ref {slist}"
|
||||
)
|
||||
|
||||
self.sorted_class_names = [camelcase(cname) for cname in imported_classes]
|
||||
self.sorted_class_names += [camelcase(c.name) for c in slist]
|
||||
return slist
|
||||
|
||||
def get_class_slot_range(
|
||||
self, slot_range: str, inlined: bool, inlined_as_list: bool
|
||||
) -> str:
|
||||
"""
|
||||
Monkeypatch to convert Array typed slots and classes into npytyped hints
|
||||
"""
|
||||
sv = self.schemaview
|
||||
range_cls = sv.get_class(slot_range)
|
||||
if ArrayFormat.is_array(range_cls):
|
||||
return ArrayFormat.get(range_cls).make(range_cls)
|
||||
else:
|
||||
return self._get_class_slot_range_origin(
|
||||
slot_range, inlined, inlined_as_list
|
||||
)
|
||||
|
||||
def _get_class_slot_range_origin(
|
||||
self, slot_range: str, inlined: bool, inlined_as_list: bool
|
||||
) -> str:
|
||||
"""
|
||||
Parent class get class range
|
||||
|
||||
Overriding to not use strings in the type hint when a class has an identifier value
|
||||
|
||||
Not testing this method except for what we changed
|
||||
"""
|
||||
sv = self.schemaview
|
||||
range_cls = sv.get_class(slot_range)
|
||||
|
||||
# Hardcoded handling for Any
|
||||
if range_cls.class_uri == "linkml:Any": # pragma: no cover
|
||||
return "Any"
|
||||
|
||||
# Inline the class itself only if the class is defined as inline, or if the class has no
|
||||
# identifier slot and also isn't a mixin.
|
||||
if (
|
||||
inlined
|
||||
or inlined_as_list
|
||||
or (
|
||||
# sv.get_identifier_slot(range_cls.name, use_key=True) is None and
|
||||
not sv.is_mixin(range_cls.name)
|
||||
)
|
||||
):
|
||||
if (
|
||||
len(
|
||||
[x for x in sv.class_induced_slots(slot_range) if x.designates_type]
|
||||
)
|
||||
> 0
|
||||
and len(sv.class_descendants(slot_range)) > 1
|
||||
): # pragma: no cover
|
||||
return (
|
||||
"Union["
|
||||
+ ",".join([camelcase(c) for c in sv.class_descendants(slot_range)])
|
||||
+ "]"
|
||||
)
|
||||
else:
|
||||
return f"{camelcase(slot_range)}"
|
||||
|
||||
# For the more difficult cases, set string as the default and attempt to improve it
|
||||
range_cls_identifier_slot_range = "str" # pragma: no cover
|
||||
|
||||
# For mixins, try to use the identifier slot of descendant classes
|
||||
if (
|
||||
self.gen_mixin_inheritance
|
||||
and sv.is_mixin(range_cls.name)
|
||||
and sv.get_identifier_slot(range_cls.name)
|
||||
): # pragma: no cover
|
||||
range_cls_identifier_slot_range = self.get_mixin_identifier_range(range_cls)
|
||||
|
||||
return range_cls_identifier_slot_range # pragma: no cover
|
||||
|
||||
def get_class_isa_plus_mixins(
|
||||
self, classes: list[ClassDefinition] | None = None
|
||||
) -> dict[str, list[str]]:
|
||||
"""
|
||||
Generate the inheritance list for each class from is_a plus mixins
|
||||
|
||||
Patched to only get local classes
|
||||
|
||||
:return:
|
||||
"""
|
||||
sv = self.schemaview
|
||||
if classes is None: # pragma: no cover
|
||||
classes = sv.all_classes(imports=False).values()
|
||||
|
||||
parents = {}
|
||||
for class_def in classes:
|
||||
class_parents = []
|
||||
if class_def.is_a:
|
||||
class_parents.append(camelcase(class_def.is_a))
|
||||
if self.gen_mixin_inheritance and class_def.mixins: # pragma: no cover
|
||||
class_parents.extend([camelcase(mixin) for mixin in class_def.mixins])
|
||||
if len(class_parents) > 0:
|
||||
# Use the sorted list of classes to order the parent classes, but reversed to match MRO needs
|
||||
class_parents.sort(key=lambda x: self.sorted_class_names.index(x))
|
||||
class_parents.reverse()
|
||||
parents[camelcase(class_def.name)] = class_parents
|
||||
return parents
|
||||
|
||||
def get_predefined_slot_value(
|
||||
self, slot: SlotDefinition, class_def: ClassDefinition
|
||||
) -> str | None:
|
||||
"""
|
||||
Modified from base pydantic generator to use already grabbed induced_slot from
|
||||
already-grabbed and modified classes rather than doing a fresh iteration to
|
||||
save time and respect changes already made elsewhere in the serialization routine
|
||||
|
||||
:return: Dictionary of dictionaries with predefined slot values for each class
|
||||
"""
|
||||
sv = self.schemaview
|
||||
slot_value: str | None = None
|
||||
# for class_def in sv.all_classes().values():
|
||||
# for slot_name in sv.class_slots(class_def.name):
|
||||
# slot = sv.induced_slot(slot_name, class_def.name)
|
||||
if slot.designates_type: # pragma: no cover
|
||||
target_value = get_type_designator_value(sv, slot, class_def)
|
||||
slot_value = f'"{target_value}"'
|
||||
if slot.multivalued:
|
||||
slot_value = "[" + slot_value + "]"
|
||||
elif slot.ifabsent is not None:
|
||||
value = ifabsent_value_declaration(slot.ifabsent, sv, class_def, slot)
|
||||
slot_value = value
|
||||
# Multivalued slots that are either not inlined (just an identifier) or are
|
||||
# inlined as lists should get default_factory list, if they're inlined but
|
||||
# not as a list, that means a dictionary
|
||||
elif slot.multivalued:
|
||||
# this is slow, needs to do additional induced slot calls
|
||||
# has_identifier_slot = self.range_class_has_identifier_slot(slot)
|
||||
|
||||
if slot.inlined and not slot.inlined_as_list: # and has_identifier_slot:
|
||||
slot_value = "default_factory=dict"
|
||||
else: # pragma: no cover
|
||||
slot_value = "default_factory=list"
|
||||
|
||||
return slot_value
|
||||
|
||||
def serialize(self) -> str:
|
||||
"""Generate LinkML models from schema!"""
|
||||
predefined_slot_values = {}
|
||||
"""splitting up parent class :meth:`.get_predefined_slot_values`"""
|
||||
|
||||
if self.template_file is not None: # pragma: no cover
|
||||
with open(self.template_file) as template_file:
|
||||
template_obj = Template(template_file.read())
|
||||
else:
|
||||
template_obj = Template(
|
||||
default_template(self.pydantic_version, extra_classes=[LinkML_Meta])
|
||||
)
|
||||
|
||||
sv: SchemaView
|
||||
sv = self.schemaview
|
||||
if self.schema_map is not None: # pragma: no cover
|
||||
sv.schema_map = self.schema_map
|
||||
schema = sv.schema
|
||||
pyschema = SchemaDefinition(
|
||||
id=schema.id,
|
||||
name=schema.name,
|
||||
description=schema.description.replace('"', '\\"')
|
||||
if schema.description
|
||||
else None,
|
||||
)
|
||||
# test caching if import closure
|
||||
enums = self.generate_enums(sv.all_enums())
|
||||
# filter skipped enums
|
||||
enums = {k: v for k, v in enums.items() if k not in self.SKIP_ENUM}
|
||||
|
||||
classes = self._get_classes(sv)
|
||||
# just induce slots once because that turns out to be expensive
|
||||
class_slots = {} # type: Dict[str, List[SlotDefinition]]
|
||||
for aclass in classes:
|
||||
class_slots[aclass.name] = self._get_class_slots(sv, aclass)
|
||||
|
||||
# figure out what classes we need to imports
|
||||
imports = self._get_imports(sv, classes, class_slots)
|
||||
|
||||
sorted_classes = self.sort_classes(classes, imports)
|
||||
|
||||
for class_original in sorted_classes:
|
||||
# Generate class definition
|
||||
class_def = self._build_class(class_original)
|
||||
|
||||
if class_def.is_a != "Arraylike":
|
||||
# skip actually generating arraylike classes, just use them to generate
|
||||
# the npytyping annotations
|
||||
pyschema.classes[class_def.name] = class_def
|
||||
else: # pragma: no cover
|
||||
continue
|
||||
|
||||
# Not sure why this happens
|
||||
for attribute in list(class_def.attributes.keys()):
|
||||
del class_def.attributes[attribute]
|
||||
|
||||
# make class attr that stores extra linkml attrs
|
||||
class_def.attributes["linkml_meta"] = linkml_classvar(class_def)
|
||||
|
||||
class_name = class_original.name
|
||||
predefined_slot_values[camelcase(class_name)] = {}
|
||||
for s in class_slots[class_name]:
|
||||
sn = SlotDefinitionName(s.name)
|
||||
predefined_slot_value = self.get_predefined_slot_value(s, class_def)
|
||||
if predefined_slot_value is not None:
|
||||
predefined_slot_values[camelcase(class_name)][
|
||||
s.name
|
||||
] = predefined_slot_value
|
||||
# logging.error(f'Induced slot {class_name}.{sn} == {s.name} {s.range}')
|
||||
s.name = underscore(s.name)
|
||||
if s.description:
|
||||
s.description = s.description.replace('"', '\\"')
|
||||
class_def.attributes[s.name] = s
|
||||
|
||||
slot_ranges: list[str] = []
|
||||
|
||||
self._check_anyof(s, sn, sv)
|
||||
|
||||
if s.any_of is not None and len(s.any_of) > 0:
|
||||
# list comprehension here is pulling ranges from within AnonymousSlotExpression
|
||||
slot_ranges.extend([r.range for r in s.any_of])
|
||||
else:
|
||||
slot_ranges.append(s.range)
|
||||
|
||||
pyranges = [
|
||||
self.generate_python_range(slot_range, s, class_def)
|
||||
for slot_range in slot_ranges
|
||||
]
|
||||
# --------------------------------------------------
|
||||
# Special Case - since we get abstract classes from
|
||||
# potentially multiple versions (which are then different)
|
||||
# model classes, we allow container classes to also
|
||||
# be generic descendants of BaseModel
|
||||
# --------------------------------------------------
|
||||
if "DynamicTable" in pyranges: # pragma: no cover
|
||||
pyranges.append("BaseModel")
|
||||
|
||||
pyranges = list(set(pyranges)) # remove duplicates
|
||||
pyranges.sort()
|
||||
|
||||
if len(pyranges) == 1:
|
||||
pyrange = pyranges[0]
|
||||
elif len(pyranges) > 1:
|
||||
pyrange = f"Union[{', '.join(pyranges)}]"
|
||||
else: # pragma: no cover
|
||||
raise Exception(
|
||||
f"Could not generate python range for {class_name}.{s.name}"
|
||||
)
|
||||
|
||||
if s.multivalued:
|
||||
if s.inlined or s.inlined_as_list:
|
||||
collection_key = self.generate_collection_key(
|
||||
slot_ranges, s, class_def
|
||||
)
|
||||
else: # pragma: no cover
|
||||
collection_key = None
|
||||
if (
|
||||
s.inlined is False
|
||||
or collection_key is None
|
||||
or s.inlined_as_list is True
|
||||
): # pragma: no cover
|
||||
pyrange = f"List[{pyrange}] | {pyrange}"
|
||||
else:
|
||||
pyrange = f"Dict[{collection_key}, {pyrange}]"
|
||||
if not s.required and not s.designates_type:
|
||||
pyrange = f"Optional[{pyrange}]"
|
||||
ann = Annotation("python_range", pyrange)
|
||||
s.annotations[ann.tag] = ann
|
||||
|
||||
code = template_obj.render(
|
||||
imports=imports,
|
||||
schema=pyschema,
|
||||
underscore=underscore,
|
||||
enums=enums,
|
||||
predefined_slot_values=predefined_slot_values,
|
||||
allow_extra=self.allow_extra,
|
||||
metamodel_version=self.schema.metamodel_version,
|
||||
version=self.schema.version,
|
||||
class_isa_plus_mixins=self.get_class_isa_plus_mixins(sorted_classes),
|
||||
injected_fields=self.INJECTED_FIELDS,
|
||||
)
|
||||
return code
|
||||
|
||||
def compile_module(
|
||||
self, module_path: Path = None, module_name: str = "test"
|
||||
) -> ModuleType: # pragma: no cover - replaced with provider
|
||||
"""
|
||||
Compiles generated python code to a module
|
||||
:return:
|
||||
"""
|
||||
pycode = self.serialize()
|
||||
if module_path is not None:
|
||||
module_path = Path(module_path)
|
||||
init_file = module_path / "__init__.py"
|
||||
with open(init_file, "w") as ifile:
|
||||
ifile.write(" ")
|
||||
|
||||
try:
|
||||
return compile_python(pycode, module_path, module_name)
|
||||
except NameError as e:
|
||||
raise e
|
||||
|
||||
|
||||
def compile_python(
|
||||
text_or_fn: str, package_path: Path = None, module_name: str = "test"
|
||||
) -> ModuleType:
|
||||
"""
|
||||
Compile the text or file and return the resulting module
|
||||
@param text_or_fn: Python text or file name that references python file
|
||||
@param package_path: Root package path. If omitted and we've got a python file, the package is the containing
|
||||
directory
|
||||
@return: Compiled module
|
||||
"""
|
||||
python_txt = file_text(text_or_fn)
|
||||
if package_path is None and python_txt != text_or_fn:
|
||||
package_path = Path(text_or_fn)
|
||||
spec = compile(python_txt, "<string>", "exec")
|
||||
module = ModuleType(module_name)
|
||||
|
||||
exec(spec, module.__dict__)
|
||||
sys.modules[module_name] = module
|
||||
return module
|
|
@ -1,183 +0,0 @@
|
|||
import inspect
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
def default_template(
|
||||
pydantic_ver: str = "2", extra_classes: list[type[BaseModel]] | None = None
|
||||
) -> str:
|
||||
"""Constructs a default template for pydantic classes based on the version of pydantic"""
|
||||
### HEADER ###
|
||||
template = """
|
||||
{#-
|
||||
|
||||
Jinja2 Template for a pydantic classes
|
||||
-#}
|
||||
from __future__ import annotations
|
||||
from datetime import datetime, date
|
||||
from enum import Enum
|
||||
from typing import Dict, Optional, Any, Union, ClassVar, Annotated, TypeVar, List, TYPE_CHECKING
|
||||
from pydantic import BaseModel as BaseModel, Field"""
|
||||
if pydantic_ver == "2":
|
||||
template += """
|
||||
from pydantic import ConfigDict, BeforeValidator
|
||||
"""
|
||||
template += """
|
||||
from nptyping import Shape, Float, Float32, Double, Float64, LongLong, Int64, Int, Int32, Int16, Short, Int8, UInt, UInt32, UInt16, UInt8, UInt64, Number, String, Unicode, Unicode, Unicode, String, Bool, Datetime64
|
||||
from nwb_linkml.types import NDArray
|
||||
import sys
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
else:
|
||||
from typing_extensions import Literal
|
||||
if TYPE_CHECKING:
|
||||
import numpy as np
|
||||
|
||||
{% for import_module, import_classes in imports.items() %}
|
||||
from {{ import_module }} import (
|
||||
{{ import_classes | join(',\n ') }}
|
||||
)
|
||||
{% endfor %}
|
||||
|
||||
metamodel_version = "{{metamodel_version}}"
|
||||
version = "{{version if version else None}}"
|
||||
"""
|
||||
### BASE MODEL ###
|
||||
if pydantic_ver == "1": # pragma: no cover
|
||||
template += """
|
||||
List = BaseList
|
||||
|
||||
class WeakRefShimBaseModel(BaseModel):
|
||||
__slots__ = '__weakref__'
|
||||
|
||||
class ConfiguredBaseModel(WeakRefShimBaseModel,
|
||||
validate_assignment = False,
|
||||
validate_all = True,
|
||||
underscore_attrs_are_private = True,
|
||||
extra = {% if allow_extra %}'allow'{% else %}'forbid'{% endif %},
|
||||
arbitrary_types_allowed = True,
|
||||
use_enum_values = True):
|
||||
"""
|
||||
else:
|
||||
template += """
|
||||
class ConfiguredBaseModel(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
validate_assignment = True,
|
||||
validate_default = True,
|
||||
extra = {% if allow_extra %}'allow'{% else %}'forbid'{% endif %},
|
||||
arbitrary_types_allowed = True,
|
||||
use_enum_values = True
|
||||
)
|
||||
"""
|
||||
### Injected Fields
|
||||
template += """
|
||||
{%- if injected_fields != None -%}
|
||||
{% for field in injected_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
{%- else -%}
|
||||
pass
|
||||
{%- endif -%}
|
||||
"""
|
||||
### Getitem
|
||||
template += """
|
||||
|
||||
def __getitem__(self, i: slice|int) -> 'np.ndarray':
|
||||
if hasattr(self, 'array'):
|
||||
return self.array[i]
|
||||
else:
|
||||
return super().__getitem__(i)
|
||||
|
||||
def __setitem__(self, i: slice|int, value: Any):
|
||||
if hasattr(self, 'array'):
|
||||
self.array[i] = value
|
||||
else:
|
||||
super().__setitem__(i, value)
|
||||
"""
|
||||
|
||||
### Extra classes
|
||||
if extra_classes is not None:
|
||||
template += """{{ '\n\n' }}"""
|
||||
for cls in extra_classes:
|
||||
template += inspect.getsource(cls) + "\n\n"
|
||||
### ENUMS ###
|
||||
template += """
|
||||
{% for e in enums.values() %}
|
||||
class {{ e.name }}(str, Enum):
|
||||
{% if e.description -%}
|
||||
\"\"\"
|
||||
{{ e.description }}
|
||||
\"\"\"
|
||||
{%- endif %}
|
||||
{% for _, pv in e['values'].items() -%}
|
||||
{% if pv.description -%}
|
||||
# {{pv.description}}
|
||||
{%- endif %}
|
||||
{{pv.label}} = "{{pv.value}}"
|
||||
{% endfor %}
|
||||
{% if not e['values'] -%}
|
||||
dummy = "dummy"
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
"""
|
||||
### CLASSES ###
|
||||
template += """
|
||||
{%- for c in schema.classes.values() %}
|
||||
class {{ c.name }}
|
||||
{%- if class_isa_plus_mixins[c.name] -%}
|
||||
({{class_isa_plus_mixins[c.name]|join(', ')}})
|
||||
{%- else -%}
|
||||
(ConfiguredBaseModel)
|
||||
{%- endif -%}
|
||||
:
|
||||
{% if c.description -%}
|
||||
\"\"\"
|
||||
{{ c.description }}
|
||||
\"\"\"
|
||||
{%- endif %}
|
||||
{% for attr in c.attributes.values() if c.attributes -%}
|
||||
{{attr.name}}:{{ ' ' }}{%- if attr.equals_string -%}
|
||||
Literal[{{ predefined_slot_values[c.name][attr.name] }}]
|
||||
{%- else -%}
|
||||
{{ attr.annotations['python_range'].value }}
|
||||
{%- endif -%}
|
||||
{%- if attr.annotations['fixed_field'] -%}
|
||||
{{ ' ' }}= {{ attr.annotations['fixed_field'].value }}
|
||||
{%- else -%}
|
||||
{{ ' ' }}= Field(
|
||||
{%- if predefined_slot_values[c.name][attr.name] is string -%}
|
||||
{{ predefined_slot_values[c.name][attr.name] }}
|
||||
{%- elif attr.required -%}
|
||||
...
|
||||
{%- else -%}
|
||||
None
|
||||
{%- endif -%}
|
||||
{%- if attr.title != None %}, title="{{attr.title}}"{% endif -%}
|
||||
{%- if attr.description %}, description=\"\"\"{{attr.description}}\"\"\"{% endif -%}
|
||||
{%- if attr.minimum_value != None %}, ge={{attr.minimum_value}}{% endif -%}
|
||||
{%- if attr.maximum_value != None %}, le={{attr.maximum_value}}{% endif -%}
|
||||
)
|
||||
{%- endif %}
|
||||
{% else -%}
|
||||
None
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
"""
|
||||
### FWD REFS / REBUILD MODEL ###
|
||||
if pydantic_ver == "1": # pragma: no cover
|
||||
template += """
|
||||
# Update forward refs
|
||||
# see https://pydantic-docs.helpmanual.io/usage/postponed_annotations/
|
||||
{% for c in schema.classes.values() -%}
|
||||
{{ c.name }}.update_forward_refs()
|
||||
{% endfor %}
|
||||
"""
|
||||
else:
|
||||
template += """
|
||||
# Model rebuild
|
||||
# see https://pydantic-docs.helpmanual.io/usage/models/#rebuilding-a-model
|
||||
{% for c in schema.classes.values() -%}
|
||||
{{ c.name }}.model_rebuild()
|
||||
{% endfor %}
|
||||
"""
|
||||
return template
|
304
pdm.lock
Normal file
304
pdm.lock
Normal file
|
@ -0,0 +1,304 @@
|
|||
# This file is @generated by PDM.
|
||||
# It is not intended for manual editing.
|
||||
|
||||
[metadata]
|
||||
groups = ["default"]
|
||||
strategy = ["cross_platform", "inherit_metadata"]
|
||||
lock_version = "4.4.1"
|
||||
content_hash = "sha256:761d4dccd4e594b9e441dddefdb5677d22a4a94c129183e0bb8c88d9acbea1b9"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.6.0"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Reusable constraint types to use with typing.Annotated"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"},
|
||||
{file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blosc2"
|
||||
version = "2.5.1"
|
||||
requires_python = "<4,>=3.8"
|
||||
summary = "Python wrapper for the C-Blosc2 library"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"msgpack",
|
||||
"ndindex>=1.4",
|
||||
"numpy>=1.20.3",
|
||||
"py-cpuinfo",
|
||||
]
|
||||
files = [
|
||||
{file = "blosc2-2.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c861262b7fe317c1614a9b59b6c9edf409532b4a6aaf5b2f4ad0d79c6f800b57"},
|
||||
{file = "blosc2-2.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f35b5d69a7a41e9d5054297d2540c25f8af5ea3c62e4a80ca7359292d783c04"},
|
||||
{file = "blosc2-2.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:546fa39f397dd54b13d7c42a4f890afaf16c70fe478712070942d464c440ce03"},
|
||||
{file = "blosc2-2.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5455af77e7e94159bb4966cae554f232ca2d52bb80cd3f878ecef39cf569da2a"},
|
||||
{file = "blosc2-2.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b4dc4f595bf95c350c50bb77a8749cdd08a5dc2bdf3bdb18983d49a52d60b595"},
|
||||
{file = "blosc2-2.5.1-cp310-cp310-win32.whl", hash = "sha256:873483bd5c6afb8d139039180ee57b74373232e87b032cb80389fd8bb883ea8e"},
|
||||
{file = "blosc2-2.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:d5a7ef00b82fbca069e949335f9c92ce7cbe2039a9fa2e2bd4f5f418043d6262"},
|
||||
{file = "blosc2-2.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:da826d42d616f8a939f27e1501b40e764fded66bc80177eeaefcebdbf3b3afb8"},
|
||||
{file = "blosc2-2.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ae2e0c5dc8561a6b17842ee4320b49621434c20e622c9e9f5c67c9c6eb3b06a3"},
|
||||
{file = "blosc2-2.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af3cab9c12a4364c643266ee7d9583b526c0f484a291d72ec6efb09ea7ffbbf9"},
|
||||
{file = "blosc2-2.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f03a723130cf07e4309fe34b1360c868f4376e862f8ff664eb40d019fdd3f6"},
|
||||
{file = "blosc2-2.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0fd109eef815ea1e50fde4f676388aa2f3bb5543502d125fb63f16ec7a014464"},
|
||||
{file = "blosc2-2.5.1-cp311-cp311-win32.whl", hash = "sha256:1a3edc3256bad04d3db30c9de7eac3a820f96e741fc754cdabb6a9991e5c37e8"},
|
||||
{file = "blosc2-2.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:e7499e277c13334d54f84e74f429f32341f99f7b978deaf9a7c2e963904cb48c"},
|
||||
{file = "blosc2-2.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ab849d3adaeb035f2f16cf495cff1792b28d58dfb3de21b9459ee355c6bb8df3"},
|
||||
{file = "blosc2-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dd66e60dafcc93d4c1f815d726d76f9fb067ecc9106a6c661010e709135c79ce"},
|
||||
{file = "blosc2-2.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb5fcd1775b3884d9825aa51fb45253f45cfa21c77f4135fad5dc5db710c2a34"},
|
||||
{file = "blosc2-2.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19f79071a336fcf1eda01cd0171291a4ab82b16cf9a15d2b4d26c010146f13b5"},
|
||||
{file = "blosc2-2.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:956a63231f1b448803e9b4bc3e704ea424c89fc14418d99093472c74f19c19e1"},
|
||||
{file = "blosc2-2.5.1-cp312-cp312-win32.whl", hash = "sha256:5856e57e0e81f9018f1a12e803b9f768fa5533175092d72d165ac60069c7d2ab"},
|
||||
{file = "blosc2-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:585d780c5e85f251dec72b75a47666e4a261dbfe1d228769bca545e9fe07f480"},
|
||||
{file = "blosc2-2.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0cb9a6ac1abc466c12bdc90052f17545512de8f854e672a1ea4d2b40292323f5"},
|
||||
{file = "blosc2-2.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3def4650faa1db43143d821228ef58797108cc95d6698c4b1581909cc2b149ca"},
|
||||
{file = "blosc2-2.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf6efecc1a22da26c73ff5c60d0dc086db1e7edcceb6b360dd193cda893bef28"},
|
||||
{file = "blosc2-2.5.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b473472b977b770aab3bf20d0feeee84ecd5bb8b15a675287e090ce818c1cd40"},
|
||||
{file = "blosc2-2.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7afe59d35d93bf8da7db8de43f4d8aef277514de43953c1e5e416ca839b9023a"},
|
||||
{file = "blosc2-2.5.1-cp39-cp39-win32.whl", hash = "sha256:4315ae8d467fe91efa0dbe22004e967008f5fe021ebb3945518f5213d7c4511f"},
|
||||
{file = "blosc2-2.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:73eb5e569a91fbe67f7dd78efe6a1ca9a54afff2c847db5dfa675bfd6a424f60"},
|
||||
{file = "blosc2-2.5.1.tar.gz", hash = "sha256:47d5df50e7286edf81e629ece35f87f13f55c13c5e8545832188c420c75d1659"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "msgpack"
|
||||
version = "1.0.8"
|
||||
requires_python = ">=3.8"
|
||||
summary = "MessagePack serializer"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-win32.whl", hash = "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693"},
|
||||
{file = "msgpack-1.0.8-cp310-cp310-win_amd64.whl", hash = "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-win32.whl", hash = "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305"},
|
||||
{file = "msgpack-1.0.8-cp311-cp311-win_amd64.whl", hash = "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-win32.whl", hash = "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c"},
|
||||
{file = "msgpack-1.0.8-cp312-cp312-win_amd64.whl", hash = "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"},
|
||||
{file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"},
|
||||
{file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndindex"
|
||||
version = "1.8"
|
||||
requires_python = ">=3.8"
|
||||
summary = "A Python library for manipulating indices of ndarrays."
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "ndindex-1.8-py3-none-any.whl", hash = "sha256:b5132cd331f3e4106913ed1a974a3e355967a5991543c2f512b40cb8bb9f50b8"},
|
||||
{file = "ndindex-1.8.tar.gz", hash = "sha256:5fc87ebc784605f01dd5367374cb40e8da8f2c30988968990066c5098a7eebe8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nptyping"
|
||||
version = "2.5.0"
|
||||
requires_python = ">=3.7"
|
||||
summary = "Type hints for NumPy."
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"numpy<2.0.0,>=1.20.0; python_version >= \"3.8\"",
|
||||
"typing-extensions<5.0.0,>=4.0.0; python_version < \"3.10\"",
|
||||
]
|
||||
files = [
|
||||
{file = "nptyping-2.5.0-py3-none-any.whl", hash = "sha256:764e51836faae33a7ae2e928af574cfb701355647accadcc89f2ad793630b7c8"},
|
||||
{file = "nptyping-2.5.0.tar.gz", hash = "sha256:e3d35b53af967e6fb407c3016ff9abae954d3a0568f7cc13a461084224e8e20a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "1.26.4"
|
||||
requires_python = ">=3.9"
|
||||
summary = "Fundamental package for array computing in Python"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"},
|
||||
{file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"},
|
||||
{file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"},
|
||||
{file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"},
|
||||
{file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"},
|
||||
{file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"},
|
||||
{file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"},
|
||||
{file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"},
|
||||
{file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"},
|
||||
{file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"},
|
||||
{file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"},
|
||||
{file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"},
|
||||
{file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"},
|
||||
{file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"},
|
||||
{file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "py-cpuinfo"
|
||||
version = "9.0.0"
|
||||
summary = "Get CPU info with pure Python"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"},
|
||||
{file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.6.4"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Data validation using Python type hints"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"annotated-types>=0.4.0",
|
||||
"pydantic-core==2.16.3",
|
||||
"typing-extensions>=4.6.1",
|
||||
]
|
||||
files = [
|
||||
{file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"},
|
||||
{file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.16.3"
|
||||
requires_python = ">=3.8"
|
||||
summary = ""
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"typing-extensions!=4.7.0,>=4.6.0",
|
||||
]
|
||||
files = [
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"},
|
||||
{file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"},
|
||||
{file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"},
|
||||
{file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"},
|
||||
{file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"},
|
||||
{file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"},
|
||||
{file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"},
|
||||
{file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"},
|
||||
{file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"},
|
||||
{file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"},
|
||||
{file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"},
|
||||
{file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"},
|
||||
{file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"},
|
||||
{file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"},
|
||||
{file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"},
|
||||
{file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"},
|
||||
{file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"},
|
||||
{file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.10.0"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"},
|
||||
{file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
|
||||
]
|
3002
poetry.lock
generated
3002
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,62 +1,59 @@
|
|||
[tool.poetry]
|
||||
[project]
|
||||
name = "numpydantic"
|
||||
version = "0.0.0"
|
||||
description = "Type and shape validation and serialization for numpy arrays in pydantic models"
|
||||
authors = ["sneakers-the-rat <sneakers-the-rat@protonmail.com>"]
|
||||
license = "MIT"
|
||||
authors = [
|
||||
{name = "sneakers-the-rat", email = "sneakers-the-rat@protonmail.com"},
|
||||
]
|
||||
dependencies = [
|
||||
"pydantic>=2.3.0",
|
||||
"nptyping>=2.5.0",
|
||||
"blosc2<3.0.0,>=2.5.1",
|
||||
]
|
||||
requires-python = "<4.0,>=3.9"
|
||||
readme = "README.md"
|
||||
license = {text = "MIT"}
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.11"
|
||||
pydantic = ">=2.3.0"
|
||||
nptyping = ">=2.5.0"
|
||||
blosc2 = "^2.5.1"
|
||||
dask = { version=">=2024.1.1", extras=["array"]}
|
||||
h5py = ">=3.10.0"
|
||||
pytest = { version=">=7.4.0", optional = true}
|
||||
pytest-depends = {version="^1.0.1", optional = true}
|
||||
coverage = {version = ">=6.1.1", optional = true}
|
||||
pytest-cov = {version = "^4.1.0", optional = true}
|
||||
coveralls = {version = "^3.3.1", optional = true}
|
||||
sphinx = {version = "^7.2.6", optional = true}
|
||||
furo = {version = ">=2024.1.29", optional = true}
|
||||
myst-parser = {version = "^2.0.0", optional = true}
|
||||
autodoc-pydantic = {version = "^2.0.1", optional = true}
|
||||
sphinx-autobuild = {version = ">=2021.3.14", optional = true}
|
||||
sphinx-design = {version = "^0.5.0", optional = true}
|
||||
black = {version = "^24.1.1", optional = true}
|
||||
ruff = {version = "^0.2.0", optional = true}
|
||||
linkml = {version = ">=1.7.0", optional = true}
|
||||
linkml-runtime = {version = ">=1.7.0", optional = true}
|
||||
|
||||
[tool.poetry.extras]
|
||||
#proxy = [
|
||||
# "dask", "h5py"
|
||||
#]
|
||||
linkml = [
|
||||
"linkml", "linkml-runtime"
|
||||
[project.optional-dependencies]
|
||||
dask = [
|
||||
"dask[array]>=2024.1.1"
|
||||
]
|
||||
hdf5 = [
|
||||
"h5py>=3.10.0"
|
||||
]
|
||||
arrays = [
|
||||
"numpydantic[dask,hdf5]"
|
||||
]
|
||||
tests = [
|
||||
"pytest", "pytest-depends", "coverage", "pytest-cov", "coveralls"
|
||||
"numpydantic[arrays]",
|
||||
"pytest>=7.4.0",
|
||||
"pytest-depends<2.0.0,>=1.0.1",
|
||||
"coverage>=6.1.1",
|
||||
"pytest-cov<5.0.0,>=4.1.0",
|
||||
"coveralls<4.0.0,>=3.3.1"
|
||||
]
|
||||
docs = [
|
||||
"sphinx", "furo", "myst-parser", "autodoc-pydantic", "sphinx-design"
|
||||
]
|
||||
"sphinx<8.0.0,>=7.2.6",
|
||||
"furo>=2024.1.29",
|
||||
"myst-parser<3.0.0,>=2.0.0",
|
||||
"autodoc-pydantic<3.0.0,>=2.0.1",
|
||||
"sphinx-design<1.0.0,>=0.5.0"]
|
||||
dev = [
|
||||
"sphinx-autobuild", "black", "ruff",
|
||||
# proxy
|
||||
# "dask", "h5py",
|
||||
# linkml
|
||||
"linkml", "linkml-runtime",
|
||||
# tests
|
||||
"pytest", "pytest-depends", "coverage", "pytest-cov", "coveralls",
|
||||
# docs
|
||||
"sphinx", "furo", "myst-parser", "autodoc-pydantic", "sphinx-design"
|
||||
"numpydantic[tests,docs]",
|
||||
"sphinx-autobuild>=2021.3.14",
|
||||
"black<25.0.0,>=24.1.1",
|
||||
"ruff<1.0.0,>=0.2.0"
|
||||
]
|
||||
|
||||
[tool.pdm]
|
||||
distribution = true
|
||||
|
||||
[tool.pdm.build]
|
||||
includes = []
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = [
|
||||
|
@ -109,4 +106,4 @@ fixable = ["ALL"]
|
|||
[tool.mypy]
|
||||
plugins = [
|
||||
"pydantic.mypy"
|
||||
]
|
||||
]
|
0
src/numpydantic/__init__.py
Normal file
0
src/numpydantic/__init__.py
Normal file
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
|
@ -1,14 +0,0 @@
|
|||
import pytest
|
||||
|
||||
from numpydantic.linkml import ArrayFormat, NWBLinkMLArraylike
|
||||
|
||||
from ..fixtures import nwb_linkml_array
|
||||
|
||||
|
||||
def test_nwb_linkml_array(nwb_linkml_array):
|
||||
classdef, generated = nwb_linkml_array
|
||||
|
||||
assert ArrayFormat.is_array(classdef)
|
||||
assert NWBLinkMLArraylike.check(classdef)
|
||||
assert ArrayFormat.get(classdef) is NWBLinkMLArraylike
|
||||
assert generated == NWBLinkMLArraylike.make(classdef)
|
Loading…
Reference in a new issue