diff --git a/pyenzyme/versions/v2.py b/pyenzyme/versions/v2.py index 47340741..8eb73a1d 100644 --- a/pyenzyme/versions/v2.py +++ b/pyenzyme/versions/v2.py @@ -33,17 +33,17 @@ ## This is a generated file. Do not modify it manually! from __future__ import annotations -from pydantic import BaseModel, Field, ConfigDict -from typing import Optional, Generic, TypeVar +from pydantic import BaseModel, Field, ConfigDict, field_validator +from typing import Optional, Generic, TypeVar, Union from enum import Enum from uuid import uuid4 +from datetime import date, datetime from mdmodels.units.annotation import UnitDefinitionAnnot # Filter Wrapper definition used to filter a list of objects # based on their attributes Cls = TypeVar("Cls") - class FilterWrapper(Generic[Cls]): """Wrapper class to filter a list of objects based on their attributes""" @@ -66,6 +66,11 @@ def _fetch_attr(self, name: str, item: Cls): # JSON-LD Helper Functions + +# JSON-LD 1.1 only uses a plain string term as a prefix if its IRI ends in one of these +GEN_DELIMS = (":", "/", "?", "#", "[", "]", "@") + + def add_namespace(obj, prefix: str | None, iri: str | None): """Adds a namespace to the JSON-LD context @@ -80,8 +85,10 @@ def add_namespace(obj, prefix: str | None, iri: str | None): elif iri and prefix is None: raise ValueError("If iri is provided, prefix must also be provided") - obj.ld_context[prefix] = iri # type: ignore - + if iri.endswith(GEN_DELIMS): # type: ignore + obj.ld_context[prefix] = iri # type: ignore + else: + obj.ld_context[prefix] = {"@id": iri, "@prefix": True} # type: ignore def validate_prefix(term: str | dict, prefix: str): """Validates that a term is prefixed with a given prefix @@ -100,21 +107,44 @@ def validate_prefix(term: str | dict, prefix: str): raise ValueError(f"Term {term} is not prefixed with {prefix}") -# Model Definitions +def merge_ld_type(defaults: list[str], value: str | list | None) -> list[str]: + """Keeps the generated types and appends extra types read from a document; + a bare string (compacted JSON-LD) is treated as a single type""" + if value is None: + return defaults + if isinstance(value, str): + value = [value] + return defaults + [t for t in value if t not in defaults] + +def merge_ld_context(defaults: dict, value: dict | list | str | None) -> dict: + """Keeps extra prefixes and terms read from a document; generated mappings win, + so documents written with an older context get the current term definitions. + Lists are merged element-wise; remote context URLs are ignored""" + if isinstance(value, dict): + value = [value] + elif not isinstance(value, list): + return defaults + extras = {k: v for d in value if isinstance(d, dict) for k, v in d.items()} + return {**defaults, **{k: v for k, v in extras.items() if k not in defaults}} + +# Model Definitions class EnzymeMLDocument(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore name: str = Field( default=..., description="""Title of the EnzymeML Document.""", ) version: str = Field( - default="2", + default= "2.1", description="""The version of the EnzymeML Document.""", + pattern="^\\d+(\\.\\d+)?$", ) description: Optional[str] = Field( default=None, @@ -188,32 +218,99 @@ class EnzymeMLDocument(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:EnzymeMLDocument/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:EnzymeMLDocument/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:EnzymeMLDocument", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "Creator": "http://www.enzymeml.org/v2/Creator/", + "Vessel": "http://www.enzymeml.org/v2/Vessel/", + "Protein": "http://www.enzymeml.org/v2/Protein/", + "Complex": "http://www.enzymeml.org/v2/Complex/", + "SmallMolecule": "http://www.enzymeml.org/v2/SmallMolecule/", + "Reaction": "http://www.enzymeml.org/v2/Reaction/", + "Measurement": "http://www.enzymeml.org/v2/Measurement/", + "Equation": "http://www.enzymeml.org/v2/Equation/", + "Parameter": "http://www.enzymeml.org/v2/Parameter/", "name": "schema:title", + "version": "enzml:EnzymeMLDocument/version", + "description": "enzml:EnzymeMLDocument/description", "created": "schema:dateCreated", "modified": "schema:dateModified", - "creators": "schema:creator", + "creators": { + "@id": "schema:creator", + "@container": "@list", + }, + "vessels": { + "@id": "enzml:EnzymeMLDocument/vessels", + "@container": "@list", + }, + "proteins": { + "@id": "enzml:EnzymeMLDocument/proteins", + "@container": "@list", + }, + "complexes": { + "@id": "enzml:EnzymeMLDocument/complexes", + "@container": "@list", + }, + "small_molecules": { + "@id": "enzml:EnzymeMLDocument/small_molecules", + "@container": "@list", + }, + "reactions": { + "@id": "enzml:EnzymeMLDocument/reactions", + "@container": "@list", + }, + "measurements": { + "@id": "enzml:EnzymeMLDocument/measurements", + "@container": "@list", + }, + "equations": { + "@id": "enzml:EnzymeMLDocument/equations", + "@container": "@list", + }, + "parameters": { + "@id": "enzml:EnzymeMLDocument/parameters", + "@container": "@list", + }, "references": { "@id": "schema:citation", - "@type": "@id", + "@container": "@list", }, - }, + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + def filter_creators(self, **kwargs) -> list[Creator]: """Filters the creators attribute based on the given kwargs @@ -322,12 +419,13 @@ def filter_parameters(self, **kwargs) -> list[Parameter]: return FilterWrapper[Parameter](self.parameters, **kwargs).filter() + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -349,9 +447,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -360,7 +456,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -387,6 +486,7 @@ def add_type_term( add_namespace(self, prefix, iri) self.ld_type.append(term) + def add_to_creators( self, given_name: str, @@ -394,22 +494,29 @@ def add_to_creators( mail: str, **kwargs, ): - params = {"given_name": given_name, "family_name": family_name, "mail": mail} + params = { + "given_name": given_name, + "family_name": family_name, + "mail": mail + } if "id" in kwargs: params["id"] = kwargs["id"] - self.creators.append(Creator(**params)) + self.creators.append( + Creator(**params) + ) return self.creators[-1] + def add_to_vessels( self, id: str, name: str, volume: float, unit: UnitDefinitionAnnot, - constant: bool = True, + constant: bool= True, **kwargs, ): params = { @@ -417,27 +524,30 @@ def add_to_vessels( "name": name, "volume": volume, "unit": unit, - "constant": constant, + "constant": constant } if "id" in kwargs: params["id"] = kwargs["id"] - self.vessels.append(Vessel(**params)) + self.vessels.append( + Vessel(**params) + ) return self.vessels[-1] + def add_to_proteins( self, id: str, name: str, - constant: bool = True, - sequence: Optional[str] = None, - vessel_id: Optional[str] = None, - ecnumber: Optional[str] = None, - organism: Optional[str] = None, - organism_tax_id: Optional[str] = None, - references: list[str] = [], + constant: bool= True, + sequence: Optional[str]= None, + vessel_id: Optional[str]= None, + ecnumber: Optional[str]= None, + organism: Optional[str]= None, + organism_tax_id: Optional[str]= None, + references: list[str]= [], **kwargs, ): params = { @@ -449,23 +559,26 @@ def add_to_proteins( "ecnumber": ecnumber, "organism": organism, "organism_tax_id": organism_tax_id, - "references": references, + "references": references } if "id" in kwargs: params["id"] = kwargs["id"] - self.proteins.append(Protein(**params)) + self.proteins.append( + Protein(**params) + ) return self.proteins[-1] + def add_to_complexes( self, id: str, name: str, - constant: bool = False, - vessel_id: Optional[str] = None, - participants: list[str] = [], + constant: bool= False, + vessel_id: Optional[str]= None, + participants: list[str]= [], **kwargs, ): params = { @@ -473,27 +586,30 @@ def add_to_complexes( "name": name, "constant": constant, "vessel_id": vessel_id, - "participants": participants, + "participants": participants } if "id" in kwargs: params["id"] = kwargs["id"] - self.complexes.append(Complex(**params)) + self.complexes.append( + Complex(**params) + ) return self.complexes[-1] + def add_to_small_molecules( self, id: str, name: str, - constant: bool = False, - vessel_id: Optional[str] = None, - canonical_smiles: Optional[str] = None, - inchi: Optional[str] = None, - inchikey: Optional[str] = None, - synonymous_names: list[str] = [], - references: list[str] = [], + constant: bool= False, + vessel_id: Optional[str]= None, + canonical_smiles: Optional[str]= None, + inchi: Optional[str]= None, + inchikey: Optional[str]= None, + synonymous_names: list[str]= [], + references: list[str]= [], **kwargs, ): params = { @@ -505,25 +621,28 @@ def add_to_small_molecules( "inchi": inchi, "inchikey": inchikey, "synonymous_names": synonymous_names, - "references": references, + "references": references } if "id" in kwargs: params["id"] = kwargs["id"] - self.small_molecules.append(SmallMolecule(**params)) + self.small_molecules.append( + SmallMolecule(**params) + ) return self.small_molecules[-1] + def add_to_reactions( self, id: str, name: str, - reversible: bool = False, - kinetic_law: Optional[Equation] = None, - reactants: list[ReactionElement] = [], - products: list[ReactionElement] = [], - modifiers: list[ModifierElement] = [], + reversible: bool= False, + kinetic_law: Optional[Equation]= None, + reactants: list[ReactionElement]= [], + products: list[ReactionElement]= [], + modifiers: list[ModifierElement]= [], **kwargs, ): params = { @@ -533,25 +652,28 @@ def add_to_reactions( "kinetic_law": kinetic_law, "reactants": reactants, "products": products, - "modifiers": modifiers, + "modifiers": modifiers } if "id" in kwargs: params["id"] = kwargs["id"] - self.reactions.append(Reaction(**params)) + self.reactions.append( + Reaction(**params) + ) return self.reactions[-1] + def add_to_measurements( self, id: str, name: str, - species_data: list[MeasurementData] = [], - group_id: Optional[str] = None, - ph: Optional[float] = None, - temperature: Optional[float] = None, - temperature_unit: Optional[UnitDefinitionAnnot] = None, + species_data: list[MeasurementData]= [], + group_id: Optional[str]= None, + ph: Optional[float]= None, + temperature: Optional[float]= None, + temperature_unit: Optional[UnitDefinitionAnnot]= None, **kwargs, ): params = { @@ -561,51 +683,57 @@ def add_to_measurements( "group_id": group_id, "ph": ph, "temperature": temperature, - "temperature_unit": temperature_unit, + "temperature_unit": temperature_unit } if "id" in kwargs: params["id"] = kwargs["id"] - self.measurements.append(Measurement(**params)) + self.measurements.append( + Measurement(**params) + ) return self.measurements[-1] + def add_to_equations( self, species_id: str, equation: str, equation_type: EquationType, - variables: list[Variable] = [], + variables: list[Variable]= [], **kwargs, ): params = { "species_id": species_id, "equation": equation, "equation_type": equation_type, - "variables": variables, + "variables": variables } if "id" in kwargs: params["id"] = kwargs["id"] - self.equations.append(Equation(**params)) + self.equations.append( + Equation(**params) + ) return self.equations[-1] + def add_to_parameters( self, id: str, name: str, symbol: str, - value: Optional[float] = None, - unit: Optional[UnitDefinitionAnnot] = None, - initial_value: Optional[float] = None, - upper_bound: Optional[float] = None, - lower_bound: Optional[float] = None, - fit: Optional[bool] = True, - stderr: Optional[float] = None, - constant: Optional[bool] = True, + value: Optional[float]= None, + unit: Optional[UnitDefinitionAnnot]= None, + initial_value: Optional[float]= None, + upper_bound: Optional[float]= None, + lower_bound: Optional[float]= None, + fit: Optional[bool]= True, + stderr: Optional[float]= None, + constant: Optional[bool]= True, **kwargs, ): params = { @@ -619,21 +747,25 @@ def add_to_parameters( "lower_bound": lower_bound, "fit": fit, "stderr": stderr, - "constant": constant, + "constant": constant } if "id" in kwargs: params["id"] = kwargs["id"] - self.parameters.append(Parameter(**params)) + self.parameters.append( + Parameter(**params) + ) return self.parameters[-1] class Creator(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore given_name: str = Field( default=..., @@ -650,31 +782,55 @@ class Creator(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Creator/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Creator/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: ["enzml:Creator", "schema:person"], + alias="@type", + default_factory = lambda: [ + "enzml:Creator","schema:person" + ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", "given_name": "schema:givenName", "family_name": "schema:familyName", "mail": "schema:email", - }, + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -696,9 +852,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -707,7 +861,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -736,9 +893,11 @@ def add_type_term( class Vessel(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -757,41 +916,64 @@ class Vessel(BaseModel): description="""Volumetric unit of the vessel.""", ) constant: bool = Field( - default=True, + default= True, description="""Whether the volume of the vessel is constant or not. Default is True.""", ) # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Vessel/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Vessel/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: ["enzml:Vessel", "OBO:OBI_0400081"], + alias="@type", + default_factory = lambda: [ + "enzml:Vessel","OBO:OBI_0400081" + ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "id": "schema:identifier", "name": "schema:name", "volume": "OBO:OBI_0002139", - }, + "unit": "enzml:Vessel/unit", + "constant": "enzml:Vessel/constant", + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -813,9 +995,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -824,7 +1004,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -853,9 +1036,11 @@ def add_type_term( class Protein(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -867,7 +1052,7 @@ class Protein(BaseModel): description="""Name of the protein.""", ) constant: bool = Field( - default=True, + default= True, description="""Whether the concentration of the protein is constant through the experiment or not. Default is True.""", @@ -902,46 +1087,64 @@ class Protein(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Protein/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Protein/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: ["enzml:Protein", "OBO:PR_000000001"], + alias="@type", + default_factory = lambda: [ + "enzml:Protein","OBO:PR_000000001" + ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "id": "schema:identifier", "name": "schema:name", + "constant": "enzml:Protein/constant", "sequence": "OBO:GSSO_007262", - "vessel_id": { - "@id": "schema:identifier", - "@type": "@id", - }, + "vessel_id": "enzml:Protein/vessel_id", + "ecnumber": "enzml:Protein/ecnumber", "organism": "OBO:OBI_0100026", - "organism_tax_id": { - "@type": "@id", - }, + "organism_tax_id": "enzml:Protein/organism_tax_id", "references": { "@id": "schema:citation", - "@type": "@id", + "@container": "@list", }, - }, + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -963,9 +1166,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -974,7 +1175,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1003,9 +1207,11 @@ def add_type_term( class Complex(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -1016,7 +1222,7 @@ class Complex(BaseModel): description="""Name of the complex.""", ) constant: bool = Field( - default=False, + default= False, description="""Whether the concentration of the complex is constant through the experiment or not. Default is False.""", @@ -1033,42 +1239,60 @@ class Complex(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Complex/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Complex/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:Complex", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "id": "schema:identifier", "name": "schema:name", - "vessel_id": { - "@id": "schema:identifier", - "@type": "@id", - }, + "constant": "enzml:Complex/constant", + "vessel_id": "enzml:Complex/vessel_id", "participants": { - "@type": "@id", + "@id": "enzml:Complex/participants", + "@container": "@list", }, - }, + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -1090,9 +1314,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -1101,7 +1323,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1130,9 +1355,11 @@ def add_type_term( class SmallMolecule(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -1145,7 +1372,7 @@ class SmallMolecule(BaseModel): description="""Name of the small molecule.""", ) constant: bool = Field( - default=False, + default= False, description="""Whether the concentration of the small molecule is constant through the experiment or not. Default is False.""", @@ -1184,43 +1411,67 @@ class SmallMolecule(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:SmallMolecule/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:SmallMolecule/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:SmallMolecule", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "id": "schema:identifier", "name": "schema:name", - "vessel_id": { - "@id": "schema:identifier", - "@type": "@id", + "constant": "enzml:SmallMolecule/constant", + "vessel_id": "enzml:SmallMolecule/vessel_id", + "canonical_smiles": "enzml:SmallMolecule/canonical_smiles", + "inchi": "enzml:SmallMolecule/inchi", + "inchikey": "enzml:SmallMolecule/inchikey", + "synonymous_names": { + "@id": "enzml:SmallMolecule/synonymous_names", + "@container": "@list", }, "references": { "@id": "schema:citation", - "@type": "@id", + "@container": "@list", }, - }, + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -1242,9 +1493,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -1253,7 +1502,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1282,9 +1534,11 @@ def add_type_term( class Reaction(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -1295,7 +1549,7 @@ class Reaction(BaseModel): description="""Name of the reaction.""", ) reversible: bool = Field( - default=False, + default= False, description="""Whether the reaction is reversible or irreversible. Default is False.""", ) @@ -1319,28 +1573,65 @@ class Reaction(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Reaction/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Reaction/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:Reaction", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "Equation": "http://www.enzymeml.org/v2/Equation/", + "ReactionElement": "http://www.enzymeml.org/v2/ReactionElement/", + "ReactionElement": "http://www.enzymeml.org/v2/ReactionElement/", + "ModifierElement": "http://www.enzymeml.org/v2/ModifierElement/", + "id": "schema:identifier", + "name": "enzml:Reaction/name", + "reversible": "enzml:Reaction/reversible", + "kinetic_law": "enzml:Reaction/kinetic_law", + "reactants": { + "@id": "enzml:Reaction/reactants", + "@container": "@list", + }, + "products": { + "@id": "enzml:Reaction/products", + "@container": "@list", }, - }, + "modifiers": { + "@id": "enzml:Reaction/modifiers", + "@container": "@list", + }, + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + def filter_reactants(self, **kwargs) -> list[ReactionElement]: """Filters the reactants attribute based on the given kwargs @@ -1377,12 +1668,13 @@ def filter_modifiers(self, **kwargs) -> list[ModifierElement]: return FilterWrapper[ModifierElement](self.modifiers, **kwargs).filter() + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -1404,9 +1696,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -1415,7 +1705,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1442,56 +1735,75 @@ def add_type_term( add_namespace(self, prefix, iri) self.ld_type.append(term) + def add_to_reactants( self, species_id: str, - stoichiometry: float = 1, + stoichiometry: float= 1.0, **kwargs, ): - params = {"species_id": species_id, "stoichiometry": stoichiometry} + params = { + "species_id": species_id, + "stoichiometry": stoichiometry + } if "id" in kwargs: params["id"] = kwargs["id"] - self.reactants.append(ReactionElement(**params)) + self.reactants.append( + ReactionElement(**params) + ) return self.reactants[-1] + def add_to_products( self, species_id: str, - stoichiometry: float = 1, + stoichiometry: float= 1.0, **kwargs, ): - params = {"species_id": species_id, "stoichiometry": stoichiometry} + params = { + "species_id": species_id, + "stoichiometry": stoichiometry + } if "id" in kwargs: params["id"] = kwargs["id"] - self.products.append(ReactionElement(**params)) + self.products.append( + ReactionElement(**params) + ) return self.products[-1] + def add_to_modifiers( self, species_id: str, role: ModifierRole, **kwargs, ): - params = {"species_id": species_id, "role": role} + params = { + "species_id": species_id, + "role": role + } if "id" in kwargs: params["id"] = kwargs["id"] - self.modifiers.append(ModifierElement(**params)) + self.modifiers.append( + ModifierElement(**params) + ) return self.modifiers[-1] - class ReactionElement(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore species_id: str = Field( default=..., @@ -1499,41 +1811,61 @@ class ReactionElement(BaseModel): reactant defined in the EnzymeML Document.""", ) stoichiometry: float = Field( - default=1, + default= 1.0, description="""Float number representing the associated stoichiometry.""", ) # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:ReactionElement/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:ReactionElement/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:ReactionElement", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "species_id": { - "@id": "schema:identifier", - "@type": "@id", - }, - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "species_id": "schema:identifier", + "stoichiometry": "enzml:ReactionElement/stoichiometry", + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -1555,9 +1887,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -1566,7 +1896,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1595,9 +1928,11 @@ def add_type_term( class ModifierElement(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore species_id: str = Field( default=..., @@ -1611,34 +1946,55 @@ class ModifierElement(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:ModifierElement/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:ModifierElement/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:ModifierElement", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "species_id": { - "@id": "schema:identifier", - "@type": "@id", - }, - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "ModifierRole": "http://www.enzymeml.org/v2/ModifierRole/", + "species_id": "schema:identifier", + "role": "enzml:ModifierElement/role", + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -1660,9 +2016,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -1671,7 +2025,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1700,9 +2057,11 @@ def add_type_term( class Equation(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore species_id: str = Field( default=..., @@ -1727,28 +2086,54 @@ class Equation(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Equation/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Equation/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:Equation", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "species_id": { - "@id": "schema:identifier", - "@type": "@id", + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "EquationType": "http://www.enzymeml.org/v2/EquationType/", + "Variable": "http://www.enzymeml.org/v2/Variable/", + "species_id": "schema:identifier", + "equation": "enzml:Equation/equation", + "equation_type": "enzml:Equation/equation_type", + "variables": { + "@id": "enzml:Equation/variables", + "@container": "@list", }, - }, + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + def filter_variables(self, **kwargs) -> list[Variable]: """Filters the variables attribute based on the given kwargs @@ -1761,12 +2146,13 @@ def filter_variables(self, **kwargs) -> list[Variable]: return FilterWrapper[Variable](self.variables, **kwargs).filter() + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -1788,9 +2174,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -1799,7 +2183,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1826,6 +2213,7 @@ def add_type_term( add_namespace(self, prefix, iri) self.ld_type.append(term) + def add_to_variables( self, id: str, @@ -1833,20 +2221,27 @@ def add_to_variables( symbol: str, **kwargs, ): - params = {"id": id, "name": name, "symbol": symbol} + params = { + "id": id, + "name": name, + "symbol": symbol + } if "id" in kwargs: params["id"] = kwargs["id"] - self.variables.append(Variable(**params)) + self.variables.append( + Variable(**params) + ) return self.variables[-1] - class Variable(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -1863,34 +2258,55 @@ class Variable(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Variable/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Variable/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:Variable", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", - }, - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "id": "schema:identifier", + "name": "enzml:Variable/name", + "symbol": "enzml:Variable/symbol", + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -1912,9 +2328,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -1923,7 +2337,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -1952,9 +2369,11 @@ def add_type_term( class Parameter(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -1992,7 +2411,7 @@ class Parameter(BaseModel): for the parameter estimation""", ) fit: Optional[bool] = Field( - default=True, + default= True, description="""Whether this parameter should be varied or not in the context of an optimization.""", ) @@ -2001,41 +2420,70 @@ class Parameter(BaseModel): description="""Standard error of the estimated parameter.""", ) constant: Optional[bool] = Field( - default=True, + default= True, description="""Specifies if this parameter is constant. Default is True.""", ) # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Parameter/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Parameter/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:Parameter", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", - }, - }, + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "id": "schema:identifier", + "name": "enzml:Parameter/name", + "symbol": "enzml:Parameter/symbol", + "value": "enzml:Parameter/value", + "unit": "enzml:Parameter/unit", + "initial_value": "enzml:Parameter/initial_value", + "upper_bound": "enzml:Parameter/upper_bound", + "lower_bound": "enzml:Parameter/lower_bound", + "fit": "enzml:Parameter/fit", + "stderr": "enzml:Parameter/stderr", + "constant": "enzml:Parameter/constant", + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -2057,9 +2505,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -2068,7 +2514,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -2097,9 +2546,11 @@ def add_type_term( class Measurement(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore id: str = Field( default=..., @@ -2135,31 +2586,56 @@ class Measurement(BaseModel): # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:Measurement/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:Measurement/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:Measurement", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "id": { - "@id": "schema:identifier", - "@type": "@id", - }, - "group_id": { - "@type": "@id", + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "MeasurementData": "http://www.enzymeml.org/v2/MeasurementData/", + "id": "schema:identifier", + "name": "enzml:Measurement/name", + "species_data": { + "@id": "enzml:Measurement/species_data", + "@container": "@list", }, - }, + "group_id": "enzml:Measurement/group_id", + "ph": "enzml:Measurement/ph", + "temperature": "enzml:Measurement/temperature", + "temperature_unit": "enzml:Measurement/temperature_unit", + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + def filter_species_data(self, **kwargs) -> list[MeasurementData]: """Filters the species_data attribute based on the given kwargs @@ -2172,12 +2648,13 @@ def filter_species_data(self, **kwargs) -> list[MeasurementData]: return FilterWrapper[MeasurementData](self.species_data, **kwargs).filter() + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -2199,9 +2676,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -2210,7 +2685,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -2237,17 +2715,18 @@ def add_type_term( add_namespace(self, prefix, iri) self.ld_type.append(term) + def add_to_species_data( self, species_id: str, - prepared: Optional[float] = None, - initial: Optional[float] = None, - data_unit: Optional[UnitDefinitionAnnot] = None, - data: list[float] = [], - time: list[float] = [], - time_unit: Optional[UnitDefinitionAnnot] = None, - data_type: Optional[DataTypes] = None, - is_simulated: Optional[bool] = False, + prepared: Optional[float]= None, + initial: Optional[float]= None, + data_unit: Optional[UnitDefinitionAnnot]= None, + data: list[float]= [], + time: list[float]= [], + time_unit: Optional[UnitDefinitionAnnot]= None, + data_type: Optional[DataTypes]= None, + is_simulated: Optional[bool]= False, **kwargs, ): params = { @@ -2259,21 +2738,25 @@ def add_to_species_data( "time": time, "time_unit": time_unit, "data_type": data_type, - "is_simulated": is_simulated, + "is_simulated": is_simulated } if "id" in kwargs: params["id"] = kwargs["id"] - self.species_data.append(MeasurementData(**params)) + self.species_data.append( + MeasurementData(**params) + ) return self.species_data[-1] class MeasurementData(BaseModel): - model_config: ConfigDict = ConfigDict( # type: ignore - validate_assignment=True, - ) # type: ignore + + model_config: ConfigDict = ConfigDict( # type: ignore + validate_assignment = True, + populate_by_name = True, + ) # type: ignore species_id: str = Field( default=..., @@ -2317,40 +2800,75 @@ class MeasurementData(BaseModel): concentration, absorbance, etc.)""", ) is_simulated: Optional[bool] = Field( - default=False, + default= False, description="""Whether or not the data has been generated by simulation. Default is False.""", ) # JSON-LD fields ld_id: str = Field( - serialization_alias="@id", - default_factory=lambda: "enzml:MeasurementData/" + str(uuid4()), + alias="@id", + default_factory=lambda: "enzml:MeasurementData/" + str(uuid4()) ) ld_type: list[str] = Field( - serialization_alias="@type", - default_factory=lambda: [ + alias="@type", + default_factory = lambda: [ "enzml:MeasurementData", ], ) ld_context: dict[str, str | dict] = Field( - serialization_alias="@context", - default_factory=lambda: { + alias="@context", + default_factory = lambda: { + "@vocab": "http://www.enzymeml.org/v2/", "enzml": "http://www.enzymeml.org/v2/", "OBO": "http://purl.obolibrary.org/obo/", + "om": "http://www.ontology-of-units-of-measure.org/resource/om-2/", + "qudt": "http://qudt.org/schema/qudt#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "schema": "https://schema.org/", - "species_id": { - "@type": "@id", + "unit": "http://qudt.org/vocab/unit#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "DataTypes": "http://www.enzymeml.org/v2/DataTypes/", + "species_id": "enzml:MeasurementData/species_id", + "prepared": "enzml:MeasurementData/prepared", + "initial": "enzml:MeasurementData/initial", + "data_unit": "enzml:MeasurementData/data_unit", + "data": { + "@id": "enzml:MeasurementData/data", + "@container": "@list", }, - }, + "time": { + "@id": "enzml:MeasurementData/time", + "@container": "@list", + }, + "time_unit": "enzml:MeasurementData/time_unit", + "data_type": "enzml:MeasurementData/data_type", + "is_simulated": "enzml:MeasurementData/is_simulated", + } ) + @field_validator("ld_id", mode="before") + @classmethod + def _default_ld_id(cls, value): + return cls.model_fields["ld_id"].default_factory() if value is None else value # type: ignore + + @field_validator("ld_type", mode="before") + @classmethod + def _merge_ld_type(cls, value: str | list | None) -> list[str]: + return merge_ld_type(cls.model_fields["ld_type"].default_factory(), value) # type: ignore + + @field_validator("ld_context", mode="before") + @classmethod + def _merge_ld_context(cls, value: dict | list | str | None) -> dict[str, str | dict]: + return merge_ld_context(cls.model_fields["ld_context"].default_factory(), value) # type: ignore + + def set_attr_term( self, attr: str, term: str | dict, prefix: str | None = None, - iri: str | None = None, + iri: str | None = None ): """Sets the term for a given attribute in the JSON-LD object @@ -2372,9 +2890,7 @@ def set_attr_term( AssertionError: If the attribute is not found in the model """ - assert attr in self.model_fields, ( - f"Attribute {attr} not found in {self.__class__.__name__}" - ) + assert attr in self.model_fields, f"Attribute {attr} not found in {self.__class__.__name__}" if prefix: validate_prefix(term, prefix) @@ -2383,7 +2899,10 @@ def set_attr_term( self.ld_context[attr] = term def add_type_term( - self, term: str, prefix: str | None = None, iri: str | None = None + self, + term: str, + prefix: str | None = None, + iri: str | None = None ): """Adds a term to the @type field of the JSON-LD object @@ -2420,14 +2939,12 @@ class ModifierRole(Enum): INHIBITOR = "inhibitor" SOLVENT = "solvent" - class EquationType(Enum): ASSIGNMENT = "assignment" INITIAL_ASSIGNMENT = "initialAssignment" ODE = "ode" RATE_LAW = "rateLaw" - class DataTypes(Enum): ABSORBANCE = "absorbance" AMOUNT = "amount" @@ -2437,4 +2954,4 @@ class DataTypes(Enum): PEAK_AREA = "peakarea" TRANSMITTANCE = "transmittance" TURNOVER = "turnover" - YIELD = "yield" + YIELD = "yield" \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 41c6306f..b7b1177f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ dependencies = [ "sympy>=1.12.1,<2", "pymetadata>=0.5.3,<0.6", "httpx>=0.27", - "mdmodels>=0.2.4,<0.3", + "mdmodels>=0.4.0,<0.5", "joblib>=1.5.0,<2", "bokeh>=3.7.3,<4", "matplotlib>=3.10,<4", diff --git a/specs b/specs index c5dc877b..97758096 160000 --- a/specs +++ b/specs @@ -1 +1 @@ -Subproject commit c5dc877bdbc4d99ce1b57009583cfe3dc97163fb +Subproject commit 977580968f54efdba5e805f8271daba0a2a1a437 diff --git a/tests/fixtures/compose/expected_compose.json b/tests/fixtures/compose/expected_compose.json index 93d80c63..534955d2 100644 --- a/tests/fixtures/compose/expected_compose.json +++ b/tests/fixtures/compose/expected_compose.json @@ -17,7 +17,7 @@ "enzml:EnzymeMLDocument" ], "name": "test", - "version": "2", + "version": "2.1", "creators": [], "vessels": [ { diff --git a/tests/fixtures/compose/expected_compose_no_vessel.json b/tests/fixtures/compose/expected_compose_no_vessel.json index cc03bf19..f701fc79 100644 --- a/tests/fixtures/compose/expected_compose_no_vessel.json +++ b/tests/fixtures/compose/expected_compose_no_vessel.json @@ -17,7 +17,7 @@ "enzml:EnzymeMLDocument" ], "name": "test", - "version": "2", + "version": "2.1", "creators": [], "vessels": [], "proteins": [ diff --git a/tests/fixtures/petab/abts_measurement_model.xml b/tests/fixtures/petab/abts_measurement_model.xml index e2a63853..7d3d909b 100644 --- a/tests/fixtures/petab/abts_measurement_model.xml +++ b/tests/fixtures/petab/abts_measurement_model.xml @@ -200,13 +200,27 @@ - - + + + u4 + l + + + + vessel0 vessel0 1.0 + + true + + litre + 1 + 1.0 + 0.0 + @@ -214,9 +228,13 @@ - - + + + slac slac + false + vessel0 + @@ -225,9 +243,13 @@ - - + + + slac_inactive slac_inactive + false + vessel0 + @@ -236,9 +258,14 @@ - - + + + abts abts + false + vessel0 + + @@ -246,9 +273,14 @@ - - + + + buffer buffer + false + vessel0 + + @@ -256,9 +288,14 @@ - - + + + abts_radical abts_radical + false + vessel0 + + @@ -268,8 +305,17 @@ - - + + + k_cat + k_cat + k_cat + 1.85 + 0.01 + 2.0 + 1e-06 + true + true @@ -282,8 +328,17 @@ - - + + + K_M + K_M + K_M + 20.0 + 120.0 + 150.0 + 1e-06 + true + true @@ -296,8 +351,17 @@ - - + + + k_ie + k_ie + k_ie + 0.001 + 0.01 + 0.05 + 1e-06 + true + true diff --git a/tests/integration/test_petab.py b/tests/integration/test_petab.py index ae1a52d0..669c574c 100644 --- a/tests/integration/test_petab.py +++ b/tests/integration/test_petab.py @@ -48,15 +48,19 @@ def test_to_petab(self): "tests/fixtures/petab/abts_measurement_parameters.tsv" ).read() - assert expected_sbml == self._remove_uuid(sbml_path.read_text()) + # rdflib writes blank-node annotations in random order. + assert sorted(expected_sbml.splitlines()) == sorted( + self._remove_uuid(sbml_path.read_text()).splitlines() + ) assert expected_condition == condition_path.read_text() assert expected_observable == observable_path.read_text() assert expected_measurement == measurement_path.read_text() assert expected_parameter == parameter_path.read_text() def _remove_uuid(self, s: str) -> str: + # UUIDs and rdflib's random blank-node IDs differ on every run. return re.sub( - r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|N[0-9a-f]{32}", "", s, ) diff --git a/uv.lock b/uv.lock index ccabeb56..21491020 100644 --- a/uv.lock +++ b/uv.lock @@ -6,6 +6,15 @@ resolution-markers = [ "python_full_version < '3.12'", ] +[[package]] +name = "annotated-doc" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/8e/38aa427ed5402449e226975b649c5dc73ccadfefeb95e6aecb8f8ea4b6b6/annotated_doc-0.0.5.tar.gz", hash = "sha256:c7e58ce09192557605d8bbd92836d7e1d520ac9580096042c0bfd197efacf1bb", size = 10758, upload-time = "2026-07-28T13:50:58.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/30/e900b21425a860e195f32e37657aa1f7c7f2b1bfb26f03ca209b90933c06/annotated_doc-0.0.5-py3-none-any.whl", hash = "sha256:117bac03a25ede5df5440e855b32d556049ca169ead221505badf432fed4b101", size = 5302, upload-time = "2026-07-28T13:50:57.239Z" }, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -350,6 +359,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, ] +[[package]] +name = "dotenv" +version = "0.9.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dotenv" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/b7/545d2c10c1fc15e48653c91efde329a790f2eecfbbf2bd16003b5db2bab0/dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9", size = 1892, upload-time = "2025-02-19T22:15:01.647Z" }, +] + [[package]] name = "dotted-dict" version = "1.1.3" @@ -368,6 +388,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, ] +[[package]] +name = "fastexcel" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ab/16/d3b4465e1c32736ada7e1bc5a11334f3b38d747074aa01c60877d01dff81/fastexcel-0.21.0.tar.gz", hash = "sha256:07313c1267ab47ba639abf1122efd5985a1fb08efc996194f422ab17f06149c5", size = 61036, upload-time = "2026-08-19T13:00:20.184Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/98/461c22faa286d7635343fcfbacbed4edf77d98f06fb4426e646ae5438d66/fastexcel-0.21.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c3e7ab5d8c8b6c5a787aaf2b64604bd8b93b94694920a2ed731ea556a81d9a35", size = 3421831, upload-time = "2026-08-19T13:00:07.163Z" }, + { url = "https://files.pythonhosted.org/packages/69/ff/a6b1b97a94bbcc0d64b946e831ff937c2c803b019a7600fc69f953c38370/fastexcel-0.21.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:768b663728cb5f29e159428fdf3a3f74e379534c2f0304b300bd95039d482abe", size = 3264928, upload-time = "2026-08-19T13:00:09.133Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a1/27454838aca7921826dd02be3828a20fcaaa36e641762bf070642c8ad65e/fastexcel-0.21.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6e66906fe3b9f68f94c4c94e2ac21b6eebd862b703983c8e0c009f91c71754", size = 3719994, upload-time = "2026-08-19T12:59:50.076Z" }, + { url = "https://files.pythonhosted.org/packages/30/b8/2f5de2ec4026aa2e121a5da3d25b1d20f653bffdd569dfb74df6732ab99d/fastexcel-0.21.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ddb458fecbbf1804c0952155fb99d18025d86e345b57a5435e0553944f25578", size = 3789119, upload-time = "2026-08-19T12:59:52.278Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b2/1e08ffca9481fa2103409a9bef52a91f0963867b4ea649a3d9e8f5c45554/fastexcel-0.21.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0376944edf90c98008b49b200f7354122ba9abac6c21bab76487655738b041b7", size = 3895258, upload-time = "2026-08-19T12:59:54.374Z" }, + { url = "https://files.pythonhosted.org/packages/6d/68/4f0d0b5d41c9fe22d45ec2b8412566cb79fbd4f412b6f33a7f60a302c1e8/fastexcel-0.21.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e919a4eaa15330341744cfee33d1f87d041d08228ce68809790e3738e80811e8", size = 4047752, upload-time = "2026-08-19T12:59:56.424Z" }, + { url = "https://files.pythonhosted.org/packages/8a/88/6879abe39db93b2c1939fe146d1335d95c30e961c2807f5bc516d4e305e1/fastexcel-0.21.0-cp310-abi3-win_amd64.whl", hash = "sha256:e1db4666a0790b48c76bb5a43cda06ffecebb22706f9ac6b3f07bcb0e7336134", size = 3318648, upload-time = "2026-08-19T13:00:14.784Z" }, + { url = "https://files.pythonhosted.org/packages/f3/03/5c8c97b47289bead5a3ba0b6cba01d27377b857446c65918c43e1b008d94/fastexcel-0.21.0-cp310-abi3-win_arm64.whl", hash = "sha256:86af0a1e3c3d8657916ea434f11636df4e4b49e0cf665b4ea39349a83d4ca3c8", size = 3035704, upload-time = "2026-08-19T13:00:16.64Z" }, + { url = "https://files.pythonhosted.org/packages/74/9d/ef3dd2022d943620653f65fd160f81be27c576a54b9ecd26cd1731da365b/fastexcel-0.21.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:f6cf28f5f3fed1f34aa15bf021d2c04bf947720df70f54b131258c913bc3b4cf", size = 3419154, upload-time = "2026-08-19T13:00:11.145Z" }, + { url = "https://files.pythonhosted.org/packages/e4/82/763ecd88db11d6f98b78aa1b951c2a259d84d6d285af2f6dd525948062f4/fastexcel-0.21.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ef2a6953e8350966d32632e3bc064edaab64ea2899f2027e564269fa7d75fb58", size = 3251184, upload-time = "2026-08-19T13:00:12.965Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0d/fce85550c9138e5e2517b33d9ec000222710b3bdc6563a6c91fddff3eb52/fastexcel-0.21.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f8fdbfd80647714a2b3d49de2517d0466f6c046aa215c16fb569c48aef8d0ee", size = 3711549, upload-time = "2026-08-19T12:59:58.613Z" }, + { url = "https://files.pythonhosted.org/packages/ac/47/b768f8165e16f15345b5eec06507b33e88cc8934d5e9d0e602d26bfdba8a/fastexcel-0.21.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47c6f42b3b82a158e4e6c4e1ed53ba0b96cec132d1fed828c8411e6f6ba5caab", size = 3778980, upload-time = "2026-08-19T13:00:00.807Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e8/3d9626a0b1e50704bfc19df2f69e2b3e7870f43e6cd8509565b5aa32e5b6/fastexcel-0.21.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bce27f751cf1661f823088e89c11375448d19e425e3c3aa993c356720305c873", size = 3888071, upload-time = "2026-08-19T13:00:03.134Z" }, + { url = "https://files.pythonhosted.org/packages/a7/ff/23f43ec08ac44a02798508593f2af5c84bbad58db17da3237428577f5b1b/fastexcel-0.21.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1a5742e598516734740ef4142cf3328d6ef6c8e43947d9a66d6a91a5d9bfa3ec", size = 4041849, upload-time = "2026-08-19T13:00:05.103Z" }, + { url = "https://files.pythonhosted.org/packages/13/90/4b2614123e185f20e386695771898c97a469f39129472db731a2c3d248ad/fastexcel-0.21.0-cp314-cp314t-win_amd64.whl", hash = "sha256:fe52f6053aac6ff3b8cc879052b671af9cb3ada16853b1c8b4bcac44574e4c10", size = 3311557, upload-time = "2026-08-19T13:00:18.614Z" }, +] + [[package]] name = "fastobo" version = "0.14.1" @@ -911,67 +954,72 @@ wheels = [ [[package]] name = "mdmodels" -version = "0.2.4" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "astropy" }, { name = "bigtree" }, + { name = "dotenv" }, { name = "dotted-dict" }, + { name = "fastexcel" }, { name = "httpx" }, { name = "mdmodels-core" }, { name = "nest-asyncio" }, { name = "pandas" }, + { name = "polars" }, { name = "pydantic-xml" }, { name = "python-forge" }, { name = "python-jsonpath" }, { name = "rich" }, + { name = "toml" }, + { name = "typer" }, { name = "validators" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/b7/8baec4cfee5cea50629025dfdc634497ad1190ae00e387c55dbbb49ce7dc/mdmodels-0.2.4.tar.gz", hash = "sha256:caeacb672aaaa1ef246885a945028554fba605a1d3fa27e55c842d275120cf89", size = 37222, upload-time = "2026-01-15T00:10:48.609Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/65/5698ee1bb1ccdf60e3a7b82dda7f0505c0c663fe20f5440b9da546178a25/mdmodels-0.4.0.tar.gz", hash = "sha256:47c5ac9b0351f4da3f3cceed356fa356f4bb1c263b462a9ee249a58e5b690f59", size = 569374, upload-time = "2026-10-11T19:16:50.311Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/50/c4c795446fbba83164051c0ff222fe4eb0931bdfdbd5da5f80563216fdc7/mdmodels-0.2.4-py3-none-any.whl", hash = "sha256:e24e2e021a04db671399aaac45164cc4062a0bbe4e903a7d0d8089ef783afe3a", size = 68759, upload-time = "2026-01-15T00:10:47.541Z" }, + { url = "https://files.pythonhosted.org/packages/3f/95/c9b1e323e9d2c005e3b83a865fe26e1c1fd7c5c9bc7aa1d9812b70dc6e39/mdmodels-0.4.0-py3-none-any.whl", hash = "sha256:fc641dc861830dc7e584b5f2cb629a1ab8c7fd1c4a7f81a1332f7d7fbcecccbd", size = 167434, upload-time = "2026-10-11T19:16:48.586Z" }, ] [[package]] name = "mdmodels-core" -version = "0.2.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/0f/131e75fe45a6a477446ca63512e39372af707057d5c9fabb29d0d2fa70e8/mdmodels_core-0.2.7.tar.gz", hash = "sha256:fbb8d744ed947aa4d3b89ab49ea61ca0620bf7ba71a540e1f6816f7792524d6e", size = 159629, upload-time = "2025-09-24T10:53:55.807Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/74/f0/4360e87eeda1b1fc531e476499d88d6cdce0bd5732cb563bbc73ee7765f5/mdmodels_core-0.2.7-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f4bd75796368e6c934a806e507633891d01f6764cac8fa8271b0a756879e60ad", size = 2352360, upload-time = "2025-09-24T10:53:51.524Z" }, - { url = "https://files.pythonhosted.org/packages/cc/ea/0a630e5b431d5e7487cd78b9e6826ec9b6d2f176e94f8d1b4053d90ff6c4/mdmodels_core-0.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2118198d1a43a228f67d03c290f4f3c17607d0332697700eb0a0f3ff5bc15843", size = 2226025, upload-time = "2025-09-24T10:53:45.526Z" }, - { url = "https://files.pythonhosted.org/packages/40/7c/12dc25f41b3b2f8c4fd86399b5569d0011933667f176992766d3f141bc14/mdmodels_core-0.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2a99bcc284284a5af0c40450d9c5b622db95483f6e5cbfdc74e3f5bffa946b9", size = 2478819, upload-time = "2025-09-24T10:52:37.066Z" }, - { url = "https://files.pythonhosted.org/packages/4f/6d/e050648d1d7f60aafc1d9a65515ae5e596ffa1fcb13c08542b5e0def15ac/mdmodels_core-0.2.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0cce18e199ff7e982735d6d6b84928ecc7d6e5aa6204926078aa7ef14981d5e", size = 2412397, upload-time = "2025-09-24T10:52:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/ec/aa/a9078e454f428763fcdb07621e3231f3428a80f3504e4ec38d476f8ff198/mdmodels_core-0.2.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05aeeaca62dae5466e38fb95052c26ecef5e955a0da8abde9dd47fb32d73d61d", size = 2791236, upload-time = "2025-09-24T10:53:07.649Z" }, - { url = "https://files.pythonhosted.org/packages/d1/63/28a05592ba1d327de8ad13d53abca9fd6daf59046ad7a18d927dd22e3d9b/mdmodels_core-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2724a23b48290b79522f4262108a91d8aacbd52c8bbb7490655e80f36d64aa", size = 2511118, upload-time = "2025-09-24T10:53:33.995Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/cd43eeeea6ec1abb0246b0c6ccf83d709afdd0506b48c97a10fef0c0e316/mdmodels_core-0.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca7964acd5697994a3a39e8e9321e13211a8fc535e7427329a47c5952702fc8a", size = 2665209, upload-time = "2025-09-24T10:53:22.109Z" }, - { url = "https://files.pythonhosted.org/packages/06/62/0b05f600b8c09b34b12e5a4e8aa775f02b2218407579f7ada6f71b94671b/mdmodels_core-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:7e713247c5c3c1df854c8aa15afb89ecef8e5d90049fb00dd84aac800446a266", size = 2062074, upload-time = "2025-09-24T10:53:58.629Z" }, - { url = "https://files.pythonhosted.org/packages/95/2d/64a9bc9cfea7109657c4412e2a79bb3e26497387dcfeb37d354050bd05fd/mdmodels_core-0.2.7-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4b396deb13b9b9d6d0fe249b1cad68866be0a531e89c5d19a8a154f7d9c089b6", size = 2351015, upload-time = "2025-09-24T10:53:52.871Z" }, - { url = "https://files.pythonhosted.org/packages/f9/20/63edb5ae3a292672f7cd05612db258b07155f2fc61046c29268f1102b598/mdmodels_core-0.2.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fad194cb2024dadddc78154611339a683d89ae23961af657b56b755d73db0c", size = 2225037, upload-time = "2025-09-24T10:53:47.122Z" }, - { url = "https://files.pythonhosted.org/packages/19/85/a0a5f19620d889a40b3fac73081133698ea98060958e171ef96e932282c4/mdmodels_core-0.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53c0567e881847132f87ef5e73c714cdd6a618cb073d3c1a164c2cade92c8280", size = 2476338, upload-time = "2025-09-24T10:52:38.355Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ac/17ef366525cec541fff01f138838c9b23ecda255b194e39e0225cbe39958/mdmodels_core-0.2.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:963308e86b5871ea4148729a759eee32fbb06079839bef7d631514b7454daea6", size = 2413706, upload-time = "2025-09-24T10:52:54.514Z" }, - { url = "https://files.pythonhosted.org/packages/c3/44/a3fa3369db5b8c72a86478f5665b7560055e264b4dc1ef6de560f90f4c7c/mdmodels_core-0.2.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:728738389e31729176dc5883d0d62d41af655646be692e6b1cc37d6b7c1245c2", size = 2785437, upload-time = "2025-09-24T10:53:09.152Z" }, - { url = "https://files.pythonhosted.org/packages/23/7b/1c2a83c0177201cf31e8e05785cfe734889d39f10747afff0302f4020194/mdmodels_core-0.2.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd15afe41241553789087bdafbad370698e1f53e266799e1d8fded05a1b6325", size = 2510283, upload-time = "2025-09-24T10:53:35.29Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5a/a62b6675ac2fcff767e829ccddd1c7c1cc46f1354574287e7705fa3c3cd4/mdmodels_core-0.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ab0f00503ce364d94388eb0c33f7cd296d8c3bc98c4ab11fe3941b58d3ba7e62", size = 2669453, upload-time = "2025-09-24T10:53:23.613Z" }, - { url = "https://files.pythonhosted.org/packages/aa/ad/04c23886dd50964f8cf0b98f153f48ec310465dff8d4dc0680c59c660b20/mdmodels_core-0.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:b9edd2b40c52251d33cc5146d2ec2c4b3890befbd57ef12d36e6bd787627789e", size = 2060452, upload-time = "2025-09-24T10:54:00.571Z" }, - { url = "https://files.pythonhosted.org/packages/d0/98/245ee93b414fae3c84ad7da97851266e2c9300fd515cde615a27fba80fc3/mdmodels_core-0.2.7-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:bbad63ea3a30e3c2b947f6c6db7a30567de6daa4af7c6416f0063cf9048d9059", size = 2350835, upload-time = "2025-09-24T10:53:54.198Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b8/9abd3a5bc86115c74393b27a2d8b4509aa11f93f49a9c3c336b0b45bcb1e/mdmodels_core-0.2.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e141e0b58ae70123948ea5ae9d62ac4c83bb2a970e98ff8b8814135287b16036", size = 2225031, upload-time = "2025-09-24T10:53:48.451Z" }, - { url = "https://files.pythonhosted.org/packages/7e/91/cf7deb03a9cd249fb3cf0dcd0adac485bf4e1934e596179e016216f4cf44/mdmodels_core-0.2.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f42bd415b595175598f1fe2c47805f38d96570ab22dfdbda047637797d7ceb2c", size = 2475937, upload-time = "2025-09-24T10:52:39.886Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9b/3c6cd8fd33afc14b07ad3d56093b05e9a5e1d7504f9074c325f6177aff95/mdmodels_core-0.2.7-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cc860ccb29199e230eaaba2b3960cee5a56addacd7320e27c1d83c6333ac755a", size = 2413826, upload-time = "2025-09-24T10:52:56.287Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c8/ef58e727af898d67963a6fe03064d678b454f72085674f78362896fdcdf4/mdmodels_core-0.2.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7322d0c156901c60b0011406cab3844f5045590fd2affc58b49f31b8373665c4", size = 2787702, upload-time = "2025-09-24T10:53:10.792Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a4/326869bba6711494493606dd2ab718fc60705b8e3c6f02aa4ac8dd138a2e/mdmodels_core-0.2.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:680bac28dff7baa562e7c40e6bd7dcd5b05be90d14b8fc9811eddf758e9f9df5", size = 2509957, upload-time = "2025-09-24T10:53:36.874Z" }, - { url = "https://files.pythonhosted.org/packages/48/3f/d58e868ee47070a896932967445c9238c10c2e5ad514ff2e9e3f0ea69102/mdmodels_core-0.2.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1f4540fc33395d90cfc5e738b9d264a41d166d4f5d9b695c81eeb085167a0f27", size = 2669241, upload-time = "2025-09-24T10:53:25.305Z" }, - { url = "https://files.pythonhosted.org/packages/37/b8/585fbfe698a272a0cc5777ba6e77494ebe6b3eac60f14d3d54656356ab84/mdmodels_core-0.2.7-cp313-cp313-win_amd64.whl", hash = "sha256:7a9082dc5a1391d168058ed22361e89eea286a127dd70e20dcc148e047cb459c", size = 2060541, upload-time = "2025-09-24T10:54:01.959Z" }, - { url = "https://files.pythonhosted.org/packages/53/d5/8e5ea53e2aa7358476c332c46be4cc0a5f4d07610347f41d0de84f4e1bc3/mdmodels_core-0.2.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ac610d20eb45b99d3d308748b36211ee0e15605f5e0c147c68ed0293d050d3b", size = 2476544, upload-time = "2025-09-24T10:52:41.647Z" }, - { url = "https://files.pythonhosted.org/packages/3d/2c/89ca6391c1021f5a8a235daa52564609b83b60231113a0c8876a43ee7c6b/mdmodels_core-0.2.7-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b74bdee8da5280ee621885eb23fc42decc27e06e485ebeec4fa8f7d2f12d79fe", size = 2413302, upload-time = "2025-09-24T10:52:57.521Z" }, - { url = "https://files.pythonhosted.org/packages/4f/88/a4f8b15d0728e1355b28e6efd02e22b0b2624ddf5a8701e6032b1e4b8e5b/mdmodels_core-0.2.7-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4b9043a494202e4c168d9892fcb536d7cdc3a091515f9d59eaa701f9bbdd49b", size = 2788129, upload-time = "2025-09-24T10:53:12.033Z" }, - { url = "https://files.pythonhosted.org/packages/f3/3c/c8c0eb696ced23d9f49eea23d461dd45da9c2cbb88c11bf27ecd6b1d3d2f/mdmodels_core-0.2.7-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ea398e34f13c1c82429dc3c39293b73519ed72fc5f72178b32aa7988d24ca3f", size = 2507619, upload-time = "2025-09-24T10:53:38.199Z" }, - { url = "https://files.pythonhosted.org/packages/ee/47/ec8f74b31de2d7ae7061bdee5e1cef30a6b674d25d5652c4deafee27ed39/mdmodels_core-0.2.7-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f4117dc9bc5cc53ea08585b418d3673613498d2458444310d07310fab79de379", size = 2671244, upload-time = "2025-09-24T10:53:26.753Z" }, - { url = "https://files.pythonhosted.org/packages/d8/dc/f5bdc75b5780977754f6127d0532ab03e82548e45e94dfb83fb5c1f853ff/mdmodels_core-0.2.7-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:615ff91d8b5097ff0e55b32a730f1996d331782470a3764d57ec3c6f22d298bd", size = 2476966, upload-time = "2025-09-24T10:52:49.174Z" }, - { url = "https://files.pythonhosted.org/packages/8b/3d/e3b99aa683697372d3693f69ccbd5de85231f3ca738e92191e1d6e94fa4b/mdmodels_core-0.2.7-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:41a6ffa8ede702236ea4908ecd028a480edfe7e946158b6562ef231f1125c9c1", size = 2409961, upload-time = "2025-09-24T10:53:03.525Z" }, - { url = "https://files.pythonhosted.org/packages/69/9f/712a56acd641e781ba8648386aa4139def8b0cfba0375c505f4ac570f6e8/mdmodels_core-0.2.7-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da40ceffaef3fbc9d4bd39d7a1dbf7a00e799859ccc02cd84bc8e990a006b5b4", size = 2787086, upload-time = "2025-09-24T10:53:17.731Z" }, - { url = "https://files.pythonhosted.org/packages/69/9a/fad040f708e6a6190950f6872ef78133e5d1e31b9930c06ea114153d044b/mdmodels_core-0.2.7-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf19c3d93d4e6fc8cd8e11659fee9eaad2c2aa6b234c321a775ff519adad1f96", size = 2510249, upload-time = "2025-09-24T10:53:42.644Z" }, - { url = "https://files.pythonhosted.org/packages/84/7c/53504ad1b1624244789cc29bb81f50a61016c9b7c66dc25ddd4a5ed1a498/mdmodels_core-0.2.7-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d73444d5cf988557a9c9cabc8e63c553868b3b59de989cbd81afadd7f9eb18e", size = 2665968, upload-time = "2025-09-24T10:53:31.47Z" }, +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/72/950f28e27988a0220f2ad4998772fa02baff17e2d6c7442dd27099898072/mdmodels_core-0.3.0.tar.gz", hash = "sha256:c06f22c1b073f0a72c66f122cfcc3696dfbb4d992f0c1e1bcaf82616204d50d8", size = 232481, upload-time = "2026-10-11T15:53:47.556Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/b7/1cbb3194032ad73eb2d5a06932eb602e5883db8033ffa98fde18e3bc14c2/mdmodels_core-0.3.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdd321c2e2476f02a6e44e046fef0fe1dd0fdb449d4168d26d2072274fa70e9f", size = 6178234, upload-time = "2026-10-11T15:53:41.633Z" }, + { url = "https://files.pythonhosted.org/packages/19/c8/1f0eeea24355763736b023d687f231eb8cb0c1e38b9cb62f4b1887859adc/mdmodels_core-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:63ce8d4aca2298b86c7e142294215eb91de45c7041a54f239d8e344e1ccb058f", size = 6071991, upload-time = "2026-10-11T15:53:33.554Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6d/052855c028939c0c3f026cdbecc16de9284e12cb62635f21e2e1197d2c3c/mdmodels_core-0.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1af50ffda8628ec90d76fc18d94907955a767e513cb9b6d86ccd1ae13f6fb2af", size = 7285606, upload-time = "2026-10-11T15:52:59.259Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8e/b82d3ebefef079a9d5629b9d82664c823b6d39a49d1a61624c41a4f101fc/mdmodels_core-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff1c0e0856c27f7787147d91113a68be1ab917b3f26a870807fdc6b5ddbcc1d1", size = 6710389, upload-time = "2026-10-11T15:53:17.409Z" }, + { url = "https://files.pythonhosted.org/packages/c5/c8/7bedd6c643d626a3e87ae58b062a618777128ad40e885f2a5b4e880aae07/mdmodels_core-0.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:67d9001db8fc8e8011e2858c20819ecbe995c81eb16227b133f1c745efcd3fc3", size = 6970359, upload-time = "2026-10-11T15:52:43.367Z" }, + { url = "https://files.pythonhosted.org/packages/60/6a/97ef54eff77a02e2179db56fee2827566cb7d27340c35a5d611b8367ec2f/mdmodels_core-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:07c7c5ffe79594e2a73a25a9819f31ef5a35a8de07194eb4b5cb8fe7429c2e84", size = 5787834, upload-time = "2026-10-11T15:53:50.443Z" }, + { url = "https://files.pythonhosted.org/packages/56/bf/9a38095410f702fc815976cdfbf1bf3dc455384d65a0b06657653b8180e7/mdmodels_core-0.3.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8add412f06dd3e938aad84de484414486cc9482e2a593797ab17913e200eb231", size = 6174289, upload-time = "2026-10-11T15:53:43.357Z" }, + { url = "https://files.pythonhosted.org/packages/82/dd/78b65d389ee6e9fae23163e2e11ea0b0bf177cee3806fe85652cafbf391f/mdmodels_core-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:74dc36aacf89628734c8b531911ee2b40f24f2f51534bcda9c2804dee692637b", size = 6069995, upload-time = "2026-10-11T15:53:35.245Z" }, + { url = "https://files.pythonhosted.org/packages/10/df/3b83d43928093fb862f363f73d3c2c5ebea3918eb078ca957652380350b7/mdmodels_core-0.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dd38e9931fe33610a9f2e321ed1c6c1ecff72ffb22cdc2a1f0740b8ab282e79", size = 7283350, upload-time = "2026-10-11T15:53:01.021Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ef/b39a0ced1344af3346c528224335de7e181248c551a0cfbe0b400c8b3a97/mdmodels_core-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8847dca503ff70ecb098393304b13d63c5b81c1e9aee3a0d491a04cdcc0e6fce", size = 6716697, upload-time = "2026-10-11T15:53:18.835Z" }, + { url = "https://files.pythonhosted.org/packages/62/11/b7f258ca0e09cedde46c32afdc18ee3aa565874ef1d83d7dcc2731a2976e/mdmodels_core-0.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:4cc746ccdf1dedddf9b0840e8922cbdad944782acf1618725668467f4d554d4b", size = 6977676, upload-time = "2026-10-11T15:52:45.025Z" }, + { url = "https://files.pythonhosted.org/packages/1a/e8/f49ba3f9a2e26d8223260ddf754192bad76c4e47fa0bf50fd49383602be4/mdmodels_core-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b1303ceba652f87fab9a2ab5ce3af0bc3d4997d2d5128a459aff82b82d43943d", size = 5787065, upload-time = "2026-10-11T15:53:52.255Z" }, + { url = "https://files.pythonhosted.org/packages/1c/58/f8e0d9edb9bf3e8bbda6bc2c589587493109c09c1df495a0d0aaf63d1766/mdmodels_core-0.3.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:12cfcdc37c0731dafdfaa913f63035b60d4afdf1956491fedff3e966f8b61de6", size = 6173564, upload-time = "2026-10-11T15:53:44.892Z" }, + { url = "https://files.pythonhosted.org/packages/69/7e/dfa71fac6b04163910b9ee56a46ca4a926375e7e7689a4cc809d1bf54756/mdmodels_core-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f6c72552a5ad2cd22aa1972317f4f52833f9c5867edbe004fab4f36752cd8453", size = 6069570, upload-time = "2026-10-11T15:53:37.228Z" }, + { url = "https://files.pythonhosted.org/packages/35/74/9f62a40e010c901738832aeac548c55dc2477f2a60e9d1440114bd1c9ba4/mdmodels_core-0.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:976fdba87e6429b358a0017ea8272820866fb2baf0c78f32b5cbd148941dcc8c", size = 7283399, upload-time = "2026-10-11T15:53:02.684Z" }, + { url = "https://files.pythonhosted.org/packages/63/2a/5e666e4316f1d962825486dc2e33cc11d76bbe6cc83d154de95c3301d543/mdmodels_core-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23df994edd1e52bf382b79b64714043b8ddec36eb69635dec1166de489fe9dfb", size = 6715948, upload-time = "2026-10-11T15:53:20.439Z" }, + { url = "https://files.pythonhosted.org/packages/2c/16/8aa6f4faf86c2350e192b28d732af672b7c71f69d14163b03aac2d931dd0/mdmodels_core-0.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c3e1b0818d6449e5f712416853105466316a942e445136dcb051117196d00e7e", size = 6976320, upload-time = "2026-10-11T15:52:46.86Z" }, + { url = "https://files.pythonhosted.org/packages/43/0e/893628812477123c529b59b9c6d2f6b59a9b2bf7b3edcbe239f7e22f83cf/mdmodels_core-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:687e6dbb1d7d1c422bdffef3d78bcc7880b0e9abcd838bfaa541829e22f0486c", size = 5786135, upload-time = "2026-10-11T15:53:53.637Z" }, + { url = "https://files.pythonhosted.org/packages/60/1e/c902bc536b22ec1b12a7c6d7ddf4c7cdc55170721f29342660a10326a654/mdmodels_core-0.3.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:8313bd2bbf55248fc7ad342057bd07aa0f632e0e5cf86d45290a5ee2c755f58b", size = 6170881, upload-time = "2026-10-11T15:53:46.237Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/83ec9f25d8dd3d87f7a7700558822411cea0c953602bfe4ba52c5ea1f329/mdmodels_core-0.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3f9ac6cdd11bbf2fc70a0a20748aba006d2e17686540587ee26e24c383bd6287", size = 6069037, upload-time = "2026-10-11T15:53:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/b0/0b/28604d76d74e3ce8afe3da2095e0967c1e909b4327eec31bbdfe350cc458/mdmodels_core-0.3.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c269db4eb0a11cb0b529b95576d0dcc5ab2172d1d9a163fbb238154ea9712096", size = 7282658, upload-time = "2026-10-11T15:53:04.423Z" }, + { url = "https://files.pythonhosted.org/packages/03/b9/c6cd0959b71b5dcdfbd9ccd71d1dd4370d534c74f51102d101e1fa547fa4/mdmodels_core-0.3.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e43e0d9d76ed6ea76175d4743036881af88f26942913c91eea31b192e3b0ff8", size = 6703846, upload-time = "2026-10-11T15:53:22.332Z" }, + { url = "https://files.pythonhosted.org/packages/4b/bc/9dae07951c07d6a903ed74d9334e6f6da39cf228139dbb445dcd1ebfd920/mdmodels_core-0.3.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:4a39aedfadb7bc94e8e7f1115a921bdd0855c2b26e9e6bcaf1661b141efc960f", size = 6966231, upload-time = "2026-10-11T15:52:48.388Z" }, + { url = "https://files.pythonhosted.org/packages/94/7d/c4b5af5be144a71c412990ad8215d5770e5aca071e29252f3b8d876c0938/mdmodels_core-0.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:7a1a70a69f7f041e8dc39bf8c761f7ac7bff5501790bf540a5f22cd2d0732205", size = 5782181, upload-time = "2026-10-11T15:53:55.436Z" }, + { url = "https://files.pythonhosted.org/packages/65/4e/91bc6e6b12703cf11ad661e535b3a08a3a254c9b2049c0976badb47715d4/mdmodels_core-0.3.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7028ba383d800fb9174b0eb7be6b8c599476b54a5b94b4cef70a7d3fd575941", size = 7283824, upload-time = "2026-10-11T15:53:06.148Z" }, + { url = "https://files.pythonhosted.org/packages/e2/07/5faf5198d4503f06885513ed6a0464df9220bbb7192a71488afe3c608389/mdmodels_core-0.3.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fbd97b18bf70f25f35e3a71b177a0d3aa614e79d99f15ddb17c1110f4d96d5b", size = 6701398, upload-time = "2026-10-11T15:53:23.821Z" }, + { url = "https://files.pythonhosted.org/packages/93/97/a54b6307067f1b52d34e042f25b082f7c918e32b539ff49a0a0401224aa1/mdmodels_core-0.3.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2403c18d1c1ecae12344667acbb81da2e87433855f258c13991555bea056152b", size = 6963494, upload-time = "2026-10-11T15:52:49.998Z" }, + { url = "https://files.pythonhosted.org/packages/79/bb/d96928582244eb1f0dc135b12845182e6cce5eb8cfc97963b6fe4fa8184f/mdmodels_core-0.3.0-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f45c75eacc4ff263a06d57984b6bbc19830698cf3595fa7ef5fa8d40703a0ec4", size = 7282905, upload-time = "2026-10-11T15:53:09.032Z" }, + { url = "https://files.pythonhosted.org/packages/82/59/31701ec6da98cb19c95685d320e3a7b6a27363fd6eec2303e7037f373045/mdmodels_core-0.3.0-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1946732cec00ab48b342821f0e4f92807107cb99ffb6cfd31b06e02c709b8e1", size = 6703853, upload-time = "2026-10-11T15:53:25.28Z" }, + { url = "https://files.pythonhosted.org/packages/58/cb/a4e255cd7a103a3e1fd36bce339b924f28fc568ad041635ebc335e5c7b71/mdmodels_core-0.3.0-cp315-cp315t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01af75d4a5e6c4fe471c68ac30ebceeeaf1bbcb6a119af65f40d998dd2e69b38", size = 7283596, upload-time = "2026-10-11T15:53:10.981Z" }, + { url = "https://files.pythonhosted.org/packages/cf/11/9994b2a321c2bf82559e27b425ffaffee87887fb1ba7e2c7d8ef95b08032/mdmodels_core-0.3.0-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fe5c15b97c969e166147c3295b1ec564149732a0d367380f84b2f19427a8d4a", size = 6701443, upload-time = "2026-10-11T15:53:26.736Z" }, + { url = "https://files.pythonhosted.org/packages/d6/4b/3c0949ab26526545c7f97adc492e499068156d15639a8d185d21fc9550bd/mdmodels_core-0.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49c31f3fcc21b73e29a3a129e33f69b064974432d62c7044758e36704f4033f0", size = 7287671, upload-time = "2026-10-11T15:53:14.006Z" }, + { url = "https://files.pythonhosted.org/packages/4c/c5/722b074c9ba3fbd998aff1897dffa170ea9f7610f6142525f6ba199e3e84/mdmodels_core-0.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675e975ddda3316e70179f6dd2bbca1ca673aa7df31ea33b44c53bb55abaf98b", size = 6712337, upload-time = "2026-10-11T15:53:30.443Z" }, + { url = "https://files.pythonhosted.org/packages/7c/20/b1c84156a4377ab624b359a4d31b740dc0a94942219808fd53eeb5abff77/mdmodels_core-0.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:641b0eef2cea65160e5c3a2271332d22d4c29348fc0441f4495364dbdece82c7", size = 6968024, upload-time = "2026-10-11T15:52:55.251Z" }, ] [[package]] @@ -1337,6 +1385,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "polars" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "polars-runtime-32" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/e9/001f371ec6a1bb54893f599ceebd56e6144fed4091f09f09fec0021a9276/polars-2.0.0.tar.gz", hash = "sha256:62da109e27a19a9d36657ee25dc035c9d3f87e7bd610526fe467dc37ea7dc115", size = 778215, upload-time = "2026-10-06T11:51:29.679Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/09/cc33bbd5463749c116b62c204d88bed6c02a6cb901eac7adab0d38651b07/polars-2.0.0-py3-none-any.whl", hash = "sha256:35d62f3541b7a6d4c360a2e2f07fccc0c2bcbd33b0ea51c83a25417a47a3f3ad", size = 876611, upload-time = "2026-10-06T11:44:04.327Z" }, +] + +[[package]] +name = "polars-runtime-32" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/34/ad/dbb6f6d7070867951532bcfe5e6a648d8777b416b18cddabc07030404e8c/polars_runtime_32-2.0.0.tar.gz", hash = "sha256:b5f9afcc742b4a67eabd2c680ff0f12eb02ede9b4bf807bffabd6dbb9a58d5c7", size = 3591339, upload-time = "2026-10-06T11:51:31.076Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/88/d35dec6c8928dfbaa1cccf9b626a1067da906e792c92d9f994ca825ab2b5/polars_runtime_32-2.0.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ffb7ac6cf4e8c4a652df1951e3c3840c7c23a033603d5a9efd422fa8dd699d82", size = 52494314, upload-time = "2026-10-06T11:44:07.768Z" }, + { url = "https://files.pythonhosted.org/packages/5f/fd/2237bf53ffaff47cdf1edc6c10587a7a6444d4951150eeb08d84f3493ff8/polars_runtime_32-2.0.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:7012d8a0201bd95638545ce8f256c0efe2c5cab0f806eb043021dddde5a9498b", size = 47930083, upload-time = "2026-10-06T11:44:11.592Z" }, + { url = "https://files.pythonhosted.org/packages/0d/0d/85e3ed90417996fc09770be91b39979074fe2978fc15b431bf8a9459760d/polars_runtime_32-2.0.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b85bb42e6009acc9629afcc70a83473fd468694d6a30ffb0ab376c8dd1a0a17", size = 50417889, upload-time = "2026-10-06T11:50:20.774Z" }, + { url = "https://files.pythonhosted.org/packages/83/88/e9fecfd49159da92f54ff2445883577a0f1bc195da53ecc9535c458d55dd/polars_runtime_32-2.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d6ac584ea2b38913784db943879412380d92e28ab9cb88e20a77ba71ba3f911", size = 54475036, upload-time = "2026-10-06T11:50:24.411Z" }, + { url = "https://files.pythonhosted.org/packages/48/ad/b2abf732697b21467aaaeaac0f3bf7eee0d89c59ce8125f1ed41b28a2d97/polars_runtime_32-2.0.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a6bf5e260e0a6f00d0f9181438fe9e45776df8c66cee9cba16e3675cc3888488", size = 50579474, upload-time = "2026-10-06T11:50:28.377Z" }, + { url = "https://files.pythonhosted.org/packages/7f/05/304deee59a95865e1b5e9ec7b066069b49093b81b768f473d9d3b165c686/polars_runtime_32-2.0.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55c26eef325b6840584d91aac232e9cf3ac19e1b904594b9b54131be1edeab4d", size = 54413293, upload-time = "2026-10-06T11:50:31.828Z" }, + { url = "https://files.pythonhosted.org/packages/61/59/8c9fd7199f7c4eb1b64e640306a946a2e4a46337b3bbb33b840972c7d84b/polars_runtime_32-2.0.0-cp310-abi3-win_amd64.whl", hash = "sha256:7da1caf3c7b4f397fb213c984013a0c755557619a2d511899a1ff74392484078", size = 54229989, upload-time = "2026-10-06T11:50:35.206Z" }, + { url = "https://files.pythonhosted.org/packages/e2/93/43608026f38aa6ed4d22da8597706a61682ee403caef0021ce8e6dc73227/polars_runtime_32-2.0.0-cp310-abi3-win_arm64.whl", hash = "sha256:c30ba698c8904048df4a9bc3d6c5033cc2d0a7cbb0e13f4fd2de5a1947b61994", size = 48730655, upload-time = "2026-10-06T11:50:38.756Z" }, +] + [[package]] name = "pronto" version = "2.7.3" @@ -1535,7 +1611,7 @@ requires-dist = [ { name = "lmfit", marker = "extra == 'pysces'", specifier = ">=1.3.3,<2" }, { name = "loguru", specifier = ">=0.7.2,<0.8" }, { name = "matplotlib", specifier = ">=3.10,<4" }, - { name = "mdmodels", specifier = ">=0.2.4,<0.3" }, + { name = "mdmodels", specifier = ">=0.4.0,<0.5" }, { name = "numexpr", marker = "extra == 'v1'", specifier = ">=2.11.0,<3" }, { name = "openpyxl", marker = "extra == 'excel'", specifier = ">=3.1.4,<4" }, { name = "pandas", specifier = ">=2.0.0" }, @@ -1728,6 +1804,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-dotenv" +version = "1.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/26/2fbeedb218a787a5eea551c7532cac4e009f83d689dd2faa0d0353473f86/python_dotenv-1.2.4.tar.gz", hash = "sha256:f0d53e69935a851c0dcc78f3ab7aaccd8cabef0b92382b576b824212902873c0", size = 60824, upload-time = "2026-10-01T05:36:10Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/d1/38f3a3405989a89ac18390803e70c6ad7c7760da4f9b83cbeca0c44a0c72/python_dotenv-1.2.4-py3-none-any.whl", hash = "sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc", size = 23266, upload-time = "2026-10-01T05:36:08.633Z" }, +] + [[package]] name = "python-forge" version = "18.6.0" @@ -2005,6 +2090,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, ] +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + [[package]] name = "six" version = "1.17.0" @@ -2035,6 +2129,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, +] + [[package]] name = "tornado" version = "6.5.4" @@ -2054,6 +2157,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, ] +[[package]] +name = "typer" +version = "0.27.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "rich" }, + { name = "shellingham" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/51/d33db42cc72ffd8c30777547b42d01f0cbf9d95a770457698d0174b3ed71/typer-0.27.3.tar.gz", hash = "sha256:d0396f770a560ab1b0a8504e13b5f254b728cedb05c61cf0359e944e50ce8901", size = 205303, upload-time = "2026-10-06T17:24:16.61Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/ea/2e31b67051e91a133189e9c000c222502ddc6969856416de0d095de4c0b0/typer-0.27.3-py3-none-any.whl", hash = "sha256:e50022f28b82a86313e54501317a1db64bf8f8d036ff8cfe5ca7e47675454aff", size = 123312, upload-time = "2026-10-06T17:24:15.054Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0"