diff --git a/data/oai_sources.json b/data/oai_sources.json
index 707bf3c0a..03b8493ae 100644
--- a/data/oai_sources.json
+++ b/data/oai_sources.json
@@ -1,12 +1,4 @@
[
- {
- "key": "rerodoc",
- "name": "rerodoc",
- "url": "http://doc.rero.ch/oai2d",
- "metadataprefix": "marcxml",
- "comment": "",
- "setspecs": "unisi unifr nl-epfl nl-ethz nl-fachhochschulen nl-lib4ri nl-unibas nl-unibe nl-unifr nl-unige nl-unil nl-unilu nl-unine nl-unisg nl-usi nl-uzh bge mhnge baage bmuge imvge mhsge hepbejune unifr"
- },
{
"key": "archive_ouverte_unige",
"name": "Archive ouverte UNIGE",
diff --git a/sonar/modules/documents/cli/documents.py b/sonar/modules/documents/cli/documents.py
index cdea9e199..2841b7c96 100644
--- a/sonar/modules/documents/cli/documents.py
+++ b/sonar/modules/documents/cli/documents.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -18,7 +18,6 @@
import click
from .oai import oai
-from .rerodoc import rerodoc
from .urn import urn
@@ -27,6 +26,5 @@ def documents():
"""Commands for documents."""
-documents.add_command(rerodoc)
documents.add_command(urn)
documents.add_command(oai)
diff --git a/sonar/modules/documents/cli/rerodoc.py b/sonar/modules/documents/cli/rerodoc.py
deleted file mode 100644
index 5a599ef4f..000000000
--- a/sonar/modules/documents/cli/rerodoc.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""RERODOC specific CLI commands."""
-
-import csv
-import re
-
-import click
-from flask import current_app
-from flask.cli import with_appcontext
-from invenio_db import db
-
-from sonar.modules.documents.api import DocumentIndexer, DocumentRecord
-
-
-@click.group()
-def rerodoc():
- """RERODOC specific commands."""
-
-
-@rerodoc.command("update-file-permissions")
-@click.argument("permissions_file", type=click.File("r"))
-@click.option("-c", "--chunk-size", type=int, default=500, help="Chunk size for bulk indexing.")
-@with_appcontext
-def update_file_permissions(permissions_file, chunk_size):
- """Update file permission with information given by input file.
-
- :param permissions_file: CSV file containing files permissions.
- """
- indexer = DocumentIndexer(record_cls=DocumentRecord)
-
- def save_records(ids):
- """Save current records set into database and re-index.
-
- :param ids: List of records to save
- """
- db.session.commit()
- indexer.bulk_index(ids)
- indexer.process_bulk_queue()
-
- try:
- with open(permissions_file.name) as file:
- reader = csv.reader(file, delimiter=",")
-
- # header
- header = next(reader)
-
- # check number of columns
- if len(header) != 3:
- raise Exception("CSV file seems to be not well formatted.")
-
- # To store ids for bulk indexing
- ids = []
-
- for row in reader:
- try:
- # try to load corresponding record
- record = DocumentRecord.get_record_by_identifier([{"type": "bf:Local", "value": row[0]}])
-
- # No record found, skipping..
- if not record:
- raise Exception(f"Record {row[0]} not found")
-
- file_name = f"{row[2]}.pdf"
-
- # File not found in record, skipping
- if file_name not in record.files:
- raise Exception(f"File {file_name} not found in record {row[0]}")
-
- record_file = record.files[file_name]
-
- # permissions contains a status
- matches = re.search(r"status:(\w+)$", row[1])
- if matches:
- # If status if RERO or INTERNAL, file must not be
- # displayed, otherwise file is not accessible outside
- # organisation
- record_file["access"] = "coar:c_16ec" # restricted access
- if matches.group(1) in ["RERO", "INTERNAL"]:
- record_file["restricted_outside_organisation"] = False
- else:
- record_file["restricted_outside_organisation"] = True
- else:
- # permissions contains a date
- matches = re.search(
- r"allow roles \/\.\*,(\w+),\.\*\/\n\s+.+(\d{4}-"
- r"\d{2}-\d{2})",
- row[1],
- )
-
- if matches:
- # file is accessible inside organisation
- if matches.group(1) != "INTERNAL":
- record_file["restricted_outside_organisation"] = True
- # file is not accessible
- else:
- record_file["restricted_outside_organisation"] = False
-
- record_file["access"] = "coar:c_f1cf" # embargoed access
- record_file["embargo_date"] = matches.group(2)
-
- record.commit()
- db.session.flush()
- ids.append(str(record.id))
-
- current_app.logger.warning(f"Restriction added for file {file_name} in record {record['pid']}.")
-
- # Bulk save and index
- if len(ids) % chunk_size == 0:
- save_records(ids)
- ids = []
-
- except Exception as exception:
- click.secho(str(exception), fg="yellow")
-
- # save remaining records
- save_records(ids)
-
- click.secho("Process finished", fg="green")
-
- except Exception as exception:
- click.secho(
- f"An error occured during file process: {exception}",
- fg="red",
- )
diff --git a/sonar/modules/documents/dojson/rerodoc/__init__.py b/sonar/modules/documents/dojson/rerodoc/__init__.py
deleted file mode 100644
index da7f08d42..000000000
--- a/sonar/modules/documents/dojson/rerodoc/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""DOJSON RERODOC transformation for SONAR."""
diff --git a/sonar/modules/documents/dojson/rerodoc/model.py b/sonar/modules/documents/dojson/rerodoc/model.py
deleted file mode 100644
index 6629708b4..000000000
--- a/sonar/modules/documents/dojson/rerodoc/model.py
+++ /dev/null
@@ -1,990 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""RERODOC MARC21 model definition."""
-
-import hashlib
-import re
-
-from dojson import utils
-from flask import current_app
-from invenio_db import db
-
-from sonar.modules.collections.api import Record as CollectionRecord
-from sonar.modules.documents.dojson.rerodoc.overdo import Overdo
-from sonar.modules.organisations.api import OrganisationRecord
-from sonar.modules.subdivisions.api import Record as SubdivisionRecord
-from sonar.modules.subdivisions.api import RecordSearch
-from sonar.modules.utils import remove_trailing_punctuation
-
-overdo = Overdo()
-
-TYPE_MAPPINGS = {
- "PREPRINT|": "coar:c_816b",
- "POSTPRINT|ART_JOURNAL": "coar:c_6501",
- "POSTPRINT|ART_INBOOK": "coar:c_3248",
- "POSTPRINT|ART_INPROC": "coar:c_5794",
- "BOOK|": "coar:c_2f33",
- "DISSERTATION|DISS_MASTER": "coar:c_bdcc",
- "DISSERTATION|DISS_BACHELOR": "coar:c_7a1f",
- "DISSERTATION|DISS_CONT_EDU": "coar:c_46ec",
- "THESIS|": "coar:c_db06",
- "THESIS|TH_PHD": "coar:c_db06",
- "THESIS|TH_HABILIT": "coar:c_46ec",
- "MAP|": "coar:c_12cc",
- "REPORT|": "coar:c_18ws",
- "NEWSPAPER|": "coar:c_2fe3",
- "JOURNAL|": "coar:c_0640",
- "PRINT_MEDIA|": "coar:c_2fe3",
- "AUDIO|": "coar:c_18cc",
- "IMAGE|": "coar:c_ecc8",
- "PARTITION|": "coar:c_18cw",
-}
-
-
-@overdo.over("type", "^980")
-@utils.ignore_value
-def marc21_to_type_and_organisation(self, key, value):
- """Get document type and organisation from 980 field."""
- subdivision_name = None
-
- # organisation
- if value.get("b"):
- organisation = value.get("b").lower()
-
- # Specific transformation for `unisi`, because the real acronym is
- # `usi`.
- if organisation == "unisi":
- organisation = "usi"
-
- # Specific transformation for `hep bejune`, in order to fill out
- # custom fields `Filière` (`customField1`) and `Titre obtenu`
- # (`customField2`)
- if organisation == "hepbejune" and value.get("f"):
- document_subtype = value.get("f").lower()
- custom_field1 = ""
- custom_field2 = ""
- if document_subtype == "diss_bachelor":
- custom_field1 = "Enseignement primaire"
- custom_field2 = "Bachelor of Arts in Pre-Primary and Primary Education"
- elif document_subtype == "diss_master":
- custom_field1 = "Enseignement secondaire"
- custom_field2 = "Master of Arts or of Science in Secondary Education"
- if custom_field1:
- self["customField1"] = [custom_field1]
- if custom_field2:
- self["customField2"] = [custom_field2]
-
- # Specific transformation for `hepfr`, which should be imported as
- # a faculty AND a subdivision of FOLIA/unifr
- if organisation == "hepfr":
- organisation = "unifr"
- self["organisation"] = [{"$ref": OrganisationRecord.get_ref_link("organisations", organisation)}]
- # `hepfr` is a faculty of FOLIA/unifr
- self["customField1"] = ["HEP|PH FR"]
- # `hepfr` is a subdivision of FOLIA/unifr
- subdivision_name = "HEP Fribourg"
- # Store subdivision
- # TODO: avoid possible clashes between subdivision
- # names in different languages
- result = (
- RecordSearch()
- .filter("term", organisation__pid=organisation)
- .filter("term", name__value__raw=subdivision_name)
- .source(includes="pid")
- .scan()
- )
- subdivision_pid = next(result).pid
- # If the subdivision exists, assign it to the record
- if subdivision_pid:
- self["subdivisions"] = [{"$ref": SubdivisionRecord.get_ref_link("subdivisions", subdivision_pid)}]
-
- # Specific transformation for `bpuge` and `mhnge`, because the real
- # acronym is `vge`.
- subdivision_name = None
-
- if organisation in ["bpuge", "mhnge", "baage", "bmuge", "imvge", "mhsge"]:
- subdivision_name = "bge" if organisation == "bpuge" else organisation
- organisation = "vge"
-
- if organisation not in overdo.registererd_organisations:
- overdo.create_organisation(organisation)
- overdo.registererd_organisations.append(organisation)
-
- self["organisation"] = [{"$ref": OrganisationRecord.get_ref_link("organisations", organisation)}]
-
- if subdivision_name:
- # Store subdivision
- hash_key = hashlib.md5((subdivision_name + organisation).encode()).hexdigest()
-
- subdivision_pid = SubdivisionRecord.get_pid_by_hash_key(hash_key)
-
- # No subdivision found
- if not subdivision_pid:
- subdivision = SubdivisionRecord.create(
- {
- "name": [{"language": "eng", "value": subdivision_name}],
- "organisation": {"$ref": OrganisationRecord.get_ref_link("organisations", organisation)},
- "hashKey": hash_key,
- }
- )
- subdivision.commit()
- subdivision.reindex()
- db.session.commit()
- subdivision_pid = subdivision["pid"]
-
- self["subdivisions"] = [{"$ref": SubdivisionRecord.get_ref_link("subdivisions", subdivision_pid)}]
-
- # get doc type by mapping
- key = value.get("a", "") + "|" + value.get("f", "")
- if key not in TYPE_MAPPINGS:
- current_app.logger.warning(f'Document type not found in mapping for type "{key}"')
- return
-
- # Store types to records
- self["documentType"] = TYPE_MAPPINGS[key]
-
- return
-
-
-@overdo.over("language", "^041")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_language(self, key, value):
- """Get languages."""
- if not value.get("a"):
- return
-
- language = self.get("language", [])
-
- for code in utils.force_list(value.get("a")):
- language.append({"type": "bf:Language", "value": code})
-
- self["language"] = language
-
- return
-
-
-@overdo.over("title", "^245..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_title_245(self, key, value):
- """Get title."""
- main_title = value.get("a")
- language = value.get("9", "eng")
- subtitle = value.get("b")
-
- if not main_title:
- return None
-
- title = {
- "type": "bf:Title",
- "mainTitle": [{"value": main_title.rstrip(":"), "language": language}],
- }
-
- if subtitle:
- title["subtitle"] = [{"value": subtitle, "language": language}]
-
- return title
-
-
-@overdo.over("title", "^246..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_title_246(self, key, value):
- """Get title."""
- main_title = value.get("a")
- language = value.get("9", "eng")
-
- if not main_title:
- return
-
- title = self.get("title", [{"type": "bf:Title", "mainTitle": []}])
-
- # Add title 246 to last title in mainTitle propert
- title[-1]["mainTitle"].append({"value": main_title, "language": language})
-
- self["title"] = title
-
- return
-
-
-@overdo.over("editionStatement", "^250..")
-@utils.ignore_value
-def marc21_to_edition_statement(self, key, value):
- """Get edition statement data."""
- if not value.get("a") or not value.get("b"):
- return None
-
- return {
- "editionDesignation": {"value": value.get("a")},
- "responsibility": {"value": value.get("b")},
- }
-
-
-@overdo.over("provisionActivity", "^260..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_provision_activity_field_260(self, key, value):
- """Get provision activity data from field 260."""
- provision_activity = self.get("provisionActivity", [])
-
- # Only if there is a date
- if value.get("c"):
- publication = {"type": "bf:Publication", "statement": []}
-
- # Place
- if value.get("a"):
- publication["statement"].append({"type": "bf:Place", "label": [{"value": value.get("a")}]})
-
- # Agent
- if value.get("b"):
- publication["statement"].append(
- {
- "type": "bf:Agent",
- "label": [{"value": remove_trailing_punctuation(value.get("b"))}],
- }
- )
-
- years = value.get("c").split("-")
-
- # Start date
- if years and re.match(r"^\d{4}$", years[0]):
- publication["startDate"] = years[0]
-
- publication["statement"].append({"type": "Date", "label": [{"value": value.get("c")}]})
-
- # End date
- if len(years) > 1 and re.match(r"^\d{4}$", years[1]):
- publication["endDate"] = years[1]
-
- provision_activity.append(publication)
-
- # Manufacture
- if value.get("e") or value.get("f"):
- manufacture = {"type": "bf:Manufacture", "statement": []}
-
- if value.get("e"):
- manufacture["statement"].append(
- {
- "type": "bf:Place",
- "label": [{"value": remove_trailing_punctuation(value.get("e"))}],
- }
- )
-
- if value.get("f"):
- manufacture["statement"].append({"type": "bf:Agent", "label": [{"value": value.get("f")}]})
-
- provision_activity.append(manufacture)
-
- # Re-assign provision activity
- if provision_activity:
- self["provisionActivity"] = provision_activity
-
- return
-
-
-@overdo.over("provisionActivity", "^269..")
-@utils.ignore_value
-def marc21_to_provision_activity_field_269(self, key, value):
- """Get provision activity data from field 269."""
- # 260$c has priority to this date
- if overdo.blob_record.get("260__", {}).get("c"):
- return
-
- # No date, skipping
- if not value.get("c"):
- return
-
- # Assign start date
- match = re.search(r"^[0-9]{4}(-[0-9]{2}-[0-9]{2})?$", value.get("c"))
-
- # Date does not match "YYYY" or "YYYY-MM-DD"
- if not match:
- return
-
- add_provision_activity_start_date(self, value.get("c"))
-
- return
-
-
-@overdo.over("formats", "^300..")
-@utils.ignore_value
-def marc21_to_description(self, key, value):
- """Get extent, otherMaterialCharacteristics, formats.
-
- extent: 300$a (the first one if many)
- otherMaterialCharacteristics: 300$b (the first one if many)
- formats: 300 [$c repetitive]
- """
- if value.get("a") and not self.get("extent"):
- self["extent"] = remove_trailing_punctuation(overdo.not_repetitive(value, "a"))
-
- if value.get("b") and self.get("otherMaterialCharacteristics", []) == []:
- self["otherMaterialCharacteristics"] = remove_trailing_punctuation(overdo.not_repetitive(value, "b"))
-
- if value.get("c"):
- formats = self.get("formats")
-
- if not formats:
- data = value.get("c")
- formats = list(utils.force_list(data))
-
- return formats
-
- return None
-
-
-@overdo.over("series", "^490..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_series(self, key, value):
- """Get series.
-
- series.name: [490$a repetitive]
- series.number: [490$v repetitive]
- """
- series = {}
-
- name = value.get("a")
- if name:
- series["name"] = ", ".join(utils.force_list(name))
-
- number = value.get("v")
- if number:
- series["number"] = ", ".join(utils.force_list(number))
-
- return series
-
-
-@overdo.over("abstracts", "^520..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_abstract(self, key, value):
- """Get abstract."""
- abstract = value.get("a")
- language = value.get("9", "eng")
-
- if not abstract:
- return
-
- if language == "fr":
- language = "fre"
-
- abstracts_data = self.get("abstracts", [])
- abstracts_data.append({"value": abstract, "language": language})
-
- self["abstracts"] = abstracts_data
-
- return
-
-
-@overdo.over("identifiedBy", "001")
-@utils.ignore_value
-def marc21_to_identified_by_from_001(self, key, value):
- """Get identifier from field 001."""
- identified_by = self.get("identifiedBy", [])
-
- identified_by.append({"type": "bf:Local", "source": "RERO DOC", "value": value})
-
- return identified_by
-
-
-@overdo.over("identifiedBy", "^020..")
-@utils.ignore_value
-def marc21_to_identified_by_from_020(self, key, value):
- """Get identifier from field 020."""
- identified_by = self.get("identifiedBy", [])
-
- if not value.get("a"):
- return None
-
- identified_by.append({"type": "bf:Isbn", "value": value.get("a")})
-
- return identified_by
-
-
-@overdo.over("identifiedBy", "^0247.")
-@utils.ignore_value
-def marc21_to_identified_by_from_024(self, key, value):
- """Get identifier from field 024."""
- identified_by = self.get("identifiedBy", [])
-
- if not value.get("a") or value.get("2") != "urn":
- return None
-
- identified_by.append({"type": "bf:Urn", "value": value.get("a")})
-
- return identified_by
-
-
-@overdo.over("identifiedBy", "^027..")
-@utils.ignore_value
-def marc21_to_identified_by_from_027(self, key, value):
- """Get identifier from field 027."""
- identified_by = self.get("identifiedBy", [])
-
- if not value.get("a"):
- return None
-
- identified_by.append({"type": "bf:Strn", "value": value.get("a")})
-
- return identified_by
-
-
-@overdo.over("identifiedBy", "^035..")
-@utils.ignore_value
-def marc21_to_identified_by_from_035(self, key, value):
- """Get identifier from field 035."""
- identified_by = self.get("identifiedBy", [])
-
- if not value.get("a"):
- return None
-
- identified_by.append({"type": "bf:Local", "source": "RERO", "value": value.get("a")})
-
- return identified_by
-
-
-@overdo.over("identifiedBy", "^037..")
-@utils.ignore_value
-def marc21_to_identified_by_from_037(self, key, value):
- """Get identifier from field 037."""
- identified_by = self.get("identifiedBy", [])
-
- if not value.get("a"):
- return None
-
- identified_by.append(
- {
- "type": "bf:Local",
- "source": "Swissbib",
- "value": value.get("a").replace("swissbib.ch:", "").strip(),
- }
- )
-
- return identified_by
-
-
-@overdo.over("identifiedBy", "^088..")
-@utils.ignore_value
-def marc21_to_identified_by_from_088(self, key, value):
- """Get identifier from field 088."""
- identified_by = self.get("identifiedBy", [])
-
- if not value.get("a"):
- return None
-
- identified_by.append({"type": "bf:ReportNumber", "value": value.get("a")})
-
- return identified_by
-
-
-@overdo.over("identifiedBy", "^091..")
-@utils.ignore_value
-def marc21_to_identified_by_from_091(self, key, value):
- """Get identifier from field 091."""
- identified_by = self.get("identifiedBy", [])
-
- if not value.get("a") or value.get("b") != "pmid":
- return None
-
- identified_by.append({"type": "bf:Local", "value": value.get("a"), "source": "PMID"})
-
- return identified_by
-
-
-@overdo.over("notes", "^500..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_notes(self, key, value):
- """Get notes."""
- return overdo.not_repetitive(value, "a")
-
-
-@overdo.over("subjects", "^600..|695..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_subjects(self, key, value):
- """Get subjects."""
- if not value.get("a"):
- return None
-
- subjects = {"label": {"value": [item for item in value.get("a").split(" ; ") if item]}}
-
- # If field is 695 and no language is available
- if key == "695__":
- if not value.get("9"):
- return None
-
- subjects["label"]["language"] = value.get("9")
-
- # If field is 600 and no source is available
- if key == "600__":
- if not value.get("2"):
- return None
-
- subjects["source"] = value.get("2")
-
- return subjects
-
-
-@overdo.over("files", "^856..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_files(self, key, value):
- """Get files."""
- key = value.get("f")
- url = value.get("u")
- mime_type = value.get("q", "text/plain")
-
- if not key or not url:
- return None
-
- # TODO: Check why this type of file exists. Real example with rerodoc ID
- # 29085
- if mime_type == "pdt/download":
- current_app.logger.warning(
- f"File {key} for record {self['identifiedBy']} has a strange pdt/download mime "
- "type, skipping import of file..."
- )
- return None
-
- url = url.strip()
-
- # Retreive file order
- # If order not set we put a value to 99 for easily point theses files
- order = 99
- if value.get("y"):
- match = re.search(r"order:([0-9]+)$", value.get("y"))
- if match:
- order = int(match.group(1))
-
- return {
- "key": key,
- "url": url,
- "label": value.get("z", key),
- "type": "file",
- "order": order,
- }
-
-
-@overdo.over("otherEdition", "^775..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_other_edition(self, key, value):
- """Get other edition."""
- electronic_locator = value.get("o")
- public_note = value.get("g")
-
- if not electronic_locator or not public_note:
- return None
-
- # if the value matches a DOI, apply `identifiedBy[type:bf:Doi]`
- matches = re.search(r"(?P10\.\d{4,9}/[-._;()/:a-zA-Z0-9]+)", value.get("o"))
- if matches and matches.group("doi"):
- identified_by = self.get("identifiedBy", [])
- identified_by.append({"type": "bf:Doi", "value": matches.group("doi")})
- self["identifiedBy"] = identified_by
- return None
- return {
- "document": {"electronicLocator": electronic_locator},
- "publicNote": public_note,
- }
-
-
-@overdo.over("collections", "^982..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_specific_collection(self, key, value):
- """Extract collection for record."""
- if not value.get("a"):
- return None
-
- # No organisation found, the collection is not imported.
- if not self.get("organisation"):
- return None
-
- organisation_pid = OrganisationRecord.get_pid_by_ref_link(self["organisation"][0]["$ref"])
-
- hash_key = hashlib.md5((value.get("a") + organisation_pid).encode()).hexdigest()
-
- collection_pid = CollectionRecord.get_pid_by_hash_key(hash_key)
-
- # No collection found
- if not collection_pid:
- collection = CollectionRecord.create(
- {
- "name": [{"language": "eng", "value": value.get("a")}],
- "organisation": {"$ref": self["organisation"][0]["$ref"]},
- "hashKey": hash_key,
- }
- )
- collection.commit()
- collection.reindex()
- db.session.commit()
- collection_pid = collection["pid"]
-
- return {"$ref": CollectionRecord.get_ref_link("collections", collection_pid)}
-
-
-@overdo.over("classification", "^080..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_classification_field_080(self, key, value):
- """Get classification data from field 080."""
- if not value.get("a"):
- return None
-
- return {"type": "bf:ClassificationUdc", "classificationPortion": value.get("a")}
-
-
-@overdo.over("classification", "^084..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_classification_field_084(self, key, value):
- """Get classification data from field 084."""
- if not value.get("a") or value.get("2") != "ddc":
- return None
-
- return {"type": "bf:ClassificationDdc", "classificationPortion": value.get("a")}
-
-
-@overdo.over("contentNote", "^505..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_content_note(self, key, value):
- """Extract collection for record."""
- return value.get("a")
-
-
-@overdo.over("dissertation", "^502..")
-@utils.ignore_value
-def marc21_to_dissertation_field_502(self, key, value):
- """Extract dissertation degree."""
- record = overdo.blob_record
- if value.get("a"):
- dissertation = self.get("dissertation", {})
- dissertation["degree"] = value.get("a")
- self["dissertation"] = dissertation
-
- # try to parse the thesis note more precisely
- matches = re.match(
- r"^(?P[^:]+) : (?P[^,]+) ?[,:] (?P\d{4})( ; .*)?$",
- value.get("a"),
- )
- if matches:
- if matches.group("degree"):
- dissertation["degree"] = matches.group("degree")
- if matches.group("grantingInstitution"):
- dissertation["grantingInstitution"] = matches.group("grantingInstitution")
- if matches.group("date"):
- dissertation["date"] = matches.group("date")
-
- # Specific transformation for `hep bejune`, in order to fill out
- # custom fields `Filière` (`customField1`) and `Titre obtenu`
- # (`customField2`)
- organisation = record.get("980__", {}).get("b")
- if organisation and organisation.lower() == "hepbejune":
- degree = matches.group("degree").lower()
- custom_field1 = None
- custom_field2 = None
- if "mémoire de master spécialisé" in degree:
- custom_field1 = "Enseignement spécialisé"
- custom_field2 = "Master of Arts in special needs education, orientation enseignement spécialisé"
- elif "mémoire de master" in degree:
- custom_field1 = "Enseignement secondaire"
- custom_field2 = "Master of Arts or of Science in Secondary Education"
- elif "mémoire de bachelor" in degree:
- custom_field1 = "Enseignement primaire"
- custom_field2 = "Bachelor of Arts in Pre-Primary and Primary Education"
- if custom_field1:
- self["customField1"] = [custom_field1]
- if custom_field2:
- self["customField2"] = [custom_field2]
-
- # Try to get start date and store in provision activity
- # 260$c and 269$c have priority to this date
- if record.get("260__", {}).get("c") or record.get("269__", {}).get("c") or record.get("773__", {}).get("g"):
- return
-
- # No date, skipping
- if not value.get("9"):
- return
-
- # Match either 2019 or 2019-01-01
- match = re.search(r"^[0-9]{4}(-[0-9]{2}-[0-9]{2})?$", value.get("9"))
-
- if not match:
- return
-
- add_provision_activity_start_date(self, value.get("9"))
-
- return
-
-
-@overdo.over("dissertation", "^508..")
-@utils.ignore_value
-def marc21_to_dissertation_field_508(self, key, value):
- """Extract dissertation note."""
- if not value.get("a"):
- return
-
- dissertation = self.get("dissertation", {})
- dissertation["jury_note"] = value.get("a")
-
- self["dissertation"] = dissertation
-
- return
-
-
-@overdo.over("usageAndAccessPolicy", "^540..")
-@utils.ignore_value
-def marc21_to_usage_and_access_policy(self, key, value):
- """Extract usage and access policy."""
- if not value.get("a"):
- return None
-
- return {"label": value.get("a"), "license": "License undefined"}
-
-
-@overdo.over("contribution", "^100..")
-@utils.ignore_value
-def marc21_to_contribution_field_100(self, key, value):
- """Extract contribution from field 100."""
- if not value.get("a"):
- return
-
- contribution = self.get("contribution", [])
-
- data = {
- "agent": {"type": "bf:Person", "preferred_name": value.get("a")},
- "role": ["cre"],
- }
-
- # Affiliation
- if value.get("u"):
- data["affiliation"] = value.get("u")
-
- # Date of birth - date of death
- date_of_birth, date_of_death = overdo.extract_date(value.get("d"))
-
- if date_of_birth:
- data["agent"]["date_of_birth"] = date_of_birth
-
- if date_of_death:
- data["agent"]["date_of_death"] = date_of_death
-
- contribution.append(data)
- self["contribution"] = contribution
-
- return
-
-
-@overdo.over("contribution", "^700..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_contribution_field_700(self, key, value):
- """Extract contribution from field 100."""
- if not value.get("a"):
- return
-
- contribution = self.get("contribution", [])
-
- role = overdo.get_contributor_role(value.get("e"))
-
- if not role:
- raise Exception(f"No role found for contributor {value}")
-
- data = {
- "agent": {"type": "bf:Person", "preferred_name": value.get("a")},
- "role": [role],
- }
-
- # Affiliation
- if value.get("u"):
- data["affiliation"] = value.get("u")
-
- # Date of birth - date of death
- date_of_birth, date_of_death = overdo.extract_date(value.get("d"))
-
- if date_of_birth:
- data["agent"]["date_of_birth"] = date_of_birth
-
- if date_of_death:
- data["agent"]["date_of_death"] = date_of_death
-
- contribution.append(data)
- self["contribution"] = contribution
-
- return
-
-
-@overdo.over("contribution", "^710..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_contribution_field_710(self, key, value):
- """Extract contribution from field 710."""
- if not value.get("a"):
- return
-
- contribution = self.get("contribution", [])
- contribution.append(
- {
- "agent": {"type": "bf:Organization", "preferred_name": value.get("a")},
- "role": ["ctb"],
- }
- )
- self["contribution"] = contribution
-
- return
-
-
-@overdo.over("contribution", "^711..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_contribution_field_711(self, key, value):
- """Extract contribution from field 711."""
- if not value.get("a"):
- return
-
- contribution = self.get("contribution", [])
-
- data = {
- "agent": {"type": "bf:Meeting", "preferred_name": value.get("a")},
- "role": ["cre"],
- }
-
- # Place
- if value.get("c"):
- data["agent"]["place"] = value.get("c")
-
- # Date
- if value.get("d"):
- data["agent"]["date"] = value.get("d")
-
- # Number
- if value.get("n"):
- data["agent"]["number"] = value.get("n")
-
- contribution.append(data)
- self["contribution"] = contribution
-
- return
-
-
-@overdo.over("customField1", "^918..")
-@utils.ignore_value
-def marc21_to_faculty_and_department(self, key, value):
- """Extract faculty and department for UNIFR."""
- record = overdo.blob_record
- org = record.get("980__", {}).get("b")
- if org and org == "UNIFR":
- faculty = value.get("a")
- if faculty:
- self["customField1"] = [faculty]
- dep = value.get("c")
- if dep:
- self["customField2"] = [dep]
- return
-
-
-@overdo.over("partOf", "^773..")
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_part_of(self, key, value):
- """Extract related document for record."""
- if not value.get("g"):
- return None
-
- # Split value for getting numbering values
- numbering = value.get("g").split("/")
-
- # Numbering year
- if not numbering[0]:
- return None
-
- data = {"numberingYear": numbering[0]}
-
- # Volume
- if len(numbering) > 1 and numbering[1]:
- data["numberingVolume"] = numbering[1]
-
- # Issue
- if len(numbering) > 2 and numbering[2]:
- data["numberingIssue"] = numbering[2]
-
- # Pages
- if len(numbering) > 3 and numbering[3] and numbering[3] != "-":
- data["numberingPages"] = numbering[3]
-
- document = {}
-
- # Title is found
- if value.get("t"):
- document["title"] = value.get("t")
-
- # Contribution
- if value.get("c"):
- document["contribution"] = list(value.get("c").split(";"))
-
- record = overdo.blob_record
-
- # Publication based on document sub type
- sub_type = record.get("980__", {}).get("f")
- if value.get("d") or sub_type == "ART_INBOOK":
- document["publication"] = {}
-
- if value.get("d"):
- document["publication"]["statement"] = value.get("d")
-
- if sub_type == "ART_INBOOK":
- document["publication"]["startDate"] = numbering[0]
-
- # If no field 260$c or 269$c, store start date
- if not record.get("260__", {}).get("c") and not record.get("269__", {}).get("c"):
- add_provision_activity_start_date(self, numbering[0])
-
- if document:
- data["document"] = document
-
- return data
-
-
-def add_provision_activity_start_date(data, date):
- """Add start date for provision activity.
-
- :param data: Data dictionary.
- :param date: Date to add.
- """
- provisition_activity = data.get("provisionActivity", [])
-
- def get_publication():
- """Get stored publication."""
- for key, item in enumerate(provisition_activity):
- if item["type"] == "bf:Publication":
- return provisition_activity.pop(key)
-
- return {"type": "bf:Publication", "startDate": None}
-
- publication = get_publication()
-
- publication["startDate"] = date
-
- # Inject publiction into provision activity
- provisition_activity.append(publication)
-
- # Re-assign provisionActivity
- data["provisionActivity"] = provisition_activity
diff --git a/sonar/modules/documents/dojson/rerodoc/model.py_hesso b/sonar/modules/documents/dojson/rerodoc/model.py_hesso
deleted file mode 100644
index 436f009eb..000000000
--- a/sonar/modules/documents/dojson/rerodoc/model.py_hesso
+++ /dev/null
@@ -1,1168 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""RERODOC MARC21 model definition."""
-
-import hashlib
-import re
-
-from dojson import utils
-from flask import current_app
-from invenio_db import db
-
-from sonar.modules.collections.api import Record as CollectionRecord
-from sonar.modules.documents.dojson.rerodoc.overdo import Overdo
-from sonar.modules.organisations.api import OrganisationRecord
-from sonar.modules.subdivisions.api import Record as SubdivisionRecord
-from sonar.modules.subdivisions.api import RecordSearch
-from sonar.modules.utils import remove_trailing_punctuation
-
-overdo = Overdo()
-
-TYPE_MAPPINGS = {
- 'PREPRINT|': 'coar:c_816b',
- 'POSTPRINT|ART_JOURNAL': 'coar:c_6501',
- 'POSTPRINT|ART_INBOOK': 'coar:c_3248',
- 'POSTPRINT|ART_INPROC': 'coar:c_5794',
- 'BOOK|': 'coar:c_2f33',
- 'DISSERTATION|DISS_MASTER': 'coar:c_bdcc',
- 'DISSERTATION|DISS_BACHELOR': 'coar:c_7a1f',
- 'DISSERTATION|DISS_CONT_EDU': 'advanced_studies_thesis',
- 'THESIS|': 'coar:c_db06',
- 'THESIS|TH_PHD': 'coar:c_db06',
- 'THESIS|TH_HABILIT': 'coar:c_46ec',
- 'MAP|': 'coar:c_12cc',
- 'REPORT|': 'coar:c_18ws',
- 'NEWSPAPER|': 'coar:c_2fe3',
- 'JOURNAL|': 'coar:c_0640',
- 'PRINT_MEDIA|': 'coar:c_2fe3',
- 'AUDIO|': 'coar:c_18cc',
- 'IMAGE|': 'coar:c_ecc8',
- 'PARTITION|': 'coar:c_18cw'
-}
-
-
-@overdo.over('type', '^980')
-@utils.ignore_value
-def marc21_to_type_and_organisation(self, key, value):
- """Get document type and organisation from 980 field."""
- subdivision_name = None
- record = overdo.blob_record
-
- # organisation
- if value.get('b'):
- organisation = value.get('b').lower()
-
- # Specific transformation for `unisi`, because the real acronym is
- # `usi`.
- if organisation == 'unisi':
- organisation = 'usi'
-
- # Specific transformation for `hep bejune`, in order to fill out
- # custom fields `Filière` (`customField1`) and `Titre obtenu`
- # (`customField2`)
- if organisation == 'hepbejune' and value.get('f'):
- document_subtype = value.get('f').lower()
- customField1 = ''
- customField2 = ''
- if document_subtype == 'diss_bachelor':
- customField1 = 'Enseignement primaire'
- customField2 = 'Bachelor of Arts in Pre-Primary and Primary Education'
- elif document_subtype == 'diss_master':
- customField1 = 'Enseignement secondaire'
- customField2 = 'Master of Arts or of Science in Secondary Education'
- if customField1:
- self['customField1'] = [customField1]
- if customField2:
- self['customField2'] = [customField2]
-
- # Specific transformation for `hepfr`, which should be imported as
- # a faculty AND a subdivision of FOLIA/unifr
- if organisation == 'hepfr':
- organisation = 'unifr'
- self['organisation'] = [{
- '$ref':
- OrganisationRecord.get_ref_link('organisations', organisation)
- }]
- # `hepfr` is a faculty of FOLIA/unifr
- self['customField1'] = ['HEP|PH FR']
- # `hepfr` is a subdivision of FOLIA/unifr
- subdivision_name = 'HEP Fribourg'
- # Store subdivision
- # TODO: avoid possible clashes between subdivision
- # names in different languages
- result = RecordSearch()\
- .filter('term', organisation__pid=organisation)\
- .filter('term', name__value__raw=subdivision_name)\
- .source(includes='pid').scan()
- subdivision_pid = next(result).pid
- # If the subdivision exists, assign it to the record
- if subdivision_pid:
- self['subdivisions'] = [{
- '$ref':
- SubdivisionRecord.get_ref_link('subdivisions', subdivision_pid)
- }]
-
- # Specific transformation for `hesso` - 11 institutions in RERO DOC
- # are imported to a new `hesso` institution in SONAR
- if organisation in [
- 'heascne', 'heasju', 'hedsfr', 'hegge', 'hedsge',
- 'hetsge', 'hetsvs', 'hegtvs', 'hedsvs', 'heivs', 'esdsvs'
- ]:
- # include the original organisation code (from RERO DOC) as a note,
- # for later reference
- notes = []
- if 'notes' in self:
- notes = self['notes']
- institution = None
- code = None
-
- # replace the original RERO DOC institution codes and names
- # by their current equivalent
- # NB: records from 'esdsvs' are imported as 'hetsvs'
- inst_mapping = {
- 'heascne': ('hearc-cor', 'Haute Ecole Arc Conservation-Restauration Neuchâtel'),
- 'heasju': ('hearc-san', 'Haute Ecole Arc Santé'),
- 'hedsfr': ('hedsfr', 'Haute école de santé Fribourg'),
- 'hegge': ('hegge', 'Haute école de gestion Genève'),
- 'hedsge': ('hedsge', 'Haute école de santé Genève'),
- 'hetsge': ('hetsge', 'Haute école de travail social Genève'),
- 'hetsvs': ('hetsvs', 'Haute Ecole de Travail Social Valais'),
- 'esdsvs': ('hetsvs', 'Haute Ecole de Travail Social Valais'),
- 'hegtvs': ('hegvs', 'Haute Ecole de Gestion Valais'),
- 'hedsvs': ('hedsvs', 'Haute Ecole de Santé Valais'),
- 'heivs': ('heivs', 'Haute Ecole d\'Ingénierie Valais')
- }
- (code, institution) = inst_mapping.get(organisation, (None, None))
-
- # reject deprecated institution names
- depracated_names = (
- 'Haute Ecole Arc Conservation-Restauration',
- 'Haute Ecole de Santé de Fribourg',
- 'Haute école de gestion de Genève',
- 'Haute école de travail social de Genève',
- 'Haute Ecole de Travail Social',
- 'Haute Ecole de Gestion & Tourisme',
- 'Haute Ecole d\'Ingénierie',
- )
-
- # include the institution name as note
- if not institution:
- # get it from source MARC if not found in the dict
- institution = record.get('919__', {}).get('a')
- if (institution and institution not in notes and
- institution not in depracated_names):
- notes.append(institution)
- # include faculty and department information as notes, as well
- faculty = record.get('918__', {}).get('a')
- if (faculty and faculty not in notes and
- faculty not in depracated_names):
- notes.append(faculty)
- department = record.get('918__', {}).get('c')
- if department and department not in notes:
- notes.append(department)
- # add a note with a code identifiying the source institution
- notes.append('hesso:' + code)
- self['notes'] = notes
- # from now on, the organisation code is `hesso`
- organisation = 'hesso'
-
-
- # Specific transformation for `bpuge` and `mhnge`, because the real
- # acronym is `vge`.
- subdivision_name = None
-
- if organisation in [
- 'bpuge', 'mhnge', 'baage', 'bmuge', 'imvge', 'mhsge'
- ]:
- subdivision_name = 'bge' if organisation == 'bpuge' else organisation
- organisation = 'vge'
-
- if organisation not in overdo.registererd_organisations:
- overdo.create_organisation(organisation)
- overdo.registererd_organisations.append(organisation)
-
- self['organisation'] = [{
- '$ref':
- OrganisationRecord.get_ref_link('organisations', organisation)
- }]
-
- if subdivision_name:
- # Store subdivision
- hash_key = hashlib.md5(
- (subdivision_name + organisation).encode()).hexdigest()
-
- subdivision_pid = SubdivisionRecord.get_pid_by_hash_key(hash_key)
-
- # No subdivision found
- if not subdivision_pid:
- subdivision = SubdivisionRecord.create({
- 'name': [{
- 'language': 'eng',
- 'value': subdivision_name
- }],
- 'organisation': {
- '$ref':
- OrganisationRecord.get_ref_link(
- 'organisations', organisation)
- },
- 'hashKey':
- hash_key
- })
- subdivision.commit()
- subdivision.reindex()
- db.session.commit()
- subdivision_pid = subdivision['pid']
-
- self['subdivisions'] = [{
- '$ref':
- SubdivisionRecord.get_ref_link('subdivisions', subdivision_pid)
- }]
-
- # get doc type by mapping
- key = value.get('a', '') + '|' + value.get('f', '')
- if key not in TYPE_MAPPINGS:
- current_app.logger.warning(f'Document type not found in mapping for type "{key}"')
- return None
-
- # Store types to records
- self['documentType'] = TYPE_MAPPINGS[key]
-
- return None
-
-
-@overdo.over('language', '^041')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_language(self, key, value):
- """Get languages."""
- if not value.get('a'):
- return None
-
- language = self.get('language', [])
-
- codes = utils.force_list(value.get('a'))
-
- for code in codes:
- language.append({'type': 'bf:Language', 'value': code})
-
- self['language'] = language
-
- return None
-
-
-@overdo.over('title', '^245..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_title_245(self, key, value):
- """Get title."""
- main_title = value.get('a')
- language = value.get('9', 'eng')
- subtitle = value.get('b')
-
- if not main_title:
- return None
-
- title = {
- 'type': 'bf:Title',
- 'mainTitle': [{
- 'value': main_title.rstrip(':'),
- 'language': language
- }]
- }
-
- if subtitle:
- title['subtitle'] = [{'value': subtitle, 'language': language}]
-
- return title
-
-
-@overdo.over('title', '^246..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_title_246(self, key, value):
- """Get title."""
- main_title = value.get('a')
- language = value.get('9', 'eng')
-
- if not main_title:
- return None
-
- title = self.get('title', [{'type': 'bf:Title', 'mainTitle': []}])
-
- # Add title 246 to last title in mainTitle propert
- title[-1]['mainTitle'].append({'value': main_title, 'language': language})
-
- self['title'] = title
-
- return None
-
-
-@overdo.over('editionStatement', '^250..')
-@utils.ignore_value
-def marc21_to_edition_statement(self, key, value):
- """Get edition statement data."""
- if not value.get('a'):
- return None
-
- editionStatement = {
- 'editionDesignation': {
- 'value': value.get('a')
- }
- }
- if value.get('b'):
- editionStatement['responsibility'] = {
- 'value': value.get('b')
- }
- return editionStatement
-
-
-@overdo.over('provisionActivity', '^260..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_provision_activity_field_260(self, key, value):
- """Get provision activity data from field 260."""
- provision_activity = self.get('provisionActivity', [])
-
- # Only if there is a date
- if value.get('c'):
- publication = {'type': 'bf:Publication', 'statement': []}
-
- # Place
- if value.get('a'):
- publication['statement'].append({
- 'type':
- 'bf:Place',
- 'label': [{
- 'value': value.get('a')
- }]
- })
-
- # Agent
- if value.get('b'):
- publication['statement'].append({
- 'type':
- 'bf:Agent',
- 'label': [{
- 'value': remove_trailing_punctuation(value.get('b'))
- }]
- })
-
- years = value.get('c').split('-')
-
- # Start date
- if years and re.match(r'^\d{4}$', years[0]):
- publication['startDate'] = years[0]
-
- publication['statement'].append({
- 'type':
- 'Date',
- 'label': [{
- 'value': value.get('c')
- }]
- })
-
- # End date
- if len(years) > 1 and re.match(r'^\d{4}$', years[1]):
- publication['endDate'] = years[1]
-
- provision_activity.append(publication)
-
- # Manufacture
- if value.get('e') or value.get('f'):
- manufacture = {'type': 'bf:Manufacture', 'statement': []}
-
- if value.get('e'):
- manufacture['statement'].append({
- 'type':
- 'bf:Place',
- 'label': [{
- 'value': remove_trailing_punctuation(value.get('e'))
- }]
- })
-
- if value.get('f'):
- manufacture['statement'].append({
- 'type':
- 'bf:Agent',
- 'label': [{
- 'value': value.get('f')
- }]
- })
-
- provision_activity.append(manufacture)
-
- # Re-assign provision activity
- if provision_activity:
- self['provisionActivity'] = provision_activity
-
- return None
-
-
-@overdo.over('provisionActivity', '^269..')
-@utils.ignore_value
-def marc21_to_provision_activity_field_269(self, key, value):
- """Get provision activity data from field 269."""
- # 260$c has priority to this date
- if overdo.blob_record.get('260__', {}).get('c'):
- return None
-
- # No date, skipping
- if not value.get('c'):
- return None
-
- # Assign start date
- match = re.search(r'^[0-9]{4}(-[0-9]{2}-[0-9]{2})?$', value.get('c'))
-
- # Date does not match "YYYY" or "YYYY-MM-DD"
- if not match:
- return None
-
- add_provision_activity_start_date(self, value.get('c'))
-
- return None
-
-
-@overdo.over('formats', '^300..')
-@utils.ignore_value
-def marc21_to_description(self, key, value):
- """Get extent, otherMaterialCharacteristics, formats.
-
- extent: 300$a (the first one if many)
- otherMaterialCharacteristics: 300$b (the first one if many)
- formats: 300 [$c repetitive]
- """
- if value.get('a'):
- if not self.get('extent'):
- self['extent'] = remove_trailing_punctuation(
- overdo.not_repetitive(value, 'a'))
-
- if value.get('b'):
- if self.get('otherMaterialCharacteristics', []) == []:
- self['otherMaterialCharacteristics'] = remove_trailing_punctuation(
- overdo.not_repetitive(value, 'b'))
-
- if value.get('c'):
- formats = self.get('formats')
-
- if not formats:
- data = value.get('c')
- formats = list(utils.force_list(data))
-
- return formats
-
- return None
-
-
-@overdo.over('series', '^490..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_series(self, key, value):
- """Get series.
-
- series.name: [490$a repetitive]
- series.number: [490$v repetitive]
- """
- series = {}
-
- name = value.get('a')
- if name:
- series['name'] = ', '.join(utils.force_list(name))
-
- number = value.get('v')
- if number:
- series['number'] = ', '.join(utils.force_list(number))
-
- return series
-
-
-@overdo.over('abstracts', '^520..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_abstract(self, key, value):
- """Get abstract."""
- abstract = value.get('a')
- language = value.get('9', 'eng')
-
- if not abstract:
- return None
-
- if language == 'fr':
- language = 'fre'
-
- abstracts_data = self.get('abstracts', [])
- abstracts_data.append({'value': abstract, 'language': language})
-
- self['abstracts'] = abstracts_data
-
- return None
-
-
-@overdo.over('identifiedBy', '001')
-@utils.ignore_value
-def marc21_to_identified_by_from_001(self, key, value):
- """Get identifier from field 001."""
- identified_by = self.get('identifiedBy', [])
-
- identified_by.append({
- 'type': 'bf:Local',
- 'source': 'RERO DOC',
- 'value': value
- })
-
- return identified_by
-
-
-@overdo.over('identifiedBy', '^020..')
-@utils.ignore_value
-def marc21_to_identified_by_from_020(self, key, value):
- """Get identifier from field 020."""
- identified_by = self.get('identifiedBy', [])
-
- if not value.get('a'):
- return None
-
- identified_by.append({'type': 'bf:Isbn', 'value': value.get('a')})
-
- return identified_by
-
-
-@overdo.over('identifiedBy', '^0247.')
-@utils.ignore_value
-def marc21_to_identified_by_from_024(self, key, value):
- """Get identifier from field 024."""
- identified_by = self.get('identifiedBy', [])
-
- if not value.get('a') or value.get('2') != 'urn':
- return None
-
- identified_by.append({'type': 'bf:Urn', 'value': value.get('a')})
-
- return identified_by
-
-
-@overdo.over('identifiedBy', '^027..')
-@utils.ignore_value
-def marc21_to_identified_by_from_027(self, key, value):
- """Get identifier from field 027."""
- identified_by = self.get('identifiedBy', [])
-
- if not value.get('a'):
- return None
-
- identified_by.append({'type': 'bf:Strn', 'value': value.get('a')})
-
- return identified_by
-
-
-@overdo.over('identifiedBy', '^035..')
-@utils.ignore_value
-def marc21_to_identified_by_from_035(self, key, value):
- """Get identifier from field 035."""
- identified_by = self.get('identifiedBy', [])
-
- if not value.get('a'):
- return None
-
- identified_by.append({
- 'type': 'bf:Local',
- 'source': 'RERO',
- 'value': value.get('a')
- })
-
- return identified_by
-
-
-@overdo.over('identifiedBy', '^037..')
-@utils.ignore_value
-def marc21_to_identified_by_from_037(self, key, value):
- """Get identifier from field 037."""
- identified_by = self.get('identifiedBy', [])
-
- if not value.get('a'):
- return None
-
- identified_by.append({
- 'type':
- 'bf:Local',
- 'source':
- 'Swissbib',
- 'value':
- value.get('a').replace('swissbib.ch:', '').strip()
- })
-
- return identified_by
-
-
-@overdo.over('identifiedBy', '^088..')
-@utils.ignore_value
-def marc21_to_identified_by_from_088(self, key, value):
- """Get identifier from field 088."""
- identified_by = self.get('identifiedBy', [])
-
- if not value.get('a'):
- return None
-
- identified_by.append({'type': 'bf:ReportNumber', 'value': value.get('a')})
-
- return identified_by
-
-
-@overdo.over('identifiedBy', '^091..')
-@utils.ignore_value
-def marc21_to_identified_by_from_091(self, key, value):
- """Get identifier from field 091."""
- identified_by = self.get('identifiedBy', [])
-
- if not value.get('a') or value.get('b') != 'pmid':
- return None
-
- identified_by.append({
- 'type': 'bf:Local',
- 'value': value.get('a'),
- 'source': 'PMID'
- })
-
- return identified_by
-
-
-@overdo.over('notes', '^500..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_notes(self, key, value):
- """Get notes."""
- return overdo.not_repetitive(value, 'a')
-
-
-@overdo.over('subjects', '^600..|695..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_subjects(self, key, value):
- """Get subjects."""
- if not value.get('a'):
- return None
-
- subject_values = []
-
- for item in value.get('a').split(' ; '):
- if item:
- subject_values.append(item)
-
- subjects = {'label': {'value': subject_values}}
-
- # If field is 695 and no language is available
- if key == '695__':
- if not value.get('9'):
- return None
-
- subjects['label']['language'] = value.get('9')
-
- # If field is 600 and no source is available
- if key == '600__':
- if not value.get('2'):
- return None
-
- subjects['source'] = value.get('2')
-
- return subjects
-
-
-@overdo.over('files', '^856..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_files(self, key, value):
- """Get files."""
- key = value.get('f')
- url = value.get('u')
- mime_type = value.get('q', 'text/plain')
-
- if not key or not url:
- return None
-
- # TODO: Check why this type of file exists. Real example with rerodoc ID
- # 29085
- if mime_type == 'pdt/download':
- current_app.logger.warning(
- f"File {key} for record {self['identifiedBy']} has a strange pdt/download mime "
- "type, skipping import of file..."
- )
- return None
-
- url = url.strip()
-
- # Retreive file order
- # If order not set we put a value to 99 for easily point theses files
- order = 99
- if value.get('y'):
- match = re.search(r'order:([0-9]+)$', value.get('y'))
- if match:
- order = int(match.group(1))
-
- data = {
- 'key': key,
- 'url': url,
- 'label': value.get('z', key),
- 'type': 'file',
- 'order': order
- }
-
- return data
-
-
-@overdo.over('otherEdition', '^775..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_other_edition(self, key, value):
- """Get other edition."""
- electronic_locator = value.get('o')
- public_note = value.get('g')
-
- if not electronic_locator or not public_note:
- return None
-
- # if the value matches a DOI, apply `identifiedBy[type:bf:Doi]`
- matches = re.search(r'(?P10\.\d{4,9}/[-._;()/:a-zA-Z0-9]+)', value.get('o'))
- if matches and matches.group('doi'):
- identified_by = self.get('identifiedBy', [])
- identified_by.append({
- 'type': 'bf:Doi',
- 'value': matches.group('doi')
- })
- self['identifiedBy'] = identified_by
- return None
- else:
- return {
- 'document': {
- 'electronicLocator': electronic_locator
- },
- 'publicNote': public_note
- }
-
-
-@overdo.over('collections', '^982..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_specific_collection(self, key, value):
- """Extract collection for record."""
- if not value.get('a'):
- return None
-
- # No organisation found, the collection is not imported.
- if not self.get('organisation'):
- return None
-
- organisation_pid = OrganisationRecord.get_pid_by_ref_link(
- self['organisation'][0]['$ref'])
-
- hash_key = hashlib.md5(
- (value.get('a') + organisation_pid).encode()).hexdigest()
-
- collection_pid = CollectionRecord.get_pid_by_hash_key(hash_key)
-
- # No collection found
- if not collection_pid:
- collection = CollectionRecord.create({
- 'name': [{
- 'language': 'eng',
- 'value': value.get('a')
- }],
- 'organisation': {
- '$ref': self['organisation'][0]['$ref']
- },
- 'hashKey':
- hash_key
- })
- collection.commit()
- collection.reindex()
- db.session.commit()
- collection_pid = collection['pid']
-
- return {
- '$ref': CollectionRecord.get_ref_link('collections', collection_pid)
- }
-
-
-@overdo.over('classification', '^080..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_classification_field_080(self, key, value):
- """Get classification data from field 080."""
- if not value.get('a'):
- return None
-
- return {
- 'type': 'bf:ClassificationUdc',
- 'classificationPortion': value.get('a')
- }
-
-
-@overdo.over('classification', '^084..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_classification_field_084(self, key, value):
- """Get classification data from field 084."""
- if not value.get('a') or value.get('2') != 'ddc':
- return None
-
- return {
- 'type': 'bf:ClassificationDdc',
- 'classificationPortion': value.get('a')
- }
-
-
-@overdo.over('contentNote', '^505..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_content_note(self, key, value):
- """Extract content note for record."""
- return value.get('a')
-
-
-@overdo.over('dissertation', '^502..')
-@utils.ignore_value
-def marc21_to_dissertation_field_502(self, key, value):
- """Extract dissertation degree."""
- record = overdo.blob_record
- if value.get('a'):
- dissertation = self.get('dissertation', {})
- dissertation['degree'] = value.get('a')
- self['dissertation'] = dissertation
-
- # try to parse the thesis note more precisely
- matches = re.match(r'^(?P[^:]+) : (?P[^,]+) ?[,:] (?P\d{4})( ; .*)?$', value.get('a'))
- if matches:
- if matches.group("degree"):
- dissertation['degree'] = matches.group("degree")
- if matches.group("grantingInstitution"):
- dissertation['grantingInstitution'] = matches.group("grantingInstitution")
- if matches.group("date"):
- dissertation['date'] = matches.group("date")
-
- # Specific transformation for `hep bejune`, in order to fill out
- # custom fields `Filière` (`customField1`) and `Titre obtenu`
- # (`customField2`)
- organisation = record.get('980__', {}).get('b')
- if (organisation and organisation.lower() == 'hepbejune'):
- degree = matches.group("degree").lower()
- customField1 = None
- customField2 = None
- if 'mémoire de master spécialisé' in degree:
- customField1 = 'Enseignement spécialisé'
- customField2 = 'Master of Arts in special needs ' \
- 'education, orientation enseignement spécialisé'
- elif 'mémoire de master' in degree:
- customField1 = 'Enseignement secondaire'
- customField2 = 'Master of Arts or of Science ' \
- 'in Secondary Education'
- elif 'mémoire de bachelor' in degree:
- customField1 = 'Enseignement primaire'
- customField2 = 'Bachelor of Arts in Pre-Primary and ' \
- 'Primary Education'
- if customField1:
- self['customField1'] = [customField1]
- if customField2:
- self['customField2'] = [customField2]
-
- # Try to get start date and store in provision activity
- # 260$c and 269$c have priority to this date
- if (record.get('260__', {}).get('c') or record.get('269__', {}).get('c') or
- record.get('773__', {}).get('g')):
- return None
-
- # No date, skipping
- if not value.get('9'):
- return None
-
- # Match either 2019 or 2019-01-01
- match = re.search(r'^[0-9]{4}(-[0-9]{2}-[0-9]{2})?$', value.get('9'))
-
- if not match:
- return None
-
- add_provision_activity_start_date(self, value.get('9'))
-
- return None
-
-
-@overdo.over('dissertation', '^508..')
-@utils.ignore_value
-def marc21_to_dissertation_field_508(self, key, value):
- """Extract dissertation note."""
- if not value.get('a'):
- return None
-
- dissertation = self.get('dissertation', {})
- dissertation['jury_note'] = value.get('a')
-
- self['dissertation'] = dissertation
-
- return None
-
-
-@overdo.over('usageAndAccessPolicy', '^540..')
-@utils.ignore_value
-def marc21_to_usage_and_access_policy(self, key, value):
- """Extract usage and access policy."""
- if not value.get('a'):
- return None
-
- return {'label': value.get('a'), 'license': 'License undefined'}
-
-
-@overdo.over('contribution', '^100..')
-@utils.ignore_value
-def marc21_to_contribution_field_100(self, key, value):
- """Extract contribution from field 100."""
- if not value.get('a'):
- return None
-
- contribution = self.get('contribution', [])
-
- data = {
- 'agent': {
- 'type': 'bf:Person',
- 'preferred_name': value.get('a')
- },
- 'role': ['cre']
- }
-
- # Affiliation
- if value.get('u'):
- data['affiliation'] = value.get('u')
-
- # Date of birth - date of death
- date_of_birth, date_of_death = overdo.extract_date(value.get('d'))
-
- if date_of_birth:
- data['agent']['date_of_birth'] = date_of_birth
-
- if date_of_death:
- data['agent']['date_of_death'] = date_of_death
-
- contribution.append(data)
- self['contribution'] = contribution
-
- return None
-
-
-@overdo.over('contribution', '^700..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_contribution_field_700(self, key, value):
- """Extract contribution from field 100."""
- if not value.get('a'):
- return None
-
- contribution = self.get('contribution', [])
-
- role = overdo.get_contributor_role(value.get('e'))
-
- if not role:
- raise Exception(f'No role found for contributor {value}')
-
- data = {
- 'agent': {
- 'type': 'bf:Person',
- 'preferred_name': value.get('a')
- },
- 'role': [role]
- }
-
- # Affiliation
- if value.get('u'):
- data['affiliation'] = value.get('u')
-
- # Date of birth - date of death
- date_of_birth, date_of_death = overdo.extract_date(value.get('d'))
-
- if date_of_birth:
- data['agent']['date_of_birth'] = date_of_birth
-
- if date_of_death:
- data['agent']['date_of_death'] = date_of_death
-
- contribution.append(data)
- self['contribution'] = contribution
-
- return None
-
-
-@overdo.over('contribution', '^710..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_contribution_field_710(self, key, value):
- """Extract contribution from field 710."""
- if not value.get('a'):
- return None
-
- contribution = self.get('contribution', [])
- contribution.append({
- 'agent': {
- 'type': 'bf:Organization',
- 'preferred_name': value.get('a')
- },
- 'role': ['ctb']
- })
- self['contribution'] = contribution
-
- return None
-
-
-@overdo.over('contribution', '^711..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_contribution_field_711(self, key, value):
- """Extract contribution from field 711."""
- if not value.get('a'):
- return None
-
- contribution = self.get('contribution', [])
-
- data = {
- 'agent': {
- 'type': 'bf:Meeting',
- 'preferred_name': value.get('a')
- },
- 'role': ['cre']
- }
-
- # Place
- if value.get('c'):
- data['agent']['place'] = value.get('c')
-
- # Date
- if value.get('d'):
- data['agent']['date'] = value.get('d')
-
- # Number
- if value.get('n'):
- data['agent']['number'] = value.get('n')
-
- contribution.append(data)
- self['contribution'] = contribution
-
- return None
-
-
-@overdo.over('customField1', '^918..')
-@utils.ignore_value
-def marc21_to_faculty_and_department(self, key, value):
- """Extract faculty and department for UNIFR."""
- record = overdo.blob_record
- org = record.get('980__', {}).get('b')
- if org and org == 'UNIFR':
- faculty = value.get('a')
- if faculty:
- self['customField1'] = [faculty]
- dep = value.get('c')
- if dep:
- self['customField2'] = [dep]
- return None
-
-
-@overdo.over('partOf', '^773..')
-@utils.for_each_value
-@utils.ignore_value
-def marc21_to_part_of(self, key, value):
- """Extract related document for record."""
- if not value.get('g'):
- return None
-
- # Split value for getting numbering values
- numbering = value.get('g').split('/')
-
- # Numbering year
- if not numbering[0]:
- return None
-
- data = {'numberingYear': numbering[0]}
-
- # Volume
- if len(numbering) > 1 and numbering[1]:
- data['numberingVolume'] = numbering[1]
-
- # Issue
- if len(numbering) > 2 and numbering[2]:
- data['numberingIssue'] = numbering[2]
-
- # Pages
- if len(numbering) > 3 and numbering[3] and numbering[3] != '-':
- data['numberingPages'] = numbering[3]
-
- document = {}
-
- # Title is found
- if value.get('t'):
- document['title'] = value.get('t')
-
- # Contribution
- if value.get('c'):
- contributors = []
- for contributor in value.get('c').split(';'):
- if contributor:
- contributors.append(contributor)
-
- if contributors:
- document['contribution'] = contributors
-
- record = overdo.blob_record
-
- # Publication based on document sub type
- sub_type = record.get('980__', {}).get('f')
- if value.get('d') or sub_type == 'ART_INBOOK':
- document['publication'] = {}
-
- if value.get('d'):
- document['publication']['statement'] = value.get('d')
-
- if sub_type == 'ART_INBOOK':
- document['publication']['startDate'] = numbering[0]
-
- # If no field 260$c or 269$c, store start date
- if (not record.get('260__', {}).get('c') and
- not record.get('269__', {}).get('c')):
- add_provision_activity_start_date(self, numbering[0])
-
- if document:
- data['document'] = document
-
- return data
-
-
-def add_provision_activity_start_date(data, date):
- """Add start date for provision activity.
-
- :param data: Data dictionary.
- :param date: Date to add.
- """
- provisition_activity = data.get('provisionActivity', [])
-
- def get_publication():
- """Get stored publication."""
- for key, item in enumerate(provisition_activity):
- if item['type'] == 'bf:Publication':
- return provisition_activity.pop(key)
-
- return {'type': 'bf:Publication', 'startDate': None}
-
- publication = get_publication()
-
- publication['startDate'] = date
-
- # Inject publiction into provision activity
- provisition_activity.append(publication)
-
- # Re-assign provisionActivity
- data['provisionActivity'] = provisition_activity
diff --git a/sonar/modules/documents/dojson/rerodoc/overdo.py b/sonar/modules/documents/dojson/rerodoc/overdo.py
deleted file mode 100644
index 3e635871b..000000000
--- a/sonar/modules/documents/dojson/rerodoc/overdo.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""Overdo specialized class for RERODOC DOJSON transformation."""
-
-from flask import current_app
-
-from sonar.modules.documents.dojson.overdo import Overdo as BaseOverdo
-from sonar.modules.organisations.api import OrganisationRecord
-
-
-class Overdo(BaseOverdo):
- """Overdo specialized class for RERODOC DOJSON transformation."""
-
- registererd_organisations = []
-
- @staticmethod
- def create_organisation(organisation_key):
- """Create organisation if not existing and return it.
-
- :param str organisation_key: Key (PID) of the organisation.
- """
- if not organisation_key:
- raise Exception("No key provided")
-
- # Get organisation record from database
- organisation = OrganisationRecord.get_record_by_pid(organisation_key)
-
- if not organisation:
- # Create organisation record
- organisation = OrganisationRecord.create(
- {
- "code": organisation_key,
- "name": organisation_key,
- "isShared": False,
- "isDedicated": False,
- },
- with_bucket=True,
- dbcommit=True,
- )
- organisation.reindex()
-
- def do(self, blob, ignore_missing=True, exception_handlers=None):
- """Do transformation."""
- result = super().do(blob, ignore_missing=ignore_missing, exception_handlers=exception_handlers)
-
- # Verify data integrity
- self.verify(result)
-
- # Add default license if not set.
- if not result.get("usageAndAccessPolicy"):
- default_license = "License undefined"
- if (
- result.get("organisation")
- and result["organisation"][0]["$ref"] == "https://sonar.ch/api/organisations/hepbejune"
- ):
- default_license = "CC BY-NC-SA"
-
- result["usageAndAccessPolicy"] = {"license": default_license}
-
- return result
-
- def get_contributor_role(self, role_700=None):
- """Return contributor role.
-
- :param role_700: String, role found in field 700$e
- :returns: String containing the mapped role or None
- """
- if role_700 in ["Dir.", "Codir."]:
- return "dgs"
-
- if role_700 == "Libr./Impr.":
- return "prt"
-
- if role_700 == "joint author":
- return "cre"
-
- if not role_700:
- doc_type = self.blob_record.get("980__", {}).get("a")
-
- if not doc_type:
- return None
-
- if doc_type in ["PREPRINT", "POSTPRINT", "DISSERTATION", "REPORT"]:
- return "cre"
-
- if doc_type in [
- "BOOK",
- "THESIS",
- "MAP",
- "JOURNAL",
- "PARTITION",
- "AUDIO",
- "IMAGE",
- ]:
- return "ctb"
-
- return None
-
- def verify(self, result):
- """Verify record data integrity after processing.
-
- :param result: Record data
- """
-
- def is_pa_mandatory():
- """Check if record types make provision activity mandatory."""
- document_type = result.get("documentType")
-
- if not document_type:
- return True
-
- return document_type not in [
- "coar:c_beb9",
- "coar:c_6501",
- "coar:c_998f",
- "coar:c_dcae04bc",
- "coar:c_3e5a",
- "coar:c_5794",
- "coar:c_6670",
- ]
-
- self.result_ok = True
-
- # Check if provision activity is set, but it's optional depending
- # on record types
- if "provisionActivity" not in result and is_pa_mandatory():
- self.result_ok = False
- current_app.logger.warning(f"No provision activity found in record {result}")
diff --git a/sonar/modules/documents/loaders/schemas/factory.py b/sonar/modules/documents/loaders/schemas/factory.py
index 738b33cab..8eff08f00 100644
--- a/sonar/modules/documents/loaders/schemas/factory.py
+++ b/sonar/modules/documents/loaders/schemas/factory.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -17,14 +17,12 @@
from .archive_ouverte_unige import ArchiveOuverteUnigeSchema
from .boris import BorisSchema
-from .rerodoc import RerodocSchema
class LoaderSchemaFactory:
"""Factory for creating a loader schema."""
schemas = {
- "rerodoc": RerodocSchema,
"archive_ouverte_unige": ArchiveOuverteUnigeSchema,
"boris": BorisSchema,
}
diff --git a/sonar/modules/documents/loaders/schemas/rerodoc.py b/sonar/modules/documents/loaders/schemas/rerodoc.py
deleted file mode 100644
index cf27d2266..000000000
--- a/sonar/modules/documents/loaders/schemas/rerodoc.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""RERODOC schema."""
-
-from invenio_records_rest.schemas.fields import SanitizedUnicode
-from marshmallow import fields, pre_dump
-
-from sonar.modules.documents.dojson.rerodoc.model import overdo
-
-from .marc21 import Marc21Schema
-
-
-class RerodocSchema(Marc21Schema):
- """RERODOC schema."""
-
- documentType = SanitizedUnicode()
- title = fields.List(fields.Dict())
- partOf = fields.List(fields.Dict())
- abstracts = fields.List(fields.Dict())
- contribution = fields.List(fields.Dict())
- organisation = fields.List(fields.Dict())
- language = fields.List(fields.Dict())
- copyrightDate = fields.List(fields.String())
- editionStatement = fields.Dict()
- provisionActivity = fields.List(fields.Dict())
- extent = SanitizedUnicode()
- otherMaterialCharacteristics = SanitizedUnicode()
- formats = fields.List(SanitizedUnicode())
- additionalMaterials = SanitizedUnicode()
- series = fields.List(fields.Dict())
- notes = fields.List(fields.String())
- identifiedBy = fields.List(fields.Dict())
- subjects = fields.List(fields.Dict())
- classification = fields.List(fields.Dict())
- collections = fields.List(fields.Dict())
- dissertation = fields.Dict()
- otherEdition = fields.List(fields.Dict())
- usageAndAccessPolicy = fields.Dict()
- files = fields.List(fields.Dict())
- subdivisions = fields.List(fields.Dict())
- customField1 = fields.List(fields.String())
- customField2 = fields.List(fields.String())
- customField3 = fields.List(fields.String())
-
- @pre_dump
- def process(self, obj, **kwargs):
- """All the process is done by overdo."""
- return overdo.do(obj)
diff --git a/sonar/modules/documents/minters.py b/sonar/modules/documents/minters.py
index 378def10e..07bcff134 100644
--- a/sonar/modules/documents/minters.py
+++ b/sonar/modules/documents/minters.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -19,7 +19,6 @@
from invenio_oaiserver.minters import oaiid_minter
from invenio_oaiserver.provider import OAIIDProvider
from invenio_pidstore.errors import PIDAlreadyExists, PIDDoesNotExistError
-from invenio_pidstore.models import PersistentIdentifier, PIDStatus
from sonar.modules.ark.api import Ark
@@ -48,26 +47,12 @@ def id_minter(record_uuid, data, provider, pid_key="pid", object_type="rec"):
def external_minters(record_uuid, data, pid_key="pid"):
"""External minters.
- RERO DOC and ARK.
+ ARK.
:param record_uuid: Record UUID.
:param data: Record data.
:param pid_key: PID key.
- :returns: Created PID object.
"""
- for identifier in data.get("identifiedBy", []):
- if identifier.get("source") == "RERO DOC":
- try:
- pid = PersistentIdentifier.create(
- "rerod",
- identifier["value"],
- object_type="rec",
- object_uuid=record_uuid,
- status=PIDStatus.REGISTERED,
- )
- pid.redirect(PersistentIdentifier.get("doc", data[pid_key]))
- except PIDAlreadyExists:
- pass
new_data = current_app.extensions.get("invenio-records").replace_refs(data.get("organisation", [{}])[0])
naan = new_data.get("arkNAAN")
diff --git a/sonar/theme/views.py b/sonar/theme/views.py
index db310bac7..4e6fcf38f 100644
--- a/sonar/theme/views.py
+++ b/sonar/theme/views.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -42,14 +42,12 @@
from flask_menu import current_menu
from invenio_jsonschemas import current_jsonschemas
from invenio_jsonschemas.errors import JSONSchemaNotFound
-from invenio_pidstore.models import PersistentIdentifier
from sonar.jsonschemas.factory import JSONSchemaFactory
from sonar.modules.collections.permissions import (
RecordPermission as CollectionPermission,
)
from sonar.modules.deposits.permissions import DepositPermission
-from sonar.modules.documents.api import DocumentRecord
from sonar.modules.documents.permissions import DocumentPermission
from sonar.modules.organisations.api import OrganisationSearch
from sonar.modules.organisations.permissions import OrganisationPermission
@@ -124,55 +122,6 @@ def error():
raise Exception("this is an error for test purposes")
-@blueprint.route("/rerodoc/")
-@blueprint.route("/rerodoc//files/")
-def rerodoc_redirection(pid, filename=None):
- """Redirection to document with identifier from RERODOC.
-
- :param pid: PID from RERODOC.
- :returns: A redirection to record's detail page or 404 if not found.
- """
- try:
- pid = PersistentIdentifier.get("rerod", pid)
- except Exception:
- abort(404)
-
- # Files URLs does not contains view
- if filename:
- return redirect(
- url_for(
- "invenio_records_ui.doc_files",
- pid_value=pid.get_redirect().pid_value,
- filename=filename,
- )
- )
- doc_pid = pid.get_redirect().pid_value
- doc = DocumentRecord.get_record_by_pid(doc_pid)
- if doc:
- doc = doc.resolve()
- orgs = doc.get("organisation", [])
- # In case of multiple organisations we redirect to the global view
- if len(orgs) == 1:
- org = orgs.pop()
- # Only for dedicated or shared
- if org.get("isDedicated") or org.get("isShared"):
- return redirect(
- url_for(
- "invenio_records_ui.doc",
- view=org.get("code"),
- pid_value=pid.get_redirect().pid_value,
- )
- )
- global_view = current_app.config.get("SONAR_APP_DEFAULT_ORGANISATION")
- return redirect(
- url_for(
- "invenio_records_ui.doc",
- view=global_view,
- pid_value=pid.get_redirect().pid_value,
- )
- )
-
-
@blueprint.route("/manage/")
@blueprint.route("/manage/")
@can_access_manage_view
diff --git a/tests/conftest.py b/tests/conftest.py
index 58fb43c89..b4a0acf82 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -433,7 +433,6 @@ def document_json(app, db, bucket_location, organisation):
return {
"identifiedBy": [
{"value": "oai:doc.rero.ch:20050302172954-WU", "type": "bf:Identifier"},
- {"value": "111111", "type": "bf:Local", "source": "RERO DOC"},
{"value": "R003415713", "type": "bf:Local", "source": "RERO"},
],
"language": [{"value": "eng", "type": "bf:Language"}],
diff --git a/tests/ui/conftest.py b/tests/ui/conftest.py
index 9d2c75082..4df80e3c4 100644
--- a/tests/ui/conftest.py
+++ b/tests/ui/conftest.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -23,7 +23,7 @@
@pytest.fixture(scope="module")
def harvested_record():
- """Return test XML output file path."""
+ """Return test XML record."""
with open(os.path.join(os.path.dirname(__file__), "data", "harvested_record.xml")) as file:
yield file.read()
diff --git a/tests/ui/data/harvested_record.xml b/tests/ui/data/harvested_record.xml
index b269ec2a0..b8a95c62b 100644
--- a/tests/ui/data/harvested_record.xml
+++ b/tests/ui/data/harvested_record.xml
@@ -1,128 +1,6 @@
-
-
- oai:doc.rero.ch:20120503160026-MV
- 2013-06-17T11:29:40Z
- postprint
- cdu1
- rero_explore
- article
- unifr
-
-
-
- 00000coc 2200000uu 4500
- 29085
- 20150420164351.0
-
- oai:doc.rero.ch:20120503160026-MV
- article
- rero_explore
- cdu1
- postprint
- unifr
-
-
- eng
-
-
- 1
-
-
- Betschart, Christof
-
-
- Was ist Lebenskraft?
- eng
- Edith Steins anthropologischer Beitrag in 'Psychische
- Kausalität' (Teil 2)
-
-
- What is Lifeforce? Edith Stein's Anthropological
- Contribution in 'Psychic Causality' (Part 2)
- eng
-
-
- Dieser Folge-Artikel im Edith Stein Jahrbuch 2010 fragt nach
- der Lebenskraft in Edith Steins Abhandlung „Psychische Kausalität“ (1918
- geschrieben, 1922 publiziert). Es geht besonders um den Wandel der Lebenskraft
- im Hinblick auf ihre Umsetzung im sinnlichen und geistigen Bereich, sowie ihre
- Erneuerung durch die Welt der Werte, durch die intersubjektiven Beziehungen und
- durch Gott. Ein eigener Abschnitt ist der Frage nach ganz aufgebrauchter
- Lebenskraft gewidmet. Im Ausblick wird die Lebenskraft im Sinne eines Potenzials
- zu sinnlicher und geistiger Betätigung interpretiert und eine Auseinandersetzung
- mit der Tiefenpsychologie Sigmund Freuds angestrebt.
- ger
-
-
- force vitale ; phénoménologie ; conscience phénoménologique
- ; réalité psychique ; idéalisme-réalisme ; dépression ; neurologie ; psychologie
- des profondeurs ; vécu religieux ; monde des valeurs ; Edith Stein ; Edmund
- Husserl
- fre
-
-
- Lebenskraft ; Betätigungspotenzial ; Phänomenologie ;
- Bewusstsein ; Psyche ; Idealismus-Realismus ; Depression ; Neurologie ;
- Tiefenpsychologie ; religiöses Erlebnis ; Wertewelt ; Burnout ; Edith Stein ;
- Edmund Husserl
- ger
-
-
- vital force ; life force ; phenomenology ; phenomenological
- conscience ; psyche ; idealism-realism ; depression ; neurology ; psychology of
- Sigmund Freud ; world of values ; burnout ; Edith Stein ; Edmund Husserl
- eng
-
-
- forza vitale ; fenomenologia ; coscienza fenomenologica ;
- psiche ; idealismo-realismo ; depressione ; neurologia ; psicologia freudiana ;
- vissuto religioso ; mondo dei valori ; burnout ; Edith Stein ; Edmund Husserl
- ita
-
-
- Edith Stein Jahrbuch
- 2010/16//33-64
- Echter
-
-
- Betschart_Jahrbuch_2010.pdf
- pdt/download
- 126302
-
- http://doc.rero.ch/lm.php?url=1000,43,2,20120503160026-MV/Betschart_Jahrbuch_2010.pdf
- 2012-05-03 16:03:50
- Texte intégral
-
-
- Betschart_Jahrbuch_2010.pdf
- application/pdf
- 126302
-
- http://doc.rero.ch/record/29085/files/Betschart_Jahrbuch_2010.pdf
- order:1
- Texte intégral
-
-
- Faculté de théologie
- Décanat, Av. de l'Europe 20, 1700 Fribourg
-
-
- Université de Fribourg
- Fribourg
- doc.support@rero.ch
-
-
- POSTPRINT
- UNIFR
- ART_JOURNAL
-
-
- 20120503160026-MV
-
-
-
+
+ 123456
+
+ Test record
+
diff --git a/tests/ui/documents/cli/test_documents_cli_ark.py b/tests/ui/documents/cli/test_documents_cli_ark.py
index abcb302c9..a7aed23aa 100644
--- a/tests/ui/documents/cli/test_documents_cli_ark.py
+++ b/tests/ui/documents/cli/test_documents_cli_ark.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-"""Test documents RERODOC cli commands."""
+"""Test ARK cli commands."""
from click.testing import CliRunner
diff --git a/tests/ui/documents/cli/test_documents_cli_rerodoc.py b/tests/ui/documents/cli/test_documents_cli_rerodoc.py
deleted file mode 100644
index d359e4345..000000000
--- a/tests/ui/documents/cli/test_documents_cli_rerodoc.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""Test documents RERODOC cli commands."""
-
-from click.testing import CliRunner
-
-import sonar.modules.documents.cli.rerodoc as cli
-
-
-def test_update_file_permissions(app, script_info, document_with_file):
- """Test update file permissions."""
- runner = CliRunner()
-
- # Not existing input file
- result = runner.invoke(
- cli.update_file_permissions,
- ["./tests/ui/documents/data/not_existing.csv", "-c", "1"],
- obj=script_info,
- )
- assert "Error: Invalid value for 'PERMISSIONS_FILE'" in result.output
-
- # Invalid input file
- result = runner.invoke(
- cli.update_file_permissions,
- ["./tests/ui/documents/data/invalid.csv", "-c", "1"],
- obj=script_info,
- )
- assert "CSV file seems to be not well formatted." in result.output
-
- # File cannot be parsed
- result = runner.invoke(
- cli.update_file_permissions,
- ["./tests/ui/documents/data/permissions_file.pdf", "-c", "1"],
- obj=script_info,
- )
- assert "An error occured during file process" in result.output
-
- # OK
- result = runner.invoke(
- cli.update_file_permissions,
- ["./tests/ui/documents/data/permissions_file.csv", "-c", "1"],
- obj=script_info,
- )
- assert "Process finished" in result.output
diff --git a/tests/ui/documents/dojson/rerodoc/test_rerodoc_model.py b/tests/ui/documents/dojson/rerodoc/test_rerodoc_model.py
deleted file mode 100644
index 50b6bcf15..000000000
--- a/tests/ui/documents/dojson/rerodoc/test_rerodoc_model.py
+++ /dev/null
@@ -1,2587 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""DOJSON module tests."""
-
-import pytest
-from dojson.contrib.marc21.utils import create_record
-
-from sonar.modules.documents.dojson.rerodoc.model import overdo
-
-
-def test_marc21_to_type_and_organisation(app, bucket_location):
- """Test type and organisation."""
-
- # Type only
- marc21xml = """
-
-
- BOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("documentType") == "coar:c_2f33"
- assert not data.get("organisation")
-
- # Type and organisation
- marc21xml = """
-
-
- BOOK
- TEST
-
-
- 1966
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("documentType") == "coar:c_2f33"
- assert data.get("organisation") == [{"$ref": "https://sonar.ch/api/organisations/test"}]
-
- # Type, subtype and organisation
- marc21xml = """
-
-
- POSTPRINT
- TEST
- ART_JOURNAL
-
-
- 1966
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("documentType") == "coar:c_6501"
- assert data.get("organisation") == [{"$ref": "https://sonar.ch/api/organisations/test"}]
-
- # Organisation only
- marc21xml = """
-
-
- TEST
-
-
- 1966
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("documentType")
- assert data.get("organisation") == [{"$ref": "https://sonar.ch/api/organisations/test"}]
-
- # Specific conversion for unisi
- marc21xml = """
-
-
- UNISI
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("documentType")
- assert data.get("organisation") == [{"$ref": "https://sonar.ch/api/organisations/usi"}]
-
- # Specific conversion for bpuge
- marc21xml = """
-
-
- BPUGE
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("documentType")
- assert data.get("organisation") == [{"$ref": "https://sonar.ch/api/organisations/vge"}]
- assert len(data["subdivisions"]) == 1
-
- # Specific conversion for mhnge
- marc21xml = """
-
-
- MHNGE
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("documentType")
- assert data.get("organisation") == [{"$ref": "https://sonar.ch/api/organisations/vge"}]
- assert len(data["subdivisions"]) == 1
-
-
-def test_marc21_to_title_245(app):
- """Test dojson marc21_to_title."""
-
- # One title with subtitle
- marc21xml = """
-
-
- Main title
- eng
- Subtitle
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [
- {
- "type": "bf:Title",
- "mainTitle": [{"value": "Main title", "language": "eng"}],
- "subtitle": [{"value": "Subtitle", "language": "eng"}],
- }
- ]
-
- # Multiple titles with subtitles
- marc21xml = """
-
-
- Main title
- eng
- Subtitle
-
-
- Titre principal
- fre
- Sous-titre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [
- {
- "type": "bf:Title",
- "mainTitle": [{"value": "Main title", "language": "eng"}],
- "subtitle": [{"value": "Subtitle", "language": "eng"}],
- },
- {
- "type": "bf:Title",
- "mainTitle": [{"value": "Titre principal", "language": "fre"}],
- "subtitle": [{"value": "Sous-titre", "language": "fre"}],
- },
- ]
-
- # One title without subtitle
- marc21xml = """
-
-
- Main title
- eng
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [{"type": "bf:Title", "mainTitle": [{"value": "Main title", "language": "eng"}]}]
-
- # No title
- marc21xml = """
-
-
- eng
- Subtitle
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("title")
-
- # No language
- marc21xml = """
-
-
- Main title
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [{"type": "bf:Title", "mainTitle": [{"value": "Main title", "language": "eng"}]}]
-
- # Multiple title with one without title
- marc21xml = """
-
-
- Main title
- eng
- Subtitle
-
-
- fre
- Sous-titre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [
- {
- "type": "bf:Title",
- "mainTitle": [{"value": "Main title", "language": "eng"}],
- "subtitle": [{"value": "Subtitle", "language": "eng"}],
- }
- ]
-
-
-def test_marc21_to_title_246(app):
- """Test dojson marc21_to_title."""
-
- # One title 246 without 245
- marc21xml = """
-
-
- Main title
- eng
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [{"type": "bf:Title", "mainTitle": [{"value": "Main title", "language": "eng"}]}]
-
- # One title 246 without $a and without 245
- marc21xml = """
-
-
- eng
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("title")
-
- # One title 246 without language and without 245
- marc21xml = """
-
-
- Main title
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [{"type": "bf:Title", "mainTitle": [{"value": "Main title", "language": "eng"}]}]
-
- # One title 246 with one 245 title
- marc21xml = """
-
-
- Main title 245
- eng
-
-
- Main title 246
- fre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [
- {
- "type": "bf:Title",
- "mainTitle": [
- {"value": "Main title 245", "language": "eng"},
- {"value": "Main title 246", "language": "fre"},
- ],
- }
- ]
-
- # One title 246 with multiple 245 title
- marc21xml = """
-
-
- Main title 245 1
- eng
-
-
- Main title 245 2
- eng
-
-
- Main title 246
- fre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("title") == [
- {
- "type": "bf:Title",
- "mainTitle": [{"value": "Main title 245 1", "language": "eng"}],
- },
- {
- "type": "bf:Title",
- "mainTitle": [
- {"value": "Main title 245 2", "language": "eng"},
- {"value": "Main title 246", "language": "fre"},
- ],
- },
- ]
-
-
-def test_marc21_to_language(app):
- """Test language transformation."""
- # OK
- marc21xml = """
-
-
- fre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("language") == [{"type": "bf:Language", "value": "fre"}]
-
- # Multiple $a
- marc21xml = """
-
-
- eng
- fre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("language") == [
- {"type": "bf:Language", "value": "eng"},
- {"type": "bf:Language", "value": "fre"},
- ]
-
- # Multiple 041
- marc21xml = """
-
-
- eng
-
-
- fre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("language") == [
- {"type": "bf:Language", "value": "eng"},
- {"type": "bf:Language", "value": "fre"},
- ]
-
- # Not $a
- marc21xml = """
-
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("language")
-
-
-def test_marc21_to_provision_activity_field_260(app):
- """Test provision activity with field 260."""
- # OK
- marc21xml = """
-
-
- Lausanne
- 1798-1799
- Bulletin officiel du Directoire,
- Lausanne :
- Henri Vincent
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [
- {
- "type": "bf:Publication",
- "startDate": "1798",
- "endDate": "1799",
- "statement": [
- {"label": [{"value": "Lausanne"}], "type": "bf:Place"},
- {
- "label": [{"value": "Bulletin officiel du Directoire"}],
- "type": "bf:Agent",
- },
- {"label": [{"value": "1798-1799"}], "type": "Date"},
- ],
- },
- {
- "type": "bf:Manufacture",
- "statement": [
- {"label": [{"value": "Lausanne"}], "type": "bf:Place"},
- {"label": [{"value": "Henri Vincent"}], "type": "bf:Agent"},
- ],
- },
- ]
-
- # No start date --> throw error
- marc21xml = """
-
-
- Lausanne
- Bulletin officiel du Directoire,
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("provisionActivity")
-
- # No provision activity and wrong type --> throw error
- marc21xml = """
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("provisionActivity")
-
- # No provision activity and right types --> ok provision activity is not
- # mandatory
- marc21xml = """
-
-
- POSTPRINT
- ART_JOURNAL
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("provisionActivity")
-
- # Without end date
- marc21xml = """
-
-
- Lausanne
- 1798
- Bulletin officiel du Directoire,
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity")[0]["startDate"] == "1798"
- assert "endDate" not in data.get("provisionActivity")[0]
-
- # Wrong start date
- marc21xml = """
-
-
- Lausanne
- [1798?]
- Bulletin officiel du Directoire,
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert "startDate" not in data.get("provisionActivity")[0]
-
- # Wrong end date
- marc21xml = """
-
-
- Lausanne
- 1798-
- Bulletin officiel du Directoire,
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert "endDate" not in data.get("provisionActivity")[0]
-
-
-def test_marc21_to_provision_activity_field_269(app):
- """Test provision activity with field 269."""
- # One field
- marc21xml = """
-
-
- 1966
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [{"startDate": "1966", "type": "bf:Publication"}]
-
- # One field with full date
- marc21xml = """
-
-
- 1966-01-01
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [{"startDate": "1966-01-01", "type": "bf:Publication"}]
-
- # Date does not match "YYYY" OR "YYYY-MM-DD"
- marc21xml = """
-
-
- 1966-1999
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("provisionActivity")
-
- # Multiple fields
- marc21xml = """
-
-
- 1966
-
-
- 2005
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [{"startDate": "2005", "type": "bf:Publication"}]
-
- # No field $c
- marc21xml = """
-
-
- 1966
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("provisionActivity")
-
-
-def test_marc21_to_provision_activity_all(app):
- """Test provision activity with both 260 and 269 fields."""
- marc21xml = """
-
-
- Lausanne
- 1798-1799
- Bulletin officiel du Directoire,
- Lausanne :
- Henri Vincent
-
-
- 1700
-
-
- Thèse 2
- 2020
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [
- {
- "type": "bf:Publication",
- "startDate": "1798",
- "endDate": "1799",
- "statement": [
- {"label": [{"value": "Lausanne"}], "type": "bf:Place"},
- {
- "label": [{"value": "Bulletin officiel du Directoire"}],
- "type": "bf:Agent",
- },
- {"label": [{"value": "1798-1799"}], "type": "Date"},
- ],
- },
- {
- "type": "bf:Manufacture",
- "statement": [
- {"label": [{"value": "Lausanne"}], "type": "bf:Place"},
- {"label": [{"value": "Henri Vincent"}], "type": "bf:Agent"},
- ],
- },
- ]
-
-
-def test_marc21_to_edition_statement(app):
- """Test edition statement dojson from field 250."""
- # OK
- marc21xml = """
-
-
- Reproduction numérique
- René Wetzel
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("editionStatement") == {
- "editionDesignation": {"value": "Reproduction numérique"},
- "responsibility": {"value": "René Wetzel"},
- }
-
- # Without field $a
- marc21xml = """
-
-
- René Wetzel
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("editionStatement")
-
- # Without field $b
- marc21xml = """
-
-
- Reproduction numérique
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("editionStatement")
-
- # Multiple --> keep only one value
- marc21xml = """
-
-
- Reproduction numérique 1
- John Doe
-
-
- Reproduction numérique 2
- René Wetzel
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("editionStatement") == {
- "editionDesignation": {"value": "Reproduction numérique 2"},
- "responsibility": {"value": "René Wetzel"},
- }
-
-
-# extent: 300$a (the first one if many)
-# otherMaterialCharacteristics: 300$b (the first one if many)
-# formats: 300 [$c repetitive]
-def test_marc21_to_description(app):
- """Test dojson extent, otherMaterialCharacteristics, formats."""
-
- marc21xml = """
-
-
- 116 p.
- ill.
- 22 cm
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("extent") == "116 p."
- assert data.get("otherMaterialCharacteristics") == "ill."
- assert data.get("formats") == ["22 cm"]
-
- marc21xml = """
-
-
- 116 p.
- ill.
- 22 cm
- 12 x 15
-
-
- 200 p.
- ill.
- 19 cm
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("extent") == "116 p."
- assert data.get("otherMaterialCharacteristics") == "ill."
- assert data.get("formats") == ["22 cm", "12 x 15"]
-
- marc21xml = """
-
-
- 116 p.
- ill.
- 22 cm
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("extent") == "116 p."
- assert data.get("otherMaterialCharacteristics") == "ill."
-
-
-# series.name: [490$a repetitive]
-# series.number: [490$v repetitive]
-def test_marc21_to_series(app):
- """Test dojson series."""
-
- marc21xml = """
-
-
- Collection One
- 5
-
-
- Collection Two
- 123
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("series") == [
- {"name": "Collection One", "number": "5"},
- {"name": "Collection Two", "number": "123"},
- ]
-
-
-def test_marc21_to_abstract(app):
- """Test dojson abstract."""
-
- # One abstract without language
- marc21xml = """
-
-
- Abstract
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("abstracts") == [{"value": "Abstract", "language": "eng"}]
-
- # One abstract with language
- marc21xml = """
-
-
- Résumé
- fre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("abstracts") == [{"value": "Résumé", "language": "fre"}]
-
- # Multiple abstracts
- marc21xml = """
-
-
- Abstract
- eng
-
-
- Résumé
- fre
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("abstracts") == [
- {"value": "Abstract", "language": "eng"},
- {"value": "Résumé", "language": "fre"},
- ]
-
- # Without abstract
- marc21xml = """
-
-
- eng
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("abstracts")
-
- # Special case with lang --> fr
- marc21xml = """
-
-
- Résumé
- fr
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("abstracts") == [{"value": "Résumé", "language": "fre"}]
-
-
-# notes: [500$a repetitive]
-def test_marc21_to_notes(app):
- """Test dojson notes."""
-
- marc21xml = """
-
-
- note 1
-
-
- note 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("notes") == ["note 1", "note 2"]
-
-
-# subjects: 6xx [duplicates could exist between several vocabularies,
-# if possible deduplicate]
-def test_marc21_to_subjects(app):
- """Test dojson subjects."""
-
- marc21xml = """
-
-
- eng
- subject 1 ; subject 2
-
-
- fre
- sujet 1 ; sujet 2
-
-
- rero
- subject 600 1 ; subject 600 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("subjects") == [
- {"label": {"language": "eng", "value": ["subject 1", "subject 2"]}},
- {"label": {"language": "fre", "value": ["sujet 1", "sujet 2"]}},
- {"label": {"value": ["subject 600 1", "subject 600 2"]}, "source": "rero"},
- ]
-
- # 600 without $a
- marc21xml = """
-
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("subjects")
-
- # 600 without source
- marc21xml = """
-
-
- subject 600 1 ; subject 600 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("subjects")
-
- # 695 without language
- marc21xml = """
-
-
- subject 1 ; subject 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("subjects")
-
-
-def test_marc21_to_identified_by_from_001(app):
- """Test identifiedBy from 001."""
-
- marc21xml = """
-
- 327171
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [{"type": "bf:Local", "source": "RERO DOC", "value": "327171"}]
-
- marc21xml = ""
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_from_020(app):
- """Test identifiedBy from 020."""
-
- marc21xml = """
-
-
- 9783796539138
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [{"type": "bf:Isbn", "value": "9783796539138"}]
-
- # Without code $a
- marc21xml = """
-
-
- 9783796539138
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_from_024(app):
- """Test identifiedBy from 024."""
-
- marc21xml = """
-
-
- urn:nbn:ch:rero-002-118667
- urn
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [{"type": "bf:Urn", "value": "urn:nbn:ch:rero-002-118667"}]
-
- # Without code $a
- marc21xml = """
-
-
- urn
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
- # Without code $2
- marc21xml = """
-
-
- urn:nbn:ch:rero-002-118667
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
- # $2 is a falsy value
- marc21xml = """
-
-
- urn:nbn:ch:rero-002-118667
- falsy_value
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
- # Without ind1 == 7
- marc21xml = """
-
-
- urn:nbn:ch:rero-002-118667
- falsy_value
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_from_027(app):
- """Test identifiedBy from 027."""
-
- marc21xml = """
-
-
- 9789027223951
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [{"type": "bf:Strn", "value": "9789027223951"}]
-
- # Without code $a
- marc21xml = """
-
-
- 9789027223951
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_from_035(app):
- """Test identifiedBy from 035."""
-
- marc21xml = """
-
-
- R008966083
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [{"type": "bf:Local", "source": "RERO", "value": "R008966083"}]
-
- # Without code $a
- marc21xml = """
-
-
- R008966083
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_from_037(app):
- """Test identifiedBy from 037."""
-
- marc21xml = """
-
-
-
- swissbib.ch:(NATIONALLICENCE)springer-10.1007/s00209-014-1344-0
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [
- {
- "type": "bf:Local",
- "source": "Swissbib",
- "value": "(NATIONALLICENCE)springer-10.1007/s00209-014-1344-0",
- }
- ]
-
- # Without code $a
- marc21xml = """
-
-
-
- swissbib.ch:(NATIONALLICENCE)springer-10.1007/s00209-014-1344-0
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_from_088(app):
- """Test identifiedBy from 088."""
-
- marc21xml = """
-
-
- 25
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [{"type": "bf:ReportNumber", "value": "25"}]
-
- # Without code $a
- marc21xml = """
-
-
- 25
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_from_091(app):
- """Test identifiedBy from 091."""
-
- marc21xml = """
-
-
- 24638240
- pmid
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [{"type": "bf:Local", "value": "24638240", "source": "PMID"}]
-
- # Without code $a
- marc21xml = """
-
-
- pmid
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
- # Without code $b
- marc21xml = """
-
-
- 24638240
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
- # Invalid code $b
- marc21xml = """
-
-
- 24638240
- fake
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("identifiedBy")
-
-
-def test_marc21_to_identified_by_full(app):
- """Test full identified by."""
- marc21xml = """
-
- 327171
-
- 9783796539138
-
-
- urn:nbn:ch:rero-002-118667
- urn
-
-
- 9789027223951
-
-
- R008966083
-
-
-
- swissbib.ch:(NATIONALLICENCE)springer-10.1007/s00209-014-1344-0
-
-
-
- 25
-
-
- 24638240
- pmid
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("identifiedBy") == [
- {"type": "bf:Local", "source": "RERO DOC", "value": "327171"},
- {"type": "bf:Isbn", "value": "9783796539138"},
- {"type": "bf:Urn", "value": "urn:nbn:ch:rero-002-118667"},
- {"type": "bf:Strn", "value": "9789027223951"},
- {"type": "bf:Local", "source": "RERO", "value": "R008966083"},
- {
- "type": "bf:Local",
- "source": "Swissbib",
- "value": "(NATIONALLICENCE)springer-10.1007/s00209-014-1344-0",
- },
- {"type": "bf:ReportNumber", "value": "25"},
- {"type": "bf:Local", "value": "24638240", "source": "PMID"},
- ]
-
-
-def test_marc21_to_files(app):
- """Test getting files from field 856."""
- # Only one file
- marc21xml = """
-
-
- file.pdf
- application/pdf
- 1467377
-
- http://some.url/file.pdf
-
- order:1
- Dépliant de l'exposition
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert len(data.get("files")) == 1
- assert data.get("files")[0]["key"] == "file.pdf"
- assert data.get("files")[0]["url"] == "http://some.url/file.pdf"
- assert data.get("files")[0]["label"] == "Dépliant de l'exposition"
- assert data.get("files")[0]["order"] == 1
-
- # Not key
- marc21xml = """
-
-
- application/pdf
- 1467377
-
- http://some.url/file.pdf
-
- order:1
- Dépliant de l'exposition
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("files")
-
- # Not URL
- marc21xml = """
-
-
- file.pdf
- application/pdf
- 1467377
- order:1
- Dépliant de l'exposition
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("files")
-
- # Wrong mime type
- marc21xml = """
-
- 327171
-
- file.pdf
- pdt/download
- 1467377
-
- http://some.url/file.pdf
-
- order:1
- Dépliant de l'exposition
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("files")
-
-
-def test_marc21_to_other_edition(app):
- """Test other edition extraction."""
- # One other edition
- marc21xml = """
-
-
- http://domain.com/url
- version publiée
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("otherEdition") == [
- {
- "document": {"electronicLocator": "http://domain.com/url"},
- "publicNote": "version publiée",
- }
- ]
-
- # Multiple other editions
- marc21xml = """
-
-
- http://domain.com/url
- version publiée
-
-
- http://domain.com/url-2
- version publiée
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("otherEdition") == [
- {
- "document": {"electronicLocator": "http://domain.com/url"},
- "publicNote": "version publiée",
- },
- {
- "document": {"electronicLocator": "http://domain.com/url-2"},
- "publicNote": "version publiée",
- },
- ]
-
- # No electronic location
- marc21xml = """
-
-
- version publiée
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("otherEdition")
-
- # No public note
- marc21xml = """
-
-
- http://domain.com/url
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("otherEdition")
-
- # Incorrect DOIs - they do get collected in `otherEdition`
- # instead of `identifiedBy`
- marc21xml = """
-
-
- http://dx.doi.org/10.1130%2F0091-7613(2002)030%3C0655:CWCIAP%3E2.0.CO%3B2
- version publiée
-
-
- http://dx.doi.org/0.1021/jp0558775
- version publiée
-
-
- http://dx.doi.org/1017/S0031182010000296
- version publiée
-
-
- http://dx.doi.org/1039/B926873A
- version publiée
-
-
- http://dx.doi.org/0.1016/j.str.2012.09.019
- version publiée
-
-
- https://doi.org/10.1111%2Fj.1467-9280.2009.02364.x
- version publiée
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("otherEdition") == [
- {
- "document": {
- "electronicLocator": "http://dx.doi.org/10.1130%2F0091-7613(2002)030%3C0655:CWCIAP%3E2.0.CO%3B2"
- },
- "publicNote": "version publiée",
- },
- {
- "document": {"electronicLocator": "http://dx.doi.org/0.1021/jp0558775"},
- "publicNote": "version publiée",
- },
- {
- "document": {"electronicLocator": "http://dx.doi.org/1017/S0031182010000296"},
- "publicNote": "version publiée",
- },
- {
- "document": {"electronicLocator": "http://dx.doi.org/1039/B926873A"},
- "publicNote": "version publiée",
- },
- {
- "document": {"electronicLocator": "http://dx.doi.org/0.1016/j.str.2012.09.019"},
- "publicNote": "version publiée",
- },
- {
- "document": {"electronicLocator": "https://doi.org/10.1111%2Fj.1467-9280.2009.02364.x"},
- "publicNote": "version publiée",
- },
- ]
- assert not data.get("identifiedBy")
-
- # Well-formed DOIs - they get collected in `identifiedBy`
- # instead of`otherEdition`
- marc21xml = """
-
-
- http://dx.doi.org/10.1002/1521-3773(20020104)41:1
- version publiée
-
-
- 10.1016/j.apergo.2008.03.002
- version publiée
-
-
- : https://doi.pangaea.de/10.1594/PANGAEA.914883
- version publiée
-
-
- https://www.brepolsonline.net/doi/abs/10.1484/J.BPM.5.110808
- version publiée
-
-
- https://doi.org710.35662/unine-thesis-2747
- version publiée
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("otherEdition")
- assert data.get("identifiedBy") == [
- {"type": "bf:Doi", "value": "10.1002/1521-3773(20020104)41:1"},
- {"type": "bf:Doi", "value": "10.1016/j.apergo.2008.03.002"},
- {"type": "bf:Doi", "value": "10.1594/PANGAEA.914883"},
- {"type": "bf:Doi", "value": "10.1484/J.BPM.5.110808"},
- {"type": "bf:Doi", "value": "10.35662/unine-thesis-2747"},
- ]
-
-
-def test_marc21_to_specific_collection(app, bucket_location):
- """Test extracting collection from file 982."""
- # No code a
- marc21xml = """
-
-
- Treize étoiles
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("collections")
-
- # Not field 982
- marc21xml = """
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("collections")
-
- # No organisation
- marc21xml = """
-
-
- Treize étoiles
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("collections")
-
- # OK
- marc21xml = """
-
-
- test-org
-
-
- Treize étoiles
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data["collections"]
-
- # Multiple collections
- marc21xml = """
-
-
- test-org
-
-
- Collection 1
-
-
- Collection 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert len(data["collections"]) == 2
-
-
-def test_marc21_to_classification_from_field_080(app):
- """Test classification from field 080."""
- # OK
- marc21xml = """
-
-
- 82
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("classification") == [{"type": "bf:ClassificationUdc", "classificationPortion": "82"}]
-
- # Not $a record
- marc21xml = """
-
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("classification")
-
-
-def test_marc21_to_classification_from_field_084(app):
- """Test classification from field 084."""
- # OK
- marc21xml = """
-
-
- 610
- ddc
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("classification") == [{"type": "bf:ClassificationDdc", "classificationPortion": "610"}]
-
- # Not $a record
- marc21xml = """
-
-
- ddc
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("classification")
-
- # Not $2 record
- marc21xml = """
-
-
- 610
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("classification")
-
-
-def test_marc21_to_classification_from_all(app):
- """Test classification from all field."""
- marc21xml = """
-
-
- 82
-
-
- 610
- ddc
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("classification") == [
- {"type": "bf:ClassificationUdc", "classificationPortion": "82"},
- {"type": "bf:ClassificationDdc", "classificationPortion": "610"},
- ]
-
-
-def test_marc21_to_content_note(app):
- """Test extracting content notes from field 505."""
- # OK
- marc21xml = """
-
-
- La comtesse de Mortane
-
-
- Voyage de campagne
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contentNote") == ["La comtesse de Mortane", "Voyage de campagne"]
-
- # No field $a
- marc21xml = """
-
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("contentNote")
-
-
-def test_marc21_to_dissertation_field_502(app):
- """Test extracting dissertation degree from field 502."""
- # OK
- marc21xml = """
-
-
- Thèse de doctorat
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("dissertation") == {"degree": "Thèse de doctorat"}
-
- # thesis note decomposition
- marc21xml = """
-
- Thèse de doctorat : Université de Fribourg, 2010 ; Nr. 1671
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("dissertation") == {
- "degree": "Thèse de doctorat",
- "grantingInstitution": "Université de Fribourg",
- "date": "2010",
- }
-
- # Multiple --> keep always last value
- marc21xml = """
-
-
- Thèse de doctorat
-
-
- Last degree
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("dissertation") == {"degree": "Last degree"}
-
- # Without $a
- marc21xml = """
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("dissertation")
-
-
-def test_marc21_to_dissertation_field_508(app):
- """Test extracting dissertation notes from field 508."""
- # OK
- marc21xml = """
-
-
- Magna cum laude
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("dissertation") == {"jury_note": "Magna cum laude"}
-
- # Multiple
- marc21xml = """
-
-
- Note 1
-
-
- Note 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("dissertation") == {"jury_note": "Note 2"}
-
- # Without $a
- marc21xml = """
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("dissertation")
-
-
-def test_marc21_to_dissertation_all(app):
- """Test extracting dissertation notes and degree."""
- # OK
- marc21xml = """
-
-
- Thèse de doctorat
-
-
- Magna cum laude
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("dissertation") == {
- "degree": "Thèse de doctorat",
- "jury_note": "Magna cum laude",
- }
-
-
-def test_marc21_to_usage_and_access_policy(app):
- """Test extracting usage and access policy."""
- # OK
- marc21xml = """
-
-
- Springer-Verlag Berlin
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("usageAndAccessPolicy") == {
- "label": "Springer-Verlag Berlin",
- "license": "License undefined",
- }
-
- # Multiple
- marc21xml = """
-
-
- Usage 1
-
-
- Usage 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("usageAndAccessPolicy") == {
- "label": "Usage 2",
- "license": "License undefined",
- }
-
- # Without $a
- marc21xml = """
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("usageAndAccessPolicy") == {"license": "License undefined"}
-
- # Without 540
- marc21xml = """
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("usageAndAccessPolicy") == {"license": "License undefined"}
-
-
-def test_marc21_to_contribution_field_100(app):
- """Test extracting contribution from field 100."""
- # OK
- marc21xml = """
-
-
- Romagnani, Andrea
- 1980-2010
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Person",
- "preferred_name": "Romagnani, Andrea",
- "date_of_birth": "1980",
- "date_of_death": "2010",
- },
- "role": ["cre"],
- "affiliation": "University of Bern, Switzerland",
- }
- ]
-
- # Not $a
- marc21xml = """
-
-
- 1980-2010
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("contribution")
-
- # Date does not match
- marc21xml = """
-
-
- Romagnani, Andrea
- zzzz
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- with pytest.raises(Exception) as exception:
- data = overdo.do(marc21json)
- assert str(exception.value) == 'Date "zzzz" is not recognized'
-
- # Only birth date
- marc21xml = """
-
-
- Romagnani, Andrea
- 1980-
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Person",
- "preferred_name": "Romagnani, Andrea",
- "date_of_birth": "1980",
- },
- "role": ["cre"],
- "affiliation": "University of Bern, Switzerland",
- }
- ]
-
- # Only birth date, variant 2
- marc21xml = """
-
-
- Romagnani, Andrea
- 1980
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Person",
- "preferred_name": "Romagnani, Andrea",
- "date_of_birth": "1980",
- },
- "role": ["cre"],
- "affiliation": "University of Bern, Switzerland",
- }
- ]
-
- # Only birth date, variant 3
- marc21xml = """
-
-
- Romagnani, Andrea
- 1980-04-04
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Person",
- "preferred_name": "Romagnani, Andrea",
- "date_of_birth": "1980-04-04",
- },
- "role": ["cre"],
- "affiliation": "University of Bern, Switzerland",
- }
- ]
-
-
-def test_marc21_to_contribution_field_700(app):
- """Test extracting contribution from field 700."""
- # OK
- marc21xml = """
-
-
- Piguet, Etienne
- 1980-2010
- Dir.
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Person",
- "preferred_name": "Piguet, Etienne",
- "date_of_birth": "1980",
- "date_of_death": "2010",
- },
- "role": ["dgs"],
- "affiliation": "University of Bern, Switzerland",
- }
- ]
-
- # Not $a
- marc21xml = """
-
-
- 1980-2010
- Dir.
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("contribution")
-
- # Only birth date
- marc21xml = """
-
-
- Piguet, Etienne
- 1980-
- Dir.
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Person",
- "preferred_name": "Piguet, Etienne",
- "date_of_birth": "1980",
- },
- "role": ["dgs"],
- "affiliation": "University of Bern, Switzerland",
- }
- ]
-
- # Role from field 980, but not existing
- marc21xml = """
-
-
- Piguet, Etienne
- 1980-
- University of Bern, Switzerland
-
-
- """
- marc21json = create_record(marc21xml)
- with pytest.raises(Exception) as exception:
- data = overdo.do(marc21json)
- assert str(exception.value).startswith("No role found for contributor")
-
- # Role from field 980, but 980 is not mapped
- marc21xml = """
-
-
- Piguet, Etienne
-
-
- NOT EXISTING
-
-
- """
- marc21json = create_record(marc21xml)
- with pytest.raises(Exception) as exception:
- data = overdo.do(marc21json)
- assert str(exception.value).startswith("No role found for contributor")
-
- # Role from field 980, but $a is not existing
- marc21xml = """
-
-
- Piguet, Etienne
-
-
-
-
- """
- marc21json = create_record(marc21xml)
- with pytest.raises(Exception) as exception:
- data = overdo.do(marc21json)
- assert str(exception.value).startswith("No role found for contributor")
-
- # Role from field 980, found 'cre'
- marc21xml = """
-
-
- Piguet, Etienne
-
-
- POSTPRINT
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution")[0]["role"] == ["cre"]
-
- # Role from field 980, found 'ctb'
- marc21xml = """
-
-
- Piguet, Etienne
-
-
- BOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution")[0]["role"] == ["ctb"]
-
- # Role 'prt' found
- marc21xml = """
-
-
- Piguet, Etienne
- Libr./Impr.
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution")[0]["role"] == ["prt"]
-
- # Role for joint author
- marc21xml = """
-
-
- Piguet, Etienne
- joint author
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution")[0]["role"] == ["cre"]
-
-
-def test_marc21_to_contribution_field_710(app):
- """Test extracting contribution from field 710."""
- # OK
- marc21xml = """
-
-
- Musée d'art et d'histoire
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Organization",
- "preferred_name": "Musée d'art et d'histoire",
- },
- "role": ["ctb"],
- }
- ]
-
- # No $a
- marc21xml = """
-
-
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("contribution")
-
-
-def test_marc21_to_contribution_field_711(app):
- """Test extracting contribution from field 711."""
- # OK
- marc21xml = """
-
-
- Theologisches Forum Christentum
- Stuttgart-Hohenheim
- 2004
- 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("contribution") == [
- {
- "agent": {
- "type": "bf:Meeting",
- "preferred_name": "Theologisches Forum Christentum",
- "place": "Stuttgart-Hohenheim",
- "date": "2004",
- "number": "2",
- },
- "role": ["cre"],
- }
- ]
-
- # Not $a
- marc21xml = """
-
-
- Stuttgart-Hohenheim
- 2004
- 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("contribution")
-
-
-def test_marc21_to_part_of(app):
- """Test extracting is part of from field 773."""
- # With sub type of ART INBOOK
- marc21xml = """
-
-
- Belser, Eva Maria
- Mehr oder weniger Staat?
- 2015///
- Stämpfli Verlag, Bern
-
-
- ART_INBOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("partOf") == [
- {
- "numberingYear": "2015",
- "document": {
- "title": "Mehr oder weniger Staat?",
- "contribution": ["Belser, Eva Maria"],
- "publication": {
- "statement": "Stämpfli Verlag, Bern",
- "startDate": "2015",
- },
- },
- }
- ]
- assert data.get("provisionActivity") == [{"startDate": "2015", "type": "bf:Publication"}]
-
- # With sub type is not ART INBOOK
- marc21xml = """
-
-
- Optics Express
- 2020/28/6/8200-8210
- Optical Society of America
-
-
- ART_JOURNAL
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("partOf") == [
- {
- "numberingYear": "2020",
- "numberingVolume": "28",
- "numberingIssue": "6",
- "numberingPages": "8200-8210",
- "document": {
- "title": "Optics Express",
- "publication": {"statement": "Optical Society of America"},
- },
- }
- ]
- assert data.get("provisionActivity") == [{"startDate": "2020", "type": "bf:Publication"}]
-
- # Without $g
- marc21xml = """
-
-
- Belser, Eva Maria
- Mehr oder weniger Staat?
- Stämpfli Verlag, Bern
-
-
- ART_INBOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("partOf")
- assert not data.get("provisionActivity")
-
- # Without empty numbering year
- marc21xml = """
-
-
- ///-
- Belser, Eva Maria
- Mehr oder weniger Staat?
- Stämpfli Verlag, Bern
-
-
- ART_INBOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("partOf")
- assert not data.get("provisionActivity")
-
- # Without numbering year
- marc21xml = """
-
-
- Belser, Eva Maria
-
- Mehr oder weniger Staat?
- Stämpfli Verlag, Bern
-
-
- ART_INBOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("partOf")
- assert not data.get("provisionActivity")
-
- # Without title
- marc21xml = """
-
-
- Belser, Eva Maria
- 2015///
- Stämpfli Verlag, Bern
-
-
- ART_INBOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("partOf") == [
- {
- "numberingYear": "2015",
- "document": {
- "contribution": ["Belser, Eva Maria"],
- "publication": {
- "startDate": "2015",
- "statement": "Stämpfli Verlag, Bern",
- },
- },
- }
- ]
- assert data.get("provisionActivity") == [{"startDate": "2015", "type": "bf:Publication"}]
-
- # Without $c
- marc21xml = """
-
-
- Mehr oder weniger Staat?
- 2015///
- Stämpfli Verlag, Bern
-
-
- ART_INBOOK
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("partOf") == [
- {
- "numberingYear": "2015",
- "document": {
- "title": "Mehr oder weniger Staat?",
- "publication": {
- "statement": "Stämpfli Verlag, Bern",
- "startDate": "2015",
- },
- },
- }
- ]
- assert data.get("provisionActivity") == [{"startDate": "2015", "type": "bf:Publication"}]
-
- # Without document
- marc21xml = """
-
-
- 2015///
-
-
- ART_JOURNAL
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("partOf") == [{"numberingYear": "2015"}]
- assert data.get("provisionActivity") == [{"startDate": "2015", "type": "bf:Publication"}]
-
-
-def test_start_date_priorities(app):
- """Test start date priorities for provision activity."""
- # Four potential start dates.
- marc21xml = """
-
-
- Lausanne
- 1798-1799
- Bulletin officiel du Directoire,
-
-
- 2015///
-
-
- 1966
-
-
- Thèse 1
- 2020
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data["provisionActivity"][0]["startDate"] == "1798"
-
- # Start dates from 269$c must be taken.
- marc21xml = """
-
-
- 1966
-
-
- Thèse 1
- 2020
-
-
- 2015///
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data["provisionActivity"][0]["startDate"] == "1966"
-
- # Start dates from 773$g must be taken.
- marc21xml = """
-
-
- Thèse 1
- 2020
-
-
- 2015///
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data["provisionActivity"][0]["startDate"] == "2015"
-
- # Only 502$9
- marc21xml = """
-
-
- Thèse 1
- 2020
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data["provisionActivity"][0]["startDate"] == "2020"
-
-
-def test_marc21_to_provision_activity_field_502(app):
- """Test provision activity with field 502."""
- # One field
- marc21xml = """
-
-
- Thèse 1
- 2020
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [{"startDate": "2020", "type": "bf:Publication"}]
-
- # One field with full date
- marc21xml = """
-
-
- Thèse 1
- 2020-09-09
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [{"startDate": "2020-09-09", "type": "bf:Publication"}]
-
- # Date does not match "YYYY" OR "YYYY-MM-DD"
- marc21xml = """
-
-
- Thèse 1
- 2010-2020
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("provisionActivity")
-
- # Multiple fields
- marc21xml = """
-
-
- Thèse 1
- 2010
-
-
- Thèse 2
- 2020
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert data.get("provisionActivity") == [{"startDate": "2020", "type": "bf:Publication"}]
-
- # No field $9
- marc21xml = """
-
-
- Thèse 2
-
-
- """
- marc21json = create_record(marc21xml)
- data = overdo.do(marc21json)
- assert not data.get("provisionActivity")
diff --git a/tests/ui/documents/dojson/rerodoc/test_rerodoc_overdo.py b/tests/ui/documents/dojson/rerodoc/test_rerodoc_overdo.py
deleted file mode 100644
index 314530b45..000000000
--- a/tests/ui/documents/dojson/rerodoc/test_rerodoc_overdo.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""Test RERODOC overdo."""
-
-import pytest
-
-from sonar.modules.documents.dojson.rerodoc.overdo import Overdo
-from sonar.modules.organisations.api import OrganisationRecord
-
-
-def test_create_organisation(app, bucket_location):
- """Test create organisation."""
- Overdo.create_organisation("test")
-
- # Organisation creation OK
- organisation = OrganisationRecord.get_record_by_pid("test")
- assert organisation
- assert organisation["pid"] == "test"
-
- # No organisation key provided
- with pytest.raises(Exception) as exception:
- Overdo.create_organisation(None)
- assert str(exception.value) == "No key provided"
-
-
-def test_extract_date():
- """Test date extraction."""
- # No date provided
- assert Overdo.extract_date(None) == (None, None)
-
- # Full first date
- assert Overdo.extract_date("1980-01-01") == ("1980-01-01", None)
-
- # Full first date, variant
- assert Overdo.extract_date("01-01-1980") == ("01-01-1980", None)
-
- # First year only
- assert Overdo.extract_date("1980") == ("1980", None)
-
- # First year only, variant with dash
- assert Overdo.extract_date("1980-") == ("1980", None)
-
- # Start and end year
- assert Overdo.extract_date("1980-2010") == ("1980", "2010")
-
- # Error on date format
- with pytest.raises(Exception) as exception:
- assert Overdo.extract_date("AAAA")
- assert str(exception.value) == 'Date "AAAA" is not recognized'
-
-
-def test_get_contributor_role():
- """Test contributor role mapping."""
- overdo = Overdo()
- overdo.blob_record = {}
-
- # dgs
- assert overdo.get_contributor_role("Dir.") == "dgs"
-
- # prt
- assert overdo.get_contributor_role("Libr./Impr.") == "prt"
-
- # joint author
- assert overdo.get_contributor_role("joint author") == "cre"
-
- # with role but no mapping found
- assert not overdo.get_contributor_role("not-mapped")
-
- # no role, no doc type
- assert not overdo.get_contributor_role(None)
-
- # no role, doc type mapped to 'cre'
- overdo.blob_record = {"980__": {"a": "PREPRINT"}}
- assert overdo.get_contributor_role(None) == "cre"
-
- # no role, doc type mapped to 'ctb'
- overdo.blob_record = {"980__": {"a": "BOOK"}}
- assert overdo.get_contributor_role(None) == "ctb"
-
-
-def test_verify(app):
- """Test verify result."""
- overdo = Overdo()
- overdo.blob_record = {}
-
- # No provision activity and no type
- overdo.verify({})
- assert not overdo.result_ok
-
- # No provision activity and type make it mandatory
- overdo.verify({"documentType": "coar:c_816b"})
- assert not overdo.result_ok
-
- # Provision activity is present in result
- overdo.blob_record = {}
- overdo.verify({"provisionActivity": {}})
- assert overdo.result_ok
-
- # No provision activity and provision activity is optional
- overdo.verify({"documentType": "coar:c_beb9"})
- assert overdo.result_ok
diff --git a/tests/ui/documents/test_documents_api.py b/tests/ui/documents/test_documents_api.py
index 1bb351c74..310df5d07 100644
--- a/tests/ui/documents/test_documents_api.py
+++ b/tests/ui/documents/test_documents_api.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -28,26 +28,12 @@
def test_get_record_by_identifier(app, db, document):
"""Test getting record by its identifier."""
# Record found
- record = DocumentRecord.get_record_by_identifier(
- [
- {"value": "111111", "type": "bf:Local", "source": "RERO DOC"},
- {"value": "R003415713", "type": "bf:Local", "source": "RERO"},
- ]
- )
+ record = DocumentRecord.get_record_by_identifier([{"value": "R003415713", "type": "bf:Local", "source": "RERO"}])
assert record["pid"] == document["pid"]
# Not matching complete identifier
record = DocumentRecord.get_record_by_identifier(
- [
- {"value": "111111", "type": "bf:Local", "source": "Unmatching"},
- {"value": "R003415713", "type": "bf:Local", "source": "RERO"},
- ]
- )
- assert not record
-
- # Mixing identifier data
- record = DocumentRecord.get_record_by_identifier(
- [{"value": "R003415713", "type": "bf:Local", "source": "RERO DOC"}]
+ [{"value": "R003415713", "type": "bf:Local", "source": "Unmatching"}]
)
assert not record
diff --git a/tests/ui/documents/test_documents_receivers.py b/tests/ui/documents/test_documents_receivers.py
index fe0bec72b..a04b90ca2 100644
--- a/tests/ui/documents/test_documents_receivers.py
+++ b/tests/ui/documents/test_documents_receivers.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -29,17 +29,17 @@
def test_transform_harvested_records(app, bucket_location, capsys, harvested_record):
"""Test harvested record transformation."""
- transform_harvested_records(None, [harvested_record], name="rerodoc", max="1")
+ transform_harvested_records(None, [harvested_record], name="archive_ouverte_unige", max="1")
captured = capsys.readouterr()
assert captured.out.find("1 records harvested") != -1
# Max set to 0 --> import all
- transform_harvested_records(None, [harvested_record], name="rerodoc", max="0")
+ transform_harvested_records(None, [harvested_record], name="archive_ouverte_unige", max="0")
captured = capsys.readouterr()
assert captured.out.find("1 records harvested") != -1
# Not an import
- transform_harvested_records(None, [harvested_record], name="rerodoc", max="1", action="not-existing")
+ transform_harvested_records(None, [harvested_record], name="archive_ouverte_unige", max="1", action="not-existing")
captured = capsys.readouterr()
assert captured.out == ""
@@ -61,10 +61,10 @@ def test_export_json(app, bucket_location, monkeypatch, harvested_record):
data_directory = join(app.instance_path, "data")
- export_json(None, [harvested_record], clean_file=False, name="rerodoc", action="not-existing")
+ export_json(None, [harvested_record], clean_file=False, name="archive_ouverte_unige", action="not-existing")
assert not exists(data_directory)
- export_json(None, [harvested_record], clean_file=False, name="rerodoc", action="export")
+ export_json(None, [harvested_record], clean_file=False, name="archive_ouverte_unige", action="export")
assert len(listdir(data_directory)) == 1
shutil.rmtree(data_directory)
diff --git a/tests/ui/test_views.py b/tests/ui/test_views.py
index d4187aad0..c3c4f0b21 100644
--- a/tests/ui/test_views.py
+++ b/tests/ui/test_views.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -318,45 +318,6 @@ def test_record_image_url(client):
assert record_image_url(record, "org", "test2.jpg") == "/organisations/1/files/test2.jpg"
-def test_rerodoc_redirection(client, app, document, organisation):
- """Test redirection with RERODOC identifier."""
- global_view = app.config.get("SONAR_APP_DEFAULT_ORGANISATION")
- # does not exist
- res = client.get(url_for("sonar.rerodoc_redirection", pid="NOT-EXISTING"))
- assert res.status_code == 404
-
- # Files
- res = client.get(url_for("sonar.rerodoc_redirection", pid="111111", filename="test.pdf"))
- assert res.status_code == 302
- assert res.location.find(f"/documents/{document['pid']}/files/test.pdf") != -1
-
- def changeorg(key, value):
- organisation[key] = value
- organisation.commit()
- organisation.dbcommit()
- # Note: this is not needed as all is done from the db
- # organisation.reindex()
-
- # No dedicated
- changeorg("isShared", False)
- res = client.get(url_for("sonar.rerodoc_redirection", pid="111111"))
- assert res.status_code == 302
- assert res.location.find(f"/{global_view}/documents/{document['pid']}") != -1
-
- # Dedicated
- changeorg("isDedicated", True)
- res = client.get(url_for("sonar.rerodoc_redirection", pid="111111"))
- assert res.status_code == 302
- assert res.location.find(f"/{organisation['code']}/documents/{document['pid']}") != -1
-
- # Shared
- changeorg("isDedicated", False)
- changeorg("isShared", True)
- res = client.get(url_for("sonar.rerodoc_redirection", pid="111111"))
- assert res.status_code == 302
- assert res.location.find(f"/{organisation['code']}/documents/{document['pid']}") != -1
-
-
def test_format_date(app):
"""Test date formatting."""
assert format_date("1984-05-01 14:30:00", "%d/%m/%Y %H:%M") == "01/05/1984 16:30"
diff --git a/tests/unit/documents/loaders/test_loader_schema_factory.py b/tests/unit/documents/loaders/test_loader_schema_factory.py
index c13d80dce..45aef6d4e 100644
--- a/tests/unit/documents/loaders/test_loader_schema_factory.py
+++ b/tests/unit/documents/loaders/test_loader_schema_factory.py
@@ -1,5 +1,5 @@
# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
+# Copyright (C) 2021-2026 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -13,19 +13,19 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-"""Test BORIS record loader."""
+"""Test loader schema factory."""
import pytest
+from sonar.modules.documents.loaders.schemas.archive_ouverte_unige import ArchiveOuverteUnigeSchema
from sonar.modules.documents.loaders.schemas.factory import LoaderSchemaFactory
-from sonar.modules.documents.loaders.schemas.rerodoc import RerodocSchema
def test_loader_schema_factory():
"""Test loader schema factory."""
- schema = LoaderSchemaFactory.create("rerodoc")
- assert isinstance(schema, RerodocSchema)
+ schema = LoaderSchemaFactory.create("archive_ouverte_unige")
+ assert isinstance(schema, ArchiveOuverteUnigeSchema)
with pytest.raises(Exception) as exception:
- schema = LoaderSchemaFactory.create("not-existing")
- assert str(exception) == 'No schema defined for key "not-existing"'
+ LoaderSchemaFactory.create("not-existing")
+ assert str(exception.value) == 'No schema defined for key "not-existing"'
diff --git a/tests/unit/documents/loaders/test_rerodoc_loader.py b/tests/unit/documents/loaders/test_rerodoc_loader.py
deleted file mode 100644
index 66aacb60e..000000000
--- a/tests/unit/documents/loaders/test_rerodoc_loader.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# Swiss Open Access Repository
-# Copyright (C) 2021 RERO
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, version 3 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-"""Test BORIS record loader."""
-
-from sonar.modules.documents.loaders.schemas.rerodoc import RerodocSchema
-
-
-def test_rerodoc_loader(app, organisation):
- """Test RERODOC record loader."""
- xml = """
-
-
- oai:doc.rero.ch:289209
- 2017-08-02T19:31:33Z
- nl-uzh
- article
- rero_explore
- postprint
-
-
-
- 00000coc 2200000uu 4500
- 289209
- 20170803135013.0
-
- 10.1093/mnras/stu2500
- doi
-
-
- oai:doc.rero.ch:289209
- nl-uzh
- article
- rero_explore
- postprint
-
-
- swissbib.ch:(NATIONALLICENCE)oxford-10.1093/mnras/stu2500
-
-
- eng
-
-
- 52
-
-
- Capelo, Pedro R.
- Department of Astronomy, University of Michigan, Ann Arbor, MI 48109, USA
-
-
- Growth and activity of black holes in galaxy mergers with varying mass ratios
-
-
- We study supermassive black holes (BHs) in merging galaxies
-
-
- © 2015 The Authors Published by Oxford University Press on behalf of the Royal Astronomical Society
-
-
- galaxies: active ; galaxies: interactions ; galaxies: nuclei
-
-
- Volonteri, Marta
- Department of Astronomy, University of Michigan, Ann Arbor, MI 48109, USA
-
-
- Dotti, Massimo
- Dipartimento di Fisica G. Occhialini, Università degli Studi di Milano Bicocca, Piazza della Scienza 3, I-20126 Milano, Italy
-
-
- Bellovary, Jillian M.
- Department of Physics and Astronomy, Vanderbilt University, Nashville, TN 37235, USA
-
-
- Mayer, Lucio
- Institute for Computational Science, University of Zürich, Winterthurerstrasse 190, CH-8057 Zürich, Switzerland
-
-
- Governato, Fabio
- Department of Astronomy, University of Washington, Box 351580, Seattle, WA 98195, USA
-
-
- 0035-8711
- Monthly Notices of the Royal Astronomical Society
- 2015/447/3/2123-2143
- Oxford University Press
-
-
- Publisher's version
- https://doi.org/10.1093/mnras/stu2500
-
-
- Alternative version
- http://www-geol.unine.ch/GEOMAGNETISME/tract.html
-
-
- Consortium of Swiss Academic Libraries
- Zurich
- doc.support@rero.ch
-
-
- POSTPRINT
- org
- ART_JOURNAL
-
-
- National Licences: uzh
-
-
-
-
- """ # nopep8
- assert RerodocSchema().dump(xml) == {
- "identifiedBy": [
- {"type": "bf:Local", "source": "RERO DOC", "value": "289209"},
- {
- "type": "bf:Local",
- "source": "Swissbib",
- "value": "(NATIONALLICENCE)oxford-10.1093/mnras/stu2500",
- },
- {"type": "bf:Doi", "value": "10.1093/mnras/stu2500"},
- ],
- "collections": [{"$ref": "https://sonar.ch/api/collections/1"}],
- "usageAndAccessPolicy": {
- "label": "© 2015 The Authors Published by Oxford University Press on "
- "behalf of the Royal Astronomical Society",
- "license": "License undefined",
- },
- "abstracts": [
- {
- "value": "We study supermassive black holes (BHs) in merging galaxies",
- "language": "eng",
- }
- ],
- "partOf": [
- {
- "numberingYear": "2015",
- "numberingVolume": "447",
- "numberingIssue": "3",
- "numberingPages": "2123-2143",
- "document": {
- "title": "Monthly Notices of the Royal Astronomical Society",
- "publication": {"statement": "Oxford University Press"},
- },
- }
- ],
- "provisionActivity": [{"type": "bf:Publication", "startDate": "2015"}],
- "otherEdition": [
- {
- "document": {"electronicLocator": "http://www-geol.unine.ch/GEOMAGNETISME/tract.html"},
- "publicNote": "Alternative version",
- }
- ],
- "language": [{"type": "bf:Language", "value": "eng"}],
- "documentType": "coar:c_6501",
- "organisation": [{"$ref": "https://sonar.ch/api/organisations/org"}],
- "classification": [{"type": "bf:ClassificationUdc", "classificationPortion": "52"}],
- "contribution": [
- {
- "agent": {"type": "bf:Person", "preferred_name": "Capelo, Pedro R."},
- "role": ["cre"],
- "affiliation": "Department of Astronomy, University of Michigan, Ann Arbor, MI 48109, USA",
- },
- {
- "agent": {"type": "bf:Person", "preferred_name": "Volonteri, Marta"},
- "role": ["cre"],
- "affiliation": "Department of Astronomy, University of Michigan, Ann Arbor, MI 48109, USA",
- },
- {
- "agent": {"type": "bf:Person", "preferred_name": "Dotti, Massimo"},
- "role": ["cre"],
- "affiliation": "Dipartimento di Fisica G. Occhialini, Università degli Studi di "
- "Milano Bicocca, Piazza della Scienza 3, I-20126 Milano, Italy",
- },
- {
- "agent": {
- "type": "bf:Person",
- "preferred_name": "Bellovary, Jillian M.",
- },
- "role": ["cre"],
- "affiliation": "Department of Physics and Astronomy, Vanderbilt University, Nashville, TN 37235, USA",
- },
- {
- "agent": {"type": "bf:Person", "preferred_name": "Mayer, Lucio"},
- "role": ["cre"],
- "affiliation": "Institute for Computational Science, University of Zürich, "
- "Winterthurerstrasse 190, CH-8057 Zürich, Switzerland",
- },
- {
- "agent": {"type": "bf:Person", "preferred_name": "Governato, Fabio"},
- "role": ["cre"],
- "affiliation": "Department of Astronomy, University of Washington, Box 351580, Seattle, WA 98195, USA",
- },
- ],
- "title": [
- {
- "type": "bf:Title",
- "mainTitle": [
- {
- "value": "Growth and activity of black holes in galaxy mergers with varying mass ratios",
- "language": "eng",
- }
- ],
- }
- ],
- }
diff --git a/uv.lock b/uv.lock
index de36261f0..4e1604797 100644
--- a/uv.lock
+++ b/uv.lock
@@ -118,11 +118,11 @@ wheels = [
[[package]]
name = "attrs"
-version = "25.4.0"
+version = "26.1.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
+ { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" },
]
[[package]]
@@ -140,7 +140,8 @@ version = "1.2.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "babel" },
- { name = "edtf" },
+ { name = "edtf", version = "5.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "edtf", version = "5.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f9/25/b2ca3f471b91d37f59ec4304b5f98bdb6001e174a431dda34cf98b2a217c/babel-edtf-1.2.1.tar.gz", hash = "sha256:1ed0c454e123ed7579510d9531eae5af4399272b0dff897d3d42f68e9bed8d8e", size = 18138, upload-time = "2024-11-07T13:05:22.818Z" }
wheels = [
@@ -302,7 +303,8 @@ version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama", marker = "os_name == 'nt'" },
- { name = "importlib-metadata", marker = "python_full_version < '3.10.2'" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "9.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and python_full_version < '3.10.2'" },
{ name = "packaging", version = "24.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "packaging", version = "26.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pyproject-hooks" },
@@ -354,7 +356,7 @@ wheels = [
[package.optional-dependencies]
filecache = [
- { name = "filelock", version = "3.25.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "filelock", version = "3.25.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
[[package]]
@@ -468,75 +470,75 @@ wheels = [
[[package]]
name = "charset-normalizer"
-version = "3.4.5"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/a7/21/a2b1505639008ba2e6ef03733a81fc6cfd6a07ea6139a2b76421230b8dad/charset_normalizer-3.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4167a621a9a1a986c73777dbc15d4b5eac8ac5c10393374109a343d4013ec765", size = 283319, upload-time = "2026-03-06T06:00:26.433Z" },
- { url = "https://files.pythonhosted.org/packages/70/67/df234c29b68f4e1e095885c9db1cb4b69b8aba49cf94fac041db4aaf1267/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f64c6bf8f32f9133b668c7f7a7cbdbc453412bc95ecdbd157f3b1e377a92990", size = 189974, upload-time = "2026-03-06T06:00:28.222Z" },
- { url = "https://files.pythonhosted.org/packages/df/7f/fc66af802961c6be42e2c7b69c58f95cbd1f39b0e81b3365d8efe2a02a04/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:568e3c34b58422075a1b49575a6abc616d9751b4d61b23f712e12ebb78fe47b2", size = 207866, upload-time = "2026-03-06T06:00:29.769Z" },
- { url = "https://files.pythonhosted.org/packages/c9/23/404eb36fac4e95b833c50e305bba9a241086d427bb2167a42eac7c4f7da4/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:036c079aa08a6a592b82487f97c60b439428320ed1b2ea0b3912e99d30c77765", size = 203239, upload-time = "2026-03-06T06:00:31.086Z" },
- { url = "https://files.pythonhosted.org/packages/4b/2f/8a1d989bfadd120c90114ab33e0d2a0cbde05278c1fc15e83e62d570f50a/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:340810d34ef83af92148e96e3e44cb2d3f910d2bf95e5618a5c467d9f102231d", size = 196529, upload-time = "2026-03-06T06:00:32.608Z" },
- { url = "https://files.pythonhosted.org/packages/a5/0c/c75f85ff7ca1f051958bb518cd43922d86f576c03947a050fbedfdfb4f15/charset_normalizer-3.4.5-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:cd2d0f0ec9aa977a27731a3209ebbcacebebaf41f902bd453a928bfd281cf7f8", size = 184152, upload-time = "2026-03-06T06:00:33.93Z" },
- { url = "https://files.pythonhosted.org/packages/f9/20/4ed37f6199af5dde94d4aeaf577f3813a5ec6635834cda1d957013a09c76/charset_normalizer-3.4.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b362bcd27819f9c07cbf23db4e0e8cd4b44c5ecd900c2ff907b2b92274a7412", size = 195226, upload-time = "2026-03-06T06:00:35.469Z" },
- { url = "https://files.pythonhosted.org/packages/28/31/7ba1102178cba7c34dcc050f43d427172f389729e356038f0726253dd914/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:77be992288f720306ab4108fe5c74797de327f3248368dfc7e1a916d6ed9e5a2", size = 192933, upload-time = "2026-03-06T06:00:36.83Z" },
- { url = "https://files.pythonhosted.org/packages/4b/23/f86443ab3921e6a60b33b93f4a1161222231f6c69bc24fb18f3bee7b8518/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8b78d8a609a4b82c273257ee9d631ded7fac0d875bdcdccc109f3ee8328cfcb1", size = 185647, upload-time = "2026-03-06T06:00:38.367Z" },
- { url = "https://files.pythonhosted.org/packages/82/44/08b8be891760f1f5a6d23ce11d6d50c92981603e6eb740b4f72eea9424e2/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ba20bdf69bd127f66d0174d6f2a93e69045e0b4036dc1ca78e091bcc765830c4", size = 209533, upload-time = "2026-03-06T06:00:41.931Z" },
- { url = "https://files.pythonhosted.org/packages/3b/5f/df114f23406199f8af711ddccfbf409ffbc5b7cdc18fa19644997ff0c9bb/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:76a9d0de4d0eab387822e7b35d8f89367dd237c72e82ab42b9f7bf5e15ada00f", size = 195901, upload-time = "2026-03-06T06:00:43.978Z" },
- { url = "https://files.pythonhosted.org/packages/07/83/71ef34a76fe8aa05ff8f840244bda2d61e043c2ef6f30d200450b9f6a1be/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8fff79bf5978c693c9b1a4d71e4a94fddfb5fe744eb062a318e15f4a2f63a550", size = 204950, upload-time = "2026-03-06T06:00:45.202Z" },
- { url = "https://files.pythonhosted.org/packages/58/40/0253be623995365137d7dc68e45245036207ab2227251e69a3d93ce43183/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c7e84e0c0005e3bdc1a9211cd4e62c78ba80bc37b2365ef4410cd2007a9047f2", size = 198546, upload-time = "2026-03-06T06:00:46.481Z" },
- { url = "https://files.pythonhosted.org/packages/ed/5c/5f3cb5b259a130895ef5ae16b38eaf141430fa3f7af50cd06c5d67e4f7b2/charset_normalizer-3.4.5-cp310-cp310-win32.whl", hash = "sha256:58ad8270cfa5d4bef1bc85bd387217e14ff154d6630e976c6f56f9a040757475", size = 132516, upload-time = "2026-03-06T06:00:47.924Z" },
- { url = "https://files.pythonhosted.org/packages/a5/c3/84fb174e7770f2df2e1a2115090771bfbc2227fb39a765c6d00568d1aab4/charset_normalizer-3.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:02a9d1b01c1e12c27883b0c9349e0bcd9ae92e727ff1a277207e1a262b1cbf05", size = 142906, upload-time = "2026-03-06T06:00:49.389Z" },
- { url = "https://files.pythonhosted.org/packages/d7/b2/6f852f8b969f2cbd0d4092d2e60139ab1af95af9bb651337cae89ec0f684/charset_normalizer-3.4.5-cp310-cp310-win_arm64.whl", hash = "sha256:039215608ac7b358c4da0191d10fc76868567fbf276d54c14721bdedeb6de064", size = 133258, upload-time = "2026-03-06T06:00:51.051Z" },
- { url = "https://files.pythonhosted.org/packages/8f/9e/bcec3b22c64ecec47d39bf5167c2613efd41898c019dccd4183f6aa5d6a7/charset_normalizer-3.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:610f72c0ee565dfb8ae1241b666119582fdbfe7c0975c175be719f940e110694", size = 279531, upload-time = "2026-03-06T06:00:52.252Z" },
- { url = "https://files.pythonhosted.org/packages/58/12/81fd25f7e7078ab5d1eedbb0fac44be4904ae3370a3bf4533c8f2d159acd/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60d68e820af339df4ae8358c7a2e7596badeb61e544438e489035f9fbf3246a5", size = 188006, upload-time = "2026-03-06T06:00:53.8Z" },
- { url = "https://files.pythonhosted.org/packages/ae/6e/f2d30e8c27c1b0736a6520311982cf5286cfc7f6cac77d7bc1325e3a23f2/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b473fc8dca1c3ad8559985794815f06ca3fc71942c969129070f2c3cdf7281", size = 205085, upload-time = "2026-03-06T06:00:55.311Z" },
- { url = "https://files.pythonhosted.org/packages/d0/90/d12cefcb53b5931e2cf792a33718d7126efb116a320eaa0742c7059a95e4/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d4eb8ac7469b2a5d64b5b8c04f84d8bf3ad340f4514b98523805cbf46e3b3923", size = 200545, upload-time = "2026-03-06T06:00:56.532Z" },
- { url = "https://files.pythonhosted.org/packages/03/f4/44d3b830a20e89ff82a3134912d9a1cf6084d64f3b95dcad40f74449a654/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bcb3227c3d9aaf73eaaab1db7ccd80a8995c509ee9941e2aae060ca6e4e5d81", size = 193863, upload-time = "2026-03-06T06:00:57.823Z" },
- { url = "https://files.pythonhosted.org/packages/25/4b/f212119c18a6320a9d4a730d1b4057875cdeabf21b3614f76549042ef8a8/charset_normalizer-3.4.5-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:75ee9c1cce2911581a70a3c0919d8bccf5b1cbc9b0e5171400ec736b4b569497", size = 181827, upload-time = "2026-03-06T06:00:59.323Z" },
- { url = "https://files.pythonhosted.org/packages/74/00/b26158e48b425a202a92965f8069e8a63d9af1481dfa206825d7f74d2a3c/charset_normalizer-3.4.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d1401945cb77787dbd3af2446ff2d75912327c4c3a1526ab7955ecf8600687c", size = 191085, upload-time = "2026-03-06T06:01:00.546Z" },
- { url = "https://files.pythonhosted.org/packages/c4/c2/1c1737bf6fd40335fe53d28fe49afd99ee4143cc57a845e99635ce0b9b6d/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a45e504f5e1be0bd385935a8e1507c442349ca36f511a47057a71c9d1d6ea9e", size = 190688, upload-time = "2026-03-06T06:01:02.479Z" },
- { url = "https://files.pythonhosted.org/packages/5a/3d/abb5c22dc2ef493cd56522f811246a63c5427c08f3e3e50ab663de27fcf4/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e09f671a54ce70b79a1fc1dc6da3072b7ef7251fadb894ed92d9aa8218465a5f", size = 183077, upload-time = "2026-03-06T06:01:04.231Z" },
- { url = "https://files.pythonhosted.org/packages/44/33/5298ad4d419a58e25b3508e87f2758d1442ff00c2471f8e0403dab8edad5/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d01de5e768328646e6a3fa9e562706f8f6641708c115c62588aef2b941a4f88e", size = 206706, upload-time = "2026-03-06T06:01:05.773Z" },
- { url = "https://files.pythonhosted.org/packages/7b/17/51e7895ac0f87c3b91d276a449ef09f5532a7529818f59646d7a55089432/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:131716d6786ad5e3dc542f5cc6f397ba3339dc0fb87f87ac30e550e8987756af", size = 191665, upload-time = "2026-03-06T06:01:07.473Z" },
- { url = "https://files.pythonhosted.org/packages/90/8f/cce9adf1883e98906dbae380d769b4852bb0fa0004bc7d7a2243418d3ea8/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a374cc0b88aa710e8865dc1bd6edb3743c59f27830f0293ab101e4cf3ce9f85", size = 201950, upload-time = "2026-03-06T06:01:08.973Z" },
- { url = "https://files.pythonhosted.org/packages/08/ca/bce99cd5c397a52919e2769d126723f27a4c037130374c051c00470bcd38/charset_normalizer-3.4.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d31f0d1671e1534e395f9eb84a68e0fb670e1edb1fe819a9d7f564ae3bc4e53f", size = 195830, upload-time = "2026-03-06T06:01:10.155Z" },
- { url = "https://files.pythonhosted.org/packages/87/4f/2e3d023a06911f1281f97b8f036edc9872167036ca6f55cc874a0be6c12c/charset_normalizer-3.4.5-cp311-cp311-win32.whl", hash = "sha256:cace89841c0599d736d3d74a27bc5821288bb47c5441923277afc6059d7fbcb4", size = 132029, upload-time = "2026-03-06T06:01:11.706Z" },
- { url = "https://files.pythonhosted.org/packages/fe/1f/a853b73d386521fd44b7f67ded6b17b7b2367067d9106a5c4b44f9a34274/charset_normalizer-3.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:f8102ae93c0bc863b1d41ea0f4499c20a83229f52ed870850892df555187154a", size = 142404, upload-time = "2026-03-06T06:01:12.865Z" },
- { url = "https://files.pythonhosted.org/packages/b4/10/dba36f76b71c38e9d391abe0fd8a5b818790e053c431adecfc98c35cd2a9/charset_normalizer-3.4.5-cp311-cp311-win_arm64.whl", hash = "sha256:ed98364e1c262cf5f9363c3eca8c2df37024f52a8fa1180a3610014f26eac51c", size = 132796, upload-time = "2026-03-06T06:01:14.106Z" },
- { url = "https://files.pythonhosted.org/packages/9c/b6/9ee9c1a608916ca5feae81a344dffbaa53b26b90be58cc2159e3332d44ec/charset_normalizer-3.4.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade", size = 280976, upload-time = "2026-03-06T06:01:15.276Z" },
- { url = "https://files.pythonhosted.org/packages/f8/d8/a54f7c0b96f1df3563e9190f04daf981e365a9b397eedfdfb5dbef7e5c6c/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54", size = 189356, upload-time = "2026-03-06T06:01:16.511Z" },
- { url = "https://files.pythonhosted.org/packages/42/69/2bf7f76ce1446759a5787cb87d38f6a61eb47dbbdf035cfebf6347292a65/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467", size = 206369, upload-time = "2026-03-06T06:01:17.853Z" },
- { url = "https://files.pythonhosted.org/packages/10/9c/949d1a46dab56b959d9a87272482195f1840b515a3380e39986989a893ae/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60", size = 203285, upload-time = "2026-03-06T06:01:19.473Z" },
- { url = "https://files.pythonhosted.org/packages/67/5c/ae30362a88b4da237d71ea214a8c7eb915db3eec941adda511729ac25fa2/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d", size = 196274, upload-time = "2026-03-06T06:01:20.728Z" },
- { url = "https://files.pythonhosted.org/packages/b2/07/c9f2cb0e46cb6d64fdcc4f95953747b843bb2181bda678dc4e699b8f0f9a/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e", size = 184715, upload-time = "2026-03-06T06:01:22.194Z" },
- { url = "https://files.pythonhosted.org/packages/36/64/6b0ca95c44fddf692cd06d642b28f63009d0ce325fad6e9b2b4d0ef86a52/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f", size = 193426, upload-time = "2026-03-06T06:01:23.795Z" },
- { url = "https://files.pythonhosted.org/packages/50/bc/a730690d726403743795ca3f5bb2baf67838c5fea78236098f324b965e40/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc", size = 191780, upload-time = "2026-03-06T06:01:25.053Z" },
- { url = "https://files.pythonhosted.org/packages/97/4f/6c0bc9af68222b22951552d73df4532b5be6447cee32d58e7e8c74ecbb7b/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95", size = 185805, upload-time = "2026-03-06T06:01:26.294Z" },
- { url = "https://files.pythonhosted.org/packages/dd/b9/a523fb9b0ee90814b503452b2600e4cbc118cd68714d57041564886e7325/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a", size = 208342, upload-time = "2026-03-06T06:01:27.55Z" },
- { url = "https://files.pythonhosted.org/packages/4d/61/c59e761dee4464050713e50e27b58266cc8e209e518c0b378c1580c959ba/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac", size = 193661, upload-time = "2026-03-06T06:01:29.051Z" },
- { url = "https://files.pythonhosted.org/packages/1c/43/729fa30aad69783f755c5ad8649da17ee095311ca42024742701e202dc59/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1", size = 204819, upload-time = "2026-03-06T06:01:30.298Z" },
- { url = "https://files.pythonhosted.org/packages/87/33/d9b442ce5a91b96fc0840455a9e49a611bbadae6122778d0a6a79683dd31/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98", size = 198080, upload-time = "2026-03-06T06:01:31.478Z" },
- { url = "https://files.pythonhosted.org/packages/56/5a/b8b5a23134978ee9885cee2d6995f4c27cc41f9baded0a9685eabc5338f0/charset_normalizer-3.4.5-cp312-cp312-win32.whl", hash = "sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262", size = 132630, upload-time = "2026-03-06T06:01:33.056Z" },
- { url = "https://files.pythonhosted.org/packages/70/53/e44a4c07e8904500aec95865dc3f6464dc3586a039ef0df606eb3ac38e35/charset_normalizer-3.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636", size = 142856, upload-time = "2026-03-06T06:01:34.489Z" },
- { url = "https://files.pythonhosted.org/packages/ea/aa/c5628f7cad591b1cf45790b7a61483c3e36cf41349c98af7813c483fd6e8/charset_normalizer-3.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02", size = 132982, upload-time = "2026-03-06T06:01:35.641Z" },
- { url = "https://files.pythonhosted.org/packages/be/76/96dec962aa996081c48f544d5e9e97322006a1e67e8f76bad41f3fb0b151/charset_normalizer-3.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:259cd1ca995ad525f638e131dbcc2353a586564c038fc548a3fe450a91882139", size = 283220, upload-time = "2026-03-06T06:02:53.024Z" },
- { url = "https://files.pythonhosted.org/packages/cc/80/050c340587611be9743eff02d1ca34b5fc76a4356849dcb74dfd898d6d87/charset_normalizer-3.4.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a28afb04baa55abf26df544e3e5c6534245d3daa5178bc4a8eeb48202060d0e", size = 189988, upload-time = "2026-03-06T06:02:54.448Z" },
- { url = "https://files.pythonhosted.org/packages/c7/a3/bb6caf9f5544ccaaca5c7e387fa868868d3420bcb03e8bc30f37be2e8a72/charset_normalizer-3.4.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ff95a9283de8a457e6b12989de3f9f5193430f375d64297d323a615ea52cbdb3", size = 207786, upload-time = "2026-03-06T06:02:55.808Z" },
- { url = "https://files.pythonhosted.org/packages/ee/50/e56713141f2fdb3a4d46092425d58dc97a48e1e10ce321ac6ba43862aacf/charset_normalizer-3.4.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:708c7acde173eedd4bfa4028484426ba689d2103b28588c513b9db2cd5ecde9c", size = 203556, upload-time = "2026-03-06T06:02:57.31Z" },
- { url = "https://files.pythonhosted.org/packages/22/34/ed0cfd388dd9106725afc2beb036adbaa167fc0b5a9ee8cd3940757fb060/charset_normalizer-3.4.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa92ec1102eaff840ccd1021478af176a831f1bccb08e526ce844b7ddda85c22", size = 196552, upload-time = "2026-03-06T06:02:59.05Z" },
- { url = "https://files.pythonhosted.org/packages/9a/8b/da4a4c3d26c539fdd777cfbd2c0d83e77e1218879517ef91c4ece7238563/charset_normalizer-3.4.5-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:5fea359734b140d0d6741189fea5478c6091b54ffc69d7ce119e0a05637d8c99", size = 184289, upload-time = "2026-03-06T06:03:00.448Z" },
- { url = "https://files.pythonhosted.org/packages/d3/05/9f67c1f94ea9ae1e08c8fa2182b1f5411732e18643e7080fc8c10ba1e021/charset_normalizer-3.4.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e545b51da9f9af5c67815ca0eb40676c0f016d0b0381c86f20451e35696c5f95", size = 195282, upload-time = "2026-03-06T06:03:02.161Z" },
- { url = "https://files.pythonhosted.org/packages/59/5e/aaf84a2e37e75470640e965d6619c6d9a521eb7c8aa097f2586907859198/charset_normalizer-3.4.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:30987f4a8ed169983f93e1be8ffeea5214a779e27ed0b059835c7afe96550ad7", size = 192889, upload-time = "2026-03-06T06:03:03.629Z" },
- { url = "https://files.pythonhosted.org/packages/eb/94/9b714873baf9a841613e8b49a5a3cd77d985d2c6c80f5038a5057395ebac/charset_normalizer-3.4.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:149ec69866c3d6c2fb6f758dbc014ecb09f30b35a5ca90b6a8a2d4e54e18fdfe", size = 185738, upload-time = "2026-03-06T06:03:05.173Z" },
- { url = "https://files.pythonhosted.org/packages/ab/e5/bf57e1a9210a6ba78c740d66d05165a55b2cbeca29a83b8c659c9eb2d6c6/charset_normalizer-3.4.5-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:530beedcec9b6e027e7a4b6ce26eed36678aa39e17da85e6e03d7bd9e8e9d7c9", size = 209458, upload-time = "2026-03-06T06:03:06.54Z" },
- { url = "https://files.pythonhosted.org/packages/65/91/3c8cb46d840840f2593028fd708ea50695f8f61e1c490530ef1cce824f56/charset_normalizer-3.4.5-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:14498a429321de554b140013142abe7608f9d8ccc04d7baf2ad60498374aefa2", size = 195792, upload-time = "2026-03-06T06:03:08Z" },
- { url = "https://files.pythonhosted.org/packages/b0/43/783be5c6932fa8846a98313a2242fbcfe0c06c1c0ac2d6856b99d93069eb/charset_normalizer-3.4.5-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2820a98460c83663dd8ec015d9ddfd1e4879f12e06bb7d0500f044fb477d2770", size = 204829, upload-time = "2026-03-06T06:03:09.488Z" },
- { url = "https://files.pythonhosted.org/packages/36/7d/138b5311c32fd24396321db796538cc748287c92da5e6fc1996babc06f99/charset_normalizer-3.4.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:aa2f963b4da26daf46231d9b9e0e2c9408a751f8f0d0f44d2de56d3caf51d294", size = 198558, upload-time = "2026-03-06T06:03:11.585Z" },
- { url = "https://files.pythonhosted.org/packages/9c/87/ddd8bbdd703707c019fe9d14b678011627e6c5131dfdefe42aff151d718c/charset_normalizer-3.4.5-cp39-cp39-win32.whl", hash = "sha256:82cc7c2ad42faec8b574351f8bc2a0c049043893853317bd9bb309f5aba6cb5a", size = 132370, upload-time = "2026-03-06T06:03:13.327Z" },
- { url = "https://files.pythonhosted.org/packages/59/f6/d7cd28ae6d4dd47170b95153986789d69af4d5844f640edbc5138e4a70a2/charset_normalizer-3.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:92263f7eca2f4af326cd20de8d16728d2602f7cfea02e790dcde9d83c365d7cc", size = 142877, upload-time = "2026-03-06T06:03:15.041Z" },
- { url = "https://files.pythonhosted.org/packages/9c/26/8d68681566f288998eb36a0c60dd2c5c8aa93ee67b0d7e3dc72606650828/charset_normalizer-3.4.5-cp39-cp39-win_arm64.whl", hash = "sha256:014837af6fabf57121b6254fa8ade10dceabc3528b27b721a64bbc7b8b1d4eb4", size = 133186, upload-time = "2026-03-06T06:03:16.476Z" },
- { url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" },
+version = "3.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7b/60/e3bec1881450851b087e301bedc3daa9377a4d45f1c26aa90b0b235e38aa/charset_normalizer-3.4.6.tar.gz", hash = "sha256:1ae6b62897110aa7c79ea2f5dd38d1abca6db663687c0b1ad9aed6f6bae3d9d6", size = 143363, upload-time = "2026-03-15T18:53:25.478Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e6/8c/2c56124c6dc53a774d435f985b5973bc592f42d437be58c0c92d65ae7296/charset_normalizer-3.4.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2e1d8ca8611099001949d1cdfaefc510cf0f212484fe7c565f735b68c78c3c95", size = 298751, upload-time = "2026-03-15T18:50:00.003Z" },
+ { url = "https://files.pythonhosted.org/packages/86/2a/2a7db6b314b966a3bcad8c731c0719c60b931b931de7ae9f34b2839289ee/charset_normalizer-3.4.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e25369dc110d58ddf29b949377a93e0716d72a24f62bad72b2b39f155949c1fd", size = 200027, upload-time = "2026-03-15T18:50:01.702Z" },
+ { url = "https://files.pythonhosted.org/packages/68/f2/0fe775c74ae25e2a3b07b01538fc162737b3e3f795bada3bc26f4d4d495c/charset_normalizer-3.4.6-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:259695e2ccc253feb2a016303543d691825e920917e31f894ca1a687982b1de4", size = 220741, upload-time = "2026-03-15T18:50:03.194Z" },
+ { url = "https://files.pythonhosted.org/packages/10/98/8085596e41f00b27dd6aa1e68413d1ddda7e605f34dd546833c61fddd709/charset_normalizer-3.4.6-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dda86aba335c902b6149a02a55b38e96287157e609200811837678214ba2b1db", size = 215802, upload-time = "2026-03-15T18:50:05.859Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/ce/865e4e09b041bad659d682bbd98b47fb490b8e124f9398c9448065f64fee/charset_normalizer-3.4.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51fb3c322c81d20567019778cb5a4a6f2dc1c200b886bc0d636238e364848c89", size = 207908, upload-time = "2026-03-15T18:50:07.676Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/54/8c757f1f7349262898c2f169e0d562b39dcb977503f18fdf0814e923db78/charset_normalizer-3.4.6-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:4482481cb0572180b6fd976a4d5c72a30263e98564da68b86ec91f0fe35e8565", size = 194357, upload-time = "2026-03-15T18:50:09.327Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/29/e88f2fac9218907fc7a70722b393d1bbe8334c61fe9c46640dba349b6e66/charset_normalizer-3.4.6-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:39f5068d35621da2881271e5c3205125cc456f54e9030d3f723288c873a71bf9", size = 205610, upload-time = "2026-03-15T18:50:10.732Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/c5/21d7bb0cb415287178450171d130bed9d664211fdd59731ed2c34267b07d/charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8bea55c4eef25b0b19a0337dc4e3f9a15b00d569c77211fa8cde38684f234fb7", size = 203512, upload-time = "2026-03-15T18:50:12.535Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/be/ce52f3c7fdb35cc987ad38a53ebcef52eec498f4fb6c66ecfe62cfe57ba2/charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:f0cdaecd4c953bfae0b6bb64910aaaca5a424ad9c72d85cb88417bb9814f7550", size = 195398, upload-time = "2026-03-15T18:50:14.236Z" },
+ { url = "https://files.pythonhosted.org/packages/81/a0/3ab5dd39d4859a3555e5dadfc8a9fa7f8352f8c183d1a65c90264517da0e/charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:150b8ce8e830eb7ccb029ec9ca36022f756986aaaa7956aad6d9ec90089338c0", size = 221772, upload-time = "2026-03-15T18:50:15.581Z" },
+ { url = "https://files.pythonhosted.org/packages/04/6e/6a4e41a97ba6b2fa87f849c41e4d229449a586be85053c4d90135fe82d26/charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:e68c14b04827dd76dcbd1aeea9e604e3e4b78322d8faf2f8132c7138efa340a8", size = 205759, upload-time = "2026-03-15T18:50:17.047Z" },
+ { url = "https://files.pythonhosted.org/packages/db/3b/34a712a5ee64a6957bf355b01dc17b12de457638d436fdb05d01e463cd1c/charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:3778fd7d7cd04ae8f54651f4a7a0bd6e39a0cf20f801720a4c21d80e9b7ad6b0", size = 216938, upload-time = "2026-03-15T18:50:18.44Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/05/5bd1e12da9ab18790af05c61aafd01a60f489778179b621ac2a305243c62/charset_normalizer-3.4.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dad6e0f2e481fffdcf776d10ebee25e0ef89f16d691f1e5dee4b586375fdc64b", size = 210138, upload-time = "2026-03-15T18:50:19.852Z" },
+ { url = "https://files.pythonhosted.org/packages/bd/8e/3cb9e2d998ff6b21c0a1860343cb7b83eba9cdb66b91410e18fc4969d6ab/charset_normalizer-3.4.6-cp310-cp310-win32.whl", hash = "sha256:74a2e659c7ecbc73562e2a15e05039f1e22c75b7c7618b4b574a3ea9118d1557", size = 144137, upload-time = "2026-03-15T18:50:21.505Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/8f/78f5489ffadb0db3eb7aff53d31c24531d33eb545f0c6f6567c25f49a5ff/charset_normalizer-3.4.6-cp310-cp310-win_amd64.whl", hash = "sha256:aa9cccf4a44b9b62d8ba8b4dd06c649ba683e4bf04eea606d2e94cfc2d6ff4d6", size = 154244, upload-time = "2026-03-15T18:50:22.81Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/74/e472659dffb0cadb2f411282d2d76c60da1fc94076d7fffed4ae8a93ec01/charset_normalizer-3.4.6-cp310-cp310-win_arm64.whl", hash = "sha256:e985a16ff513596f217cee86c21371b8cd011c0f6f056d0920aa2d926c544058", size = 143312, upload-time = "2026-03-15T18:50:24.074Z" },
+ { url = "https://files.pythonhosted.org/packages/62/28/ff6f234e628a2de61c458be2779cb182bc03f6eec12200d4a525bbfc9741/charset_normalizer-3.4.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:82060f995ab5003a2d6e0f4ad29065b7672b6593c8c63559beefe5b443242c3e", size = 293582, upload-time = "2026-03-15T18:50:25.454Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/b7/b1a117e5385cbdb3205f6055403c2a2a220c5ea80b8716c324eaf75c5c95/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60c74963d8350241a79cb8feea80e54d518f72c26db618862a8f53e5023deaf9", size = 197240, upload-time = "2026-03-15T18:50:27.196Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/5f/2574f0f09f3c3bc1b2f992e20bce6546cb1f17e111c5be07308dc5427956/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6e4333fb15c83f7d1482a76d45a0818897b3d33f00efd215528ff7c51b8e35d", size = 217363, upload-time = "2026-03-15T18:50:28.601Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/d1/0ae20ad77bc949ddd39b51bf383b6ca932f2916074c95cad34ae465ab71f/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bc72863f4d9aba2e8fd9085e63548a324ba706d2ea2c83b260da08a59b9482de", size = 212994, upload-time = "2026-03-15T18:50:30.102Z" },
+ { url = "https://files.pythonhosted.org/packages/60/ac/3233d262a310c1b12633536a07cde5ddd16985e6e7e238e9f3f9423d8eb9/charset_normalizer-3.4.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9cc4fc6c196d6a8b76629a70ddfcd4635a6898756e2d9cac5565cf0654605d73", size = 204697, upload-time = "2026-03-15T18:50:31.654Z" },
+ { url = "https://files.pythonhosted.org/packages/25/3c/8a18fc411f085b82303cfb7154eed5bd49c77035eb7608d049468b53f87c/charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:0c173ce3a681f309f31b87125fecec7a5d1347261ea11ebbb856fa6006b23c8c", size = 191673, upload-time = "2026-03-15T18:50:33.433Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/a7/11cfe61d6c5c5c7438d6ba40919d0306ed83c9ab957f3d4da2277ff67836/charset_normalizer-3.4.6-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c907cdc8109f6c619e6254212e794d6548373cc40e1ec75e6e3823d9135d29cc", size = 201120, upload-time = "2026-03-15T18:50:35.105Z" },
+ { url = "https://files.pythonhosted.org/packages/b5/10/cf491fa1abd47c02f69687046b896c950b92b6cd7337a27e6548adbec8e4/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:404a1e552cf5b675a87f0651f8b79f5f1e6fd100ee88dc612f89aa16abd4486f", size = 200911, upload-time = "2026-03-15T18:50:36.819Z" },
+ { url = "https://files.pythonhosted.org/packages/28/70/039796160b48b18ed466fde0af84c1b090c4e288fae26cd674ad04a2d703/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e3c701e954abf6fc03a49f7c579cc80c2c6cc52525340ca3186c41d3f33482ef", size = 192516, upload-time = "2026-03-15T18:50:38.228Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/34/c56f3223393d6ff3124b9e78f7de738047c2d6bc40a4f16ac0c9d7a1cb3c/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7a6967aaf043bceabab5412ed6bd6bd26603dae84d5cb75bf8d9a74a4959d398", size = 218795, upload-time = "2026-03-15T18:50:39.664Z" },
+ { url = "https://files.pythonhosted.org/packages/e8/3b/ce2d4f86c5282191a041fdc5a4ce18f1c6bd40a5bd1f74cf8625f08d51c1/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5feb91325bbceade6afab43eb3b508c63ee53579fe896c77137ded51c6b6958e", size = 201833, upload-time = "2026-03-15T18:50:41.552Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/9b/b6a9f76b0fd7c5b5ec58b228ff7e85095370282150f0bd50b3126f5506d6/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f820f24b09e3e779fe84c3c456cb4108a7aa639b0d1f02c28046e11bfcd088ed", size = 213920, upload-time = "2026-03-15T18:50:43.33Z" },
+ { url = "https://files.pythonhosted.org/packages/ae/98/7bc23513a33d8172365ed30ee3a3b3fe1ece14a395e5fc94129541fc6003/charset_normalizer-3.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b35b200d6a71b9839a46b9b7fff66b6638bb52fc9658aa58796b0326595d3021", size = 206951, upload-time = "2026-03-15T18:50:44.789Z" },
+ { url = "https://files.pythonhosted.org/packages/32/73/c0b86f3d1458468e11aec870e6b3feac931facbe105a894b552b0e518e79/charset_normalizer-3.4.6-cp311-cp311-win32.whl", hash = "sha256:9ca4c0b502ab399ef89248a2c84c54954f77a070f28e546a85e91da627d1301e", size = 143703, upload-time = "2026-03-15T18:50:46.103Z" },
+ { url = "https://files.pythonhosted.org/packages/c6/e3/76f2facfe8eddee0bbd38d2594e709033338eae44ebf1738bcefe0a06185/charset_normalizer-3.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:a9e68c9d88823b274cf1e72f28cb5dc89c990edf430b0bfd3e2fb0785bfeabf4", size = 153857, upload-time = "2026-03-15T18:50:47.563Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/dc/9abe19c9b27e6cd3636036b9d1b387b78c40dedbf0b47f9366737684b4b0/charset_normalizer-3.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:97d0235baafca5f2b09cf332cc275f021e694e8362c6bb9c96fc9a0eb74fc316", size = 142751, upload-time = "2026-03-15T18:50:49.234Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/62/c0815c992c9545347aeea7859b50dc9044d147e2e7278329c6e02ac9a616/charset_normalizer-3.4.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ef7fedc7a6ecbe99969cd09632516738a97eeb8bd7258bf8a0f23114c057dab", size = 295154, upload-time = "2026-03-15T18:50:50.88Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/37/bdca6613c2e3c58c7421891d80cc3efa1d32e882f7c4a7ee6039c3fc951a/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4ea868bc28109052790eb2b52a9ab33f3aa7adc02f96673526ff47419490e21", size = 199191, upload-time = "2026-03-15T18:50:52.658Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/92/9934d1bbd69f7f398b38c5dae1cbf9cc672e7c34a4adf7b17c0a9c17d15d/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:836ab36280f21fc1a03c99cd05c6b7af70d2697e374c7af0b61ed271401a72a2", size = 218674, upload-time = "2026-03-15T18:50:54.102Z" },
+ { url = "https://files.pythonhosted.org/packages/af/90/25f6ab406659286be929fd89ab0e78e38aa183fc374e03aa3c12d730af8a/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f1ce721c8a7dfec21fcbdfe04e8f68174183cf4e8188e0645e92aa23985c57ff", size = 215259, upload-time = "2026-03-15T18:50:55.616Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/ef/79a463eb0fff7f96afa04c1d4c51f8fc85426f918db467854bfb6a569ce3/charset_normalizer-3.4.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e28d62a8fc7a1fa411c43bd65e346f3bce9716dc51b897fbe930c5987b402d5", size = 207276, upload-time = "2026-03-15T18:50:57.054Z" },
+ { url = "https://files.pythonhosted.org/packages/f7/72/d0426afec4b71dc159fa6b4e68f868cd5a3ecd918fec5813a15d292a7d10/charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:530d548084c4a9f7a16ed4a294d459b4f229db50df689bfe92027452452943a0", size = 195161, upload-time = "2026-03-15T18:50:58.686Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/18/c82b06a68bfcb6ce55e508225d210c7e6a4ea122bfc0748892f3dc4e8e11/charset_normalizer-3.4.6-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:30f445ae60aad5e1f8bdbb3108e39f6fbc09f4ea16c815c66578878325f8f15a", size = 203452, upload-time = "2026-03-15T18:51:00.196Z" },
+ { url = "https://files.pythonhosted.org/packages/44/d6/0c25979b92f8adafdbb946160348d8d44aa60ce99afdc27df524379875cb/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ac2393c73378fea4e52aa56285a3d64be50f1a12395afef9cce47772f60334c2", size = 202272, upload-time = "2026-03-15T18:51:01.703Z" },
+ { url = "https://files.pythonhosted.org/packages/2e/3d/7fea3e8fe84136bebbac715dd1221cc25c173c57a699c030ab9b8900cbb7/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:90ca27cd8da8118b18a52d5f547859cc1f8354a00cd1e8e5120df3e30d6279e5", size = 195622, upload-time = "2026-03-15T18:51:03.526Z" },
+ { url = "https://files.pythonhosted.org/packages/57/8a/d6f7fd5cb96c58ef2f681424fbca01264461336d2a7fc875e4446b1f1346/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e5a94886bedca0f9b78fecd6afb6629142fd2605aa70a125d49f4edc6037ee6", size = 220056, upload-time = "2026-03-15T18:51:05.269Z" },
+ { url = "https://files.pythonhosted.org/packages/16/50/478cdda782c8c9c3fb5da3cc72dd7f331f031e7f1363a893cdd6ca0f8de0/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:695f5c2823691a25f17bc5d5ffe79fa90972cc34b002ac6c843bb8a1720e950d", size = 203751, upload-time = "2026-03-15T18:51:06.858Z" },
+ { url = "https://files.pythonhosted.org/packages/75/fc/cc2fcac943939c8e4d8791abfa139f685e5150cae9f94b60f12520feaa9b/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:231d4da14bcd9301310faf492051bee27df11f2bc7549bc0bb41fef11b82daa2", size = 216563, upload-time = "2026-03-15T18:51:08.564Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/b7/a4add1d9a5f68f3d037261aecca83abdb0ab15960a3591d340e829b37298/charset_normalizer-3.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a056d1ad2633548ca18ffa2f85c202cfb48b68615129143915b8dc72a806a923", size = 209265, upload-time = "2026-03-15T18:51:10.312Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/18/c094561b5d64a24277707698e54b7f67bd17a4f857bbfbb1072bba07c8bf/charset_normalizer-3.4.6-cp312-cp312-win32.whl", hash = "sha256:c2274ca724536f173122f36c98ce188fd24ce3dad886ec2b7af859518ce008a4", size = 144229, upload-time = "2026-03-15T18:51:11.694Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/20/0567efb3a8fd481b8f34f739ebddc098ed062a59fed41a8d193a61939e8f/charset_normalizer-3.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:c8ae56368f8cc97c7e40a7ee18e1cedaf8e780cd8bc5ed5ac8b81f238614facb", size = 154277, upload-time = "2026-03-15T18:51:13.004Z" },
+ { url = "https://files.pythonhosted.org/packages/15/57/28d79b44b51933119e21f65479d0864a8d5893e494cf5daab15df0247c17/charset_normalizer-3.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:899d28f422116b08be5118ef350c292b36fc15ec2daeb9ea987c89281c7bb5c4", size = 142817, upload-time = "2026-03-15T18:51:14.408Z" },
+ { url = "https://files.pythonhosted.org/packages/41/85/580dbaa12ab31041ed7df59f0bebc8893514fc21da6c05c3a1c1707d118f/charset_normalizer-3.4.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31215157227939b4fb3d740cd23fe27be0439afef67b785a1eb78a3ae69cba9e", size = 298620, upload-time = "2026-03-15T18:52:57.332Z" },
+ { url = "https://files.pythonhosted.org/packages/67/2c/1e55af3a5e2f52e44396d5c5b731e0ae4f3bb92915ff09a610fb2f4497eb/charset_normalizer-3.4.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecbbd45615a6885fe3240eb9db73b9e62518b611850fdf8ab08bd56de7ad2b17", size = 200106, upload-time = "2026-03-15T18:52:59.2Z" },
+ { url = "https://files.pythonhosted.org/packages/10/42/0f2f51a1d16caa45fbf384fd337d4242df1a5b313babee211381d2d39a96/charset_normalizer-3.4.6-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c45a03a4c69820a399f1dda9e1d8fbf3562eda46e7720458180302021b08f778", size = 220539, upload-time = "2026-03-15T18:53:01.019Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/0c/4e10996c740eec0f4ae8afbbbfa25f66e8479c4b6ee9cff1ca366a4f6c04/charset_normalizer-3.4.6-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e8aeb10fcbe92767f0fa69ad5a72deca50d0dca07fbde97848997d778a50c9fe", size = 215821, upload-time = "2026-03-15T18:53:02.621Z" },
+ { url = "https://files.pythonhosted.org/packages/46/73/205ae7644ebb581a7c6fa9c3751e283606e145f0e6f066003c66aafc9973/charset_normalizer-3.4.6-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54fae94be3d75f3e573c9a1b5402dc593de19377013c9a0e4285e3d402dd3a2a", size = 207917, upload-time = "2026-03-15T18:53:04.413Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/ca/18f7dcf19afdab8097aeb2feb8b3809bb4b6ee356cb720abf5263d79406a/charset_normalizer-3.4.6-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:2f7fdd9b6e6c529d6a2501a2d36b240109e78a8ceaef5687cfcfa2bbe671d297", size = 194513, upload-time = "2026-03-15T18:53:06.025Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/6a/e7e3e204c8d79832a091e00b24595af1d5d9800d37dc1f67a6b264cc99a6/charset_normalizer-3.4.6-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4d1d02209e06550bdaef34af58e041ad71b88e624f5d825519da3a3308e22687", size = 205612, upload-time = "2026-03-15T18:53:07.494Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/ae/2169ebcea2851c5460c7a21993a0f87028be3c3e60899cb36251e1135cf5/charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8bc5f0687d796c05b1e28ab0d38a50e6309906ee09375dd3aff6a9c09dd6e8f4", size = 203519, upload-time = "2026-03-15T18:53:09.048Z" },
+ { url = "https://files.pythonhosted.org/packages/43/a0/6a49a925b9c225fe35dffeac5c76f68996b814c637e9d7213718f96be109/charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ee4ec14bc1680d6b0afab9aea2ef27e26d2024f18b24a2d7155a52b60da7e833", size = 195411, upload-time = "2026-03-15T18:53:10.542Z" },
+ { url = "https://files.pythonhosted.org/packages/47/f7/a26b0a18e52b1a0f11f53c2c400ed062f386ac227a64ae4be4c5a64699be/charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d1a2ee9c1499fc8f86f4521f27a973c914b211ffa87322f4ee33bb35392da2c5", size = 221653, upload-time = "2026-03-15T18:53:12.394Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/3a/ed1d3b5bb55e3634bd5c31cedbe4fff79d0e5b8d9a062f663a757a07760d/charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:48696db7f18afb80a068821504296eb0787d9ce239b91ca15059d1d3eaacf13b", size = 205650, upload-time = "2026-03-15T18:53:13.934Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/27/c75819eea5ceeefc49bae329327bb91e81adc346e2a9873d9fdb9e77cde6/charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4f41da960b196ea355357285ad1316a00099f22d0929fe168343b99b254729c9", size = 216919, upload-time = "2026-03-15T18:53:15.44Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/42/6e91bf8b15f67b7c957091138a36057a083e60703cc27848d5e36ca1eb03/charset_normalizer-3.4.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:802168e03fba8bbc5ce0d866d589e4b1ca751d06edee69f7f3a19c5a9fe6b597", size = 210101, upload-time = "2026-03-15T18:53:17.045Z" },
+ { url = "https://files.pythonhosted.org/packages/99/ff/101af2605e66a7ee59961d7f9e1060df7c92e8ea54208a02ab881422c24e/charset_normalizer-3.4.6-cp39-cp39-win32.whl", hash = "sha256:8761ac29b6c81574724322a554605608a9960769ea83d2c73e396f3df896ad54", size = 144136, upload-time = "2026-03-15T18:53:19.152Z" },
+ { url = "https://files.pythonhosted.org/packages/1d/da/de5942dfbf21f28c19e9202267dabf7bc73f195465d020a3a60054520cc5/charset_normalizer-3.4.6-cp39-cp39-win_amd64.whl", hash = "sha256:1cf0a70018692f85172348fe06d3a4b63f94ecb055e13a00c644d368eb82e5b8", size = 154210, upload-time = "2026-03-15T18:53:20.576Z" },
+ { url = "https://files.pythonhosted.org/packages/06/df/1b780a25b86d22b1d736f6ac883afd38ffdf30ddc18e5dc0e82211f493f1/charset_normalizer-3.4.6-cp39-cp39-win_arm64.whl", hash = "sha256:3516bbb8d42169de9e61b8520cbeeeb716f12f4ecfe3fd30a9919aa16c806ca8", size = 143225, upload-time = "2026-03-15T18:53:22.072Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/68/687187c7e26cb24ccbd88e5069f5ef00eba804d36dde11d99aad0838ab45/charset_normalizer-3.4.6-py3-none-any.whl", hash = "sha256:947cf925bc916d90adba35a64c82aace04fa39b46b52d4630ece166655905a69", size = 61455, upload-time = "2026-03-15T18:53:23.833Z" },
]
[[package]]
@@ -734,60 +736,60 @@ toml = [
[[package]]
name = "coverage"
-version = "7.13.4"
+version = "7.13.5"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
"python_full_version == '3.11.*'",
"python_full_version == '3.10.*'",
]
-sdist = { url = "https://files.pythonhosted.org/packages/24/56/95b7e30fa389756cb56630faa728da46a27b8c6eb46f9d557c68fff12b65/coverage-7.13.4.tar.gz", hash = "sha256:e5c8f6ed1e61a8b2dcdf31eb0b9bbf0130750ca79c1c49eb898e2ad86f5ccc91", size = 827239, upload-time = "2026-02-09T12:59:03.86Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/44/d4/7827d9ffa34d5d4d752eec907022aa417120936282fc488306f5da08c292/coverage-7.13.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fc31c787a84f8cd6027eba44010517020e0d18487064cd3d8968941856d1415", size = 219152, upload-time = "2026-02-09T12:56:11.974Z" },
- { url = "https://files.pythonhosted.org/packages/35/b0/d69df26607c64043292644dbb9dc54b0856fabaa2cbb1eeee3331cc9e280/coverage-7.13.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a32ebc02a1805adf637fc8dec324b5cdacd2e493515424f70ee33799573d661b", size = 219667, upload-time = "2026-02-09T12:56:13.33Z" },
- { url = "https://files.pythonhosted.org/packages/82/a4/c1523f7c9e47b2271dbf8c2a097e7a1f89ef0d66f5840bb59b7e8814157b/coverage-7.13.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e24f9156097ff9dc286f2f913df3a7f63c0e333dcafa3c196f2c18b4175ca09a", size = 246425, upload-time = "2026-02-09T12:56:14.552Z" },
- { url = "https://files.pythonhosted.org/packages/f8/02/aa7ec01d1a5023c4b680ab7257f9bfde9defe8fdddfe40be096ac19e8177/coverage-7.13.4-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8041b6c5bfdc03257666e9881d33b1abc88daccaf73f7b6340fb7946655cd10f", size = 248229, upload-time = "2026-02-09T12:56:16.31Z" },
- { url = "https://files.pythonhosted.org/packages/35/98/85aba0aed5126d896162087ef3f0e789a225697245256fc6181b95f47207/coverage-7.13.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a09cfa6a5862bc2fc6ca7c3def5b2926194a56b8ab78ffcf617d28911123012", size = 250106, upload-time = "2026-02-09T12:56:18.024Z" },
- { url = "https://files.pythonhosted.org/packages/96/72/1db59bd67494bc162e3e4cd5fbc7edba2c7026b22f7c8ef1496d58c2b94c/coverage-7.13.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:296f8b0af861d3970c2a4d8c91d48eb4dd4771bcef9baedec6a9b515d7de3def", size = 252021, upload-time = "2026-02-09T12:56:19.272Z" },
- { url = "https://files.pythonhosted.org/packages/9d/97/72899c59c7066961de6e3daa142d459d47d104956db43e057e034f015c8a/coverage-7.13.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e101609bcbbfb04605ea1027b10dc3735c094d12d40826a60f897b98b1c30256", size = 247114, upload-time = "2026-02-09T12:56:21.051Z" },
- { url = "https://files.pythonhosted.org/packages/39/1f/f1885573b5970235e908da4389176936c8933e86cb316b9620aab1585fa2/coverage-7.13.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aa3feb8db2e87ff5e6d00d7e1480ae241876286691265657b500886c98f38bda", size = 248143, upload-time = "2026-02-09T12:56:22.585Z" },
- { url = "https://files.pythonhosted.org/packages/a8/cf/e80390c5b7480b722fa3e994f8202807799b85bc562aa4f1dde209fbb7be/coverage-7.13.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4fc7fa81bbaf5a02801b65346c8b3e657f1d93763e58c0abdf7c992addd81a92", size = 246152, upload-time = "2026-02-09T12:56:23.748Z" },
- { url = "https://files.pythonhosted.org/packages/44/bf/f89a8350d85572f95412debb0fb9bb4795b1d5b5232bd652923c759e787b/coverage-7.13.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:33901f604424145c6e9c2398684b92e176c0b12df77d52db81c20abd48c3794c", size = 249959, upload-time = "2026-02-09T12:56:25.209Z" },
- { url = "https://files.pythonhosted.org/packages/f7/6e/612a02aece8178c818df273e8d1642190c4875402ca2ba74514394b27aba/coverage-7.13.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:bb28c0f2cf2782508a40cec377935829d5fcc3ad9a3681375af4e84eb34b6b58", size = 246416, upload-time = "2026-02-09T12:56:26.475Z" },
- { url = "https://files.pythonhosted.org/packages/cb/98/b5afc39af67c2fa6786b03c3a7091fc300947387ce8914b096db8a73d67a/coverage-7.13.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d107aff57a83222ddbd8d9ee705ede2af2cc926608b57abed8ef96b50b7e8f9", size = 247025, upload-time = "2026-02-09T12:56:27.727Z" },
- { url = "https://files.pythonhosted.org/packages/51/30/2bba8ef0682d5bd210c38fe497e12a06c9f8d663f7025e9f5c2c31ce847d/coverage-7.13.4-cp310-cp310-win32.whl", hash = "sha256:a6f94a7d00eb18f1b6d403c91a88fd58cfc92d4b16080dfdb774afc8294469bf", size = 221758, upload-time = "2026-02-09T12:56:29.051Z" },
- { url = "https://files.pythonhosted.org/packages/78/13/331f94934cf6c092b8ea59ff868eb587bc8fe0893f02c55bc6c0183a192e/coverage-7.13.4-cp310-cp310-win_amd64.whl", hash = "sha256:2cb0f1e000ebc419632bbe04366a8990b6e32c4e0b51543a6484ffe15eaeda95", size = 222693, upload-time = "2026-02-09T12:56:30.366Z" },
- { url = "https://files.pythonhosted.org/packages/b4/ad/b59e5b451cf7172b8d1043dc0fa718f23aab379bc1521ee13d4bd9bfa960/coverage-7.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d490ba50c3f35dd7c17953c68f3270e7ccd1c6642e2d2afe2d8e720b98f5a053", size = 219278, upload-time = "2026-02-09T12:56:31.673Z" },
- { url = "https://files.pythonhosted.org/packages/f1/17/0cb7ca3de72e5f4ef2ec2fa0089beafbcaaaead1844e8b8a63d35173d77d/coverage-7.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:19bc3c88078789f8ef36acb014d7241961dbf883fd2533d18cb1e7a5b4e28b11", size = 219783, upload-time = "2026-02-09T12:56:33.104Z" },
- { url = "https://files.pythonhosted.org/packages/ab/63/325d8e5b11e0eaf6d0f6a44fad444ae58820929a9b0de943fa377fe73e85/coverage-7.13.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3998e5a32e62fdf410c0dbd3115df86297995d6e3429af80b8798aad894ca7aa", size = 250200, upload-time = "2026-02-09T12:56:34.474Z" },
- { url = "https://files.pythonhosted.org/packages/76/53/c16972708cbb79f2942922571a687c52bd109a7bd51175aeb7558dff2236/coverage-7.13.4-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8e264226ec98e01a8e1054314af91ee6cde0eacac4f465cc93b03dbe0bce2fd7", size = 252114, upload-time = "2026-02-09T12:56:35.749Z" },
- { url = "https://files.pythonhosted.org/packages/eb/c2/7ab36d8b8cc412bec9ea2d07c83c48930eb4ba649634ba00cb7e4e0f9017/coverage-7.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3aa4e7b9e416774b21797365b358a6e827ffadaaca81b69ee02946852449f00", size = 254220, upload-time = "2026-02-09T12:56:37.796Z" },
- { url = "https://files.pythonhosted.org/packages/d6/4d/cf52c9a3322c89a0e6febdfbc83bb45c0ed3c64ad14081b9503adee702e7/coverage-7.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71ca20079dd8f27fcf808817e281e90220475cd75115162218d0e27549f95fef", size = 256164, upload-time = "2026-02-09T12:56:39.016Z" },
- { url = "https://files.pythonhosted.org/packages/78/e9/eb1dd17bd6de8289df3580e967e78294f352a5df8a57ff4671ee5fc3dcd0/coverage-7.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e2f25215f1a359ab17320b47bcdaca3e6e6356652e8256f2441e4ef972052903", size = 250325, upload-time = "2026-02-09T12:56:40.668Z" },
- { url = "https://files.pythonhosted.org/packages/71/07/8c1542aa873728f72267c07278c5cc0ec91356daf974df21335ccdb46368/coverage-7.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d65b2d373032411e86960604dc4edac91fdfb5dca539461cf2cbe78327d1e64f", size = 251913, upload-time = "2026-02-09T12:56:41.97Z" },
- { url = "https://files.pythonhosted.org/packages/74/d7/c62e2c5e4483a748e27868e4c32ad3daa9bdddbba58e1bc7a15e252baa74/coverage-7.13.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94eb63f9b363180aff17de3e7c8760c3ba94664ea2695c52f10111244d16a299", size = 249974, upload-time = "2026-02-09T12:56:43.323Z" },
- { url = "https://files.pythonhosted.org/packages/98/9f/4c5c015a6e98ced54efd0f5cf8d31b88e5504ecb6857585fc0161bb1e600/coverage-7.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e856bf6616714c3a9fbc270ab54103f4e685ba236fa98c054e8f87f266c93505", size = 253741, upload-time = "2026-02-09T12:56:45.155Z" },
- { url = "https://files.pythonhosted.org/packages/bd/59/0f4eef89b9f0fcd9633b5d350016f54126ab49426a70ff4c4e87446cabdc/coverage-7.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:65dfcbe305c3dfe658492df2d85259e0d79ead4177f9ae724b6fb245198f55d6", size = 249695, upload-time = "2026-02-09T12:56:46.636Z" },
- { url = "https://files.pythonhosted.org/packages/b5/2c/b7476f938deb07166f3eb281a385c262675d688ff4659ad56c6c6b8e2e70/coverage-7.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b507778ae8a4c915436ed5c2e05b4a6cecfa70f734e19c22a005152a11c7b6a9", size = 250599, upload-time = "2026-02-09T12:56:48.13Z" },
- { url = "https://files.pythonhosted.org/packages/b8/34/c3420709d9846ee3785b9f2831b4d94f276f38884032dca1457fa83f7476/coverage-7.13.4-cp311-cp311-win32.whl", hash = "sha256:784fc3cf8be001197b652d51d3fd259b1e2262888693a4636e18879f613a62a9", size = 221780, upload-time = "2026-02-09T12:56:50.479Z" },
- { url = "https://files.pythonhosted.org/packages/61/08/3d9c8613079d2b11c185b865de9a4c1a68850cfda2b357fae365cf609f29/coverage-7.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:2421d591f8ca05b308cf0092807308b2facbefe54af7c02ac22548b88b95c98f", size = 222715, upload-time = "2026-02-09T12:56:51.815Z" },
- { url = "https://files.pythonhosted.org/packages/18/1a/54c3c80b2f056164cc0a6cdcb040733760c7c4be9d780fe655f356f433e4/coverage-7.13.4-cp311-cp311-win_arm64.whl", hash = "sha256:79e73a76b854d9c6088fe5d8b2ebe745f8681c55f7397c3c0a016192d681045f", size = 221385, upload-time = "2026-02-09T12:56:53.194Z" },
- { url = "https://files.pythonhosted.org/packages/d1/81/4ce2fdd909c5a0ed1f6dedb88aa57ab79b6d1fbd9b588c1ac7ef45659566/coverage-7.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02231499b08dabbe2b96612993e5fc34217cdae907a51b906ac7fca8027a4459", size = 219449, upload-time = "2026-02-09T12:56:54.889Z" },
- { url = "https://files.pythonhosted.org/packages/5d/96/5238b1efc5922ddbdc9b0db9243152c09777804fb7c02ad1741eb18a11c0/coverage-7.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40aa8808140e55dc022b15d8aa7f651b6b3d68b365ea0398f1441e0b04d859c3", size = 219810, upload-time = "2026-02-09T12:56:56.33Z" },
- { url = "https://files.pythonhosted.org/packages/78/72/2f372b726d433c9c35e56377cf1d513b4c16fe51841060d826b95caacec1/coverage-7.13.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5b856a8ccf749480024ff3bd7310adaef57bf31fd17e1bfc404b7940b6986634", size = 251308, upload-time = "2026-02-09T12:56:57.858Z" },
- { url = "https://files.pythonhosted.org/packages/5d/a0/2ea570925524ef4e00bb6c82649f5682a77fac5ab910a65c9284de422600/coverage-7.13.4-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c048ea43875fbf8b45d476ad79f179809c590ec7b79e2035c662e7afa3192e3", size = 254052, upload-time = "2026-02-09T12:56:59.754Z" },
- { url = "https://files.pythonhosted.org/packages/e8/ac/45dc2e19a1939098d783c846e130b8f862fbb50d09e0af663988f2f21973/coverage-7.13.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b7b38448866e83176e28086674fe7368ab8590e4610fb662b44e345b86d63ffa", size = 255165, upload-time = "2026-02-09T12:57:01.287Z" },
- { url = "https://files.pythonhosted.org/packages/2d/4d/26d236ff35abc3b5e63540d3386e4c3b192168c1d96da5cb2f43c640970f/coverage-7.13.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:de6defc1c9badbf8b9e67ae90fd00519186d6ab64e5cc5f3d21359c2a9b2c1d3", size = 257432, upload-time = "2026-02-09T12:57:02.637Z" },
- { url = "https://files.pythonhosted.org/packages/ec/55/14a966c757d1348b2e19caf699415a2a4c4f7feaa4bbc6326a51f5c7dd1b/coverage-7.13.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7eda778067ad7ffccd23ecffce537dface96212576a07924cbf0d8799d2ded5a", size = 251716, upload-time = "2026-02-09T12:57:04.056Z" },
- { url = "https://files.pythonhosted.org/packages/77/33/50116647905837c66d28b2af1321b845d5f5d19be9655cb84d4a0ea806b4/coverage-7.13.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e87f6c587c3f34356c3759f0420693e35e7eb0e2e41e4c011cb6ec6ecbbf1db7", size = 253089, upload-time = "2026-02-09T12:57:05.503Z" },
- { url = "https://files.pythonhosted.org/packages/c2/b4/8efb11a46e3665d92635a56e4f2d4529de6d33f2cb38afd47d779d15fc99/coverage-7.13.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8248977c2e33aecb2ced42fef99f2d319e9904a36e55a8a68b69207fb7e43edc", size = 251232, upload-time = "2026-02-09T12:57:06.879Z" },
- { url = "https://files.pythonhosted.org/packages/51/24/8cd73dd399b812cc76bb0ac260e671c4163093441847ffe058ac9fda1e32/coverage-7.13.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:25381386e80ae727608e662474db537d4df1ecd42379b5ba33c84633a2b36d47", size = 255299, upload-time = "2026-02-09T12:57:08.245Z" },
- { url = "https://files.pythonhosted.org/packages/03/94/0a4b12f1d0e029ce1ccc1c800944a9984cbe7d678e470bb6d3c6bc38a0da/coverage-7.13.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:ee756f00726693e5ba94d6df2bdfd64d4852d23b09bb0bc700e3b30e6f333985", size = 250796, upload-time = "2026-02-09T12:57:10.142Z" },
- { url = "https://files.pythonhosted.org/packages/73/44/6002fbf88f6698ca034360ce474c406be6d5a985b3fdb3401128031eef6b/coverage-7.13.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fdfc1e28e7c7cdce44985b3043bc13bbd9c747520f94a4d7164af8260b3d91f0", size = 252673, upload-time = "2026-02-09T12:57:12.197Z" },
- { url = "https://files.pythonhosted.org/packages/de/c6/a0279f7c00e786be75a749a5674e6fa267bcbd8209cd10c9a450c655dfa7/coverage-7.13.4-cp312-cp312-win32.whl", hash = "sha256:01d4cbc3c283a17fc1e42d614a119f7f438eabb593391283adca8dc86eff1246", size = 221990, upload-time = "2026-02-09T12:57:14.085Z" },
- { url = "https://files.pythonhosted.org/packages/77/4e/c0a25a425fcf5557d9abd18419c95b63922e897bc86c1f327f155ef234a9/coverage-7.13.4-cp312-cp312-win_amd64.whl", hash = "sha256:9401ebc7ef522f01d01d45532c68c5ac40fb27113019b6b7d8b208f6e9baa126", size = 222800, upload-time = "2026-02-09T12:57:15.944Z" },
- { url = "https://files.pythonhosted.org/packages/47/ac/92da44ad9a6f4e3a7debd178949d6f3769bedca33830ce9b1dcdab589a37/coverage-7.13.4-cp312-cp312-win_arm64.whl", hash = "sha256:b1ec7b6b6e93255f952e27ab58fbc68dcc468844b16ecbee881aeb29b6ab4d8d", size = 221415, upload-time = "2026-02-09T12:57:17.497Z" },
- { url = "https://files.pythonhosted.org/packages/0d/4a/331fe2caf6799d591109bb9c08083080f6de90a823695d412a935622abb2/coverage-7.13.4-py3-none-any.whl", hash = "sha256:1af1641e57cf7ba1bd67d677c9abdbcd6cc2ab7da3bca7fa1e2b7e50e65f2ad0", size = 211242, upload-time = "2026-02-09T12:59:02.032Z" },
+sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/69/33/e8c48488c29a73fd089f9d71f9653c1be7478f2ad6b5bc870db11a55d23d/coverage-7.13.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0723d2c96324561b9aa76fb982406e11d93cdb388a7a7da2b16e04719cf7ca5", size = 219255, upload-time = "2026-03-17T10:29:51.081Z" },
+ { url = "https://files.pythonhosted.org/packages/da/bd/b0ebe9f677d7f4b74a3e115eec7ddd4bcf892074963a00d91e8b164a6386/coverage-7.13.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52f444e86475992506b32d4e5ca55c24fc88d73bcbda0e9745095b28ef4dc0cf", size = 219772, upload-time = "2026-03-17T10:29:52.867Z" },
+ { url = "https://files.pythonhosted.org/packages/48/cc/5cb9502f4e01972f54eedd48218bb203fe81e294be606a2bc93970208013/coverage-7.13.5-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:704de6328e3d612a8f6c07000a878ff38181ec3263d5a11da1db294fa6a9bdf8", size = 246532, upload-time = "2026-03-17T10:29:54.688Z" },
+ { url = "https://files.pythonhosted.org/packages/7d/d8/3217636d86c7e7b12e126e4f30ef1581047da73140614523af7495ed5f2d/coverage-7.13.5-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a1a6d79a14e1ec1832cabc833898636ad5f3754a678ef8bb4908515208bf84f4", size = 248333, upload-time = "2026-03-17T10:29:56.221Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/30/2002ac6729ba2d4357438e2ed3c447ad8562866c8c63fc16f6dfc33afe56/coverage-7.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79060214983769c7ba3f0cee10b54c97609dca4d478fa1aa32b914480fd5738d", size = 250211, upload-time = "2026-03-17T10:29:57.938Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/85/552496626d6b9359eb0e2f86f920037c9cbfba09b24d914c6e1528155f7d/coverage-7.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:356e76b46783a98c2a2fe81ec79df4883a1e62895ea952968fb253c114e7f930", size = 252125, upload-time = "2026-03-17T10:29:59.388Z" },
+ { url = "https://files.pythonhosted.org/packages/44/21/40256eabdcbccdb6acf6b381b3016a154399a75fe39d406f790ae84d1f3c/coverage-7.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0cef0cdec915d11254a7f549c1170afecce708d30610c6abdded1f74e581666d", size = 247219, upload-time = "2026-03-17T10:30:01.199Z" },
+ { url = "https://files.pythonhosted.org/packages/b1/e8/96e2a6c3f21a0ea77d7830b254a1542d0328acc8d7bdf6a284ba7e529f77/coverage-7.13.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dc022073d063b25a402454e5712ef9e007113e3a676b96c5f29b2bda29352f40", size = 248248, upload-time = "2026-03-17T10:30:03.317Z" },
+ { url = "https://files.pythonhosted.org/packages/da/ba/8477f549e554827da390ec659f3c38e4b6d95470f4daafc2d8ff94eaa9c2/coverage-7.13.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9b74db26dfea4f4e50d48a4602207cd1e78be33182bc9cbf22da94f332f99878", size = 246254, upload-time = "2026-03-17T10:30:04.832Z" },
+ { url = "https://files.pythonhosted.org/packages/55/59/bc22aef0e6aa179d5b1b001e8b3654785e9adf27ef24c93dc4228ebd5d68/coverage-7.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ad146744ca4fd09b50c482650e3c1b1f4dfa1d4792e0a04a369c7f23336f0400", size = 250067, upload-time = "2026-03-17T10:30:06.535Z" },
+ { url = "https://files.pythonhosted.org/packages/de/1b/c6a023a160806a5137dca53468fd97530d6acad24a22003b1578a9c2e429/coverage-7.13.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:c555b48be1853fe3997c11c4bd521cdd9a9612352de01fa4508f16ec341e6fe0", size = 246521, upload-time = "2026-03-17T10:30:08.486Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/3f/3532c85a55aa2f899fa17c186f831cfa1aa434d88ff792a709636f64130e/coverage-7.13.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7034b5c56a58ae5e85f23949d52c14aca2cfc6848a31764995b7de88f13a1ea0", size = 247126, upload-time = "2026-03-17T10:30:09.966Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/2e/b9d56af4a24ef45dfbcda88e06870cb7d57b2b0bfa3a888d79b4c8debd76/coverage-7.13.5-cp310-cp310-win32.whl", hash = "sha256:eb7fdf1ef130660e7415e0253a01a7d5a88c9c4d158bcf75cbbd922fd65a5b58", size = 221860, upload-time = "2026-03-17T10:30:11.393Z" },
+ { url = "https://files.pythonhosted.org/packages/9f/cc/d938417e7a4d7f0433ad4edee8bb2acdc60dc7ac5af19e2a07a048ecbee3/coverage-7.13.5-cp310-cp310-win_amd64.whl", hash = "sha256:3e1bb5f6c78feeb1be3475789b14a0f0a5b47d505bfc7267126ccbd50289999e", size = 222788, upload-time = "2026-03-17T10:30:12.886Z" },
+ { url = "https://files.pythonhosted.org/packages/4b/37/d24c8f8220ff07b839b2c043ea4903a33b0f455abe673ae3c03bbdb7f212/coverage-7.13.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66a80c616f80181f4d643b0f9e709d97bcea413ecd9631e1dedc7401c8e6695d", size = 219381, upload-time = "2026-03-17T10:30:14.68Z" },
+ { url = "https://files.pythonhosted.org/packages/35/8b/cd129b0ca4afe886a6ce9d183c44d8301acbd4ef248622e7c49a23145605/coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:145ede53ccbafb297c1c9287f788d1bc3efd6c900da23bf6931b09eafc931587", size = 219880, upload-time = "2026-03-17T10:30:16.231Z" },
+ { url = "https://files.pythonhosted.org/packages/55/2f/e0e5b237bffdb5d6c530ce87cc1d413a5b7d7dfd60fb067ad6d254c35c76/coverage-7.13.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0672854dc733c342fa3e957e0605256d2bf5934feeac328da9e0b5449634a642", size = 250303, upload-time = "2026-03-17T10:30:17.748Z" },
+ { url = "https://files.pythonhosted.org/packages/92/be/b1afb692be85b947f3401375851484496134c5554e67e822c35f28bf2fbc/coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ec10e2a42b41c923c2209b846126c6582db5e43a33157e9870ba9fb70dc7854b", size = 252218, upload-time = "2026-03-17T10:30:19.804Z" },
+ { url = "https://files.pythonhosted.org/packages/da/69/2f47bb6fa1b8d1e3e5d0c4be8ccb4313c63d742476a619418f85740d597b/coverage-7.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be3d4bbad9d4b037791794ddeedd7d64a56f5933a2c1373e18e9e568b9141686", size = 254326, upload-time = "2026-03-17T10:30:21.321Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/d0/79db81da58965bd29dabc8f4ad2a2af70611a57cba9d1ec006f072f30a54/coverage-7.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d2afbc5cc54d286bfb54541aa50b64cdb07a718227168c87b9e2fb8f25e1743", size = 256267, upload-time = "2026-03-17T10:30:23.094Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/32/d0d7cc8168f91ddab44c0ce4806b969df5f5fdfdbb568eaca2dbc2a04936/coverage-7.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ad050321264c49c2fa67bb599100456fc51d004b82534f379d16445da40fb75", size = 250430, upload-time = "2026-03-17T10:30:25.311Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/06/a055311d891ddbe231cd69fdd20ea4be6e3603ffebddf8704b8ca8e10a3c/coverage-7.13.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7300c8a6d13335b29bb76d7651c66af6bd8658517c43499f110ddc6717bfc209", size = 252017, upload-time = "2026-03-17T10:30:27.284Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/f6/d0fd2d21e29a657b5f77a2fe7082e1568158340dceb941954f776dce1b7b/coverage-7.13.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eb07647a5738b89baab047f14edd18ded523de60f3b30e75c2acc826f79c839a", size = 250080, upload-time = "2026-03-17T10:30:29.481Z" },
+ { url = "https://files.pythonhosted.org/packages/4e/ab/0d7fb2efc2e9a5eb7ddcc6e722f834a69b454b7e6e5888c3a8567ecffb31/coverage-7.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9adb6688e3b53adffefd4a52d72cbd8b02602bfb8f74dcd862337182fd4d1a4e", size = 253843, upload-time = "2026-03-17T10:30:31.301Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/6f/7467b917bbf5408610178f62a49c0ed4377bb16c1657f689cc61470da8ce/coverage-7.13.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7c8d4bc913dd70b93488d6c496c77f3aff5ea99a07e36a18f865bca55adef8bd", size = 249802, upload-time = "2026-03-17T10:30:33.358Z" },
+ { url = "https://files.pythonhosted.org/packages/75/2c/1172fb689df92135f5bfbbd69fc83017a76d24ea2e2f3a1154007e2fb9f8/coverage-7.13.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e3c426ffc4cd952f54ee9ffbdd10345709ecc78a3ecfd796a57236bfad0b9b8", size = 250707, upload-time = "2026-03-17T10:30:35.2Z" },
+ { url = "https://files.pythonhosted.org/packages/67/21/9ac389377380a07884e3b48ba7a620fcd9dbfaf1d40565facdc6b36ec9ef/coverage-7.13.5-cp311-cp311-win32.whl", hash = "sha256:259b69bb83ad9894c4b25be2528139eecba9a82646ebdda2d9db1ba28424a6bf", size = 221880, upload-time = "2026-03-17T10:30:36.775Z" },
+ { url = "https://files.pythonhosted.org/packages/af/7f/4cd8a92531253f9d7c1bbecd9fa1b472907fb54446ca768c59b531248dc5/coverage-7.13.5-cp311-cp311-win_amd64.whl", hash = "sha256:258354455f4e86e3e9d0d17571d522e13b4e1e19bf0f8596bcf9476d61e7d8a9", size = 222816, upload-time = "2026-03-17T10:30:38.891Z" },
+ { url = "https://files.pythonhosted.org/packages/12/a6/1d3f6155fb0010ca68eba7fe48ca6c9da7385058b77a95848710ecf189b1/coverage-7.13.5-cp311-cp311-win_arm64.whl", hash = "sha256:bff95879c33ec8da99fc9b6fe345ddb5be6414b41d6d1ad1c8f188d26f36e028", size = 221483, upload-time = "2026-03-17T10:30:40.463Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/c3/a396306ba7db865bf96fc1fb3b7fd29bcbf3d829df642e77b13555163cd6/coverage-7.13.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:460cf0114c5016fa841214ff5564aa4864f11948da9440bc97e21ad1f4ba1e01", size = 219554, upload-time = "2026-03-17T10:30:42.208Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/16/a68a19e5384e93f811dccc51034b1fd0b865841c390e3c931dcc4699e035/coverage-7.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e223ce4b4ed47f065bfb123687686512e37629be25cc63728557ae7db261422", size = 219908, upload-time = "2026-03-17T10:30:43.906Z" },
+ { url = "https://files.pythonhosted.org/packages/29/72/20b917c6793af3a5ceb7fb9c50033f3ec7865f2911a1416b34a7cfa0813b/coverage-7.13.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6e3370441f4513c6252bf042b9c36d22491142385049243253c7e48398a15a9f", size = 251419, upload-time = "2026-03-17T10:30:45.545Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/49/cd14b789536ac6a4778c453c6a2338bc0a2fb60c5a5a41b4008328b9acc1/coverage-7.13.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:03ccc709a17a1de074fb1d11f217342fb0d2b1582ed544f554fc9fc3f07e95f5", size = 254159, upload-time = "2026-03-17T10:30:47.204Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/00/7b0edcfe64e2ed4c0340dac14a52ad0f4c9bd0b8b5e531af7d55b703db7c/coverage-7.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f4818d065964db3c1c66dc0fbdac5ac692ecbc875555e13374fdbe7eedb4376", size = 255270, upload-time = "2026-03-17T10:30:48.812Z" },
+ { url = "https://files.pythonhosted.org/packages/93/89/7ffc4ba0f5d0a55c1e84ea7cee39c9fc06af7b170513d83fbf3bbefce280/coverage-7.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:012d5319e66e9d5a218834642d6c35d265515a62f01157a45bcc036ecf947256", size = 257538, upload-time = "2026-03-17T10:30:50.77Z" },
+ { url = "https://files.pythonhosted.org/packages/81/bd/73ddf85f93f7e6fa83e77ccecb6162d9415c79007b4bc124008a4995e4a7/coverage-7.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8dd02af98971bdb956363e4827d34425cb3df19ee550ef92855b0acb9c7ce51c", size = 251821, upload-time = "2026-03-17T10:30:52.5Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/81/278aff4e8dec4926a0bcb9486320752811f543a3ce5b602cc7a29978d073/coverage-7.13.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f08fd75c50a760c7eb068ae823777268daaf16a80b918fa58eea888f8e3919f5", size = 253191, upload-time = "2026-03-17T10:30:54.543Z" },
+ { url = "https://files.pythonhosted.org/packages/70/ee/fe1621488e2e0a58d7e94c4800f0d96f79671553488d401a612bebae324b/coverage-7.13.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:843ea8643cf967d1ac7e8ecd4bb00c99135adf4816c0c0593fdcc47b597fcf09", size = 251337, upload-time = "2026-03-17T10:30:56.663Z" },
+ { url = "https://files.pythonhosted.org/packages/37/a6/f79fb37aa104b562207cc23cb5711ab6793608e246cae1e93f26b2236ed9/coverage-7.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:9d44d7aa963820b1b971dbecd90bfe5fe8f81cff79787eb6cca15750bd2f79b9", size = 255404, upload-time = "2026-03-17T10:30:58.427Z" },
+ { url = "https://files.pythonhosted.org/packages/75/f0/ed15262a58ec81ce457ceb717b7f78752a1713556b19081b76e90896e8d4/coverage-7.13.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7132bed4bd7b836200c591410ae7d97bf7ae8be6fc87d160b2bd881df929e7bf", size = 250903, upload-time = "2026-03-17T10:31:00.093Z" },
+ { url = "https://files.pythonhosted.org/packages/0f/e9/9129958f20e7e9d4d56d51d42ccf708d15cac355ff4ac6e736e97a9393d2/coverage-7.13.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a698e363641b98843c517817db75373c83254781426e94ada3197cabbc2c919c", size = 252780, upload-time = "2026-03-17T10:31:01.916Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/d7/0ad9b15812d81272db94379fe4c6df8fd17781cc7671fdfa30c76ba5ff7b/coverage-7.13.5-cp312-cp312-win32.whl", hash = "sha256:bdba0a6b8812e8c7df002d908a9a2ea3c36e92611b5708633c50869e6d922fdf", size = 222093, upload-time = "2026-03-17T10:31:03.642Z" },
+ { url = "https://files.pythonhosted.org/packages/29/3d/821a9a5799fac2556bcf0bd37a70d1d11fa9e49784b6d22e92e8b2f85f18/coverage-7.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:d2c87e0c473a10bffe991502eac389220533024c8082ec1ce849f4218dded810", size = 222900, upload-time = "2026-03-17T10:31:05.651Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/fa/2238c2ad08e35cf4f020ea721f717e09ec3152aea75d191a7faf3ef009a8/coverage-7.13.5-cp312-cp312-win_arm64.whl", hash = "sha256:bf69236a9a81bdca3bff53796237aab096cdbf8d78a66ad61e992d9dac7eb2de", size = 221515, upload-time = "2026-03-17T10:31:07.293Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" },
]
[package.optional-dependencies]
@@ -822,7 +824,7 @@ resolution-markers = [
"python_full_version == '3.10.*'",
]
dependencies = [
- { name = "coverage", version = "7.13.4", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" },
+ { name = "coverage", version = "7.13.5", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" },
{ name = "requests", marker = "python_full_version >= '3.10'" },
{ name = "typer", marker = "python_full_version >= '3.10'" },
]
@@ -897,7 +899,7 @@ wheels = [
[[package]]
name = "cyclonedx-python-lib"
-version = "11.6.0"
+version = "11.7.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
@@ -911,9 +913,9 @@ dependencies = [
{ name = "sortedcontainers", marker = "python_full_version >= '3.10'" },
{ name = "typing-extensions", marker = "python_full_version >= '3.10'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/89/ed/54ecfa25fc145c58bf4f98090f7b6ffe5188d0759248c57dde44427ea239/cyclonedx_python_lib-11.6.0.tar.gz", hash = "sha256:7fb85a4371fa3a203e5be577ac22b7e9a7157f8b0058b7448731474d6dea7bf0", size = 1408147, upload-time = "2025-12-02T12:28:46.446Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/21/0d/64f02d3fd9c116d6f50a540d04d1e4f2e3c487f5062d2db53733ddb25917/cyclonedx_python_lib-11.7.0.tar.gz", hash = "sha256:fb1bc3dedfa31208444dbd743007f478ab6984010a184e5bd466bffd969e936e", size = 1411174, upload-time = "2026-03-17T15:19:16.606Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/c7/1b/534ad8a5e0f9470522811a8e5a9bc5d328fb7738ba29faf357467a4ef6d0/cyclonedx_python_lib-11.6.0-py3-none-any.whl", hash = "sha256:94f4aae97db42a452134dafdddcfab9745324198201c4777ed131e64c8380759", size = 511157, upload-time = "2025-12-02T12:28:44.158Z" },
+ { url = "https://files.pythonhosted.org/packages/30/09/fe0e3bc32bd33707c519b102fc064ad2a2ce5a1b53e2be38b86936b476b1/cyclonedx_python_lib-11.7.0-py3-none-any.whl", hash = "sha256:02fa4f15ddbba21ac9093039f8137c0d1813af7fe88b760c5dcd3311a8da2178", size = 513041, upload-time = "2026-03-17T15:19:14.369Z" },
]
[[package]]
@@ -1045,15 +1047,35 @@ wheels = [
name = "edtf"
version = "5.0.0"
source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
dependencies = [
- { name = "pyparsing" },
- { name = "python-dateutil" },
+ { name = "pyparsing", marker = "python_full_version < '3.10'" },
+ { name = "python-dateutil", marker = "python_full_version < '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7b/24/0a9053bea41c2860046416f3d136283233ce307adb218d406dede64a8fac/edtf-5.0.0.tar.gz", hash = "sha256:7393c570b4838c8cbc05b0687c6ea0578039ba007c8ce125206f44f18f2dea5d", size = 45617, upload-time = "2024-07-18T08:01:52.882Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/08/746096971fae3585928a631912bdd4393f5ab5696706bd34cbdcccf763fc/edtf-5.0.0-py3-none-any.whl", hash = "sha256:b38ca29fa166a5c628b899a76e73a9f4cc732da565b85e737af4c0e457775f5e", size = 40319, upload-time = "2024-07-18T08:01:50.873Z" },
]
+[[package]]
+name = "edtf"
+version = "5.0.1"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.12'",
+ "python_full_version == '3.11.*'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "pyparsing", marker = "python_full_version >= '3.10'" },
+ { name = "python-dateutil", marker = "python_full_version >= '3.10'" },
+]
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/76/23/e9f69255f67f55b03e2705bfd7a579a01c26146b9ea98f9cdb07d8156b4d/edtf-5.0.1-py3-none-any.whl", hash = "sha256:d3ed8c1307330d7563ae9efc4193988acddeb60dcfb740d4fe0abe739ef0944a", size = 36776, upload-time = "2026-03-15T03:22:56.53Z" },
+]
+
[[package]]
name = "elasticsearch"
version = "7.13.4"
@@ -1139,16 +1161,16 @@ wheels = [
[[package]]
name = "filelock"
-version = "3.25.0"
+version = "3.25.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
"python_full_version == '3.11.*'",
"python_full_version == '3.10.*'",
]
-sdist = { url = "https://files.pythonhosted.org/packages/77/18/a1fd2231c679dcb9726204645721b12498aeac28e1ad0601038f94b42556/filelock-3.25.0.tar.gz", hash = "sha256:8f00faf3abf9dc730a1ffe9c354ae5c04e079ab7d3a683b7c32da5dd05f26af3", size = 40158, upload-time = "2026-03-01T15:08:45.916Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl", hash = "sha256:5ccf8069f7948f494968fc0713c10e5c182a9c9d9eef3a636307a20c2490f047", size = 26427, upload-time = "2026-03-01T15:08:44.593Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" },
]
[[package]]
@@ -1159,7 +1181,7 @@ dependencies = [
{ name = "blinker" },
{ name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "click", version = "8.3.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "itsdangerous" },
{ name = "jinja2" },
{ name = "markupsafe" },
@@ -1546,40 +1568,40 @@ wheels = [
[[package]]
name = "fonttools"
-version = "4.61.1"
+version = "4.62.1"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
"python_full_version == '3.11.*'",
"python_full_version == '3.10.*'",
]
-sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799, upload-time = "2025-12-12T17:29:27.5Z" },
- { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032, upload-time = "2025-12-12T17:29:30.115Z" },
- { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863, upload-time = "2025-12-12T17:29:32.535Z" },
- { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076, upload-time = "2025-12-12T17:29:34.907Z" },
- { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623, upload-time = "2025-12-12T17:29:37.33Z" },
- { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327, upload-time = "2025-12-12T17:29:39.781Z" },
- { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180, upload-time = "2025-12-12T17:29:42.217Z" },
- { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654, upload-time = "2025-12-12T17:29:44.564Z" },
- { url = "https://files.pythonhosted.org/packages/69/12/bf9f4eaa2fad039356cc627587e30ed008c03f1cebd3034376b5ee8d1d44/fonttools-4.61.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09", size = 2852213, upload-time = "2025-12-12T17:29:46.675Z" },
- { url = "https://files.pythonhosted.org/packages/ac/49/4138d1acb6261499bedde1c07f8c2605d1d8f9d77a151e5507fd3ef084b6/fonttools-4.61.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37", size = 2401689, upload-time = "2025-12-12T17:29:48.769Z" },
- { url = "https://files.pythonhosted.org/packages/e5/fe/e6ce0fe20a40e03aef906af60aa87668696f9e4802fa283627d0b5ed777f/fonttools-4.61.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb", size = 5058809, upload-time = "2025-12-12T17:29:51.701Z" },
- { url = "https://files.pythonhosted.org/packages/79/61/1ca198af22f7dd22c17ab86e9024ed3c06299cfdb08170640e9996d501a0/fonttools-4.61.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9", size = 5036039, upload-time = "2025-12-12T17:29:53.659Z" },
- { url = "https://files.pythonhosted.org/packages/99/cc/fa1801e408586b5fce4da9f5455af8d770f4fc57391cd5da7256bb364d38/fonttools-4.61.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87", size = 5034714, upload-time = "2025-12-12T17:29:55.592Z" },
- { url = "https://files.pythonhosted.org/packages/bf/aa/b7aeafe65adb1b0a925f8f25725e09f078c635bc22754f3fecb7456955b0/fonttools-4.61.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56", size = 5158648, upload-time = "2025-12-12T17:29:57.861Z" },
- { url = "https://files.pythonhosted.org/packages/99/f9/08ea7a38663328881384c6e7777bbefc46fd7d282adfd87a7d2b84ec9d50/fonttools-4.61.1-cp311-cp311-win32.whl", hash = "sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a", size = 2280681, upload-time = "2025-12-12T17:29:59.943Z" },
- { url = "https://files.pythonhosted.org/packages/07/ad/37dd1ae5fa6e01612a1fbb954f0927681f282925a86e86198ccd7b15d515/fonttools-4.61.1-cp311-cp311-win_amd64.whl", hash = "sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7", size = 2331951, upload-time = "2025-12-12T17:30:02.254Z" },
- { url = "https://files.pythonhosted.org/packages/6f/16/7decaa24a1bd3a70c607b2e29f0adc6159f36a7e40eaba59846414765fd4/fonttools-4.61.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e", size = 2851593, upload-time = "2025-12-12T17:30:04.225Z" },
- { url = "https://files.pythonhosted.org/packages/94/98/3c4cb97c64713a8cf499b3245c3bf9a2b8fd16a3e375feff2aed78f96259/fonttools-4.61.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2", size = 2400231, upload-time = "2025-12-12T17:30:06.47Z" },
- { url = "https://files.pythonhosted.org/packages/b7/37/82dbef0f6342eb01f54bca073ac1498433d6ce71e50c3c3282b655733b31/fonttools-4.61.1-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796", size = 4954103, upload-time = "2025-12-12T17:30:08.432Z" },
- { url = "https://files.pythonhosted.org/packages/6c/44/f3aeac0fa98e7ad527f479e161aca6c3a1e47bb6996b053d45226fe37bf2/fonttools-4.61.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d", size = 5004295, upload-time = "2025-12-12T17:30:10.56Z" },
- { url = "https://files.pythonhosted.org/packages/14/e8/7424ced75473983b964d09f6747fa09f054a6d656f60e9ac9324cf40c743/fonttools-4.61.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8", size = 4944109, upload-time = "2025-12-12T17:30:12.874Z" },
- { url = "https://files.pythonhosted.org/packages/c8/8b/6391b257fa3d0b553d73e778f953a2f0154292a7a7a085e2374b111e5410/fonttools-4.61.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0", size = 5093598, upload-time = "2025-12-12T17:30:15.79Z" },
- { url = "https://files.pythonhosted.org/packages/d9/71/fd2ea96cdc512d92da5678a1c98c267ddd4d8c5130b76d0f7a80f9a9fde8/fonttools-4.61.1-cp312-cp312-win32.whl", hash = "sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261", size = 2269060, upload-time = "2025-12-12T17:30:18.058Z" },
- { url = "https://files.pythonhosted.org/packages/80/3b/a3e81b71aed5a688e89dfe0e2694b26b78c7d7f39a5ffd8a7d75f54a12a8/fonttools-4.61.1-cp312-cp312-win_amd64.whl", hash = "sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9", size = 2319078, upload-time = "2025-12-12T17:30:22.862Z" },
- { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" },
+sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/5a/ff/532ed43808b469c807e8cb6b21358da3fe6fd51486b3a8c93db0bb5d957f/fonttools-4.62.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ad5cca75776cd453b1b035b530e943334957ae152a36a88a320e779d61fc980c", size = 2873740, upload-time = "2026-03-13T13:52:11.822Z" },
+ { url = "https://files.pythonhosted.org/packages/85/e4/2318d2b430562da7227010fb2bb029d2fa54d7b46443ae8942bab224e2a0/fonttools-4.62.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0b3ae47e8636156a9accff64c02c0924cbebad62854c4a6dbdc110cd5b4b341a", size = 2417649, upload-time = "2026-03-13T13:52:14.605Z" },
+ { url = "https://files.pythonhosted.org/packages/4c/28/40f15523b5188598018e7956899fed94eb7debec89e2dd70cb4a8df90492/fonttools-4.62.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b9e288b4da2f64fd6180644221749de651703e8d0c16bd4b719533a3a7d6e3", size = 4935213, upload-time = "2026-03-13T13:52:17.399Z" },
+ { url = "https://files.pythonhosted.org/packages/42/09/7dbe3d7023f57d9b580cfa832109d521988112fd59dddfda3fddda8218f9/fonttools-4.62.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7bca7a1c1faf235ffe25d4f2e555246b4750220b38de8261d94ebc5ce8a23c23", size = 4892374, upload-time = "2026-03-13T13:52:20.175Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/2d/84509a2e32cb925371560ef5431365d8da2183c11d98e5b4b8b4e42426a5/fonttools-4.62.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b4e0fcf265ad26e487c56cb12a42dffe7162de708762db951e1b3f755319507d", size = 4911856, upload-time = "2026-03-13T13:52:22.777Z" },
+ { url = "https://files.pythonhosted.org/packages/a5/80/df28131379eed93d9e6e6fccd3bf6e3d077bebbfe98cc83f21bbcd83ed02/fonttools-4.62.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2d850f66830a27b0d498ee05adb13a3781637b1826982cd7e2b3789ef0cc71ae", size = 5031712, upload-time = "2026-03-13T13:52:25.14Z" },
+ { url = "https://files.pythonhosted.org/packages/3d/03/3c8f09aad64230cd6d921ae7a19f9603c36f70930b00459f112706f6769a/fonttools-4.62.1-cp310-cp310-win32.whl", hash = "sha256:486f32c8047ccd05652aba17e4a8819a3a9d78570eb8a0e3b4503142947880ed", size = 1507878, upload-time = "2026-03-13T13:52:28.149Z" },
+ { url = "https://files.pythonhosted.org/packages/dd/ec/f53f626f8f3e89f4cadd8fc08f3452c8fd182c951ad5caa35efac22b29ab/fonttools-4.62.1-cp310-cp310-win_amd64.whl", hash = "sha256:5a648bde915fba9da05ae98856987ca91ba832949a9e2888b48c47ef8b96c5a9", size = 1556766, upload-time = "2026-03-13T13:52:30.814Z" },
+ { url = "https://files.pythonhosted.org/packages/88/39/23ff32561ec8d45a4d48578b4d241369d9270dc50926c017570e60893701/fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:40975849bac44fb0b9253d77420c6d8b523ac4dcdcefeff6e4d706838a5b80f7", size = 2871039, upload-time = "2026-03-13T13:52:33.127Z" },
+ { url = "https://files.pythonhosted.org/packages/24/7f/66d3f8a9338a9b67fe6e1739f47e1cd5cee78bd3bc1206ef9b0b982289a5/fonttools-4.62.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9dde91633f77fa576879a0c76b1d89de373cae751a98ddf0109d54e173b40f14", size = 2416346, upload-time = "2026-03-13T13:52:35.676Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/53/5276ceba7bff95da7793a07c5284e1da901cf00341ce5e2f3273056c0cca/fonttools-4.62.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6acb4109f8bee00fec985c8c7afb02299e35e9c94b57287f3ea542f28bd0b0a7", size = 5100897, upload-time = "2026-03-13T13:52:38.102Z" },
+ { url = "https://files.pythonhosted.org/packages/cc/a1/40a5c4d8e28b0851d53a8eeeb46fbd73c325a2a9a165f290a5ed90e6c597/fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1c5c25671ce8805e0d080e2ffdeca7f1e86778c5cbfbeae86d7f866d8830517b", size = 5071078, upload-time = "2026-03-13T13:52:41.305Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/be/d378fca4c65ea1956fee6d90ace6e861776809cbbc5af22388a090c3c092/fonttools-4.62.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a5d8825e1140f04e6c99bb7d37a9e31c172f3bc208afbe02175339e699c710e1", size = 5076908, upload-time = "2026-03-13T13:52:44.122Z" },
+ { url = "https://files.pythonhosted.org/packages/f8/d9/ae6a1d0693a4185a84605679c8a1f719a55df87b9c6e8e817bfdd9ef5936/fonttools-4.62.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:268abb1cb221e66c014acc234e872b7870d8b5d4657a83a8f4205094c32d2416", size = 5202275, upload-time = "2026-03-13T13:52:46.591Z" },
+ { url = "https://files.pythonhosted.org/packages/54/6c/af95d9c4efb15cabff22642b608342f2bd67137eea6107202d91b5b03184/fonttools-4.62.1-cp311-cp311-win32.whl", hash = "sha256:942b03094d7edbb99bdf1ae7e9090898cad7bf9030b3d21f33d7072dbcb51a53", size = 2293075, upload-time = "2026-03-13T13:52:48.711Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/97/bf54c5b3f2be34e1f143e6db838dfdc54f2ffa3e68c738934c82f3b2a08d/fonttools-4.62.1-cp311-cp311-win_amd64.whl", hash = "sha256:e8514f4924375f77084e81467e63238b095abda5107620f49421c368a6017ed2", size = 2344593, upload-time = "2026-03-13T13:52:50.725Z" },
+ { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", size = 2870219, upload-time = "2026-03-13T13:52:53.664Z" },
+ { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", size = 2414891, upload-time = "2026-03-13T13:52:56.493Z" },
+ { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", size = 5033197, upload-time = "2026-03-13T13:52:59.179Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", size = 4988768, upload-time = "2026-03-13T13:53:02.761Z" },
+ { url = "https://files.pythonhosted.org/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", size = 4971512, upload-time = "2026-03-13T13:53:05.678Z" },
+ { url = "https://files.pythonhosted.org/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", size = 5122723, upload-time = "2026-03-13T13:53:08.662Z" },
+ { url = "https://files.pythonhosted.org/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", size = 2281278, upload-time = "2026-03-13T13:53:10.998Z" },
+ { url = "https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", size = 2331414, upload-time = "2026-03-13T13:53:13.992Z" },
+ { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" },
]
[[package]]
@@ -1610,7 +1632,7 @@ resolution-markers = [
]
dependencies = [
{ name = "defusedxml", marker = "python_full_version >= '3.10'" },
- { name = "fonttools", version = "4.61.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "fonttools", version = "4.62.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pillow", version = "12.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/27/f2/72feae0b2827ed38013e4307b14f95bf0b3d124adfef4d38a7d57533f7be/fpdf2-2.8.7.tar.gz", hash = "sha256:7060ccee5a9c7ab0a271fb765a36a23639f83ef8996c34e3d46af0a17ede57f9", size = 362351, upload-time = "2026-02-28T05:39:16.456Z" }
@@ -1807,28 +1829,48 @@ wheels = [
[[package]]
name = "idutils"
-version = "1.5.1"
+version = "1.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "isbnlib" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/ce/be/114efec47bd7b4b6e7ba4819e27e0ff1cba13bbd3c829bae5a31d12f82a5/idutils-1.5.1.tar.gz", hash = "sha256:d010750b10c0f516509614fc2997da619ab95585f9f2fe3bc149e5819d3acfd7", size = 35001, upload-time = "2025-12-16T15:57:44.826Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/06/ea/97f631ea64e756bbbd4b17c3e8173033321fb39527da8bfd5b5b8332fdd4/idutils-1.6.0.tar.gz", hash = "sha256:dfffe30a6abdba85b1710ef3bb469ae586f72a3db3f36217b82213ed8de32f85", size = 35905, upload-time = "2026-03-19T07:49:10.553Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9c/d4/0b075ed2e75ffbb4ec5ac927be4f10a5c349d8e5642f0499e40e931a1c06/idutils-1.5.1-py2.py3-none-any.whl", hash = "sha256:bbeb5dd8d7d803e69a32d825ae2d3dd1bf33b271cc06de06e3e83f2b93fc74c5", size = 24080, upload-time = "2025-12-16T15:57:43.456Z" },
+ { url = "https://files.pythonhosted.org/packages/5f/25/eb953116f129414fb21f563c0253efda09fbc482507cede686005a5026a4/idutils-1.6.0-py2.py3-none-any.whl", hash = "sha256:fe84d9d837c16f1ec9062687fa8bdc133fcbdab6365f894511e67b2aaa1849d7", size = 24654, upload-time = "2026-03-19T07:49:09.07Z" },
]
[[package]]
name = "importlib-metadata"
version = "8.7.1"
source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
dependencies = [
- { name = "zipp" },
+ { name = "zipp", marker = "python_full_version < '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" },
]
+[[package]]
+name = "importlib-metadata"
+version = "9.0.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.12'",
+ "python_full_version == '3.11.*'",
+ "python_full_version == '3.10.*'",
+]
+dependencies = [
+ { name = "zipp", marker = "python_full_version >= '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" },
+]
+
[[package]]
name = "importlib-resources"
version = "6.5.2"
@@ -1984,7 +2026,8 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "blinker" },
{ name = "flask" },
- { name = "importlib-metadata" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "9.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "importlib-resources" },
{ name = "itsdangerous" },
{ name = "markupsafe" },
@@ -2019,7 +2062,7 @@ dependencies = [
{ name = "invenio-base" },
{ name = "msgpack" },
{ name = "redis", version = "7.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "redis", version = "7.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "redis", version = "7.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9a/0b/33f7e233501a833706c25892ccb3132133285a23762fdbe4e25ad5a688f7/invenio_celery-2.2.0.tar.gz", hash = "sha256:348f9fadd2af2b33ec8cef61e0c926a9d12995c1687bf74d1de579440ad7f046", size = 21141, upload-time = "2025-07-03T21:30:49.923Z" }
wheels = [
@@ -2041,7 +2084,7 @@ wheels = [
[[package]]
name = "invenio-db"
-version = "2.3.0"
+version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "alembic", version = "1.16.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
@@ -2053,9 +2096,9 @@ dependencies = [
{ name = "sqlalchemy-continuum" },
{ name = "sqlalchemy-utils" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/b7/b8/13946c58a059e0c42bf69cdf606d359078065be857df8bfff729d556860e/invenio_db-2.3.0.tar.gz", hash = "sha256:b85f7739e15b48a0e9373b4e6428c92ab9fcb92a45d91425d6a33ae653146796", size = 22289, upload-time = "2026-02-25T08:42:45.994Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/3e/f0/bd62981ea87b484757fb40c627d086fe65353b22be3451852ab79f9c4667/invenio_db-2.4.0.tar.gz", hash = "sha256:e4d509e0f22850c6b190979878d45b400d33d09943c879ea49884fb10cc2a587", size = 22108, upload-time = "2026-03-12T22:08:26.296Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/e3/86/2bc3ca5504fa3ff22264c0946197fcc395333af77f88c0fc0ad93ef048c2/invenio_db-2.3.0-py2.py3-none-any.whl", hash = "sha256:6a7348c20a3ae419716a09002b589f62690b4460962f5b4a0e054f87a00d0918", size = 22274, upload-time = "2026-02-25T08:42:44.78Z" },
+ { url = "https://files.pythonhosted.org/packages/db/ab/86e676d5a543baca9de4a2b542f8e23d7d2dd264e42cdf0de02ab3511b77/invenio_db-2.4.0-py2.py3-none-any.whl", hash = "sha256:cff42013df5acfa0cdd8538787ab16961b5e7f01ab323d75f313b1f6bf9ced72", size = 21797, upload-time = "2026-03-12T22:08:25.255Z" },
]
[package.optional-dependencies]
@@ -2212,7 +2255,8 @@ dependencies = [
{ name = "flask-oauthlib-invenio" },
{ name = "flask-wtf" },
{ name = "future" },
- { name = "importlib-metadata" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "9.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "invenio-accounts" },
{ name = "invenio-base" },
{ name = "invenio-i18n" },
@@ -2258,7 +2302,8 @@ version = "2.2.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "base32-lib" },
- { name = "importlib-metadata" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "9.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "importlib-resources" },
{ name = "invenio-base" },
{ name = "invenio-i18n" },
@@ -2298,7 +2343,7 @@ dependencies = [
{ name = "invenio-base" },
{ name = "invenio-celery" },
{ name = "redis", version = "7.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "redis", version = "7.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "redis", version = "7.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5a/02/e81070f10cfbb1c821caa68853b77116bdb41ada95c5640f3f3e26e62a53/invenio_queues-1.0.2.tar.gz", hash = "sha256:47b70d71459b5057bb3fd8aafa45a467c8ec099ddf01d9c065e0fb8a80c23ba1", size = 10926, upload-time = "2025-11-04T09:45:53.12Z" }
wheels = [
@@ -2494,7 +2539,7 @@ wheels = [
[[package]]
name = "invenio-theme"
-version = "4.5.0"
+version = "4.6.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "flask-menu" },
@@ -2503,9 +2548,9 @@ dependencies = [
{ name = "invenio-i18n" },
{ name = "jsmin" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e3/55/487b727ca7c34b370f6a6632ecdd039473a7deef3e9d0a9667cfebf7f61a/invenio_theme-4.5.0.tar.gz", hash = "sha256:840027c16ddd9b2d3e9d156c38ee0c3b106925f515da172e9940db3de54182bc", size = 4438293, upload-time = "2025-12-05T15:12:44.597Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/8f/2b/afe6f4e155defbb07c6cbfb9967dce6633b21a0788bc4469110cf063eac5/invenio_theme-4.6.0.tar.gz", hash = "sha256:370be32b5453516030644d4e0916f8024079e5dc85d106a8b3d38a4c31c0ff90", size = 4438771, upload-time = "2026-03-09T10:57:35.467Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/60/1e/851d36dbf13ee6787d729a190fce80f177ba0dfc6840e3024f1582a3b9fc/invenio_theme-4.5.0-py2.py3-none-any.whl", hash = "sha256:69ea8a010fe6b0720b9d15f10fbadb17f9c37cc241af76d3a5d2779ac1798091", size = 4567262, upload-time = "2025-12-05T15:12:42.792Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/26/6f393d68c25fb419314a0c34d0f68569be78bb98329351f2781481bccdef/invenio_theme-4.6.0-py2.py3-none-any.whl", hash = "sha256:9186944490ccb8c78997b958e00ddc7f66c9876ef6beb4eb9e228a85a829e84b", size = 4567436, upload-time = "2026-03-09T10:57:33.456Z" },
]
[[package]]
@@ -2658,7 +2703,7 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1e/82/fa43935523efdfcce6abbae9da7f372b627b27142c3419fcf13bf5b0c397/isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481", size = 824325, upload-time = "2025-10-01T16:26:45.027Z" }
wheels = [
@@ -2723,7 +2768,8 @@ name = "jsonpatch"
version = "1.33"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "jsonpointer" },
+ { name = "jsonpointer", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "jsonpointer", version = "3.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" }
wheels = [
@@ -2734,11 +2780,28 @@ wheels = [
name = "jsonpointer"
version = "3.0.0"
source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version < '3.10'",
+]
sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" },
]
+[[package]]
+name = "jsonpointer"
+version = "3.1.0"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+ "python_full_version >= '3.12'",
+ "python_full_version == '3.11.*'",
+ "python_full_version == '3.10.*'",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/48/bf/9ecc036fbc15cf4153ea6ed4dbeed31ef043f762cccc9d44a534be8319b0/jsonpointer-3.1.0.tar.gz", hash = "sha256:f9b39abd59ba8c1de8a4ff16141605d2a8dacc4dd6cf399672cf237bfe47c211", size = 9000, upload-time = "2026-03-20T21:47:09.982Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e4/25/cebb241a435cbf4626b5ea096d8385c04416d7ca3082a15299b746e248fa/jsonpointer-3.1.0-py3-none-any.whl", hash = "sha256:f82aa0f745001f169b96473348370b43c3f581446889c41c807bab1db11c8e7b", size = 7651, upload-time = "2026-03-20T21:47:08.792Z" },
+]
+
[[package]]
name = "jsonref"
version = "1.1.0"
@@ -2750,15 +2813,16 @@ wheels = [
[[package]]
name = "jsonresolver"
-version = "0.5.0"
+version = "0.5.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
+ { name = "jsonschema-specifications" },
{ name = "pluggy" },
{ name = "werkzeug" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/19/ef/256abb36bc5a371a4bad078f1883e64bfa21385c6962548d324ff9fcadf2/jsonresolver-0.5.0.tar.gz", hash = "sha256:32bdc7aff09d5c64276e0711c6b9fa4c4b1bda979b1b02a8185d79487ba9fff5", size = 13689, upload-time = "2026-01-27T12:10:00.328Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/25/c2/5d7ee99eaf8cb1f2b97ef295332921a8dd3903f0eafb15559e04312bc200/jsonresolver-0.5.1.tar.gz", hash = "sha256:dc48f19f3e329af6d30a696c53fb087edf95d97c4615bccd27f517e683503864", size = 13788, upload-time = "2026-03-20T07:27:53.892Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/69/fd/0cacf8a2f37952e589b55919e46df50ed24ae1612e0b1d7a1ca74709f017/jsonresolver-0.5.0-py2.py3-none-any.whl", hash = "sha256:e39be56d675a1756dc1fa56036b499aeaef79f22caeb0d220397a7aac5c4bbc2", size = 13594, upload-time = "2026-01-27T12:09:58.943Z" },
+ { url = "https://files.pythonhosted.org/packages/19/57/45bde3c362518fd3a8078a32d704edeb94a61ad814302a246b351016f492/jsonresolver-0.5.1-py2.py3-none-any.whl", hash = "sha256:5736bca6678cde4ef501c09a9b7754467d11863bab89af6d2cee45adc49f689d", size = 13634, upload-time = "2026-03-20T07:27:52.682Z" },
]
[[package]]
@@ -2820,7 +2884,7 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "python-dateutil", marker = "python_full_version < '3.10'" },
{ name = "pyzmq", marker = "python_full_version < '3.10'" },
@@ -3237,7 +3301,7 @@ resolution-markers = [
"python_full_version < '3.10'",
]
dependencies = [
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" }
wheels = [
@@ -3345,7 +3409,8 @@ dependencies = [
{ name = "babel-edtf" },
{ name = "bleach", version = "6.2.0", source = { registry = "https://pypi.org/simple" }, extra = ["css"], marker = "python_full_version < '3.10'" },
{ name = "bleach", version = "6.3.0", source = { registry = "https://pypi.org/simple" }, extra = ["css"], marker = "python_full_version >= '3.10'" },
- { name = "edtf" },
+ { name = "edtf", version = "5.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
+ { name = "edtf", version = "5.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "ftfy" },
{ name = "geojson" },
{ name = "idutils" },
@@ -3612,7 +3677,7 @@ dependencies = [
{ name = "bleach", version = "6.2.0", source = { registry = "https://pypi.org/simple" }, extra = ["css"], marker = "python_full_version < '3.10'" },
{ name = "bleach", version = "6.3.0", source = { registry = "https://pypi.org/simple" }, extra = ["css"], marker = "python_full_version >= '3.10'" },
{ name = "defusedxml" },
- { name = "importlib-metadata", marker = "python_full_version < '3.10'" },
+ { name = "importlib-metadata", version = "8.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "jinja2" },
{ name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "jupyter-core", version = "5.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
@@ -3976,7 +4041,7 @@ resolution-markers = [
]
dependencies = [
{ name = "cachecontrol", version = "0.14.4", source = { registry = "https://pypi.org/simple" }, extra = ["filecache"], marker = "python_full_version >= '3.10'" },
- { name = "cyclonedx-python-lib", version = "11.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "cyclonedx-python-lib", version = "11.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "packaging", version = "26.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pip-api", marker = "python_full_version >= '3.10'" },
{ name = "pip-requirements-parser", marker = "python_full_version >= '3.10'" },
@@ -4272,11 +4337,14 @@ wheels = [
[[package]]
name = "pyjwt"
-version = "2.11.0"
+version = "2.12.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/5c/5a/b46fa56bf322901eee5b0454a34343cdbdae202cd421775a8ee4e42fd519/pyjwt-2.11.0.tar.gz", hash = "sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623", size = 98019, upload-time = "2026-01-30T19:59:55.694Z" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c2/27/a3b6e5bf6ff856d2509292e95c8f57f0df7017cf5394921fc4e4ef40308a/pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b", size = 102564, upload-time = "2026-03-13T19:27:37.25Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl", hash = "sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469", size = 28224, upload-time = "2026-01-30T19:59:54.539Z" },
+ { url = "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c", size = 29726, upload-time = "2026-03-13T19:27:35.677Z" },
]
[package.optional-dependencies]
@@ -4304,22 +4372,22 @@ wheels = [
[[package]]
name = "pymupdf"
-version = "1.27.1"
+version = "1.27.2.2"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
"python_full_version == '3.11.*'",
"python_full_version == '3.10.*'",
]
-sdist = { url = "https://files.pythonhosted.org/packages/1b/0c/40dda0cc4bd2220a2ef75f8c53dd7d8ed1e29681fcb3df75db6ee9677a7e/pymupdf-1.27.1.tar.gz", hash = "sha256:4afbde0769c336717a149ab0de3330dcb75378f795c1a8c5af55c1a628b17d55", size = 85303479, upload-time = "2026-02-12T08:29:17.682Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/32/f6b645c51d79a188a4844140c5dabca7b487ad56c4be69c4bc782d0d11a9/pymupdf-1.27.2.2.tar.gz", hash = "sha256:ea8fdc3ab6671ca98f629d5ec3032d662c8cf1796b146996b7ad306ac7ed3335", size = 85354380, upload-time = "2026-03-20T09:47:58.386Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/13/19/fde6ea4712a904b65e8f41124a0e4233879b87a770fe6a8ce857964de6d5/pymupdf-1.27.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bee9f95512f9556dbf2cacfd1413c61b29a55baa07fa7f8fc83d221d8419888a", size = 23986707, upload-time = "2026-02-11T15:03:24.025Z" },
- { url = "https://files.pythonhosted.org/packages/75/c2/070dff91ad3f1bc16fd6c6ceff23495601fcce4c92d28be534417596418a/pymupdf-1.27.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:3de95a0889395b0966fafd11b94980b7543a816e89dd1c218597a08543ac3415", size = 23263493, upload-time = "2026-02-11T15:03:45.528Z" },
- { url = "https://files.pythonhosted.org/packages/8e/db/937377f4b3e0fbf6273c17436a49f7db17df1a46b1be9e26653b6fafc0e1/pymupdf-1.27.1-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2c9d9353b840040cbc724341f4095fb7e2cc1a12a9147d0ec1a0a79f5d773147", size = 24317651, upload-time = "2026-02-11T22:33:38.967Z" },
- { url = "https://files.pythonhosted.org/packages/72/d5/c701cf2d0cdd6e5d6bca3ca9188d7f5d7ce3ae67dd1368d658cd4bae2707/pymupdf-1.27.1-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:aeaed76e72cbc061149a825ab0811c5f4752970c56591c2938c5042ec06b26e1", size = 24945742, upload-time = "2026-02-11T15:04:06.21Z" },
- { url = "https://files.pythonhosted.org/packages/2b/29/690202b38b93cf77b73a29c25a63a2b6f3fcb36b1f75006e50b8dee7c108/pymupdf-1.27.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4f1837554134fb45d390a44de8844b2ca9b6c901c82ccc90b340e3b7f3b126ca", size = 25167965, upload-time = "2026-02-11T22:36:35.478Z" },
- { url = "https://files.pythonhosted.org/packages/8a/81/f937e6aa606fd263c3a45d0ff0f0bbdbf3fb779933091fc0f6179513cc93/pymupdf-1.27.1-cp310-abi3-win32.whl", hash = "sha256:fa33b512d82c6c4852edadf57f22d5f27d16243bb33dac0fbe4eb0f281c5b17e", size = 18006253, upload-time = "2026-02-12T13:48:07.129Z" },
- { url = "https://files.pythonhosted.org/packages/3e/99/fe4a7752990bf65277718fffbead4478de9afd1c7288d7a6d643f79a6fa7/pymupdf-1.27.1-cp310-abi3-win_amd64.whl", hash = "sha256:4b6268dff3a9d713034eba5c2ffce0da37c62443578941ac5df433adcde57b2f", size = 19236703, upload-time = "2026-02-11T15:04:19.607Z" },
+ { url = "https://files.pythonhosted.org/packages/90/88/d01992a50165e22dec057a1129826846c547feb4ba07f42720ac030ce438/pymupdf-1.27.2.2-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:800f43e60a6f01f644343c2213b8613db02eaf4f4ba235b417b3351fa99e01c0", size = 23987563, upload-time = "2026-03-19T12:35:42.989Z" },
+ { url = "https://files.pythonhosted.org/packages/6d/0e/9f526bc1d49d8082eff0d1547a69d541a0c5a052e71da625559efaba46a6/pymupdf-1.27.2.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e2e4299ef1ac0c9dff9be096cbd22783699673abecfa7c3f73173ae06421d73", size = 23263089, upload-time = "2026-03-20T09:44:16.982Z" },
+ { url = "https://files.pythonhosted.org/packages/42/be/984f0d6343935b5dd30afaed6be04fc753146bf55709e63ef28bf9ef7497/pymupdf-1.27.2.2-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5e3d54922db1c7da844f1208ac1db05704770988752311f81dd36694ae0a07b", size = 24318817, upload-time = "2026-03-20T09:44:33.209Z" },
+ { url = "https://files.pythonhosted.org/packages/22/8e/85e9d9f11dbf34036eb1df283805ef6b885f2005a56d6533bb58ab0b8a11/pymupdf-1.27.2.2-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:892698c9768457eb0991c102c96a856c0a7062539371df5e6bee0816f3ef498e", size = 24948135, upload-time = "2026-03-20T09:44:51.012Z" },
+ { url = "https://files.pythonhosted.org/packages/db/e6/386edb017e5b93f1ab0bf6653ae32f3dd8dfc834ed770212e10ca62f4af9/pymupdf-1.27.2.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b4bbfa6ef347fade678771a93f6364971c51a2cdc44cd2400dc4eeed1ddb4e6", size = 25169585, upload-time = "2026-03-20T09:45:05.393Z" },
+ { url = "https://files.pythonhosted.org/packages/ba/fd/f1ebe24fcd31aaea8b85b3a7ac4c3fc96e20388be5466ace27c9a3c546d9/pymupdf-1.27.2.2-cp310-abi3-win32.whl", hash = "sha256:0b8e924433b7e0bd46be820899300259235997d5a747638471fb2762baa8ee30", size = 18008861, upload-time = "2026-03-20T09:45:21.353Z" },
+ { url = "https://files.pythonhosted.org/packages/a8/b6/2a9a8556000199bbf80a5915dcd15d550d1e5288894316445c54726aaf53/pymupdf-1.27.2.2-cp310-abi3-win_amd64.whl", hash = "sha256:09bb53f9486ccb5297030cbc2dbdae845ba1c3c5126e96eb2d16c4f118de0b5b", size = 19238032, upload-time = "2026-03-20T09:45:37.941Z" },
]
[[package]]
@@ -4412,17 +4480,17 @@ wheels = [
[[package]]
name = "pytest-cov"
-version = "7.0.0"
+version = "7.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.10'" },
- { name = "coverage", version = "7.13.4", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" },
+ { name = "coverage", version = "7.13.5", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" },
{ name = "pluggy" },
{ name = "pytest" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" },
]
[[package]]
@@ -4478,7 +4546,7 @@ source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "check-manifest" },
{ name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "coverage", version = "7.13.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "coverage", version = "7.13.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "docker-services-cli" },
{ name = "pytest" },
{ name = "pytest-cov" },
@@ -4953,7 +5021,7 @@ wheels = [
[[package]]
name = "redis"
-version = "7.2.1"
+version = "7.3.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.12'",
@@ -4963,9 +5031,9 @@ resolution-markers = [
dependencies = [
{ name = "async-timeout", marker = "python_full_version >= '3.10' and python_full_version < '3.11.3'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/e9/31/1476f206482dd9bc53fdbbe9f6fbd5e05d153f18e54667ce839df331f2e6/redis-7.2.1.tar.gz", hash = "sha256:6163c1a47ee2d9d01221d8456bc1c75ab953cbda18cfbc15e7140e9ba16ca3a5", size = 4906735, upload-time = "2026-02-25T20:05:18.171Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/da/82/4d1a5279f6c1251d3d2a603a798a1137c657de9b12cfc1fba4858232c4d2/redis-7.3.0.tar.gz", hash = "sha256:4d1b768aafcf41b01022410b3cc4f15a07d9b3d6fe0c66fc967da2c88e551034", size = 4928081, upload-time = "2026-03-06T18:18:16.287Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/ca/98/1dd1a5c060916cf21d15e67b7d6a7078e26e2605d5c37cbc9f4f5454c478/redis-7.2.1-py3-none-any.whl", hash = "sha256:49e231fbc8df2001436ae5252b3f0f3dc930430239bfeb6da4c7ee92b16e5d33", size = 396057, upload-time = "2026-02-25T20:05:16.533Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/28/84e57fce7819e81ec5aa1bd31c42b89607241f4fb1a3ea5b0d2dbeaea26c/redis-7.3.0-py3-none-any.whl", hash = "sha256:9d4fcb002a12a5e3c3fbe005d59c48a2cc231f87fbb2f6b70c2d89bb64fec364", size = 404379, upload-time = "2026-03-06T18:18:14.583Z" },
]
[[package]]
@@ -5081,7 +5149,7 @@ dependencies = [
{ name = "poethepoet", version = "0.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
{ name = "poethepoet", version = "0.42.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
{ name = "pymupdf", version = "1.26.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
- { name = "pymupdf", version = "1.27.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
+ { name = "pymupdf", version = "1.27.2.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/75/0e/5b103716694ef4146b9792958e97b4b09c0d46326c2097c1d8c5d7f8c501/rero_invenio_files-1.2.0.tar.gz", hash = "sha256:2b1b8ddfa03e46f9e052630a9b275091a992e35cd9d6e06f1fa78b67607e69f1", size = 1454460, upload-time = "2025-09-02T14:38:45.923Z" }
wheels = [
@@ -5295,27 +5363,27 @@ wheels = [
[[package]]
name = "ruff"
-version = "0.15.5"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/77/9b/840e0039e65fcf12758adf684d2289024d6140cde9268cc59887dc55189c/ruff-0.15.5.tar.gz", hash = "sha256:7c3601d3b6d76dce18c5c824fc8d06f4eef33d6df0c21ec7799510cde0f159a2", size = 4574214, upload-time = "2026-03-05T20:06:34.946Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/47/20/5369c3ce21588c708bcbe517a8fbe1a8dfdb5dfd5137e14790b1da71612c/ruff-0.15.5-py3-none-linux_armv6l.whl", hash = "sha256:4ae44c42281f42e3b06b988e442d344a5b9b72450ff3c892e30d11b29a96a57c", size = 10478185, upload-time = "2026-03-05T20:06:29.093Z" },
- { url = "https://files.pythonhosted.org/packages/44/ed/e81dd668547da281e5dce710cf0bc60193f8d3d43833e8241d006720e42b/ruff-0.15.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6edd3792d408ebcf61adabc01822da687579a1a023f297618ac27a5b51ef0080", size = 10859201, upload-time = "2026-03-05T20:06:32.632Z" },
- { url = "https://files.pythonhosted.org/packages/c4/8f/533075f00aaf19b07c5cd6aa6e5d89424b06b3b3f4583bfa9c640a079059/ruff-0.15.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:89f463f7c8205a9f8dea9d658d59eff49db05f88f89cc3047fb1a02d9f344010", size = 10184752, upload-time = "2026-03-05T20:06:40.312Z" },
- { url = "https://files.pythonhosted.org/packages/66/0e/ba49e2c3fa0395b3152bad634c7432f7edfc509c133b8f4529053ff024fb/ruff-0.15.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba786a8295c6574c1116704cf0b9e6563de3432ac888d8f83685654fe528fd65", size = 10534857, upload-time = "2026-03-05T20:06:19.581Z" },
- { url = "https://files.pythonhosted.org/packages/59/71/39234440f27a226475a0659561adb0d784b4d247dfe7f43ffc12dd02e288/ruff-0.15.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd4b801e57955fe9f02b31d20375ab3a5c4415f2e5105b79fb94cf2642c91440", size = 10309120, upload-time = "2026-03-05T20:06:00.435Z" },
- { url = "https://files.pythonhosted.org/packages/f5/87/4140aa86a93df032156982b726f4952aaec4a883bb98cb6ef73c347da253/ruff-0.15.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391f7c73388f3d8c11b794dbbc2959a5b5afe66642c142a6effa90b45f6f5204", size = 11047428, upload-time = "2026-03-05T20:05:51.867Z" },
- { url = "https://files.pythonhosted.org/packages/5a/f7/4953e7e3287676f78fbe85e3a0ca414c5ca81237b7575bdadc00229ac240/ruff-0.15.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dc18f30302e379fe1e998548b0f5e9f4dff907f52f73ad6da419ea9c19d66c8", size = 11914251, upload-time = "2026-03-05T20:06:22.887Z" },
- { url = "https://files.pythonhosted.org/packages/77/46/0f7c865c10cf896ccf5a939c3e84e1cfaeed608ff5249584799a74d33835/ruff-0.15.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc6e7f90087e2d27f98dc34ed1b3ab7c8f0d273cc5431415454e22c0bd2a681", size = 11333801, upload-time = "2026-03-05T20:05:57.168Z" },
- { url = "https://files.pythonhosted.org/packages/d3/01/a10fe54b653061585e655f5286c2662ebddb68831ed3eaebfb0eb08c0a16/ruff-0.15.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb7169f53c1ddb06e71a9aebd7e98fc0fea936b39afb36d8e86d36ecc2636a", size = 11206821, upload-time = "2026-03-05T20:06:03.441Z" },
- { url = "https://files.pythonhosted.org/packages/7a/0d/2132ceaf20c5e8699aa83da2706ecb5c5dcdf78b453f77edca7fb70f8a93/ruff-0.15.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9b037924500a31ee17389b5c8c4d88874cc6ea8e42f12e9c61a3d754ff72f1ca", size = 11133326, upload-time = "2026-03-05T20:06:25.655Z" },
- { url = "https://files.pythonhosted.org/packages/72/cb/2e5259a7eb2a0f87c08c0fe5bf5825a1e4b90883a52685524596bfc93072/ruff-0.15.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65bb414e5b4eadd95a8c1e4804f6772bbe8995889f203a01f77ddf2d790929dd", size = 10510820, upload-time = "2026-03-05T20:06:37.79Z" },
- { url = "https://files.pythonhosted.org/packages/ff/20/b67ce78f9e6c59ffbdb5b4503d0090e749b5f2d31b599b554698a80d861c/ruff-0.15.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d20aa469ae3b57033519c559e9bc9cd9e782842e39be05b50e852c7c981fa01d", size = 10302395, upload-time = "2026-03-05T20:05:54.504Z" },
- { url = "https://files.pythonhosted.org/packages/5f/e5/719f1acccd31b720d477751558ed74e9c88134adcc377e5e886af89d3072/ruff-0.15.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:15388dd28c9161cdb8eda68993533acc870aa4e646a0a277aa166de9ad5a8752", size = 10754069, upload-time = "2026-03-05T20:06:06.422Z" },
- { url = "https://files.pythonhosted.org/packages/c3/9c/d1db14469e32d98f3ca27079dbd30b7b44dbb5317d06ab36718dee3baf03/ruff-0.15.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b30da330cbd03bed0c21420b6b953158f60c74c54c5f4c1dabbdf3a57bf355d2", size = 11304315, upload-time = "2026-03-05T20:06:10.867Z" },
- { url = "https://files.pythonhosted.org/packages/28/3a/950367aee7c69027f4f422059227b290ed780366b6aecee5de5039d50fa8/ruff-0.15.5-py3-none-win32.whl", hash = "sha256:732e5ee1f98ba5b3679029989a06ca39a950cced52143a0ea82a2102cb592b74", size = 10551676, upload-time = "2026-03-05T20:06:13.705Z" },
- { url = "https://files.pythonhosted.org/packages/b8/00/bf077a505b4e649bdd3c47ff8ec967735ce2544c8e4a43aba42ee9bf935d/ruff-0.15.5-py3-none-win_amd64.whl", hash = "sha256:821d41c5fa9e19117616c35eaa3f4b75046ec76c65e7ae20a333e9a8696bc7fe", size = 11678972, upload-time = "2026-03-05T20:06:45.379Z" },
- { url = "https://files.pythonhosted.org/packages/fe/4e/cd76eca6db6115604b7626668e891c9dd03330384082e33662fb0f113614/ruff-0.15.5-py3-none-win_arm64.whl", hash = "sha256:b498d1c60d2fe5c10c45ec3f698901065772730b411f164ae270bb6bfcc4740b", size = 10965572, upload-time = "2026-03-05T20:06:16.984Z" },
+version = "0.15.7"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a1/22/9e4f66ee588588dc6c9af6a994e12d26e19efbe874d1a909d09a6dac7a59/ruff-0.15.7.tar.gz", hash = "sha256:04f1ae61fc20fe0b148617c324d9d009b5f63412c0b16474f3d5f1a1a665f7ac", size = 4601277, upload-time = "2026-03-19T16:26:22.605Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/41/2f/0b08ced94412af091807b6119ca03755d651d3d93a242682bf020189db94/ruff-0.15.7-py3-none-linux_armv6l.whl", hash = "sha256:a81cc5b6910fb7dfc7c32d20652e50fa05963f6e13ead3c5915c41ac5d16668e", size = 10489037, upload-time = "2026-03-19T16:26:32.47Z" },
+ { url = "https://files.pythonhosted.org/packages/91/4a/82e0fa632e5c8b1eba5ee86ecd929e8ff327bbdbfb3c6ac5d81631bef605/ruff-0.15.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:722d165bd52403f3bdabc0ce9e41fc47070ac56d7a91b4e0d097b516a53a3477", size = 10955433, upload-time = "2026-03-19T16:27:00.205Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/10/12586735d0ff42526ad78c049bf51d7428618c8b5c467e72508c694119df/ruff-0.15.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7fbc2448094262552146cbe1b9643a92f66559d3761f1ad0656d4991491af49e", size = 10269302, upload-time = "2026-03-19T16:26:26.183Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/5d/32b5c44ccf149a26623671df49cbfbd0a0ae511ff3df9d9d2426966a8d57/ruff-0.15.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b39329b60eba44156d138275323cc726bbfbddcec3063da57caa8a8b1d50adf", size = 10607625, upload-time = "2026-03-19T16:27:03.263Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/f1/f0001cabe86173aaacb6eb9bb734aa0605f9a6aa6fa7d43cb49cbc4af9c9/ruff-0.15.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87768c151808505f2bfc93ae44e5f9e7c8518943e5074f76ac21558ef5627c85", size = 10324743, upload-time = "2026-03-19T16:27:09.791Z" },
+ { url = "https://files.pythonhosted.org/packages/7a/87/b8a8f3d56b8d848008559e7c9d8bf367934d5367f6d932ba779456e2f73b/ruff-0.15.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb0511670002c6c529ec66c0e30641c976c8963de26a113f3a30456b702468b0", size = 11138536, upload-time = "2026-03-19T16:27:06.101Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/f2/4fd0d05aab0c5934b2e1464784f85ba2eab9d54bffc53fb5430d1ed8b829/ruff-0.15.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0d19644f801849229db8345180a71bee5407b429dd217f853ec515e968a6912", size = 11994292, upload-time = "2026-03-19T16:26:48.718Z" },
+ { url = "https://files.pythonhosted.org/packages/64/22/fc4483871e767e5e95d1622ad83dad5ebb830f762ed0420fde7dfa9d9b08/ruff-0.15.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4806d8e09ef5e84eb19ba833d0442f7e300b23fe3f0981cae159a248a10f0036", size = 11398981, upload-time = "2026-03-19T16:26:54.513Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/99/66f0343176d5eab02c3f7fcd2de7a8e0dd7a41f0d982bee56cd1c24db62b/ruff-0.15.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dce0896488562f09a27b9c91b1f58a097457143931f3c4d519690dea54e624c5", size = 11242422, upload-time = "2026-03-19T16:26:29.277Z" },
+ { url = "https://files.pythonhosted.org/packages/5d/3a/a7060f145bfdcce4c987ea27788b30c60e2c81d6e9a65157ca8afe646328/ruff-0.15.7-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:1852ce241d2bc89e5dc823e03cff4ce73d816b5c6cdadd27dbfe7b03217d2a12", size = 11232158, upload-time = "2026-03-19T16:26:42.321Z" },
+ { url = "https://files.pythonhosted.org/packages/a7/53/90fbb9e08b29c048c403558d3cdd0adf2668b02ce9d50602452e187cd4af/ruff-0.15.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5f3e4b221fb4bd293f79912fc5e93a9063ebd6d0dcbd528f91b89172a9b8436c", size = 10577861, upload-time = "2026-03-19T16:26:57.459Z" },
+ { url = "https://files.pythonhosted.org/packages/2f/aa/5f486226538fe4d0f0439e2da1716e1acf895e2a232b26f2459c55f8ddad/ruff-0.15.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b15e48602c9c1d9bdc504b472e90b90c97dc7d46c7028011ae67f3861ceba7b4", size = 10327310, upload-time = "2026-03-19T16:26:35.909Z" },
+ { url = "https://files.pythonhosted.org/packages/99/9e/271afdffb81fe7bfc8c43ba079e9d96238f674380099457a74ccb3863857/ruff-0.15.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b4705e0e85cedc74b0a23cf6a179dbb3df184cb227761979cc76c0440b5ab0d", size = 10840752, upload-time = "2026-03-19T16:26:45.723Z" },
+ { url = "https://files.pythonhosted.org/packages/bf/29/a4ae78394f76c7759953c47884eb44de271b03a66634148d9f7d11e721bd/ruff-0.15.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:112c1fa316a558bb34319282c1200a8bf0495f1b735aeb78bfcb2991e6087580", size = 11336961, upload-time = "2026-03-19T16:26:39.076Z" },
+ { url = "https://files.pythonhosted.org/packages/26/6b/8786ba5736562220d588a2f6653e6c17e90c59ced34a2d7b512ef8956103/ruff-0.15.7-py3-none-win32.whl", hash = "sha256:6d39e2d3505b082323352f733599f28169d12e891f7dd407f2d4f54b4c2886de", size = 10582538, upload-time = "2026-03-19T16:26:15.992Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/e9/346d4d3fffc6871125e877dae8d9a1966b254fbd92a50f8561078b88b099/ruff-0.15.7-py3-none-win_amd64.whl", hash = "sha256:4d53d712ddebcd7dace1bc395367aec12c057aacfe9adbb6d832302575f4d3a1", size = 11755839, upload-time = "2026-03-19T16:26:19.897Z" },
+ { url = "https://files.pythonhosted.org/packages/8f/e8/726643a3ea68c727da31570bde48c7a10f1aa60eddd628d94078fec586ff/ruff-0.15.7-py3-none-win_arm64.whl", hash = "sha256:18e8d73f1c3fdf27931497972250340f92e8c861722161a9caeb89a58ead6ed2", size = 11023304, upload-time = "2026-03-19T16:26:51.669Z" },
]
[[package]]
@@ -5822,21 +5890,19 @@ wheels = [
[[package]]
name = "tornado"
-version = "6.5.4"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" }
-wheels = [
- { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" },
- { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" },
- { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" },
- { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" },
- { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" },
- { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" },
- { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" },
- { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" },
- { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" },
- { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" },
- { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" },
+version = "6.5.5"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" },
+ { url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" },
+ { url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" },
+ { url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" },
+ { url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" },
+ { url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" },
+ { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" },
]
[[package]]