diff --git a/nomenclature/__init__.py b/nomenclature/__init__.py index d4b695ad..1f4fb850 100644 --- a/nomenclature/__init__.py +++ b/nomenclature/__init__.py @@ -1,6 +1,5 @@ import logging from importlib.metadata import version -from pathlib import Path import yaml @@ -10,7 +9,7 @@ from nomenclature.countries import countries # noqa from nomenclature.definition import SPECIAL_CODELIST, DataStructureDefinition # noqa from nomenclature.processor import RegionAggregationMapping # noqa -from nomenclature.processor import RegionProcessor, RequiredDataValidator +from nomenclature.processor import RegionProcessor, RequiredDataValidator # noqa # set up logging logging.basicConfig( diff --git a/nomenclature/code.py b/nomenclature/code.py index 499a2a87..a02350ac 100644 --- a/nomenclature/code.py +++ b/nomenclature/code.py @@ -3,8 +3,8 @@ import pycountry from keyword import iskeyword from pathlib import Path -from typing import Any, Dict, List, Optional, Set, Union -from pydantic import BaseModel, Field, validator +from typing import Any, Dict, List, Set, Union +from pydantic import field_validator, ConfigDict, BaseModel, Field, ValidationInfo from pyam.utils import to_list @@ -13,24 +13,25 @@ class Code(BaseModel): """A simple class for a mapping of a "code" to its attributes""" name: str - description: Optional[str] - file: Optional[Union[str, Path]] = None + description: str | None = None + file: Union[str, Path] | None = None extra_attributes: Dict[str, Any] = {} def __eq__(self, other) -> bool: - return {key: value for key, value in self.dict().items() if key != "file"} == { - key: value for key, value in other.dict().items() if key != "file" - } + return self.model_dump(exclude="file") == other.model_dump(exclude="file") - @validator("extra_attributes") - def check_attribute_names(cls, v, values): + @field_validator("extra_attributes") + @classmethod + def check_attribute_names( + cls, v: Dict[str, Any], info: ValidationInfo + ) -> Dict[str, Any]: # Check that attributes only contains keys which are valid identifiers if illegal_keys := [ key for key in v.keys() if not key.isidentifier() or iskeyword(key) ]: raise ValueError( "Only valid identifiers are allowed as attribute keys. Found " - f"'{illegal_keys}' in '{values['name']}' which are not allowed." + f"'{illegal_keys}' in '{info.data['name']}' which are not allowed." ) return v @@ -68,7 +69,7 @@ def from_dict(cls, mapping) -> "Code": @classmethod def named_attributes(cls) -> Set[str]: - return {a for a in cls.__dict__["__fields__"].keys() if a != "extra_attributes"} + return {a for a in cls.model_fields if a != "extra_attributes"} @property def contains_tags(self) -> bool: @@ -80,15 +81,10 @@ def tags(self): @property def flattened_dict(self): - fields_set_alias = { - self.__fields__[field].alias for field in self.__fields_set__ - } return { - **{ - k: v - for k, v in self.dict(by_alias=True).items() - if k != "extra_attributes" and k in fields_set_alias - }, + **self.model_dump( + by_alias=True, exclude_unset=True, exclude="extra_attributes" + ), **self.extra_attributes, } @@ -148,25 +144,20 @@ def __setattr__(self, name, value): class VariableCode(Code): - unit: Optional[Union[str, List[str]]] = Field(...) - weight: Optional[str] = None - region_aggregation: Optional[List[Dict[str, Dict]]] = Field( + unit: Union[str, List[str]] | None = Field(...) + weight: str | None = None + region_aggregation: List[Dict[str, Dict]] | None = Field( None, alias="region-aggregation" ) - skip_region_aggregation: Optional[bool] = Field( - False, alias="skip-region-aggregation" - ) - method: Optional[str] = None - check_aggregate: Optional[bool] = Field(False, alias="check-aggregate") - components: Optional[Union[List[str], List[Dict[str, List[str]]]]] = None - drop_negative_weights: Optional[bool] = None - - class Config: - # this allows using both "check_aggregate" and "check-aggregate" for attribute - # setting - allow_population_by_field_name = True - - @validator("region_aggregation", "components", "unit", pre=True) + skip_region_aggregation: bool | None = Field(False, alias="skip-region-aggregation") + method: str | None = None + check_aggregate: bool | None = Field(False, alias="check-aggregate") + components: Union[List[str], List[Dict[str, List[str]]]] | None = None + drop_negative_weights: bool | None = None + model_config = ConfigDict(populate_by_name=True) + + @field_validator("region_aggregation", "components", "unit", mode="before") + @classmethod def deserialize_json(cls, v): try: return json.loads(v) if isinstance(v, str) else v @@ -180,9 +171,7 @@ def units(self) -> List[Union[str, None]]: @classmethod def named_attributes(cls) -> Set[str]: return ( - super() - .named_attributes() - .union(f.alias for f in cls.__dict__["__fields__"].values()) + super().named_attributes().union(f.alias for f in cls.model_fields.values()) ) @property @@ -225,8 +214,8 @@ class RegionCode(Code): hierarchy: str = None iso3_codes: Union[List[str], str] = None - @validator("iso3_codes") - def check_iso3_codes(cls, v, values) -> List[str]: + @field_validator("iso3_codes") + def check_iso3_codes(cls, v: List[str], info: ValidationInfo) -> List[str]: """Verifies that each ISO3 code is valid according to pycountry library.""" if invalid_iso3_codes := [ iso3_code @@ -234,7 +223,7 @@ def check_iso3_codes(cls, v, values) -> List[str]: if pycountry.countries.get(alpha_3=iso3_code) is None ]: raise ValueError( - f"Region '{values['name']}' has invalid ISO3 country code(s): " + f"Region '{info.data['name']}' has invalid ISO3 country code(s): " + ", ".join(invalid_iso3_codes) ) return v @@ -250,4 +239,4 @@ class MetaCode(Code): """ - allowed_values: Optional[List[Any]] + allowed_values: List[Any] | None = None diff --git a/nomenclature/codelist.py b/nomenclature/codelist.py index 5ba4e0fa..f4b00cd3 100644 --- a/nomenclature/codelist.py +++ b/nomenclature/codelist.py @@ -7,17 +7,13 @@ import pandas as pd import yaml from pyam.utils import write_sheet -from pydantic import BaseModel, validator +from pydantic import field_validator, BaseModel, ValidationInfo +from pydantic_core import PydanticCustomError import nomenclature from nomenclature.code import Code, MetaCode, RegionCode, VariableCode from nomenclature.config import NomenclatureConfig -from nomenclature.error.codelist import DuplicateCodeError -from nomenclature.error.variable import ( - MissingWeightError, - VariableRenameArgError, - VariableRenameTargetError, -) +from nomenclature.error import custom_pydantic_errors from pyam.utils import is_list_like here = Path(__file__).parent.absolute() @@ -45,8 +41,9 @@ class CodeList(BaseModel): def __eq__(self, other): return self.name == other.name and self.mapping == other.mapping - @validator("mapping") - def check_stray_tag(cls, v): + @field_validator("mapping") + @classmethod + def check_stray_tag(cls, v: Dict[str, Code]) -> Dict[str, Code]: """Check that no '{' are left in codes after tag replacement""" for code in v: if "{" in code: @@ -56,20 +53,22 @@ def check_stray_tag(cls, v): ) return v - @validator("mapping") - def check_end_whitespace(cls, v, values): + @field_validator("mapping") + def check_end_whitespace( + cls, v: Dict[str, Code], info: ValidationInfo + ) -> Dict[str, Code]: """Check that no code ends with a whitespace""" for code in v: if code.endswith(" "): raise ValueError( - f"Unexpected whitespace at the end of a {values['name']}" + f"Unexpected whitespace at the end of a {info.data['name']}" f" code: '{code}'." ) return v def __setitem__(self, key, value): if key in self.mapping: - raise DuplicateCodeError(name=self.name, code=key) + raise ValueError(f"Duplicate item in {self.name} codelist: {key}") self.mapping[key] = value def __getitem__(self, k): @@ -154,7 +153,7 @@ def _parse_and_replace_tags( for tag in _tag_list: tag_name = next(iter(tag)) if tag_name in tag_dict: - raise DuplicateCodeError(name="tag", code=tag_name) + raise ValueError(f"Duplicate item in tag codelist: {tag_name}") tag_dict[tag_name] = [Code.from_dict(t) for t in tag[tag_name]] # start with all non tag codes @@ -213,7 +212,7 @@ def from_directory( mapping: Dict[str, Code] = {} for code in code_list: if code.name in mapping: - raise DuplicateCodeError(name=name, code=code.name) + raise ValueError(f"Duplicate item in {name} codelist: {code.name}") mapping[code.name] = code return cls(name=name, mapping=mapping) @@ -469,7 +468,8 @@ def to_dimensionless(u): return sorted(list(units)) - @validator("mapping") + @field_validator("mapping") + @classmethod def check_variable_region_aggregation_args(cls, v): """Check that any variable "region-aggregation" mappings are valid""" @@ -478,10 +478,9 @@ def check_variable_region_aggregation_args(cls, v): # pyam-aggregation-kwargs and a 'region-aggregation' attribute if var.region_aggregation is not None: if conflict_args := list(var.pyam_agg_kwargs.keys()): - raise VariableRenameArgError( - variable=var.name, - file=var.file, - args=conflict_args, + raise PydanticCustomError( + *custom_pydantic_errors.VariableRenameArgError, + {"variable": var.name, "file": var.file, "args": conflict_args}, ) # ensure that mapped variables are defined in the nomenclature @@ -489,12 +488,14 @@ def check_variable_region_aggregation_args(cls, v): for inst in var.region_aggregation: invalid.extend(var for var in inst if var not in v) if invalid: - raise VariableRenameTargetError( - variable=var.name, file=var.file, target=invalid + raise PydanticCustomError( + *custom_pydantic_errors.VariableRenameTargetError, + {"variable": var.name, "file": var.file, "target": invalid}, ) return v - @validator("mapping") + @field_validator("mapping") + @classmethod def check_weight_in_vars(cls, v): """Check that all variables specified in 'weight' are present in the codelist""" if missing_weights := [ @@ -502,15 +503,19 @@ def check_weight_in_vars(cls, v): for var in v.values() if var.weight is not None and var.weight not in v ]: - raise MissingWeightError( - missing_weights="".join( - f"'{weight}' used for '{var}' in: {file}\n" - for var, weight, file in missing_weights - ) + raise PydanticCustomError( + *custom_pydantic_errors.MissingWeightError, + { + "missing_weights": "".join( + f"'{weight}' used for '{var}' in: {file}\n" + for var, weight, file in missing_weights + ) + }, ) return v - @validator("mapping") + @field_validator("mapping") + @classmethod def cast_variable_components_args(cls, v): """Cast "components" list of dicts to a codelist""" diff --git a/nomenclature/config.py b/nomenclature/config.py index 19de636c..8295a835 100644 --- a/nomenclature/config.py +++ b/nomenclature/config.py @@ -1,23 +1,21 @@ from pathlib import Path -from typing import Optional, Dict -from pydantic import BaseModel, root_validator, validator +from typing import Dict, Optional import yaml from git import Repo +from pydantic import BaseModel, ValidationInfo, field_validator, model_validator class CodeListConfig(BaseModel): dimension: str - repository: Optional[str] - repository_dimension_path: Optional[Path] - - @root_validator() - def set_repository_dimension_path(cls, v): - if ( - v.get("repository") is not None - and v.get("repository_dimension_path") is None - ): - v["repository_dimension_path"] = f"definitions/{v['dimension']}" + repository: str | None = None + repository_dimension_path: Path | None = None + + @model_validator(mode="after") + @classmethod + def set_repository_dimension_path(cls, v: "CodeListConfig") -> "CodeListConfig": + if v.repository is not None and v.repository_dimension_path is None: + v.repository_dimension_path = f"definitions/{v.dimension}" return v @@ -27,17 +25,21 @@ class RegionCodeListConfig(CodeListConfig): class Repository(BaseModel): url: str - hash: Optional[str] - release: Optional[str] - local_path: Optional[Path] # defined via the `repository` name in the configuration + hash: str | None = None + release: str | None = None + local_path: Path | None = ( + None # defined via the `repository` name in the configuration + ) - @root_validator() - def check_hash_and_release(cls, v): - if v.get("hash") and v.get("release"): + @model_validator(mode="after") + @classmethod + def check_hash_and_release(cls, v: "Repository") -> "Repository": + if v.hash and v.release: raise ValueError("Either `hash` or `release` can be provided, not both.") return v - @validator("local_path") + @field_validator("local_path") + @classmethod def check_path_empty(cls, v): if v is not None: raise ValueError("The `local_path` must not be set as part of the config.") @@ -74,29 +76,13 @@ class DataStructureConfig(BaseModel): """ - region: Optional[RegionCodeListConfig] - variable: Optional[CodeListConfig] - - @validator("region", "variable", pre=True) - def add_dimension(cls, v, field): - return {"dimension": field.name, **v} - - @root_validator - def check_repository_consistency(cls, values): - for dimension in ("region", "variable"): - if ( - values.get("repository") - and values.get(dimension) - and values.get(dimension).repository - and values.get(dimension).repository not in values.get("repository") - ): - raise ValueError( - ( - f"Unknown repository '{values.get(dimension).repository}' in" - f" {dimension}.repository." - ) - ) - return values + region: Optional[RegionCodeListConfig] = None + variable: Optional[CodeListConfig] = None + + @field_validator("region", "variable", mode="before") + @classmethod + def add_dimension(cls, v, info: ValidationInfo): + return {"dimension": info.field_name, **v} @property def repos(self) -> Dict[str, str]: @@ -113,17 +99,18 @@ class RegionMappingConfig(BaseModel): class NomenclatureConfig(BaseModel): repositories: Dict[str, Repository] = {} - definitions: Optional[DataStructureConfig] - mappings: Optional[RegionMappingConfig] - - @root_validator - def check_definitions_repository(cls, v): - definitions_repos = v.get("definitions").repos if v.get("definitions") else {} - mapping_repos = ( - {"mappings": v.get("mappings").repository} if v.get("mappings") else {} - ) + definitions: Optional[DataStructureConfig] = None + mappings: Optional[RegionMappingConfig] = None + + @model_validator(mode="after") + @classmethod + def check_definitions_repository( + cls, v: "NomenclatureConfig" + ) -> "NomenclatureConfig": + definitions_repos = v.definitions.repos if v.definitions else {} + mapping_repos = {"mappings": v.mappings.repository} if v.mappings else {} repos = {**definitions_repos, **mapping_repos} - if repos and not v.get("repositories"): + if repos and not v.repositories: raise ValueError( ( "If repositories are used for definitions or mappings, they need " @@ -132,7 +119,7 @@ def check_definitions_repository(cls, v): ) for use, repository in repos.items(): - if repository not in v.get("repositories"): + if repository not in v.repositories: raise ValueError((f"Unknown repository '{repository}' in {use}.")) return v diff --git a/nomenclature/core.py b/nomenclature/core.py index c3d8a1e9..4da95f3d 100644 --- a/nomenclature/core.py +++ b/nomenclature/core.py @@ -2,7 +2,7 @@ from typing import Optional, Union, List import pyam -from pydantic import validate_arguments +from pydantic import validate_call from nomenclature.definition import DataStructureDefinition from nomenclature.processor import Processor, RegionProcessor @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) -@validate_arguments(config={"arbitrary_types_allowed": True}) +@validate_call(config={"arbitrary_types_allowed": True}) def process( df: pyam.IamDataFrame, dsd: DataStructureDefinition, diff --git a/nomenclature/error.py b/nomenclature/error.py new file mode 100644 index 00000000..2bf2c6c0 --- /dev/null +++ b/nomenclature/error.py @@ -0,0 +1,63 @@ +from collections import namedtuple + +pydantic_custom_error_config = { + "RegionNameCollisionError": ( + "region_name_collision", + "Name collision in {location} for {duplicates} in {file}", + ), + "ExcludeRegionOverlapError": ( + "exclude_region_overlap", + ( + "Region(s) {region} can only be present in 'exclude_regions' or " + "'{region_type}' in {file}." + ), + ), + "VariableRenameArgError": ( + "variable_rename_conflict", + ( + "Using attribute 'region-aggregation' and arguments {args} not " + "supported, occurred in variable '{variable}' (file: {file})" + ), + ), + "VariableRenameTargetError": ( + "variable_rename_target", + ( + "Region-aggregation-target(s) {target} not defined in the " + "DataStructureDefinition, occurred in variable '{variable}'" + " (file: {file})" + ), + ), + "MissingWeightError": ( + "missing_weight", + ( + "The following variables are used as 'weight' for aggregation but " + "are not defined in the variable codelist:\n{missing_weights}" + ), + ), + "RegionNotDefinedError": ( + "region_not_defined", + "Region(s) {regions} in {file} not found in RegionCodeList", + ), +} + +PydanticCustomErrors = namedtuple("PydanticCustomErrors", pydantic_custom_error_config) +custom_pydantic_errors = PydanticCustomErrors(**pydantic_custom_error_config) + + +class ErrorCollector: + errors: list[Exception] + + def __init__(self) -> None: + self.errors = [] + + def append(self, error: Exception) -> None: + self.errors.append(error) + + def __repr__(self) -> str: + error = "error" if len(self.errors) == 1 else "errors" + return f"Collected {len(self.errors)} {error}:\n" + "\n\t".join( + str(error) for error in self.errors + ) + + def __bool__(self) -> bool: + return bool(self.errors) diff --git a/nomenclature/error/__init__.py b/nomenclature/error/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/nomenclature/error/codelist.py b/nomenclature/error/codelist.py deleted file mode 100644 index 17429502..00000000 --- a/nomenclature/error/codelist.py +++ /dev/null @@ -1,6 +0,0 @@ -from pydantic import PydanticValueError - - -class DuplicateCodeError(PydanticValueError): - code = "duplicate_code" - msg_template = "Duplicate item in {name} codelist: {code}" diff --git a/nomenclature/error/region.py b/nomenclature/error/region.py deleted file mode 100644 index 0f54506f..00000000 --- a/nomenclature/error/region.py +++ /dev/null @@ -1,33 +0,0 @@ -from pydantic import PydanticValueError - - -class RegionNameCollisionError(PydanticValueError): - code = "region_name_collision" - msg_template = "Name collision in {location} for {duplicates} in {file}" - - -class ModelMappingCollisionError(PydanticValueError): - code = "model_mapping_collision" - msg_template = ( - "Multiple region aggregation mappings for model {model} in [{file1}, {file2}]" - ) - - -class RegionNotDefinedError(PydanticValueError): - code = "region_not_defined" - msg_template = ( - "Region(s) {region} in {file} not defined in the DataStructureDefinition" - ) - - -class ExcludeRegionOverlapError(PydanticValueError): - code = "exclude_region_overlap" - msg_template = ( - "Region(s) {region} can only be present in 'exclude_regions' or " - "'{region_type}' in {file}." - ) - - -class RegionAggregationMappingParsingError(PydanticValueError): - code = "model_mapping_parsing" - msg_template = "{error} in {file}" diff --git a/nomenclature/error/required_data.py b/nomenclature/error/required_data.py deleted file mode 100644 index 468fac9a..00000000 --- a/nomenclature/error/required_data.py +++ /dev/null @@ -1,2 +0,0 @@ -class RequiredDataMissingError(ValueError): - pass diff --git a/nomenclature/error/variable.py b/nomenclature/error/variable.py deleted file mode 100644 index 566ccb0d..00000000 --- a/nomenclature/error/variable.py +++ /dev/null @@ -1,25 +0,0 @@ -from pydantic import PydanticValueError - - -class VariableRenameArgError(PydanticValueError): - code = "variable_rename_conflict_error" - msg_template = ( - "Using attribute 'region-aggregation' and arguments {args} not supported, " - "occurred in variable '{variable}' (file: {file})" - ) - - -class VariableRenameTargetError(PydanticValueError): - code = "variable_rename_target_error" - msg_template = ( - "Region-aggregation-target(s) {target} not defined in the " - "DataStructureDefinition, occurred in variable '{variable}' (file: {file})" - ) - - -class MissingWeightError(PydanticValueError): - code = "missing_weight_error" - msg_template = ( - "The following variables are used as 'weight' for aggregation but " - "are not defined in the variable codelist:\n{missing_weights}" - ) diff --git a/nomenclature/processor/region.py b/nomenclature/processor/region.py index 975db427..10d0c61a 100644 --- a/nomenclature/processor/region.py +++ b/nomenclature/processor/region.py @@ -2,28 +2,29 @@ from collections import Counter from pathlib import Path from typing import Dict, List, Optional, Tuple, Union +from typing_extensions import Annotated import numpy as np import pandas as pd import pyam -import pydantic import yaml from pyam import IamDataFrame from pyam.logging import adjust_log_level -from pydantic import BaseModel, root_validator, validate_arguments, validator -from pydantic.error_wrappers import ErrorWrapper +from pydantic import ( + AfterValidator, + BaseModel, + ConfigDict, + ValidationInfo, + field_validator, + model_validator, + validate_call, +) from pydantic.types import DirectoryPath, FilePath +from pydantic_core import PydanticCustomError from nomenclature.codelist import RegionCodeList, VariableCodeList -from nomenclature.config import NomenclatureConfig from nomenclature.definition import DataStructureDefinition -from nomenclature.error.region import ( - ExcludeRegionOverlapError, - ModelMappingCollisionError, - RegionAggregationMappingParsingError, - RegionNameCollisionError, - RegionNotDefinedError, -) +from nomenclature.error import custom_pydantic_errors, ErrorCollector from nomenclature.processor import Processor from nomenclature.processor.utils import get_relative_path from nomenclature.validation import log_error @@ -47,7 +48,7 @@ class NativeRegion(BaseModel): """ name: str - rename: Optional[str] + rename: Optional[str] = None @property def target_native_region(self) -> str: @@ -116,16 +117,17 @@ class RegionAggregationMapping(BaseModel): model: List[str] file: FilePath - native_regions: Optional[List[NativeRegion]] - common_regions: Optional[List[CommonRegion]] - exclude_regions: Optional[List[str]] + native_regions: List[NativeRegion] | None = None + common_regions: List[CommonRegion] | None = None + exclude_regions: List[str] | None = None - @root_validator(pre=True) + @model_validator(mode="before") + @classmethod def check_no_additional_attributes(cls, v): if illegal_additional_attributes := [ input_attribute for input_attribute in v.keys() - if input_attribute not in cls.__dict__["__fields__"] + if input_attribute not in cls.model_fields ]: raise ValueError( "Illegal attributes in 'RegionAggregationMapping': " @@ -133,89 +135,110 @@ def check_no_additional_attributes(cls, v): ) return v - @validator("model", pre=True) + @field_validator("model", mode="before") + @classmethod def convert_to_list(cls, v): return pyam.utils.to_list(v) - @validator("native_regions") - def validate_native_regions_name(cls, v, values): + @field_validator("native_regions") + def validate_native_regions_name(cls, v, info: ValidationInfo): native_names = [nr.name for nr in v] - duplicates = [ + if duplicates := [ item for item, count in Counter(native_names).items() if count > 1 - ] - if duplicates: + ]: # Raise a RegionNameCollisionError with parameters duplicates and file. - raise RegionNameCollisionError( - location="native regions (names)", - duplicates=duplicates, - file=values["file"], + raise PydanticCustomError( + *custom_pydantic_errors.RegionNameCollisionError, + { + "location": "native regions (names)", + "duplicates": duplicates, + "file": info.data["file"], + }, ) return v - @validator("native_regions") - def validate_native_regions_target(cls, v, values): + @field_validator("native_regions") + def validate_native_regions_target(cls, v, info: ValidationInfo): target_names = [nr.target_native_region for nr in v] duplicates = [ item for item, count in Counter(target_names).items() if count > 1 ] if duplicates: # Raise a RegionNameCollisionError with parameters duplicates and file. - raise RegionNameCollisionError( - location="native regions (rename-targets)", - duplicates=duplicates, - file=values["file"], + raise PydanticCustomError( + *custom_pydantic_errors.RegionNameCollisionError, + { + "location": "native regions (rename-targets)", + "duplicates": duplicates, + "file": info.data["file"], + }, ) return v - @validator("common_regions") - def validate_common_regions(cls, v, values): + @field_validator("common_regions") + def validate_common_regions(cls, v, info: ValidationInfo): names = [cr.name for cr in v] duplicates = [item for item, count in Counter(names).items() if count > 1] if duplicates: - raise RegionNameCollisionError( - location="common regions", duplicates=duplicates, file=values["file"] + raise PydanticCustomError( + *custom_pydantic_errors.RegionNameCollisionError, + { + "location": "common regions", + "duplicates": duplicates, + "file": info.data["file"], + }, ) return v - @root_validator(skip_on_failure=True) - def check_native_or_common_regions(cls, values): + @model_validator(mode="after") + @classmethod + def check_native_or_common_regions( + cls, v: "RegionAggregationMapping" + ) -> "RegionAggregationMapping": # Check that we have at least one of the two: native and common regions - if ( - values.get("native_regions") is None - and values.get("common_regions") is None - ): + if v.native_regions is None and v.common_regions is None: raise ValueError( "At least one of 'native_regions' and 'common_regions' must be " - f"provided in {values['file']}" + f"provided in {v.file}" ) - return values + return v - @root_validator(skip_on_failure=True) - def check_illegal_renaming(cls, values): + @model_validator(mode="after") + @classmethod + def check_illegal_renaming( + cls, v: "RegionAggregationMapping" + ) -> "RegionAggregationMapping": """Check if any renaming overlaps with common regions""" # Skip if only either native-regions or common-regions are specified - if values.get("native_regions") is None or values.get("common_regions") is None: - return values - native_region_names = { - nr.target_native_region for nr in values["native_regions"] - } - common_region_names = {cr.name for cr in values["common_regions"]} + if v.native_regions is None or v.common_regions is None: + return v + native_region_names = {nr.target_native_region for nr in v.native_regions} + common_region_names = {cr.name for cr in v.common_regions} overlap = list(native_region_names & common_region_names) if overlap: - raise RegionNameCollisionError( - location="native and common regions", - duplicates=overlap, - file=values["file"], + raise PydanticCustomError( + *custom_pydantic_errors.RegionNameCollisionError, + { + "location": "native and common regions", + "duplicates": overlap, + "file": v.file, + }, ) - return values + return v - @root_validator(skip_on_failure=True) - def check_exclude_native_region_overlap(cls, values): - return _check_exclude_region_overlap(values, "native_regions") + @model_validator(mode="after") + @classmethod + def check_exclude_native_region_overlap( + cls, v: "RegionAggregationMapping" + ) -> "RegionAggregationMapping": + return _check_exclude_region_overlap(v, "native_regions") - @root_validator(skip_on_failure=True) - def check_exclude_common_region_overlap(cls, values): - return _check_exclude_region_overlap(values, "common_regions") + @model_validator(mode="after") + @classmethod + def check_exclude_common_region_overlap( + cls, v: "RegionAggregationMapping" + ) -> "RegionAggregationMapping": + return _check_exclude_region_overlap(v, "common_regions") @classmethod def from_file(cls, file: Union[Path, str]): @@ -286,9 +309,7 @@ def from_yaml(cls, file: Path) -> "RegionAggregationMapping": ) mapping_input["common_regions"] = common_region_list except Exception as error: - raise RegionAggregationMappingParsingError( - file=get_relative_path(file), error=str(error) - ) from error + raise ValueError(f"{error} in {get_relative_path(file)}") from error return cls(**mapping_input) @classmethod @@ -327,11 +348,8 @@ def from_excel(cls, file) -> "RegionAggregationMapping": .to_dict() .items() ] - # common_regions = [for common_region_group in common_region_groups for ] except Exception as error: - raise RegionAggregationMappingParsingError( - file=get_relative_path(file), error=str(error) - ) from error + raise ValueError(f"{error} in {get_relative_path(file)}") from error return cls( model=model, file=file, @@ -370,10 +388,6 @@ def upload_native_regions(self) -> List[str]: def reverse_rename_mapping(self) -> Dict[str, str]: return {renamed: original for original, renamed in self.rename_mapping.items()} - def validate_regions(self, region_codelist: RegionCodeList) -> None: - if invalid := region_codelist.validate_items(self.all_regions): - raise RegionNotDefinedError(region=invalid, file=self.file) - def check_unexpected_regions(self, df: IamDataFrame) -> None: # Raise error if a region in the input data is not used in the model mapping @@ -396,7 +410,7 @@ def check_unexpected_regions(self, df: IamDataFrame) -> None: ) def __eq__(self, other: "RegionAggregationMapping") -> bool: - return self.dict(exclude={"file"}) == other.dict(exclude={"file"}) + return self.model_dump(exclude={"file"}) == other.model_dump(exclude={"file"}) def to_yaml(self, file) -> None: dict_representation = {"model": self.model} @@ -418,15 +432,29 @@ def to_yaml(self, file) -> None: yaml.dump(dict_representation, f, sort_keys=False) +def validate_with_definition(v: RegionAggregationMapping, info: ValidationInfo): + """Check if mappings valid with respect to RegionCodeList.""" + if invalid := info.data["region_codelist"].validate_items(v.all_regions): + raise PydanticCustomError( + *custom_pydantic_errors.RegionNotDefinedError, + {"regions": invalid, "file": v.file}, + ) + return v + + class RegionProcessor(Processor): """Region aggregation mappings for scenario processing""" region_codelist: RegionCodeList variable_codelist: VariableCodeList - mappings: Dict[str, RegionAggregationMapping] + mappings: Dict[ + str, + Annotated[RegionAggregationMapping, AfterValidator(validate_with_definition)], + ] + model_config = ConfigDict(hide_input_in_errors=True) @classmethod - @validate_arguments(config={"arbitrary_types_allowed": True}) + @validate_call(config={"arbitrary_types_allowed": True}) def from_directory(cls, path: DirectoryPath, dsd: DataStructureDefinition): """Initialize a RegionProcessor from a directory of model-aggregation mappings. @@ -445,11 +473,15 @@ def from_directory(cls, path: DirectoryPath, dsd: DataStructureDefinition): Raises ------ - ModelMappingCollisionError - Raised in case there are multiple mappings defined for the same model. + ValueError + Raised in case there are multiple mappings defined for the same model or + there is an issue with region the RegionAggregationMapping + AttributeError + Raised if the provided DataStructureDefinition does not contain the dimensions ``region`` and ``variable``. + """ mapping_dict: Dict[str, RegionAggregationMapping] = {} - errors: List[ErrorWrapper] = [] + errors = ErrorCollector() mapping_files = [f for f in path.glob("**/*") if f.suffix in {".yaml", ".yml"}] @@ -471,30 +503,24 @@ def from_directory(cls, path: DirectoryPath, dsd: DataStructureDefinition): mapping_dict[model] = mapping else: errors.append( - ErrorWrapper( - ModelMappingCollisionError( - model=model, - file1=mapping.file, - file2=mapping_dict[model].file, - ), - "__root__", + ValueError( + "Multiple region aggregation mappings for " + f"model {model} in [{mapping.file}, " + f"{mapping_dict[model].file}]" ) ) - except ( - pydantic.ValidationError, - RegionAggregationMappingParsingError, - ) as error: - errors.append(ErrorWrapper(error, "__root__")) + except ValueError as error: + errors.append(error) if errors: - raise pydantic.ValidationError(errors, model=RegionProcessor) + raise ValueError(errors) if missing_dims := [ dim for dim in ("region", "variable") if not hasattr(dsd, dim) ]: raise AttributeError( - "Provided DataStructureDefinition is missing the following attributes " - f"{missing_dims}" + "Provided DataStructureDefinition is missing the following " + f"attributes: {missing_dims}" ) return cls( mappings=mapping_dict, @@ -502,12 +528,6 @@ def from_directory(cls, path: DirectoryPath, dsd: DataStructureDefinition): variable_codelist=dsd.variable, ) - @validator("mappings", each_item=True) - def validate_with_definition(cls, v, values): - """Check if all mappings are valid and collect all errors.""" - v.validate_regions(values["region_codelist"]) - return v - def apply(self, df: IamDataFrame) -> IamDataFrame: """Apply region processing @@ -595,9 +615,6 @@ def _apply_region_processing( ) model = model_df.model[0] - # before aggregating, check that all regions are valid - self.mappings[model].validate_regions(self.region_codelist) - # check for regions not mentioned in the model mapping self.mappings[model].check_unexpected_regions(model_df) @@ -771,13 +788,23 @@ def _compare_and_merge( return pd.concat([original, aggregated[index]]), difference -def _check_exclude_region_overlap(values: Dict, region_type: str) -> Dict: - if values.get("exclude_regions") is None or values.get(region_type) is None: - return values - if overlap := set(values["exclude_regions"]) & { - r.name for r in values[region_type] +def _check_exclude_region_overlap( + region_aggregation_mapping: RegionAggregationMapping, region_type: str +) -> RegionAggregationMapping: + if ( + region_aggregation_mapping.exclude_regions is None + or getattr(region_aggregation_mapping, region_type) is None + ): + return region_aggregation_mapping + if overlap := set(region_aggregation_mapping.exclude_regions) & { + r.name for r in getattr(region_aggregation_mapping, region_type) }: - raise ExcludeRegionOverlapError( - region=overlap, region_type=region_type, file=values["file"] + raise PydanticCustomError( + *custom_pydantic_errors.ExcludeRegionOverlapError, + { + "region": overlap, + "region_type": region_type, + "file": region_aggregation_mapping.file, + }, ) - return values + return region_aggregation_mapping diff --git a/nomenclature/processor/required_data.py b/nomenclature/processor/required_data.py index 539210a2..edd4012f 100644 --- a/nomenclature/processor/required_data.py +++ b/nomenclature/processor/required_data.py @@ -1,17 +1,21 @@ import logging from pathlib import Path -from typing import Any, List, Optional, Tuple, Union +from typing import Any, List, Tuple, Union, Annotated import pandas as pd -import pydantic import yaml import pyam from pyam import IamDataFrame -from pydantic import BaseModel, validator, root_validator, Field -from pydantic.error_wrappers import ErrorWrapper +from pydantic import ( + field_validator, + model_validator, + BaseModel, + Field, + BeforeValidator, +) from nomenclature.definition import DataStructureDefinition -from nomenclature.error.required_data import RequiredDataMissingError +from nomenclature.error import ErrorCollector from nomenclature.processor import Processor from nomenclature.processor.utils import get_relative_path @@ -22,40 +26,48 @@ class RequiredMeasurand(BaseModel): variable: str unit: List[Union[str, None]] = Field(...) - @validator("unit", pre=True) + @field_validator("unit", mode="before") + @classmethod def single_input_to_list(cls, v): return v if isinstance(v, list) else [v] -class RequiredData(BaseModel): - measurand: Optional[List[RequiredMeasurand]] - variable: Optional[List[str]] - region: Optional[List[str]] - year: Optional[List[int]] +def cast_to_RequiredMeasurand(v) -> RequiredMeasurand: + if isinstance(v, RequiredMeasurand): + return v + if len(v) != 1: + raise ValueError("Measurand must be a single value dictionary") + variable = next(iter(v)) + return RequiredMeasurand(variable=variable, **v[variable]) + - @validator("measurand", "region", "year", "variable", pre=True) +class RequiredData(BaseModel): + measurand: List[ + Annotated[RequiredMeasurand, BeforeValidator(cast_to_RequiredMeasurand)] + ] | None = None + variable: List[str] | None = None + region: List[str] | None = None + year: List[int] | None = None + + @field_validator("measurand", "region", "year", "variable", mode="before") + @classmethod def single_input_to_list(cls, v): return v if isinstance(v, list) else [v] - @root_validator(pre=True) + @model_validator(mode="before") + @classmethod def check_variable_measurand_collision(cls, values): if values.get("measurand") and values.get("variable"): raise ValueError("'measurand' and 'variable' cannot be used together.") return values - @root_validator(pre=True) + @model_validator(mode="before") + @classmethod def check_variable_measurand_neither(cls, values): if values.get("measurand") is None and values.get("variable") is None: raise ValueError("Either 'measurand' or 'variable' must be given.") return values - @validator("measurand", pre=True, each_item=True) - def cast_to_RequiredMeasurand(cls, v): - if len(v) != 1: - raise ValueError("Measurand must be a single value dictionary") - variable = next(iter(v)) - return RequiredMeasurand(variable=variable, **v[variable]) - def validate_with_definition(self, dsd: DataStructureDefinition) -> None: error_msg = "" @@ -133,12 +145,13 @@ def _wrong_unit_variables( class RequiredDataValidator(Processor): - description: Optional[str] - model: Optional[List[str]] + description: str | None = None + model: List[str] | None = None required_data: List[RequiredData] file: Path - @validator("model", pre=True) + @field_validator("model", mode="before") + @classmethod def convert_to_list(cls, v): return pyam.utils.to_list(v) @@ -169,9 +182,7 @@ def apply(self, df: IamDataFrame) -> IamDataFrame: get_relative_path(self.file), missing_data_log_info, ) - raise RequiredDataMissingError( - "Required data missing. Please check the log for details." - ) + raise ValueError("Required data missing. Please check the log for details.") return df def check_required_data_per_model( @@ -203,19 +214,11 @@ def check_required_data_per_model( return missing_data def validate_with_definition(self, dsd: DataStructureDefinition) -> None: - errors = [] - for i, data in enumerate(self.required_data): + errors = ErrorCollector() + for data in self.required_data: try: data.validate_with_definition(dsd) except ValueError as value_error: - errors.append( - ErrorWrapper( - value_error, - ( - f"In file {get_relative_path(self.file)}\n" - f"entry nr. {i+1}" - ), - ) - ) + errors.append(value_error) if errors: - raise pydantic.ValidationError(errors, model=self.__class__) + raise ValueError(f"In file {get_relative_path(self.file)}:\n{errors}") diff --git a/nomenclature/testing.py b/nomenclature/testing.py index 4a9c31e0..66fc2b83 100644 --- a/nomenclature/testing.py +++ b/nomenclature/testing.py @@ -2,11 +2,11 @@ from pathlib import Path from typing import List, Optional -import pydantic import yaml from nomenclature.definition import DataStructureDefinition from nomenclature.processor import RegionProcessor, RequiredDataValidator +from nomenclature.error import ErrorCollector logger = logging.getLogger(__name__) @@ -66,15 +66,14 @@ def _check_mappings( def _collect_RequiredData_errors( required_data_dir: Path, dsd: DataStructureDefinition ) -> None: - errors: List[str] = [] + errors = ErrorCollector() for file in required_data_dir.iterdir(): try: RequiredDataValidator.from_file(file).validate_with_definition(dsd) - except pydantic.ValidationError as pve: - errors.append(str(pve)) + except ValueError as error: + errors.append(error) if errors: - all_errors = "\n".join(errors) - raise ValueError(f"Found error(s) in required data files: {all_errors}") + raise ValueError(f"Found error(s) in required data files:\n{errors}") def _check_RequiredData( diff --git a/poetry.lock b/poetry.lock index 7e5a650f..1b802b15 100644 --- a/poetry.lock +++ b/poetry.lock @@ -30,26 +30,37 @@ typing-extensions = ">=4" [package.extras] tz = ["backports.zoneinfo"] +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + [[package]] name = "anyio" -version = "4.1.0" +version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "anyio-4.1.0-py3-none-any.whl", hash = "sha256:56a415fbc462291813a94528a779597226619c8e78af7de0507333f700011e5f"}, - {file = "anyio-4.1.0.tar.gz", hash = "sha256:5a0bec7085176715be77df87fc66d6c9d70626bd752fcc85f57cdbee5b3760da"}, + {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, + {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, ] [package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] +test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (<0.22)"] [[package]] name = "babel" @@ -320,6 +331,70 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pill test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +[[package]] +name = "coverage" +version = "7.3.3" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d874434e0cb7b90f7af2b6e3309b0733cde8ec1476eb47db148ed7deeb2a9494"}, + {file = "coverage-7.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee6621dccce8af666b8c4651f9f43467bfbf409607c604b840b78f4ff3619aeb"}, + {file = "coverage-7.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1367aa411afb4431ab58fd7ee102adb2665894d047c490649e86219327183134"}, + {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f0f8f0c497eb9c9f18f21de0750c8d8b4b9c7000b43996a094290b59d0e7523"}, + {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db0338c4b0951d93d547e0ff8d8ea340fecf5885f5b00b23be5aa99549e14cfd"}, + {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d31650d313bd90d027f4be7663dfa2241079edd780b56ac416b56eebe0a21aab"}, + {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9437a4074b43c177c92c96d051957592afd85ba00d3e92002c8ef45ee75df438"}, + {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9e17d9cb06c13b4f2ef570355fa45797d10f19ca71395910b249e3f77942a837"}, + {file = "coverage-7.3.3-cp310-cp310-win32.whl", hash = "sha256:eee5e741b43ea1b49d98ab6e40f7e299e97715af2488d1c77a90de4a663a86e2"}, + {file = "coverage-7.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:593efa42160c15c59ee9b66c5f27a453ed3968718e6e58431cdfb2d50d5ad284"}, + {file = "coverage-7.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c944cf1775235c0857829c275c777a2c3e33032e544bcef614036f337ac37bb"}, + {file = "coverage-7.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eda7f6e92358ac9e1717ce1f0377ed2b9320cea070906ece4e5c11d172a45a39"}, + {file = "coverage-7.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c854c1d2c7d3e47f7120b560d1a30c1ca221e207439608d27bc4d08fd4aeae8"}, + {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:222b038f08a7ebed1e4e78ccf3c09a1ca4ac3da16de983e66520973443b546bc"}, + {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff4800783d85bff132f2cc7d007426ec698cdce08c3062c8d501ad3f4ea3d16c"}, + {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fc200cec654311ca2c3f5ab3ce2220521b3d4732f68e1b1e79bef8fcfc1f2b97"}, + {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:307aecb65bb77cbfebf2eb6e12009e9034d050c6c69d8a5f3f737b329f4f15fb"}, + {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ffb0eacbadb705c0a6969b0adf468f126b064f3362411df95f6d4f31c40d31c1"}, + {file = "coverage-7.3.3-cp311-cp311-win32.whl", hash = "sha256:79c32f875fd7c0ed8d642b221cf81feba98183d2ff14d1f37a1bbce6b0347d9f"}, + {file = "coverage-7.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:243576944f7c1a1205e5cd658533a50eba662c74f9be4c050d51c69bd4532936"}, + {file = "coverage-7.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a2ac4245f18057dfec3b0074c4eb366953bca6787f1ec397c004c78176a23d56"}, + {file = "coverage-7.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f9191be7af41f0b54324ded600e8ddbcabea23e1e8ba419d9a53b241dece821d"}, + {file = "coverage-7.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c0b1b8b5a4aebf8fcd227237fc4263aa7fa0ddcd4d288d42f50eff18b0bac4"}, + {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee453085279df1bac0996bc97004771a4a052b1f1e23f6101213e3796ff3cb85"}, + {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1191270b06ecd68b1d00897b2daddb98e1719f63750969614ceb3438228c088e"}, + {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:007a7e49831cfe387473e92e9ff07377f6121120669ddc39674e7244350a6a29"}, + {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:af75cf83c2d57717a8493ed2246d34b1f3398cb8a92b10fd7a1858cad8e78f59"}, + {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:811ca7373da32f1ccee2927dc27dc523462fd30674a80102f86c6753d6681bc6"}, + {file = "coverage-7.3.3-cp312-cp312-win32.whl", hash = "sha256:733537a182b5d62184f2a72796eb6901299898231a8e4f84c858c68684b25a70"}, + {file = "coverage-7.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:e995efb191f04b01ced307dbd7407ebf6e6dc209b528d75583277b10fd1800ee"}, + {file = "coverage-7.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbd8a5fe6c893de21a3c6835071ec116d79334fbdf641743332e442a3466f7ea"}, + {file = "coverage-7.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:50c472c1916540f8b2deef10cdc736cd2b3d1464d3945e4da0333862270dcb15"}, + {file = "coverage-7.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e9223a18f51d00d3ce239c39fc41410489ec7a248a84fab443fbb39c943616c"}, + {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f501e36ac428c1b334c41e196ff6bd550c0353c7314716e80055b1f0a32ba394"}, + {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:475de8213ed95a6b6283056d180b2442eee38d5948d735cd3d3b52b86dd65b92"}, + {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afdcc10c01d0db217fc0a64f58c7edd635b8f27787fea0a3054b856a6dff8717"}, + {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fff0b2f249ac642fd735f009b8363c2b46cf406d3caec00e4deeb79b5ff39b40"}, + {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a1f76cfc122c9e0f62dbe0460ec9cc7696fc9a0293931a33b8870f78cf83a327"}, + {file = "coverage-7.3.3-cp38-cp38-win32.whl", hash = "sha256:757453848c18d7ab5d5b5f1827293d580f156f1c2c8cef45bfc21f37d8681069"}, + {file = "coverage-7.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad2453b852a1316c8a103c9c970db8fbc262f4f6b930aa6c606df9b2766eee06"}, + {file = "coverage-7.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b15e03b8ee6a908db48eccf4e4e42397f146ab1e91c6324da44197a45cb9132"}, + {file = "coverage-7.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:89400aa1752e09f666cc48708eaa171eef0ebe3d5f74044b614729231763ae69"}, + {file = "coverage-7.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c59a3e59fb95e6d72e71dc915e6d7fa568863fad0a80b33bc7b82d6e9f844973"}, + {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ede881c7618f9cf93e2df0421ee127afdfd267d1b5d0c59bcea771cf160ea4a"}, + {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3bfd2c2f0e5384276e12b14882bf2c7621f97c35320c3e7132c156ce18436a1"}, + {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f3bad1a9313401ff2964e411ab7d57fb700a2d5478b727e13f156c8f89774a0"}, + {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:65d716b736f16e250435473c5ca01285d73c29f20097decdbb12571d5dfb2c94"}, + {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a702e66483b1fe602717020a0e90506e759c84a71dbc1616dd55d29d86a9b91f"}, + {file = "coverage-7.3.3-cp39-cp39-win32.whl", hash = "sha256:7fbf3f5756e7955174a31fb579307d69ffca91ad163467ed123858ce0f3fd4aa"}, + {file = "coverage-7.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cad9afc1644b979211989ec3ff7d82110b2ed52995c2f7263e7841c846a75348"}, + {file = "coverage-7.3.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:d299d379b676812e142fb57662a8d0d810b859421412b4d7af996154c00c31bb"}, + {file = "coverage-7.3.3.tar.gz", hash = "sha256:df04c64e58df96b4427db8d0559e95e2df3138c9916c96f9f6a4dd220db2fdb7"}, +] + +[package.extras] +toml = ["tomli"] + [[package]] name = "cycler" version = "0.12.1" @@ -402,24 +477,23 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.94.1" +version = "0.104.1" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "fastapi-0.94.1-py3-none-any.whl", hash = "sha256:451387550c2d25a972193f22e408a82e75a8e7867c834a03076704fe20df3256"}, - {file = "fastapi-0.94.1.tar.gz", hash = "sha256:4a75936dbf9eb74be5eb0d41a793adefe9f3fc6ba66dbdabd160120fd3c2d9cd"}, + {file = "fastapi-0.104.1-py3-none-any.whl", hash = "sha256:752dc31160cdbd0436bb93bad51560b57e525cbb1d4bbf6f4904ceee75548241"}, + {file = "fastapi-0.104.1.tar.gz", hash = "sha256:e5e4540a7c5e1dcfbbcf5b903c234feddcdcd881f191977a1c5dfd917487e7ae"}, ] [package.dependencies] -pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = ">=0.26.1,<0.27.0" +anyio = ">=3.7.1,<4.0.0" +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.27.0,<0.28.0" +typing-extensions = ">=4.8.0" [package.extras] -all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.21.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer-cli (>=0.0.13,<0.0.14)", "typer[all] (>=0.6.1,<0.8.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==23.1.0)", "coverage[toml] (>=6.5.0,<8.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.7)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<1.4.43)", "types-orjson (==3.6.2)", "types-ujson (==5.7.0.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "flake8" @@ -678,46 +752,47 @@ files = [ [[package]] name = "httpcore" -version = "0.16.3" +version = "1.0.2" description = "A minimal low-level HTTP client." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, - {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, + {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, + {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, ] [package.dependencies] -anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = "==1.*" [package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.23.0)"] [[package]] name = "httpx" -version = "0.23.3" +version = "0.25.2" description = "The next generation HTTP client." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, - {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, + {file = "httpx-0.25.2-py3-none-any.whl", hash = "sha256:a05d3d052d9b2dfce0e3896636467f8a5342fb2b902c819428e1ac65413ca118"}, + {file = "httpx-0.25.2.tar.gz", hash = "sha256:8b8fcaa0c8ea7b05edd69a094e63a2094c4efcb48129fb757361bc423c0ad9e8"}, ] [package.dependencies] +anyio = "*" certifi = "*" h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} -httpcore = ">=0.15.0,<0.17.0" -rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +httpcore = "==1.*" +idna = "*" sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<13)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -804,32 +879,33 @@ files = [ [[package]] name = "ixmp4" -version = "0.5.0" +version = "0.6.0" description = "a data warehouse for scenario analysis" optional = false python-versions = ">=3.10,<3.12" files = [ - {file = "ixmp4-0.5.0-py3-none-any.whl", hash = "sha256:17da5143602b8d1c2210fe7bef38d331fe61d0b603ed4b0582d301ff3295f3be"}, - {file = "ixmp4-0.5.0.tar.gz", hash = "sha256:e4fad15899ff19f3d4644a3164b9e2b1efde7370e049628576d5310e6e642e10"}, + {file = "ixmp4-0.6.0-py3-none-any.whl", hash = "sha256:5c775e04d66569decd60f8378529710c3bfadfa31cc7a27c4b24cd7f16144edb"}, + {file = "ixmp4-0.6.0.tar.gz", hash = "sha256:ebc93cbe57152c6792634a53827db68117f5b73b2af66b888fb3be48dc699da5"}, ] [package.dependencies] -alembic = ">=1.10.2,<2.0.0" -dask = ">=2023.4.0,<2024.0.0" -fastapi = ">=0.94.0,<0.95.0" -httpx = {version = ">=0.23.3,<0.24.0", extras = ["http2"]} +alembic = ">=1.12.1,<2.0.0" +dask = ">=2023.10.1,<2024.0.0" +fastapi = ">=0.104.0,<0.105.0" +httpx = {version = ">=0.25.0,<0.26.0", extras = ["http2"]} openpyxl = ">=3.0.9,<4.0.0" -pandas = ">=2.0.0,<3.0.0" -pandera = ">=0.13.4,<0.14.0" +pandas = ">=2.1.2,<3.0.0" +pandera = ">=0.17.0,<0.18.0" psycopg = {version = ">=3.1.10,<4.0.0", extras = ["binary"]} -pydantic = ">=1.10.5,<2.0.0" +pydantic = ">=2.4.0,<3.0.0" +pydantic-settings = ">=2.0.3,<3.0.0" PyJWT = ">=2.4.0,<3.0.0" -python-dotenv = ">=0.19.0,<0.20.0" +python-dotenv = ">=1.0.0,<2.0.0" requests = ">=2.27.1,<3.0.0" -SQLAlchemy = {version = ">=2.0.7,<3.0.0", extras = ["mypy"]} -SQLAlchemy-Utils = ">=0.40.0,<0.41.0" +SQLAlchemy = {version = ">=2.0.22,<3.0.0", extras = ["mypy"]} +SQLAlchemy-Utils = ">=0.41.1,<0.42.0" toml = ">=0.10.2,<0.11.0" -typer = ">=0.4.0,<0.5.0" +typer = ">=0.9.0,<0.10.0" [[package]] name = "jinja2" @@ -1018,6 +1094,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -1122,6 +1208,17 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] +[[package]] +name = "multimethod" +version = "1.10" +description = "Multiple argument dispatching." +optional = false +python-versions = ">=3.8" +files = [ + {file = "multimethod-1.10-py3-none-any.whl", hash = "sha256:afd84da9c3d0445c84f827e4d63ad42d17c6d29b122427c6dee9032ac2d2a0d4"}, + {file = "multimethod-1.10.tar.gz", hash = "sha256:daa45af3fe257f73abb69673fd54ddeaf31df0eb7363ad6e1251b7c9b192d8c5"}, +] + [[package]] name = "mypy" version = "1.7.1" @@ -1333,34 +1430,36 @@ xml = ["lxml (>=4.8.0)"] [[package]] name = "pandera" -version = "0.13.4" +version = "0.17.2" description = "A light-weight and flexible data validation and testing tool for statistical data objects." optional = false python-versions = ">=3.7" files = [ - {file = "pandera-0.13.4-py3-none-any.whl", hash = "sha256:9e91687861406284270add1d467f204630377892e7a4b45809bb7546f0013153"}, - {file = "pandera-0.13.4.tar.gz", hash = "sha256:6ef2b7ee00d3439ac815d4347984421a08502da1020cec60c06dd0135e8aee2f"}, + {file = "pandera-0.17.2-py3-none-any.whl", hash = "sha256:8e4e7b279c62f6d4b5109801544bf8d46e1c9fdf7ceceb8fedd5f3dad0c1bea1"}, + {file = "pandera-0.17.2.tar.gz", hash = "sha256:67515984f855ba14d12443f893b5ff90ae6796f613d5f3df43abad406a48c373"}, ] [package.dependencies] +multimethod = "*" numpy = ">=1.19.0" packaging = ">=20.0" pandas = ">=1.2.0" pydantic = "*" +typeguard = ">=3.0.2" typing-inspect = ">=0.6.0" wrapt = "*" [package.extras] -all = ["black", "dask", "fastapi", "frictionless", "geopandas", "hypothesis (>=5.41.1)", "modin", "pandas-stubs (<=1.4.3.220807)", "pyspark (>=3.2.0)", "pyyaml (>=5.1)", "ray (<=1.7.0)", "scipy", "shapely"] +all = ["black", "dask", "fastapi", "frictionless (<=4.40.8)", "geopandas", "hypothesis (>=5.41.1)", "modin", "pandas-stubs", "pyspark (>=3.2.0)", "pyyaml (>=5.1)", "ray", "scipy", "shapely"] dask = ["dask"] fastapi = ["fastapi"] geopandas = ["geopandas", "shapely"] hypotheses = ["scipy"] -io = ["black", "frictionless", "pyyaml (>=5.1)"] -modin = ["dask", "modin", "ray (<=1.7.0)"] +io = ["black", "frictionless (<=4.40.8)", "pyyaml (>=5.1)"] +modin = ["dask", "modin", "ray"] modin-dask = ["dask", "modin"] -modin-ray = ["modin", "ray (<=1.7.0)"] -mypy = ["pandas-stubs (<=1.4.3.220807)"] +modin-ray = ["modin", "ray"] +mypy = ["pandas-stubs"] pyspark = ["pyspark (>=3.2.0)"] strategies = ["hypothesis (>=5.41.1)"] @@ -1518,23 +1617,23 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "psycopg" -version = "3.1.14" +version = "3.1.15" description = "PostgreSQL database adapter for Python" optional = false python-versions = ">=3.7" files = [ - {file = "psycopg-3.1.14-py3-none-any.whl", hash = "sha256:f5bce37d357578b230ede15fb461e2c601122986f6dd590e94283aaca8958b14"}, - {file = "psycopg-3.1.14.tar.gz", hash = "sha256:7a63249f52e9c312d2d3978df5f170d21a0defd3a0c950d7859d226b7cfbfad5"}, + {file = "psycopg-3.1.15-py3-none-any.whl", hash = "sha256:a6c03e508be0e42facb1e8581156fdc2904322fe8077ba4f298f5f0a947cb8e0"}, + {file = "psycopg-3.1.15.tar.gz", hash = "sha256:1b8e3e8d1612ea289a2684a5bf0c1f9a209549b222b6958377ce970a6e10b80c"}, ] [package.dependencies] -psycopg-binary = {version = "3.1.14", optional = true, markers = "implementation_name != \"pypy\" and extra == \"binary\""} +psycopg-binary = {version = "3.1.15", optional = true, markers = "implementation_name != \"pypy\" and extra == \"binary\""} typing-extensions = ">=4.1" tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] -binary = ["psycopg-binary (==3.1.14)"] -c = ["psycopg-c (==3.1.14)"] +binary = ["psycopg-binary (==3.1.15)"] +c = ["psycopg-c (==3.1.15)"] dev = ["black (>=23.1.0)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.4.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] pool = ["psycopg-pool"] @@ -1542,76 +1641,76 @@ test = ["anyio (>=3.6.2,<4.0)", "mypy (>=1.4.1)", "pproxy (>=2.7)", "pytest (>=6 [[package]] name = "psycopg-binary" -version = "3.1.14" +version = "3.1.15" description = "PostgreSQL database adapter for Python -- C optimisation distribution" optional = false python-versions = ">=3.7" files = [ - {file = "psycopg_binary-3.1.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cf6ff7f025643e42d27d903e8be5d171db7db4f486076a6942cbf8daa4f8b3e"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:57841e59f181e546c28d73036847f42eeab3e917a1cceb4a27e54b4a1d75683e"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67cc4b0b3585bbce8782c7ad4a498549f8150fa77872c3cffdf476f04bbcb714"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdb9c2e796d029eaa53881ed3de065628639fa0550fa462f145e54e4f90a429e"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7da7f174a34fd0441caf2a44a71d20800f19a9565753e3531197914a7441b42b"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b95c1d1be1a243e28583a70f257e970941c5b2c7f0d21e24dfc92145ad82407"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e31bb31fa6abe74041715bc15e23e4d784887b388952503f6fa54d38bbcc3258"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:eb1e5df4adc6514a78643ac7119de7725f089338c8907a2b40f919abe5595ce7"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:15b3b04d8ec665c660268169364f4befab490231224486eb4c761d5365a01108"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96c123bebc7a6d83e90f480ca44696ac804d74e4b7920b5d6ca7479ea179732e"}, - {file = "psycopg_binary-3.1.14-cp310-cp310-win_amd64.whl", hash = "sha256:2ccfa9d7e5272a6cc25038b6e2bc67a9a118765fba4cebcc8318ac0336f2ac86"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eb093578a56e3074c9573d8c1bea408ae857e3e8330ed831c4d7fc5ece6f9cad"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d431c41321168035dfd7217253ca02f985769636500ae951fa72cb9f6473d393"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d4de5646460ea7f26fe19feffc9853648a05ee419d2f861029a1c9c53817d"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dad6eef513754219a696f8bd51c7c5f25f6b988ac5b6edc87e698c737158f4d3"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e0a41b2a2e78a785e7b415e495ae7f35817fac7377d34192b56ce7dd914c1f"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33a76e665826ebb4298fb931985f466e3cd553bb7cf30cfef9214e2c9156f026"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ab1f40717be4bb12e43c6789ba05efdffd342c8c7aa9db346110d814779a8088"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:664cff756a8a636f9c6810d41dc5da46879142865ebcceae2edcd045dcb30b6f"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:6babfd78e6e0a91eff45b82b2517e82bfe078de084f354853b1017cc04e37ad9"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d88c15597732b6021e29cf5bdaa7245af51a986f2834ca2c77aca4c05f224f59"}, - {file = "psycopg_binary-3.1.14-cp311-cp311-win_amd64.whl", hash = "sha256:32f09adce74208aea1b6500ab07bda68bed45df902f0125a3b292137a2133a2a"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d5ca34fad0558244d5fbfbc19a691b423a471e9e601d4ddabd759aa05ded0fa1"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a19d4776ccb4c22192ffa5878c82389a0d2ba8a861933b95f91b73d426b2f54f"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:749760b5d963390859397b745c797b62ee0757c72a961ee77f918fd4a1ae6646"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56e668a6a61f33d48b1696207393e5ec33a371a3692cc434c445b909f97a5e34"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:abeb8ed0fe3ff635f10914edb8c8febe99046a99143d21e004352aebc4ab1241"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f623d0952bc0e118c4de529a20fba98855654ff3a1f30d9bce77898af0518e70"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:57a4055b63a824589f9e9a8edc5dcf498ef49b888bc945d7a5e865ffe5a42ff8"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:068d29ebcba782b815a5a3842c740af8d4c314e2caf82636a5e0e80120606655"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b1528ea7ef8f5e109d9eda470e7a7917b467938c1371245eddad0caff8edb5a7"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd078bb91b5957913cebefbaa8b9e296e31c4f3eaab16b875e2f75a84640ebc6"}, - {file = "psycopg_binary-3.1.14-cp312-cp312-win_amd64.whl", hash = "sha256:313be7a062e96dbc153ca7ecd6bce86fc67ac5fd9f5722cfbc5fba5431f4eb36"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:099123c231a38dc071c9d41b983300196e05ed724b7642bc4bc9ee64ee46c5ff"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:501a73961115c962d22ece4a0e1d8d8711cea6d6a8a2284521876973275fb01a"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c74c27acedbc463007647ca3082b1848c07ec9c03bfaea068ee0d87050fdb629"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8bd8d92d8418fed8c749134469676ce08b492fcaad4cfe2cde713bd33decfa7"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39d7bccddac038d1627425b2ac9e8f054909ef8c4d0f8bfb684831dcee275ee2"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a394ebcf129e2344d091c04254bb289b7454e913ca921570af8f2185bf8fd86"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a510c6bb19c81587be0ef1e72ab75228bde70d1fef1f2ca62a124b663987fbbb"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e25448293623a0dc2fa32a1781e87d14da7cb608a1cfac27681cc640d9523a1e"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:740f0914da1e4db4021969ff467ae2fcec7cac40ee58b3a32ffa8fe476658f8a"}, - {file = "psycopg_binary-3.1.14-cp37-cp37m-win_amd64.whl", hash = "sha256:d305d825b78a59f32bb6c1bca751d18ccc4bb9b80340c8d2d4c1924ab9d347d5"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e67e5c4f08ce8bf59a54f957168423910bfb46feb469da13fc76d0c6dd377047"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a171ba6aed4845da2f5c1205de498f9f51826f181ef86a2a1e1342c98d35859b"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e612ab1ffb680ac928a641abd75d0b0fa5ea87421f0fdabd082baff55849b90e"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c92805c868fc0fa629033f74eebef58f3d5d15e0d7981ec33a1cb4027a7cc62"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4df14e755962b1324f70aadea2ff915dfdb6dfdf56d9cdb10aebd183d0dc83b7"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e790397d555a438b7785e611bc3ae1f344f1f799507fd97005476e2bc816947"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d49bbdcb49939e97d6a161b864272e5f5daf199034d996b506a1006c78611481"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:19e34d464ceab28825f1e9e8c5b482d5da51b2c9a6e105901d384ea4e225edc1"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b44af0b30eb4bd733446474eb4051d93c4f2eb30928cd4c4b2180d162fa35483"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:95f212ce9c9c7f754e7d981978de1603ddeac15bb4b2434afccbc976c84a9529"}, - {file = "psycopg_binary-3.1.14-cp38-cp38-win_amd64.whl", hash = "sha256:545ea4b72321c25afa76aa5a7eeb04e22ac7d5ead9762d5f30849fe2fdf1217a"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a9e8cda0acfcfe127b390a877ab43ca2c248adff2ad746f26db19f3025eb4ba3"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:502a06d4037a2c27e67f2521322ec173335108d5ee303dd58129b3a5b358ed30"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be20bcccca8326a9f060a6749fdf92bf6147e8b5039c7a6cd9f0f5fe7c190ec"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:044f8eb0ae01588d2da80c12f897c7562b430e04aa841555fc478f370be34d1e"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f67b956506958f12fa9a110f19d9ec2caf4c98708386c84b4622d7227b344f4"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74ee5c67ad273cf0b4653f440afd69cff4d1a19684a52653ad6b10b270d4589b"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b1780b065f3b85403dcf818a6397305eaa57206a4a5d195b9b3589bd818f757b"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:32e9d8bdfcfef9ccbd916bcbb8bcfcb281613e5dec9f5dcc3e4bff3e2eb9d490"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0f7014dd971a3c00d63244381107800d47eebf3b1fa4f95784e6e4fa4d77d3c2"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98409e33c7a2907c5cdf172d8f83c5664cd3ed99122a9c43b8d6e915c3beb050"}, - {file = "psycopg_binary-3.1.14-cp39-cp39-win_amd64.whl", hash = "sha256:d7a52d5bfd09a89872a192ad4bbf0dd2a1de07ceaa420337c35061376606310b"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12417e4aade7549c25d34d3f256c006713db81877b44934d50afa81e11f2fce5"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7e891f8d5e935c805ccf9acb5a012a3fd7032724d35022e4eba72babbd24003b"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:399a4a857a4aec8548fa8763d28b89c738408d0a66638019a74d92c19029421e"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0906a9297e057635d14687aa6cd8f783776918f1549d04d1c9bc84c0ad984d77"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d8152933b84f43d48ab13c9fb6a7f59194f4879f2a0236824778165e14b97b"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d9ecf64337b6c5ba7e81ed1b46f05149d37a653e2dc9138ccd065db26252840"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dda4250b3aad981a37a504e555b784663d0b2dda2a385631662157ce808129f1"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1da944ad974c90c741e1f0139d71bab62e9603c32f4f3b3edcd766db5df88da"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:4a8c1c0d5ff08e8b089dbd4397b9b6cf9eec676685a53d6331f45fd6112bb138"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:18f5666d6f4064e454f279fbf59553f1665b81b4ababb384132682e244d85da7"}, + {file = "psycopg_binary-3.1.15-cp310-cp310-win_amd64.whl", hash = "sha256:cf231c921dc0dfb71cb2dab0647f9a620729276b19b724b50703663ab0ecc9a4"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1126bdfff795db17f09aa20e2ff3efeeced82b43ef0628ac92f5c1d9e4fa2482"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75b49634b0f4f63f6bfb62006f3b0736ef636a2d19475dcba1b3728d8d172721"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b265ce896527a752eee111ba780eaed6ed8ad6c2c50be45ad98099c8f1c34865"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7836017a850c3e48ed09052c0e1348547656815dc653218645d74e5d6da0357b"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02de4d5240fe40c0c000b1fc072f403f2f88ff963e0fe09b4bda6caf3bdb2d32"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be50b8cee9d0910ee9c98127e70216ac2865e34715e57a5490583af90734259d"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:773ae209449352788432f916f6e518e28c23a139a29d352810c4b21382d0f61d"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:288214e81966872adbe46057a66eb76e9250f628aff2cc9e46a5fcf1da24123b"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4781bda7d34fe12c10f128255abfc1ead12f58a3a0aaa2bd91b4055548be519b"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:076a50bc71b3f597a6fd1ec7e662b6948cd532486d4be5d107ff74dc9647be1e"}, + {file = "psycopg_binary-3.1.15-cp311-cp311-win_amd64.whl", hash = "sha256:c75e12eeb7a48e19eb4599524e24d883150ce3ef2c6967f7aff2f8f3c73ddb7a"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:666722d41389de0ab6cec5aa780548e2c60f36bda74da929f5ede6ca932dc34c"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e72129c3dc41ad4aaecb49ec54ed5f9c2311c53fb9a8e3c0fc63ad0f1699295e"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2f7e0fbd66e69a1c5f164c5c6c8b0b98f6e851a41ffd23ef44a0dd9ef3a175e"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07c11f76a258060e047db460ac05f76ae5e09d94c10ea9f81f3f0f28b401ac0f"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fd9a19784237845bfdd93c25d59c475e1ce069717470b7d6a7d928113a3743d"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97ab8928fa7403a17b6df76bc3337527c454a9653bd966b1eccfd3176336f909"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:007ec68533f530b8fdaf77cb5c7961812772f31ecc90cc9c1000f3e321621e66"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d8b0e31a5243f648d17d78f2405ceb08c7819a4e97bbff778ffd10a7bf1a08a1"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fa6cedc562e26b55de17b7897e8bf21e01d7aea271493b8d6ef2c31f63ad7c55"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3b02eb2bc11a41c67825d14b12e0d8f65bdaa0a9d1c792f22f6b9c97d0123a2e"}, + {file = "psycopg_binary-3.1.15-cp312-cp312-win_amd64.whl", hash = "sha256:8220860bb7553b37d3e50f877da7a96e487ad02e9cb996407db16b4e9b94c853"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:21f54d3778d4fd50ce7501b55a6f84ce74eb7e0bbe2725dca049a0b478e9a431"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb9cbcc354b019ab59d92c739b55ecd654938b76b0e4174878bdaf9689060ed"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05407acf763766507e2d66473de904fc176ed3674bd0340246a80e4247ded39b"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:716bf9cd2b4e7ac09534b875a14ea9614776c8d9036e9c56d64c05b76e0aa6b3"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:410b4e97f617f9af58b0d41c5118d71276817ef2046d5f55c289a0d9d5696dc1"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1148adc146c10ebd7432cf32324c1c977ebb4ab1a84c912dffec9b36523ab49"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ab7d92e7f1da609a145313ccb227f5f3d687d9aeaff4a46b5ada0395f270c09d"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2336d69180ce3d55f58fd899a47d334083e9c808e033bfe5ff43943064566e1d"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2be2a61a6cb7bccba7785dfb3268381d34b4a3868437ecf41aed0751b38255d9"}, + {file = "psycopg_binary-3.1.15-cp37-cp37m-win_amd64.whl", hash = "sha256:d3a49a4ffa8cb7bf27b5e951ea856273cc2bbd60de78707e2701deef59ff3792"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4e0e5d48c6541a186771f1c728a8b60e1494878def584f59c59a8a29a913776c"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bf1399084583875548e4df301e92bab00ce0ce03a2a72197c1b4f14f48d5135"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8bc1a830912d43f1904e6de51f1bf3495b438158ac77e4c6446b60139d8e6d0d"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:456707bd6a67bc2fe466c9f0b0ed7e1e4179d98c965e4065209a83fbabc71d38"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:110d3235b7147526d1d1e77ecc81c9078cc99271011078744da9184104573575"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb368f0c40fc2e0c667197cad3529bf0bc8a20c1536a177d18890e0e7a1946b9"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca0d47cd667b076f0cf7f6621100378bf8ec6717f669eb9232649dc3ce4bd6df"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c4a32dace67083d62adf58cb7214f0741a3bf8346e519340538035992dfd642e"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3b404b6e8b789039b627b3ed6a14989c70acfa044240bf94974fd3b3f9ce96c4"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:83aaaa7dd3df8cab472fdf8ffa616b2bf059ba146d15a1301ca988a29330ace2"}, + {file = "psycopg_binary-3.1.15-cp38-cp38-win_amd64.whl", hash = "sha256:cb9732b7b1bbd9f8f464f2478e184ccc34efca5126a2386c4e6fd752f56f1ac7"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d099a62090074f1df0aeed670a7b342ab1352b8fce21bbc5252e4e393fe840a2"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:624921c699b278a2ec64ccb4164be491fdf178bd50c898fef18c8c6fd8989d3e"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:522a62f38139c6fd4122648b4eb91636a9cd888567a7712318097150f52771a1"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe9fb4100cf8827e52d53471a8aadba284b5863842fcf7b3ae5394ab01ccb196"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23c406ad98a816a75ee29673b518ec6288de5784bf9768e74f5e8a3e8b20c33b"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba5a495696b64eb9a9c68ffd10c33816cf51d69410e1d91f999eb93e41dc371c"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9af56d13dc6071dd627d342a3fe7302b8a290056e66bc2c1bf9e4c5e38150d78"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ad609cef3bbd501a369a5ba7c72bd34e30972417f7601fd4684ee5f8b0f5cdba"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:699a14733709f0c08b7d4fe32abd1d0fbb67ae58675ec7d0512048bd6eadeab4"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b51b3d8b955585c6fc3e3d90b09f4e481e47e28a6486c2fbad7866ddb6a5868"}, + {file = "psycopg_binary-3.1.15-cp39-cp39-win_amd64.whl", hash = "sha256:361b0a0697b582ff019a15590063c1065f109ae207c0374f297926d5b359012b"}, ] [[package]] @@ -1674,55 +1773,154 @@ files = [ [[package]] name = "pydantic" -version = "1.10.13" -description = "Data validation and settings management using python type hints" +version = "2.5.2" +description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:efff03cc7a4f29d9009d1c96ceb1e7a70a65cfe86e89d34e4a5f2ab1e5693737"}, - {file = "pydantic-1.10.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3ecea2b9d80e5333303eeb77e180b90e95eea8f765d08c3d278cd56b00345d01"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1740068fd8e2ef6eb27a20e5651df000978edce6da6803c2bef0bc74540f9548"}, - {file = "pydantic-1.10.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84bafe2e60b5e78bc64a2941b4c071a4b7404c5c907f5f5a99b0139781e69ed8"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bc0898c12f8e9c97f6cd44c0ed70d55749eaf783716896960b4ecce2edfd2d69"}, - {file = "pydantic-1.10.13-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:654db58ae399fe6434e55325a2c3e959836bd17a6f6a0b6ca8107ea0571d2e17"}, - {file = "pydantic-1.10.13-cp310-cp310-win_amd64.whl", hash = "sha256:75ac15385a3534d887a99c713aa3da88a30fbd6204a5cd0dc4dab3d770b9bd2f"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c553f6a156deb868ba38a23cf0df886c63492e9257f60a79c0fd8e7173537653"}, - {file = "pydantic-1.10.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e08865bc6464df8c7d61439ef4439829e3ab62ab1669cddea8dd00cd74b9ffe"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31647d85a2013d926ce60b84f9dd5300d44535a9941fe825dc349ae1f760df9"}, - {file = "pydantic-1.10.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:210ce042e8f6f7c01168b2d84d4c9eb2b009fe7bf572c2266e235edf14bacd80"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8ae5dd6b721459bfa30805f4c25880e0dd78fc5b5879f9f7a692196ddcb5a580"}, - {file = "pydantic-1.10.13-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f8e81fc5fb17dae698f52bdd1c4f18b6ca674d7068242b2aff075f588301bbb0"}, - {file = "pydantic-1.10.13-cp311-cp311-win_amd64.whl", hash = "sha256:61d9dce220447fb74f45e73d7ff3b530e25db30192ad8d425166d43c5deb6df0"}, - {file = "pydantic-1.10.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4b03e42ec20286f052490423682016fd80fda830d8e4119f8ab13ec7464c0132"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f59ef915cac80275245824e9d771ee939133be38215555e9dc90c6cb148aaeb5"}, - {file = "pydantic-1.10.13-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a1f9f747851338933942db7af7b6ee8268568ef2ed86c4185c6ef4402e80ba8"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:97cce3ae7341f7620a0ba5ef6cf043975cd9d2b81f3aa5f4ea37928269bc1b87"}, - {file = "pydantic-1.10.13-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:854223752ba81e3abf663d685f105c64150873cc6f5d0c01d3e3220bcff7d36f"}, - {file = "pydantic-1.10.13-cp37-cp37m-win_amd64.whl", hash = "sha256:b97c1fac8c49be29486df85968682b0afa77e1b809aff74b83081cc115e52f33"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c958d053453a1c4b1c2062b05cd42d9d5c8eb67537b8d5a7e3c3032943ecd261"}, - {file = "pydantic-1.10.13-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c5370a7edaac06daee3af1c8b1192e305bc102abcbf2a92374b5bc793818599"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d6f6e7305244bddb4414ba7094ce910560c907bdfa3501e9db1a7fd7eaea127"}, - {file = "pydantic-1.10.13-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3a3c792a58e1622667a2837512099eac62490cdfd63bd407993aaf200a4cf1f"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c636925f38b8db208e09d344c7aa4f29a86bb9947495dd6b6d376ad10334fb78"}, - {file = "pydantic-1.10.13-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:678bcf5591b63cc917100dc50ab6caebe597ac67e8c9ccb75e698f66038ea953"}, - {file = "pydantic-1.10.13-cp38-cp38-win_amd64.whl", hash = "sha256:6cf25c1a65c27923a17b3da28a0bdb99f62ee04230c931d83e888012851f4e7f"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8ef467901d7a41fa0ca6db9ae3ec0021e3f657ce2c208e98cd511f3161c762c6"}, - {file = "pydantic-1.10.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:968ac42970f57b8344ee08837b62f6ee6f53c33f603547a55571c954a4225691"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9849f031cf8a2f0a928fe885e5a04b08006d6d41876b8bbd2fc68a18f9f2e3fd"}, - {file = "pydantic-1.10.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:56e3ff861c3b9c6857579de282ce8baabf443f42ffba355bf070770ed63e11e1"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f00790179497767aae6bcdc36355792c79e7bbb20b145ff449700eb076c5f96"}, - {file = "pydantic-1.10.13-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:75b297827b59bc229cac1a23a2f7a4ac0031068e5be0ce385be1462e7e17a35d"}, - {file = "pydantic-1.10.13-cp39-cp39-win_amd64.whl", hash = "sha256:e70ca129d2053fb8b728ee7d1af8e553a928d7e301a311094b8a0501adc8763d"}, - {file = "pydantic-1.10.13-py3-none-any.whl", hash = "sha256:b87326822e71bd5f313e7d3bfdc77ac3247035ac10b0c0618bd99dcf95b1e687"}, - {file = "pydantic-1.10.13.tar.gz", hash = "sha256:32c8b48dcd3b2ac4e78b0ba4af3a2c2eb6048cb75202f0ea7b34feb740efc340"}, + {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, + {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, ] [package.dependencies] -typing-extensions = ">=4.2.0" +annotated-types = ">=0.4.0" +pydantic-core = "2.14.5" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.14.5" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, + {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, + {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, + {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, + {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, + {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, + {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, + {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, + {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, + {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, + {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, + {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, + {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, + {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, + {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, + {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.1.0" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_settings-2.1.0-py3-none-any.whl", hash = "sha256:7621c0cb5d90d1140d2f0ef557bdf03573aac7035948109adf2574770b77605a"}, + {file = "pydantic_settings-2.1.0.tar.gz", hash = "sha256:26b1492e0a24755626ac5e6d715e9077ab7ad4fb5f19a8b7ed7011d52f36141c"}, +] + +[package.dependencies] +pydantic = ">=2.3.0" +python-dotenv = ">=0.21.0" [[package]] name = "pyflakes" @@ -1819,13 +2017,13 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "0.19.2" +version = "1.0.0" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"}, - {file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"}, + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, ] [package.extras] @@ -1854,6 +2052,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1861,8 +2060,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1879,6 +2085,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1886,6 +2093,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1912,23 +2120,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "rfc3986" -version = "1.5.0" -description = "Validating URI References per RFC 3986" -optional = false -python-versions = "*" -files = [ - {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, - {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, -] - -[package.dependencies] -idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} - -[package.extras] -idna2008 = ["idna"] - [[package]] name = "scipy" version = "1.11.4" @@ -2318,13 +2509,13 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "sqlalchemy-utils" -version = "0.40.0" +version = "0.41.1" description = "Various utility functions for SQLAlchemy." optional = false python-versions = ">=3.6" files = [ - {file = "SQLAlchemy-Utils-0.40.0.tar.gz", hash = "sha256:af803089a7929803faeb6173b90f29d1a67ad02f1d1e732f40b054a8eb3c7370"}, - {file = "SQLAlchemy_Utils-0.40.0-py3-none-any.whl", hash = "sha256:4c7098d4857d5cad1248bf7cd940727aecb75b596a5574b86a93b37079929520"}, + {file = "SQLAlchemy-Utils-0.41.1.tar.gz", hash = "sha256:a2181bff01eeb84479e38571d2c0718eb52042f9afd8c194d0d02877e84b7d74"}, + {file = "SQLAlchemy_Utils-0.41.1-py3-none-any.whl", hash = "sha256:6c96b0768ea3f15c0dc56b363d386138c562752b84f647fb8d31a2223aaab801"}, ] [package.dependencies] @@ -2339,20 +2530,20 @@ intervals = ["intervals (>=0.7.1)"] password = ["passlib (>=1.6,<2.0)"] pendulum = ["pendulum (>=2.0.5)"] phone = ["phonenumbers (>=5.9.2)"] -test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] -test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] timezone = ["python-dateutil"] url = ["furl (>=0.4.1)"] [[package]] name = "starlette" -version = "0.26.1" +version = "0.27.0" description = "The little ASGI library that shines." optional = false python-versions = ">=3.7" files = [ - {file = "starlette-0.26.1-py3-none-any.whl", hash = "sha256:e87fce5d7cbdde34b76f0ac69013fd9d190d581d80681493016666e6f96c6d5e"}, - {file = "starlette-0.26.1.tar.gz", hash = "sha256:41da799057ea8620e4667a3e69a5b1923ebd32b1819c8fa75634bbe8d8bea9bd"}, + {file = "starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91"}, + {file = "starlette-0.27.0.tar.gz", hash = "sha256:6a6b0d042acb8d469a01eba54e9cda6cbd24ac602c4cd016723117d6a7e73b75"}, ] [package.dependencies] @@ -2408,25 +2599,44 @@ files = [ {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, ] +[[package]] +name = "typeguard" +version = "4.1.5" +description = "Run-time type checker for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typeguard-4.1.5-py3-none-any.whl", hash = "sha256:8923e55f8873caec136c892c3bed1f676eae7be57cdb94819281b3d3bc9c0953"}, + {file = "typeguard-4.1.5.tar.gz", hash = "sha256:ea0a113bbc111bcffc90789ebb215625c963411f7096a7e9062d4e4630c155fd"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.7.0", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=7)", "mypy (>=1.2.0)", "pytest (>=7)"] + [[package]] name = "typer" -version = "0.4.2" +version = "0.9.0" description = "Typer, build great CLIs. Easy to code. Based on Python type hints." optional = false python-versions = ">=3.6" files = [ - {file = "typer-0.4.2-py3-none-any.whl", hash = "sha256:023bae00d1baf358a6cc7cea45851639360bb716de687b42b0a4641cd99173f1"}, - {file = "typer-0.4.2.tar.gz", hash = "sha256:b8261c6c0152dd73478b5ba96ba677e5d6948c715c310f7c91079f311f62ec03"}, + {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, + {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, ] [package.dependencies] click = ">=7.1.1,<9.0.0" +typing-extensions = ">=3.7.4.3" [package.extras] -all = ["colorama (>=0.4.3,<0.5.0)", "shellingham (>=1.3.0,<2.0.0)"] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)"] -test = ["black (>=22.3.0,<23.0.0)", "coverage (>=5.2,<6.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<5.4.0)", "pytest-cov (>=2.10.0,<3.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<2.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] [[package]] name = "typing-extensions" @@ -2603,4 +2813,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.10, <3.12" -content-hash = "2669fc102f40f4db66c51b17772753019b7080e04f13a24c5dba2d8d553b4ad4" +content-hash = "456489cf4930d53cf3f897c48b923b5c8a8e19c1c02c30ee8bf902eafb2edd20" diff --git a/pyproject.toml b/pyproject.toml index f6b7f20d..90f83192 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ python = ">=3.10, <3.12" click = ">= 8" pyam-iamc = ">=2.0.0" openpyxl = "^3.1.2" -pydantic = "<2" +pydantic = "^2" PyYAML = "^6.0.1" pandas = ">=1.5.2" pycountry = "^23.12.11" @@ -24,6 +24,7 @@ black = "^23.12.0" mypy = "^1.7.1" flake8 = "^6.1.0" pytest = "^7.4.3" +coverage = "^7.3.3" [tool.poetry.group.docs.dependencies] diff --git a/tests/test_code.py b/tests/test_code.py index 9e3a3fb7..2f2ee44c 100644 --- a/tests/test_code.py +++ b/tests/test_code.py @@ -154,10 +154,12 @@ def test_RegionCode_iso3_code_list_fail(): ] error_pattern = ( - "1 validation error for RegionCode\niso3_codes\n Region 'Western Europe' has " + "1 validation error for RegionCode\n" + "iso3_codes\n" + " Value error, Region 'Western Europe' has " "invalid ISO3 country code\(s\): DMK, IPL, ATZ, FNL, FRE, DEX, GRE, " # noqa "IBL, ITL, LIC, MLA, BEG, FRT, ANB, GDR, LXB, MNO, NTD, NRW, PRE, EPA, " # noqa - "SWD, CEW, GTR, SOR \(type=value_error\)" # noqa + "SWD, CEW, GTR, SOR" # noqa ) with pytest.raises(ValueError, match=error_pattern): RegionCode(name="Western Europe", hierarchy="R5OECD", iso3_codes=iso3_codes) @@ -165,8 +167,9 @@ def test_RegionCode_iso3_code_list_fail(): def test_RegionCode_iso3_code_str_fail(): error_pattern = ( - "1 validation error for RegionCode\niso3_codes\n Region 'Austria' has invalid " - "ISO3 country code\(s\): AUTT \(type=value_error\)" + "1 validation error for RegionCode\n" + "iso3_codes\n" + " Value error, Region 'Austria' has invalid ISO3 country code\(s\): AUTT" ) with pytest.raises(ValueError, match=error_pattern): RegionCode(name="Austria", hierarchy="country", iso3_codes="AUTT") diff --git a/tests/test_codelist.py b/tests/test_codelist.py index 3384bec3..bdc6767b 100644 --- a/tests/test_codelist.py +++ b/tests/test_codelist.py @@ -10,7 +10,6 @@ RegionCodeList, MetaCodeList, ) -from nomenclature.error.codelist import DuplicateCodeError from conftest import TEST_DATA_DIR @@ -45,7 +44,7 @@ def test_codelist_to_yaml(): def test_duplicate_code_raises(): """Check that code conflicts across different files raises""" match = "Duplicate item in variable codelist: Some Variable" - with pytest.raises(DuplicateCodeError, match=match): + with pytest.raises(ValueError, match=match): VariableCodeList.from_directory( "variable", TEST_DATA_DIR / "duplicate_code_raises" ) @@ -54,7 +53,7 @@ def test_duplicate_code_raises(): def test_duplicate_tag_raises(): """Check that code conflicts across different files raises""" match = "Duplicate item in tag codelist: Tag" - with pytest.raises(DuplicateCodeError, match=match): + with pytest.raises(ValueError, match=match): VariableCodeList.from_directory( "variable", TEST_DATA_DIR / "duplicate_tag_raises" ) diff --git a/tests/test_definition.py b/tests/test_definition.py index cd90f4dd..2de7187e 100644 --- a/tests/test_definition.py +++ b/tests/test_definition.py @@ -1,4 +1,3 @@ -import shutil import pytest import pandas as pd from nomenclature import DataStructureDefinition, create_yaml_from_xlsx @@ -20,7 +19,6 @@ def test_definition_with_custom_dimension(simple_definition): assert obs.variable == simple_definition.variable # check that "custom" dimensions are as expected - file = "scenario/scenarios.yaml" assert obs.scenario["scen_a"] == Code( name="scen_a", extra_attributes={"attribute": "value"} ) diff --git a/tests/test_region_aggregation.py b/tests/test_region_aggregation.py index a6f9f829..b9e6b600 100644 --- a/tests/test_region_aggregation.py +++ b/tests/test_region_aggregation.py @@ -9,7 +9,6 @@ RegionProcessor, process, ) -from nomenclature.error.region import RegionAggregationMappingParsingError from nomenclature.processor.region import NativeRegion, CommonRegion from pyam import IamDataFrame, assert_iamframe_equal from pyam.utils import IAMC_IDX @@ -91,9 +90,7 @@ def test_illegal_mappings(file, error_msg_pattern): def test_mapping_parsing_error(): - with pytest.raises( - RegionAggregationMappingParsingError, match="string indices must be integers" - ): + with pytest.raises(ValueError, match="string indices must be integers"): RegionAggregationMapping.from_file( TEST_FOLDER_REGION_MAPPING / "illegal_mapping_invalid_format_dict.yaml" ) @@ -146,11 +143,13 @@ def test_region_processor_not_defined(simple_definition): # Test a RegionProcessor with regions that are not defined in the data structure # definition error_msg = ( - "model_(a|b).*\n.*region_a.*mapping_(1|2).yaml.*value_error.region_not_defined" - ".*\n.*model_(a|b).*\n.*region_a.*mapping_(1|2).yaml.*value_error." - "region_not_defined" + "mappings.model_(a|b).*\n" + ".*region_a.*mapping_(1|2).yaml.*region_not_defined.*\n" + "mappings.model_(a|b).*\n" + ".*region_a.*mapping_(1|2).yaml.*region_not_defined" ) - with pytest.raises(pydantic.ValidationError, match=error_msg): + + with pytest.raises(ValueError, match=error_msg): RegionProcessor.from_directory( TEST_DATA_DIR / "regionprocessor_not_defined", simple_definition ) @@ -158,7 +157,7 @@ def test_region_processor_not_defined(simple_definition): def test_region_processor_duplicate_model_mapping(simple_definition): error_msg = ".*model_a.*mapping_(1|2).yaml.*mapping_(1|2).yaml" - with pytest.raises(pydantic.ValidationError, match=error_msg): + with pytest.raises(ValueError, match=error_msg): RegionProcessor.from_directory( TEST_DATA_DIR / "regionprocessor_duplicate", simple_definition ) @@ -169,7 +168,7 @@ def test_region_processor_wrong_args(): # Test with an integer with pytest.raises(pydantic.ValidationError, match=".*path\n.*not a valid path.*"): - RegionProcessor.from_directory(123) + RegionProcessor.from_directory(path=123) # Test with a file, a path pointing to a directory is required with pytest.raises( @@ -177,15 +176,15 @@ def test_region_processor_wrong_args(): match=".*path\n.*does not point to a directory.*", ): RegionProcessor.from_directory( - TEST_DATA_DIR / "regionprocessor_working/mapping_1.yml" + path=TEST_DATA_DIR / "regionprocessor_working/mapping_1.yml" ) def test_region_processor_multiple_wrong_mappings(simple_definition): # Read in the entire region_aggregation directory and return **all** errors - msg = "9 validation errors for RegionProcessor" + msg = "Collected 9 errors" - with pytest.raises(pydantic.ValidationError, match=msg): + with pytest.raises(ValueError, match=msg): RegionProcessor.from_directory( TEST_DATA_DIR / "region_aggregation", simple_definition ) @@ -195,7 +194,7 @@ def test_region_processor_exclude_model_native_overlap_raises(simple_definition) # Test that exclude regions in either native or common regions raise errors with pytest.raises( - pydantic.ValidationError, + ValueError, match=( "'region_a'.* ['native_regions'|'common_regions'].*\n.*\n.*'region_a'.*" "['native_regions'|'common_regions']" diff --git a/tests/test_required_data.py b/tests/test_required_data.py index 0ef7e036..e616e250 100644 --- a/tests/test_required_data.py +++ b/tests/test_required_data.py @@ -1,35 +1,35 @@ from copy import deepcopy -import pandas as pd import pytest from conftest import TEST_DATA_DIR from pyam import assert_iamframe_equal from nomenclature import DataStructureDefinition, RequiredDataValidator from nomenclature.processor.required_data import RequiredMeasurand -from nomenclature.error.required_data import RequiredDataMissingError REQUIRED_DATA_TEST_DIR = TEST_DATA_DIR / "required_data" / "required_data" def test_RequiredDataValidator_from_file(): - exp = { - "description": "Required variables for running MAGICC", - "model": ["model_a"], - "required_data": [ - { - "measurand": [ - RequiredMeasurand(variable="Emissions|CO2", unit="Mt CO2/yr") - ], - "region": ["World"], - "year": [2020, 2030, 2040, 2050], - }, - ], - "file": REQUIRED_DATA_TEST_DIR / "requiredData.yaml", - } + exp = RequiredDataValidator( + **{ + "description": "Required variables for running MAGICC", + "model": ["model_a"], + "required_data": [ + { + "measurand": [ + RequiredMeasurand(variable="Emissions|CO2", unit="Mt CO2/yr") + ], + "region": ["World"], + "year": [2020, 2030, 2040, 2050], + }, + ], + "file": REQUIRED_DATA_TEST_DIR / "requiredData.yaml", + } + ) obs = RequiredDataValidator.from_file(REQUIRED_DATA_TEST_DIR / "requiredData.yaml") - assert obs.dict(exclude_unset=True) == exp + assert obs == exp def test_RequiredDataValidator_validate_with_definition(): @@ -96,7 +96,7 @@ def test_RequiredData_apply_raises(simple_df, caplog): REQUIRED_DATA_TEST_DIR / "requiredData_apply_error.yaml" ) # assert that the correct error is raised - with pytest.raises(RequiredDataMissingError, match="Required data missing"): + with pytest.raises(ValueError, match="Required data missing"): required_data_validator.apply(simple_df) missing_data = [