diff --git a/.gitignore b/.gitignore index 4c454286..bb2539fd 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ nmdc_automation/workflow_automation/_state/*.json # Ignore `coverage.xml` file in this directory. /coverage.xml +prof/ diff --git a/nmdc_automation/__init__.py b/nmdc_automation/__init__.py index 0dd591c9..356b0118 100644 --- a/nmdc_automation/__init__.py +++ b/nmdc_automation/__init__.py @@ -2,3 +2,4 @@ from .config import siteconfig from .import_automation import activity_mapper from .workflow_automation import watch_nmdc, wfutils, workflows, workflow_process +from .models import workflow, nmdc diff --git a/nmdc_automation/api/nmdcapi.py b/nmdc_automation/api/nmdcapi.py index 15efb92c..78d3adc2 100755 --- a/nmdc_automation/api/nmdcapi.py +++ b/nmdc_automation/api/nmdcapi.py @@ -193,6 +193,8 @@ def post_objects(self, obj_data): url = self._base_url + "workflows/workflow_executions" resp = requests.post(url, headers=self.header, data=json.dumps(obj_data)) + if not resp.ok: + resp.raise_for_status() return resp.json() @refresh_token @@ -320,6 +322,8 @@ def update_op(self, opid, done=None, results=None, meta=None): def run_query(self, query): url = "%squeries:run" % self._base_url resp = requests.post(url, headers=self.header, data=json.dumps(query)) + if not resp.ok: + resp.raise_for_status() return resp.json() diff --git a/nmdc_automation/import_automation/activity_mapper.py b/nmdc_automation/import_automation/activity_mapper.py index 1226855e..303c1725 100644 --- a/nmdc_automation/import_automation/activity_mapper.py +++ b/nmdc_automation/import_automation/activity_mapper.py @@ -13,6 +13,7 @@ from linkml_runtime.dumpers import json_dumper from nmdc_automation.api import NmdcRuntimeApi +from nmdc_automation.models.nmdc import DataObject, workflow_process_factory from .utils import object_action, file_link, get_md5, filter_import_by_type logger = logging.getLogger(__name__) @@ -26,7 +27,7 @@ def __init__( nucelotide_sequencing_id: str, yaml_file: Union[str, Path], project_directory: Union[str, Path], - site_config_file: Union[str, Path], + runtime: NmdcRuntimeApi, ): """ Initialize the GoldMapper object. @@ -39,9 +40,7 @@ def __init__( project_directory: Project directory path. """ - with open(yaml_file, "r") as file: - self.import_data = yaml.safe_load(file) - + self.import_data = self.load_yaml_file(yaml_file) self.nmdc_db = nmdc.Database() self.iteration = iteration self.file_list = file_list @@ -52,140 +51,170 @@ def __init__( self.project_dir = project_directory self.url = self.import_data["Workflow Metadata"]["Source URL"] self.data_object_type = "nmdc:DataObject" - self.objects = {} + self.data_object_map = {} self.workflow_execution_ids = {} - self.workflows_by_type = {} + self.workflows_by_type = self.build_workflows_by_type() + self.runtime = runtime - self.runtime = NmdcRuntimeApi(site_config_file) - for wf in self.import_data["Workflows"]: - self.workflows_by_type[wf["Type"]] = wf + def load_yaml_file(self, yaml_file: Union[str, Path]) -> Dict: + """Utility function to load YAML file.""" + with open(yaml_file, "r") as file: + return yaml.safe_load(file) + + def build_workflows_by_type(self) -> Dict: + """Builds a dictionary of workflows by their type.""" + return {wf["Type"]: wf for wf in self.import_data["Workflows"]} - def unique_object_mapper(self) -> None: + def map_sequencing_data(self) -> Tuple[nmdc.Database, Dict]: """ - Map unique data objects from the file list based on unique matching import suffix. - The method relates each object to an workflow execution ID and updates the file with object action. - It updates the nmdc database with the DataObject and stores the information in the objects dictionary. + Map sequencing data to an NMDC data object and create an update to be applied to the has_output + list of the sequencing data generation. """ - - for data_object_dict in self.import_data["Data Objects"]["Unique"]: - if not filter_import_by_type( - self.import_data["Workflows"], data_object_dict["output_of"] - ): - continue - for file in self.file_list: - file = str(file) - if data_object_dict is None: - continue - elif "import_suffix" not in data_object_dict: - logging.warning("Missing suffix") - continue - - elif re.search(data_object_dict["import_suffix"], file): - workflow_execution_id = self.get_workflow_execution_id(data_object_dict["output_of"]) - + # Define the sequencing types to look for - + sequencing_types = ["Metagenome Raw Reads",] + db = nmdc.Database() + + # get the Metagenome Raw Reads import data + sequencing_import_data = [ + d for d in self.import_data["Data Objects"]["Unique"] if d["data_object_type"] in sequencing_types + ] + has_output = [] + for data_object_dict in sequencing_import_data: + # get the file(s) that match the import suffix + for import_file in self.file_list: + import_file = str(import_file) + if re.search(data_object_dict["import_suffix"], import_file): + logging.debug(f"Processing {data_object_dict['data_object_type']}") file_destination_name = object_action( - file, + import_file, data_object_dict["action"], - workflow_execution_id, + self.nucelotide_sequencing_id, data_object_dict["nmdc_suffix"], ) - - workflow_execution_dir = os.path.join(self.root_dir, workflow_execution_id) - - updated_file = file_link( - self.project_dir, file, workflow_execution_dir, file_destination_name - ) - - filemeta = os.stat(updated_file) - - md5 = get_md5(updated_file) - - dobj = self.runtime.minter(self.data_object_type) - - self.nmdc_db.data_object_set.append( - nmdc.DataObject( - file_size_bytes=filemeta.st_size, - name=file_destination_name, - url=f"{self.url}/{self.nucelotide_sequencing_id}/{workflow_execution_id}/{file_destination_name}", - data_object_type=data_object_dict["data_object_type"], - type=self.data_object_type, - id=dobj, - md5_checksum=md5, - description=data_object_dict["description"].replace( - "{id}", self.nucelotide_sequencing_id - ), + # sequencing_dir = os.path.join(self.root_dir, self.nucelotide_sequencing_id) + try: + os.makedirs(self.root_dir) + except FileExistsError: + logger.debug(f"{self.root_dir} already exists") + + export_file = os.path.join(self.root_dir, file_destination_name) + + try: + os.link(import_file, export_file) + except FileExistsError: + logger.debug(f"{export_file} already exists") + + filemeta = os.stat(export_file) + md5 = get_md5(export_file) + data_object_id = self.runtime.minter(self.data_object_type) + # Imported nucleotide sequencing data object does not have a URL + do_record = { + "id": data_object_id, + "type": self.data_object_type, + "name": file_destination_name, + "file_size_bytes": filemeta.st_size, + "md5_checksum": md5, + "data_object_type": data_object_dict["data_object_type"], + "description": data_object_dict["description"].replace( + "{id}", self.nucelotide_sequencing_id ) - ) - self.objects[data_object_dict["data_object_type"]] = ( - data_object_dict["input_to"], - [data_object_dict["output_of"]], - dobj, - ) + } + db.data_object_set.append(DataObject(**do_record)) + has_output.append(data_object_id) + update = { + "collection": "data_generation_set", + "filter": {"id": self.nucelotide_sequencing_id}, + "update": {"$addToSet": {"has_output": has_output}} + } + # update self.data_object_map + if len(has_output) > 1: + raise ValueError("More than one sequencing data object found") + self.data_object_map["Metagenome Raw Reads"] = ( + ["nmdc:ReadQcAnalysis"], ["nmdc:NucleotideSequencing"], has_output[0] + ) + return db, update - def multiple_objects_mapper(self) -> None: + + def map_data(self,db: nmdc.Database, unique: bool = True) -> Tuple[nmdc.Database, Dict]: """ - Maps multiple data objects from the file list based on matching import suffix into one nmdc data object. - The method relates each object to an workflow execution ID and updates the file with object action. - It updates the nmdc database with the DataObject and stores the information in the objects dictionary. + Map data objects to the NMDC database. """ - multiple_objects_list = [] - - for data_object_dict in self.import_data["Data Objects"]["Multiples"]: - for file in self.file_list: - file = str(file) - if re.search(data_object_dict["import_suffix"], file): - multiple_objects_list.append(file) - - workflow_execution_id = self.get_workflow_execution_id(data_object_dict["output_of"]) - - workflow_execution_dir = os.path.join(self.root_dir, workflow_execution_id) - + def process_files(files: Union[str, List[str]], data_object_dict: Dict, workflow_execution_id: str, + multiple: bool = False) -> DataObject: + """ + Process import file(s) and return a DataObject instance. Map data object ids to input_to and + output_of workflow execution types. + """ file_destination_name = object_action( - multiple_objects_list, + files, data_object_dict["action"], workflow_execution_id, data_object_dict["nmdc_suffix"], - workflow_execution_dir=workflow_execution_dir, - multiple=True, + workflow_execution_dir=os.path.join(self.root_dir, workflow_execution_id), + multiple=multiple, ) - updated_file = file_link( self.project_dir, - multiple_objects_list, - workflow_execution_dir, + files, + os.path.join(self.root_dir, workflow_execution_id), file_destination_name, ) - filemeta = os.stat(updated_file) - md5 = get_md5(updated_file) - - dobj = self.runtime.minter(self.data_object_type) - - self.nmdc_db.data_object_set.append( - nmdc.DataObject( - file_size_bytes=filemeta.st_size, - name=data_object_dict["name"], - url=f"{self.url}/{self.nucelotide_sequencing_id}/{workflow_execution_id}/{file_destination_name}", - data_object_type=data_object_dict["data_object_type"], - type=self.data_object_type, - id=dobj, - md5_checksum=md5, - description=data_object_dict["description"].replace( - "{id}", self.nucelotide_sequencing_id - ), + data_object_id = self.runtime.minter(self.data_object_type) + do_record = { + "id": data_object_id, + "type": self.data_object_type, + "name": file_destination_name, + "url": f"{self.url}/{self.nucelotide_sequencing_id}/{workflow_execution_id}/{file_destination_name}", + "file_size_bytes": filemeta.st_size, + "md5_checksum": md5, + "data_object_type": data_object_dict["data_object_type"], + "description": data_object_dict["description"].replace( + "{id}", self.nucelotide_sequencing_id ) - ) - - self.objects[data_object_dict["data_object_type"]] = ( + } + # update self.objects mapping + self.data_object_map[data_object_dict["data_object_type"]] = ( data_object_dict["input_to"], [data_object_dict["output_of"]], - dobj, + data_object_id, ) + return DataObject(**do_record) + + # Select the correct data source (unique or multiple) + data_objects_key = "Unique" if unique else "Multiples" + data_object_specs = self.import_data["Data Objects"][data_objects_key] + for data_object_spec in data_object_specs: + if not filter_import_by_type(self.import_data["Workflows"], data_object_spec["output_of"]): + continue + if not "import_suffix" in data_object_spec: + logging.warning("Missing suffix") + continue + + # Process unique data objects + if unique: + for file in map(str, self.file_list): + if re.search(data_object_spec["import_suffix"], file): + workflow_execution_id = self.get_workflow_execution_id(data_object_spec["output_of"]) + db.data_object_set.append(process_files(file, data_object_spec, workflow_execution_id)) + + # Process multiple data data files into a single data object + else: + multiple_files = [] + for file in map(str, self.file_list): + if re.search(data_object_spec["import_suffix"], file): + multiple_files.append(file) + if multiple_files: + workflow_execution_id = self.get_workflow_execution_id(data_object_spec["output_of"]) + db.data_object_set.append(process_files(multiple_files, data_object_spec, workflow_execution_id, multiple=True)) - def workflow_execution_mapper(self) -> None: + return db, self.data_object_map + + + def map_workflow_executions(self, db) -> nmdc.Database: """ Maps workflow executions from the import data to the NMDC database. The function creates a database workflow execution set for each workflow type in the import data, @@ -200,39 +229,45 @@ def workflow_execution_mapper(self) -> None: if not workflow.get("Import"): continue logging.info(f"Processing {workflow['Name']}") + + # Get the input / output lists for the workflow execution type has_inputs_list, has_output_list = self.attach_objects_to_workflow_execution( workflow["Type"] ) - # quick fix because nmdc-schema does not support [], even though raw product has none - if len(has_output_list) == 0: - logging.warning("No outputs. That seems odd.") - has_output_list = ["None"] - # input may be none for metagenome sequencing - if len(has_inputs_list) == 0: - has_inputs_list = ["None"] - # Lookup the nmdc database class - database_workflow_execution_set = getattr(self.nmdc_db, workflow["Collection"]) - # Lookup the nmdc schema range class - database_workflow_execution_range = getattr(nmdc, workflow["WorkflowExecutionRange"]) - # Mint an ID - workflow_execution_id = self.get_workflow_execution_id(workflow["Type"]) - database_workflow_execution_set.append( - database_workflow_execution_range( - id=workflow_execution_id, - name=workflow["Workflow_Execution"]["name"].replace("{id}", workflow_execution_id), - git_url=workflow["Git_repo"], - version=workflow["Version"], - execution_resource=self.import_data["Workflow Metadata"][ - "Execution Resource" - ], - started_at_time=datetime.datetime.now(pytz.utc).isoformat(), - has_input=has_inputs_list, - has_output=has_output_list, - type=workflow["Type"], - ended_at_time=datetime.datetime.now(pytz.utc).isoformat(), - was_informed_by=self.nucelotide_sequencing_id, + # We can't make a valid workflow execution without inputs and outputs + if not has_inputs_list or not has_output_list: + logging.error( + f"Skipping {workflow['Name']} due to missing inputs or outputs" ) - ) + continue + # Mint an ID if needed + wf_id = self.workflow_execution_ids.get(workflow["Type"], None) + if wf_id is None: + # mint an ID + wf_id = self.runtime.minter(workflow["Type"]) + "." + self.iteration + # store the ID + self.workflow_execution_ids[workflow["Type"]] = wf_id + + + # Create the workflow execution object + record = { + "id": wf_id, + "name": workflow["Workflow_Execution"]["name"].replace("{id}", wf_id), + "type": workflow["Type"], + "has_input": has_inputs_list, + "has_output": has_output_list, + "git_url": workflow["Git_repo"], + "version": workflow["Version"], + "execution_resource": self.import_data["Workflow Metadata"]["Execution Resource"], + "started_at_time": datetime.datetime.now(pytz.utc).isoformat(), + "ended_at_time": datetime.datetime.now(pytz.utc).isoformat(), + "was_informed_by": self.nucelotide_sequencing_id + } + wfe = workflow_process_factory(record) + db.workflow_execution_set.append(wfe) + + return db + def get_workflow_execution_id(self, output_of: str) -> str: """Lookup and returns minted workflow execution id @@ -269,40 +304,14 @@ def attach_objects_to_workflow_execution( workflow execution type. """ - data_object_outputs_of_list = [] - - data_object_inputs_to_list = [] + has_input = [] + has_output = [] - for _, data_object_items in self.objects.items(): - if workflow_execution_type in data_object_items[1]: - data_object_outputs_of_list.append(data_object_items[2]) - elif workflow_execution_type in data_object_items[0]: - data_object_inputs_to_list.append(data_object_items[2]) + for _, data_object_items in self.data_object_map.items(): + input_types, ouput_types, data_object_id = data_object_items + if workflow_execution_type in input_types: + has_input.append(data_object_id) + if workflow_execution_type in ouput_types: + has_output.append(data_object_id) - return data_object_inputs_to_list, data_object_outputs_of_list - - def post_nmdc_database_object(self) -> Dict: - """ - Post the nmdc database object. - - This function dumps the NMDC database object into JSON format, then posts - it using the runtime API. - - Returns: - Dict: The response from the runtime API after posting the object. - """ - - nmdc_database_object = json.loads( - json_dumper.dumps(self.nmdc_db, inject_type=False) - ) - res = self.runtime.post_objects(nmdc_database_object) - return res - - def get_database_object_dump(self) -> nmdc.Database: - """ - Get the NMDC database object. - - Returns: - nmdc.Database: NMDC database object. - """ - return self.nmdc_db + return has_input, has_output diff --git a/nmdc_automation/import_automation/utils.py b/nmdc_automation/import_automation/utils.py index 73007e3c..e818cd43 100644 --- a/nmdc_automation/import_automation/utils.py +++ b/nmdc_automation/import_automation/utils.py @@ -145,7 +145,7 @@ def file_link( linked_path = os.path.join(destination_dir, updated_file) try: - os.link(original_path, linked_path) + os.link(import_file, linked_path) except FileExistsError: logger.info(f"{linked_path} already exists") diff --git a/nmdc_automation/models/__init__.py b/nmdc_automation/models/__init__.py new file mode 100644 index 00000000..ea870490 --- /dev/null +++ b/nmdc_automation/models/__init__.py @@ -0,0 +1 @@ +""" Data classes for NMDC automation. """ \ No newline at end of file diff --git a/nmdc_automation/models/nmdc.py b/nmdc_automation/models/nmdc.py new file mode 100644 index 00000000..0b964474 --- /dev/null +++ b/nmdc_automation/models/nmdc.py @@ -0,0 +1,119 @@ +""" Factory methods for NMDC models. """ +import importlib.resources +from typing import Any, Dict, Union +import linkml_runtime +import linkml.validator +import importlib.resources +from functools import lru_cache +from linkml_runtime.dumpers import yaml_dumper +import yaml + + +from nmdc_schema.nmdc import DataGeneration, FileTypeEnum, MagsAnalysis, MetagenomeAnnotation, MetagenomeAssembly, \ + MetatranscriptomeAnnotation, MetatranscriptomeAssembly, MetatranscriptomeExpressionAnalysis, NucleotideSequencing, \ + ReadBasedTaxonomyAnalysis, ReadQcAnalysis, WorkflowExecution +import nmdc_schema.nmdc as nmdc + + +@lru_cache(maxsize=None) +def get_nmdc_materialized(): + with importlib.resources.open_text("nmdc_schema", "nmdc_materialized_patterns.yaml") as f: + return yaml.safe_load(f) + +def workflow_process_factory(record: Dict[str, Any], validate: bool = False) -> Union[DataGeneration, +WorkflowExecution]: + """ + Factory function to create a PlannedProcess subclass object from a record. + Subclasses are determined by the "type" field in the record, and can be + either a WorkflowExecution or DataGeneration object. + """ + nmdc_materialized = get_nmdc_materialized() + process_types = { + "nmdc:MagsAnalysis": MagsAnalysis, + "nmdc:MetagenomeAnnotation": MetagenomeAnnotation, + "nmdc:MetagenomeAssembly": MetagenomeAssembly, + "nmdc:MetatranscriptomeAnnotation": MetatranscriptomeAnnotation, + "nmdc:MetatranscriptomeAssembly": MetatranscriptomeAssembly, + "nmdc:MetatranscriptomeExpressionAnalysis": MetatranscriptomeExpressionAnalysis, + "nmdc:NucleotideSequencing": NucleotideSequencing, + "nmdc:ReadBasedTaxonomyAnalysis": ReadBasedTaxonomyAnalysis, + "nmdc:ReadQcAnalysis": ReadQcAnalysis, + } + record = _normalize_record(record) + target_class = record["type"].split(":")[1] + if validate: + validation_report = linkml.validator.validate(record, nmdc_materialized, target_class) + if validation_report.results: + raise ValueError(f"Validation error: {validation_report.results[0].message}") + + + + + try: + cls = process_types[record["type"]] + except KeyError: + raise ValueError(f"Invalid workflow execution type: {record['type']}") + wfe = cls(**record) + return wfe + + +def _normalize_record(record: Dict[str, Any]) -> Dict[str, Any]: + """ Normalize the record by removing the _id field and converting the type field to a string """ + record.pop("_id", None) + # for backwards compatibility strip Activity from the end of the type + record["type"] = record["type"].replace("Activity", "") + normalized_record = _strip_empty_values(record) + + + # type-specific normalization + if normalized_record["type"] == "nmdc:MagsAnalysis": + normalized_record = _normalize_mags_record(normalized_record) + + return normalized_record + + +def _normalize_mags_record(record: Dict[str, Any]) -> Dict[str, Any]: + """ Normalize the record for a MagsAnalysis object """ + for i, mag in enumerate(record.get("mags_list", [])): + if not mag.get("type"): + # Update the original dictionary in the list + record["mags_list"][i]["type"] = "nmdc:MagBin" + # for backwards compatibility normalize num_tRNA to num_t_rna + if "num_tRNA" in mag: + record["mags_list"][i]["num_t_rna"] = mag.pop("num_tRNA") + # add type to eukaryotic_evaluation if it exists + if "eukaryotic_evaluation" in mag: + record["mags_list"][i]["eukaryotic_evaluation"]["type"] = "nmdc:EukEval" + # gene count should be a positive integer - remove if 'null' + if "gene_count" in mag and mag["gene_count"] == "null": + mag.pop("gene_count") + return record + + +def _strip_empty_values(d: Dict[str, Any]) -> Dict[str, Any]: + """ Strip empty values from a record """ + empty_values = [None, "", []] + def clean_dict(d): + if isinstance(d, dict): + return {k: clean_dict(v) for k, v in d.items() if v not in empty_values} + elif isinstance(d, list): + return [clean_dict(v) for v in d if v not in empty_values] + return d + return clean_dict(d) + + +class DataObject(nmdc.DataObject): + """ + Extends the NMDC DataObject dataclass with additional methods for serialization. + """ + def __init__(self, **record): + """ Initialize the object from a dictionary """ + # _id is a MongoDB field that makes the parent class fail to initialize + record.pop("_id", None) + if "type" not in record: + record["type"] = "nmdc:DataObject" + super().__init__(**record) + + def as_dict(self) -> Dict[str, Any]: + """ Convert the object to a dictionary """ + return yaml.safe_load(yaml_dumper.dumps(self)) diff --git a/nmdc_automation/workflow_automation/models.py b/nmdc_automation/models/workflow.py similarity index 55% rename from nmdc_automation/workflow_automation/models.py rename to nmdc_automation/models/workflow.py index 0db245ab..ed0b29f3 100644 --- a/nmdc_automation/workflow_automation/models.py +++ b/nmdc_automation/models/workflow.py @@ -1,90 +1,11 @@ -""" Model classes for the workflow automation app. """ +""" Data classed for NMDC workflow automation. """ from dataclasses import dataclass, field -from dateutil import parser from datetime import datetime -from typing import List, Dict, Any, Optional, Set, Union - -from nmdc_schema.nmdc import ( - DataGeneration, - FileTypeEnum, - NucleotideSequencing, - MagsAnalysis, - MetagenomeAssembly, - MetagenomeAnnotation, - MetatranscriptomeAssembly, - MetatranscriptomeAnnotation, - MetatranscriptomeExpressionAnalysis, - ReadBasedTaxonomyAnalysis, - ReadQcAnalysis, - WorkflowExecution -) -from nmdc_schema import nmdc - - -def workflow_process_factory(record: Dict[str, Any]) -> Union[DataGeneration, WorkflowExecution]: - """ - Factory function to create a PlannedProcess subclass object from a record. - Subclasses are determined by the "type" field in the record, and can be - either a WorkflowExecution or DataGeneration object. - """ - process_types = { - "nmdc:MagsAnalysis": MagsAnalysis, - "nmdc:MetagenomeAnnotation": MetagenomeAnnotation, - "nmdc:MetagenomeAssembly": MetagenomeAssembly, - "nmdc:MetatranscriptomeAnnotation": MetatranscriptomeAnnotation, - "nmdc:MetatranscriptomeAssembly": MetatranscriptomeAssembly, - "nmdc:MetatranscriptomeExpressionAnalysis": MetatranscriptomeExpressionAnalysis, - "nmdc:NucleotideSequencing": NucleotideSequencing, - "nmdc:ReadBasedTaxonomyAnalysis": ReadBasedTaxonomyAnalysis, - "nmdc:ReadQcAnalysis": ReadQcAnalysis, - } - record = _normalize_record(record) - - try: - cls = process_types[record["type"]] - except KeyError: - raise ValueError(f"Invalid workflow execution type: {record['type']}") - wfe = cls(**record) - return wfe - -def _normalize_record(record: Dict[str, Any]) -> Dict[str, Any]: - """ Normalize the record by removing the _id field and converting the type field to a string """ - record.pop("_id", None) - # for backwards compatibility strip Activity from the end of the type - record["type"] = record["type"].replace("Activity", "") - normalized_record = _strip_empty_values(record) - - # type-specific normalization - if normalized_record["type"] == "nmdc:MagsAnalysis": - normalized_record = _normalize_mags_record(normalized_record) - - return normalized_record - -def _normalize_mags_record(record: Dict[str, Any]) -> Dict[str, Any]: - """ Normalize the record for a MagsAnalysis object """ - for i, mag in enumerate(record.get("mags_list", [])): - if not mag.get("type"): - # Update the original dictionary in the list - record["mags_list"][i]["type"] = "nmdc:MagBin" - # for backwards compatibility normalize num_tRNA to num_t_rna - if "num_tRNA" in mag: - record["mags_list"][i]["num_t_rna"] = mag.pop("num_tRNA") - # add type to eukaryotic_evaluation if it exists - if "eukaryotic_evaluation" in mag: - record["mags_list"][i]["eukaryotic_evaluation"]["type"] = "nmdc:EukEval" - return record - - -def _strip_empty_values(d: Dict[str, Any]) -> Dict[str, Any]: - """ Strip empty values from a record """ - empty_values = [None, "", [], "null", 0] - def clean_dict(d): - if isinstance(d, dict): - return {k: clean_dict(v) for k, v in d.items() if v not in empty_values} - elif isinstance(d, list): - return [clean_dict(v) for v in d if v not in empty_values] - return d - return clean_dict(d) +from typing import Any, Dict, List, Optional, Set + +from dateutil import parser + +from nmdc_automation.models.nmdc import DataObject, workflow_process_factory class WorkflowProcessNode(object): @@ -108,7 +29,7 @@ def __eq__(self, other): return self.id == other.id and self.type == other.type def add_data_object(self, data_object): - self.data_objects_by_type[data_object.data_object_type] = data_object + self.data_objects_by_type[data_object.data_object_type.code.text] = data_object @property def id(self): @@ -151,42 +72,6 @@ def was_informed_by(self): return getattr(self.process, "was_informed_by", self.id) -class DataObject(nmdc.DataObject): - """ - Extends the NMDC DataObject dataclass with additional methods for serialization. - """ - def __init__(self, **record): - """ Initialize the object from a dictionary """ - # _id is a MongoDB field that makes the parent class fail to initialize - record.pop("_id", None) - if "type" not in record: - record["type"] = "nmdc:DataObject" - super().__init__(**record) - - def as_dict(self): - """ Return the object as a dictionary, excluding None values, empty lists, and data_object_type as a string """ - return { - key: value - for key, value in self.__dict__.items() - if not key.startswith("_") and value - } | {"data_object_type": self.data_object_type} - - @property - def data_object_type(self): - """ Return the data object type as a string """ - if isinstance(self._data_object_type, FileTypeEnum): - return self._data_object_type.code.text - return str(self._data_object_type) - - @data_object_type.setter - def data_object_type(self, value): - """ Set the data object type from a string or FileTypeEnum """ - if isinstance(value, FileTypeEnum): - self._data_object_type = value - else: - self._data_object_type = FileTypeEnum(value) - - @dataclass class WorkflowConfig: """ Configuration for a workflow execution. Defined by .yaml files in nmdc_automation/config/workflows """ @@ -248,6 +133,7 @@ def add_parent(self, parent: "WorkflowConfig"): class JobWorkflow: id: str + @dataclass class JobConfig: """ Represents a job configuration from the NMDC API jobs endpoint / MongoDB jobs collection """ @@ -271,6 +157,7 @@ class JobClaim: op_id: str site_id: str + @dataclass class JobOutput: """ Represents a job output specification. """ @@ -292,6 +179,7 @@ def __post_init__(self): description=self.description, ) + @dataclass class Job: """ Represents a job from the NMDC API jobs endpoint / MongoDB jobs collection """ diff --git a/nmdc_automation/run_process/run_import.py b/nmdc_automation/run_process/run_import.py index 2b4beb17..922765d3 100644 --- a/nmdc_automation/run_process/run_import.py +++ b/nmdc_automation/run_process/run_import.py @@ -1,8 +1,19 @@ import click -from typing import List import csv +import importlib.resources +from functools import lru_cache +import logging import os +import linkml.validator +from linkml_runtime.dumpers import yaml_dumper +import yaml + from nmdc_automation.import_automation import GoldMapper +from nmdc_automation.api import NmdcRuntimeApi + + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) @click.group() @@ -15,34 +26,90 @@ def cli(): @click.argument("import_yaml", type=click.Path(exists=True)) @click.argument("site_configuration", type=click.Path(exists=True)) @click.option("--iteration", default=1, type=str, help="Number of iterations") -def project_import(import_file, import_yaml, site_configuration, iteration): - with open(import_file) as bioscales_file: - mappings = csv.reader(bioscales_file, delimiter="\t") - - for line in mappings: - omics_processing_id = line[0] - project_path = line[3] - files_list = [ - os.path.join(project_path, f) - for f in os.listdir(os.path.abspath(project_path)) - if os.path.isfile(os.path.join(project_path, f)) - ] - - gold_mappings = GoldMapper( - iteration, - files_list, - omics_processing_id, - import_yaml, - project_path, - site_configuration, - ) - - gold_mappings.unique_object_mapper() - # gold_mappings.multiple_objects_mapper() - gold_mappings.activity_mapper() - response = gold_mappings.post_nmdc_database_object() - print(response) - print(f"processed {omics_processing_id}") +def import_projects(import_file, import_yaml, site_configuration, iteration): + + logger.info(f"Importing project from {import_file}") + + runtime = NmdcRuntimeApi(site_configuration) + nmdc_materialized = _get_nmdc_materialized() + + data_imports = _parse_tsv(import_file) + for data_import in data_imports: + project_path = data_import["project_path"] + nucleotide_sequencing_id = data_import["nucleotide_sequencing_id"] + files_list = [ + os.path.join(project_path, f) + for f in os.listdir(os.path.abspath(project_path)) + if os.path.isfile(os.path.join(project_path, f)) + ] + + logger.info(f"Importing {nucleotide_sequencing_id} from {project_path}: {len(files_list)} files") + mapper = GoldMapper( + iteration, + files_list, + nucleotide_sequencing_id, + import_yaml, + project_path, + runtime, + ) + # Initialize the db with the sequencing data and create an update to be applied + # to the sequencing data generation has_output list + logger.info("Mapping sequencing data") + db, data_generation_update = mapper.map_sequencing_data() + # Map the rest of the data files - single files + logger.info("Mapping single data files") + db, do_mapping = mapper.map_data(db) + # Map the rest of the data files - multiple files + logger.info("Mapping multiple data files") + db, do_mapping = mapper.map_data(db, unique=False) + + # map the workflow executions + logger.info("Mapping workflow executions") + db = mapper.map_workflow_executions(db) + + # validate the database + logger.info("Validating imported data") + db_dict = yaml.safe_load(yaml_dumper.dumps(db)) + validation_report = linkml.validator.validate(db_dict, nmdc_materialized) + if validation_report.results: + logger.error(f"Validation Failed") + for result in validation_report.results: + logger.error(result.message) + raise Exception("Validation Failed") + else: + logger.info("Validation Passed") + + # apply the update to the sequencing data generation has_output list + logger.info("Applying update to sequencing data generation") + try: + runtime.run_query(data_generation_update) + except Exception as e: + logger.error(f"Error applying update to sequencing data generation: {e}") + raise e + + + # Post the data to the API + logger.info("Posting data to the API") + try: + runtime.post_objects(db_dict) + except Exception as e: + logger.error(f"Error posting data to the API: {e}") + raise e + + + + +@lru_cache(maxsize=None) +def _get_nmdc_materialized(): + with importlib.resources.open_text("nmdc_schema", "nmdc_materialized_patterns.yaml") as f: + return yaml.safe_load(f) + +def _parse_tsv(file): + with open(file) as f: + reader = csv.DictReader(f, delimiter="\t") + data = [row for row in reader] + + return data if __name__ == "__main__": diff --git a/nmdc_automation/workflow_automation/sched.py b/nmdc_automation/workflow_automation/sched.py index 08540658..8ddf92d5 100644 --- a/nmdc_automation/workflow_automation/sched.py +++ b/nmdc_automation/workflow_automation/sched.py @@ -10,7 +10,7 @@ from pymongo import MongoClient from pymongo.database import Database as MongoDatabase from nmdc_automation.workflow_automation.workflow_process import load_workflow_process_nodes -from nmdc_automation.workflow_automation.models import WorkflowProcessNode, WorkflowConfig +from nmdc_automation.models.workflow import WorkflowConfig, WorkflowProcessNode from semver.version import Version diff --git a/nmdc_automation/workflow_automation/watch_nmdc.py b/nmdc_automation/workflow_automation/watch_nmdc.py index 5894df91..091b87aa 100644 --- a/nmdc_automation/workflow_automation/watch_nmdc.py +++ b/nmdc_automation/workflow_automation/watch_nmdc.py @@ -12,8 +12,7 @@ from nmdc_schema.nmdc import Database from nmdc_automation.api import NmdcRuntimeApi from nmdc_automation.config import SiteConfig -from .wfutils import WorkflowJob -from .wfutils import _md5 +from nmdc_automation.workflow_automation.wfutils import WorkflowJob DEFAULT_STATE_DIR = Path(__file__).parent / "_state" diff --git a/nmdc_automation/workflow_automation/wfutils.py b/nmdc_automation/workflow_automation/wfutils.py index 86c67912..a4f531e1 100755 --- a/nmdc_automation/workflow_automation/wfutils.py +++ b/nmdc_automation/workflow_automation/wfutils.py @@ -16,7 +16,7 @@ import requests from nmdc_automation.config import SiteConfig -from nmdc_automation.workflow_automation.models import DataObject +from nmdc_automation.models.nmdc import DataObject DEFAULT_MAX_RETRIES = 2 diff --git a/nmdc_automation/workflow_automation/workflow_process.py b/nmdc_automation/workflow_automation/workflow_process.py index 1e2b5382..194ac1a6 100644 --- a/nmdc_automation/workflow_automation/workflow_process.py +++ b/nmdc_automation/workflow_automation/workflow_process.py @@ -5,7 +5,8 @@ from semver.version import Version -from nmdc_automation.workflow_automation.models import WorkflowProcessNode, DataObject, WorkflowConfig +from nmdc_automation.models.nmdc import DataObject +from nmdc_automation.models.workflow import WorkflowConfig, WorkflowProcessNode warned_objects = set() @@ -27,7 +28,7 @@ def get_required_data_objects_map(db, workflows: List[WorkflowConfig]) -> Dict[s required_data_objs_by_id = dict() for rec in db.data_object_set.find(): do = DataObject(**rec) - if do.data_object_type not in required_types: + if do.data_object_type.code.text not in required_types: continue required_data_objs_by_id[do.id] = do return required_data_objs_by_id @@ -64,7 +65,7 @@ def _check(match_types, data_object_ids, data_objs): do_types = set() for doid in data_object_ids: if doid in data_objs: - do_types.add(data_objs[doid].data_object_type) + do_types.add(data_objs[doid].data_object_type.code.text) return match_set.issubset(do_types) diff --git a/nmdc_automation/workflow_automation/workflows.py b/nmdc_automation/workflow_automation/workflows.py index acefd44b..f99cb4ee 100644 --- a/nmdc_automation/workflow_automation/workflows.py +++ b/nmdc_automation/workflow_automation/workflows.py @@ -5,7 +5,7 @@ except ImportError: from yaml import Loader -from nmdc_automation.workflow_automation.models import WorkflowConfig +from nmdc_automation.models.workflow import WorkflowConfig def load_workflow_configs(yaml_file) -> list[WorkflowConfig]: diff --git a/poetry.lock b/poetry.lock index f71e5de7..c88772a5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "annotated-types" @@ -131,101 +131,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -255,83 +270,73 @@ files = [ [[package]] name = "coverage" -version = "7.6.1" +version = "7.6.3" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, - {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, - {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, - {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, - {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, - {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, - {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, - {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, - {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, + {file = "coverage-7.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6da42bbcec130b188169107ecb6ee7bd7b4c849d24c9370a0c884cf728d8e976"}, + {file = "coverage-7.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c222958f59b0ae091f4535851cbb24eb57fc0baea07ba675af718fb5302dddb2"}, + {file = "coverage-7.6.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab84a8b698ad5a6c365b08061920138e7a7dd9a04b6feb09ba1bfae68346ce6d"}, + {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70a6756ce66cd6fe8486c775b30889f0dc4cb20c157aa8c35b45fd7868255c5c"}, + {file = "coverage-7.6.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c2e6fa98032fec8282f6b27e3f3986c6e05702828380618776ad794e938f53a"}, + {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:921fbe13492caf6a69528f09d5d7c7d518c8d0e7b9f6701b7719715f29a71e6e"}, + {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6d99198203f0b9cb0b5d1c0393859555bc26b548223a769baf7e321a627ed4fc"}, + {file = "coverage-7.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:87cd2e29067ea397a47e352efb13f976eb1b03e18c999270bb50589323294c6e"}, + {file = "coverage-7.6.3-cp310-cp310-win32.whl", hash = "sha256:a3328c3e64ea4ab12b85999eb0779e6139295bbf5485f69d42cf794309e3d007"}, + {file = "coverage-7.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:bca4c8abc50d38f9773c1ec80d43f3768df2e8576807d1656016b9d3eeaa96fd"}, + {file = "coverage-7.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c51ef82302386d686feea1c44dbeef744585da16fcf97deea2a8d6c1556f519b"}, + {file = "coverage-7.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ca37993206402c6c35dc717f90d4c8f53568a8b80f0bf1a1b2b334f4d488fba"}, + {file = "coverage-7.6.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c77326300b839c44c3e5a8fe26c15b7e87b2f32dfd2fc9fee1d13604347c9b38"}, + {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e484e479860e00da1f005cd19d1c5d4a813324e5951319ac3f3eefb497cc549"}, + {file = "coverage-7.6.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c6c0f4d53ef603397fc894a895b960ecd7d44c727df42a8d500031716d4e8d2"}, + {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:37be7b5ea3ff5b7c4a9db16074dc94523b5f10dd1f3b362a827af66a55198175"}, + {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:43b32a06c47539fe275106b376658638b418c7cfdfff0e0259fbf877e845f14b"}, + {file = "coverage-7.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee77c7bef0724165e795b6b7bf9c4c22a9b8468a6bdb9c6b4281293c6b22a90f"}, + {file = "coverage-7.6.3-cp311-cp311-win32.whl", hash = "sha256:43517e1f6b19f610a93d8227e47790722c8bf7422e46b365e0469fc3d3563d97"}, + {file = "coverage-7.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:04f2189716e85ec9192df307f7c255f90e78b6e9863a03223c3b998d24a3c6c6"}, + {file = "coverage-7.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27bd5f18d8f2879e45724b0ce74f61811639a846ff0e5c0395b7818fae87aec6"}, + {file = "coverage-7.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d546cfa78844b8b9c1c0533de1851569a13f87449897bbc95d698d1d3cb2a30f"}, + {file = "coverage-7.6.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9975442f2e7a5cfcf87299c26b5a45266ab0696348420049b9b94b2ad3d40234"}, + {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:583049c63106c0555e3ae3931edab5669668bbef84c15861421b94e121878d3f"}, + {file = "coverage-7.6.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2341a78ae3a5ed454d524206a3fcb3cec408c2a0c7c2752cd78b606a2ff15af4"}, + {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a4fb91d5f72b7e06a14ff4ae5be625a81cd7e5f869d7a54578fc271d08d58ae3"}, + {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e279f3db904e3b55f520f11f983cc8dc8a4ce9b65f11692d4718ed021ec58b83"}, + {file = "coverage-7.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aa23ce39661a3e90eea5f99ec59b763b7d655c2cada10729ed920a38bfc2b167"}, + {file = "coverage-7.6.3-cp312-cp312-win32.whl", hash = "sha256:52ac29cc72ee7e25ace7807249638f94c9b6a862c56b1df015d2b2e388e51dbd"}, + {file = "coverage-7.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:40e8b1983080439d4802d80b951f4a93d991ef3261f69e81095a66f86cf3c3c6"}, + {file = "coverage-7.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9134032f5aa445ae591c2ba6991d10136a1f533b1d2fa8f8c21126468c5025c6"}, + {file = "coverage-7.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:99670790f21a96665a35849990b1df447993880bb6463a0a1d757897f30da929"}, + {file = "coverage-7.6.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc7d6b380ca76f5e817ac9eef0c3686e7834c8346bef30b041a4ad286449990"}, + {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7b26757b22faf88fcf232f5f0e62f6e0fd9e22a8a5d0d5016888cdfe1f6c1c4"}, + {file = "coverage-7.6.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c59d6a4a4633fad297f943c03d0d2569867bd5372eb5684befdff8df8522e39"}, + {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f263b18692f8ed52c8de7f40a0751e79015983dbd77b16906e5b310a39d3ca21"}, + {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79644f68a6ff23b251cae1c82b01a0b51bc40c8468ca9585c6c4b1aeee570e0b"}, + {file = "coverage-7.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71967c35828c9ff94e8c7d405469a1fb68257f686bca7c1ed85ed34e7c2529c4"}, + {file = "coverage-7.6.3-cp313-cp313-win32.whl", hash = "sha256:e266af4da2c1a4cbc6135a570c64577fd3e6eb204607eaff99d8e9b710003c6f"}, + {file = "coverage-7.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:ea52bd218d4ba260399a8ae4bb6b577d82adfc4518b93566ce1fddd4a49d1dce"}, + {file = "coverage-7.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8d4c6ea0f498c7c79111033a290d060c517853a7bcb2f46516f591dab628ddd3"}, + {file = "coverage-7.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:331b200ad03dbaa44151d74daeb7da2cf382db424ab923574f6ecca7d3b30de3"}, + {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54356a76b67cf8a3085818026bb556545ebb8353951923b88292556dfa9f812d"}, + {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ebec65f5068e7df2d49466aab9128510c4867e532e07cb6960075b27658dca38"}, + {file = "coverage-7.6.3-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d33a785ea8354c480515e781554d3be582a86297e41ccbea627a5c632647f2cd"}, + {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f7ddb920106bbbbcaf2a274d56f46956bf56ecbde210d88061824a95bdd94e92"}, + {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:70d24936ca6c15a3bbc91ee9c7fc661132c6f4c9d42a23b31b6686c05073bde5"}, + {file = "coverage-7.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c30e42ea11badb147f0d2e387115b15e2bd8205a5ad70d6ad79cf37f6ac08c91"}, + {file = "coverage-7.6.3-cp313-cp313t-win32.whl", hash = "sha256:365defc257c687ce3e7d275f39738dcd230777424117a6c76043459db131dd43"}, + {file = "coverage-7.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:23bb63ae3f4c645d2d82fa22697364b0046fbafb6261b258a58587441c5f7bd0"}, + {file = "coverage-7.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:da29ceabe3025a1e5a5aeeb331c5b1af686daab4ff0fb4f83df18b1180ea83e2"}, + {file = "coverage-7.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df8c05a0f574d480947cba11b947dc41b1265d721c3777881da2fb8d3a1ddfba"}, + {file = "coverage-7.6.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec1e3b40b82236d100d259854840555469fad4db64f669ab817279eb95cd535c"}, + {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4adeb878a374126f1e5cf03b87f66279f479e01af0e9a654cf6d1509af46c40"}, + {file = "coverage-7.6.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43d6a66e33b1455b98fc7312b124296dad97a2e191c80320587234a77b1b736e"}, + {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1990b1f4e2c402beb317840030bb9f1b6a363f86e14e21b4212e618acdfce7f6"}, + {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:12f9515d875859faedb4144fd38694a761cd2a61ef9603bf887b13956d0bbfbb"}, + {file = "coverage-7.6.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99ded130555c021d99729fabd4ddb91a6f4cc0707df4b1daf912c7850c373b13"}, + {file = "coverage-7.6.3-cp39-cp39-win32.whl", hash = "sha256:c3a79f56dee9136084cf84a6c7c4341427ef36e05ae6415bf7d787c96ff5eaa3"}, + {file = "coverage-7.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:aac7501ae73d4a02f4b7ac8fcb9dc55342ca98ffb9ed9f2dfb8a25d53eda0e4d"}, + {file = "coverage-7.6.3-pp39.pp310-none-any.whl", hash = "sha256:b9853509b4bf57ba7b1f99b9d866c422c9c5248799ab20e652bbb8a184a38181"}, + {file = "coverage-7.6.3.tar.gz", hash = "sha256:bb7d5fe92bd0dc235f63ebe9f8c6e0884f7360f88f3411bfed1350c872ef2054"}, ] [package.dependencies] @@ -611,6 +616,23 @@ files = [ {file = "hbreader-0.9.1.tar.gz", hash = "sha256:d2c132f8ba6276d794c66224c3297cec25c8079d0a4cf019c061611e0a3b94fa"}, ] +[[package]] +name = "html5lib-modern" +version = "1.2" +description = "HTML parser based on the WHATWG HTML specification" +optional = false +python-versions = ">=3.8" +files = [ + {file = "html5lib_modern-1.2-py2.py3-none-any.whl", hash = "sha256:3458b6e31525ede4fcaac0ff42d9eeb5efaf755473768103cb56e0275caa8d99"}, + {file = "html5lib_modern-1.2.tar.gz", hash = "sha256:1fadbfc27ea955431270e4e79a4a4c290ba11c3a3098a95cc22dc73e312a1768"}, +] + +[package.extras] +all = ["chardet (>=2.2.1)", "genshi (>=0.7.1)", "lxml (>=3.4.0)"] +chardet = ["chardet (>=2.2.1)"] +genshi = ["genshi (>=0.7.1)"] +lxml = ["lxml (>=3.4.0)"] + [[package]] name = "idna" version = "3.10" @@ -625,6 +647,16 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +[[package]] +name = "importlib" +version = "1.0.4" +description = "Backport of importlib.import_module() from Python 2.7" +optional = false +python-versions = "*" +files = [ + {file = "importlib-1.0.4.zip", hash = "sha256:b6ee7066fea66e35f8d0acee24d98006de1a0a8a94a8ce6efe73a9a23c8d9826"}, +] + [[package]] name = "importlib-metadata" version = "8.5.0" @@ -661,18 +693,15 @@ files = [ [[package]] name = "isodate" -version = "0.6.1" +version = "0.7.2" description = "An ISO 8601 date/time/duration parser and formatter" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96"}, - {file = "isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9"}, + {file = "isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15"}, + {file = "isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6"}, ] -[package.dependencies] -six = "*" - [[package]] name = "isoduration" version = "20.11.0" @@ -774,13 +803,12 @@ jsonpointer = ">=1.9" [[package]] name = "jsonpath-ng" -version = "1.6.1" +version = "1.7.0" description = "A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming." optional = false python-versions = "*" files = [ - {file = "jsonpath-ng-1.6.1.tar.gz", hash = "sha256:086c37ba4917304850bd837aeab806670224d3f038fe2833ff593a672ef0a5fa"}, - {file = "jsonpath_ng-1.6.1-py3-none-any.whl", hash = "sha256:8f22cd8273d7772eea9aaa84d922e0841aa36fdb8a2c6b7f6c3791a16a9bc0be"}, + {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, ] [package.dependencies] @@ -1087,13 +1115,13 @@ pyyaml = ">=5.1" [[package]] name = "mkdocs-material" -version = "9.5.39" +version = "9.5.41" description = "Documentation that simply works" optional = false python-versions = ">=3.8" files = [ - {file = "mkdocs_material-9.5.39-py3-none-any.whl", hash = "sha256:0f2f68c8db89523cb4a59705cd01b4acd62b2f71218ccb67e1e004e560410d2b"}, - {file = "mkdocs_material-9.5.39.tar.gz", hash = "sha256:25faa06142afa38549d2b781d475a86fb61de93189f532b88e69bf11e5e5c3be"}, + {file = "mkdocs_material-9.5.41-py3-none-any.whl", hash = "sha256:990bc138c33342b5b73e7545915ebc0136e501bfbd8e365735144f5120891d83"}, + {file = "mkdocs_material-9.5.41.tar.gz", hash = "sha256:30fa5d459b4b8130848ecd8e1c908878345d9d8268f7ddbc31eebe88d462d97b"}, ] [package.dependencies] @@ -1186,13 +1214,13 @@ pymongo = ["pymongo"] [[package]] name = "nmdc-schema" -version = "11.0.1" +version = "11.0.3" description = "Schema resources for the National Microbiome Data Collaborative (NMDC)" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "nmdc_schema-11.0.1-py3-none-any.whl", hash = "sha256:ff4e8a150fd192fb8daf7423f7ac1bd6b0dd26c68d8030e0359748fbf4e8fd15"}, - {file = "nmdc_schema-11.0.1.tar.gz", hash = "sha256:e491484308375ae913924112b39f38796e9881abd5701621105b3d455c1ca97e"}, + {file = "nmdc_schema-11.0.3-py3-none-any.whl", hash = "sha256:e2b6bc44382c75b2522d6da2767e802a970dcc0de8db9b90aeede82769884703"}, + {file = "nmdc_schema-11.0.3.tar.gz", hash = "sha256:679ce7817766673a3bf08dfd2bd2b6a348c7fb6e6a0a742cce8cdd53a4bda8ca"}, ] [package.dependencies] @@ -1546,13 +1574,13 @@ requests = ">=2.28.1,<3.0.0" [[package]] name = "prefixmaps" -version = "0.2.5" +version = "0.2.6" description = "A python library for retrieving semantic prefix maps" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "prefixmaps-0.2.5-py3-none-any.whl", hash = "sha256:68caa04b3a6a8e058aa1c55affe32c62e44b564d031d63f768e267b796a1f3ee"}, - {file = "prefixmaps-0.2.5.tar.gz", hash = "sha256:aaccd2425ade2ea97a502c58be49fe8f3536e3d5e919712ae0358a39fc800799"}, + {file = "prefixmaps-0.2.6-py3-none-any.whl", hash = "sha256:f6cef28a7320fc6337cf411be212948ce570333a0ce958940ef684c7fb192a62"}, + {file = "prefixmaps-0.2.6.tar.gz", hash = "sha256:7421e1244eea610217fa1ba96c9aebd64e8162a930dc0626207cd8bf62ecf4b9"}, ] [package.dependencies] @@ -1835,13 +1863,13 @@ zstd = ["zstandard"] [[package]] name = "pyparsing" -version = "3.1.4" +version = "3.2.0" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false -python-versions = ">=3.6.8" +python-versions = ">=3.9" files = [ - {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"}, - {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"}, + {file = "pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84"}, + {file = "pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c"}, ] [package.extras] @@ -2169,24 +2197,25 @@ pyyaml = "*" [[package]] name = "rdflib" -version = "7.0.0" +version = "7.1.0" description = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information." optional = false -python-versions = ">=3.8.1,<4.0.0" +python-versions = "<4.0.0,>=3.8.1" files = [ - {file = "rdflib-7.0.0-py3-none-any.whl", hash = "sha256:0438920912a642c866a513de6fe8a0001bd86ef975057d6962c79ce4771687cd"}, - {file = "rdflib-7.0.0.tar.gz", hash = "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae"}, + {file = "rdflib-7.1.0-py3-none-any.whl", hash = "sha256:240c25c6e1b573ffa67aed23aae128e253c443c15291c9a01d8d392ea80c05b6"}, + {file = "rdflib-7.1.0.tar.gz", hash = "sha256:a29a8fccebd3d3a5f1b7e88d92dace1c89829018c7d29a6114fff4449c188b3b"}, ] [package.dependencies] -isodate = ">=0.6.0,<0.7.0" +html5lib-modern = ">=1.2,<2.0" +isodate = {version = ">=0.7.2,<1.0.0", markers = "python_version < \"3.11\""} pyparsing = ">=2.1.0,<4" [package.extras] berkeleydb = ["berkeleydb (>=18.1.0,<19.0.0)"] -html = ["html5lib (>=1.0,<2.0)"] -lxml = ["lxml (>=4.3.0,<5.0.0)"] -networkx = ["networkx (>=2.0.0,<3.0.0)"] +lxml = ["lxml (>=4.3,<6.0)"] +networkx = ["networkx (>=2,<4)"] +orjson = ["orjson (>=3.9.14,<4)"] [[package]] name = "rdflib-jsonld" @@ -2537,24 +2566,24 @@ python-versions = ">=3.6" files = [ {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d92f81886165cb14d7b067ef37e142256f1c6a90a65cd156b063a43da1708cfd"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, - {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:b5edda50e5e9e15e54a6a8a0070302b00c518a9d32accc2346ad6c984aacd279"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, - {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:7048c338b6c86627afb27faecf418768acb6331fc24cfa56c93e8c9780f815fa"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, - {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, @@ -2562,7 +2591,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, - {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3fcc54cb0c8b811ff66082de1680b4b14cf8a81dce0d4fbf665c2265a81e07a1"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, @@ -2570,7 +2599,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, - {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:665f58bfd29b167039f714c6998178d27ccd83984084c286110ef26b230f259f"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, @@ -2578,7 +2607,7 @@ files = [ {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, - {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9eb5dee2772b0f704ca2e45b1713e4e5198c18f515b52743576d196348f374d3"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, @@ -2709,60 +2738,68 @@ pandas = ["pandas (>=1.3.5)"] [[package]] name = "sqlalchemy" -version = "2.0.35" +version = "2.0.36" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67219632be22f14750f0d1c70e62f204ba69d28f62fd6432ba05ab295853de9b"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4668bd8faf7e5b71c0319407b608f278f279668f358857dbfd10ef1954ac9f90"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb8bea573863762bbf45d1e13f87c2d2fd32cee2dbd50d050f83f87429c9e1ea"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f552023710d4b93d8fb29a91fadf97de89c5926c6bd758897875435f2a939f33"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:016b2e665f778f13d3c438651dd4de244214b527a275e0acf1d44c05bc6026a9"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7befc148de64b6060937231cbff8d01ccf0bfd75aa26383ffdf8d82b12ec04ff"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-win32.whl", hash = "sha256:22b83aed390e3099584b839b93f80a0f4a95ee7f48270c97c90acd40ee646f0b"}, - {file = "SQLAlchemy-2.0.35-cp310-cp310-win_amd64.whl", hash = "sha256:a29762cd3d116585278ffb2e5b8cc311fb095ea278b96feef28d0b423154858e"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e21f66748ab725ade40fa7af8ec8b5019c68ab00b929f6643e1b1af461eddb60"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a6219108a15fc6d24de499d0d515c7235c617b2540d97116b663dade1a54d62"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:042622a5306c23b972192283f4e22372da3b8ddf5f7aac1cc5d9c9b222ab3ff6"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:627dee0c280eea91aed87b20a1f849e9ae2fe719d52cbf847c0e0ea34464b3f7"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4fdcd72a789c1c31ed242fd8c1bcd9ea186a98ee8e5408a50e610edfef980d71"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:89b64cd8898a3a6f642db4eb7b26d1b28a497d4022eccd7717ca066823e9fb01"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-win32.whl", hash = "sha256:6a93c5a0dfe8d34951e8a6f499a9479ffb9258123551fa007fc708ae2ac2bc5e"}, - {file = "SQLAlchemy-2.0.35-cp311-cp311-win_amd64.whl", hash = "sha256:c68fe3fcde03920c46697585620135b4ecfdfc1ed23e75cc2c2ae9f8502c10b8"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:eb60b026d8ad0c97917cb81d3662d0b39b8ff1335e3fabb24984c6acd0c900a2"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6921ee01caf375363be5e9ae70d08ce7ca9d7e0e8983183080211a062d299468"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cdf1a0dbe5ced887a9b127da4ffd7354e9c1a3b9bb330dce84df6b70ccb3a8d"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93a71c8601e823236ac0e5d087e4f397874a421017b3318fd92c0b14acf2b6db"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e04b622bb8a88f10e439084486f2f6349bf4d50605ac3e445869c7ea5cf0fa8c"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1b56961e2d31389aaadf4906d453859f35302b4eb818d34a26fab72596076bb8"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-win32.whl", hash = "sha256:0f9f3f9a3763b9c4deb8c5d09c4cc52ffe49f9876af41cc1b2ad0138878453cf"}, - {file = "SQLAlchemy-2.0.35-cp312-cp312-win_amd64.whl", hash = "sha256:25b0f63e7fcc2a6290cb5f7f5b4fc4047843504983a28856ce9b35d8f7de03cc"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f021d334f2ca692523aaf7bbf7592ceff70c8594fad853416a81d66b35e3abf9"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05c3f58cf91683102f2f0265c0db3bd3892e9eedabe059720492dbaa4f922da1"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:032d979ce77a6c2432653322ba4cbeabf5a6837f704d16fa38b5a05d8e21fa00"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:2e795c2f7d7249b75bb5f479b432a51b59041580d20599d4e112b5f2046437a3"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:cc32b2990fc34380ec2f6195f33a76b6cdaa9eecf09f0c9404b74fc120aef36f"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-win32.whl", hash = "sha256:9509c4123491d0e63fb5e16199e09f8e262066e58903e84615c301dde8fa2e87"}, - {file = "SQLAlchemy-2.0.35-cp37-cp37m-win_amd64.whl", hash = "sha256:3655af10ebcc0f1e4e06c5900bb33e080d6a1fa4228f502121f28a3b1753cde5"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4c31943b61ed8fdd63dfd12ccc919f2bf95eefca133767db6fbbd15da62078ec"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a62dd5d7cc8626a3634208df458c5fe4f21200d96a74d122c83bc2015b333bc1"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0630774b0977804fba4b6bbea6852ab56c14965a2b0c7fc7282c5f7d90a1ae72"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d625eddf7efeba2abfd9c014a22c0f6b3796e0ffb48f5d5ab106568ef01ff5a"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ada603db10bb865bbe591939de854faf2c60f43c9b763e90f653224138f910d9"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c41411e192f8d3ea39ea70e0fae48762cd11a2244e03751a98bd3c0ca9a4e936"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-win32.whl", hash = "sha256:d299797d75cd747e7797b1b41817111406b8b10a4f88b6e8fe5b5e59598b43b0"}, - {file = "SQLAlchemy-2.0.35-cp38-cp38-win_amd64.whl", hash = "sha256:0375a141e1c0878103eb3d719eb6d5aa444b490c96f3fedab8471c7f6ffe70ee"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ccae5de2a0140d8be6838c331604f91d6fafd0735dbdcee1ac78fc8fbaba76b4"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2a275a806f73e849e1c309ac11108ea1a14cd7058577aba962cd7190e27c9e3c"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:732e026240cdd1c1b2e3ac515c7a23820430ed94292ce33806a95869c46bd139"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:890da8cd1941fa3dab28c5bac3b9da8502e7e366f895b3b8e500896f12f94d11"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0d8326269dbf944b9201911b0d9f3dc524d64779a07518199a58384c3d37a44"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b76d63495b0508ab9fc23f8152bac63205d2a704cd009a2b0722f4c8e0cba8e0"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-win32.whl", hash = "sha256:69683e02e8a9de37f17985905a5eca18ad651bf592314b4d3d799029797d0eb3"}, - {file = "SQLAlchemy-2.0.35-cp39-cp39-win_amd64.whl", hash = "sha256:aee110e4ef3c528f3abbc3c2018c121e708938adeeff9006428dd7c8555e9b3f"}, - {file = "SQLAlchemy-2.0.35-py3-none-any.whl", hash = "sha256:2ab3f0336c0387662ce6221ad30ab3a5e6499aab01b9790879b6578fd9b8faa1"}, - {file = "sqlalchemy-2.0.35.tar.gz", hash = "sha256:e11d7ea4d24f0a262bccf9a7cd6284c976c5369dac21db237cff59586045ab9f"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win32.whl", hash = "sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa"}, + {file = "SQLAlchemy-2.0.36-cp310-cp310-win_amd64.whl", hash = "sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f"}, + {file = "SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e"}, + {file = "SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436"}, + {file = "SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-win32.whl", hash = "sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c"}, + {file = "SQLAlchemy-2.0.36-cp37-cp37m-win_amd64.whl", hash = "sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-win32.whl", hash = "sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e"}, + {file = "SQLAlchemy-2.0.36-cp38-cp38-win_amd64.whl", hash = "sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-win32.whl", hash = "sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28"}, + {file = "SQLAlchemy-2.0.36-cp39-cp39-win_amd64.whl", hash = "sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a"}, + {file = "SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e"}, + {file = "sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5"}, ] [package.dependencies] @@ -2775,7 +2812,7 @@ aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] @@ -3027,4 +3064,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "66d85f7aabd3fae397f61f071a2f4e5ea0361eba5fe846213e9b5e6bcdc759c7" +content-hash = "abe523d5df94ecbf819e7c5f08721410df1e77dabd1739f80d0ea6c97b284a08" diff --git a/pyproject.toml b/pyproject.toml index 51c545b2..653dae6a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ python = "^3.9" pymongo = "^4.3.3" pyYAML = "^6.0" requests = "^2.28.2" -nmdc-schema = "^11.0.1" +nmdc-schema = "^11.0.3" deepdiff = "^6.2.1" pytz = "^2023.3" python-dotenv = "^1.0.0" @@ -28,6 +28,7 @@ mongomock = "^4.1.2" requests-mock = "^1.11.0" pytest-local-badge = "^1.0.3" pysam = "^0.22.1" +importlib = "^1.0.4" [tool.poetry.group.dev.dependencies] pytest = "^7.3.1" diff --git a/tests/conftest.py b/tests/conftest.py index b8a89714..b14164d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,12 +6,12 @@ import requests_mock import shutil from time import time -from unittest.mock import Mock +from unittest.mock import MagicMock from yaml import load, Loader from nmdc_automation.config import SiteConfig -from nmdc_automation.workflow_automation.models import WorkflowConfig +from nmdc_automation.models.workflow import WorkflowConfig from tests.fixtures import db_utils from nmdc_automation.workflow_automation.wfutils import WorkflowJob @@ -22,6 +22,36 @@ def mock_job_state(): ) return state +@fixture(scope="session") +def mock_nucleotide_sequencing(): + return { + "id": "nmdc:omprc-11-metag1", + "name": "Test Metagenome Processing", + "has_input": [ + "nmdc:bsm-11-qezc0h51" + ], + "has_output": [ + "nmdc:dobj-11-rawreads1", + "nmdc:dobj-11-rawreads2" + ], + "analyte_category": "metagenome", + "associated_studies": [ + "nmdc:sty-11-test001" + ], + "processing_institution": "JGI", + "principal_investigator": { + "has_raw_value": "PI Name", + "email": "pi_name@example.com", + "name": "PI Name", + "type": "nmdc:PersonValue" + }, + "type": "nmdc:NucleotideSequencing" + } + + +@fixture(scope="session") +def mock_metagenome_assembly(): + return @fixture(scope="session") def mags_config(fixtures_dir)->WorkflowConfig: @@ -46,7 +76,9 @@ def mock_api(monkeypatch, requests_mock, test_data_dir): "access_token": "abcd" } requests_mock.post("http://localhost/token", json=token_resp) - resp = ["nmdc:abcd"] + resp = ["nmdc:dobj-01-abcd4321"] + # mock mint responses in sequence + requests_mock.post("http://localhost/pids/mint", json=resp) requests_mock.post( "http://localhost/workflows/workflow_executions", @@ -156,4 +188,60 @@ def mock_cromwell_api(fixtures_dir): json=successful_job_metadata ) - yield m \ No newline at end of file + yield m + + +@fixture(scope="session") +def gold_import_dir(fixtures_dir): + return fixtures_dir / "gold_import" + +@fixture(scope="session") +def gold_import_files(gold_import_dir): + # return the full paths to fixtures that simulate JGI import files. These are used to test the GoldMapper class. + # One (1) file is a nucleotide sequencing file. All the other files are RQC, assembly, MAGs, etc. + return [str(f) for f in gold_import_dir.iterdir() if f.is_file()] + + +class MockNmdcRuntimeApi: + def __init__(self): + self.counter = 10 + + def minter(self, id_type): + type_code_map = { + "nmdc:DataObject": "nmdc:dobj", + "nmdc:MetagenomeAssembly": "nmdc:wfmgas", + "nmdc:MetagenomeAnnotation": "nmdc:wfmgan", + "nmdc:MagsAnalysis": "nmdc:wfmag", + "nmdc:ReadQcAnalysis": "nmdc:wfrqc", + "nmdc:ReadBasedTaxonomyAnalysis": "nmdc:wfrbt", + } + self.counter += 1 + prefix = type_code_map[id_type] + return f"{prefix}-{self.counter:02d}-abcd1234" + + def get_token(self): + return {"expires": {"minutes": time()+60}, + "access_token": "abcd" + } + + def refresh_token(self): + return {"expires": {"minutes": time()+60}, + "access_token": "abcd" + } + + def get_object(self, id): + return { + "id": id, + "name": "Test Object", + "type": "nmdc:DataObject" + } + + + + + + + +@fixture(scope="session") +def mock_nmdc_runtime_api(): + return MockNmdcRuntimeApi() diff --git a/tests/db_dict.json b/tests/db_dict.json new file mode 100644 index 00000000..8c332851 --- /dev/null +++ b/tests/db_dict.json @@ -0,0 +1,136 @@ +{ + "data_object_set": [ + { + "id": "nmdc:dobj-11-abcd1234", + "type": "nmdc:DataObject", + "name": "52834.4.466476.GATCGAGT-GATCGAGT.fastq.gz", + "description": "Metagenome Raw Reads for nmdc:omprc-11-importT", + "data_object_type": "Metagenome Raw Reads", + "file_size_bytes": 114, + "md5_checksum": "d007b1a06373c7ae7c15e681b41a0fc3", + "url": "https://data.microbiomedata.org/data/nmdc:omprc-11-importT/52834.4.466476.GATCGAGT-GATCGAGT.fastq.gz" + }, + { + "id": "nmdc:dobj-13-abcd1234", + "type": "nmdc:DataObject", + "name": "nmdc_wfmgan-12-abcd1234.1_proteins.faa", + "description": "FASTA Amino Acid File for nmdc:omprc-11-importT", + "data_object_type": "Annotation Amino Acid FASTA", + "file_size_bytes": 675, + "md5_checksum": "272b6e22c3a418f3e2819e2485f3bf01", + "url": "https://data.microbiomedata.org/data/nmdc:omprc-11-importT/nmdc:wfmgan-12-abcd1234.1/nmdc_wfmgan-12-abcd1234.1_proteins.faa" + }, + { + "id": "nmdc:dobj-14-abcd1234", + "type": "nmdc:DataObject", + "name": "nmdc_wfmgan-12-abcd1234.1_cog.gff", + "description": "COGs for nmdc:omprc-11-importT", + "data_object_type": "Clusters of Orthologous Groups (COG) Annotation GFF", + "file_size_bytes": 2618, + "md5_checksum": "513be591318b13d46d318bc6bd2c859c", + "url": "https://data.microbiomedata.org/data/nmdc:omprc-11-importT/nmdc:wfmgan-12-abcd1234.1/nmdc_wfmgan-12-abcd1234.1_cog.gff" + }, + { + "id": "nmdc:dobj-15-abcd1234", + "type": "nmdc:DataObject", + "name": "nmdc_wfmgan-12-abcd1234.1_pfam.gff", + "description": "Pfam Annotation for nmdc:omprc-11-importT", + "data_object_type": "Pfam Annotation GFF", + "file_size_bytes": 0, + "md5_checksum": "d41d8cd98f00b204e9800998ecf8427e", + "url": "https://data.microbiomedata.org/data/nmdc:omprc-11-importT/nmdc:wfmgan-12-abcd1234.1/nmdc_wfmgan-12-abcd1234.1_pfam.gff" + }, + { + "id": "nmdc:dobj-17-abcd1234", + "type": "nmdc:DataObject", + "name": "nmdc_wfrqc-16-abcd1234.1_filtered.fastq.gz", + "description": "Reads QC for nmdc:omprc-11-importT", + "data_object_type": "Filtered Sequencing Reads", + "file_size_bytes": 114, + "md5_checksum": "d007b1a06373c7ae7c15e681b41a0fc3", + "url": "https://data.microbiomedata.org/data/nmdc:omprc-11-importT/nmdc:wfrqc-16-abcd1234.1/nmdc_wfrqc-16-abcd1234.1_filtered.fastq.gz" + }, + { + "id": "nmdc:dobj-19-abcd1234", + "type": "nmdc:DataObject", + "name": "nmdc_wfmgas-18-abcd1234.1_contigs.fna", + "description": "Assembly contigs for nmdc:omprc-11-importT", + "data_object_type": "Assembly Contigs", + "file_size_bytes": 563, + "md5_checksum": "a9838d4cb59f6444d63b5d254af9a479", + "url": "https://data.microbiomedata.org/data/nmdc:omprc-11-importT/nmdc:wfmgas-18-abcd1234.1/nmdc_wfmgas-18-abcd1234.1_contigs.fna" + } + ], + "workflow_execution_set": [ + { + "id": "nmdc:wfrqc-16-abcd1234.1", + "type": "nmdc:ReadQcAnalysis", + "name": "Read QC for nmdc:wfrqc-16-abcd1234.1", + "has_input": [ + "nmdc:dobj-11-abcd1234" + ], + "has_output": [ + "nmdc:dobj-17-abcd1234" + ], + "execution_resource": "JGI", + "git_url": "https://github.com/microbiomedata/ReadsQC", + "started_at_time": "2024-10-18T15:36:13.791386+00:00", + "was_informed_by": "nmdc:omprc-11-importT", + "ended_at_time": "2024-10-18T15:36:13.791397+00:00", + "version": "v1.0.8" + }, + { + "id": "nmdc:wfmgas-18-abcd1234.1", + "type": "nmdc:MetagenomeAssembly", + "name": "Metagenome Assembly for nmdc:wfmgas-18-abcd1234.1", + "has_input": [ + "nmdc:dobj-17-abcd1234" + ], + "has_output": [ + "nmdc:dobj-19-abcd1234" + ], + "execution_resource": "JGI", + "git_url": "https://github.com/microbiomedata/metaAssembly", + "started_at_time": "2024-10-18T15:36:17.489784+00:00", + "was_informed_by": "nmdc:omprc-11-importT", + "ended_at_time": "2024-10-18T15:36:17.489798+00:00", + "version": "v1.0.3" + }, + { + "id": "nmdc:wfmgan-12-abcd1234.1", + "type": "nmdc:MetagenomeAnnotation", + "name": "Metagenome Annotation Analysis for nmdc:wfmgan-12-abcd1234.1", + "has_input": [ + "nmdc:dobj-19-abcd1234" + ], + "has_output": [ + "nmdc:dobj-13-abcd1234", + "nmdc:dobj-14-abcd1234", + "nmdc:dobj-15-abcd1234" + ], + "execution_resource": "JGI", + "git_url": "https://github.com/microbiomedata/mg_annotation", + "started_at_time": "2024-10-18T15:36:17.489960+00:00", + "was_informed_by": "nmdc:omprc-11-importT", + "ended_at_time": "2024-10-18T15:36:17.489965+00:00", + "version": "v1.0.4" + }, + { + "id": "nmdc:wfmags-20-abcd1234.1", + "type": "nmdc:MagsAnalysis", + "name": "Metagenome Assembled Genomes Analysis for nmdc:wfmags-20-abcd1234.1", + "has_input": [ + "nmdc:dobj-13-abcd1234", + "nmdc:dobj-14-abcd1234", + "nmdc:dobj-15-abcd1234", + "nmdc:dobj-19-abcd1234" + ], + "execution_resource": "JGI", + "git_url": "https://github.com/microbiomedata/metaMAGs", + "started_at_time": "2024-10-18T15:36:17.490112+00:00", + "was_informed_by": "nmdc:omprc-11-importT", + "ended_at_time": "2024-10-18T15:36:17.490117+00:00", + "version": "v1.0.6" + } + ] +} diff --git a/tests/fixtures/gold_import/52834.4.466476.GATCGAGT-GATCGAGT.fastq.gz b/tests/fixtures/gold_import/52834.4.466476.GATCGAGT-GATCGAGT.fastq.gz new file mode 100644 index 00000000..8136bfd9 Binary files /dev/null and b/tests/fixtures/gold_import/52834.4.466476.GATCGAGT-GATCGAGT.fastq.gz differ diff --git a/tests/fixtures/gold_import/52834.4.466476.GATCGAGT-GATCGAGT.filter-METAGENOME.fastq.gz b/tests/fixtures/gold_import/52834.4.466476.GATCGAGT-GATCGAGT.filter-METAGENOME.fastq.gz new file mode 100644 index 00000000..8136bfd9 Binary files /dev/null and b/tests/fixtures/gold_import/52834.4.466476.GATCGAGT-GATCGAGT.filter-METAGENOME.fastq.gz differ diff --git a/tests/fixtures/gold_import/assembly.contigs.fasta b/tests/fixtures/gold_import/assembly.contigs.fasta new file mode 100644 index 00000000..12114f4e --- /dev/null +++ b/tests/fixtures/gold_import/assembly.contigs.fasta @@ -0,0 +1,10 @@ +>scaffold_1_c2 +AAATTGGTGGCTAAGCCACCAATTTCCGCACAAAAACAACCTCTTTTCTAGTGGTAAGAC +GTTTTGGCGACTTTGACACTGCCCTATTTTCCAGGTAATTGCCTATTGACAATGCATCCA +TATGGATGTATAATCGGGTTACTTCAGATGTTGAGCTTTGGCTCTTTTTTGAAGTGACTG +AACTCCGGTTGGTCCGCAAGGATTGCCTGGAGTTCTTTATTTATCCCCAGCCGGGACGTT +GTTCCGGTTGGGGCTTCTTTTTTATCCGGGAACGCTGTAGAGCGGAAGGAGATAAAAGCC +GTGTCGCAATTCGAGGCAAACCACGTGGAGAGAAGCGCAACCATCACCCTTGTGGCCCCA +CCGGACAAGGTATTCCACCTGTTCGAGCCTATAGGAGAGAAAGCATGGGCGGCAGGCTGG +GAGCCGCGCTTCGTGTACCCACAGGACGAGGAGGCTAAGGAGGGAGCCGTCTTCAAAATA +GAGGCTGAAAACGGGCCGGACACGACCTGGATCATCAGCCGCTACGACAGGGAGCATAAC \ No newline at end of file diff --git a/tests/test_data/test_2.tar.gz b/tests/fixtures/gold_import/test_2.tar.gz similarity index 100% rename from tests/test_data/test_2.tar.gz rename to tests/fixtures/gold_import/test_2.tar.gz diff --git a/tests/test_data/test_72.tar.gz b/tests/fixtures/gold_import/test_72.tar.gz similarity index 100% rename from tests/test_data/test_72.tar.gz rename to tests/fixtures/gold_import/test_72.tar.gz diff --git a/tests/test_data/test_cog.gff b/tests/fixtures/gold_import/test_cog.gff similarity index 100% rename from tests/test_data/test_cog.gff rename to tests/fixtures/gold_import/test_cog.gff diff --git a/tests/test_data/test_pfam.gff b/tests/fixtures/gold_import/test_pfam.gff similarity index 100% rename from tests/test_data/test_pfam.gff rename to tests/fixtures/gold_import/test_pfam.gff diff --git a/tests/fixtures/gold_import/test_proteins.faa b/tests/fixtures/gold_import/test_proteins.faa new file mode 100644 index 00000000..2bd968a4 --- /dev/null +++ b/tests/fixtures/gold_import/test_proteins.faa @@ -0,0 +1,10 @@ +>Ga0597026_0000001_301_783 # Prodigal v2.6.3_patched # 301 # 783 # + # tt=11 +MSQFEANHVERSATITLVAPPDKVFHLFEPIGEKAWAAGWEPRFVYPQDEEAKEGAVFKIEAENGPDTTW +IISRYDREHNAIEYMTVKPDTRVGRIRVEVAGGSEGTSIAAVSYTFTALTEQGNALNDSFTEDHYRHKMH +WWEKAINHYLRTGETLAHHD +>Ga0597026_0000001_1887_3365 # Prodigal v2.6.3_patched # 1887 # 3365 # + # tt=11 +MIDQIRPRLEDNTLLRQLALVLLALGVGVAGGLAIVAGNPVVPFVALTGLLALPWLVTRPMADMLLVVCT +ATLLPFAASPVRLAVLTPTLLEVGLLLLYMAWLLRMLLNTGEGFARTPVDVWVMLFLACTLFAFVLGLGR +DASTDVVHNYFKMLLSIGVFFAAANVIRTWEQVATVLKALIVSGAAAASIGIVLWRLPDTFAASLLTRLS +VIGYPTERVIRYVEENPALGERAVGTQVDPNSFAGMLVIIAAITGVHLLSRKPLLPRWLLAGMLLVDVAA +IVLTQSRSALLGILVAAALVATLRYRHLWTWGVAGAVAIAVLGVGSGYFARLTAGIRFEDQASIMRLAEY \ No newline at end of file diff --git a/tests/fixtures/models/mags_analysis_record.json b/tests/fixtures/models/mags_analysis_record.json index df222d83..34778ead 100644 --- a/tests/fixtures/models/mags_analysis_record.json +++ b/tests/fixtures/models/mags_analysis_record.json @@ -52,52 +52,7 @@ "gtdbtk_family": "UBA11358", "gtdbtk_genus": "UBA11358", "gtdbtk_species": "null", - "members_id": [ - "nmdc:wfmgas-13-56028x05.1_7_c1", - "nmdc:wfmgas-13-56028x05.1_9_c1", - "nmdc:wfmgas-13-56028x05.1_16_c1", - "nmdc:wfmgas-13-56028x05.1_20_c1", - "nmdc:wfmgas-13-56028x05.1_23_c1", - "nmdc:wfmgas-13-56028x05.1_27_c1", - "nmdc:wfmgas-13-56028x05.1_45_c1", - "nmdc:wfmgas-13-56028x05.1_55_c1", - "nmdc:wfmgas-13-56028x05.1_71_c1", - "nmdc:wfmgas-13-56028x05.1_79_c1", - "nmdc:wfmgas-13-56028x05.1_99_c1", - "nmdc:wfmgas-13-56028x05.1_52_c2", - "nmdc:wfmgas-13-56028x05.1_127_c1", - "nmdc:wfmgas-13-56028x05.1_131_c1", - "nmdc:wfmgas-13-56028x05.1_137_c1", - "nmdc:wfmgas-13-56028x05.1_169_c1", - "nmdc:wfmgas-13-56028x05.1_200_c1", - "nmdc:wfmgas-13-56028x05.1_212_c1", - "nmdc:wfmgas-13-56028x05.1_223_c1", - "nmdc:wfmgas-13-56028x05.1_372_c1", - "nmdc:wfmgas-13-56028x05.1_393_c1", - "nmdc:wfmgas-13-56028x05.1_428_c1", - "nmdc:wfmgas-13-56028x05.1_52_c1", - "nmdc:wfmgas-13-56028x05.1_582_c1", - "nmdc:wfmgas-13-56028x05.1_706_c1", - "nmdc:wfmgas-13-56028x05.1_888_c1", - "nmdc:wfmgas-13-56028x05.1_912_c1", - "nmdc:wfmgas-13-56028x05.1_1268_c1", - "nmdc:wfmgas-13-56028x05.1_1271_c1", - "nmdc:wfmgas-13-56028x05.1_1492_c1", - "nmdc:wfmgas-13-56028x05.1_1494_c1", - "nmdc:wfmgas-13-56028x05.1_1604_c1", - "nmdc:wfmgas-13-56028x05.1_1627_c1", - "nmdc:wfmgas-13-56028x05.1_1888_c1", - "nmdc:wfmgas-13-56028x05.1_1938_c1", - "nmdc:wfmgas-13-56028x05.1_2944_c1", - "nmdc:wfmgas-13-56028x05.1_3261_c1", - "nmdc:wfmgas-13-56028x05.1_3477_c1", - "nmdc:wfmgas-13-56028x05.1_4194_c1", - "nmdc:wfmgas-13-56028x05.1_6257_c1", - "nmdc:wfmgas-13-56028x05.1_7589_c1", - "nmdc:wfmgas-13-56028x05.1_10469_c1", - "nmdc:wfmgas-13-56028x05.1_10553_c1", - "nmdc:wfmgas-13-56028x05.1_13792_c1" - ] + "members_id": ["nmdc:wfmgas-13-56028x05.1_7_c1", "nmdc:wfmgas-13-56028x05.1_7_c2"] }, { "bin_name": "bins.9", @@ -118,100 +73,7 @@ "gtdbtk_family": "null", "gtdbtk_genus": "null", "gtdbtk_species": "null", - "members_id": [ - "nmdc:wfmgas-13-56028x05.1_7094_c1", - "nmdc:wfmgas-13-56028x05.1_9486_c1", - "nmdc:wfmgas-13-56028x05.1_9853_c1", - "nmdc:wfmgas-13-56028x05.1_10857_c1", - "nmdc:wfmgas-13-56028x05.1_11702_c1", - "nmdc:wfmgas-13-56028x05.1_12042_c1", - "nmdc:wfmgas-13-56028x05.1_14174_c1", - "nmdc:wfmgas-13-56028x05.1_14597_c1", - "nmdc:wfmgas-13-56028x05.1_16115_c1", - "nmdc:wfmgas-13-56028x05.1_16261_c1", - "nmdc:wfmgas-13-56028x05.1_16795_c1", - "nmdc:wfmgas-13-56028x05.1_16943_c1", - "nmdc:wfmgas-13-56028x05.1_17208_c1", - "nmdc:wfmgas-13-56028x05.1_17245_c1", - "nmdc:wfmgas-13-56028x05.1_17383_c1", - "nmdc:wfmgas-13-56028x05.1_17783_c1", - "nmdc:wfmgas-13-56028x05.1_18468_c1", - "nmdc:wfmgas-13-56028x05.1_18553_c1", - "nmdc:wfmgas-13-56028x05.1_18858_c1", - "nmdc:wfmgas-13-56028x05.1_19302_c1", - "nmdc:wfmgas-13-56028x05.1_19824_c1", - "nmdc:wfmgas-13-56028x05.1_20316_c1", - "nmdc:wfmgas-13-56028x05.1_20787_c1", - "nmdc:wfmgas-13-56028x05.1_21029_c1", - "nmdc:wfmgas-13-56028x05.1_21435_c1", - "nmdc:wfmgas-13-56028x05.1_21475_c1", - "nmdc:wfmgas-13-56028x05.1_21484_c1", - "nmdc:wfmgas-13-56028x05.1_21518_c1", - "nmdc:wfmgas-13-56028x05.1_21685_c1", - "nmdc:wfmgas-13-56028x05.1_21809_c1", - "nmdc:wfmgas-13-56028x05.1_21924_c1", - "nmdc:wfmgas-13-56028x05.1_21958_c1", - "nmdc:wfmgas-13-56028x05.1_22186_c1", - "nmdc:wfmgas-13-56028x05.1_22271_c1", - "nmdc:wfmgas-13-56028x05.1_22516_c1", - "nmdc:wfmgas-13-56028x05.1_22514_c1", - "nmdc:wfmgas-13-56028x05.1_22777_c1", - "nmdc:wfmgas-13-56028x05.1_23003_c1", - "nmdc:wfmgas-13-56028x05.1_23115_c1", - "nmdc:wfmgas-13-56028x05.1_23204_c1", - "nmdc:wfmgas-13-56028x05.1_23239_c1", - "nmdc:wfmgas-13-56028x05.1_23352_c1", - "nmdc:wfmgas-13-56028x05.1_23445_c1", - "nmdc:wfmgas-13-56028x05.1_23505_c1", - "nmdc:wfmgas-13-56028x05.1_23571_c1", - "nmdc:wfmgas-13-56028x05.1_24047_c1", - "nmdc:wfmgas-13-56028x05.1_24749_c1", - "nmdc:wfmgas-13-56028x05.1_24981_c1", - "nmdc:wfmgas-13-56028x05.1_25059_c1", - "nmdc:wfmgas-13-56028x05.1_25526_c1", - "nmdc:wfmgas-13-56028x05.1_26162_c1", - "nmdc:wfmgas-13-56028x05.1_26376_c1", - "nmdc:wfmgas-13-56028x05.1_26773_c1", - "nmdc:wfmgas-13-56028x05.1_26816_c1", - "nmdc:wfmgas-13-56028x05.1_26891_c1", - "nmdc:wfmgas-13-56028x05.1_27179_c1", - "nmdc:wfmgas-13-56028x05.1_27272_c1", - "nmdc:wfmgas-13-56028x05.1_27358_c1", - "nmdc:wfmgas-13-56028x05.1_27411_c1", - "nmdc:wfmgas-13-56028x05.1_27550_c1", - "nmdc:wfmgas-13-56028x05.1_28892_c1", - "nmdc:wfmgas-13-56028x05.1_29003_c1", - "nmdc:wfmgas-13-56028x05.1_29238_c1", - "nmdc:wfmgas-13-56028x05.1_29324_c1", - "nmdc:wfmgas-13-56028x05.1_29771_c1", - "nmdc:wfmgas-13-56028x05.1_29878_c1", - "nmdc:wfmgas-13-56028x05.1_30248_c1", - "nmdc:wfmgas-13-56028x05.1_30476_c1", - "nmdc:wfmgas-13-56028x05.1_30587_c1", - "nmdc:wfmgas-13-56028x05.1_31160_c1", - "nmdc:wfmgas-13-56028x05.1_31834_c1", - "nmdc:wfmgas-13-56028x05.1_31922_c1", - "nmdc:wfmgas-13-56028x05.1_31971_c1", - "nmdc:wfmgas-13-56028x05.1_32244_c1", - "nmdc:wfmgas-13-56028x05.1_32605_c1", - "nmdc:wfmgas-13-56028x05.1_32623_c1", - "nmdc:wfmgas-13-56028x05.1_32832_c1", - "nmdc:wfmgas-13-56028x05.1_33068_c1", - "nmdc:wfmgas-13-56028x05.1_33334_c1", - "nmdc:wfmgas-13-56028x05.1_33438_c1", - "nmdc:wfmgas-13-56028x05.1_33855_c1", - "nmdc:wfmgas-13-56028x05.1_34035_c1", - "nmdc:wfmgas-13-56028x05.1_34120_c1", - "nmdc:wfmgas-13-56028x05.1_34140_c1", - "nmdc:wfmgas-13-56028x05.1_34133_c1", - "nmdc:wfmgas-13-56028x05.1_34177_c1", - "nmdc:wfmgas-13-56028x05.1_34481_c1", - "nmdc:wfmgas-13-56028x05.1_34728_c1", - "nmdc:wfmgas-13-56028x05.1_34843_c1", - "nmdc:wfmgas-13-56028x05.1_35665_c1", - "nmdc:wfmgas-13-56028x05.1_35772_c1", - "nmdc:wfmgas-13-56028x05.1_35995_c1" - ] + "members_id": ["nmdc:wfmgas-13-56028x05.1_7_c1", "nmdc:wfmgas-13-56028x05.1_7_c2"] } ], "too_short_contig_num": 2005162, diff --git a/tests/test_db2.json b/tests/test_db2.json new file mode 100644 index 00000000..b4a5225d --- /dev/null +++ b/tests/test_db2.json @@ -0,0 +1,21 @@ +{ + "id": "nmdc:wfmag-20-abcd1234.1", + "type": "nmdc:MagsAnalysis", + "name": "Metagenome Assembled Genomes Analysis for nmdc:wfmags-20-abcd1234.1", + "has_input": [ + "nmdc:dobj-13-abcd1234", + "nmdc:dobj-14-abcd1234", + "nmdc:dobj-15-abcd1234", + "nmdc:dobj-19-abcd1234" + ], + "has_output": [ + "nmdc:dobj-21-abcd1234" + ], + "execution_resource": "JGI", + "git_url": "https://github.com/microbiomedata/metaMAGs", + "started_at_time": "2024-10-18T15:36:17.490112+00:00", + "was_informed_by": "nmdc:omprc-11-importT", + "ended_at_time": "2024-10-18T15:36:17.490117+00:00", + "version": "v1.0.6" + } + diff --git a/tests/test_imports.py b/tests/test_imports.py index ccc0eb8e..b3614777 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -1,8 +1,17 @@ import os import shutil from nmdc_automation.import_automation.activity_mapper import GoldMapper +from nmdc_automation.models.nmdc import DataObject +from nmdc_schema.nmdc import Database from pytest import fixture +import importlib.resources +import yaml +from functools import lru_cache +import linkml.validator +from linkml_runtime.dumpers import yaml_dumper +from linkml_runtime.loaders import json_loader from time import time +from unittest.mock import patch @@ -11,61 +20,150 @@ #TODO NEXT: add test for import-mt.yaml similar to what is in test_workflow_process.py @fixture -def gold_mapper(mock_api, base_test_dir, test_data_dir): +def gold_mapper(mock_nmdc_runtime_api, base_test_dir, gold_import_files, gold_import_dir): """ Base test function for code related to importing JGI records. """ yaml_file = base_test_dir / "import_test.yaml" - test_files = [test_data_dir / "test_pfam.gff", - test_data_dir / "test_cog.gff", - test_data_dir / "test_2.tar.gz", - test_data_dir / "test_72.tar.gz"] - # proj_dir = os.path.abspath("./test_data") - site_conf = base_test_dir / "site_configuration_test.toml" nucleotide_sequencing_id = "nmdc:omprc-11-importT" root_dir = f"/tmp/{nucleotide_sequencing_id}" if os.path.exists(root_dir): shutil.rmtree(root_dir) - gm = GoldMapper("1", test_files, nucleotide_sequencing_id, yaml_file, test_data_dir, site_conf) + gm = GoldMapper("1", gold_import_files, nucleotide_sequencing_id, yaml_file, gold_import_dir, mock_nmdc_runtime_api) gm.root_dir = root_dir return gm -def test_workflow_execution_mapper(gold_mapper): +@lru_cache(maxsize=None) +def get_nmdc_materialized(): + with importlib.resources.open_text("nmdc_schema", "nmdc_materialized_patterns.yaml") as f: + return yaml.safe_load(f) + + +def test_gold_mapper_map_sequencing_data(gold_mapper): """ - Test the creation of workflow execution records and data objects that are has_output of those workflow execution subclasses. + Test that the gold mapper creates data objects for the sequencing data, and + provides an update to be applied to the has_output list of the sequencing data generation """ - gold_mapper.unique_object_mapper() - gold_mapper.multiple_objects_mapper() - gold_mapper.workflow_execution_mapper() - gold_mapper.post_nmdc_database_object() - db = gold_mapper.get_database_object_dump() - #This should return 4 workflow_execution_set records becuase that is the number of records with Import:true in the config file - #note that if these records were tested against the actual schema they would fail b/c workflow executions can't have has_output be null. - assert len(db.workflow_execution_set) == 4 - # gff files are 1:1 with data objects that are has_output of nmdc:MetagenomeAnnotation - # *tar.gz files should be combined into a single data object that is has_output of nmdc:MagsAnalysis - assert len(db.data_object_set) == 3 - - -def test_unique_object_mapper(gold_mapper): + exp_num_data_objects = 1 # There is only one sequencing data file from the gold import files fixture + exp_dobj_id = "nmdc:dobj-11-abcd1234" # From the mock API minter response + exp_dobj_type = "Metagenome Raw Reads" # From the gold_import_files fixture + exp_nucleotide_sequencing_id = "nmdc:omprc-11-importT" # From the gold mapper fixture + exp_update = { + "collection": "data_generation_set", + "filter": {"id": exp_nucleotide_sequencing_id}, + "update": {"$addToSet": {"has_output": [exp_dobj_id]}} + } + # Sequencing data does not get a URL + exp_url = None + exp_name = '52834.4.466476.GATCGAGT-GATCGAGT.fastq.gz' + exp_description = 'Metagenome Raw Reads for nmdc:omprc-11-importT' + + db, update = gold_mapper.map_sequencing_data() + # Database assertions + assert db + assert isinstance(db, Database) + assert db.data_object_set + data_objects = db.data_object_set + assert len(data_objects) == exp_num_data_objects + # Data object assertions + dobj = data_objects[0] + assert isinstance(dobj, DataObject) + assert str(dobj.data_object_type) == exp_dobj_type + assert dobj.id == exp_dobj_id + assert dobj.name == exp_name + assert dobj.description == exp_description + assert dobj.url == exp_url + assert dobj.file_size_bytes + assert dobj.md5_checksum + + # Update assertions + assert update + assert update == exp_update + + +def test_gold_mapper_map_data_unique(gold_mapper): """ - This test counts the number of files from gold_mapper where the data object creation should be 1:1. + Test that the gold mapper creates data objects for the data files other + than the sequencing data """ - gold_mapper.unique_object_mapper() - assert len(gold_mapper.nmdc_db.data_object_set) == 2 - assert len(gold_mapper.objects) == 2 + initial_num_data_objects = 1 + db, update = gold_mapper.map_sequencing_data() + # sanity check + assert len(db.data_object_set) == initial_num_data_objects + # two unique data files from the gold import files fixture get added to the database + exp_data_object_types = [ + "Clusters of Orthologous Groups (COG) Annotation GFF", + "Pfam Annotation GFF", + "Metagenome Raw Reads", + "Annotation Amino Acid FASTA", + "Filtered Sequencing Reads", + "Assembly Contigs", + ] + + exp_nucleotide_sequencing_id = "nmdc:omprc-11-importT" # From the gold mapper fixture + + db, do_map = gold_mapper.map_data(db) + assert db + assert len(db.data_object_set) == len(exp_data_object_types) + data_objects = db.data_object_set + for dobj in data_objects: + assert str(dobj.data_object_type) in exp_data_object_types + assert isinstance(dobj, DataObject) + # sequencing data object should not have a URL + if str(dobj.data_object_type) == "Metagenome Raw Reads": + assert not dobj.url + else: + assert dobj.url + assert exp_nucleotide_sequencing_id in dobj.url + assert exp_nucleotide_sequencing_id in dobj.description -def test_multiple_object_mapper(gold_mapper): +def test_gold_mapper_map_data_multiple(gold_mapper): """ - This test counts the number of files from gold_mapper where the data object creation should be many:1. JGI stores each binning file - individually whereas NMDC combines all the records into a single tar.gz file. + Test that the mapper is able to combine multiple data files into a single data object. """ - gold_mapper.multiple_objects_mapper() - # Add assertions to check if the method works as expected - assert len(gold_mapper.nmdc_db.data_object_set) == 1 - print(gold_mapper.nmdc_db.data_object_set) - assert len(gold_mapper.objects) == 1 - #check that the data object url gets made correctly for the multiple object mapper function. - assert "https://data.microbiomedata.org/data/nmdc:omprc-11-importT/nmdc:abcd.1/nmdc_abcd.1_hqmq_bin.zip" in (do["url"] for do in gold_mapper.nmdc_db.data_object_set) + initial_num_data_objects = 1 + db, update = gold_mapper.map_sequencing_data() + # sanity check + assert len(db.data_object_set) == initial_num_data_objects + exp_num_data_objects = 2 # two files are combined into a single data object + + db, do_map = gold_mapper.map_data(db, unique=False) + assert db + assert len(db.data_object_set) == exp_num_data_objects + + +def test_gold_mapper_map_workflow_executions(gold_mapper, ): + """ + Test that the gold mapper creates workflow execution records and data objects that are has_output of those workflow execution subclasses. + """ + + # setup + db, update = gold_mapper.map_sequencing_data() + db, do_map = gold_mapper.map_data(db) + db, do_map = gold_mapper.map_data(db, unique=False) + + # test + db = gold_mapper.map_workflow_executions(db) + assert db.workflow_execution_set + + + # test that the db is valid according to the schema + nmdc_materialized = get_nmdc_materialized() + # db is a schema object, so we need to convert it to a dictionary + + db_dict = yaml.safe_load(yaml_dumper.dumps(db)) + + validation_report = linkml.validator.validate(db_dict, nmdc_materialized, "Database") + + assert not validation_report.results, f"Validation error: {validation_report.results[0].message}" + + + + + + + + + diff --git a/tests/test_models.py b/tests/test_models.py index 1d9aa4ec..8fb00898 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,20 +1,18 @@ """ Test cases for the models module. """ import json - +import pytest from bson import ObjectId from pathlib import Path -from pytest import mark -from nmdc_automation.workflow_automation.models import( - DataObject, - Job, - JobOutput, - JobWorkflow, - WorkflowProcessNode, - workflow_process_factory, -) +from pytest import mark, raises +from nmdc_automation.models.nmdc import DataObject, workflow_process_factory +from nmdc_automation.models.workflow import Job, JobOutput, JobWorkflow, WorkflowProcessNode from nmdc_automation.workflow_automation.workflows import load_workflow_configs from tests.fixtures import db_utils +from linkml_runtime.dumpers import yaml_dumper +import yaml + + def test_workflow_process_factory(fixtures_dir): """ Test the workflow_process_factory function. """ record_types = { @@ -33,6 +31,35 @@ def test_workflow_process_factory(fixtures_dir): wfe = workflow_process_factory(record) assert wfe.type == record_type + +def test_workflow_process_factory_incorrect_id(fixtures_dir): + record = json.load(open(fixtures_dir / "models/metagenome_annotation_record.json")) + # Change the id to an incorrect value - this would be an assembly id + record["id"] = "nmdc:wfmgas-11-009f3582.1" + with pytest.raises(ValueError) as excinfo: + workflow_process_factory(record, validate=True) + assert "'nmdc:wfmgas-11-009f3582.1' does not match" in str(excinfo.value) + + + + + +def test_workflow_process_factory_data_generation_invalid_analyte_category(fixtures_dir): + record = json.load(open(fixtures_dir / "models/nucleotide_sequencing_record.json")) + record["analyte_category"] = "Something Invalid" + + with raises(ValueError) as excinfo: + wfe = workflow_process_factory(record) + + + +def test_workflow_process_factory_metagenome_assembly_with_invalid_execution_resource(fixtures_dir): + record = json.load(open(fixtures_dir / "models/metagenome_assembly_record.json")) + record["execution_resource"] = "Something Invalid" + with raises(ValueError) as excinfo: + wfe = workflow_process_factory(record) + + def test_workflow_process_factory_mags_with_mags_list(fixtures_dir): record = json.load(open(fixtures_dir / "models/mags_analysis_record.json")) mga = workflow_process_factory(record) @@ -50,6 +77,7 @@ def test_process_factory_with_db_record(): wfe = workflow_process_factory(record) assert wfe.type == "nmdc:NucleotideSequencing" + @mark.parametrize("record_file, record_type", [ ("mags_analysis_record.json", "nmdc:MagsAnalysis"), ("metagenome_annotation_record.json", "nmdc:MetagenomeAnnotation"), @@ -90,16 +118,15 @@ def test_data_object_creation_from_records(fixtures_dir): assert data_obj.type == "nmdc:DataObject" assert data_obj.id == record["id"] assert data_obj.name == record["name"] - assert data_obj.data_object_type == record["data_object_type"] + assert str(data_obj.data_object_type) == record["data_object_type"] - data_obj_dict = data_obj.as_dict() + data_obj_dict = yaml.safe_load(yaml_dumper.dumps(data_obj)) assert data_obj_dict == record def test_data_object_creation_from_db_records(test_db, fixtures_dir): db_utils.reset_db(test_db) db_utils.load_fixture(test_db, "data_object_set.json") - # db_utils.read_json("data_object_set.json") db_records = test_db["data_object_set"].find() db_records = list(db_records) @@ -109,7 +136,7 @@ def test_data_object_creation_from_db_records(test_db, fixtures_dir): assert data_obj.type == "nmdc:DataObject" assert data_obj.id == db_record["id"] assert data_obj.name == db_record["name"] - assert data_obj.data_object_type == db_record["data_object_type"] + assert str(data_obj.data_object_type) == db_record["data_object_type"] assert data_obj.description == db_record["description"] assert data_obj.url == db_record["url"] assert data_obj.file_size_bytes == db_record.get("file_size_bytes") @@ -122,6 +149,40 @@ def test_data_object_creation_from_db_records(test_db, fixtures_dir): assert data_obj_dict == db_record +def test_data_object_creation_invalid_data_object_type(): + record = { + "id": "nmdc:dobj-11-rawreads1", + "name": "metaG_R1_001.fastq.gz", + "description": "Sequencing results for metaG_R1", + "md5_checksum": "ed9467e690babb683b024ed47dd97b85", + "data_object_type": "Something Invalid", + "type": "nmdc:DataObject", + "url": "https://portal.nersc.gov" + } + with raises(ValueError) as excinfo: + data_obj = DataObject(**record) + + # Test with a valid data object type + record.update({"data_object_type": "Metagenome Raw Reads"}) + data_obj = DataObject(**record) + assert str(data_obj.data_object_type) == "Metagenome Raw Reads" + + +def test_data_object_creation_invalid_data_category(): + record = { + "id": "nmdc:dobj-11-qcstats", + "name": "nmdc_wfrqc-11-metag.1_filterStats.txt", + "description": "Reads QC summary for nmdc:wfrqc-11-metag1.1", + "file_size_bytes": 123456, + "md5_checksum": "7172cd332a734e002c88b35827acd991", + "data_object_type": "QC Statistics", + "data_category": "Something Invalid", + "url": "https://data.microbiomedata.org", + "type": "nmdc:DataObject" + } + with raises(ValueError) as excinfo: + data_obj = DataObject(**record) + def test_job_output_creation(): outputs = [ { diff --git a/tests/test_nmdcapi.py b/tests/test_nmdcapi.py index 646e4c62..060c3200 100644 --- a/tests/test_nmdcapi.py +++ b/tests/test_nmdcapi.py @@ -3,7 +3,7 @@ import os -def test_basics(mock_api, requests_mock, site_config_file): +def test_basics(requests_mock, site_config_file): n = nmdcapi(site_config_file) # Add decode description @@ -14,7 +14,7 @@ def test_basics(mock_api, requests_mock, site_config_file): assert "metadata" in resp -def test_objects(mock_api, requests_mock, site_config_file, test_data_dir): +def test_objects(requests_mock, site_config_file, test_data_dir): n = nmdcapi(site_config_file) requests_mock.post("http://localhost/objects", json={}) @@ -37,7 +37,7 @@ def test_objects(mock_api, requests_mock, site_config_file, test_data_dir): assert "a" in resp -def test_list_funcs(mock_api, requests_mock, site_config_file, test_data_dir): +def test_list_funcs(requests_mock, site_config_file, test_data_dir): n = nmdcapi(site_config_file) mock_resp = json.load(open(test_data_dir / "mock_jobs.json")) @@ -55,7 +55,7 @@ def test_list_funcs(mock_api, requests_mock, site_config_file, test_data_dir): assert resp is not None -def test_update_op(mock_api, requests_mock, site_config_file): +def test_update_op(requests_mock, site_config_file): n = nmdcapi(site_config_file) mock_resp = {'metadata': {"b": "c"}} @@ -69,7 +69,7 @@ def test_update_op(mock_api, requests_mock, site_config_file): assert "b" in resp["metadata"] -def test_jobs(mock_api, requests_mock, site_config_file): +def test_jobs(requests_mock, site_config_file): n = nmdcapi(site_config_file) requests_mock.get("http://localhost/jobs/abc", json="jobs/") diff --git a/tests/test_wfutils.py b/tests/test_wfutils.py index fde4942c..6e05344f 100644 --- a/tests/test_wfutils.py +++ b/tests/test_wfutils.py @@ -4,7 +4,7 @@ WorkflowStateManager, _json_tmp, ) -from nmdc_automation.workflow_automation.models import DataObject, workflow_process_factory +from nmdc_automation.models.nmdc import DataObject, workflow_process_factory from nmdc_schema.nmdc import MagsAnalysis, EukEval import io import json diff --git a/tests/test_workflow_process.py b/tests/test_workflow_process.py index f8813353..1cf81058 100644 --- a/tests/test_workflow_process.py +++ b/tests/test_workflow_process.py @@ -105,7 +105,7 @@ def test_get_required_data_objects_by_id(test_db, workflows_config_dir, workflow # get a unique list of the data object types do_types = set() for do in required_data_object_map.values(): - do_types.add(do.data_object_type) + do_types.add(do.data_object_type.code.text) # check that the expected data object types are present for do_type in exp_do_types: assert do_type in do_types