From 87c9ebf1dba651e0349428aaba9475941ea6e6db Mon Sep 17 00:00:00 2001 From: Ian Patterson Date: Mon, 15 Sep 2025 16:53:54 -0500 Subject: [PATCH 1/6] initial joining of OSHConnect with previous dep csapi4py --- oshconnect/control.py | 6 +- oshconnect/core_datamodels.py | 8 +- oshconnect/csapi4py/__init__.py | 0 oshconnect/csapi4py/comm/__init__.py | 0 oshconnect/csapi4py/comm/mqtt.py | 197 +++++++ oshconnect/csapi4py/con_sys_api.py | 105 ++++ oshconnect/csapi4py/constants.py | 108 ++++ oshconnect/csapi4py/core/__init__.py | 0 .../csapi4py/core/default_api_helpers.py | 249 +++++++++ oshconnect/csapi4py/endpoints.py | 117 ++++ oshconnect/csapi4py/part_1/__init__.py | 7 + oshconnect/csapi4py/part_1/capabilities.py | 31 ++ oshconnect/csapi4py/part_1/collections_ep.py | 67 +++ oshconnect/csapi4py/part_1/deployments.py | 217 ++++++++ oshconnect/csapi4py/part_1/procedures.py | 97 ++++ oshconnect/csapi4py/part_1/properties.py | 80 +++ .../csapi4py/part_1/sampling_features.py | 116 ++++ oshconnect/csapi4py/part_1/systems.py | 213 ++++++++ oshconnect/csapi4py/part_2/__init__.py | 0 oshconnect/csapi4py/part_2/commands.py | 227 ++++++++ .../csapi4py/part_2/control_channels.py | 159 ++++++ oshconnect/csapi4py/part_2/datastreams.py | 155 ++++++ oshconnect/csapi4py/part_2/observations.py | 122 +++++ oshconnect/csapi4py/part_2/system_events.py | 122 +++++ oshconnect/csapi4py/part_2/system_history.py | 83 +++ oshconnect/csapi4py/querymodel.py | 25 + oshconnect/csapi4py/request_bodies.py | 99 ++++ oshconnect/csapi4py/request_wrappers.py | 58 ++ oshconnect/csapi4py/sensor_ml/__init__.py | 0 oshconnect/csapi4py/sensor_ml/sml.py | 51 ++ oshconnect/csapi4py/utilities/__init__.py | 0 oshconnect/csapi4py/utilities/model_utils.py | 10 + oshconnect/datamodels/__init__.py | 0 oshconnect/datamodels/api_utils.py | 39 ++ oshconnect/datamodels/commands.py | 14 + oshconnect/datamodels/control_streams.py | 39 ++ oshconnect/datamodels/datastreams.py | 25 + oshconnect/datamodels/encoding.py | 11 + oshconnect/datamodels/geometry.py | 14 + oshconnect/datamodels/network_properties.py | 10 + oshconnect/datamodels/observations.py | 19 + oshconnect/datamodels/swe_components.py | 200 +++++++ .../datamodels/system_events_and_history.py | 46 ++ oshconnect/datasource.py | 6 +- oshconnect/osh_connect_datamodels.py | 10 +- oshconnect/oshconnectapi.py | 2 +- pyproject.toml | 3 +- rud/README.md | 3 - rud/__init__.py | 6 - rud/unimpl/__init__.py | 6 - rud/unimpl/datasources/__init__.py | 6 - rud/unimpl/datasources/handler.py | 67 --- uv.lock | 498 +++++++++--------- 53 files changed, 3386 insertions(+), 367 deletions(-) create mode 100644 oshconnect/csapi4py/__init__.py create mode 100644 oshconnect/csapi4py/comm/__init__.py create mode 100644 oshconnect/csapi4py/comm/mqtt.py create mode 100644 oshconnect/csapi4py/con_sys_api.py create mode 100644 oshconnect/csapi4py/constants.py create mode 100644 oshconnect/csapi4py/core/__init__.py create mode 100644 oshconnect/csapi4py/core/default_api_helpers.py create mode 100644 oshconnect/csapi4py/endpoints.py create mode 100644 oshconnect/csapi4py/part_1/__init__.py create mode 100644 oshconnect/csapi4py/part_1/capabilities.py create mode 100644 oshconnect/csapi4py/part_1/collections_ep.py create mode 100644 oshconnect/csapi4py/part_1/deployments.py create mode 100644 oshconnect/csapi4py/part_1/procedures.py create mode 100644 oshconnect/csapi4py/part_1/properties.py create mode 100644 oshconnect/csapi4py/part_1/sampling_features.py create mode 100644 oshconnect/csapi4py/part_1/systems.py create mode 100644 oshconnect/csapi4py/part_2/__init__.py create mode 100644 oshconnect/csapi4py/part_2/commands.py create mode 100644 oshconnect/csapi4py/part_2/control_channels.py create mode 100644 oshconnect/csapi4py/part_2/datastreams.py create mode 100644 oshconnect/csapi4py/part_2/observations.py create mode 100644 oshconnect/csapi4py/part_2/system_events.py create mode 100644 oshconnect/csapi4py/part_2/system_history.py create mode 100644 oshconnect/csapi4py/querymodel.py create mode 100644 oshconnect/csapi4py/request_bodies.py create mode 100644 oshconnect/csapi4py/request_wrappers.py create mode 100644 oshconnect/csapi4py/sensor_ml/__init__.py create mode 100644 oshconnect/csapi4py/sensor_ml/sml.py create mode 100644 oshconnect/csapi4py/utilities/__init__.py create mode 100644 oshconnect/csapi4py/utilities/model_utils.py create mode 100644 oshconnect/datamodels/__init__.py create mode 100644 oshconnect/datamodels/api_utils.py create mode 100644 oshconnect/datamodels/commands.py create mode 100644 oshconnect/datamodels/control_streams.py create mode 100644 oshconnect/datamodels/datastreams.py create mode 100644 oshconnect/datamodels/encoding.py create mode 100644 oshconnect/datamodels/geometry.py create mode 100644 oshconnect/datamodels/network_properties.py create mode 100644 oshconnect/datamodels/observations.py create mode 100644 oshconnect/datamodels/swe_components.py create mode 100644 oshconnect/datamodels/system_events_and_history.py delete mode 100644 rud/README.md delete mode 100644 rud/__init__.py delete mode 100644 rud/unimpl/__init__.py delete mode 100644 rud/unimpl/datasources/__init__.py delete mode 100644 rud/unimpl/datasources/handler.py diff --git a/oshconnect/control.py b/oshconnect/control.py index fdce1b3..01f2c45 100644 --- a/oshconnect/control.py +++ b/oshconnect/control.py @@ -5,9 +5,9 @@ # Contact Email: ian@botts-inc.com # ============================================================================== import websockets -from consys4py.comm.mqtt import MQTTCommClient -from consys4py.datamodels.commands import CommandJSON -from consys4py.datamodels.control_streams import ControlStreamJSONSchema +from oshconnect.csapi4py.comm.mqtt import MQTTCommClient +from oshconnect.datamodels.commands import CommandJSON +from oshconnect.datamodels.control_streams import ControlStreamJSONSchema from oshconnect.osh_connect_datamodels import System diff --git a/oshconnect/core_datamodels.py b/oshconnect/core_datamodels.py index 4bd179e..83fced5 100644 --- a/oshconnect/core_datamodels.py +++ b/oshconnect/core_datamodels.py @@ -8,9 +8,9 @@ from typing import List -from consys4py.datamodels.swe_components import GeometrySchema -from consys4py.datamodels.datastreams import DatastreamSchema -from consys4py.datamodels.api_utils import Link +from oshconnect.datamodels.geometry import Geometry +from oshconnect.datamodels.datastreams import DatastreamSchema +from oshconnect.datamodels.api_utils import Link from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny from shapely import Point @@ -94,7 +94,7 @@ class SystemResource(BaseModel): feature_type: str = Field(None, serialization_alias="type") system_id: str = Field(None, serialization_alias="id") properties: dict = Field(None) - geometry: GeometrySchema | None = Field(None) + geometry: Geometry | None = Field(None) bbox: BoundingBox = Field(None) links: List[Link] = Field(None) description: str = Field(None) diff --git a/oshconnect/csapi4py/__init__.py b/oshconnect/csapi4py/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oshconnect/csapi4py/comm/__init__.py b/oshconnect/csapi4py/comm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oshconnect/csapi4py/comm/mqtt.py b/oshconnect/csapi4py/comm/mqtt.py new file mode 100644 index 0000000..9295545 --- /dev/null +++ b/oshconnect/csapi4py/comm/mqtt.py @@ -0,0 +1,197 @@ +import paho.mqtt.client as mqtt + + +class MQTTCommClient: + def __init__(self, url, port=1883, username=None, password=None, path='mqtt', client_id="", transport='tcp'): + """ + Wraps a paho mqtt client to provide a simple interface for interacting with the mqtt server that is customized + for this library. + + :param url: url of the mqtt server + :param port: port the mqtt server is communicating over, default is 1883 or whichever port the main node is + using if in websocket mode + :param username: used if node is requiring authentication to access this service + :param password: used if node is requiring authentication to access this service + :param path: used for setting the path when using websockets (usually sensorhub/mqtt by default) + """ + self.__url = url + self.__port = port + self.__path = path + self.__client_id = client_id + self.__transport = transport + + self.__client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=client_id) + + if self.__transport == 'websockets': + self.__client.ws_set_options(path=self.__path) + + if username is not None and password is not None: + self.__client.username_pw_set(username, password) + self.__client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLSv1_2) + + self.__client.on_connect = self.on_connect + self.__client.on_subscribe = self.on_subscribe + self.__client.on_message = self.on_message + self.__client.on_publish = self.on_publish + self.__client.on_log = self.on_log + self.__client.on_disconnect = self.on_disconnect + + self.__is_connected = False + + @staticmethod + def on_connect(client, userdata, flags, rc, properties): + print(f'Connected with result code: {rc}') + print(f'{properties}') + + @staticmethod + def on_subscribe(client, userdata, mid, granted_qos, properties): + print(f'Subscribed: {mid} {granted_qos}') + + @staticmethod + def on_message(client, userdata, msg): + print(f'{msg.payload.decode("utf-8")}') + + @staticmethod + def on_publish(client, userdata, mid, info, properties): + print(f'Published: {mid}') + + @staticmethod + def on_log(client, userdata, level, buf): + print(f'Log: {buf}') + + @staticmethod + def on_disconnect(client, userdata, dc_flag, rc, properties): + print(f'Client {client} disconnected: {dc_flag} {rc}') + + def connect(self, keepalive=60): + # print(f'Connecting to {self.__url}:{self.__port}') + self.__client.connect(self.__url, self.__port, keepalive=keepalive) + + def subscribe(self, topic, qos=0, msg_callback=None): + """ + Subscribe to a topic, and optionally set a callback for when a message is received on that topic. To actually + retrieve any information you must set a callback. + + :param topic: MQTT topic to subscribe to (example/topic) + :param qos: quality of service, 0, 1, or 2 + :param msg_callback: callback with the form: callback(client, userdata, msg) + :return: + """ + self.__client.subscribe(topic, qos) + if msg_callback is not None: + self.__client.message_callback_add(topic, msg_callback) + + def publish(self, topic, payload=None, qos=0, retain=False): + self.__client.publish(topic, payload, qos, retain=retain) + + def unsubscribe(self, topic): + self.__client.unsubscribe(topic) + + def disconnect(self): + self.__client.disconnect() + + def set_on_connect(self, on_connect): + """ + Set the on_connect callback for the MQTT client. + + :param on_connect: + :return: + """ + self.__client.on_connect = on_connect + + def set_on_disconnect(self, on_disconnect): + """ + Set the on_disconnect callback for the MQTT client. + + :param on_disconnect: + :return: + """ + self.__client.on_disconnect = on_disconnect + + def set_on_subscribe(self, on_subscribe): + """ + Set the on_subscribe callback for the MQTT client. + + :param on_subscribe: + :return: + """ + self.__client.on_subscribe = on_subscribe + + def set_on_unsubscribe(self, on_unsubscribe): + """ + Set the on_unsubscribe callback for the MQTT client. + + :param on_unsubscribe: + :return: + """ + self.__client.on_unsubscribe = on_unsubscribe + + def set_on_publish(self, on_publish): + """ + Set the on_publish callback for the MQTT client. + + :param on_publish: + :return: + """ + self.__client.on_publish = on_publish + + def set_on_message(self, on_message): + """ + Set the on_message callback for the MQTT client. It is recommended to set individual callbacks for each + subscribed topic. + + :param on_message: + :return: + """ + self.__client.on_message = on_message + + def set_on_log(self, on_log): + """ + Set the on_log callback for the MQTT client. + + :param on_log: + :return: + """ + self.__client.on_log = on_log + + def set_on_message_callback(self, sub, on_message_callback): + """ + Set the on_message callback for a specific topic. + :param sub: + :param on_message_callback: + :return: + """ + self.__client.message_callback_add(sub, on_message_callback) + + def start(self): + """ + Start the MQTT client in a separate thread. This is required for the client to be able to receive messages. + + :return: + """ + self.__client.loop_start() + + def stop(self): + """ + Stop the MQTT client.\ + + :return: + """ + self.__client.loop_stop() + + def __toggle_is_connected(self): + self.__is_connected = not self.__is_connected + + def is_connected(self): + return self.__is_connected + + @staticmethod + def publish_single(self, topic, msg): + self.__client.single(topic, msg, 0) + + @staticmethod + def publish_multiple(self, topic, msgs): + self.__client.multiple(msgs, ) + + def tls_set(self): + self.__client.tls_set() diff --git a/oshconnect/csapi4py/con_sys_api.py b/oshconnect/csapi4py/con_sys_api.py new file mode 100644 index 0000000..120ba32 --- /dev/null +++ b/oshconnect/csapi4py/con_sys_api.py @@ -0,0 +1,105 @@ +from typing import Union + +from pydantic import BaseModel, HttpUrl, Field + +from oshconnect.csapi4py.endpoints import Endpoint +from oshconnect.csapi4py.request_wrappers import post_request, put_request, get_request, delete_request + + +class ConnectedSystemAPIRequest(BaseModel): + url: HttpUrl = Field(None) + body: Union[dict, str] = Field(None) + params: dict = Field(None) + request_method: str = Field('GET') + headers: dict = Field(None) + auth: Union[tuple, None] = Field(None) + + def make_request(self): + match self.request_method: + case 'GET': + return get_request(self.url, self.params, self.headers, self.auth) + case 'POST': + print(f'POST request: {self}') + return post_request(self.url, self.body, self.headers, self.auth) + case 'PUT': + print(f'PUT request: {self}') + return put_request(self.url, self.body, self.headers, self.auth) + case 'DELETE': + print(f'DELETE request: {self}') + return delete_request(self.url, self.params, self.headers, self.auth) + case _: + raise ValueError('Invalid request method') + + +class ConnectedSystemsRequestBuilder(BaseModel): + api_request: ConnectedSystemAPIRequest = Field(default_factory=ConnectedSystemAPIRequest) + base_url: HttpUrl = None + endpoint: Endpoint = Field(default_factory=Endpoint) + + def with_api_url(self, url: HttpUrl): + self.api_request.url = url + return self + + def with_server_url(self, server_url: HttpUrl): + self.base_url = server_url + return self + + def build_url_from_base(self): + """ + Builds the full API endpoint URL from the base URL and the endpoint parameters that have been previously + provided. + """ + self.api_request.url = f'{self.base_url}/{self.endpoint.create_endpoint()}' + return self + + def with_api_root(self, api_root: str): + """ + Optional: Set the API root for the request. This is useful if you want to use a different API root than the + default one (api). + :param api_root: + :return: + """ + self.endpoint.api_root = api_root + return self + + def for_resource_type(self, resource_type: str): + self.endpoint.base_resource = resource_type + return self + + def with_resource_id(self, resource_id: str): + self.endpoint.resource_id = resource_id + return self + + def for_sub_resource_type(self, sub_resource_type: str): + self.endpoint.sub_component = sub_resource_type + return self + + def with_secondary_resource_id(self, resource_id: str): + self.endpoint.secondary_resource_id = resource_id + return self + + def with_request_body(self, request_body: str): + self.api_request.body = request_body + return self + + def with_request_method(self, request_method: str): + self.api_request.request_method = request_method + return self + + def with_headers(self, headers: dict = None): + # TODO: ensure headers can default if excluded + self.api_request.headers = headers + return self + + def with_auth(self, uname: str, pword: str): + self.api_request.auth = (uname, pword) + return self + + def build(self): + # convert endpoint to HttpUrl + return self.api_request + + def reset(self): + self.api_request = ConnectedSystemAPIRequest() + self.endpoint = Endpoint() + return self diff --git a/oshconnect/csapi4py/constants.py b/oshconnect/csapi4py/constants.py new file mode 100644 index 0000000..aa91a86 --- /dev/null +++ b/oshconnect/csapi4py/constants.py @@ -0,0 +1,108 @@ +from enum import Enum + + +class APITerms(Enum): + """ + Defines common endpoint terms used in the API + """ + API = 'api' + COLLECTIONS = 'collections' + COMMANDS = 'commands' + COMPONENTS = 'components' + CONFORMANCE = 'conformance' + CONTROL_STREAMS = 'controlstreams' + DATASTREAMS = 'datastreams' + DEPLOYMENTS = 'deployments' + EVENTS = 'events' + FOIS = 'featuresOfInterest' + HISTORY = 'history' + ITEMS = 'items' + OBSERVATIONS = 'observations' + PROCEDURES = 'procedures' + PROPERTIES = 'properties' + SAMPLING_FEATURES = 'samplingFeatures' + SCHEMA = 'schema' + STATUS = 'status' + SYSTEMS = 'systems' + SYSTEM_EVENTS = 'systemEvents' + TASKING = 'controls' + UNDEFINED = '' + + +class SystemTypes(Enum): + """ + Defines the system types + """ + FEATURE = "Feature" + + +class ObservationFormat(Enum): + """ + Defines common observation formats + """ + JSON = "application/om+json" + XML = "application/om+xml" + SWE_XML = "application/swe+xml" + SWE_JSON = "application/swe+json" + SWE_CSV = "application/swe+csv" + SWE_BINARY = "application/swe+binary" + SWE_TEXT = "application/swe+text" + + +class DatastreamResultTypes(Enum): + """ + Defines the datastream result types + """ + MEASURE = "measure" + VECTOR = "vector" + RECORD = "record" + COVERAGE_1D = "coverage1D" + COVERAGE_2D = "coverage2D" + COVERAGE_3D = "coverage3D" + + +class GeometryTypes(Enum): + """ + Defines the geometry types + """ + POINT = "Point" + LINESTRING = "LineString" + POLYGON = "Polygon" + MULTI_POINT = "MultiPoint" + MULTI_LINESTRING = "MultiLineString" + MULTI_POLYGON = "MultiPolygon" + + +class APIResourceTypes(Enum): + """ + Defines the resource types + """ + COLLECTION = "Collection" + COMMAND = "Command" + COMPONENT = "Component" + CONTROL_CHANNEL = "ControlChannel" + DATASTREAM = "Datastream" + DEPLOYMENT = "Deployment" + OBSERVATION = "Observation" + PROCEDURE = "Procedure" + PROPERTY = "Property" + SAMPLING_FEATURE = "SamplingFeature" + SYSTEM = "System" + SYSTEM_EVENT = "SystemEvent" + SYSTEM_HISTORY = "SystemHistory" + + +class EncodingSchema(Enum): + """ + Defines the encoding formats + """ + JSON = "application/json" + XML = "application/xml" + SWE_XML = "application/swe+xml" + SWE_JSON = "application/swe+json" + SWE_CSV = "application/swe+csv" + SWE_BINARY = "application/swe+binary" + SWE_TEXT = "application/swe+text" + GEO_JSON = "application/geo+json" + SML_JSON = "application/sml+json" + OM_JSON = "application/om+json" diff --git a/oshconnect/csapi4py/core/__init__.py b/oshconnect/csapi4py/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oshconnect/csapi4py/core/default_api_helpers.py b/oshconnect/csapi4py/core/default_api_helpers.py new file mode 100644 index 0000000..d034876 --- /dev/null +++ b/oshconnect/csapi4py/core/default_api_helpers.py @@ -0,0 +1,249 @@ +from __future__ import annotations + +from abc import ABC +from dataclasses import dataclass + +from pydantic import BaseModel, Field + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemAPIRequest +from oshconnect.csapi4py.constants import APIResourceTypes, EncodingSchema, APITerms + + +def determine_parent_type(res_type: APIResourceTypes): + match res_type: + case APIResourceTypes.SYSTEM: + return APIResourceTypes.SYSTEM + case APIResourceTypes.COLLECTION: + return None + case APIResourceTypes.CONTROL_CHANNEL: + return APIResourceTypes.SYSTEM + case APIResourceTypes.COMMAND: + return APIResourceTypes.CONTROL_CHANNEL + case APIResourceTypes.DATASTREAM: + return APIResourceTypes.SYSTEM + case APIResourceTypes.OBSERVATION: + return APIResourceTypes.DATASTREAM + case APIResourceTypes.SYSTEM_EVENT: + return APIResourceTypes.SYSTEM + case APIResourceTypes.SAMPLING_FEATURE: + return APIResourceTypes.SYSTEM + case APIResourceTypes.PROCEDURE: + return None + case APIResourceTypes.PROPERTY: + return None + case APIResourceTypes.SYSTEM_HISTORY: + return None + case APIResourceTypes.DEPLOYMENT: + return None + case _: + return None + + +def resource_type_to_endpoint(res_type: APIResourceTypes, parent_type: APIResourceTypes = None): + if parent_type is APIResourceTypes.COLLECTION: + return APITerms.ITEMS.value + + match res_type: + case APIResourceTypes.SYSTEM: + return APITerms.SYSTEMS.value + case APIResourceTypes.COLLECTION: + return APITerms.COLLECTIONS.value + case APIResourceTypes.CONTROL_CHANNEL: + return APITerms.CONTROL_STREAMS.value + case APIResourceTypes.COMMAND: + return APITerms.COMMANDS.value + case APIResourceTypes.DATASTREAM: + return APITerms.DATASTREAMS.value + case APIResourceTypes.OBSERVATION: + return APITerms.OBSERVATIONS.value + case APIResourceTypes.SYSTEM_EVENT: + return APITerms.SYSTEM_EVENTS.value + case APIResourceTypes.SAMPLING_FEATURE: + return APITerms.SAMPLING_FEATURES.value + case APIResourceTypes.PROCEDURE: + return APITerms.PROCEDURES.value + case APIResourceTypes.PROPERTY: + return APITerms.PROPERTIES.value + case APIResourceTypes.SYSTEM_HISTORY: + return APITerms.HISTORY.value + case APIResourceTypes.DEPLOYMENT: + return APITerms.DEPLOYMENTS.value + case _: + raise ValueError('Invalid resource type') + + +@dataclass +class APIHelper(ABC): + server_url: str = None + api_root: str = "api" + username: str = None + password: str = None + user_auth: bool = False + + def create_resource(self, res_type: APIResourceTypes, json_data: any, parent_res_id: str = None, + from_collection: bool = False, url_endpoint: str = None, req_headers: dict = None): + """ + Creates a resource of the given type with the given data, will attempt to create a sub-resource if parent_res_id + is provided. + :param req_headers: + :param res_type: + :param json_data: + :param parent_res_id: + :param from_collection: + :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. + :return: + """ + + if url_endpoint is None: + url = self.resource_url_resolver(res_type, None, parent_res_id, from_collection) + else: + url = f'{self.server_url}/{self.api_root}/{url_endpoint}' + api_request = ConnectedSystemAPIRequest(url=url, request_method='POST', auth=self.get_helper_auth(), + body=json_data, headers=req_headers) + return api_request.make_request() + + def retrieve_resource(self, res_type: APIResourceTypes, res_id: str = None, parent_res_id: str = None, + from_collection: bool = False, + collection_id: str = None, url_endpoint: str = None, req_headers: dict = None): + """ + Retrieves a resource or list of resources if no res_id is provided, will attempt to retrieve a sub-resource if + parent_res_id is provided. + :param req_headers: + :param res_type: + :param res_id: + :param parent_res_id: + :param from_collection: + :param collection_id: + :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. + :return: + """ + if url_endpoint is None: + url = self.resource_url_resolver(res_type, res_id, parent_res_id, from_collection) + else: + url = f'{self.server_url}/{self.api_root}/{url_endpoint}' + api_request = ConnectedSystemAPIRequest(url=url, request_method='GET', auth=self.get_helper_auth(), + headers=req_headers) + return api_request.make_request() + + def update_resource(self, res_type: APIResourceTypes, res_id: str, json_data: any, parent_res_id: str = None, + from_collection: bool = False, url_endpoint: str = None, req_headers: dict = None): + """ + Updates a resource of the given type by its id, if necessary, will attempt to update a sub-resource if + parent_res_id is provided. + :param req_headers: + :param res_type: + :param res_id: + :param json_data: + :param parent_res_id: + :param from_collection: + :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. + :return: + """ + if url_endpoint is None: + url = self.resource_url_resolver(res_type, None, parent_res_id, from_collection) + else: + url = f'{self.server_url}/{self.api_root}/{url_endpoint}' + api_request = ConnectedSystemAPIRequest(url=url, request_method='PUT', auth=self.get_helper_auth(), + body=json_data, headers=req_headers) + return api_request.make_request() + + def delete_resource(self, res_type: APIResourceTypes, res_id: str, parent_res_id: str = None, + from_collection: bool = False, url_endpoint: str = None, req_headers: dict = None): + """ + Deletes a resource of the given type by its id, if necessary, will attempt to delete a sub-resource if + parent_res_id is provided. + :param req_headers: + :param res_type: + :param res_id: + :param parent_res_id: + :param from_collection: + :param url_endpoint: If given, will override the default URL construction. Should contain the endpoint past the API root. + :return: + """ + if url_endpoint is None: + url = self.resource_url_resolver(res_type, None, parent_res_id, from_collection) + else: + url = f'{self.server_url}/{self.api_root}/{url_endpoint}' + api_request = ConnectedSystemAPIRequest(url=url, request_method='DELETE', auth=self.get_helper_auth(), + headers=req_headers) + return api_request.make_request() + + # Helpers + def resource_url_resolver(self, res_type: APIResourceTypes, res_id: str = None, parent_res_id: str = None, + from_collection: bool = False): + """ + Helper to generate a URL endpoint for a given resource type and id by matching the resource type to an + appropriate parent endpoint and inserting the resource ids as necessary. + :param res_type: + :param res_id: + :param parent_res_id: + :param from_collection: + :return: + """ + if res_type is None: + raise ValueError('Resource type must contain a valid APIResourceType') + if res_type is APIResourceTypes.COLLECTION and from_collection: + raise ValueError('Collections are not sub-resources of other collections') + + parent_type = None + if parent_res_id and not from_collection: + parent_type = determine_parent_type(res_type) + elif parent_res_id and from_collection: + parent_type = APIResourceTypes.COLLECTION + + return self.construct_url(parent_type, res_id, res_type, parent_res_id) + + def construct_url(self, parent_type, res_id, res_type, parent_res_id): + """ + Constructs an API endpoint url from the given parameters + :param parent_type: + :param res_id: + :param res_type: + :param parent_res_id: + :return: + """ + # TODO: Test for less common cases to ensure that the URL is being constructed correctly + base_url = f'{self.server_url}/{self.api_root}' + resource_endpoint = resource_type_to_endpoint(res_type, parent_type) + url = f'{base_url}/{resource_endpoint}' + + if parent_type: + parent_endpoint = resource_type_to_endpoint(parent_type) + url = f'{base_url}/{parent_endpoint}/{parent_res_id}/{resource_endpoint}' + + if res_id: + url = f'{url}/{res_id}' + + return url + + def get_helper_auth(self): + if self.user_auth: + return self.username, self.password + return None + + +@dataclass(kw_only=True) +class ResponseParserHelper: + default_object_reps: DefaultObjectRepresentations + + +class DefaultObjectRepresentations(BaseModel): + """ + Intended to be used as a way to determine which formats should be used when serializing and deserializing objects. + Should work in tandem with planned Serializer/Deserializer classes. + """ + # Part 1 + collections: str = Field(EncodingSchema.JSON.value) + deployments: str = Field(EncodingSchema.GEO_JSON.value) + procedures: str = Field(EncodingSchema.GEO_JSON.value) + properties: str = Field(EncodingSchema.SML_JSON.value) + sampling_features: str = Field(EncodingSchema.GEO_JSON.value) + systems: str = Field(EncodingSchema.GEO_JSON.value) + # Part 2 + datastreams: str = Field(EncodingSchema.JSON.value) + observations: str = Field(EncodingSchema.JSON.value) + control_channels: str = Field(EncodingSchema.JSON.value) + commands: str = Field(EncodingSchema.JSON.value) + system_events: str = Field(EncodingSchema.OM_JSON.value) + system_history: str = Field(EncodingSchema.GEO_JSON.value) + # TODO: validate schemas for each resource to amke sure they are allowed per the spec diff --git a/oshconnect/csapi4py/endpoints.py b/oshconnect/csapi4py/endpoints.py new file mode 100644 index 0000000..5943fe7 --- /dev/null +++ b/oshconnect/csapi4py/endpoints.py @@ -0,0 +1,117 @@ +from enum import Enum + +import requests +# import websockets +from pydantic import BaseModel, Field + +from oshconnect.csapi4py.constants import APITerms + + +class Endpoint(BaseModel): + api_root: str = APITerms.API.value + base_resource: APITerms = Field(None) + resource_id: str = Field(None) + sub_component: APITerms = Field(None) + secondary_resource_id: str = Field(None) + + def create_endpoint(self): + # TODO: Handle insertion of "/" in the right places + # Create endpoints bases of api spec + base_res_id = '' if self.base_resource is None else f'/{self.base_resource}' + res_id = '' if self.resource_id is None else f'/{self.resource_id}' + sub_comp = '' if self.sub_component is None else f'/{self.sub_component}' + secondary_res_id = '' if self.secondary_resource_id is None else f'/{self.secondary_resource_id}' + + return f'{self.api_root}{base_res_id}{res_id}{sub_comp}{secondary_res_id}' + + +class SystemQueryParams(Enum): + Keywords = 'q' + """ + A comma-separated list of keywords to search for in the system name, description, and definition. + """ + BBOX = 'bbox' + """ + BBOX to fileter resources based on their location + """ + LOCATION = 'location' + """ + WKT geometry to filter resources based on their location or geometry + """ + VALID_TIME = 'validTime' + """ + ISO 8601 time interval to filter resources based on their valid time. When omitted, the implicit time is "now" + except for "history" collection where no filtering is applied. + """ + PARENT = 'parent' + """ + Comma-separated list of parent system IDs or "*" to included nested resources at any level + """ + SELECT = 'select' + """ + Comma-separated list of properties to include or exclude from results (use "!" prefix to exclude) + """ + FORMAT = 'format' + """ + Mime type of the response format. + """ + LIMIT = 'limit' + """ + Maximum number of resources to return per page (max 1000) + """ + OFFSET = 'offset' + """ + Token specifying the page to return (usually the token provided in the previous call) + """ + + @classmethod + def list(cls): + return list(map(lambda c: c.value, cls)) + + +def handle_request(url, params=None, content_json=None, method='get', response_handler=None): + """ + Handles a request to the API + :param url: The URL to make the request to + :param params: The parameters to send with the request + :param content_json: The JSON to send with the request + :param method: The method to use for the request + :param response_handler: + :return: The response from the API + """ + + r = None + + if method == 'get': + r = requests.get(url, params=params) + elif method == 'post': + r = requests.post(url, params=params, json=content_json, headers={'Content-Type': 'application/json'}) + elif method == 'put': + r = requests.put(url, params=params, json=content_json) + elif method == 'delete': + r = requests.delete(url, params=params) + else: + raise ValueError(f'Invalid method: {method}') + + if response_handler is not None: + return response_handler(r) + else: + return r + + +# async def handle_ws(url, params=None, json_data=None, method='get', response_handler=None): +# """ +# Handles a request to the API. Functionality is limited to receiving observations for now, but will be improved in +# future versions. +# :param url: The URL to make the request to +# :param params: The parameters to send with the request +# :param json_data: The JSON to send with the request +# :param method: The method to use for the request +# :param response_handler: callback function to handle the response msg +# :return: The response from the API +# """ +# +# async with websockets.connect(url) as ws: +# while True: +# msg = await ws.recv() +# response_handler(msg) diff --git a/oshconnect/csapi4py/part_1/__init__.py b/oshconnect/csapi4py/part_1/__init__.py new file mode 100644 index 0000000..dd72804 --- /dev/null +++ b/oshconnect/csapi4py/part_1/__init__.py @@ -0,0 +1,7 @@ +# import capabilities +# import collections_ep +# import deployments +# import procedures +# import properties +# import sampling_features +# import systems diff --git a/oshconnect/csapi4py/part_1/capabilities.py b/oshconnect/csapi4py/part_1/capabilities.py new file mode 100644 index 0000000..e094aa5 --- /dev/null +++ b/oshconnect/csapi4py/part_1/capabilities.py @@ -0,0 +1,31 @@ +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def get_landing_page(server_addr: HttpUrl, api_root: str = APITerms.API.value): + """ + Returns the landing page of the API + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .build_url_from_base() + .build()) + return api_request + + +def get_conformance_info(server_addr: HttpUrl, api_root: str = APITerms.API.value): + """ + Returns the conformance information of the API + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONFORMANCE.value) + .build_url_from_base() + .build()) + return api_request diff --git a/oshconnect/csapi4py/part_1/collections_ep.py b/oshconnect/csapi4py/part_1/collections_ep.py new file mode 100644 index 0000000..0c8dbfc --- /dev/null +++ b/oshconnect/csapi4py/part_1/collections_ep.py @@ -0,0 +1,67 @@ +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_collections(server_addr: HttpUrl, api_root: str = APITerms.API.value): + """ + List all collections + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COLLECTIONS.value) + .build_url_from_base() + .build()) + return api_request + + +def retrieve_collection_metadata(server_addr: HttpUrl, collection_id: str, api_root: str = APITerms.API.value): + """ + Retrieve a collection by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COLLECTIONS.value) + .with_resource_id(collection_id) + .build_url_from_base() + .build()) + return api_request + + +def list_all_items_in_collection(server_addr: HttpUrl, collection_id: str, api_root: str = APITerms.API.value): + """ + Lists all systems in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COLLECTIONS.value) + .with_resource_id(collection_id) + .for_sub_resource_type(APITerms.ITEMS.value) + .build_url_from_base() + .build()) + return api_request + + +def retrieve_collection_item_by_id(server_addr: HttpUrl, collection_id: str, item_id: str, + api_root: str = APITerms.API.value): + """ + Retrieves a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COLLECTIONS.value) + .with_resource_id(collection_id) + .for_sub_resource_type(APITerms.ITEMS.value) + .with_resource_id(item_id) + .build_url_from_base() + .build()) + return api_request diff --git a/oshconnect/csapi4py/part_1/deployments.py b/oshconnect/csapi4py/part_1/deployments.py new file mode 100644 index 0000000..0f8fe60 --- /dev/null +++ b/oshconnect/csapi4py/part_1/deployments.py @@ -0,0 +1,217 @@ +from typing import Union + +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_deployments(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all deployments in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def create_new_deployments(server_addr: HttpUrl, request_body: Union[str, dict], api_root: str = APITerms.API.value, + headers: dict = None): + """ + Create a new deployment as defined by the request body + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + return api_request.make_request() + + +def retrieve_deployment_by_id(server_addr: HttpUrl, deployment_id: str, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Retrieve a deployment by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_deployment_by_id(server_addr: HttpUrl, deployment_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers: dict = None): + """ + Update a deployment by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() + + +def delete_deployment_by_id(server_addr: HttpUrl, deployment_id: str, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Delete a deployment by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + return api_request + + +def list_deployed_systems(server_addr: HttpUrl, deployment_id, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Lists all deployed systems in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .for_sub_resource_type(APITerms.SYSTEMS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def add_systems_to_deployment(server_addr: HttpUrl, deployment_id: str, uri_list: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all systems in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .for_sub_resource_type(APITerms.SYSTEMS.value) + .with_request_body(uri_list) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + return api_request.make_request() + + +def retrieve_deployed_system_by_id(server_addr: HttpUrl, deployment_id: str, system_id: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Retrieves a system by its id + :return: + """ + + # TODO: Add a way to have a secondary resource ID for certain endpoints + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .for_sub_resource_type(APITerms.SYSTEMS.value) + .with_secondary_resource_id(system_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_deployed_system_by_id(server_addr: HttpUrl, deployment_id: str, system_id: str, request_body: dict, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Update a system by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .for_sub_resource_type(APITerms.SYSTEMS.value) + .with_secondary_resource_id(system_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + + return api_request + + +def delete_deployed_system_by_id(server_addr: HttpUrl, deployment_id: str, system_id: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Delete a system by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DEPLOYMENTS.value) + .with_resource_id(deployment_id) + .for_sub_resource_type(APITerms.SYSTEMS.value) + .with_secondary_resource_id(system_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + return api_request.make_request() + + +def list_deployments_of_specific_system(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Lists all deployments of a specific system in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.DEPLOYMENTS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_1/procedures.py b/oshconnect/csapi4py/part_1/procedures.py new file mode 100644 index 0000000..41e58a5 --- /dev/null +++ b/oshconnect/csapi4py/part_1/procedures.py @@ -0,0 +1,97 @@ +from typing import Union + +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_procedures(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all procedures in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROCEDURES.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def create_new_procedures(server_addr: HttpUrl, request_body: Union[str, dict], api_root: str = APITerms.API.value, + headers: dict = None): + """ + Create a new procedure as defined by the request body + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROCEDURES.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + print(api_request) + return api_request.make_request() + + +def retrieve_procedure_by_id(server_addr: HttpUrl, procedure_id: str, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Retrieve a procedure by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROCEDURES.value) + .with_resource_id(procedure_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_procedure_by_id(server_addr: HttpUrl, procedure_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers: dict = None): + """ + Update a procedure by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROCEDURES.value) + .with_resource_id(procedure_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() + + +def delete_procedure_by_id(server_addr: HttpUrl, procedure_id: str, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Delete a procedure by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROCEDURES.value) + .with_resource_id(procedure_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_1/properties.py b/oshconnect/csapi4py/part_1/properties.py new file mode 100644 index 0000000..8347424 --- /dev/null +++ b/oshconnect/csapi4py/part_1/properties.py @@ -0,0 +1,80 @@ +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_properties(server_addr: HttpUrl, api_root: str = APITerms.API.value): + """ + List all properties + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROPERTIES.value) + .build_url_from_base() + .build()) + return api_request + + +def create_new_properties(server_addr: HttpUrl, request_body: dict, api_root: str = APITerms.API.value): + """ + Create a new property as defined by the request body + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROPERTIES.value) + .with_request_body(request_body) + .build_url_from_base() + .build()) + return api_request + + +def retrieve_property_by_id(server_addr: HttpUrl, property_id: str, api_root: str = APITerms.API.value): + """ + Retrieve a property by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROPERTIES.value) + .with_resource_id(property_id) + .build_url_from_base() + .build()) + return api_request + + +def update_property_by_id(server_addr: HttpUrl, property_id: str, request_body: dict, + api_root: str = APITerms.API.value): + """ + Update a property by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROPERTIES.value) + .with_resource_id(property_id) + .with_request_body(request_body) + .build_url_from_base() + .build()) + return api_request + + +def delete_property_by_id(server_addr: HttpUrl, property_id: str, api_root: str = APITerms.API.value): + """ + Delete a property by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.PROPERTIES.value) + .with_resource_id(property_id) + .build_url_from_base() + .build()) + return api_request diff --git a/oshconnect/csapi4py/part_1/sampling_features.py b/oshconnect/csapi4py/part_1/sampling_features.py new file mode 100644 index 0000000..5ae3d5c --- /dev/null +++ b/oshconnect/csapi4py/part_1/sampling_features.py @@ -0,0 +1,116 @@ +from typing import Union + +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_sampling_features(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers=None): + """ + Lists all sampling features in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SAMPLING_FEATURES.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def list_sampling_features_of_system(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Lists all sampling features of a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.SAMPLING_FEATURES.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def create_new_sampling_features(server_addr: HttpUrl, system_id: str, request_body: Union[dict, str], + api_root: str = APITerms.API.value, headers=None): + """ + Create a new sampling feature as defined by the request body + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.SAMPLING_FEATURES.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + return api_request.make_request() + + +def retrieve_sampling_feature_by_id(server_addr: HttpUrl, sampling_feature_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Retrieve a sampling feature by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SAMPLING_FEATURES.value) + .with_resource_id(sampling_feature_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_sampling_feature_by_id(server_addr: HttpUrl, sampling_feature_id: str, request_body: Union[dict, str], + api_root: str = APITerms.API.value, headers=None): + """ + Update a sampling feature by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SAMPLING_FEATURES.value) + .with_resource_id(sampling_feature_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() + + +def delete_sampling_feature_by_id(server_addr: HttpUrl, sampling_feature_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Delete a sampling feature by its ID + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SAMPLING_FEATURES.value) + .with_resource_id(sampling_feature_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_1/systems.py b/oshconnect/csapi4py/part_1/systems.py new file mode 100644 index 0000000..d746b24 --- /dev/null +++ b/oshconnect/csapi4py/part_1/systems.py @@ -0,0 +1,213 @@ +from typing import Union + +import requests +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms +from oshconnect.csapi4py.request_wrappers import post_request + + +def list_all_systems(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all systems in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def create_new_systems(server_addr: HttpUrl, request_body: Union[str, dict], api_root: str = APITerms.API.value, + uname: str = None, + pword: str = None, headers: dict = None): + """ + Create a new system as defined by the request body + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_auth(uname, pword) + .with_headers(headers) + .with_request_method('POST') + .build()) + print(api_request.url) + # resp = requests.post(api_request.url, data=api_request.body, headers=api_request.headers, auth=(uname, pword)) + resp = post_request(api_request.url, api_request.body, api_request.headers, api_request.auth) + print(f'Create new system response: {resp}') + return resp + + +def list_all_systems_in_collection(server_addr: HttpUrl, collection_id: str, api_root: str = APITerms.API.value): + """ + NOTE: function may not be able to fully represent a request to the API at this time, as the test server lacks a few + elements. + Lists all systems in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COLLECTIONS.value) + .with_resource_id(collection_id) + # .for_sub_resource_type(APITerms.ITEMS.value) + .build_url_from_base() + .build()) + print(api_request.url) + resp = requests.get(api_request.url, params=api_request.body, headers=api_request.headers) + return resp.json() + + +def add_systems_to_collection(server_addr: HttpUrl, collection_id: str, uri_list: str, + api_root: str = APITerms.API.value): + """ + Lists all systems in the server at the default API endpoint + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COLLECTIONS.value) + .with_resource_id(collection_id) + .for_sub_resource_type(APITerms.ITEMS.value) + .with_request_body(uri_list) + .build_url_from_base() + .build()) + resp = requests.post(api_request.url, json=api_request.body, headers=api_request.headers) + return resp.json() + + +def retrieve_system_by_id(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value): + """ + Retrieves a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .build_url_from_base() + .build()) + resp = requests.get(api_request.url, params=api_request.body, headers=api_request.headers) + return resp.json() + + +def update_system_description(server_addr: HttpUrl, system_id: str, request_body: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Updates a system's description by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .build()) + resp = requests.put(api_request.url, data=request_body, headers=api_request.headers) + return resp + + +def delete_system_by_id(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value, headers: dict = None): + """ + Deletes a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + return api_request.make_request() + + +def list_system_components(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value): + """ + Lists all components of a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.COMPONENTS.value) + .build_url_from_base() + .build()) + print(api_request.url) + resp = requests.get(api_request.url, params=api_request.body, headers=api_request.headers) + return resp.json() + + +def add_system_components(server_addr: HttpUrl, system_id: str, request_body: dict, + api_root: str = APITerms.API.value): + """ + Adds components to a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.COMPONENTS.value) + .with_request_body(request_body) + .build_url_from_base() + .build()) + resp = requests.post(api_request.url, params=api_request.body, headers=api_request.headers) + return resp.json() + + +def list_deployments_of_system(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value): + """ + Lists all deployments of a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.DEPLOYMENTS.value) + .build_url_from_base() + + .build()) + resp = requests.get(api_request.url, params=api_request.body, headers=api_request.headers) + return resp.json() + + +def list_sampling_features_of_system(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value): + """ + Lists all sampling features of a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.SAMPLING_FEATURES.value) + .build_url_from_base() + .build()) + print(api_request.url) + resp = requests.get(api_request.url, params=api_request.body, headers=api_request.headers) + return resp.json() diff --git a/oshconnect/csapi4py/part_2/__init__.py b/oshconnect/csapi4py/part_2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oshconnect/csapi4py/part_2/commands.py b/oshconnect/csapi4py/part_2/commands.py new file mode 100644 index 0000000..ac26dbf --- /dev/null +++ b/oshconnect/csapi4py/part_2/commands.py @@ -0,0 +1,227 @@ +from typing import Union + +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_commands(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all commands + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def list_commands_of_control_channel(server_addr: HttpUrl, control_channel_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Lists all commands of a control channel + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .with_resource_id(control_channel_id) + .for_sub_resource_type(APITerms.COMMANDS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def send_commands_to_specific_control_stream(server_addr: HttpUrl, control_stream_id: str, + request_body: Union[dict, str], + api_root: str = APITerms.API.value, headers=None): + """ + Sends a command to a control stream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .with_resource_id(control_stream_id) + .for_sub_resource_type(APITerms.COMMANDS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + + return api_request.make_request() + + +def retrieve_command_by_id(server_addr: HttpUrl, command_id: str, api_root: str = APITerms.API.value, headers=None): + """ + Retrieves a command by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def update_command_description(server_addr: HttpUrl, command_id: str, request_body: Union[dict, str], + api_root: str = APITerms.API.value, headers=None): + """ + Updates a command's description by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + + return api_request.make_request() + + +def delete_command_by_id(server_addr: HttpUrl, command_id: str, api_root: str = APITerms.API.value, headers=None): + """ + Deletes a command by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + + return api_request.make_request() + + +def list_command_status_reports(server_addr: HttpUrl, command_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Lists all status reports of a command by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .for_sub_resource_type(APITerms.STATUS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def add_command_status_reports(server_addr: HttpUrl, command_id: str, request_body: Union[dict, str], + api_root: str = APITerms.API.value, headers=None): + """ + Adds a status report to a command by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .for_sub_resource_type(APITerms.STATUS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + + return api_request.make_request() + + +def retrieve_command_status_report_by_id(server_addr: HttpUrl, command_id: str, status_report_id: str, + api_root: str = APITerms.API.value, headers=None): + """ + Retrieves a status report of a command by its id and status report id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .for_sub_resource_type(APITerms.STATUS.value) + .with_secondary_resource_id(status_report_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def update_command_status_report_by_id(server_addr: HttpUrl, command_id: str, status_report_id: str, + request_body: Union[dict, str], api_root: str = APITerms.API.value, + headers=None): + """ + Updates a status report of a command by its id and status report id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .for_sub_resource_type(APITerms.STATUS.value) + .with_secondary_resource_id(status_report_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + + return api_request.make_request() + + +def delete_command_status_report_by_id(server_addr: HttpUrl, command_id: str, status_report_id: str, + api_root: str = APITerms.API.value, headers=None): + """ + Deletes a status report of a command by its id and status report id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.COMMANDS.value) + .with_resource_id(command_id) + .for_sub_resource_type(APITerms.STATUS.value) + .with_secondary_resource_id(status_report_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_2/control_channels.py b/oshconnect/csapi4py/part_2/control_channels.py new file mode 100644 index 0000000..3b4d995 --- /dev/null +++ b/oshconnect/csapi4py/part_2/control_channels.py @@ -0,0 +1,159 @@ +from typing import Union + +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_control_streams(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all control streams + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def list_control_streams_of_system(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Lists all control streams of a system + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.CONTROL_STREAMS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def add_control_streams_to_system(server_addr: HttpUrl, system_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers=None): + """ + Adds a control stream to a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.CONTROL_STREAMS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + return api_request.make_request() + + +def retrieve_control_stream_description_by_id(server_addr: HttpUrl, control_stream_id: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Retrieves a control stream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .with_resource_id(control_stream_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def update_control_stream_description_by_id(server_addr: HttpUrl, control_stream_id: str, + request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers: dict = None): + """ + Updates a control stream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .with_resource_id(control_stream_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() + + +def delete_control_stream_by_id(server_addr: HttpUrl, control_stream_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Deletes a control stream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .with_resource_id(control_stream_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + + return api_request.make_request() + + +def retrieve_control_stream_schema_by_id(server_addr: HttpUrl, control_stream_id: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Retrieves a control stream schema by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .with_resource_id(control_stream_id) + .for_sub_resource_type(APITerms.SCHEMA.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def update_control_stream_schema_by_id(server_addr: HttpUrl, control_stream_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers: dict = None): + """ + Updates a control stream schema by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.CONTROL_STREAMS.value) + .with_resource_id(control_stream_id) + # .for_sub_resource_type(APITerms.SCHEMA.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_2/datastreams.py b/oshconnect/csapi4py/part_2/datastreams.py new file mode 100644 index 0000000..3a21b3a --- /dev/null +++ b/oshconnect/csapi4py/part_2/datastreams.py @@ -0,0 +1,155 @@ +from typing import Union + +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_datastreams(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all datastreams + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def list_all_datastreams_of_system(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Lists all datastreams of a system + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.DATASTREAMS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def add_datastreams_to_system(server_addr: HttpUrl, system_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers=None): + """ + Adds a datastream to a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.DATASTREAMS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + return api_request.make_request() + + +def retrieve_datastream_by_id(server_addr: HttpUrl, datastream_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Retrieves a datastream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .with_resource_id(datastream_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_datastream_by_id(server_addr: HttpUrl, datastream_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers=None): + """ + Updates a datastream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .with_resource_id(datastream_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() + + +def delete_datastream_by_id(server_addr: HttpUrl, datastream_id: str, api_root: str = APITerms.API.value, headers=None): + """ + Deletes a datastream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .with_resource_id(datastream_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + return api_request.make_request() + + +def retrieve_datastream_schema(server_addr: HttpUrl, datastream_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Retrieves a datastream schema by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .with_resource_id(datastream_id) + .for_sub_resource_type(APITerms.SCHEMA.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_datastream_schema(server_addr: HttpUrl, datastream_id: str, request_body: dict, + api_root: str = APITerms.API.value, headers=None): + """ + Updates a datastream schema by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .with_resource_id(datastream_id) + .for_resource_type(APITerms.SCHEMA.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_2/observations.py b/oshconnect/csapi4py/part_2/observations.py new file mode 100644 index 0000000..788407b --- /dev/null +++ b/oshconnect/csapi4py/part_2/observations.py @@ -0,0 +1,122 @@ +from typing import Union + +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_all_observations(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers=None): + """ + Lists all observations + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.OBSERVATIONS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def list_observations_from_datastream(server_addr: HttpUrl, datastream_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Lists all observations of a datastream + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .with_resource_id(datastream_id) + .for_sub_resource_type(APITerms.OBSERVATIONS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def add_observations_to_datastream(server_addr: HttpUrl, datastream_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers=None): + """ + Adds an observation to a datastream by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.DATASTREAMS.value) + .with_resource_id(datastream_id) + .for_sub_resource_type(APITerms.OBSERVATIONS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + + return api_request.make_request() + + +def retrieve_observation_by_id(server_addr: HttpUrl, observation_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Retrieves an observation by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.OBSERVATIONS.value) + .with_resource_id(observation_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + + return api_request.make_request() + + +def update_observation_by_id(server_addr: HttpUrl, observation_id: str, request_body: Union[str, dict], + api_root: str = APITerms.API.value, headers=None): + """ + Updates an observation by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.OBSERVATIONS.value) + .with_resource_id(observation_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + + return api_request.make_request() + + +def delete_observation_by_id(server_addr: HttpUrl, observation_id: str, api_root: str = APITerms.API.value, + headers=None): + """ + Deletes an observation by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.OBSERVATIONS.value) + .with_resource_id(observation_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_2/system_events.py b/oshconnect/csapi4py/part_2/system_events.py new file mode 100644 index 0000000..afbbb47 --- /dev/null +++ b/oshconnect/csapi4py/part_2/system_events.py @@ -0,0 +1,122 @@ +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_system_events(server_addr: HttpUrl, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all system events + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEM_EVENTS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def list_events_by_system_id(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Lists all events of a system + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.EVENTS.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def add_new_system_events(server_addr: HttpUrl, system_id: str, request_body: dict, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Adds a new system event to a system by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.EVENTS.value) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('POST') + .build()) + return api_request.make_request() + + +def retrieve_system_event_by_id(server_addr: HttpUrl, system_id: str, event_id: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Retrieves a system event by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.EVENTS.value) + .with_secondary_resource_id(event_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_system_event_by_id(server_addr: HttpUrl, system_id: str, event_id: str, request_body: dict, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Updates a system event by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.EVENTS.value) + + .with_secondary_resource_id(event_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() + + +def delete_system_event_by_id(server_addr: HttpUrl, system_id: str, event_id: str, api_root: str = APITerms.API.value, + headers: dict = None): + """ + Deletes a system event by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_sub_resource_type(APITerms.EVENTS.value) + .with_secondary_resource_id(event_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + + return api_request.make_request() diff --git a/oshconnect/csapi4py/part_2/system_history.py b/oshconnect/csapi4py/part_2/system_history.py new file mode 100644 index 0000000..dc73c5c --- /dev/null +++ b/oshconnect/csapi4py/part_2/system_history.py @@ -0,0 +1,83 @@ +from pydantic import HttpUrl + +from oshconnect.csapi4py.con_sys_api import ConnectedSystemsRequestBuilder +from oshconnect.csapi4py.constants import APITerms + + +def list_system_history(server_addr: HttpUrl, system_id: str, api_root: str = APITerms.API.value, headers: dict = None): + """ + Lists all history versions of a system + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_resource_type(APITerms.HISTORY.value) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def retrieve_system_historical_description_by_id(server_addr: HttpUrl, system_id: str, history_id: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Retrieves a historical system description by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_resource_type(APITerms.HISTORY.value) + .with_secondary_resource_id(history_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('GET') + .build()) + return api_request.make_request() + + +def update_system_historical_description(server_addr: HttpUrl, system_id: str, history_rev_id: str, request_body: dict, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Updates a historical system description by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_resource_type(APITerms.HISTORY.value) + .with_secondary_resource_id(history_rev_id) + .with_request_body(request_body) + .build_url_from_base() + .with_headers(headers) + .with_request_method('PUT') + .build()) + return api_request.make_request() + + +def delete_system_historical_description_by_id(server_addr: HttpUrl, system_id: str, history_rev_id: str, + api_root: str = APITerms.API.value, headers: dict = None): + """ + Deletes a historical system description by its id + :return: + """ + builder = ConnectedSystemsRequestBuilder() + api_request = (builder.with_server_url(server_addr) + .with_api_root(api_root) + .for_resource_type(APITerms.SYSTEMS.value) + .with_resource_id(system_id) + .for_resource_type(APITerms.HISTORY.value) + .with_secondary_resource_id(history_rev_id) + .build_url_from_base() + .with_headers(headers) + .with_request_method('DELETE') + .build()) + return api_request.make_request() diff --git a/oshconnect/csapi4py/querymodel.py b/oshconnect/csapi4py/querymodel.py new file mode 100644 index 0000000..f483b06 --- /dev/null +++ b/oshconnect/csapi4py/querymodel.py @@ -0,0 +1,25 @@ +from datetime import datetime +from typing import Union, Optional, List + +from pydantic import BaseModel, StrictStr, Field, field_validator + + +class QueryModel(BaseModel): + id: list = None + bbox: list = None + date_time: Union[StrictStr, datetime] = Field(None, alias='datetime') + geom: dict = None + q: list = Optional[List[str]] + parent: list = None + procedure: list = None + foi: list = None + observed_property: list = Field(None, serialization_alias='observedProperty') + controlled_property: list = Field(None, serialization_alias='controlledProperty') + recursive: bool = False + limit: int = Field(10, ge=1, le=10000) + + @field_validator('q') + def validate_q(cls, v): + if v is not None: + return v.split(',') + return v diff --git a/oshconnect/csapi4py/request_bodies.py b/oshconnect/csapi4py/request_bodies.py new file mode 100644 index 0000000..c9bbb93 --- /dev/null +++ b/oshconnect/csapi4py/request_bodies.py @@ -0,0 +1,99 @@ +from typing import Union + +from pydantic import BaseModel, HttpUrl, Field, model_serializer, RootModel, SerializeAsAny + +from oshconnect.csapi4py.constants import DatastreamResultTypes +from oshconnect.datamodels.datastreams import DatastreamSchema +from oshconnect.datamodels.geometry import Geometry +from oshconnect.csapi4py.sensor_ml.sml import TypeOf + + +# TODO: Consider some sort of Abstract Base Class for all valid request bodies to inherit from to reduce the complexity +# of the final request body. + +class GeoJSONBody(BaseModel): + type: str + id: str + properties: dict = None + geometry: Geometry = None + bbox: list = None + links: list = None + + +class SmlJSONBody(BaseModel): + object_type: str = Field(None, serialization_alias='type') + id: str = Field(None) + description: str = Field(None) + unique_id: str = Field(..., serialization_alias='uniqueId') + label: str = Field(...) + lang: str = None + keywords: list = None + identifiers: list = None + classifiers: list = None + valid_time: list = Field(None, serialization_alias='validTime') + security_constraints: list = Field(None, serialization_alias='securityConstraints') + legal_constraints: list = Field(None, serialization_alias='legalConstraints') + characteristics: list = None + capabilities: list = None + contacts: list = None + documents: list = None + history: list = None + definition: HttpUrl = None + type_of: TypeOf = Field(None, serialization_alias='typeOf') + configuration: HttpUrl = None + features_of_interest: list = Field(None, serialization_alias='featuresOfInterest') + inputs: list = None + outputs: list = None + parameters: list = None + modes: list = None + method: str = None + position: list = None + links: list = Field(None) + + +class OMJSONBody(BaseModel): + datastream_id: str = Field(None, alias="datastream@id") + foi_id: str = Field(None, alias="foi@id") + phenomenon_time: str = Field(None, alias="phenomenonTime") + result_time: str = Field(None, alias="resultTime") + parameters: list = Field(None) + result: dict = Field(None) + result_links: list = Field(None, alias="result@links") + + +class DatastreamBodyJSON(BaseModel): + """ + NOTES: though the spec does not require that outputName, and schema be present, they are required for the + implementation of the API present on OSH + """ + id: str = Field(None) + name: str = Field(...) + description: str = Field(None) + deployment: HttpUrl = Field(None, serialization_alias='deployment@link') + ultimate_feature_of_interest: HttpUrl = Field(None, serialization_alias='ultimateFeatureOfInterest@link') + sampling_feature: HttpUrl = Field(None, serialization_alias='samplingFeature@link') + valid_time: list = Field(None, serialization_alias='validTime') + output_name: str = Field(..., serialization_alias='outputName') + phenomenon_time_interval: str = Field(None, serialization_alias='phenomenonTimeInterval') + result_time_interval: str = Field(None, serialization_alias='resultTimeInterval') + result_type: DatastreamResultTypes = Field(None, serialization_alias='resultType') + links: list = Field(None) + datastream_schema: SerializeAsAny[DatastreamSchema] = Field(..., serialization_alias='schema') + + +class RequestBody(BaseModel): + """ + Wrapper class to support different request json structures + """ + json_structure: Union[GeoJSONBody, SmlJSONBody, OMJSONBody, DatastreamSchema] = Field(..., + serialization_alias='json') + test_extra: str = Field("Hello, I am test", serialization_alias='testExtra') + + @model_serializer + def ser_model(self): + print("Serializing model...") + return self.json_structure + + +class RequestBodyList(RootModel): + root: list[Union[GeoJSONBody, SmlJSONBody, OMJSONBody, DatastreamSchema]] = Field(...) diff --git a/oshconnect/csapi4py/request_wrappers.py b/oshconnect/csapi4py/request_wrappers.py new file mode 100644 index 0000000..8f1f837 --- /dev/null +++ b/oshconnect/csapi4py/request_wrappers.py @@ -0,0 +1,58 @@ +from typing import Union + +import requests +from pydantic import HttpUrl + + +def get_request(url: HttpUrl, params: dict = None, headers: dict = None, auth: tuple = None): + """ + Sends a GET request to the provided URL with the given parameters and headers + :param url: + :param params: + :param headers: + :param auth: + :return: the response of the request + """ + return requests.get(url, params=params, headers=headers, auth=auth) + + +def post_request(url: HttpUrl, body: Union[str, dict] = None, headers: dict = None, auth: tuple = None): + """ + Sends a POST request to the provided URL with the given content and headers + :param url: + :param content_json: + :param headers: + :param auth: + :return: the response of the request + """ + if isinstance(body, str): + return requests.post(url, data=body, headers=headers, auth=auth) + else: + return requests.post(url, json=body, headers=headers, auth=auth) + + +def put_request(url: HttpUrl, body: Union[str, dict] = None, headers: dict = None, auth: tuple = None): + """ + Sends a PUT request to the provided URL with the given content and headers + :param url: + :param content_json: + :param headers: + :param auth: + :return: the response of the request + """ + if isinstance(body, str): + return requests.put(url, data=body, headers=headers, auth=auth) + else: + return requests.put(url, json=body, headers=headers, auth=auth) + + +def delete_request(url: HttpUrl, params: dict = None, headers: dict = None, auth: tuple = None): + """ + Sends a DELETE request to the provided URL with the given parameters and headers + :param url: + :param params: + :param headers: + :param auth: + :return: the response of the request + """ + return requests.delete(url, params=params, headers=headers, auth=auth) diff --git a/oshconnect/csapi4py/sensor_ml/__init__.py b/oshconnect/csapi4py/sensor_ml/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oshconnect/csapi4py/sensor_ml/sml.py b/oshconnect/csapi4py/sensor_ml/sml.py new file mode 100644 index 0000000..8c704b0 --- /dev/null +++ b/oshconnect/csapi4py/sensor_ml/sml.py @@ -0,0 +1,51 @@ +from pydantic import BaseModel, HttpUrl, Field + + +class TypeOf(BaseModel): + """ + TypeOf is a resolvable reference to some other general process (that can be any type inheriting from AbstractProcess) + :param href: The URL of the referenced process + :param relationship: The relationship of the referenced process to the current process + :param media_type: The media type of the referenced process + :param href_lang: The language of the referenced process + :param title: The title of the referenced process + :param uid: The unique identifier of the referenced process + :param target_resource: The target resource of the referenced process + :param interface: The interface of the referenced process + """ + href: HttpUrl + relationship: str = Field(..., serialization_alias='rel') + media_type: str = Field(None, serialization_alias='type') + href_lang: str = Field(None, serialization_alias='hreflang') + title: str = Field(None) + uid: str = Field(None) + target_resource: str = Field(None, serialization_alias='rt') + interface: str = Field(None, serialization_alias='if') + + +class SMLAbstractProcess(BaseModel): + description: str = None + unique_id: str = Field(None, serialization_alias='uniqueID') + label: str = None + lang: str = None + keywords: list = None + identifiers: list = None + classifiers: list = None + valid_time: list = Field(None, serialization_alias='validTime') + security_constraints: list = Field(None, serialization_alias='securityConstraints') + legal_constraints: list = Field(None, serialization_alias='legalConstraints') + characteristics: list = None + capabilities: list = None + contacts: list = None + documents: list = None + history: list = None + definition: HttpUrl = None + type_of: TypeOf = Field(None, serialization_alias='typeOf') + configuration: HttpUrl = None + features_of_interest: list = Field(None, serialization_alias='featuresOfInterest') + inputs: list = None + outputs: list = None + parameters: list = None + modes: list = None + method: str = None + position: list = None diff --git a/oshconnect/csapi4py/utilities/__init__.py b/oshconnect/csapi4py/utilities/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oshconnect/csapi4py/utilities/model_utils.py b/oshconnect/csapi4py/utilities/model_utils.py new file mode 100644 index 0000000..87cac03 --- /dev/null +++ b/oshconnect/csapi4py/utilities/model_utils.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel + + +def serialize_model_list(model_list: list[BaseModel]): + """ + Serializes a list of pydantic models + :param model_list: + :return: a valid json string + """ + return '[' + ','.join([model.model_dump_json(exclude_none=True, by_alias=True) for model in model_list]) + ']' diff --git a/oshconnect/datamodels/__init__.py b/oshconnect/datamodels/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oshconnect/datamodels/api_utils.py b/oshconnect/datamodels/api_utils.py new file mode 100644 index 0000000..9ed710f --- /dev/null +++ b/oshconnect/datamodels/api_utils.py @@ -0,0 +1,39 @@ +from __future__ import annotations +from pydantic import BaseModel, Field, HttpUrl, field_validator + + +class Link(BaseModel): + href: HttpUrl = Field(...) + rel: str = Field(None) + type: str = Field(None) + hreflang: str = Field(None) + title: str = Field(None) + uid: URI = Field(None) + rt: URI = Field(None) + interface: URI = Field(None, serialization_alias='if') + + +class UCUMCode(BaseModel): + code: str = Field(...) + label: str = Field(None) + + @field_validator('code', 'label') + @classmethod + def validate_string_fields(cls, v): + if isinstance(v, str) and len(v) > 0: + return v + else: + raise ValueError('code and label must be strings of length > 0') + + +class URI(BaseModel): + href: HttpUrl = Field(...) + label: str = Field(None) + + @field_validator('label') + @classmethod + def validate_label(cls, v): + if isinstance(v, str) and len(v) > 0: + return v + else: + raise ValueError('label must be strings of length > 0') diff --git a/oshconnect/datamodels/commands.py b/oshconnect/datamodels/commands.py new file mode 100644 index 0000000..999b480 --- /dev/null +++ b/oshconnect/datamodels/commands.py @@ -0,0 +1,14 @@ +from datetime import datetime +from typing import Union + +from pydantic import BaseModel, Field + + +class CommandJSON(BaseModel): + """ + A class to represent a command in JSON format + """ + control_id: str = Field(None, serialization_alias="control@id") + issue_time: Union[str, float] = Field(datetime.now().isoformat(), serialization_alias="issueTime") + sender: str = Field(None) + params: Union[dict, list, int, float, str] = Field(None) diff --git a/oshconnect/datamodels/control_streams.py b/oshconnect/datamodels/control_streams.py new file mode 100644 index 0000000..8ee8eb5 --- /dev/null +++ b/oshconnect/datamodels/control_streams.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +from typing import Union + +from pydantic import BaseModel, Field, SerializeAsAny + +from oshconnect.datamodels.encoding import Encoding +from oshconnect.datamodels.swe_components import AnyComponentSchema + + +class ControlStreamJSONSchema(BaseModel): + """ + A class to represent the schema of a control stream + """ + id: str = Field(None) + name: str = Field(...) + description: str = Field(None) + deployment_link: str = Field(None, serialization_alias='deployment@link') + ultimate_feature_of_interest_link: str = Field(None, serialization_alias='ultimateFeatureOfInterest@link') + sampling_feature_link: str = Field(None, alias='samplingFeature@link') + valid_time: list = Field(None, serialization_alias='validTime') + input_name: str = Field(None, serialization_alias='inputName') + links: list = Field(None) + control_stream_schema: SerializeAsAny[Union[SWEControlChannelSchema, JSONControlChannelSchema]] = Field(..., + serialization_alias='schema') + + +class SWEControlChannelSchema(BaseModel): + """ + A class to represent the schema of a control channel + """ + command_format: str = Field("application/swe+json", serialization_alias='commandFormat') + encoding: SerializeAsAny[Encoding] = Field(...) + record_schema: SerializeAsAny[AnyComponentSchema] = Field(..., serialization_alias='recordSchema') + + +class JSONControlChannelSchema(BaseModel): + command_format: str = Field("application/cmd+json", serialization_alias='commandFormat') + params_schema: SerializeAsAny[AnyComponentSchema] = Field(..., serialization_alias='paramsSchema') diff --git a/oshconnect/datamodels/datastreams.py b/oshconnect/datamodels/datastreams.py new file mode 100644 index 0000000..11d3986 --- /dev/null +++ b/oshconnect/datamodels/datastreams.py @@ -0,0 +1,25 @@ +from pydantic import BaseModel, Field, field_validator, SerializeAsAny + +from oshconnect.csapi4py.constants import ObservationFormat +from oshconnect.datamodels.encoding import Encoding +from oshconnect.datamodels.swe_components import AnyComponentSchema + + +class DatastreamSchema(BaseModel): + """ + A class to represent the schema of a datastream + """ + obs_format: str = Field(..., serialization_alias='obsFormat') + + +class SWEDatastreamSchema(DatastreamSchema): + encoding: SerializeAsAny[Encoding] = Field(...) + record_schema: SerializeAsAny[AnyComponentSchema] = Field(..., serialization_alias='recordSchema') + + @field_validator('obs_format') + @classmethod + def check_check_obs_format(cls, v): + if v not in [ObservationFormat.SWE_JSON.value, ObservationFormat.SWE_CSV.value, + ObservationFormat.SWE_TEXT.value, ObservationFormat.SWE_BINARY.value]: + raise ValueError('obsFormat must be on of the SWE formats') + return v diff --git a/oshconnect/datamodels/encoding.py b/oshconnect/datamodels/encoding.py new file mode 100644 index 0000000..e2c04d7 --- /dev/null +++ b/oshconnect/datamodels/encoding.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel, Field + + +class Encoding(BaseModel): + id: str = Field(None) + type: str = Field(...) + vector_as_arrays: bool = Field(False, alias='vectorAsArrays') + + +class JSONEncoding(Encoding): + type: str = "JSONEncoding" diff --git a/oshconnect/datamodels/geometry.py b/oshconnect/datamodels/geometry.py new file mode 100644 index 0000000..60bbaab --- /dev/null +++ b/oshconnect/datamodels/geometry.py @@ -0,0 +1,14 @@ +from pydantic import BaseModel, Field + +from oshconnect.csapi4py.constants import GeometryTypes + + +# TODO: Add specific validations for each type +# TODO: update to either use third party Geometry definitions or create a more robust definition +class Geometry(BaseModel): + """ + A class to represent the geometry of a feature + """ + type: GeometryTypes = Field(...) + coordinates: list + bbox: list = None \ No newline at end of file diff --git a/oshconnect/datamodels/network_properties.py b/oshconnect/datamodels/network_properties.py new file mode 100644 index 0000000..51a0b95 --- /dev/null +++ b/oshconnect/datamodels/network_properties.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel, HttpUrl + + +class NetworkProperties(BaseModel): + endpoint_url: HttpUrl + tls: bool = False + stream_protocol: str = 'ws' + mqtt_opts: dict = None + mqtt_endpoint_url: HttpUrl = None + connector_opts: dict = None diff --git a/oshconnect/datamodels/observations.py b/oshconnect/datamodels/observations.py new file mode 100644 index 0000000..3de9dee --- /dev/null +++ b/oshconnect/datamodels/observations.py @@ -0,0 +1,19 @@ +from datetime import datetime +from typing import Union, List + +from pydantic import BaseModel, Field + +from oshconnect.datamodels.api_utils import Link + + +class ObservationOMJSONInline(BaseModel): + """ + A class to represent an observation in OM-JSON format + """ + datastream_id: str = Field(None, serialization_alias="datastream@id") + foi_id: str = Field(None, serialization_alias="foi@id") + phenomenon_time: str = Field(None, serialization_alias="phenomenonTime") + result_time: str = Field(datetime.now().isoformat(), serialization_alias="resultTime") + parameters: dict = Field(None) + result: Union[int, float, str, dict, list] = Field(...) + result_links: List[Link] = Field(None, serialization_alias="result@links") diff --git a/oshconnect/datamodels/swe_components.py b/oshconnect/datamodels/swe_components.py new file mode 100644 index 0000000..911ac52 --- /dev/null +++ b/oshconnect/datamodels/swe_components.py @@ -0,0 +1,200 @@ +from __future__ import annotations + +from numbers import Real +from typing import Union, Any + +from pydantic import BaseModel, Field, field_validator, SerializeAsAny + +from oshconnect.csapi4py.constants import GeometryTypes +from oshconnect.datamodels.api_utils import UCUMCode, URI +from oshconnect.datamodels.geometry import Geometry + +""" + NOTE: The following classes are used to represent the Record Schemas that are required for use with Datastreams +The names are likely to change to include a "Schema" suffix to differentiate them from the actual data structures. +The current scope of the project likely excludes conversion from received data to actual SWE Common data structures, +in the event this is added it will most likely be in a separate module as those structures have use cases outside of +the API solely +""" + + +# TODO: Add field validators that are missing +# TODO: valid string fields that are intended to represent time/date values +# TODO: Validate places where string fields are not allowed to be empty + + +class AnyComponentSchema(BaseModel): + type: str = Field(...) + id: str = Field(None) + label: str = Field(None) + description: str = Field(None) + updatable: bool = Field(False) + optional: bool = Field(False) + definition: str = Field(None) + + +class DataRecordSchema(AnyComponentSchema): + type: str = "DataRecord" + fields: SerializeAsAny[list[AnyComponentSchema]] = Field(...) + + +class VectorSchema(AnyComponentSchema): + label: str = Field(...) + name: str = Field(...) + type: str = "Vector" + definition: str = Field(...) + reference_frame: str = Field(...) + local_frame: str = Field(None) + # TODO: VERIFY might need to be moved further down when these are defined + coordinates: SerializeAsAny[Union[list[CountSchema], list[QuantitySchema], list[TimeSchema]]] = Field(...) + + +class DataArraySchema(AnyComponentSchema): + type: str = "DataArray" + name: str = Field(...) + element_count: dict | str | CountSchema = Field(..., serialization_alias='elementCount') # Should type of Count + element_type: SerializeAsAny[list[AnyComponentSchema]] = Field(..., serialization_alias='elementType') + encoding: str = Field(...) # TODO: implement an encodings class + values: list = Field(None) + + +class MatrixSchema(AnyComponentSchema): + type: str = "Matrix" + element_count: dict | str | CountSchema = Field(..., serialization_alias='elementCount') # Should be type of Count + element_type: SerializeAsAny[list[AnyComponentSchema]] = Field(..., serialization_alias='elementType') + encoding: str = Field(...) # TODO: implement an encodings class + values: list = Field(None) + reference_frame: str = Field(None) + local_frame: str = Field(None) + + +class DataChoiceSchema(AnyComponentSchema): + type: str = "DataChoice" + updatable: bool = Field(False) + optional: bool = Field(False) + choice_value: CategorySchema = Field(..., serialization_alias='choiceValue') # TODO: Might be called "choiceValues" + items: SerializeAsAny[list[AnyComponentSchema]] = Field(...) + + +class GeometrySchema(AnyComponentSchema): + label: str = Field(...) + type: str = "Geometry" + updatable: bool = Field(False) + optional: bool = Field(False) + definition: str = Field(...) + constraint: dict = Field(default_factory=lambda: { + 'geomTypes': [ + GeometryTypes.POINT.value, + GeometryTypes.LINESTRING.value, + GeometryTypes.POLYGON.value, + GeometryTypes.MULTI_POINT.value, + GeometryTypes.MULTI_LINESTRING.value, + GeometryTypes.MULTI_POLYGON.value + ] + }) + nil_values: list = Field(None, serialization_alias='nilValues') + srs: str = Field(...) + value: Geometry = Field(None) + + +class AnySimpleComponentSchema(AnyComponentSchema): + label: str = Field(...) + description: str = Field(None) + type: str = Field(...) + updatable: bool = Field(False) + optional: bool = Field(False) + definition: str = Field(...) + reference_frame: str = Field(None, serialization_alias='referenceFrame') + axis_id: str = Field(None, serialization_alias='axisID') + quality: Union[list[QuantitySchema], list[QuantityRangeSchema], list[CategorySchema], list[TextSchema]] = Field( + None) # TODO: Union[Quantity, QuantityRange, Category, Text] + nil_values: list = Field(None, serialization_alias='nilValues') + constraint: Any = Field(None) + value: Any = Field(None) + name: str = Field(...) + + +class AnyScalarComponentSchema(AnySimpleComponentSchema): + """ + A base class for all scalar components. The structure is essentially that of AnySimpleComponent + """ + pass + + +class BooleanSchema(AnyScalarComponentSchema): + type: str = "Boolean" + value: bool = Field(None) + + +class CountSchema(AnyScalarComponentSchema): + type: str = "Count" + value: int = Field(None) + + +class QuantitySchema(AnyScalarComponentSchema): + type: str = "Quantity" + value: Union[float, str] = Field(None) + uom: Union[UCUMCode, URI] = Field(...) + + @field_validator('value') + @classmethod + def validate_value(cls, v): + if isinstance(v, Real): + return v + elif isinstance(v, str): + if v in ['NaN', 'INFINITY', '+INFINITY', '-INFINITY']: + return v + else: + raise ValueError( + 'string representation of value must be one of the following: NaN, INFINITY, +INFINITY, -INFINITY') + else: + try: + return float(v) + except ValueError: + raise ValueError('value must be a number or a string representing a special value ' + '[NaN, INFINITY, +INFINITY, -INFINITY]') + + +class TimeSchema(AnyScalarComponentSchema): + type: str = "Time" + value: str = Field(None) + reference_time: str = Field(None, serialization_alias='referenceTime') + local_frame: str = Field(None) + uom: Union[UCUMCode, URI] = Field(...) + + +class CategorySchema(AnyScalarComponentSchema): + type: str = "Category" + value: str = Field(None) + code_space: str = Field(None, serialization_alias='codeSpace') + + +class TextSchema(AnyScalarComponentSchema): + type: str = "Text" + value: str = Field(None) + + +class CountRangeSchema(AnySimpleComponentSchema): + type: str = "CountRange" + value: list[int] = Field(None) + uom: Union[UCUMCode, URI] = Field(...) + + +class QuantityRangeSchema(AnySimpleComponentSchema): + type: str = "QuantityRange" + value: list[Union[float, str]] = Field(None) + uom: Union[UCUMCode, URI] = Field(...) + + +class TimeRangeSchema(AnySimpleComponentSchema): + type: str = "TimeRange" + value: list[str] = Field(None) + reference_time: str = Field(None, serialization_alias='referenceTime') + local_frame: str = Field(None) + uom: Union[UCUMCode, URI] = Field(...) + + +class CategoryRangeSchema(AnySimpleComponentSchema): + type: str = "CategoryRange" + value: list[str] = Field(None) + code_space: str = Field(None, serialization_alias='codeSpace') diff --git a/oshconnect/datamodels/system_events_and_history.py b/oshconnect/datamodels/system_events_and_history.py new file mode 100644 index 0000000..f0801ec --- /dev/null +++ b/oshconnect/datamodels/system_events_and_history.py @@ -0,0 +1,46 @@ +from __future__ import annotations + +from pydantic import BaseModel, Field, HttpUrl + +from oshconnect.datamodels.api_utils import Link, URI +from oshconnect.datamodels.geometry import Geometry + + +class SystemEventOMJSON(BaseModel): + """ + A class to represent the schema of a system event + """ + label: str = Field(...) + description: str = Field(None) + definition: HttpUrl = Field(...) + identifiers: list = Field(None) + classifiers: list = Field(None) + contacts: list = Field(None) + documentation: list = Field(None) + time: str = Field(...) + properties: list = Field(None) + configuration: dict = Field(None) + links: list[Link] = Field(None) + + +class SystemHistoryGeoJSON(BaseModel): + """ + A class to represent the schema of a system history + """ + type: str = Field(...) + id: str = Field(None) + properties: SystemHistoryProperties = Field(...) + geometry: Geometry = Field(None) + bbox: list = Field(None) + links: list[Link] = Field(None) + + +class SystemHistoryProperties(BaseModel): + feature_type: str = Field(...) + uid: URI = Field(...) + name: str = Field(...) + description: str = Field(None) + asset_type: str = Field(None) + valid_time: list = Field(None) + parent_system_link: str = Field(None, serialization_alias='parentSystem@link') + procedure_link: str = Field(None, serialization_alias='procedure@link') diff --git a/oshconnect/datasource.py b/oshconnect/datasource.py index dcefa1f..d63c1fb 100644 --- a/oshconnect/datasource.py +++ b/oshconnect/datasource.py @@ -16,9 +16,9 @@ import requests import websockets -from consys4py.constants import APIResourceTypes -from consys4py.datamodels.observations import ObservationOMJSONInline -from consys4py.datamodels.swe_components import DataRecordSchema +from oshconnect.csapi4py.constants import APIResourceTypes +from oshconnect.datamodels.observations import ObservationOMJSONInline +from oshconnect.datamodels.swe_components import DataRecordSchema from .core_datamodels import DatastreamResource, SystemResource, TimePeriod from .timemanagement import TemporalModes diff --git a/oshconnect/osh_connect_datamodels.py b/oshconnect/osh_connect_datamodels.py index 6f1899e..e9d4461 100644 --- a/oshconnect/osh_connect_datamodels.py +++ b/oshconnect/osh_connect_datamodels.py @@ -10,11 +10,11 @@ import uuid from dataclasses import dataclass, field -from consys4py.constants import APIResourceTypes -from consys4py.core.default_api_helpers import APIHelper -from consys4py.datamodels.datastreams import SWEDatastreamSchema -from consys4py.datamodels.encoding import JSONEncoding -from consys4py.datamodels.swe_components import DataRecordSchema +from oshconnect.csapi4py.constants import APIResourceTypes +from oshconnect.csapi4py.core.default_api_helpers import APIHelper +from oshconnect.datamodels.datastreams import SWEDatastreamSchema +from oshconnect.datamodels.encoding import JSONEncoding +from oshconnect.datamodels.swe_components import DataRecordSchema from .core_datamodels import DatastreamResource, ObservationResource, SystemResource from .timemanagement import TimeInstant, TimePeriod, TimeUtils diff --git a/oshconnect/oshconnectapi.py b/oshconnect/oshconnectapi.py index da06767..1ac8fde 100644 --- a/oshconnect/oshconnectapi.py +++ b/oshconnect/oshconnectapi.py @@ -7,7 +7,7 @@ import logging import shelve -from consys4py.core.default_api_helpers import APIHelper +from oshconnect.csapi4py.core.default_api_helpers import APIHelper from .core_datamodels import DatastreamResource, TimePeriod from .datasource import DataStream, DataStreamHandler, MessageWrapper diff --git a/pyproject.toml b/pyproject.toml index 761bb2f..b14cd73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,11 +8,10 @@ authors = [ ] requires-python = "<4.0,>=3.12" dependencies = [ + "paho-mqtt>=2.1.0", "pydantic<3.0.0,>=2.7.4", "shapely<3.0.0,>=2.0.4", "websockets<13.0,>=12.0", - "consys4py<1.0.0,>=0.0.1b3", - "swecommondm<1.0.0,>=0.0.1a0", ] [dependency-groups] diff --git a/rud/README.md b/rud/README.md deleted file mode 100644 index e424fe2..0000000 --- a/rud/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# What is this package? -These files are all either redundant, not needed for the project, or deprecated. They are kept here for reference purposes -as the library moves forward to v1.0 \ No newline at end of file diff --git a/rud/__init__.py b/rud/__init__.py deleted file mode 100644 index 6dc4918..0000000 --- a/rud/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# ============================================================================== -# Copyright (c) 2024 Botts Innovative Research, Inc. -# Date: 2024/6/25 -# Author: Ian Patterson -# Contact Email: ian@botts-inc.com -# ============================================================================== diff --git a/rud/unimpl/__init__.py b/rud/unimpl/__init__.py deleted file mode 100644 index 6dc4918..0000000 --- a/rud/unimpl/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# ============================================================================== -# Copyright (c) 2024 Botts Innovative Research, Inc. -# Date: 2024/6/25 -# Author: Ian Patterson -# Contact Email: ian@botts-inc.com -# ============================================================================== diff --git a/rud/unimpl/datasources/__init__.py b/rud/unimpl/datasources/__init__.py deleted file mode 100644 index 6dc4918..0000000 --- a/rud/unimpl/datasources/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# ============================================================================== -# Copyright (c) 2024 Botts Innovative Research, Inc. -# Date: 2024/6/25 -# Author: Ian Patterson -# Contact Email: ian@botts-inc.com -# ============================================================================== diff --git a/rud/unimpl/datasources/handler.py b/rud/unimpl/datasources/handler.py deleted file mode 100644 index 269391a..0000000 --- a/rud/unimpl/datasources/handler.py +++ /dev/null @@ -1,67 +0,0 @@ - -# ============================================================================== -# Copyright (c) 2024 Botts Innovative Research, Inc. -# Date: 2024/5/28 -# Author: Ian Patterson -# Contact Email: ian@botts-inc.com -# ============================================================================== - -from abc import ABC, abstractmethod - - -# Might not be necessary due to differences in this implementation die to actual multiprocessing -class DataSourceHandler(ABC): - def __init__(self): - self.context = None - self.topic = None - self.broadcast_channel = None - self.values = [] - self.version = 0 - self.properties = { - "batchsize": 1 - } - self._initialized = False - self.datasource_id = None - - @abstractmethod - def create_context(self, properties: dict): - pass - - async def init(self, datasource_id: str, properties: dict, topics: list[str]): - self.datasource_id = datasource_id - self.properties.update(properties) - self.topic = self.set_topics(topics) - # Context doesn't really have to exist in python - self.context = self.create_context(properties) - self.context.on_change_status = self.on_change_status() - self.context.handle_data = self.handle_data() - await self.context.init(self.properties) - self._initialized = True - - # TODO: topics may not be necessary - def set_topics(self, topics): - _topic = topics.data - if self.topic == _topic: - return - return - - def on_change_status(self): - pass - - def handle_data(self): - pass - - def flush(self): - pass - - def connect(self): - pass - - def disconnect(self): - pass - - def is_initialized(self): - return self._initialized - - def is_connected(self): - pass diff --git a/uv.lock b/uv.lock index 1db7aca..4409817 100644 --- a/uv.lock +++ b/uv.lock @@ -1,108 +1,94 @@ version = 1 -revision = 1 +revision = 3 requires-python = ">=3.12, <4.0" [[package]] name = "alabaster" version = "0.7.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776, upload-time = "2024-01-10T00:56:10.189Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511 }, + { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511, upload-time = "2024-01-10T00:56:08.388Z" }, ] [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] [[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 } +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 }, + { 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 = "certifi" version = "2025.1.31" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577, upload-time = "2025-01-31T02:16:47.166Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, + { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393, upload-time = "2025-01-31T02:16:45.015Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, - { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, - { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, - { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, - { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, - { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, - { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, - { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, - { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, - { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, - { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, - { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, - { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, - { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, - { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, - { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, - { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, - { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, - { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, - { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, - { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, - { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, - { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, - { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, - { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, - { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, - { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, +sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188, upload-time = "2024-12-24T18:12:35.43Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105, upload-time = "2024-12-24T18:10:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404, upload-time = "2024-12-24T18:10:44.272Z" }, + { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423, upload-time = "2024-12-24T18:10:45.492Z" }, + { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184, upload-time = "2024-12-24T18:10:47.898Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268, upload-time = "2024-12-24T18:10:50.589Z" }, + { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601, upload-time = "2024-12-24T18:10:52.541Z" }, + { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098, upload-time = "2024-12-24T18:10:53.789Z" }, + { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520, upload-time = "2024-12-24T18:10:55.048Z" }, + { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852, upload-time = "2024-12-24T18:10:57.647Z" }, + { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488, upload-time = "2024-12-24T18:10:59.43Z" }, + { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192, upload-time = "2024-12-24T18:11:00.676Z" }, + { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550, upload-time = "2024-12-24T18:11:01.952Z" }, + { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785, upload-time = "2024-12-24T18:11:03.142Z" }, + { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698, upload-time = "2024-12-24T18:11:05.834Z" }, + { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162, upload-time = "2024-12-24T18:11:07.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263, upload-time = "2024-12-24T18:11:08.374Z" }, + { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966, upload-time = "2024-12-24T18:11:09.831Z" }, + { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992, upload-time = "2024-12-24T18:11:12.03Z" }, + { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162, upload-time = "2024-12-24T18:11:13.372Z" }, + { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972, upload-time = "2024-12-24T18:11:14.628Z" }, + { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095, upload-time = "2024-12-24T18:11:17.672Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668, upload-time = "2024-12-24T18:11:18.989Z" }, + { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073, upload-time = "2024-12-24T18:11:21.507Z" }, + { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732, upload-time = "2024-12-24T18:11:22.774Z" }, + { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391, upload-time = "2024-12-24T18:11:24.139Z" }, + { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702, upload-time = "2024-12-24T18:11:26.535Z" }, + { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767, upload-time = "2024-12-24T18:12:32.852Z" }, ] [[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 } +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 }, -] - -[[package]] -name = "consys4py" -version = "0.0.1b3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "paho-mqtt" }, - { name = "pydantic" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/26/5185fdf57b9ade4f5b2df9141ed01b938986bd1b8155c534536bd665c6d1/consys4py-0.0.1b3.tar.gz", hash = "sha256:10b8a8a3e3644e811af10b21052d7fa7172fd07b80c8fa60755d0c6ff3d8f816", size = 27114 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/ee/27dd55fc1068a89707a4f8205393c8c3424a77e170d7cde42319742e790b/consys4py-0.0.1b3-py3-none-any.whl", hash = "sha256:968cdd83386f64184dda6b3cd478e5b68ae4e77581901393e83a1df83922dcc5", size = 31383 }, + { 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 = "docutils" version = "0.20.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/53/a5da4f2c5739cf66290fac1431ee52aff6851c7c8ffd8264f13affd7bcdd/docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b", size = 2058365 } +sdist = { url = "https://files.pythonhosted.org/packages/1f/53/a5da4f2c5739cf66290fac1431ee52aff6851c7c8ffd8264f13affd7bcdd/docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b", size = 2058365, upload-time = "2023-05-16T23:39:19.748Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/87/f238c0670b94533ac0353a4e2a1a771a0cc73277b88bff23d3ae35a256c1/docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", size = 572666 }, + { url = "https://files.pythonhosted.org/packages/26/87/f238c0670b94533ac0353a4e2a1a771a0cc73277b88bff23d3ae35a256c1/docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", size = 572666, upload-time = "2023-05-16T23:39:15.976Z" }, ] [[package]] @@ -114,36 +100,36 @@ dependencies = [ { name = "pycodestyle" }, { name = "pyflakes" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/c4/5842fc9fc94584c455543540af62fd9900faade32511fab650e9891ec225/flake8-7.2.0.tar.gz", hash = "sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426", size = 48177 } +sdist = { url = "https://files.pythonhosted.org/packages/e7/c4/5842fc9fc94584c455543540af62fd9900faade32511fab650e9891ec225/flake8-7.2.0.tar.gz", hash = "sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426", size = 48177, upload-time = "2025-03-29T20:08:39.329Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/5c/0627be4c9976d56b1217cb5187b7504e7fd7d3503f8bfd312a04077bd4f7/flake8-7.2.0-py2.py3-none-any.whl", hash = "sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343", size = 57786 }, + { url = "https://files.pythonhosted.org/packages/83/5c/0627be4c9976d56b1217cb5187b7504e7fd7d3503f8bfd312a04077bd4f7/flake8-7.2.0-py2.py3-none-any.whl", hash = "sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343", size = 57786, upload-time = "2025-03-29T20:08:37.902Z" }, ] [[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 } +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 }, + { 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 = "imagesize" version = "1.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026, upload-time = "2022-07-01T12:21:05.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, ] [[package]] name = "iniconfig" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] [[package]] @@ -153,94 +139,94 @@ 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 } +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 }, + { 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 = "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 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { 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 }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +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/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { 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 = "mccabe" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658 } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350 }, + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, ] [[package]] name = "numpy" version = "2.2.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/78/31103410a57bc2c2b93a3597340a8119588571f6a4539067546cb9a0bfac/numpy-2.2.4.tar.gz", hash = "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", size = 20270701 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/30/182db21d4f2a95904cec1a6f779479ea1ac07c0647f064dea454ec650c42/numpy-2.2.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", size = 20947156 }, - { url = "https://files.pythonhosted.org/packages/24/6d/9483566acfbda6c62c6bc74b6e981c777229d2af93c8eb2469b26ac1b7bc/numpy-2.2.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", size = 14133092 }, - { url = "https://files.pythonhosted.org/packages/27/f6/dba8a258acbf9d2bed2525cdcbb9493ef9bae5199d7a9cb92ee7e9b2aea6/numpy-2.2.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", size = 5163515 }, - { url = "https://files.pythonhosted.org/packages/62/30/82116199d1c249446723c68f2c9da40d7f062551036f50b8c4caa42ae252/numpy-2.2.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", size = 6696558 }, - { url = "https://files.pythonhosted.org/packages/0e/b2/54122b3c6df5df3e87582b2e9430f1bdb63af4023c739ba300164c9ae503/numpy-2.2.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", size = 14084742 }, - { url = "https://files.pythonhosted.org/packages/02/e2/e2cbb8d634151aab9528ef7b8bab52ee4ab10e076509285602c2a3a686e0/numpy-2.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", size = 16134051 }, - { url = "https://files.pythonhosted.org/packages/8e/21/efd47800e4affc993e8be50c1b768de038363dd88865920439ef7b422c60/numpy-2.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", size = 15578972 }, - { url = "https://files.pythonhosted.org/packages/04/1e/f8bb88f6157045dd5d9b27ccf433d016981032690969aa5c19e332b138c0/numpy-2.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", size = 17898106 }, - { url = "https://files.pythonhosted.org/packages/2b/93/df59a5a3897c1f036ae8ff845e45f4081bb06943039ae28a3c1c7c780f22/numpy-2.2.4-cp312-cp312-win32.whl", hash = "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", size = 6311190 }, - { url = "https://files.pythonhosted.org/packages/46/69/8c4f928741c2a8efa255fdc7e9097527c6dc4e4df147e3cadc5d9357ce85/numpy-2.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", size = 12644305 }, - { url = "https://files.pythonhosted.org/packages/2a/d0/bd5ad792e78017f5decfb2ecc947422a3669a34f775679a76317af671ffc/numpy-2.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", size = 20933623 }, - { url = "https://files.pythonhosted.org/packages/c3/bc/2b3545766337b95409868f8e62053135bdc7fa2ce630aba983a2aa60b559/numpy-2.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", size = 14148681 }, - { url = "https://files.pythonhosted.org/packages/6a/70/67b24d68a56551d43a6ec9fe8c5f91b526d4c1a46a6387b956bf2d64744e/numpy-2.2.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", size = 5148759 }, - { url = "https://files.pythonhosted.org/packages/1c/8b/e2fc8a75fcb7be12d90b31477c9356c0cbb44abce7ffb36be39a0017afad/numpy-2.2.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", size = 6683092 }, - { url = "https://files.pythonhosted.org/packages/13/73/41b7b27f169ecf368b52533edb72e56a133f9e86256e809e169362553b49/numpy-2.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", size = 14081422 }, - { url = "https://files.pythonhosted.org/packages/4b/04/e208ff3ae3ddfbafc05910f89546382f15a3f10186b1f56bd99f159689c2/numpy-2.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", size = 16132202 }, - { url = "https://files.pythonhosted.org/packages/fe/bc/2218160574d862d5e55f803d88ddcad88beff94791f9c5f86d67bd8fbf1c/numpy-2.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", size = 15573131 }, - { url = "https://files.pythonhosted.org/packages/a5/78/97c775bc4f05abc8a8426436b7cb1be806a02a2994b195945600855e3a25/numpy-2.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", size = 17894270 }, - { url = "https://files.pythonhosted.org/packages/b9/eb/38c06217a5f6de27dcb41524ca95a44e395e6a1decdc0c99fec0832ce6ae/numpy-2.2.4-cp313-cp313-win32.whl", hash = "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", size = 6308141 }, - { url = "https://files.pythonhosted.org/packages/52/17/d0dd10ab6d125c6d11ffb6dfa3423c3571befab8358d4f85cd4471964fcd/numpy-2.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", size = 12636885 }, - { url = "https://files.pythonhosted.org/packages/fa/e2/793288ede17a0fdc921172916efb40f3cbc2aa97e76c5c84aba6dc7e8747/numpy-2.2.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", size = 20961829 }, - { url = "https://files.pythonhosted.org/packages/3a/75/bb4573f6c462afd1ea5cbedcc362fe3e9bdbcc57aefd37c681be1155fbaa/numpy-2.2.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", size = 14161419 }, - { url = "https://files.pythonhosted.org/packages/03/68/07b4cd01090ca46c7a336958b413cdbe75002286295f2addea767b7f16c9/numpy-2.2.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", size = 5196414 }, - { url = "https://files.pythonhosted.org/packages/a5/fd/d4a29478d622fedff5c4b4b4cedfc37a00691079623c0575978d2446db9e/numpy-2.2.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", size = 6709379 }, - { url = "https://files.pythonhosted.org/packages/41/78/96dddb75bb9be730b87c72f30ffdd62611aba234e4e460576a068c98eff6/numpy-2.2.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", size = 14051725 }, - { url = "https://files.pythonhosted.org/packages/00/06/5306b8199bffac2a29d9119c11f457f6c7d41115a335b78d3f86fad4dbe8/numpy-2.2.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", size = 16101638 }, - { url = "https://files.pythonhosted.org/packages/fa/03/74c5b631ee1ded596945c12027649e6344614144369fd3ec1aaced782882/numpy-2.2.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", size = 15571717 }, - { url = "https://files.pythonhosted.org/packages/cb/dc/4fc7c0283abe0981e3b89f9b332a134e237dd476b0c018e1e21083310c31/numpy-2.2.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", size = 17879998 }, - { url = "https://files.pythonhosted.org/packages/e5/2b/878576190c5cfa29ed896b518cc516aecc7c98a919e20706c12480465f43/numpy-2.2.4-cp313-cp313t-win32.whl", hash = "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", size = 6366896 }, - { url = "https://files.pythonhosted.org/packages/3e/05/eb7eec66b95cf697f08c754ef26c3549d03ebd682819f794cb039574a0a6/numpy-2.2.4-cp313-cp313t-win_amd64.whl", hash = "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", size = 12739119 }, +sdist = { url = "https://files.pythonhosted.org/packages/e1/78/31103410a57bc2c2b93a3597340a8119588571f6a4539067546cb9a0bfac/numpy-2.2.4.tar.gz", hash = "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", size = 20270701, upload-time = "2025-03-16T18:27:00.648Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/30/182db21d4f2a95904cec1a6f779479ea1ac07c0647f064dea454ec650c42/numpy-2.2.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", size = 20947156, upload-time = "2025-03-16T18:09:51.975Z" }, + { url = "https://files.pythonhosted.org/packages/24/6d/9483566acfbda6c62c6bc74b6e981c777229d2af93c8eb2469b26ac1b7bc/numpy-2.2.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", size = 14133092, upload-time = "2025-03-16T18:10:16.329Z" }, + { url = "https://files.pythonhosted.org/packages/27/f6/dba8a258acbf9d2bed2525cdcbb9493ef9bae5199d7a9cb92ee7e9b2aea6/numpy-2.2.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", size = 5163515, upload-time = "2025-03-16T18:10:26.19Z" }, + { url = "https://files.pythonhosted.org/packages/62/30/82116199d1c249446723c68f2c9da40d7f062551036f50b8c4caa42ae252/numpy-2.2.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", size = 6696558, upload-time = "2025-03-16T18:10:38.996Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b2/54122b3c6df5df3e87582b2e9430f1bdb63af4023c739ba300164c9ae503/numpy-2.2.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", size = 14084742, upload-time = "2025-03-16T18:11:02.76Z" }, + { url = "https://files.pythonhosted.org/packages/02/e2/e2cbb8d634151aab9528ef7b8bab52ee4ab10e076509285602c2a3a686e0/numpy-2.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", size = 16134051, upload-time = "2025-03-16T18:11:32.767Z" }, + { url = "https://files.pythonhosted.org/packages/8e/21/efd47800e4affc993e8be50c1b768de038363dd88865920439ef7b422c60/numpy-2.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", size = 15578972, upload-time = "2025-03-16T18:11:59.877Z" }, + { url = "https://files.pythonhosted.org/packages/04/1e/f8bb88f6157045dd5d9b27ccf433d016981032690969aa5c19e332b138c0/numpy-2.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", size = 17898106, upload-time = "2025-03-16T18:12:31.487Z" }, + { url = "https://files.pythonhosted.org/packages/2b/93/df59a5a3897c1f036ae8ff845e45f4081bb06943039ae28a3c1c7c780f22/numpy-2.2.4-cp312-cp312-win32.whl", hash = "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", size = 6311190, upload-time = "2025-03-16T18:12:44.46Z" }, + { url = "https://files.pythonhosted.org/packages/46/69/8c4f928741c2a8efa255fdc7e9097527c6dc4e4df147e3cadc5d9357ce85/numpy-2.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", size = 12644305, upload-time = "2025-03-16T18:13:06.864Z" }, + { url = "https://files.pythonhosted.org/packages/2a/d0/bd5ad792e78017f5decfb2ecc947422a3669a34f775679a76317af671ffc/numpy-2.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", size = 20933623, upload-time = "2025-03-16T18:13:43.231Z" }, + { url = "https://files.pythonhosted.org/packages/c3/bc/2b3545766337b95409868f8e62053135bdc7fa2ce630aba983a2aa60b559/numpy-2.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", size = 14148681, upload-time = "2025-03-16T18:14:08.031Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/67b24d68a56551d43a6ec9fe8c5f91b526d4c1a46a6387b956bf2d64744e/numpy-2.2.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", size = 5148759, upload-time = "2025-03-16T18:14:18.613Z" }, + { url = "https://files.pythonhosted.org/packages/1c/8b/e2fc8a75fcb7be12d90b31477c9356c0cbb44abce7ffb36be39a0017afad/numpy-2.2.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", size = 6683092, upload-time = "2025-03-16T18:14:31.386Z" }, + { url = "https://files.pythonhosted.org/packages/13/73/41b7b27f169ecf368b52533edb72e56a133f9e86256e809e169362553b49/numpy-2.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", size = 14081422, upload-time = "2025-03-16T18:14:54.83Z" }, + { url = "https://files.pythonhosted.org/packages/4b/04/e208ff3ae3ddfbafc05910f89546382f15a3f10186b1f56bd99f159689c2/numpy-2.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", size = 16132202, upload-time = "2025-03-16T18:15:22.035Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bc/2218160574d862d5e55f803d88ddcad88beff94791f9c5f86d67bd8fbf1c/numpy-2.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", size = 15573131, upload-time = "2025-03-16T18:15:48.546Z" }, + { url = "https://files.pythonhosted.org/packages/a5/78/97c775bc4f05abc8a8426436b7cb1be806a02a2994b195945600855e3a25/numpy-2.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", size = 17894270, upload-time = "2025-03-16T18:16:20.274Z" }, + { url = "https://files.pythonhosted.org/packages/b9/eb/38c06217a5f6de27dcb41524ca95a44e395e6a1decdc0c99fec0832ce6ae/numpy-2.2.4-cp313-cp313-win32.whl", hash = "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", size = 6308141, upload-time = "2025-03-16T18:20:15.297Z" }, + { url = "https://files.pythonhosted.org/packages/52/17/d0dd10ab6d125c6d11ffb6dfa3423c3571befab8358d4f85cd4471964fcd/numpy-2.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", size = 12636885, upload-time = "2025-03-16T18:20:36.982Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e2/793288ede17a0fdc921172916efb40f3cbc2aa97e76c5c84aba6dc7e8747/numpy-2.2.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", size = 20961829, upload-time = "2025-03-16T18:16:56.191Z" }, + { url = "https://files.pythonhosted.org/packages/3a/75/bb4573f6c462afd1ea5cbedcc362fe3e9bdbcc57aefd37c681be1155fbaa/numpy-2.2.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", size = 14161419, upload-time = "2025-03-16T18:17:22.811Z" }, + { url = "https://files.pythonhosted.org/packages/03/68/07b4cd01090ca46c7a336958b413cdbe75002286295f2addea767b7f16c9/numpy-2.2.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", size = 5196414, upload-time = "2025-03-16T18:17:34.066Z" }, + { url = "https://files.pythonhosted.org/packages/a5/fd/d4a29478d622fedff5c4b4b4cedfc37a00691079623c0575978d2446db9e/numpy-2.2.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", size = 6709379, upload-time = "2025-03-16T18:17:47.466Z" }, + { url = "https://files.pythonhosted.org/packages/41/78/96dddb75bb9be730b87c72f30ffdd62611aba234e4e460576a068c98eff6/numpy-2.2.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", size = 14051725, upload-time = "2025-03-16T18:18:11.904Z" }, + { url = "https://files.pythonhosted.org/packages/00/06/5306b8199bffac2a29d9119c11f457f6c7d41115a335b78d3f86fad4dbe8/numpy-2.2.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", size = 16101638, upload-time = "2025-03-16T18:18:40.749Z" }, + { url = "https://files.pythonhosted.org/packages/fa/03/74c5b631ee1ded596945c12027649e6344614144369fd3ec1aaced782882/numpy-2.2.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", size = 15571717, upload-time = "2025-03-16T18:19:04.512Z" }, + { url = "https://files.pythonhosted.org/packages/cb/dc/4fc7c0283abe0981e3b89f9b332a134e237dd476b0c018e1e21083310c31/numpy-2.2.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", size = 17879998, upload-time = "2025-03-16T18:19:32.52Z" }, + { url = "https://files.pythonhosted.org/packages/e5/2b/878576190c5cfa29ed896b518cc516aecc7c98a919e20706c12480465f43/numpy-2.2.4-cp313-cp313t-win32.whl", hash = "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", size = 6366896, upload-time = "2025-03-16T18:19:43.55Z" }, + { url = "https://files.pythonhosted.org/packages/3e/05/eb7eec66b95cf697f08c754ef26c3549d03ebd682819f794cb039574a0a6/numpy-2.2.4-cp313-cp313t-win_amd64.whl", hash = "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", size = 12739119, upload-time = "2025-03-16T18:20:03.94Z" }, ] [[package]] @@ -248,10 +234,9 @@ name = "oshconnect" version = "0.2.4.post1" source = { virtual = "." } dependencies = [ - { name = "consys4py" }, + { name = "paho-mqtt" }, { name = "pydantic" }, { name = "shapely" }, - { name = "swecommondm" }, { name = "websockets" }, ] @@ -265,10 +250,9 @@ dev = [ [package.metadata] requires-dist = [ - { name = "consys4py", specifier = ">=0.0.1b3,<1.0.0" }, + { name = "paho-mqtt", specifier = ">=2.1.0" }, { name = "pydantic", specifier = ">=2.7.4,<3.0.0" }, { name = "shapely", specifier = ">=2.0.4,<3.0.0" }, - { name = "swecommondm", specifier = ">=0.0.1a0,<1.0.0" }, { name = "websockets", specifier = ">=12.0,<13.0" }, ] @@ -284,36 +268,36 @@ dev = [ name = "packaging" version = "24.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950, upload-time = "2024-11-08T09:47:47.202Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451, upload-time = "2024-11-08T09:47:44.722Z" }, ] [[package]] name = "paho-mqtt" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/39/15/0a6214e76d4d32e7f663b109cf71fb22561c2be0f701d67f93950cd40542/paho_mqtt-2.1.0.tar.gz", hash = "sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834", size = 148848 } +sdist = { url = "https://files.pythonhosted.org/packages/39/15/0a6214e76d4d32e7f663b109cf71fb22561c2be0f701d67f93950cd40542/paho_mqtt-2.1.0.tar.gz", hash = "sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834", size = 148848, upload-time = "2024-04-29T19:52:55.591Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/cb/00451c3cf31790287768bb12c6bec834f5d292eaf3022afc88e14b8afc94/paho_mqtt-2.1.0-py3-none-any.whl", hash = "sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee", size = 67219 }, + { url = "https://files.pythonhosted.org/packages/c4/cb/00451c3cf31790287768bb12c6bec834f5d292eaf3022afc88e14b8afc94/paho_mqtt-2.1.0-py3-none-any.whl", hash = "sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee", size = 67219, upload-time = "2024-04-29T19:52:48.345Z" }, ] [[package]] name = "pluggy" version = "1.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, ] [[package]] name = "pycodestyle" version = "2.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/6e/1f4a62078e4d95d82367f24e685aef3a672abfd27d1a868068fed4ed2254/pycodestyle-2.13.0.tar.gz", hash = "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae", size = 39312 } +sdist = { url = "https://files.pythonhosted.org/packages/04/6e/1f4a62078e4d95d82367f24e685aef3a672abfd27d1a868068fed4ed2254/pycodestyle-2.13.0.tar.gz", hash = "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae", size = 39312, upload-time = "2025-03-29T17:33:30.669Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/be/b00116df1bfb3e0bb5b45e29d604799f7b91dd861637e4d448b4e09e6a3e/pycodestyle-2.13.0-py2.py3-none-any.whl", hash = "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9", size = 31424 }, + { url = "https://files.pythonhosted.org/packages/07/be/b00116df1bfb3e0bb5b45e29d604799f7b91dd861637e4d448b4e09e6a3e/pycodestyle-2.13.0-py2.py3-none-any.whl", hash = "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9", size = 31424, upload-time = "2025-03-29T17:33:29.405Z" }, ] [[package]] @@ -326,9 +310,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/10/2e/ca897f093ee6c5f3b0bee123ee4465c50e75431c3d5b6a3b44a47134e891/pydantic-2.11.3.tar.gz", hash = "sha256:7471657138c16adad9322fe3070c0116dd6c3ad8d649300e3cbdfe91f4db4ec3", size = 785513 } +sdist = { url = "https://files.pythonhosted.org/packages/10/2e/ca897f093ee6c5f3b0bee123ee4465c50e75431c3d5b6a3b44a47134e891/pydantic-2.11.3.tar.gz", hash = "sha256:7471657138c16adad9322fe3070c0116dd6c3ad8d649300e3cbdfe91f4db4ec3", size = 785513, upload-time = "2025-04-08T13:27:06.399Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/1d/407b29780a289868ed696d1616f4aad49d6388e5a77f567dcd2629dcd7b8/pydantic-2.11.3-py3-none-any.whl", hash = "sha256:a082753436a07f9ba1289c6ffa01cd93db3548776088aa917cc43b63f68fa60f", size = 443591 }, + { url = "https://files.pythonhosted.org/packages/b0/1d/407b29780a289868ed696d1616f4aad49d6388e5a77f567dcd2629dcd7b8/pydantic-2.11.3-py3-none-any.whl", hash = "sha256:a082753436a07f9ba1289c6ffa01cd93db3548776088aa917cc43b63f68fa60f", size = 443591, upload-time = "2025-04-08T13:27:03.789Z" }, ] [[package]] @@ -338,57 +322,57 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/19/ed6a078a5287aea7922de6841ef4c06157931622c89c2a47940837b5eecd/pydantic_core-2.33.1.tar.gz", hash = "sha256:bcc9c6fdb0ced789245b02b7d6603e17d1563064ddcfc36f046b61c0c05dd9df", size = 434395 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/ce/3cb22b07c29938f97ff5f5bb27521f95e2ebec399b882392deb68d6c440e/pydantic_core-2.33.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1293d7febb995e9d3ec3ea09caf1a26214eec45b0f29f6074abb004723fc1de8", size = 2026640 }, - { url = "https://files.pythonhosted.org/packages/19/78/f381d643b12378fee782a72126ec5d793081ef03791c28a0fd542a5bee64/pydantic_core-2.33.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99b56acd433386c8f20be5c4000786d1e7ca0523c8eefc995d14d79c7a081498", size = 1852649 }, - { url = "https://files.pythonhosted.org/packages/9d/2b/98a37b80b15aac9eb2c6cfc6dbd35e5058a352891c5cce3a8472d77665a6/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35a5ec3fa8c2fe6c53e1b2ccc2454398f95d5393ab398478f53e1afbbeb4d939", size = 1892472 }, - { url = "https://files.pythonhosted.org/packages/4e/d4/3c59514e0f55a161004792b9ff3039da52448f43f5834f905abef9db6e4a/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b172f7b9d2f3abc0efd12e3386f7e48b576ef309544ac3a63e5e9cdd2e24585d", size = 1977509 }, - { url = "https://files.pythonhosted.org/packages/a9/b6/c2c7946ef70576f79a25db59a576bce088bdc5952d1b93c9789b091df716/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9097b9f17f91eea659b9ec58148c0747ec354a42f7389b9d50701610d86f812e", size = 2128702 }, - { url = "https://files.pythonhosted.org/packages/88/fe/65a880f81e3f2a974312b61f82a03d85528f89a010ce21ad92f109d94deb/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc77ec5b7e2118b152b0d886c7514a4653bcb58c6b1d760134a9fab915f777b3", size = 2679428 }, - { url = "https://files.pythonhosted.org/packages/6f/ff/4459e4146afd0462fb483bb98aa2436d69c484737feaceba1341615fb0ac/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3d15245b08fa4a84cefc6c9222e6f37c98111c8679fbd94aa145f9a0ae23d", size = 2008753 }, - { url = "https://files.pythonhosted.org/packages/7c/76/1c42e384e8d78452ededac8b583fe2550c84abfef83a0552e0e7478ccbc3/pydantic_core-2.33.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef99779001d7ac2e2461d8ab55d3373fe7315caefdbecd8ced75304ae5a6fc6b", size = 2114849 }, - { url = "https://files.pythonhosted.org/packages/00/72/7d0cf05095c15f7ffe0eb78914b166d591c0eed72f294da68378da205101/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fc6bf8869e193855e8d91d91f6bf59699a5cdfaa47a404e278e776dd7f168b39", size = 2069541 }, - { url = "https://files.pythonhosted.org/packages/b3/69/94a514066bb7d8be499aa764926937409d2389c09be0b5107a970286ef81/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:b1caa0bc2741b043db7823843e1bde8aaa58a55a58fda06083b0569f8b45693a", size = 2239225 }, - { url = "https://files.pythonhosted.org/packages/84/b0/e390071eadb44b41f4f54c3cef64d8bf5f9612c92686c9299eaa09e267e2/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ec259f62538e8bf364903a7d0d0239447059f9434b284f5536e8402b7dd198db", size = 2248373 }, - { url = "https://files.pythonhosted.org/packages/d6/b2/288b3579ffc07e92af66e2f1a11be3b056fe1214aab314748461f21a31c3/pydantic_core-2.33.1-cp312-cp312-win32.whl", hash = "sha256:e14f369c98a7c15772b9da98987f58e2b509a93235582838bd0d1d8c08b68fda", size = 1907034 }, - { url = "https://files.pythonhosted.org/packages/02/28/58442ad1c22b5b6742b992ba9518420235adced665513868f99a1c2638a5/pydantic_core-2.33.1-cp312-cp312-win_amd64.whl", hash = "sha256:1c607801d85e2e123357b3893f82c97a42856192997b95b4d8325deb1cd0c5f4", size = 1956848 }, - { url = "https://files.pythonhosted.org/packages/a1/eb/f54809b51c7e2a1d9f439f158b8dd94359321abcc98767e16fc48ae5a77e/pydantic_core-2.33.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d13f0276806ee722e70a1c93da19748594f19ac4299c7e41237fc791d1861ea", size = 1903986 }, - { url = "https://files.pythonhosted.org/packages/7a/24/eed3466a4308d79155f1cdd5c7432c80ddcc4530ba8623b79d5ced021641/pydantic_core-2.33.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:70af6a21237b53d1fe7b9325b20e65cbf2f0a848cf77bed492b029139701e66a", size = 2033551 }, - { url = "https://files.pythonhosted.org/packages/ab/14/df54b1a0bc9b6ded9b758b73139d2c11b4e8eb43e8ab9c5847c0a2913ada/pydantic_core-2.33.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:282b3fe1bbbe5ae35224a0dbd05aed9ccabccd241e8e6b60370484234b456266", size = 1852785 }, - { url = "https://files.pythonhosted.org/packages/fa/96/e275f15ff3d34bb04b0125d9bc8848bf69f25d784d92a63676112451bfb9/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b315e596282bbb5822d0c7ee9d255595bd7506d1cb20c2911a4da0b970187d3", size = 1897758 }, - { url = "https://files.pythonhosted.org/packages/b7/d8/96bc536e975b69e3a924b507d2a19aedbf50b24e08c80fb00e35f9baaed8/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dfae24cf9921875ca0ca6a8ecb4bb2f13c855794ed0d468d6abbec6e6dcd44a", size = 1986109 }, - { url = "https://files.pythonhosted.org/packages/90/72/ab58e43ce7e900b88cb571ed057b2fcd0e95b708a2e0bed475b10130393e/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dd8ecfde08d8bfadaea669e83c63939af76f4cf5538a72597016edfa3fad516", size = 2129159 }, - { url = "https://files.pythonhosted.org/packages/dc/3f/52d85781406886c6870ac995ec0ba7ccc028b530b0798c9080531b409fdb/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f593494876eae852dc98c43c6f260f45abdbfeec9e4324e31a481d948214764", size = 2680222 }, - { url = "https://files.pythonhosted.org/packages/f4/56/6e2ef42f363a0eec0fd92f74a91e0ac48cd2e49b695aac1509ad81eee86a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:948b73114f47fd7016088e5186d13faf5e1b2fe83f5e320e371f035557fd264d", size = 2006980 }, - { url = "https://files.pythonhosted.org/packages/4c/c0/604536c4379cc78359f9ee0aa319f4aedf6b652ec2854953f5a14fc38c5a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e11f3864eb516af21b01e25fac915a82e9ddad3bb0fb9e95a246067398b435a4", size = 2120840 }, - { url = "https://files.pythonhosted.org/packages/1f/46/9eb764814f508f0edfb291a0f75d10854d78113fa13900ce13729aaec3ae/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:549150be302428b56fdad0c23c2741dcdb5572413776826c965619a25d9c6bde", size = 2072518 }, - { url = "https://files.pythonhosted.org/packages/42/e3/fb6b2a732b82d1666fa6bf53e3627867ea3131c5f39f98ce92141e3e3dc1/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:495bc156026efafd9ef2d82372bd38afce78ddd82bf28ef5276c469e57c0c83e", size = 2248025 }, - { url = "https://files.pythonhosted.org/packages/5c/9d/fbe8fe9d1aa4dac88723f10a921bc7418bd3378a567cb5e21193a3c48b43/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ec79de2a8680b1a67a07490bddf9636d5c2fab609ba8c57597e855fa5fa4dacd", size = 2254991 }, - { url = "https://files.pythonhosted.org/packages/aa/99/07e2237b8a66438d9b26482332cda99a9acccb58d284af7bc7c946a42fd3/pydantic_core-2.33.1-cp313-cp313-win32.whl", hash = "sha256:ee12a7be1742f81b8a65b36c6921022301d466b82d80315d215c4c691724986f", size = 1915262 }, - { url = "https://files.pythonhosted.org/packages/8a/f4/e457a7849beeed1e5defbcf5051c6f7b3c91a0624dd31543a64fc9adcf52/pydantic_core-2.33.1-cp313-cp313-win_amd64.whl", hash = "sha256:ede9b407e39949d2afc46385ce6bd6e11588660c26f80576c11c958e6647bc40", size = 1956626 }, - { url = "https://files.pythonhosted.org/packages/20/d0/e8d567a7cff7b04e017ae164d98011f1e1894269fe8e90ea187a3cbfb562/pydantic_core-2.33.1-cp313-cp313-win_arm64.whl", hash = "sha256:aa687a23d4b7871a00e03ca96a09cad0f28f443690d300500603bd0adba4b523", size = 1909590 }, - { url = "https://files.pythonhosted.org/packages/ef/fd/24ea4302d7a527d672c5be06e17df16aabfb4e9fdc6e0b345c21580f3d2a/pydantic_core-2.33.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:401d7b76e1000d0dd5538e6381d28febdcacb097c8d340dde7d7fc6e13e9f95d", size = 1812963 }, - { url = "https://files.pythonhosted.org/packages/5f/95/4fbc2ecdeb5c1c53f1175a32d870250194eb2fdf6291b795ab08c8646d5d/pydantic_core-2.33.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aeb055a42d734c0255c9e489ac67e75397d59c6fbe60d155851e9782f276a9c", size = 1986896 }, - { url = "https://files.pythonhosted.org/packages/71/ae/fe31e7f4a62431222d8f65a3bd02e3fa7e6026d154a00818e6d30520ea77/pydantic_core-2.33.1-cp313-cp313t-win_amd64.whl", hash = "sha256:338ea9b73e6e109f15ab439e62cb3b78aa752c7fd9536794112e14bee02c8d18", size = 1931810 }, +sdist = { url = "https://files.pythonhosted.org/packages/17/19/ed6a078a5287aea7922de6841ef4c06157931622c89c2a47940837b5eecd/pydantic_core-2.33.1.tar.gz", hash = "sha256:bcc9c6fdb0ced789245b02b7d6603e17d1563064ddcfc36f046b61c0c05dd9df", size = 434395, upload-time = "2025-04-02T09:49:41.8Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/ce/3cb22b07c29938f97ff5f5bb27521f95e2ebec399b882392deb68d6c440e/pydantic_core-2.33.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1293d7febb995e9d3ec3ea09caf1a26214eec45b0f29f6074abb004723fc1de8", size = 2026640, upload-time = "2025-04-02T09:47:25.394Z" }, + { url = "https://files.pythonhosted.org/packages/19/78/f381d643b12378fee782a72126ec5d793081ef03791c28a0fd542a5bee64/pydantic_core-2.33.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99b56acd433386c8f20be5c4000786d1e7ca0523c8eefc995d14d79c7a081498", size = 1852649, upload-time = "2025-04-02T09:47:27.417Z" }, + { url = "https://files.pythonhosted.org/packages/9d/2b/98a37b80b15aac9eb2c6cfc6dbd35e5058a352891c5cce3a8472d77665a6/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35a5ec3fa8c2fe6c53e1b2ccc2454398f95d5393ab398478f53e1afbbeb4d939", size = 1892472, upload-time = "2025-04-02T09:47:29.006Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d4/3c59514e0f55a161004792b9ff3039da52448f43f5834f905abef9db6e4a/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b172f7b9d2f3abc0efd12e3386f7e48b576ef309544ac3a63e5e9cdd2e24585d", size = 1977509, upload-time = "2025-04-02T09:47:33.464Z" }, + { url = "https://files.pythonhosted.org/packages/a9/b6/c2c7946ef70576f79a25db59a576bce088bdc5952d1b93c9789b091df716/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9097b9f17f91eea659b9ec58148c0747ec354a42f7389b9d50701610d86f812e", size = 2128702, upload-time = "2025-04-02T09:47:34.812Z" }, + { url = "https://files.pythonhosted.org/packages/88/fe/65a880f81e3f2a974312b61f82a03d85528f89a010ce21ad92f109d94deb/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc77ec5b7e2118b152b0d886c7514a4653bcb58c6b1d760134a9fab915f777b3", size = 2679428, upload-time = "2025-04-02T09:47:37.315Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ff/4459e4146afd0462fb483bb98aa2436d69c484737feaceba1341615fb0ac/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3d15245b08fa4a84cefc6c9222e6f37c98111c8679fbd94aa145f9a0ae23d", size = 2008753, upload-time = "2025-04-02T09:47:39.013Z" }, + { url = "https://files.pythonhosted.org/packages/7c/76/1c42e384e8d78452ededac8b583fe2550c84abfef83a0552e0e7478ccbc3/pydantic_core-2.33.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef99779001d7ac2e2461d8ab55d3373fe7315caefdbecd8ced75304ae5a6fc6b", size = 2114849, upload-time = "2025-04-02T09:47:40.427Z" }, + { url = "https://files.pythonhosted.org/packages/00/72/7d0cf05095c15f7ffe0eb78914b166d591c0eed72f294da68378da205101/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fc6bf8869e193855e8d91d91f6bf59699a5cdfaa47a404e278e776dd7f168b39", size = 2069541, upload-time = "2025-04-02T09:47:42.01Z" }, + { url = "https://files.pythonhosted.org/packages/b3/69/94a514066bb7d8be499aa764926937409d2389c09be0b5107a970286ef81/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:b1caa0bc2741b043db7823843e1bde8aaa58a55a58fda06083b0569f8b45693a", size = 2239225, upload-time = "2025-04-02T09:47:43.425Z" }, + { url = "https://files.pythonhosted.org/packages/84/b0/e390071eadb44b41f4f54c3cef64d8bf5f9612c92686c9299eaa09e267e2/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ec259f62538e8bf364903a7d0d0239447059f9434b284f5536e8402b7dd198db", size = 2248373, upload-time = "2025-04-02T09:47:44.979Z" }, + { url = "https://files.pythonhosted.org/packages/d6/b2/288b3579ffc07e92af66e2f1a11be3b056fe1214aab314748461f21a31c3/pydantic_core-2.33.1-cp312-cp312-win32.whl", hash = "sha256:e14f369c98a7c15772b9da98987f58e2b509a93235582838bd0d1d8c08b68fda", size = 1907034, upload-time = "2025-04-02T09:47:46.843Z" }, + { url = "https://files.pythonhosted.org/packages/02/28/58442ad1c22b5b6742b992ba9518420235adced665513868f99a1c2638a5/pydantic_core-2.33.1-cp312-cp312-win_amd64.whl", hash = "sha256:1c607801d85e2e123357b3893f82c97a42856192997b95b4d8325deb1cd0c5f4", size = 1956848, upload-time = "2025-04-02T09:47:48.404Z" }, + { url = "https://files.pythonhosted.org/packages/a1/eb/f54809b51c7e2a1d9f439f158b8dd94359321abcc98767e16fc48ae5a77e/pydantic_core-2.33.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d13f0276806ee722e70a1c93da19748594f19ac4299c7e41237fc791d1861ea", size = 1903986, upload-time = "2025-04-02T09:47:49.839Z" }, + { url = "https://files.pythonhosted.org/packages/7a/24/eed3466a4308d79155f1cdd5c7432c80ddcc4530ba8623b79d5ced021641/pydantic_core-2.33.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:70af6a21237b53d1fe7b9325b20e65cbf2f0a848cf77bed492b029139701e66a", size = 2033551, upload-time = "2025-04-02T09:47:51.648Z" }, + { url = "https://files.pythonhosted.org/packages/ab/14/df54b1a0bc9b6ded9b758b73139d2c11b4e8eb43e8ab9c5847c0a2913ada/pydantic_core-2.33.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:282b3fe1bbbe5ae35224a0dbd05aed9ccabccd241e8e6b60370484234b456266", size = 1852785, upload-time = "2025-04-02T09:47:53.149Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/e275f15ff3d34bb04b0125d9bc8848bf69f25d784d92a63676112451bfb9/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b315e596282bbb5822d0c7ee9d255595bd7506d1cb20c2911a4da0b970187d3", size = 1897758, upload-time = "2025-04-02T09:47:55.006Z" }, + { url = "https://files.pythonhosted.org/packages/b7/d8/96bc536e975b69e3a924b507d2a19aedbf50b24e08c80fb00e35f9baaed8/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dfae24cf9921875ca0ca6a8ecb4bb2f13c855794ed0d468d6abbec6e6dcd44a", size = 1986109, upload-time = "2025-04-02T09:47:56.532Z" }, + { url = "https://files.pythonhosted.org/packages/90/72/ab58e43ce7e900b88cb571ed057b2fcd0e95b708a2e0bed475b10130393e/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dd8ecfde08d8bfadaea669e83c63939af76f4cf5538a72597016edfa3fad516", size = 2129159, upload-time = "2025-04-02T09:47:58.088Z" }, + { url = "https://files.pythonhosted.org/packages/dc/3f/52d85781406886c6870ac995ec0ba7ccc028b530b0798c9080531b409fdb/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f593494876eae852dc98c43c6f260f45abdbfeec9e4324e31a481d948214764", size = 2680222, upload-time = "2025-04-02T09:47:59.591Z" }, + { url = "https://files.pythonhosted.org/packages/f4/56/6e2ef42f363a0eec0fd92f74a91e0ac48cd2e49b695aac1509ad81eee86a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:948b73114f47fd7016088e5186d13faf5e1b2fe83f5e320e371f035557fd264d", size = 2006980, upload-time = "2025-04-02T09:48:01.397Z" }, + { url = "https://files.pythonhosted.org/packages/4c/c0/604536c4379cc78359f9ee0aa319f4aedf6b652ec2854953f5a14fc38c5a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e11f3864eb516af21b01e25fac915a82e9ddad3bb0fb9e95a246067398b435a4", size = 2120840, upload-time = "2025-04-02T09:48:03.056Z" }, + { url = "https://files.pythonhosted.org/packages/1f/46/9eb764814f508f0edfb291a0f75d10854d78113fa13900ce13729aaec3ae/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:549150be302428b56fdad0c23c2741dcdb5572413776826c965619a25d9c6bde", size = 2072518, upload-time = "2025-04-02T09:48:04.662Z" }, + { url = "https://files.pythonhosted.org/packages/42/e3/fb6b2a732b82d1666fa6bf53e3627867ea3131c5f39f98ce92141e3e3dc1/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:495bc156026efafd9ef2d82372bd38afce78ddd82bf28ef5276c469e57c0c83e", size = 2248025, upload-time = "2025-04-02T09:48:06.226Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9d/fbe8fe9d1aa4dac88723f10a921bc7418bd3378a567cb5e21193a3c48b43/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ec79de2a8680b1a67a07490bddf9636d5c2fab609ba8c57597e855fa5fa4dacd", size = 2254991, upload-time = "2025-04-02T09:48:08.114Z" }, + { url = "https://files.pythonhosted.org/packages/aa/99/07e2237b8a66438d9b26482332cda99a9acccb58d284af7bc7c946a42fd3/pydantic_core-2.33.1-cp313-cp313-win32.whl", hash = "sha256:ee12a7be1742f81b8a65b36c6921022301d466b82d80315d215c4c691724986f", size = 1915262, upload-time = "2025-04-02T09:48:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f4/e457a7849beeed1e5defbcf5051c6f7b3c91a0624dd31543a64fc9adcf52/pydantic_core-2.33.1-cp313-cp313-win_amd64.whl", hash = "sha256:ede9b407e39949d2afc46385ce6bd6e11588660c26f80576c11c958e6647bc40", size = 1956626, upload-time = "2025-04-02T09:48:11.288Z" }, + { url = "https://files.pythonhosted.org/packages/20/d0/e8d567a7cff7b04e017ae164d98011f1e1894269fe8e90ea187a3cbfb562/pydantic_core-2.33.1-cp313-cp313-win_arm64.whl", hash = "sha256:aa687a23d4b7871a00e03ca96a09cad0f28f443690d300500603bd0adba4b523", size = 1909590, upload-time = "2025-04-02T09:48:12.861Z" }, + { url = "https://files.pythonhosted.org/packages/ef/fd/24ea4302d7a527d672c5be06e17df16aabfb4e9fdc6e0b345c21580f3d2a/pydantic_core-2.33.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:401d7b76e1000d0dd5538e6381d28febdcacb097c8d340dde7d7fc6e13e9f95d", size = 1812963, upload-time = "2025-04-02T09:48:14.553Z" }, + { url = "https://files.pythonhosted.org/packages/5f/95/4fbc2ecdeb5c1c53f1175a32d870250194eb2fdf6291b795ab08c8646d5d/pydantic_core-2.33.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aeb055a42d734c0255c9e489ac67e75397d59c6fbe60d155851e9782f276a9c", size = 1986896, upload-time = "2025-04-02T09:48:16.222Z" }, + { url = "https://files.pythonhosted.org/packages/71/ae/fe31e7f4a62431222d8f65a3bd02e3fa7e6026d154a00818e6d30520ea77/pydantic_core-2.33.1-cp313-cp313t-win_amd64.whl", hash = "sha256:338ea9b73e6e109f15ab439e62cb3b78aa752c7fd9536794112e14bee02c8d18", size = 1931810, upload-time = "2025-04-02T09:48:17.97Z" }, ] [[package]] name = "pyflakes" version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/cc/1df338bd7ed1fa7c317081dcf29bf2f01266603b301e6858856d346a12b3/pyflakes-3.3.2.tar.gz", hash = "sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b", size = 64175 } +sdist = { url = "https://files.pythonhosted.org/packages/af/cc/1df338bd7ed1fa7c317081dcf29bf2f01266603b301e6858856d346a12b3/pyflakes-3.3.2.tar.gz", hash = "sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b", size = 64175, upload-time = "2025-03-31T13:21:20.34Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/15/40/b293a4fa769f3b02ab9e387c707c4cbdc34f073f945de0386107d4e669e6/pyflakes-3.3.2-py2.py3-none-any.whl", hash = "sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a", size = 63164 }, + { url = "https://files.pythonhosted.org/packages/15/40/b293a4fa769f3b02ab9e387c707c4cbdc34f073f945de0386107d4e669e6/pyflakes-3.3.2-py2.py3-none-any.whl", hash = "sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a", size = 63164, upload-time = "2025-03-31T13:21:18.503Z" }, ] [[package]] name = "pygments" version = "2.19.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, ] [[package]] @@ -401,9 +385,9 @@ dependencies = [ { name = "packaging" }, { name = "pluggy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 }, + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, ] [[package]] @@ -416,9 +400,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" }, ] [[package]] @@ -428,41 +412,41 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/fe/3b0d2f828ffaceadcdcb51b75b9c62d98e62dd95ce575278de35f24a1c20/shapely-2.1.0.tar.gz", hash = "sha256:2cbe90e86fa8fc3ca8af6ffb00a77b246b918c7cf28677b7c21489b678f6b02e", size = 313617 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/d1/6a9371ec39d3ef08e13225594e6c55b045209629afd9e6d403204507c2a8/shapely-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53e7ee8bd8609cf12ee6dce01ea5affe676976cf7049315751d53d8db6d2b4b2", size = 1830732 }, - { url = "https://files.pythonhosted.org/packages/32/87/799e3e48be7ce848c08509b94d2180f4ddb02e846e3c62d0af33da4d78d3/shapely-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3cab20b665d26dbec0b380e15749bea720885a481fa7b1eedc88195d4a98cfa4", size = 1638404 }, - { url = "https://files.pythonhosted.org/packages/85/00/6665d77f9dd09478ab0993b8bc31668aec4fd3e5f1ddd1b28dd5830e47be/shapely-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a38b39a09340273c3c92b3b9a374272a12cc7e468aeeea22c1c46217a03e5c", size = 2945316 }, - { url = "https://files.pythonhosted.org/packages/34/49/738e07d10bbc67cae0dcfe5a484c6e518a517f4f90550dda2adf3a78b9f2/shapely-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:edaec656bdd9b71278b98e6f77c464b1c3b2daa9eace78012ff0f0b4b5b15b04", size = 3063099 }, - { url = "https://files.pythonhosted.org/packages/88/b8/138098674559362ab29f152bff3b6630de423378fbb0324812742433a4ef/shapely-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c8a732ddd9b25e7a54aa748e7df8fd704e23e5d5d35b7d376d80bffbfc376d04", size = 3887873 }, - { url = "https://files.pythonhosted.org/packages/67/a8/fdae7c2db009244991d86f4d2ca09d2f5ccc9d41c312c3b1ee1404dc55da/shapely-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9c93693ad8adfdc9138a5a2d42da02da94f728dd2e82d2f0f442f10e25027f5f", size = 4067004 }, - { url = "https://files.pythonhosted.org/packages/ed/78/17e17d91b489019379df3ee1afc4bd39787b232aaa1d540f7d376f0280b7/shapely-2.1.0-cp312-cp312-win32.whl", hash = "sha256:d8ac6604eefe807e71a908524de23a37920133a1729fe3a4dfe0ed82c044cbf4", size = 1527366 }, - { url = "https://files.pythonhosted.org/packages/b8/bd/9249bd6dda948441e25e4fb14cbbb5205146b0fff12c66b19331f1ff2141/shapely-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:f4f47e631aa4f9ec5576eac546eb3f38802e2f82aeb0552f9612cb9a14ece1db", size = 1708265 }, - { url = "https://files.pythonhosted.org/packages/8d/77/4e368704b2193e74498473db4461d697cc6083c96f8039367e59009d78bd/shapely-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b64423295b563f43a043eb786e7a03200ebe68698e36d2b4b1c39f31dfb50dfb", size = 1830029 }, - { url = "https://files.pythonhosted.org/packages/71/3c/d888597bda680e4de987316b05ca9db07416fa29523beff64f846503302f/shapely-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1b5578f45adc25b235b22d1ccb9a0348c8dc36f31983e57ea129a88f96f7b870", size = 1637999 }, - { url = "https://files.pythonhosted.org/packages/03/8d/ee0e23b7ef88fba353c63a81f1f329c77f5703835db7b165e7c0b8b7f839/shapely-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a7e83d383b27f02b684e50ab7f34e511c92e33b6ca164a6a9065705dd64bcb", size = 2929348 }, - { url = "https://files.pythonhosted.org/packages/d1/a7/5c9cb413e4e2ce52c16be717e94abd40ce91b1f8974624d5d56154c5d40b/shapely-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:942031eb4d8f7b3b22f43ba42c09c7aa3d843aa10d5cc1619fe816e923b66e55", size = 3048973 }, - { url = "https://files.pythonhosted.org/packages/84/23/45b90c0bd2157b238490ca56ef2eedf959d3514c7d05475f497a2c88b6d9/shapely-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d2843c456a2e5627ee6271800f07277c0d2652fb287bf66464571a057dbc00b3", size = 3873148 }, - { url = "https://files.pythonhosted.org/packages/c0/bc/ed7d5d37f5395166042576f0c55a12d7e56102799464ba7ea3a72a38c769/shapely-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8c4b17469b7f39a5e6a7cfea79f38ae08a275427f41fe8b48c372e1449147908", size = 4052655 }, - { url = "https://files.pythonhosted.org/packages/c0/8f/a1dafbb10d20d1c569f2db3fb1235488f624dafe8469e8ce65356800ba31/shapely-2.1.0-cp313-cp313-win32.whl", hash = "sha256:30e967abd08fce49513d4187c01b19f139084019f33bec0673e8dbeb557c45e4", size = 1526600 }, - { url = "https://files.pythonhosted.org/packages/e3/f0/9f8cdf2258d7aed742459cea51c70d184de92f5d2d6f5f7f1ded90a18c31/shapely-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:1dc8d4364483a14aba4c844b7bd16a6fa3728887e2c33dfa1afa34a3cf4d08a5", size = 1707115 }, - { url = "https://files.pythonhosted.org/packages/75/ed/32952df461753a65b3e5d24c8efb361d3a80aafaef0b70d419063f6f2c11/shapely-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:673e073fea099d1c82f666fb7ab0a00a77eff2999130a69357ce11941260d855", size = 1824847 }, - { url = "https://files.pythonhosted.org/packages/ff/b9/2284de512af30b02f93ddcdd2e5c79834a3cf47fa3ca11b0f74396feb046/shapely-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6d1513f915a56de67659fe2047c1ad5ff0f8cbff3519d1e74fced69c9cb0e7da", size = 1631035 }, - { url = "https://files.pythonhosted.org/packages/35/16/a59f252a7e736b73008f10d0950ffeeb0d5953be7c0bdffd39a02a6ba310/shapely-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d6a7043178890b9e028d80496ff4c79dc7629bff4d78a2f25323b661756bab8", size = 2968639 }, - { url = "https://files.pythonhosted.org/packages/a5/0a/6a20eca7b0092cfa243117e8e145a58631a4833a0a519ec9b445172e83a0/shapely-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb638378dc3d76f7e85b67d7e2bb1366811912430ac9247ac00c127c2b444cdc", size = 3055713 }, - { url = "https://files.pythonhosted.org/packages/fb/44/eeb0c7583b1453d1cf7a319a1d738e08f98a5dc993fa1ef3c372983e4cb5/shapely-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:737124e87d91d616acf9a911f74ac55e05db02a43a6a7245b3d663817b876055", size = 3890478 }, - { url = "https://files.pythonhosted.org/packages/5d/6e/37ff3c6af1d408cacb0a7d7bfea7b8ab163a5486e35acb08997eae9d8756/shapely-2.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e6c229e7bb87aae5df82fa00b6718987a43ec168cc5affe095cca59d233f314", size = 4036148 }, - { url = "https://files.pythonhosted.org/packages/c8/6a/8c0b7de3aeb5014a23f06c5e9d3c7852ebcf0d6b00fe660b93261e310e24/shapely-2.1.0-cp313-cp313t-win32.whl", hash = "sha256:a9580bda119b1f42f955aa8e52382d5c73f7957e0203bc0c0c60084846f3db94", size = 1535993 }, - { url = "https://files.pythonhosted.org/packages/a8/91/ae80359a58409d52e4d62c7eacc7eb3ddee4b9135f1db884b6a43cf2e174/shapely-2.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e8ff4e5cfd799ba5b6f37b5d5527dbd85b4a47c65b6d459a03d0962d2a9d4d10", size = 1717777 }, +sdist = { url = "https://files.pythonhosted.org/packages/fb/fe/3b0d2f828ffaceadcdcb51b75b9c62d98e62dd95ce575278de35f24a1c20/shapely-2.1.0.tar.gz", hash = "sha256:2cbe90e86fa8fc3ca8af6ffb00a77b246b918c7cf28677b7c21489b678f6b02e", size = 313617, upload-time = "2025-04-03T09:15:05.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/d1/6a9371ec39d3ef08e13225594e6c55b045209629afd9e6d403204507c2a8/shapely-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53e7ee8bd8609cf12ee6dce01ea5affe676976cf7049315751d53d8db6d2b4b2", size = 1830732, upload-time = "2025-04-03T09:14:25.047Z" }, + { url = "https://files.pythonhosted.org/packages/32/87/799e3e48be7ce848c08509b94d2180f4ddb02e846e3c62d0af33da4d78d3/shapely-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3cab20b665d26dbec0b380e15749bea720885a481fa7b1eedc88195d4a98cfa4", size = 1638404, upload-time = "2025-04-03T09:14:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/85/00/6665d77f9dd09478ab0993b8bc31668aec4fd3e5f1ddd1b28dd5830e47be/shapely-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a38b39a09340273c3c92b3b9a374272a12cc7e468aeeea22c1c46217a03e5c", size = 2945316, upload-time = "2025-04-03T09:14:28.266Z" }, + { url = "https://files.pythonhosted.org/packages/34/49/738e07d10bbc67cae0dcfe5a484c6e518a517f4f90550dda2adf3a78b9f2/shapely-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:edaec656bdd9b71278b98e6f77c464b1c3b2daa9eace78012ff0f0b4b5b15b04", size = 3063099, upload-time = "2025-04-03T09:14:30.067Z" }, + { url = "https://files.pythonhosted.org/packages/88/b8/138098674559362ab29f152bff3b6630de423378fbb0324812742433a4ef/shapely-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c8a732ddd9b25e7a54aa748e7df8fd704e23e5d5d35b7d376d80bffbfc376d04", size = 3887873, upload-time = "2025-04-03T09:14:31.912Z" }, + { url = "https://files.pythonhosted.org/packages/67/a8/fdae7c2db009244991d86f4d2ca09d2f5ccc9d41c312c3b1ee1404dc55da/shapely-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9c93693ad8adfdc9138a5a2d42da02da94f728dd2e82d2f0f442f10e25027f5f", size = 4067004, upload-time = "2025-04-03T09:14:33.976Z" }, + { url = "https://files.pythonhosted.org/packages/ed/78/17e17d91b489019379df3ee1afc4bd39787b232aaa1d540f7d376f0280b7/shapely-2.1.0-cp312-cp312-win32.whl", hash = "sha256:d8ac6604eefe807e71a908524de23a37920133a1729fe3a4dfe0ed82c044cbf4", size = 1527366, upload-time = "2025-04-03T09:14:35.348Z" }, + { url = "https://files.pythonhosted.org/packages/b8/bd/9249bd6dda948441e25e4fb14cbbb5205146b0fff12c66b19331f1ff2141/shapely-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:f4f47e631aa4f9ec5576eac546eb3f38802e2f82aeb0552f9612cb9a14ece1db", size = 1708265, upload-time = "2025-04-03T09:14:36.878Z" }, + { url = "https://files.pythonhosted.org/packages/8d/77/4e368704b2193e74498473db4461d697cc6083c96f8039367e59009d78bd/shapely-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b64423295b563f43a043eb786e7a03200ebe68698e36d2b4b1c39f31dfb50dfb", size = 1830029, upload-time = "2025-04-03T09:14:38.795Z" }, + { url = "https://files.pythonhosted.org/packages/71/3c/d888597bda680e4de987316b05ca9db07416fa29523beff64f846503302f/shapely-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1b5578f45adc25b235b22d1ccb9a0348c8dc36f31983e57ea129a88f96f7b870", size = 1637999, upload-time = "2025-04-03T09:14:40.209Z" }, + { url = "https://files.pythonhosted.org/packages/03/8d/ee0e23b7ef88fba353c63a81f1f329c77f5703835db7b165e7c0b8b7f839/shapely-2.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a7e83d383b27f02b684e50ab7f34e511c92e33b6ca164a6a9065705dd64bcb", size = 2929348, upload-time = "2025-04-03T09:14:42.11Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a7/5c9cb413e4e2ce52c16be717e94abd40ce91b1f8974624d5d56154c5d40b/shapely-2.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:942031eb4d8f7b3b22f43ba42c09c7aa3d843aa10d5cc1619fe816e923b66e55", size = 3048973, upload-time = "2025-04-03T09:14:43.841Z" }, + { url = "https://files.pythonhosted.org/packages/84/23/45b90c0bd2157b238490ca56ef2eedf959d3514c7d05475f497a2c88b6d9/shapely-2.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d2843c456a2e5627ee6271800f07277c0d2652fb287bf66464571a057dbc00b3", size = 3873148, upload-time = "2025-04-03T09:14:45.924Z" }, + { url = "https://files.pythonhosted.org/packages/c0/bc/ed7d5d37f5395166042576f0c55a12d7e56102799464ba7ea3a72a38c769/shapely-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8c4b17469b7f39a5e6a7cfea79f38ae08a275427f41fe8b48c372e1449147908", size = 4052655, upload-time = "2025-04-03T09:14:47.475Z" }, + { url = "https://files.pythonhosted.org/packages/c0/8f/a1dafbb10d20d1c569f2db3fb1235488f624dafe8469e8ce65356800ba31/shapely-2.1.0-cp313-cp313-win32.whl", hash = "sha256:30e967abd08fce49513d4187c01b19f139084019f33bec0673e8dbeb557c45e4", size = 1526600, upload-time = "2025-04-03T09:14:48.952Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f0/9f8cdf2258d7aed742459cea51c70d184de92f5d2d6f5f7f1ded90a18c31/shapely-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:1dc8d4364483a14aba4c844b7bd16a6fa3728887e2c33dfa1afa34a3cf4d08a5", size = 1707115, upload-time = "2025-04-03T09:14:50.445Z" }, + { url = "https://files.pythonhosted.org/packages/75/ed/32952df461753a65b3e5d24c8efb361d3a80aafaef0b70d419063f6f2c11/shapely-2.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:673e073fea099d1c82f666fb7ab0a00a77eff2999130a69357ce11941260d855", size = 1824847, upload-time = "2025-04-03T09:14:52.358Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b9/2284de512af30b02f93ddcdd2e5c79834a3cf47fa3ca11b0f74396feb046/shapely-2.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6d1513f915a56de67659fe2047c1ad5ff0f8cbff3519d1e74fced69c9cb0e7da", size = 1631035, upload-time = "2025-04-03T09:14:53.739Z" }, + { url = "https://files.pythonhosted.org/packages/35/16/a59f252a7e736b73008f10d0950ffeeb0d5953be7c0bdffd39a02a6ba310/shapely-2.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d6a7043178890b9e028d80496ff4c79dc7629bff4d78a2f25323b661756bab8", size = 2968639, upload-time = "2025-04-03T09:14:55.674Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0a/6a20eca7b0092cfa243117e8e145a58631a4833a0a519ec9b445172e83a0/shapely-2.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb638378dc3d76f7e85b67d7e2bb1366811912430ac9247ac00c127c2b444cdc", size = 3055713, upload-time = "2025-04-03T09:14:57.564Z" }, + { url = "https://files.pythonhosted.org/packages/fb/44/eeb0c7583b1453d1cf7a319a1d738e08f98a5dc993fa1ef3c372983e4cb5/shapely-2.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:737124e87d91d616acf9a911f74ac55e05db02a43a6a7245b3d663817b876055", size = 3890478, upload-time = "2025-04-03T09:14:59.139Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6e/37ff3c6af1d408cacb0a7d7bfea7b8ab163a5486e35acb08997eae9d8756/shapely-2.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e6c229e7bb87aae5df82fa00b6718987a43ec168cc5affe095cca59d233f314", size = 4036148, upload-time = "2025-04-03T09:15:01.328Z" }, + { url = "https://files.pythonhosted.org/packages/c8/6a/8c0b7de3aeb5014a23f06c5e9d3c7852ebcf0d6b00fe660b93261e310e24/shapely-2.1.0-cp313-cp313t-win32.whl", hash = "sha256:a9580bda119b1f42f955aa8e52382d5c73f7957e0203bc0c0c60084846f3db94", size = 1535993, upload-time = "2025-04-03T09:15:02.973Z" }, + { url = "https://files.pythonhosted.org/packages/a8/91/ae80359a58409d52e4d62c7eacc7eb3ddee4b9135f1db884b6a43cf2e174/shapely-2.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:e8ff4e5cfd799ba5b6f37b5d5527dbd85b4a47c65b6d459a03d0962d2a9d4d10", size = 1717777, upload-time = "2025-04-03T09:15:04.461Z" }, ] [[package]] name = "snowballstemmer" version = "2.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } +sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699, upload-time = "2021-11-16T18:38:38.009Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, + { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002, upload-time = "2021-11-16T18:38:34.792Z" }, ] [[package]] @@ -487,9 +471,9 @@ dependencies = [ { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911, upload-time = "2024-07-20T14:46:56.059Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624 }, + { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624, upload-time = "2024-07-20T14:46:52.142Z" }, ] [[package]] @@ -501,36 +485,36 @@ dependencies = [ { name = "sphinx" }, { name = "sphinxcontrib-jquery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/33/2a35a9cdbfda9086bda11457bcc872173ab3565b16b6d7f6b3efaa6dc3d6/sphinx_rtd_theme-2.0.0.tar.gz", hash = "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b", size = 2785005 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/33/2a35a9cdbfda9086bda11457bcc872173ab3565b16b6d7f6b3efaa6dc3d6/sphinx_rtd_theme-2.0.0.tar.gz", hash = "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b", size = 2785005, upload-time = "2023-11-28T04:14:03.104Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/46/00fda84467815c29951a9c91e3ae7503c409ddad04373e7cfc78daad4300/sphinx_rtd_theme-2.0.0-py2.py3-none-any.whl", hash = "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586", size = 2824721 }, + { url = "https://files.pythonhosted.org/packages/ea/46/00fda84467815c29951a9c91e3ae7503c409ddad04373e7cfc78daad4300/sphinx_rtd_theme-2.0.0-py2.py3-none-any.whl", hash = "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586", size = 2824721, upload-time = "2023-11-28T04:13:59.589Z" }, ] [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 }, + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, ] [[package]] name = "sphinxcontrib-devhelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 }, + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, ] [[package]] name = "sphinxcontrib-htmlhelp" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 }, + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, ] [[package]] @@ -540,53 +524,45 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331 } +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104 }, + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, ] [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, ] [[package]] name = "sphinxcontrib-qthelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 }, + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, ] [[package]] name = "sphinxcontrib-serializinghtml" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 }, -] - -[[package]] -name = "swecommondm" -version = "0.0.1a0" -source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/89/a88489999fd0d1b3409c198439962d9c41db98f1af239d79329f38554c73/swecommondm-0.0.1a0-py3-none-any.whl", hash = "sha256:e0d4fe9b15aa1516e10ce4f20c592ebbf544a76ef3af644c9efd8654de74f8f7", size = 13502 }, + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] [[package]] name = "typing-extensions" version = "4.13.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 } +sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 }, + { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" }, ] [[package]] @@ -596,36 +572,36 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 } +sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222, upload-time = "2025-02-25T17:27:59.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 }, + { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125, upload-time = "2025-02-25T17:27:57.754Z" }, ] [[package]] name = "urllib3" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680 }, + { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, ] [[package]] name = "websockets" version = "12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2e/62/7a7874b7285413c954a4cca3c11fd851f11b2fe5b4ae2d9bee4f6d9bdb10/websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b", size = 104994 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/6d/23cc898647c8a614a0d9ca703695dd04322fb5135096a20c2684b7c852b6/websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df", size = 124061 }, - { url = "https://files.pythonhosted.org/packages/39/34/364f30fdf1a375e4002a26ee3061138d1571dfda6421126127d379d13930/websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc", size = 121296 }, - { url = "https://files.pythonhosted.org/packages/2e/00/96ae1c9dcb3bc316ef683f2febd8c97dde9f254dc36c3afc65c7645f734c/websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b", size = 121326 }, - { url = "https://files.pythonhosted.org/packages/af/f1/bba1e64430685dd456c1a1fd6b0c791ae33104967b928aefeff261761e8d/websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb", size = 131807 }, - { url = "https://files.pythonhosted.org/packages/62/3b/98ee269712f37d892b93852ce07b3e6d7653160ca4c0d4f8c8663f8021f8/websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92", size = 130751 }, - { url = "https://files.pythonhosted.org/packages/f1/00/d6f01ca2b191f8b0808e4132ccd2e7691f0453cbd7d0f72330eb97453c3a/websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed", size = 131176 }, - { url = "https://files.pythonhosted.org/packages/af/9c/703ff3cd8109dcdee6152bae055d852ebaa7750117760ded697ab836cbcf/websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5", size = 136246 }, - { url = "https://files.pythonhosted.org/packages/0b/a5/1a38fb85a456b9dc874ec984f3ff34f6550eafd17a3da28753cd3c1628e8/websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2", size = 135466 }, - { url = "https://files.pythonhosted.org/packages/3c/98/1261f289dff7e65a38d59d2f591de6ed0a2580b729aebddec033c4d10881/websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113", size = 136083 }, - { url = "https://files.pythonhosted.org/packages/a9/1c/f68769fba63ccb9c13fe0a25b616bd5aebeef1c7ddebc2ccc32462fb784d/websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d", size = 124460 }, - { url = "https://files.pythonhosted.org/packages/20/52/8915f51f9aaef4e4361c89dd6cf69f72a0159f14e0d25026c81b6ad22525/websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f", size = 124985 }, - { url = "https://files.pythonhosted.org/packages/79/4d/9cc401e7b07e80532ebc8c8e993f42541534da9e9249c59ee0139dcb0352/websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e", size = 118370 }, +sdist = { url = "https://files.pythonhosted.org/packages/2e/62/7a7874b7285413c954a4cca3c11fd851f11b2fe5b4ae2d9bee4f6d9bdb10/websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b", size = 104994, upload-time = "2023-10-21T14:21:11.88Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/6d/23cc898647c8a614a0d9ca703695dd04322fb5135096a20c2684b7c852b6/websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df", size = 124061, upload-time = "2023-10-21T14:20:02.221Z" }, + { url = "https://files.pythonhosted.org/packages/39/34/364f30fdf1a375e4002a26ee3061138d1571dfda6421126127d379d13930/websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc", size = 121296, upload-time = "2023-10-21T14:20:03.591Z" }, + { url = "https://files.pythonhosted.org/packages/2e/00/96ae1c9dcb3bc316ef683f2febd8c97dde9f254dc36c3afc65c7645f734c/websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b", size = 121326, upload-time = "2023-10-21T14:20:04.956Z" }, + { url = "https://files.pythonhosted.org/packages/af/f1/bba1e64430685dd456c1a1fd6b0c791ae33104967b928aefeff261761e8d/websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb", size = 131807, upload-time = "2023-10-21T14:20:06.153Z" }, + { url = "https://files.pythonhosted.org/packages/62/3b/98ee269712f37d892b93852ce07b3e6d7653160ca4c0d4f8c8663f8021f8/websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92", size = 130751, upload-time = "2023-10-21T14:20:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/f1/00/d6f01ca2b191f8b0808e4132ccd2e7691f0453cbd7d0f72330eb97453c3a/websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed", size = 131176, upload-time = "2023-10-21T14:20:09.212Z" }, + { url = "https://files.pythonhosted.org/packages/af/9c/703ff3cd8109dcdee6152bae055d852ebaa7750117760ded697ab836cbcf/websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5", size = 136246, upload-time = "2023-10-21T14:20:10.423Z" }, + { url = "https://files.pythonhosted.org/packages/0b/a5/1a38fb85a456b9dc874ec984f3ff34f6550eafd17a3da28753cd3c1628e8/websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2", size = 135466, upload-time = "2023-10-21T14:20:11.826Z" }, + { url = "https://files.pythonhosted.org/packages/3c/98/1261f289dff7e65a38d59d2f591de6ed0a2580b729aebddec033c4d10881/websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113", size = 136083, upload-time = "2023-10-21T14:20:13.451Z" }, + { url = "https://files.pythonhosted.org/packages/a9/1c/f68769fba63ccb9c13fe0a25b616bd5aebeef1c7ddebc2ccc32462fb784d/websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d", size = 124460, upload-time = "2023-10-21T14:20:14.719Z" }, + { url = "https://files.pythonhosted.org/packages/20/52/8915f51f9aaef4e4361c89dd6cf69f72a0159f14e0d25026c81b6ad22525/websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f", size = 124985, upload-time = "2023-10-21T14:20:15.817Z" }, + { url = "https://files.pythonhosted.org/packages/79/4d/9cc401e7b07e80532ebc8c8e993f42541534da9e9249c59ee0139dcb0352/websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e", size = 118370, upload-time = "2023-10-21T14:21:10.075Z" }, ] From 78371d0360f09da759f46441d0f42801c251f9e0 Mon Sep 17 00:00:00 2001 From: Ian Patterson Date: Tue, 16 Sep 2025 22:47:57 -0500 Subject: [PATCH 2/6] Fix noted bugs from out-of-date imports --- oshconnect/__init__.py | 4 ++-- oshconnect/csapi4py/part_2/__init__.py | 6 ++++++ oshconnect/datamodels/__init__.py | 10 ++++++++++ oshconnect/datamodels/geometry.py | 3 ++- oshconnect/datasource.py | 3 ++- oshconnect/oshconnectapi.py | 13 ++++++++----- oshconnect/timemanagement.py | 11 +++++------ pyproject.toml | 16 ++++++++-------- tests/test_api_update.py | 6 ++++++ tests/test_oshconnect.py | 2 +- uv.lock | 12 ++++++------ 11 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 tests/test_api_update.py diff --git a/oshconnect/__init__.py b/oshconnect/__init__.py index e54aa51..256a5e3 100644 --- a/oshconnect/__init__.py +++ b/oshconnect/__init__.py @@ -5,5 +5,5 @@ # Contact Email: ian@botts-inc.com # ============================================================================== -class Example: - pass +from .oshconnectapi import OSHConnect, Node +from .osh_connect_datamodels import System, Node, Datastream, Observation, ControlChannel \ No newline at end of file diff --git a/oshconnect/csapi4py/part_2/__init__.py b/oshconnect/csapi4py/part_2/__init__.py index e69de29..7ddbce4 100644 --- a/oshconnect/csapi4py/part_2/__init__.py +++ b/oshconnect/csapi4py/part_2/__init__.py @@ -0,0 +1,6 @@ +# import commands +# import control_channels +# import datastreams +# import observations +# import system_events +# import system_history \ No newline at end of file diff --git a/oshconnect/datamodels/__init__.py b/oshconnect/datamodels/__init__.py index e69de29..96c9d10 100644 --- a/oshconnect/datamodels/__init__.py +++ b/oshconnect/datamodels/__init__.py @@ -0,0 +1,10 @@ +# import api_utils +# import commands +# import control_streams +# import datastreams +# import encoding +# import geometry +# import network_properties +# import observations +# import swe_components +# import system_events_and_history diff --git a/oshconnect/datamodels/geometry.py b/oshconnect/datamodels/geometry.py index 60bbaab..5a88562 100644 --- a/oshconnect/datamodels/geometry.py +++ b/oshconnect/datamodels/geometry.py @@ -1,10 +1,11 @@ from pydantic import BaseModel, Field from oshconnect.csapi4py.constants import GeometryTypes +from shapely import Geometry # TODO: Add specific validations for each type -# TODO: update to either use third party Geometry definitions or create a more robust definition +# TODO: determine if serializing 'shapely' objects gives valid JSON structures from our own serialization class Geometry(BaseModel): """ A class to represent the geometry of a feature diff --git a/oshconnect/datasource.py b/oshconnect/datasource.py index d63c1fb..ccd0f9b 100644 --- a/oshconnect/datasource.py +++ b/oshconnect/datasource.py @@ -21,7 +21,7 @@ from oshconnect.datamodels.swe_components import DataRecordSchema from .core_datamodels import DatastreamResource, SystemResource, TimePeriod -from .timemanagement import TemporalModes +from .timemanagement import TemporalModes, Synchronizer # from swecommondm.component_implementations import DataRecord @@ -48,6 +48,7 @@ class DataStream: _playback_websocket: websockets.WebSocketClientProtocol = None _extra_headers: dict = None _result_schema: DataRecordSchema = None + _synchronizer: Synchronizer = None def __init__(self, name: str, datastream: DatastreamResource, parent_system: SystemResource): diff --git a/oshconnect/oshconnectapi.py b/oshconnect/oshconnectapi.py index 1ac8fde..0a24efe 100644 --- a/oshconnect/oshconnectapi.py +++ b/oshconnect/oshconnectapi.py @@ -8,7 +8,6 @@ import shelve from oshconnect.csapi4py.core.default_api_helpers import APIHelper - from .core_datamodels import DatastreamResource, TimePeriod from .datasource import DataStream, DataStreamHandler, MessageWrapper from .datastore import DataStore @@ -26,7 +25,7 @@ class OSHConnect: _systems: list[System] = [] _cs_api_builder: APIHelper = None _datasource_handler: DataStreamHandler = None - _datafeeds: list[DataStream] = [] + _datastreams: list[DataStream] = [] _datataskers: list[DataStore] = [] _datagroups: list = [] _tasks: list = [] @@ -150,7 +149,7 @@ def discover_datastreams(self): DataStream(name=ds.name, datastream=ds, parent_system=system) for ds in res_datastreams] - self._datafeeds.extend(new_datasource) + self._datastreams.extend(new_datasource) list(map(self._datasource_handler.add_datasource, new_datasource)) def discover_systems(self, nodes: list[str] = None): @@ -199,7 +198,7 @@ def get_message_list(self) -> list[MessageWrapper]: """ return self._datasource_handler.get_messages() - def insert_system(self, system: System, target_node: Node): + def _insert_system(self, system: System, target_node: Node): """ Create a system on the target node. :param system: System object @@ -227,7 +226,7 @@ def insert_datastream(self, datastream: DatastreamResource, system: str | System sys_obj.add_insert_datastream(datastream) - self._datafeeds.append(datastream) + self._datastreams.append(datastream) def find_system(self, system_id: str) -> System | None: """ @@ -270,3 +269,7 @@ def create_and_insert_system(self, system_opts: dict, target_node: Node): def remove_system(self, system_id: str): pass + + # DataStream Helpers + def get_datastreams(self) -> list[DataStream]: + return self._datastreams diff --git a/oshconnect/timemanagement.py b/oshconnect/timemanagement.py index c7f9bb2..b7bdd8b 100644 --- a/oshconnect/timemanagement.py +++ b/oshconnect/timemanagement.py @@ -299,12 +299,6 @@ def does_timeperiod_overlap(self, checked_timeperiod: TimePeriod) -> bool: return True -class Utilities: - pass - # @staticmethod - # def parse_systems_result(result) -> System: - - class TimeManagement: time_range: TimePeriod time_controller: TimeController @@ -329,6 +323,7 @@ class TimeController: _timeline_begin: TimeInstant _timeline_end: TimeInstant _current_time: TimeInstant + _synchronizer: Synchronizer def __new__(cls, *args, **kwargs): if cls._instance is None: @@ -420,6 +415,10 @@ def _compute_time_range(self): class Synchronizer: _buffer: any + _buffering_time: int def synchronize(self, systems: list): pass + + def check_in_sync(self): + pass diff --git a/pyproject.toml b/pyproject.toml index b14cd73..1501b3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "oshconnect" -version = "0.2.4-1" +version = "0.3.0a1" description = "Library for interfacing with OSH, helping guide visualization efforts, and providing a place to store configurations." readme = "README.md" authors = [ @@ -9,17 +9,17 @@ authors = [ requires-python = "<4.0,>=3.12" dependencies = [ "paho-mqtt>=2.1.0", - "pydantic<3.0.0,>=2.7.4", - "shapely<3.0.0,>=2.0.4", - "websockets<13.0,>=12.0", + "pydantic>=2.7.4,<3.0.0", + "shapely>=2.0.4,<3.0.0", + "websockets>=12.0,<16.0", ] [dependency-groups] dev = [ - "pytest<9.0.0,>=8.2.2", - "sphinx<8.0.0,>=7.3.7", - "flake8<8.0.0,>=7.1.0", - "sphinx-rtd-theme<3.0.0,>=2.0.0", + "flake8>=7.2.0", + "pytest>=8.3.5", + "sphinx>=7.4.7", + "sphinx-rtd-theme>=2.0.0", ] [tool.setuptools] diff --git a/tests/test_api_update.py b/tests/test_api_update.py new file mode 100644 index 0000000..3eff373 --- /dev/null +++ b/tests/test_api_update.py @@ -0,0 +1,6 @@ +import pytest + +from oshconnect import OSHConnect, System, Node, Datastream + +node = Node() +app = OSHConnect() \ No newline at end of file diff --git a/tests/test_oshconnect.py b/tests/test_oshconnect.py index 29013e4..7457fe7 100644 --- a/tests/test_oshconnect.py +++ b/tests/test_oshconnect.py @@ -68,7 +68,7 @@ def test_oshconnect_find_datastreams(self): app.discover_systems() app.discover_datastreams() - assert len(app._datafeeds) > 0 + assert len(app._datastreams) > 0 async def test_obs_ws_stream(self): ds_url = ("ws://localhost:8585/sensorhub/api/datastreams/e07n5sbjqvalm/observations?f=application%2Fjson" diff --git a/uv.lock b/uv.lock index 4409817..ed74425 100644 --- a/uv.lock +++ b/uv.lock @@ -231,7 +231,7 @@ wheels = [ [[package]] name = "oshconnect" -version = "0.2.4.post1" +version = "0.3.0a1" source = { virtual = "." } dependencies = [ { name = "paho-mqtt" }, @@ -253,15 +253,15 @@ requires-dist = [ { name = "paho-mqtt", specifier = ">=2.1.0" }, { name = "pydantic", specifier = ">=2.7.4,<3.0.0" }, { name = "shapely", specifier = ">=2.0.4,<3.0.0" }, - { name = "websockets", specifier = ">=12.0,<13.0" }, + { name = "websockets", specifier = ">=12.0,<16.0" }, ] [package.metadata.requires-dev] dev = [ - { name = "flake8", specifier = ">=7.1.0,<8.0.0" }, - { name = "pytest", specifier = ">=8.2.2,<9.0.0" }, - { name = "sphinx", specifier = ">=7.3.7,<8.0.0" }, - { name = "sphinx-rtd-theme", specifier = ">=2.0.0,<3.0.0" }, + { name = "flake8", specifier = ">=7.2.0" }, + { name = "pytest", specifier = ">=8.3.5" }, + { name = "sphinx", specifier = ">=7.4.7" }, + { name = "sphinx-rtd-theme", specifier = ">=2.0.0" }, ] [[package]] From 8b324fb6ba0daca142f76d3bdd68f8b38296d887 Mon Sep 17 00:00:00 2001 From: Ian Patterson Date: Thu, 18 Sep 2025 00:09:16 -0500 Subject: [PATCH 3/6] fix simple errors from flake8 --- oshconnect/__init__.py | 4 ++-- oshconnect/csapi4py/part_2/__init__.py | 2 +- oshconnect/datamodels/geometry.py | 3 +-- tox.ini | 3 ++- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/oshconnect/__init__.py b/oshconnect/__init__.py index 256a5e3..b1e50e6 100644 --- a/oshconnect/__init__.py +++ b/oshconnect/__init__.py @@ -5,5 +5,5 @@ # Contact Email: ian@botts-inc.com # ============================================================================== -from .oshconnectapi import OSHConnect, Node -from .osh_connect_datamodels import System, Node, Datastream, Observation, ControlChannel \ No newline at end of file +from .oshconnectapi import OSHConnect +from .osh_connect_datamodels import System, Node, Datastream, Observation, ControlChannel diff --git a/oshconnect/csapi4py/part_2/__init__.py b/oshconnect/csapi4py/part_2/__init__.py index 7ddbce4..419373c 100644 --- a/oshconnect/csapi4py/part_2/__init__.py +++ b/oshconnect/csapi4py/part_2/__init__.py @@ -3,4 +3,4 @@ # import datastreams # import observations # import system_events -# import system_history \ No newline at end of file +# import system_history diff --git a/oshconnect/datamodels/geometry.py b/oshconnect/datamodels/geometry.py index 5a88562..ced5988 100644 --- a/oshconnect/datamodels/geometry.py +++ b/oshconnect/datamodels/geometry.py @@ -1,7 +1,6 @@ from pydantic import BaseModel, Field from oshconnect.csapi4py.constants import GeometryTypes -from shapely import Geometry # TODO: Add specific validations for each type @@ -12,4 +11,4 @@ class Geometry(BaseModel): """ type: GeometryTypes = Field(...) coordinates: list - bbox: list = None \ No newline at end of file + bbox: list = None diff --git a/tox.ini b/tox.ini index 0d03a58..9fd34f9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,2 +1,3 @@ [flake8] -extend-ignore = E501 \ No newline at end of file +extend-ignore = E501 +exclude = .venv,tests \ No newline at end of file From fd103a7a10e7a1d6f8ef3d8f6da61495812b9362 Mon Sep 17 00:00:00 2001 From: Ian Patterson Date: Thu, 18 Sep 2025 01:06:58 -0500 Subject: [PATCH 4/6] add publish workflow --- .github/workflows/publish.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..a1e3aaa --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,27 @@ +name: publish.yml +on: + push: + tags: + # publishes any tag starting with 'v' as in 'v.1.0' + - v* + +jobs: + run: + runs-on: ubuntu-latest + environment: + name: pypi + permissions: + id-token: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Install uv + uses: astral-sh/setup-uv@v6 + - name: Install Python 3.13 + run: uv python install 3.13 + - name: Build + run: uv build + # Need to add a test that verifies the builds + - name: Publish + run: uv publish From 5442e552dc3dddff21c8b8d625dff7af93d2d783 Mon Sep 17 00:00:00 2001 From: Ian Patterson Date: Thu, 18 Sep 2025 01:32:13 -0500 Subject: [PATCH 5/6] update workflows to newer versions --- .github/workflows/docs_pages.yaml | 43 ++++++++++++++++--------------- .github/workflows/linting.yaml | 16 +++++++----- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/.github/workflows/docs_pages.yaml b/.github/workflows/docs_pages.yaml index f5fc5d6..888ef29 100644 --- a/.github/workflows/docs_pages.yaml +++ b/.github/workflows/docs_pages.yaml @@ -1,5 +1,5 @@ name: Docs2Pages -on: [push, pull_request, workflow_dispatch] +on: [ push, pull_request, workflow_dispatch ] permissions: contents: write @@ -7,26 +7,27 @@ jobs: build-docs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - - uses: actions/setup-python@v5 - with: - python-version: '3.12' + - name: Checkout + uses: actions/checkout@v5 - - name: Install dependencies - run: | - pip install uv - uv sync --all-extras + - name: Install uv + uses: astral-sh/setup-uv@v6 - - name: Sphinx build - run: | - uv run sphinx-build -b html docs/source docs/build/html + - name: Install Python 3.13 + run: uv python install 3.13 - - name: Deploy documentation - uses: peaceiris/actions-gh-pages@v4 - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - with: - publish_branch: gh-pages - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs/build/html - force_orphan: true \ No newline at end of file + - name: Install dependencies + run: uv sync --all-extras + + - name: Sphinx build + run: | + uv run sphinx-build -b html docs/source docs/build/html + + - name: Deploy documentation + uses: peaceiris/actions-gh-pages@v4 + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + with: + publish_branch: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/build/html + force_orphan: true \ No newline at end of file diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml index 3bb0167..9a13d9c 100644 --- a/.github/workflows/linting.yaml +++ b/.github/workflows/linting.yaml @@ -4,15 +4,17 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v5 - with: - python-version: '3.12' + - name: Checkout + uses: actions/checkout@v5 + + - name: Install uv + uses: astral-sh/setup-uv@v6 + + - name: Install Python 3.13 + run: uv python install 3.13 - name: Install dependencies - run: | - pip install uv - uv sync --all-extras + run: uv sync --all-extras - name: Lint run: | From 28549ad6b62ced85176a16c5fa7ce2c5c4ed6d97 Mon Sep 17 00:00:00 2001 From: Ian Patterson Date: Thu, 18 Sep 2025 01:43:03 -0500 Subject: [PATCH 6/6] update tox.ini to ignore 401 errors in init files --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9fd34f9..86d7101 100644 --- a/tox.ini +++ b/tox.ini @@ -1,3 +1,4 @@ [flake8] extend-ignore = E501 -exclude = .venv,tests \ No newline at end of file +exclude = .venv,tests +per-file-ignores = __init__.py:F401 \ No newline at end of file