diff --git a/nrl-sdk-lib/pyproject.toml b/nrl-sdk-lib/pyproject.toml index 803ce55..47fd347 100644 --- a/nrl-sdk-lib/pyproject.toml +++ b/nrl-sdk-lib/pyproject.toml @@ -20,6 +20,9 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/nrl_sdk_lib"] +[tool.deptry] +known_first_party = ["nrl_sdk_lib"] + [dependency-groups] dev = [ "anyio>=4.9.0", @@ -59,6 +62,7 @@ ignore = [ "PLR2004", # Magic values allowed in tests ] + [tool.ruff.lint.isort] # so it knows to group first-party stuff last known-first-party = ["src"] diff --git a/nrl-sdk-lib/src/nrl_sdk_lib/converters/__init__.py b/nrl-sdk-lib/src/nrl_sdk_lib/converters/__init__.py new file mode 100644 index 0000000..1eac654 --- /dev/null +++ b/nrl-sdk-lib/src/nrl_sdk_lib/converters/__init__.py @@ -0,0 +1,5 @@ +"""Csv to GeoJson converter.""" + +from .csv_to_geojson import csv_to_geojson + +__all__ = ["csv_to_geojson"] diff --git a/nrl-sdk-lib/src/nrl_sdk_lib/converters/csv_to_geojson.py b/nrl-sdk-lib/src/nrl_sdk_lib/converters/csv_to_geojson.py new file mode 100644 index 0000000..0d78c4c --- /dev/null +++ b/nrl-sdk-lib/src/nrl_sdk_lib/converters/csv_to_geojson.py @@ -0,0 +1,410 @@ +"""Convert CSV data to GeoJSON FeatureCollections.""" + +import csv +import logging +import sys +import uuid +from pathlib import Path +from typing import IO, Literal + +from nrl_sdk_lib.models import ( + Crs, + CrsProperties, + Feature, + FeatureCollection, + FeatureStatus, + Høydereferanse, #noqa: PLC2403 + KomponentReferanse, + LineString, + LuftfartsHinderLyssetting, + LuftfartsHinderMerking, + LuftspennType, + MastType, + NrlLuftspenn, + NrlMast, + Point, +) + +logging.basicConfig( + level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s" +) +logger = logging.getLogger(__name__) + + +def map_luftspenn_type(value: str | None) -> LuftspennType: + """Map CSV value to LuftspennType.""" + mapping = { + "Ledning, høyspent": LuftspennType.høgspent, + "Ledning, lavspent": LuftspennType.lavspent, + "Ledning, regionalnett": LuftspennType.regional, + "Bardun": LuftspennType.bardun, + } + result = mapping.get(value) + if result is None: + msg = f"Unknown Luftspenntype: {value}" + raise ValueError(msg) + return result + +def map_mast_type(value: str | None) -> MastType: + """Map CSV value to MastType.""" + mapping = { + "Mast, høyspent": MastType.høgspentmast, + "Mast, lavspent": MastType.lavspentmast, + "Mast, regionalnett": MastType.regionalmast, + } + result = mapping.get(value) + if result is None: + msg = f"Unknown Masttype: {value}" + raise ValueError(msg) + return result + +def map_feature_status(value: str | None) -> FeatureStatus: + """Map CSV value to FeatureStatus.""" + mapping = { + "Eksisterende": FeatureStatus.eksisterende, + "eksisterende": FeatureStatus.eksisterende, + "Planlagt oppført": FeatureStatus.planlagt_oppført, + "planlagtOppført": FeatureStatus.planlagt_oppført, + "Planlagt fjernet": FeatureStatus.planlagt_fjernet, + "planlagtFjernet": FeatureStatus.planlagt_fjernet, + "Fjernet": FeatureStatus.fjernet, + "fjernet": FeatureStatus.fjernet, + } + result = mapping.get(value) + if result is None: + msg = f"Unknown Status: {value}" + raise ValueError(msg) + return result + +def map_lighting_kind(value: str | None) -> LuftfartsHinderLyssetting | None: + """Map CSV value to LuftfartsHinderLyssetting (optional).""" + mapping = { + "Lyssatt": LuftfartsHinderLyssetting.lyssatt, + "Mellomintensitet, type A": LuftfartsHinderLyssetting.mellomintensitet_type_a, + "Mellomintensitet, type B": LuftfartsHinderLyssetting.mellomintensitet_type_b, + "Mellomintensitet, type C": LuftfartsHinderLyssetting.mellomintensitet_type_c, + "Lavintensitet, type A": LuftfartsHinderLyssetting.lavintensitet_type_a, + "Lavintensitet, type B": LuftfartsHinderLyssetting.lavintensitet_type_b, + "Høyintensitet, type A": LuftfartsHinderLyssetting.høyintensitet_type_a, + "Høyintensitet, type B": LuftfartsHinderLyssetting.høyintensitet_type_b, + } + if not value: + return None + return mapping.get(value) + + +def map_marking_kind(value: str | None) -> LuftfartsHinderMerking | None: + """Map CSV value to LuftfartsHinderMerking (optional).""" + mapping = { + "Fargemerking": LuftfartsHinderMerking.fargermerking, + "Markør": LuftfartsHinderMerking.markør, + } + if not value: + return None + return mapping.get(value) + +def map_location_method(value: str | None) -> Literal["20230101_5-1", "0"]: + """Map CSV value to location method string.""" + if value == "FOR-2020-10-16-2068, §5(1)": + return "20230101_5-1" + return "0" + +def csv_to_geojson(file: str | Path | IO[str] | None = None) -> list[FeatureCollection]: + """Convert CSV file to GeoJSON FeatureCollections grouped by CRS. + + Args: + file: Can be: + - None: reads from stdin + - str or Path: path to CSV file + - IO[str]: file-like object (already opened file) + + Returns: + List of FeatureCollections grouped by CRS + + Examples: + # From file path + result = csv_to_geojson("data.csv") + + # From stdin + result = csv_to_geojson() + + # From file object + with open("data.csv") as f: + result = csv_to_geojson(f) + + """ + if file is None: + # Read from stdin + logger.info("Reading CSV from stdin") + return _process_csv_file(sys.stdin) + if isinstance(file, (str, Path)): + msg = f"Reading CSV from file: {file}" + logger.info(msg) + with Path(file).open(newline="", encoding="utf-8-sig") as csvfile: + return _process_csv_file(csvfile) + else: + # Use provided file object + logger.info("Reading CSV from file object") + return _process_csv_file(file) + + +def _process_csv_file(csvfile: IO[str]) -> list[FeatureCollection]: + """Process CSV file and return FeatureCollections grouped by CRS.""" + feature_by_crs = {} + reader = csv.DictReader(csvfile, dialect="excel", delimiter=";") + + for row in reader: + feature, crs = process_row(row) + crs_name = crs.properties.name + feature_by_crs.setdefault(crs_name, []).append(feature) + + return [ + FeatureCollection( + crs=Crs(properties=CrsProperties(name=crs_name)), features=features + ) + for crs_name, features in feature_by_crs.items() + ] + +def process_row(row: dict[str, str]) -> tuple[Feature, Crs]: + """Process a single CSV row and return the appropriate feature.""" + table_id = row.get("Tabell ID") + + if table_id == "261": + return ( + convert_guy_segments_rows(row) + if row["Betegnelse"] == "Bardunline" + else convert_ac_linesegments_rows(row) + ) + if table_id == "109": + return convert_overhead_structure_rows(row) + + msg = f"Unknown Tabell ID: {table_id}" + logger.warning(msg) + raise ValueError(msg) + + +def get_uuid(row: dict[str, str], *fields: str) -> uuid.UUID: + """Extract and validate UUID from row fields.""" + for field in fields: + value = row.get(field) + if value: + try: + return uuid.UUID(value) + except ValueError: + continue + msg = f"No valid UUID found in fields: {fields}" + raise ValueError(msg) + + +def parse_float(value: str | None, field_name: str) -> float: + """Parse float value with error handling.""" + if value is None: + msg = f"Missing {field_name}" + raise ValueError(msg) + try: + return float(value.replace(",", ".")) + except (ValueError, AttributeError) as e: + msg = f"{field_name} is not a valid number: {value}" + raise ValueError(msg) from e + + +def parse_coordinates(coords: list[str | None]) -> list[float]: + """Parse and convert coordinate strings to floats.""" + return [ + float(c.replace(",", ".")) + for c in coords if isinstance(c, str) and c != ""] + + +def create_geometry( + coordinates: list[list[str | None]], *,is_line: bool = True +) -> tuple[LineString | Point, Crs]: + """Create LineString or Point geometry with appropriate CRS.""" + has_z = all(coord[2] not in [None, ""] for coord in coordinates) + len_coordinates_value =2 + if is_line and len(coordinates) != len_coordinates_value: + msg = "LineString requires exactly 2 points" + raise ValueError(msg) + + try: + if has_z: + if is_line: + coords = [ + [ + parse_float(c[1], "y"), + parse_float(c[0], "x"), + parse_float(c[2], "z"), + ] + for c in coordinates + ] + geometry = LineString(type="LineString", coordinates=coords) + else: + x, y, z = parse_coordinates(coordinates[0]) + geometry = Point(type="Point", coordinates=[y, x, z]) + crs = Crs(properties=CrsProperties(name="EPSG:5972")) + else: + if is_line: + coords = [ + [parse_float(c[1], "y"), parse_float(c[0], "x")] + for c in coordinates + ] + geometry = LineString(type="LineString", coordinates=coords) + else: + x, y = parse_coordinates(coordinates[0][:2]) + geometry = Point(type="Point", coordinates=[y, x]) + crs = Crs(properties=CrsProperties(name="EPSG:25832")) + except ValueError as e: + msg = f"Invalid coordinate values: {e}" + raise ValueError(msg) from e + + return geometry, crs + +def convert_overhead_structure_rows(row: dict[str, str]) -> tuple[Feature, Crs]: + """Convert overhead structure (mast) rows to NrlMast feature.""" + komponentident = get_uuid(row, "OverheadStructure_uuid", "ID") + masttype = map_mast_type(row.get("Masttype (NRL)")) + feature_status = map_feature_status(row.get("Status (NRL)")) + nøyaktighet = map_location_method(row.get("Verifisert nøyaktighet (NRL)")) + + lyssetting = map_lighting_kind(row.get("Luftfartshinderlyssetting(NRL)")) + merking = map_marking_kind(row.get("Luftfartshindermerking (NRL)")) + + navn = row.get("Betegnelse") + høydereferanse = None + if row.get("Hoydereferanse (NRL)"): + høydereferanse = ( + Høydereferanse.topp + if row["Hoydereferanse (NRL)"].lower() == "topp" + else Høydereferanse.fot + if row["Hoydereferanse (NRL)"].lower() == "fot" + else None + ) + + referanse = KomponentReferanse( + komponentkodeverdi=row.get("ID", "") + ) if row.get("ID") else None + max_height = ( + parse_float(row["Vertikalavstand meter (NRL)"], "Vertikalavstand") + if row.get("Vertikalavstand meter (NRL)") + else None + ) + + point, crs = create_geometry( + [[row["x"], row["y"], row.get("z", "")]], is_line=False + ) + + return Feature( + geometry=point, + properties=NrlMast( + komponentident=komponentident, + status=feature_status, + verifisert_rapporteringsnøyaktighet=nøyaktighet, + feature_type="NrlMast", + mast_type=masttype, + luftfartshinderlyssetting=lyssetting if lyssetting is not None else None, + luftfartshindermerking=merking if merking is not None else None, + høydereferanse=høydereferanse if høydereferanse is not None else None, + vertikal_avstand=max_height if max_height is not None else None, + navn=navn if navn is not None else None, + referanse=referanse if referanse is not None else None, + ), + ), crs + + +def convert_guy_segments_rows(row: dict[str, str]) -> tuple[Feature, Crs]: + """Convert guy wire segments to NrlLuftspenn feature.""" + komponentident = get_uuid(row, "Guy_uuid", "ID") + feature_status = map_feature_status(row.get("Status (NRL)")) + nøyaktighet = map_location_method(row.get("Vertikalavstand meter (NRL)")) + luftspennstype: LuftspennType = map_luftspenn_type( + row.get("Luftspenntype (NRL)") + ) + linestring, crs = create_geometry( + [ + [row["x1"], row["y1"], row.get("z1", "")], + [row["x2"], row["y2"], row.get("z2", "")], + ] + ) + + komponentreferanse = ( + KomponentReferanse(komponentkodeverdi=row.get("ID", "")) + if row.get("ID") + else None + ) + navn = row.get("Betegnelse") + + return Feature( + geometry=linestring, + properties=NrlLuftspenn( + luftspenn_type=luftspennstype, + komponentident=komponentident, + status=feature_status, + verifisert_rapporteringsnøyaktighet=nøyaktighet, + feature_type="NrlLuftspenn", + referanse=komponentreferanse, + navn=navn if navn is not None else None + ), + ), crs + + +def convert_ac_linesegments_rows(row: dict[str, str]) -> tuple[Feature, Crs]: + """Convert AC line segments to NrlLuftspenn feature.""" + komponentident = get_uuid(row, "ACLineSegmentSpan_uuid", "ID") + feature_status = map_feature_status(row.get("Status (NRL)")) + luftspennstype: LuftspennType = map_luftspenn_type( + row.get("Luftspenntype (NRL)") + ) + + nøyaktighet: Literal["20230101_5-1","0"] = map_location_method( + row.get("Verifisert nøyaktighet (NRL)" + ) + ) + + lyssetting: LuftfartsHinderLyssetting | None = map_lighting_kind( + "Luftfartshinderlyssetting(NRL)" + ) + merking: LuftfartsHinderMerking | None = map_marking_kind( + "Luftfartshindermerking(NRL)" + ) + + navn = row.get("Betegnelse") + + linestring, crs = create_geometry( + [ + [row["x1"], row["y1"], row.get("z1", "")], + [row["x2"], row["y2"], row.get("z2", "")], + ] + ) + + mast = [ + uuid.UUID(row[f"Mast_{i}_ObjectID"]) + for i in [1, 2] + if row.get(f"Mast_{i}_ObjectID") + ] + + komponentreferanse = ( + KomponentReferanse(komponentkodeverdi=row.get("ID", "")) + if row.get("ID") + else None + ) + anleggsbredde = ( + parse_float(row["Anleggsbredde meter (NRL)"], "Anleggsbredde") + if row.get("Anleggsbredde meter (NRL)") + else None + ) + + return Feature( + geometry=linestring, + properties=NrlLuftspenn( + luftspenn_type=luftspennstype, + komponentident=komponentident, + nrl_mast=mast, + status=feature_status, + verifisert_rapporteringsnøyaktighet=nøyaktighet, + feature_type="NrlLuftspenn", + referanse=komponentreferanse, + luftfartshinderlyssetting=lyssetting if lyssetting is not None else None, + luftfartshindermerking=merking if merking is not None else None, + anleggsbredde=anleggsbredde if anleggsbredde is not None else None, + navn=navn if navn is not None else None + ), + ), crs diff --git a/nrl-sdk-lib/tests/files/1_bardun.csv b/nrl-sdk-lib/tests/files/1_bardun.csv new file mode 100644 index 0000000..8fd5326 --- /dev/null +++ b/nrl-sdk-lib/tests/files/1_bardun.csv @@ -0,0 +1,2 @@ +ID;Tabell ID;Klasse;Klasse;Father ID;x1;y1;z1;x2;y2;z2;Lengde (m);Bryterens tilstand 1;Bryterens tilstand 2;Betegnelse;Betegnelse x;Betegnelse y;LabelDirection;Planbetegnelse;Brukernavn;Operativt område;Endret;Driftsstatus;Arbeidets ID;Statistic;Datakilde;Status;Planlagt endring;Opprinnelig plan;Systemoperatør;Ekstern ID;Eksternt område-ID;Konstruksjon ID;Teknisk type-ID;CutId;Område;Eier;Guy_uuid;Miljø;Dybde (cm);Tverrsnitt-ID;Merknad;HREF (Lidar);SmartGIS verfisert;ObjektID (Lidar);Mast_2_ObjectID;Mast_1_ObjectID;Luftspenntype (NRL);Rapportering (NRL);Hoydereferanse (NRL);Vertikalavstand meter (NRL);Verifisert nøyaktighet (NRL);Status (NRL);Kvalitet (Lidar);Brannklasse;NRL Datavask merknad Lede;NRL Datavask kommentar Lede;NRL Datavask Komponentident;NRL Datavask - Kommentar Kartv;NRL Datavask - Eiermatch;UUIDv4;Anleggsbredde meter (NRL);Luftfartshinderlyssetting(NRL);Luftfartshindermerking (NRL);Typebetegnelse Fiber rør;Prosjektansvarlig selskap;Stikkledning;Stedfestingsarsak;Datafangstdato;Vertikalniva;Maks avvik horisontalt (cm);Maks avvik vertikalt (cm);Hoydereferanse;Stedfestingsforhold;Noyaktighet hoyde (cm);Malemetode hoyde (cm);Malemetode;Hovedbruk;NRL_Eiermatch;Ytre hoyde (cm);Ytre bredde (cm);Regional_Nett;UBW-nummer;Typebetegnelse;Tverrsnitt;Create User;Create Date;Noyaktighet;Id på gml. erstattet komponent +188488519;261;11029;Bardunline;0;6539567,996;559404,7227;0;6539579,281;559419,7617;0;18,80234433;0;0;Bardunline;0;0;3,141592654;KGASLVLVLV;KGAS;70564885;19.09.2025;I bruk;0;0;Innmålt NRL;0;0;MAHEPOIENDRINGE;Lede AS;0;0;0;0;0;Larvik;Lede AS;0291c89b-8294-4c5c-9061-445149e68330;Ikke bestemt;0;0;;;;;;;Bardun;Rapporteres NRL;Velg;0;Ingen;Eksisterende;;Velg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAHE2;08.11.2024;; \ No newline at end of file diff --git a/nrl-sdk-lib/tests/files/1_luftspenn.csv b/nrl-sdk-lib/tests/files/1_luftspenn.csv new file mode 100644 index 0000000..a30b819 --- /dev/null +++ b/nrl-sdk-lib/tests/files/1_luftspenn.csv @@ -0,0 +1,2 @@ +ID;Tabell ID;Klasse;Klasse;Father ID;x1;y1;z1;x2;y2;z2;Lengde (m);Bryterens tilstand 1;Bryterens tilstand 2;Betegnelse;Betegnelse x;Betegnelse y;LabelDirection;Planbetegnelse;Brukernavn;Operativt område;Endret;Driftsstatus;Arbeidets ID;Statistic;Datakilde;Status;Planlagt endring;Opprinnelig plan;Systemoperatør;Ekstern ID;Eksternt område-ID;Konstruksjon ID;Teknisk type-ID;CutId;Område;Eier;Miljø;Dybde (cm);Tverrsnitt-ID;Merknad;Luftspenntype (NRL);Rapportering (NRL);Hoydereferanse (NRL);Vertikalavstand meter (NRL);Verifisert nøyaktighet (NRL);Status (NRL);ObjektID (Lidar);Kvalitet (Lidar);NRL Datavask merknad Lede;NRL Datavask kommentar Lede;NRL Datavask Komponentident;NRL Datavask - Kommentar Kartv;NRL Datavask - Eiermatch;UUIDv4;Anleggsbredde meter (NRL);Luftfartshinderlyssetting(NRL);Luftfartshindermerking (NRL);Typebetegnelse Fiber rør;Prosjektansvarlig selskap;Stikkledning;Stedfestingsarsak;Datafangstdato;Vertikalniva;Maks avvik horisontalt (cm);Maks avvik vertikalt (cm);Hoydereferanse;Stedfestingsforhold;Noyaktighet hoyde (cm);Malemetode hoyde (cm);Malemetode;Hovedbruk;NRL_Eiermatch;Ytre hoyde (cm);Ytre bredde (cm);Regional_Nett;UBW-nummer;Typebetegnelse;Tverrsnitt;Create User;Create Date;Noyaktighet;Id på gml. erstattet komponent +d6716fda-aac4-4229-9e2d-690a32dc5214;261;11011;Luftnett LS trase;0;6544040,344;582430,5569;;6544042,58;582087,7993;;34276,49223;0;0;Luftnett;0;0;200;MABJLIDARNRL;INGEB;70564885;25.02.2025;I bruk;0;0;0;64;0;;Lede AS;0;0;0;0;0;Ski;Lede AS;Ikke bestemt;0;0;;Ledning, lavspent;Rapportering NRL utført;topp;;1;planlagtOppført;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; \ No newline at end of file diff --git a/nrl-sdk-lib/tests/files/1_mast.csv b/nrl-sdk-lib/tests/files/1_mast.csv new file mode 100644 index 0000000..81cb9ab --- /dev/null +++ b/nrl-sdk-lib/tests/files/1_mast.csv @@ -0,0 +1,2 @@ +ID;Tabell ID;Klasse;Klasse;Father ID;x;y;z;Retning;Tilstand;Betegnelse;Betegnelse x;Betegnelse y;LabelDirection;Planbetegnelse;Brukernavn;Operativt område;Endret;Driftsstatus;Arbeidets ID;Statistic;Datakilde;Status;Planlagt endring;Opprinnelig plan;Område;Eier;Systemoperatør;Ekstern ID;Eksternt område-ID;Konstruksjon ID;Teknisk type-ID;Kombinert bruk;Installasjonsår;HSp-linje;LSp-linje;Totalhøyde (m);Høyde 2;Stolpeklasse;Synlig høyde (m);Stolpetype;Impregnering;Fundament-type;Type 1;Materiale 1;Isolator 1;Jordbånddiameter (mm);Kombinert bruk 1;Kombinert bruk 2;Kombinert bruk 3;Kombinert bruk 4;Kombinert bruk 5;Kombinert bruk 6;Merknad;Masttype (NRL);Utskiftningsår travers;UUIDv4;Rapportering (NRL);Hoydereferanse (NRL);Luftfartshinderlyssetting(NRL);Luftfartshindermerking (NRL);Vertikalavstand meter (NRL);Verifisert nøyaktighet (NRL);Status (NRL);Aktør 4;Aktør 5;Aktør 6;Søknads nr Aktør 4;Søknads nr Aktør 5;Søknads nr Aktør 6;Aktør Veilys;Kryssende luftspenn;GPS Longitude;GPS Latitude;UBW-nummer;Regional_Nett;INVKLASSE;SAMMENFØYINGITOPP;Create User;Create Date;Søknadsnr :;Søker :;Veilys mastnr :;Driftsmerking :;Fellesføring nr :;Avgrening;Hovedlinje;Bardun antall (Stk);Anleggsbidrag;Grunnforhold fundament;IsolatorType :;Bardun type;Jordelektrode (Type, mm2);MMS Tekst;Byggeklausulert bredde (m);Ryddeklausulert bredde (m);Horisontal faseavstand (m);Antall isolatorskåler (stk);Jordbånd dim. (cm);Samsvarserklæring;Årstall venstrebein;Årstall høyrebein;Årstall mitrebein;KILE_B;Aktør 1;Aktør 2;Aktør 3;Søknads nr Aktør 1;Søknads nr Aktør 2;Søknads nr Aktør 3;PD: Skalltykkelse(mm);PD: Min frisk diameter(mm);PD: Min diameter(mm);Stagtvinge bardun;Til plan (MMS);PD: Underdimisjonert;PD: Råtten/Byttes;Avgang;Stasjon;Id på gml. erstattet komponent;Risikoindeks +fa1bf202-345c-49f0-831b-5d5a12103612;109;650;LS Stolpe;0;6544773,145;585243,7955;;81;0;LM83700;0;0;0;MABJLIDARNRL;THORH;70564885;25.02.2025;I bruk;0;0;8501;64;0;;Kristiansand;Lede AS;Lede AS;0;0;0;0;Nei;2001;0;650;0;0;0;11;Tre;Salt;Stolpe på fjell;;;;180;Udefinert;Udefinert;Udefinert;Udefinert;Udefinert;Udefinert;;Mast, lavspent;;;Rapportering NRL utført;topp;;;;1;planlagtOppført;;;;;;;;;11.62986;67.77285;;;;;;;;;;;;;;;;;;;;;;;;;18;;;;;;;;;;;;;;;;;;;;;; \ No newline at end of file diff --git a/nrl-sdk-lib/tests/test_csv_to_geojson.py b/nrl-sdk-lib/tests/test_csv_to_geojson.py new file mode 100644 index 0000000..a0faa95 --- /dev/null +++ b/nrl-sdk-lib/tests/test_csv_to_geojson.py @@ -0,0 +1,518 @@ +"""Tests for csv_to_geojson converter.""" +import csv +import io +import os +import sys +import tempfile +import uuid +from pathlib import Path +from unittest.mock import patch + +import pytest + +from nrl_sdk_lib.converters.csv_to_geojson import ( + create_geometry, + csv_to_geojson, + get_uuid, + map_feature_status, + map_lighting_kind, + map_location_method, + parse_float, +) +from nrl_sdk_lib.models import FeatureCollection, Høydereferanse # noqa:PLC2403 + + +@pytest.mark.anyio +def test_csv_to_geojson_1_mast() -> None: + """Should create a valid geojson file from csv with 1 mast.""" + input_csv = "tests/files/1_mast.csv" + + actual_content = csv_to_geojson(input_csv) + + assert len(actual_content) == 1 + assert isinstance(actual_content[0], FeatureCollection) + assert actual_content[0].crs.properties.name == "EPSG:25832" + assert actual_content[0].features[0].geometry.coordinates == pytest.approx( + [585243.7955, 6544773.145] + , rel=1e-6) + assert actual_content[0].features[0].geometry.type == "Point" + assert actual_content[0].features[0].properties.feature_type == "NrlMast" + assert (actual_content[0] + .features[0] + .properties + .høydereferanse + ) == Høydereferanse.topp + assert (actual_content[0] + .features[0] + .properties + .komponentident + ) == uuid.UUID("fa1bf202-345c-49f0-831b-5d5a12103612") + assert hasattr(actual_content[0].features[0].properties, "mast_type") + assert actual_content[0].features[0].properties.mast_type == "lavspentmast" + assert actual_content[0].features[0].properties.status == "planlagtOppført" + assert actual_content[0].features[0].properties.navn == "LM83700" + assert hasattr(actual_content[0] + .features[0] + .properties + .referanse, "komponentkodeverdi") + assert (actual_content[0] + .features[0] + .properties + .referanse.komponentkodeverdi + ) == "fa1bf202-345c-49f0-831b-5d5a12103612" + assert (actual_content[0] + .features[0] + .properties + .verifisert_rapporteringsnøyaktighet) == "0" + + +@pytest.mark.anyio +def test_csv_to_geojson_1_luftspenn() -> None: + """Should create a valid geojson file from csv with 1 luftspenn.""" + input_csv = "tests/files/1_luftspenn.csv" + + actual_content = csv_to_geojson(input_csv) + + assert len(actual_content) == 1 + assert isinstance(actual_content[0], FeatureCollection) + assert actual_content[0].crs.properties.name == "EPSG:25832" + assert actual_content[0].features[0].geometry.coordinates[0] == pytest.approx( + [582430.5569299466,6544040.344467209] + , rel=1e-4 + ) + assert actual_content[0].features[0].geometry.coordinates[1] == pytest.approx( + [582087.7992964027,6544042.579778018] + , rel=1e-4 + ) + assert actual_content[0].features[0].geometry.type == "LineString" + assert actual_content[0].features[0].properties.feature_type == "NrlLuftspenn" + assert (actual_content[0] + .features[0] + .properties + .komponentident + ) == uuid.UUID("d6716fda-aac4-4229-9e2d-690a32dc5214") + assert hasattr(actual_content[0].features[0].properties, "luftspenn_type") + assert actual_content[0].features[0].properties.luftspenn_type == "lavspent" + assert actual_content[0].features[0].properties.status == "planlagtOppført" + assert hasattr( + actual_content[0].features[0].properties.referanse, + "komponentkodeverdi" + ) + assert (actual_content[0] + .features[0] + .properties + .referanse + .komponentkodeverdi + ) == "d6716fda-aac4-4229-9e2d-690a32dc5214" + assert actual_content[0].features[0].properties.navn == "Luftnett" + assert (actual_content[0] + .features[0] + .properties + .verifisert_rapporteringsnøyaktighet + ) == "0" + + +@pytest.mark.anyio +def test_csv_to_geojson_1_bardun() -> None: + """Should create a valid geojson file from csv with 1 bardun.""" + input_csv = "tests/files/1_bardun.csv" + + actual_content = csv_to_geojson(input_csv) + + assert len(actual_content) == 1 + assert isinstance(actual_content[0], FeatureCollection) + assert actual_content[0].crs.properties.name == "EPSG:5972" + assert actual_content[0].features[0].geometry.coordinates[0] == pytest.approx( + [559404.7227,6539567.9961,0.0] + ,rel=1e-4 + ) + assert actual_content[0].features[0].geometry.coordinates[1] == pytest.approx( + [559419.7617,6539579.2813,0.0] + , rel=1e-4 + ) + assert actual_content[0].features[0].geometry.type == "LineString" + assert actual_content[0].features[0].properties.feature_type == "NrlLuftspenn" + assert hasattr(actual_content[0].features[0].properties, "luftspenn_type") + assert actual_content[0].features[0].properties.luftspenn_type == "bardun" + assert actual_content[0].features[0].properties.status == "eksisterende" + assert hasattr( + actual_content[0].features[0].properties.referanse, + "komponentkodeverdi" + ) + assert (actual_content[0] + .features[0] + .properties + .komponentident) == uuid.UUID( + "0291c89b-8294-4c5c-9061-445149e68330" + ) + assert (actual_content[0] + .features[0] + .properties + .referanse.komponentkodeverdi) == "188488519" + assert actual_content[0].features[0].properties.navn == "Bardunline" + assert (actual_content[0] + .features[0] + .properties + .verifisert_rapporteringsnøyaktighet) == "0" + + +def test_csv_to_geojson_file_object() -> None: + """Should read from file-like object.""" + gen_uuid = uuid.uuid4() + csv_content = ("Tabell ID;" + "x;" + "y;" + "z;" + "OverheadStructure_uuid;" + "Masttype (NRL);" + "Status (NRL)\n" + f"109;100;200;10;{gen_uuid};Mast, lavspent;Eksisterende\n") + file_obj = io.StringIO(csv_content) + result = csv_to_geojson(file_obj) + assert len(result) > 0 + assert result[0].features[0].properties.feature_type == "NrlMast" + +def test_csv_to_geojson_reads_from_stdin() -> None: + """Should read from stdin if no filename is given.""" + gen_uuid = uuid.uuid4() + csv_content = ("Tabell ID;" + "x;" + "y;" + "z;" + "OverheadStructure_uuid;" + "Masttype (NRL);" + "Status (NRL)\n" + f"109;100;200;10;{gen_uuid};Mast, lavspent;Eksisterende\n") + fake_stdin = io.StringIO(csv_content) + with patch.object(sys, "stdin", fake_stdin): + result = csv_to_geojson(None) + assert len(result) > 0 + assert result[0].features[0].properties.feature_type == "NrlMast" + +def test_get_uuid_valid() -> None: + """Test UUID extraction with valid UUID.""" + row = {"field1": "550e8400-e29b-41d4-a716-446655440000", "field2": "other"} + result = get_uuid(row, "field1", "field2") + assert str(result) == "550e8400-e29b-41d4-a716-446655440000" + + +def test_get_uuid_fallback() -> None: + """Test UUID extraction with fallback field.""" + row = {"field1": "invalid", "field2": "550e8400-e29b-41d4-a716-446655440000"} + result = get_uuid(row, "field1", "field2") + assert str(result) == "550e8400-e29b-41d4-a716-446655440000" + + +def test_get_uuid_missing() -> None: + """Test UUID extraction when no valid UUID exists.""" + row = {"field1": "invalid", "field2": "also-invalid"} + with pytest.raises(ValueError, match="No valid UUID found"): + get_uuid(row, "field1", "field2") + + +def test_parse_float_valid() -> None: + """Test parsing valid float.""" + assert parse_float("123.45", "test_field") == 123.45 + + +def test_parse_float_comma_decimal() -> None: + """Test parsing float with comma as decimal separator.""" + assert parse_float("123,45", "test_field") == 123.45 + + +def test_parse_float_invalid() -> None: + """Test parsing invalid float.""" + with pytest.raises(ValueError, match="not a valid number"): + parse_float("not_a_number", "test_field") + + +def test_create_geometry_line_with_z() -> None: + """Test creating LineString with z coordinates.""" + coords = [["100", "200", "10"], ["300", "400", "20"]] + geometry, crs = create_geometry(coords, is_line=True) + + assert geometry.type == "LineString" + assert isinstance(geometry.coordinates[0], list) + assert len(geometry.coordinates) == 2 + assert len(geometry.coordinates[0]) == 3 # Has z + assert crs.properties.name == "EPSG:5972" + + +def test_create_geometry_line_without_z() -> None: + """Test creating LineString without z coordinates.""" + coords = [["100", "200", ""], ["300", "400", ""]] + geometry, crs = create_geometry(coords, is_line=True) + + assert geometry.type == "LineString" + assert isinstance(geometry.coordinates[0], list) + assert len(geometry.coordinates) == 2 + assert len(geometry.coordinates[0]) == 2 # No z + assert crs.properties.name == "EPSG:25832" + + +def test_create_geometry_point_with_z() -> None: + """Test creating Point with z coordinate.""" + coords = [["100", "200", "10"]] + geometry, crs = create_geometry(coords, is_line=False) + + assert geometry.type == "Point" + assert len(geometry.coordinates) == 3 # Has z + assert crs.properties.name == "EPSG:5972" + + +def test_create_geometry_point_without_z() -> None: + """Test creating Point without z coordinate.""" + coords = [["100", "200", ""]] + geometry, crs = create_geometry(coords, is_line=False) + + assert geometry.type == "Point" + assert len(geometry.coordinates) == 2 # No z + assert crs.properties.name == "EPSG:25832" + + +def test_create_geometry_invalid_coords() -> None: + """Test creating geometry with invalid coordinates.""" + coords = [["not", "numbers", "10"], ["300", "400", "20"]] + with pytest.raises(ValueError, match="Invalid coordinate values"): + create_geometry(coords, is_line=True) + + +def test_map_feature_status_valid() -> None: + """Test mapping valid value.""" + result = map_feature_status("Eksisterende") + assert result is not None + +def test_map_feature_status_missing() -> None: + """Test mapping with missing value.""" + with pytest.raises(ValueError, match="Unknown Status"): + map_feature_status("") + +def test_map_feature_status_unknown() -> None: + """Test mapping with unknown value.""" + with pytest.raises(ValueError, match="Unknown Status"): + map_feature_status("InvalidStatus") + +def test_map_lighting_kind_allow_none() -> None: + """Test mapping with allow_none (returns None for empty value).""" + result = map_lighting_kind("") + assert result is None + +def test_map_location_kind() -> None: + """Test both location kinds.""" + result = map_location_method("FOR-2020-10-16-2068, §5(1)") + assert result == "20230101_5-1" + result = map_location_method("Some other value") + assert result == "0" + +def create_test_csv(content: list[dict], filename: str | None) -> str | None: + """Create a temporary CSV file.""" + if filename is None: + fd, filename = tempfile.mkstemp(suffix=".csv") + os.close(fd) + + with Path(filename).open("w", newline="", encoding="utf-8-sig") as f: + if content: + writer = csv.DictWriter(f, fieldnames=content[0].keys(), delimiter=";") + writer.writeheader() + writer.writerows(content) + + return filename + + +def test_csv_invalid_mast_type() -> None: + """Test handling invalid mast type.""" + content = [ + { + "Tabell ID": "109", + "OverheadStructure_uuid": "550e8400-e29b-41d4-a716-446655440000", + "Masttype (NRL)": "InvalidType", + "Status (NRL)": "Eksisterende", + "x": "100", + "y": "200", + "z": "10", + } + ] + + filename = create_test_csv(content, filename=None) + + with pytest.raises(ValueError, match="Unknown Masttype"): + csv_to_geojson(filename) + + +def test_csv_missing_status() -> None: + """Test handling missing status field.""" + content = [ + { + "Tabell ID": "109", + "OverheadStructure_uuid": "550e8400-e29b-41d4-a716-446655440000", + "Masttype (NRL)": "Mast, høyspent", + "Status (NRL)": "", + "x": "100", + "y": "200", + "z": "10", + } + ] + + filename = create_test_csv(content, filename=None) + + with pytest.raises(ValueError, match="Unknown Status:"): + csv_to_geojson(filename) + +def test_no_tabell_id() -> None: + """Test handling missing Tabell ID.""" + content = [ + { + "OverheadStructure_uuid": "550e8400-e29b-41d4-a716-446655440000", + "Masttype (NRL)": "Mast, høyspent", + "Status (NRL)": "Eksisterende", + "x": "100", + "y": "200", + "z": "10", + } + ] + + filename = create_test_csv(content, filename=None) + + with pytest.raises(ValueError, match="Unknown Tabell ID:"): + csv_to_geojson(filename) + +def test_parse_float_none_value() -> None: + """Test parsing None value.""" + with pytest.raises(ValueError, match="Missing test_field"): + parse_float(None, "test_field") + +def test_create_geometry_line_invalid_number_of_points() -> None: + """Test creating LineString with invalid number of points.""" + coords = [["100", "200", "10"]] + with pytest.raises(ValueError, match="LineString requires exactly 2 points"): + create_geometry(coords, is_line=True) + +def test_csv_optional_lighting_and_marking() -> None: + """Test handling optional lighting and marking fields.""" + content = [ + { + "Tabell ID": "109", + "OverheadStructure_uuid": "550e8400-e29b-41d4-a716-446655440000", + "Masttype (NRL)": "Mast, høyspent", + "Status (NRL)": "Eksisterende", + "Luftfartshinderlyssetting(NRL)": "Lyssatt", + "Luftfartshindermerking (NRL)": "Fargemerking", + "x": "100", + "y": "200", + "z": "10", + } + ] + + filename = create_test_csv(content, filename=None) + result = csv_to_geojson(filename) + + assert len(result) > 0 + feature = result[0].features[0] + assert feature.properties.luftfartshinderlyssetting is not None + assert feature.properties.luftfartshindermerking is not None + + +def test_csv_guy_segment_missing_uuid() -> None: + """Test guy segment with missing UUID.""" + content = [ + { + "Tabell ID": "261", + "Betegnelse": "Bardunline", + "Guy_uuid": "", + "Status (NRL)": "Eksisterende", + "x1": "100", + "y1": "200", + "z1": "10", + "x2": "300", + "y2": "400", + "z2": "20", + } + ] + + filename = create_test_csv(content, filename=None) + + with pytest.raises(ValueError, match="No valid UUID found"): + csv_to_geojson(filename) + + +def test_csv_luftspenn_invalid_type() -> None: + """Test luftspenn with invalid type.""" + content = [ + { + "Tabell ID": "261", + "Betegnelse": "Ledning", + "ACLineSegmentSpan_uuid": "550e8400-e29b-41d4-a716-446655440000", + "Status (NRL)": "Eksisterende", + "Luftspenntype (NRL)": "InvalidType", + "x1": "100", + "y1": "200", + "z1": "10", + "x2": "300", + "y2": "400", + "z2": "20", + } + ] + + filename = create_test_csv(content, filename=None) + + with pytest.raises(ValueError, match="Unknown Luftspenntype"): + csv_to_geojson(filename) + + +def test_csv_multiple_crs() -> None: + """Test CSV with features in different CRS.""" + content = [ + { + "Tabell ID": "109", + "OverheadStructure_uuid": "550e8400-e29b-41d4-a716-446655440000", + "Masttype (NRL)": "Mast, høyspent", + "Status (NRL)": "Eksisterende", + "x": "100", + "y": "200", + "z": "10", + }, + { + "Tabell ID": "109", + "OverheadStructure_uuid": "550e8400-e29b-41d4-a716-446655440001", + "Masttype (NRL)": "Mast, høyspent", + "Status (NRL)": "Eksisterende", + "x": "100", + "y": "200", + "z": "", # No z = different CRS + }, + ] + + filename = create_test_csv(content, filename=None) + result = csv_to_geojson(filename) + + # Should create 2 FeatureCollections (one per CRS) + assert len(result) == 2 + + +def test_csv_with_anleggsbredde() -> None: + """Test luftspenn with anleggsbredde field.""" + content = [ + { + "Tabell ID": "261", + "Betegnelse": "Ledning", + "ACLineSegmentSpan_uuid": "550e8400-e29b-41d4-a716-446655440000", + "Status (NRL)": "Eksisterende", + "Luftspenntype (NRL)": "Ledning, høyspent", + "Anleggsbredde meter (NRL)": "5.5", + "x1": "100", + "y1": "200", + "z1": "10", + "x2": "300", + "y2": "400", + "z2": "20", + } + ] + + filename = create_test_csv(content, filename=None) + result = csv_to_geojson(filename) + + assert len(result) > 0 + feature = result[0].features[0] + + assert hasattr(feature.properties, "anleggsbredde") + assert feature.properties.anleggsbredde == 5.5 diff --git a/nrl-sdk-lib/uv.lock b/nrl-sdk-lib/uv.lock index 13d64fb..2407db9 100644 --- a/nrl-sdk-lib/uv.lock +++ b/nrl-sdk-lib/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.13" [[package]] @@ -26,11 +26,11 @@ wheels = [ [[package]] name = "attrs" -version = "25.3.0" +version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +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" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, + { 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" }, ] [[package]] @@ -62,11 +62,11 @@ filecache = [ [[package]] name = "certifi" -version = "2025.8.3" +version = "2025.10.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, + { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, ] [[package]] @@ -471,7 +471,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.11.9" +version = "2.11.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -479,9 +479,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/54/ecab642b3bed45f7d5f59b38443dcb36ef50f85af192e6ece103dbfe9587/pydantic-2.11.10.tar.gz", hash = "sha256:dc280f0982fbda6c38fada4e476dc0a4f3aeaf9c6ad4c28df68a666ec3c61423", size = 788494, upload-time = "2025-10-04T10:40:41.338Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" }, + { url = "https://files.pythonhosted.org/packages/bd/1f/73c53fcbfb0b5a78f91176df41945ca466e71e9d9d836e5c522abda39ee7/pydantic-2.11.10-py3-none-any.whl", hash = "sha256:802a655709d49bd004c31e865ef37da30b540786a46bfce02333e0e24b5fe29a", size = 444823, upload-time = "2025-10-04T10:40:39.055Z" }, ] [[package]] @@ -663,28 +663,28 @@ wheels = [ [[package]] name = "ruff" -version = "0.13.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/df/8d7d8c515d33adfc540e2edf6c6021ea1c5a58a678d8cfce9fae59aabcab/ruff-0.13.2.tar.gz", hash = "sha256:cb12fffd32fb16d32cef4ed16d8c7cdc27ed7c944eaa98d99d01ab7ab0b710ff", size = 5416417, upload-time = "2025-09-25T14:54:09.936Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/84/5716a7fa4758e41bf70e603e13637c42cfb9dbf7ceb07180211b9bbf75ef/ruff-0.13.2-py3-none-linux_armv6l.whl", hash = "sha256:3796345842b55f033a78285e4f1641078f902020d8450cade03aad01bffd81c3", size = 12343254, upload-time = "2025-09-25T14:53:27.784Z" }, - { url = "https://files.pythonhosted.org/packages/9b/77/c7042582401bb9ac8eff25360e9335e901d7a1c0749a2b28ba4ecb239991/ruff-0.13.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ff7e4dda12e683e9709ac89e2dd436abf31a4d8a8fc3d89656231ed808e231d2", size = 13040891, upload-time = "2025-09-25T14:53:31.38Z" }, - { url = "https://files.pythonhosted.org/packages/c6/15/125a7f76eb295cb34d19c6778e3a82ace33730ad4e6f28d3427e134a02e0/ruff-0.13.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c75e9d2a2fafd1fdd895d0e7e24b44355984affdde1c412a6f6d3f6e16b22d46", size = 12243588, upload-time = "2025-09-25T14:53:33.543Z" }, - { url = "https://files.pythonhosted.org/packages/9e/eb/0093ae04a70f81f8be7fd7ed6456e926b65d238fc122311293d033fdf91e/ruff-0.13.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cceac74e7bbc53ed7d15d1042ffe7b6577bf294611ad90393bf9b2a0f0ec7cb6", size = 12491359, upload-time = "2025-09-25T14:53:35.892Z" }, - { url = "https://files.pythonhosted.org/packages/43/fe/72b525948a6956f07dad4a6f122336b6a05f2e3fd27471cea612349fedb9/ruff-0.13.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6ae3f469b5465ba6d9721383ae9d49310c19b452a161b57507764d7ef15f4b07", size = 12162486, upload-time = "2025-09-25T14:53:38.171Z" }, - { url = "https://files.pythonhosted.org/packages/6a/e3/0fac422bbbfb2ea838023e0d9fcf1f30183d83ab2482800e2cb892d02dfe/ruff-0.13.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f8f9e3cd6714358238cd6626b9d43026ed19c0c018376ac1ef3c3a04ffb42d8", size = 13871203, upload-time = "2025-09-25T14:53:41.943Z" }, - { url = "https://files.pythonhosted.org/packages/6b/82/b721c8e3ec5df6d83ba0e45dcf00892c4f98b325256c42c38ef136496cbf/ruff-0.13.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c6ed79584a8f6cbe2e5d7dbacf7cc1ee29cbdb5df1172e77fbdadc8bb85a1f89", size = 14929635, upload-time = "2025-09-25T14:53:43.953Z" }, - { url = "https://files.pythonhosted.org/packages/c4/a0/ad56faf6daa507b83079a1ad7a11694b87d61e6bf01c66bd82b466f21821/ruff-0.13.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aed130b2fde049cea2019f55deb939103123cdd191105f97a0599a3e753d61b0", size = 14338783, upload-time = "2025-09-25T14:53:46.205Z" }, - { url = "https://files.pythonhosted.org/packages/47/77/ad1d9156db8f99cd01ee7e29d74b34050e8075a8438e589121fcd25c4b08/ruff-0.13.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1887c230c2c9d65ed1b4e4cfe4d255577ea28b718ae226c348ae68df958191aa", size = 13355322, upload-time = "2025-09-25T14:53:48.164Z" }, - { url = "https://files.pythonhosted.org/packages/64/8b/e87cfca2be6f8b9f41f0bb12dc48c6455e2d66df46fe61bb441a226f1089/ruff-0.13.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5bcb10276b69b3cfea3a102ca119ffe5c6ba3901e20e60cf9efb53fa417633c3", size = 13354427, upload-time = "2025-09-25T14:53:50.486Z" }, - { url = "https://files.pythonhosted.org/packages/7f/df/bf382f3fbead082a575edb860897287f42b1b3c694bafa16bc9904c11ed3/ruff-0.13.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:afa721017aa55a555b2ff7944816587f1cb813c2c0a882d158f59b832da1660d", size = 13537637, upload-time = "2025-09-25T14:53:52.887Z" }, - { url = "https://files.pythonhosted.org/packages/51/70/1fb7a7c8a6fc8bd15636288a46e209e81913b87988f26e1913d0851e54f4/ruff-0.13.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1dbc875cf3720c64b3990fef8939334e74cb0ca65b8dbc61d1f439201a38101b", size = 12340025, upload-time = "2025-09-25T14:53:54.88Z" }, - { url = "https://files.pythonhosted.org/packages/4c/27/1e5b3f1c23ca5dd4106d9d580e5c13d9acb70288bff614b3d7b638378cc9/ruff-0.13.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939a1b2a960e9742e9a347e5bbc9b3c3d2c716f86c6ae273d9cbd64f193f22", size = 12133449, upload-time = "2025-09-25T14:53:57.089Z" }, - { url = "https://files.pythonhosted.org/packages/2d/09/b92a5ccee289f11ab128df57d5911224197d8d55ef3bd2043534ff72ca54/ruff-0.13.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:50e2d52acb8de3804fc5f6e2fa3ae9bdc6812410a9e46837e673ad1f90a18736", size = 13051369, upload-time = "2025-09-25T14:53:59.124Z" }, - { url = "https://files.pythonhosted.org/packages/89/99/26c9d1c7d8150f45e346dc045cc49f23e961efceb4a70c47dea0960dea9a/ruff-0.13.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:3196bc13ab2110c176b9a4ae5ff7ab676faaa1964b330a1383ba20e1e19645f2", size = 13523644, upload-time = "2025-09-25T14:54:01.622Z" }, - { url = "https://files.pythonhosted.org/packages/f7/00/e7f1501e81e8ec290e79527827af1d88f541d8d26151751b46108978dade/ruff-0.13.2-py3-none-win32.whl", hash = "sha256:7c2a0b7c1e87795fec3404a485096bcd790216c7c146a922d121d8b9c8f1aaac", size = 12245990, upload-time = "2025-09-25T14:54:03.647Z" }, - { url = "https://files.pythonhosted.org/packages/ee/bd/d9f33a73de84fafd0146c6fba4f497c4565fe8fa8b46874b8e438869abc2/ruff-0.13.2-py3-none-win_amd64.whl", hash = "sha256:17d95fb32218357c89355f6f6f9a804133e404fc1f65694372e02a557edf8585", size = 13324004, upload-time = "2025-09-25T14:54:06.05Z" }, - { url = "https://files.pythonhosted.org/packages/c3/12/28fa2f597a605884deb0f65c1b1ae05111051b2a7030f5d8a4ff7f4599ba/ruff-0.13.2-py3-none-win_arm64.whl", hash = "sha256:da711b14c530412c827219312b7d7fbb4877fb31150083add7e8c5336549cea7", size = 12484437, upload-time = "2025-09-25T14:54:08.022Z" }, +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/8e/f9f9ca747fea8e3ac954e3690d4698c9737c23b51731d02df999c150b1c9/ruff-0.13.3.tar.gz", hash = "sha256:5b0ba0db740eefdfbcce4299f49e9eaefc643d4d007749d77d047c2bab19908e", size = 5438533, upload-time = "2025-10-02T19:29:31.582Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/33/8f7163553481466a92656d35dea9331095122bb84cf98210bef597dd2ecd/ruff-0.13.3-py3-none-linux_armv6l.whl", hash = "sha256:311860a4c5e19189c89d035638f500c1e191d283d0cc2f1600c8c80d6dcd430c", size = 12484040, upload-time = "2025-10-02T19:28:49.199Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b5/4a21a4922e5dd6845e91896b0d9ef493574cbe061ef7d00a73c61db531af/ruff-0.13.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:2bdad6512fb666b40fcadb65e33add2b040fc18a24997d2e47fee7d66f7fcae2", size = 13122975, upload-time = "2025-10-02T19:28:52.446Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/15649af836d88c9f154e5be87e64ae7d2b1baa5a3ef317cb0c8fafcd882d/ruff-0.13.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fc6fa4637284708d6ed4e5e970d52fc3b76a557d7b4e85a53013d9d201d93286", size = 12346621, upload-time = "2025-10-02T19:28:54.712Z" }, + { url = "https://files.pythonhosted.org/packages/a5/42/bcbccb8141305f9a6d3f72549dd82d1134299177cc7eaf832599700f95a7/ruff-0.13.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c9e6469864f94a98f412f20ea143d547e4c652f45e44f369d7b74ee78185838", size = 12574408, upload-time = "2025-10-02T19:28:56.679Z" }, + { url = "https://files.pythonhosted.org/packages/ce/19/0f3681c941cdcfa2d110ce4515624c07a964dc315d3100d889fcad3bfc9e/ruff-0.13.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5bf62b705f319476c78891e0e97e965b21db468b3c999086de8ffb0d40fd2822", size = 12285330, upload-time = "2025-10-02T19:28:58.79Z" }, + { url = "https://files.pythonhosted.org/packages/10/f8/387976bf00d126b907bbd7725219257feea58650e6b055b29b224d8cb731/ruff-0.13.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78cc1abed87ce40cb07ee0667ce99dbc766c9f519eabfd948ed87295d8737c60", size = 13980815, upload-time = "2025-10-02T19:29:01.577Z" }, + { url = "https://files.pythonhosted.org/packages/0c/a6/7c8ec09d62d5a406e2b17d159e4817b63c945a8b9188a771193b7e1cc0b5/ruff-0.13.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4fb75e7c402d504f7a9a259e0442b96403fa4a7310ffe3588d11d7e170d2b1e3", size = 14987733, upload-time = "2025-10-02T19:29:04.036Z" }, + { url = "https://files.pythonhosted.org/packages/97/e5/f403a60a12258e0fd0c2195341cfa170726f254c788673495d86ab5a9a9d/ruff-0.13.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b951f9d9afb39330b2bdd2dd144ce1c1335881c277837ac1b50bfd99985ed3", size = 14439848, upload-time = "2025-10-02T19:29:06.684Z" }, + { url = "https://files.pythonhosted.org/packages/39/49/3de381343e89364c2334c9f3268b0349dc734fc18b2d99a302d0935c8345/ruff-0.13.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6052f8088728898e0a449f0dde8fafc7ed47e4d878168b211977e3e7e854f662", size = 13421890, upload-time = "2025-10-02T19:29:08.767Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b5/c0feca27d45ae74185a6bacc399f5d8920ab82df2d732a17213fb86a2c4c/ruff-0.13.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc742c50f4ba72ce2a3be362bd359aef7d0d302bf7637a6f942eaa763bd292af", size = 13444870, upload-time = "2025-10-02T19:29:11.234Z" }, + { url = "https://files.pythonhosted.org/packages/50/a1/b655298a1f3fda4fdc7340c3f671a4b260b009068fbeb3e4e151e9e3e1bf/ruff-0.13.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:8e5640349493b378431637019366bbd73c927e515c9c1babfea3e932f5e68e1d", size = 13691599, upload-time = "2025-10-02T19:29:13.353Z" }, + { url = "https://files.pythonhosted.org/packages/32/b0/a8705065b2dafae007bcae21354e6e2e832e03eb077bb6c8e523c2becb92/ruff-0.13.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6b139f638a80eae7073c691a5dd8d581e0ba319540be97c343d60fb12949c8d0", size = 12421893, upload-time = "2025-10-02T19:29:15.668Z" }, + { url = "https://files.pythonhosted.org/packages/0d/1e/cbe7082588d025cddbb2f23e6dfef08b1a2ef6d6f8328584ad3015b5cebd/ruff-0.13.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6b547def0a40054825de7cfa341039ebdfa51f3d4bfa6a0772940ed351d2746c", size = 12267220, upload-time = "2025-10-02T19:29:17.583Z" }, + { url = "https://files.pythonhosted.org/packages/a5/99/4086f9c43f85e0755996d09bdcb334b6fee9b1eabdf34e7d8b877fadf964/ruff-0.13.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9cc48a3564423915c93573f1981d57d101e617839bef38504f85f3677b3a0a3e", size = 13177818, upload-time = "2025-10-02T19:29:19.943Z" }, + { url = "https://files.pythonhosted.org/packages/9b/de/7b5db7e39947d9dc1c5f9f17b838ad6e680527d45288eeb568e860467010/ruff-0.13.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1a993b17ec03719c502881cb2d5f91771e8742f2ca6de740034433a97c561989", size = 13618715, upload-time = "2025-10-02T19:29:22.527Z" }, + { url = "https://files.pythonhosted.org/packages/28/d3/bb25ee567ce2f61ac52430cf99f446b0e6d49bdfa4188699ad005fdd16aa/ruff-0.13.3-py3-none-win32.whl", hash = "sha256:f14e0d1fe6460f07814d03c6e32e815bff411505178a1f539a38f6097d3e8ee3", size = 12334488, upload-time = "2025-10-02T19:29:24.782Z" }, + { url = "https://files.pythonhosted.org/packages/cf/49/12f5955818a1139eed288753479ba9d996f6ea0b101784bb1fe6977ec128/ruff-0.13.3-py3-none-win_amd64.whl", hash = "sha256:621e2e5812b691d4f244638d693e640f188bacbb9bc793ddd46837cea0503dd2", size = 13455262, upload-time = "2025-10-02T19:29:26.882Z" }, + { url = "https://files.pythonhosted.org/packages/fe/72/7b83242b26627a00e3af70d0394d68f8f02750d642567af12983031777fc/ruff-0.13.3-py3-none-win_arm64.whl", hash = "sha256:9e9e9d699841eaf4c2c798fa783df2fabc680b72059a02ca0ed81c460bc58330", size = 12538484, upload-time = "2025-10-02T19:29:28.951Z" }, ] [[package]] diff --git a/uv.lock b/uv.lock deleted file mode 100644 index 2d4ede6..0000000 --- a/uv.lock +++ /dev/null @@ -1,532 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.13" - -[[package]] -name = "babel" -version = "2.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, -] - -[[package]] -name = "backrefs" -version = "5.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/a7/312f673df6a79003279e1f55619abbe7daebbb87c17c976ddc0345c04c7b/backrefs-5.9.tar.gz", hash = "sha256:808548cb708d66b82ee231f962cb36faaf4f2baab032f2fbb783e9c2fdddaa59", size = 5765857, upload-time = "2025-06-22T19:34:13.97Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/4d/798dc1f30468134906575156c089c492cf79b5a5fd373f07fe26c4d046bf/backrefs-5.9-py310-none-any.whl", hash = "sha256:db8e8ba0e9de81fcd635f440deab5ae5f2591b54ac1ebe0550a2ca063488cd9f", size = 380267, upload-time = "2025-06-22T19:34:05.252Z" }, - { url = "https://files.pythonhosted.org/packages/55/07/f0b3375bf0d06014e9787797e6b7cc02b38ac9ff9726ccfe834d94e9991e/backrefs-5.9-py311-none-any.whl", hash = "sha256:6907635edebbe9b2dc3de3a2befff44d74f30a4562adbb8b36f21252ea19c5cf", size = 392072, upload-time = "2025-06-22T19:34:06.743Z" }, - { url = "https://files.pythonhosted.org/packages/9d/12/4f345407259dd60a0997107758ba3f221cf89a9b5a0f8ed5b961aef97253/backrefs-5.9-py312-none-any.whl", hash = "sha256:7fdf9771f63e6028d7fee7e0c497c81abda597ea45d6b8f89e8ad76994f5befa", size = 397947, upload-time = "2025-06-22T19:34:08.172Z" }, - { url = "https://files.pythonhosted.org/packages/10/bf/fa31834dc27a7f05e5290eae47c82690edc3a7b37d58f7fb35a1bdbf355b/backrefs-5.9-py313-none-any.whl", hash = "sha256:cc37b19fa219e93ff825ed1fed8879e47b4d89aa7a1884860e2db64ccd7c676b", size = 399843, upload-time = "2025-06-22T19:34:09.68Z" }, - { url = "https://files.pythonhosted.org/packages/fc/24/b29af34b2c9c41645a9f4ff117bae860291780d73880f449e0b5d948c070/backrefs-5.9-py314-none-any.whl", hash = "sha256:df5e169836cc8acb5e440ebae9aad4bf9d15e226d3bad049cf3f6a5c20cc8dc9", size = 411762, upload-time = "2025-06-22T19:34:11.037Z" }, - { url = "https://files.pythonhosted.org/packages/41/ff/392bff89415399a979be4a65357a41d92729ae8580a66073d8ec8d810f98/backrefs-5.9-py39-none-any.whl", hash = "sha256:f48ee18f6252b8f5777a22a00a09a85de0ca931658f1dd96d4406a34f3748c60", size = 380265, upload-time = "2025-06-22T19:34:12.405Z" }, -] - -[[package]] -name = "certifi" -version = "2025.8.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, - { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, - { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, - { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, - { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, - { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, - { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, - { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, - { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, - { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, - { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, - { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, - { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, - { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, - { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, - { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, - { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, - { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, - { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "fieldz" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/90/62/698c5cc2e7d4c8c89e63033e2e9d3c74902a1bf28782712eacb0653097ce/fieldz-0.1.2.tar.gz", hash = "sha256:0448ed5dacb13eaa49da0db786e87fae298fbd2652d26c510e5d7aea6b6bebf4", size = 17277, upload-time = "2025-06-30T18:06:40.881Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/8c/8958392cade27a272daf45d09a08473073dedeccad94b097dfeb898d969f/fieldz-0.1.2-py3-none-any.whl", hash = "sha256:e25884d2821a2d5638ef8d4d8bce5d1039359cfcb46d0f93df8cb1f7c2eb3a2e", size = 17878, upload-time = "2025-06-30T18:06:39.322Z" }, -] - -[[package]] -name = "ghp-import" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, -] - -[[package]] -name = "griffe" -version = "1.13.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/b5/23b91f22b7b3a7f8f62223f6664946271c0f5cb4179605a3e6bbae863920/griffe-1.13.0.tar.gz", hash = "sha256:246ea436a5e78f7fbf5f24ca8a727bb4d2a4b442a2959052eea3d0bfe9a076e0", size = 412759, upload-time = "2025-08-26T13:27:11.422Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/8c/b7cfdd8dfe48f6b09f7353323732e1a290c388bd14f216947928dc85f904/griffe-1.13.0-py3-none-any.whl", hash = "sha256:470fde5b735625ac0a36296cd194617f039e9e83e301fcbd493e2b58382d0559", size = 139365, upload-time = "2025-08-26T13:27:09.882Z" }, -] - -[[package]] -name = "griffe-fieldz" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fieldz" }, - { name = "griffe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/6a/94754bf39fd63ba424c667b2abf0ade78e3878e223591d1fb9c3e8a77bce/griffe_fieldz-0.3.0.tar.gz", hash = "sha256:42e7707dac51d38e26fb7f3f7f51429da9b47e98060bfeb81a4287456d5b8a89", size = 10149, upload-time = "2025-07-30T21:43:10.042Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/33/cc527c11132a6274724a04938d50e1ff2b54a5f5943cd0480427571e1adb/griffe_fieldz-0.3.0-py3-none-any.whl", hash = "sha256:52e02fdcbdf6dea3c8c95756d1e0b30861569f871d19437fda702776fde4e64d", size = 6577, upload-time = "2025-07-30T21:43:09.073Z" }, -] - -[[package]] -name = "griffe-pydantic" -version = "1.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "griffe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ff/0a/61b2fa8abe04208682bcdb9fba3ae61b1ba879fd17be9e523622f1aa9afb/griffe_pydantic-1.1.6.tar.gz", hash = "sha256:d33413bf44b01b2f9348ea3328fdfe34ad7b2aabb4005a18d36cc0ca0ade908e", size = 42613, upload-time = "2025-08-06T09:30:57.796Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/03/699f059a54b7873a11bf53389236c06640bf47be590aa87a521d7c4bb044/griffe_pydantic-1.1.6-py3-none-any.whl", hash = "sha256:57a838dd1c3b5842a7ebada8fd80f2585a25b69c37f73ede19ca20fa9af055e6", size = 12671, upload-time = "2025-08-06T09:30:56.616Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "markdown" -version = "3.8.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/c2/4ab49206c17f75cb08d6311171f2d65798988db4360c4d1485bd0eedd67c/markdown-3.8.2.tar.gz", hash = "sha256:247b9a70dd12e27f67431ce62523e675b866d254f900c4fe75ce3dda62237c45", size = 362071, upload-time = "2025-06-19T17:12:44.483Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/96/2b/34cc11786bc00d0f04d0f5fdc3a2b1ae0b6239eef72d3d345805f9ad92a1/markdown-3.8.2-py3-none-any.whl", hash = "sha256:5c83764dbd4e00bdd94d85a19b8d55ccca20fe35b2e678a1422b380324dd5f24", size = 106827, upload-time = "2025-06-19T17:12:42.994Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mergedeep" -version = "1.3.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, -] - -[[package]] -name = "mkdocs" -version = "1.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "ghp-import" }, - { name = "jinja2" }, - { name = "markdown" }, - { name = "markupsafe" }, - { name = "mergedeep" }, - { name = "mkdocs-get-deps" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "pyyaml" }, - { name = "pyyaml-env-tag" }, - { name = "watchdog" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, -] - -[[package]] -name = "mkdocs-autorefs" -version = "1.4.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown" }, - { name = "markupsafe" }, - { name = "mkdocs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/51/fa/9124cd63d822e2bcbea1450ae68cdc3faf3655c69b455f3a7ed36ce6c628/mkdocs_autorefs-1.4.3.tar.gz", hash = "sha256:beee715b254455c4aa93b6ef3c67579c399ca092259cc41b7d9342573ff1fc75", size = 55425, upload-time = "2025-08-26T14:23:17.223Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/4d/7123b6fa2278000688ebd338e2a06d16870aaf9eceae6ba047ea05f92df1/mkdocs_autorefs-1.4.3-py3-none-any.whl", hash = "sha256:469d85eb3114801d08e9cc55d102b3ba65917a869b893403b8987b601cf55dc9", size = 25034, upload-time = "2025-08-26T14:23:15.906Z" }, -] - -[[package]] -name = "mkdocs-get-deps" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mergedeep" }, - { name = "platformdirs" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, -] - -[[package]] -name = "mkdocs-material" -version = "9.6.18" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "babel" }, - { name = "backrefs" }, - { name = "click" }, - { name = "colorama" }, - { name = "jinja2" }, - { name = "markdown" }, - { name = "mkdocs" }, - { name = "mkdocs-material-extensions" }, - { name = "paginate" }, - { name = "pygments" }, - { name = "pymdown-extensions" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e6/46/db0d78add5aac29dfcd0a593bcc6049c86c77ba8a25b3a5b681c190d5e99/mkdocs_material-9.6.18.tar.gz", hash = "sha256:a2eb253bcc8b66f8c6eaf8379c10ed6e9644090c2e2e9d0971c7722dc7211c05", size = 4034856, upload-time = "2025-08-22T08:21:47.575Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/0b/545a4f8d4f9057e77f1d99640eb09aaae40c4f9034707f25636caf716ff9/mkdocs_material-9.6.18-py3-none-any.whl", hash = "sha256:dbc1e146a0ecce951a4d84f97b816a54936cdc9e1edd1667fc6868878ac06701", size = 9232642, upload-time = "2025-08-22T08:21:44.52Z" }, -] - -[[package]] -name = "mkdocs-material-extensions" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, -] - -[[package]] -name = "mkdocs-open-in-new-tab" -version = "1.0.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mkdocs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/0e/f72a506a21bdb27b807124e00c688226848a388d1fd3980b80ae3cc27203/mkdocs_open_in_new_tab-1.0.8.tar.gz", hash = "sha256:3e0dad08cc9938b0b13097be8e0aa435919de1eeb2d1a648e66b5dee8d57e048", size = 5791, upload-time = "2024-11-18T13:15:13.977Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/21/94/44f3c868495481c868d08eea065c82803f1affd8553d3383b782f497613c/mkdocs_open_in_new_tab-1.0.8-py3-none-any.whl", hash = "sha256:051d767a4467b12d89827e1fea0ec660b05b027c726317fe4fceee5456e36ad2", size = 7717, upload-time = "2024-11-18T13:15:12.286Z" }, -] - -[[package]] -name = "mkdocstrings" -version = "0.30.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "markdown" }, - { name = "markupsafe" }, - { name = "mkdocs" }, - { name = "mkdocs-autorefs" }, - { name = "pymdown-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e2/0a/7e4776217d4802009c8238c75c5345e23014a4706a8414a62c0498858183/mkdocstrings-0.30.0.tar.gz", hash = "sha256:5d8019b9c31ddacd780b6784ffcdd6f21c408f34c0bd1103b5351d609d5b4444", size = 106597, upload-time = "2025-07-22T23:48:45.998Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/b4/3c5eac68f31e124a55d255d318c7445840fa1be55e013f507556d6481913/mkdocstrings-0.30.0-py3-none-any.whl", hash = "sha256:ae9e4a0d8c1789697ac776f2e034e2ddd71054ae1cf2c2bb1433ccfd07c226f2", size = 36579, upload-time = "2025-07-22T23:48:44.152Z" }, -] - -[package.optional-dependencies] -python = [ - { name = "mkdocstrings-python" }, -] - -[[package]] -name = "mkdocstrings-python" -version = "1.18.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "griffe" }, - { name = "mkdocs-autorefs" }, - { name = "mkdocstrings" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/ae/58ab2bfbee2792e92a98b97e872f7c003deb903071f75d8d83aa55db28fa/mkdocstrings_python-1.18.2.tar.gz", hash = "sha256:4ad536920a07b6336f50d4c6d5603316fafb1172c5c882370cbbc954770ad323", size = 207972, upload-time = "2025-08-28T16:11:19.847Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/8f/ce008599d9adebf33ed144e7736914385e8537f5fc686fdb7cceb8c22431/mkdocstrings_python-1.18.2-py3-none-any.whl", hash = "sha256:944fe6deb8f08f33fa936d538233c4036e9f53e840994f6146e8e94eb71b600d", size = 138215, upload-time = "2025-08-28T16:11:18.176Z" }, -] - -[[package]] -name = "nrl-sdk" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "griffe-fieldz" }, - { name = "griffe-pydantic" }, - { name = "mkdocs" }, - { name = "mkdocs-material" }, - { name = "mkdocs-open-in-new-tab" }, - { name = "mkdocstrings", extra = ["python"] }, -] - -[package.metadata] -requires-dist = [ - { name = "griffe-fieldz", specifier = ">=0.3.0" }, - { name = "griffe-pydantic", specifier = ">=1.1.6" }, - { name = "mkdocs", specifier = ">=1.6.1" }, - { name = "mkdocs-material", specifier = ">=9.6.15" }, - { name = "mkdocs-open-in-new-tab", specifier = ">=1.0.8" }, - { name = "mkdocstrings", extras = ["python"], specifier = ">=0.29.1" }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] - -[[package]] -name = "paginate" -version = "0.5.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, -] - -[[package]] -name = "platformdirs" -version = "4.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, -] - -[[package]] -name = "pymdown-extensions" -version = "10.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/b3/6d2b3f149bc5413b0a29761c2c5832d8ce904a1d7f621e86616d96f505cc/pymdown_extensions-10.16.1.tar.gz", hash = "sha256:aace82bcccba3efc03e25d584e6a22d27a8e17caa3f4dd9f207e49b787aa9a91", size = 853277, upload-time = "2025-07-28T16:19:34.167Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/06/43084e6cbd4b3bc0e80f6be743b2e79fbc6eed8de9ad8c629939fa55d972/pymdown_extensions-10.16.1-py3-none-any.whl", hash = "sha256:d6ba157a6c03146a7fb122b2b9a121300056384eafeec9c9f9e584adfdb2a32d", size = 266178, upload-time = "2025-07-28T16:19:31.401Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "pyyaml-env-tag" -version = "1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, -] - -[[package]] -name = "requests" -version = "2.32.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, -] - -[[package]] -name = "urllib3" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, -] - -[[package]] -name = "watchdog" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, - { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, - { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, -]