From 2f36250d88b66f40fe334846fa7d131bd46efc05 Mon Sep 17 00:00:00 2001 From: Jeff Kala Date: Fri, 17 Jan 2025 17:32:24 -0600 Subject: [PATCH 1/7] Bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 52e470c9..7f59dd35 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nautobot-device-onboarding" -version = "4.2.0" +version = "4.2.1a0" description = "A app for Nautobot to easily onboard new devices." authors = ["Network to Code, LLC "] license = "Apache-2.0" From 8e20686a2f73464746c3eba740a202051552d613 Mon Sep 17 00:00:00 2001 From: David Cates <57967713+Dav-C@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:56:54 -0700 Subject: [PATCH 2/7] add missing 'adapter' from logging message (#305) * add missing 'adapter' from logging message * add change fragment --------- Co-authored-by: David Cates --- changes/306.fixed | 1 + .../diffsync/models/sync_network_data_models.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changes/306.fixed diff --git a/changes/306.fixed b/changes/306.fixed new file mode 100644 index 00000000..a1a7b17f --- /dev/null +++ b/changes/306.fixed @@ -0,0 +1 @@ +Fixed error with logging message in SyncNetworkDataIPAddress.update() \ No newline at end of file diff --git a/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py b/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py index 731e2396..e8ecdf59 100644 --- a/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py +++ b/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py @@ -161,7 +161,7 @@ def update(self, attrs): try: ip_address = IPAddress.objects.get(host=self.host, parent__namespace=self.adapter.job.namespace) except ObjectDoesNotExist as err: - self.job.logger.error(f"{self} failed to update, {err}") + self.adapter.job.logger.error(f"{self} failed to update, {err}") if attrs.get("mask_length"): ip_address.mask_length = attrs["mask_length"] if attrs.get("status__name"): @@ -171,7 +171,7 @@ def update(self, attrs): try: ip_address.validated_save() except ValidationError as err: - self.job.logger.error(f"{self} failed to update, {err}") + self.adapter.job.logger.error(f"{self} failed to update, {err}") return super().update(attrs) From b087c77c56272217a662268868b09cbf50b35324 Mon Sep 17 00:00:00 2001 From: Joe Wesch <10467633+joewesch@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:16:07 -0600 Subject: [PATCH 3/7] Updates ntc-templates to 7.x (#308) --- changes/307.dependencies | 1 + poetry.lock | 11 ++++++----- pyproject.toml | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 changes/307.dependencies mode change 100755 => 100644 poetry.lock mode change 100755 => 100644 pyproject.toml diff --git a/changes/307.dependencies b/changes/307.dependencies new file mode 100644 index 00000000..dceedf73 --- /dev/null +++ b/changes/307.dependencies @@ -0,0 +1 @@ +Updated ntc-templates to 7.x \ No newline at end of file diff --git a/poetry.lock b/poetry.lock old mode 100755 new mode 100644 index 05c23be4..b02bcf1d --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "amqp" @@ -2741,13 +2741,13 @@ nornir = ">=3,<4" [[package]] name = "ntc-templates" -version = "6.1.0" +version = "7.6.0" description = "TextFSM Templates for Network Devices, and Python wrapper for TextFSM's CliTable." optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "ntc_templates-6.1.0-py3-none-any.whl", hash = "sha256:568f85f0eae8f563188231ebf54685b00442f43473b2eccc887d82ed8ca20949"}, - {file = "ntc_templates-6.1.0.tar.gz", hash = "sha256:a58efc5ebd0ef55389731d5e9ecd2fc3ec5b5d6c263c1bf6f8c2971ded681a6e"}, + {file = "ntc_templates-7.6.0-py3-none-any.whl", hash = "sha256:6e855a443cd9ad28192bc766994cbfef58bcaae3ebaf19005a55c6f76e9ab6b5"}, + {file = "ntc_templates-7.6.0.tar.gz", hash = "sha256:b70ccaaf74014344a8446f13744691cfbf2e603101481c71decc8ee53eefea5d"}, ] [package.dependencies] @@ -3092,6 +3092,7 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, @@ -4790,4 +4791,4 @@ all = [] [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.13" -content-hash = "d5124e0e5000b0db6519f1d01866a1d668466e8027fa34333caa25acb8ad21c1" +content-hash = "8a645ab31340a5d29395f4c3f60cdefd86914701fe3464c2ec32607294713ab7" diff --git a/pyproject.toml b/pyproject.toml old mode 100755 new mode 100644 index 7f59dd35..f8a02996 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ nautobot = "^2.2.3" nautobot-ssot = "^3.0.0" nautobot-plugin-nornir = "^2.0.0" jdiff = "^0.0.6" -ntc-templates = "^6.0.0" +ntc-templates = "^7.0.0" # Netutils pin is needed for https://github.com/networktocode/netutils/pull/553 netutils = "^1.9.1" ttp = "^0.9.0" From 9f2c206d2fbc2268d3471be95c7970d4d755250c Mon Sep 17 00:00:00 2001 From: David Cates <57967713+Dav-C@users.noreply.github.com> Date: Tue, 4 Feb 2025 15:49:16 -0700 Subject: [PATCH 4/7] fix loading and saving bugs with vlans, lags and vrfs (#310) * fix loading and saving bugs with vlans, lags. and vrfs * add change fragment --------- Co-authored-by: David Cates --- changes/311.fixed | 1 + .../adapters/sync_network_data_adapters.py | 46 +-- .../models/sync_network_data_models.py | 336 +++++++++++------- 3 files changed, 231 insertions(+), 152 deletions(-) create mode 100644 changes/311.fixed diff --git a/changes/311.fixed b/changes/311.fixed new file mode 100644 index 00000000..d459f9a8 --- /dev/null +++ b/changes/311.fixed @@ -0,0 +1 @@ +Fixed issue with Lags, VRFs and Untagged Vlans not being removed from interfaces \ No newline at end of file diff --git a/nautobot_device_onboarding/diffsync/adapters/sync_network_data_adapters.py b/nautobot_device_onboarding/diffsync/adapters/sync_network_data_adapters.py index 081b40bb..86ab5f2e 100644 --- a/nautobot_device_onboarding/diffsync/adapters/sync_network_data_adapters.py +++ b/nautobot_device_onboarding/diffsync/adapters/sync_network_data_adapters.py @@ -157,12 +157,13 @@ def load_tagged_vlans_to_interface(self): vlan_dict["name"] = vlan.name vlan_dict["id"] = str(vlan.vid) tagged_vlans.append(vlan_dict) + sorted_tagged_vlans = sorted(tagged_vlans, key=lambda x: x["id"]) network_tagged_vlans_to_interface = self.tagged_vlans_to_interface( adapter=self, device__name=interface.device.name, name=interface.name, - tagged_vlans=tagged_vlans, + tagged_vlans=sorted_tagged_vlans, ) network_tagged_vlans_to_interface.model_flags = DiffSyncModelFlags.SKIP_UNMATCHED_DST self.add(network_tagged_vlans_to_interface) @@ -606,24 +607,26 @@ def load_vlans(self): if interface_data["untagged_vlan"] and interface_data["untagged_vlan"].get("id") == "0": self.job.logger.warning("Interface with untagged vlan 0 found. Skipping untagged vlan load.") continue - try: - network_vlan = self.vlan( - adapter=self, - name=interface_data["untagged_vlan"]["name"], - vid=interface_data["untagged_vlan"]["id"], - location__name=location_names.get(hostname, ""), - ) - self.add(network_vlan) - except diffsync.exceptions.ObjectAlreadyExists: - continue - except Exception as err: # pylint: disable=broad-exception-caught - self._handle_general_load_exception( - error=err, - hostname=hostname, - data=device_data, - model_type="vlan", - ) - continue + + if interface_data["untagged_vlan"]: + try: + network_vlan = self.vlan( + adapter=self, + name=interface_data["untagged_vlan"]["name"], + vid=interface_data["untagged_vlan"]["id"], + location__name=location_names.get(hostname, ""), + ) + self.add(network_vlan) + except diffsync.exceptions.ObjectAlreadyExists: + continue + except Exception as err: # pylint: disable=broad-exception-caught + self._handle_general_load_exception( + error=err, + hostname=hostname, + data=device_data, + model_type="vlan", + ) + continue def load_vrfs(self): """Load vrfs into the Diffsync store.""" @@ -691,11 +694,12 @@ def load_tagged_vlans_to_interface(self): # for interface in device_data["interfaces"]: for interface_name, interface_data in device_data["interfaces"].items(): try: + sorted_tagged_vlans = sorted(interface_data["tagged_vlans"], key=lambda x: x["id"]) network_tagged_vlans_to_interface = self.tagged_vlans_to_interface( adapter=self, device__name=hostname, name=interface_name, - tagged_vlans=interface_data["tagged_vlans"], + tagged_vlans=sorted_tagged_vlans, ) self.add(network_tagged_vlans_to_interface) except Exception as err: # pylint: disable=broad-exception-caught @@ -710,7 +714,6 @@ def load_tagged_vlans_to_interface(self): def load_untagged_vlan_to_interface(self): """Load untagged vlan to interface assignments into the Diffsync store.""" for hostname, device_data in self.job.command_getter_result.items(): - # for interface in device_data["interfaces"]: for interface_name, interface_data in device_data["interfaces"].items(): try: if interface_data["untagged_vlan"] and interface_data["untagged_vlan"].get("id") == "0": @@ -758,7 +761,6 @@ def load_lag_to_interface(self): def load_vrf_to_interface(self): """Load Vrf to interface assignments into the Diffsync store.""" for hostname, device_data in self.job.command_getter_result.items(): - # for interface in device_data["interfaces"]: for interface_name, interface_data in device_data["interfaces"].items(): try: network_vrf_to_interface = self.vrf_to_interface( diff --git a/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py b/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py index e8ecdf59..1d1f25a6 100644 --- a/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py +++ b/nautobot_device_onboarding/diffsync/models/sync_network_data_models.py @@ -249,21 +249,31 @@ class SyncNetworkDataTaggedVlansToInterface(DiffSyncModel): tagged_vlans: Optional[list] = None @classmethod - def _get_and_assign_tagged_vlans(cls, adapter, attrs, interface): - """Loop through the tagged vlans for an interface and assign them.""" - for network_vlan in attrs["tagged_vlans"]: - try: - nautobot_vlan = VLAN.objects.get( - name=network_vlan["name"], vid=network_vlan["id"], location=interface.device.location - ) - interface.tagged_vlans.add(nautobot_vlan) - except ObjectDoesNotExist: - adapter.job.logger.error( - f"Failed to assign tagged vlan to {interface.device}:{interface}, unable to locate a vlan " - f"with attributes [name: {network_vlan['name']}, vid: {network_vlan['id']} " - f"location: {interface.device.location}]" - ) - raise diffsync_exceptions.ObjectNotCreated + def _get_and_assign_tagged_vlan(cls, adapter, network_vlan, interface, diff_method_type): + """Assign a tagged vlan to an interface.""" + try: + nautobot_vlan = VLAN.objects.get( + name=network_vlan["name"], vid=network_vlan["id"], location=interface.device.location + ) + interface.tagged_vlans.add(nautobot_vlan) + except ObjectDoesNotExist as err: + adapter.job.logger.error( + f"Failed to assign tagged vlan to interface: [{interface}] on device: [{interface.device}]. " + f"Unable to locate a vlan with attributes [{network_vlan}] at location: [{interface.device.location}]" + ) + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) + except Exception as err: + adapter.job.logger.error( + f"Failed to assign tagged vlan: [{network_vlan}] " + f"to interface: [{interface}]on device: [{interface.device}], {err}" + ) + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) @classmethod def create(cls, adapter, ids, attrs): @@ -271,43 +281,56 @@ def create(cls, adapter, ids, attrs): if attrs.get("tagged_vlans"): try: interface = Interface.objects.get(device__name=ids["device__name"], name=ids["name"]) - except ObjectDoesNotExist: + except ObjectDoesNotExist as err: adapter.job.logger.error( - f"Failed to assign tagged vlans {attrs['tagged_vlans']}. An interface with " - f"attributes: [device__name: {ids['device__name']} name: {ids['name']}] was not found." + f"Failed to assign tagged vlans {attrs['tagged_vlans']}. " + f"An interface with identifiers: [{ids}] was not found." ) - raise diffsync_exceptions.ObjectNotCreated - cls._get_and_assign_tagged_vlans(adapter, attrs, interface) - if interface: - try: - interface.validated_save() - except ValidationError as err: - adapter.job.logger.error( - f"Failed to assign tagged vlans {attrs['tagged_vlans']} to {interface} on {interface.device}, {err}" - ) - raise diffsync_exceptions.ObjectNotCreated + raise diffsync_exceptions.ObjectNotCreated(err) + for network_vlan in attrs["tagged_vlans"]: + cls._get_and_assign_tagged_vlan(adapter, network_vlan, interface, diff_method_type="create") + try: + interface.validated_save() + except ValidationError as err: + adapter.job.logger.error( + f"Failed to assign tagged vlans {attrs['tagged_vlans']} to {interface} on {interface.device}, {err}" + ) + raise diffsync_exceptions.ObjectNotCreated(err) return super().create(adapter, ids, attrs) def update(self, attrs): """Update tagged vlans.""" + # An interface must exist before vlan assignments can be updated + try: + interface = Interface.objects.get(**self.get_identifiers()) + except ObjectDoesNotExist: + self.adapter.job.logger.error( + f"Failed to update tagged vlans, an interface with identifiers: [{self.get_identifiers()}] was not found." + ) + raise diffsync_exceptions.ObjectNotUpdated + # Clear all tagged vlans from an interface and assign them based on what was loaded into the diffsync store if attrs.get("tagged_vlans"): + interface.tagged_vlans.clear() + for network_vlan in attrs["tagged_vlans"]: + self._get_and_assign_tagged_vlan(self.adapter, network_vlan, interface, diff_method_type="update") try: - interface = Interface.objects.get(**self.get_identifiers()) - interface.tagged_vlans.clear() - except ObjectDoesNotExist: + interface.validated_save() + except ValidationError as err: self.adapter.job.logger.error( - f"Failed to assign tagged vlans {attrs['tagged_vlans']}. An interface with " - f"attributes: [{self.get_identifiers}] was not found." + f"Failed to assign tagged vlans {attrs['tagged_vlans']} " + f"to interface: [{interface}] on device: [{interface.device}], {err}" ) raise diffsync_exceptions.ObjectNotUpdated - self._get_and_assign_tagged_vlans(self.adapter, attrs, interface) + # Clear all tagged vlans from an interface + if not attrs.get("tagged_vlans"): + interface.tagged_vlans.clear() try: interface.validated_save() except ValidationError as err: self.adapter.job.logger.error( - f"Failed to assign tagged vlans {attrs['tagged_vlans']} to {interface} on {interface.device}, {err}" + f"Failed to remove tagged vlans from interface: [{interface}] on device: [{interface.device}], {err}" ) - raise diffsync_exceptions.ObjectNotUpdated + raise diffsync_exceptions.ObjectNotUpdated(err) return super().update(attrs) @@ -324,7 +347,7 @@ class SyncNetworkDataUnTaggedVlanToInterface(DiffSyncModel): untagged_vlan: Optional[dict] = None @classmethod - def _get_and_assign_untagged_vlan(cls, adapter, attrs, interface): + def _get_and_assign_untagged_vlan(cls, adapter, attrs, interface, diff_method_type): """Assign an untagged vlan to an interface.""" try: vlan = VLAN.objects.get( @@ -333,13 +356,25 @@ def _get_and_assign_untagged_vlan(cls, adapter, attrs, interface): location=interface.device.location, ) interface.untagged_vlan = vlan - except ObjectDoesNotExist: + except ObjectDoesNotExist as err: adapter.job.logger.error( - f"Failed to assign untagged vlan to {interface.device}:{interface}, unable to locate a vlan with " - f"attributes [name: {attrs['untagged_vlan']['name']}, vid: {attrs['untagged_vlan']['id']} " - f"location: {interface.device.location}]" + f"Failed to assign untagged vlan to interface: [{interface}] on device: [{interface.device}]. " + f"Unable to locate a vlan with attributes: [{attrs['untagged_vlan']}] " + f" at location: {interface.device.location}]" ) - raise diffsync_exceptions.ObjectNotCreated + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) + except Exception as err: + adapter.job.logger.error( + f"Failed to assign untagged vlan: [{attrs['untagged_vlan']}] " + f"to interface: [{interface}] on device: [{interface.device}], {err}" + ) + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) @classmethod def create(cls, adapter, ids, attrs): @@ -349,37 +384,50 @@ def create(cls, adapter, ids, attrs): interface = Interface.objects.get(device__name=ids["device__name"], name=ids["name"]) except ObjectDoesNotExist: adapter.job.logger.error( - f"Failed to assign untagged vlan {attrs['untagged_vlan']}. An interface with " - f"attributes: [device__name: {ids['device__name']} name: {ids['name']}] was not found." + f"Failed to assign untagged vlan {attrs['untagged_vlan']}. " + f"An interface with identifiers: [{ids}] was not found." ) raise diffsync_exceptions.ObjectNotCreated - cls._get_and_assign_untagged_vlan(adapter, attrs, interface) + cls._get_and_assign_untagged_vlan(adapter, attrs, interface, diff_method_type="create") try: interface.validated_save() except ValidationError as err: adapter.job.logger.error( - f"Failed to assign untagged vlan {attrs['untagged_vlan']} to {interface} on {interface.device}, {err}" + f"Failed to assign untagged vlan {attrs['untagged_vlan']} " + f"to interface: [{interface}] on device: [{interface.device}], {err}" ) - raise diffsync_exceptions.ObjectNotCreated + raise diffsync_exceptions.ObjectNotCreated(err) return super().create(adapter, ids, attrs) def update(self, attrs): """Update the untagged vlan on an interface.""" + # An interface must exist before vlan assignments can be updated + try: + interface = Interface.objects.get(**self.get_identifiers()) + except ObjectDoesNotExist: + self.adapter.job.logger.error( + f"Failed to update untagged vlan, an interface with identifiers: [{self.get_identifiers()}] was not found." + ) + raise diffsync_exceptions.ObjectNotUpdated + # Assign an untagged vlan to an interface if attrs.get("untagged_vlan"): + self._get_and_assign_untagged_vlan(self.adapter, attrs, interface, diff_method_type="update") try: - interface = Interface.objects.get(**self.get_identifiers()) - except ObjectDoesNotExist: + interface.validated_save() + except ValidationError as err: self.adapter.job.logger.error( - f"Failed to assign untagged vlan {attrs['untagged_vlan']}. An interface with " - f"attributes: [{self.get_identifiers}] was not found." + f"Failed to assign untagged vlan {attrs['untagged_vlan']} " + f"to interface: [{interface}] on device: [{interface.device}], {err}" ) raise diffsync_exceptions.ObjectNotUpdated - self._get_and_assign_untagged_vlan(self.adapter, attrs, interface) + # Removed an untagged vlan from an interface + if not attrs.get("untagged_vlan"): + interface.untagged_vlan = None try: interface.validated_save() except ValidationError as err: self.adapter.job.logger.error( - f"Failed to assign untagged vlans {attrs['untagged_vlan']} to {interface} on {interface.device}, {err}" + f"Failed to remove untagged vlan from {interface} on {interface.device}, {err}" ) raise diffsync_exceptions.ObjectNotUpdated return super().update(attrs) @@ -397,70 +445,79 @@ class SyncNetworkDataLagToInterface(DiffSyncModel): lag__interface__name: Optional[str] = None - # TODO: move the create and update method locgic to a single utility function + @classmethod + def _get_and_assign_lag(cls, adapter, attrs, interface, diff_method_type): + """Assign a lag interface to an interface.""" + try: + lag_interface = Interface.objects.get( + name=attrs["lag__interface__name"], device=interface.device, type=InterfaceTypeChoices.TYPE_LAG + ) + interface.lag = lag_interface + except ObjectDoesNotExist as err: + adapter.job.logger.error( + f"Failed to assign lag to interface: [{interface}] on device: [{interface.device}]. " + f"Unable to locate a lag interface with name: [{attrs['lag__interface__name']}] " + f"on device: [{interface.device}]" + ) + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) + @classmethod def create(cls, adapter, ids, attrs): """Assign a lag to an interface.""" if attrs["lag__interface__name"]: try: interface = Interface.objects.get(device__name=ids["device__name"], name=ids["name"]) - except ObjectDoesNotExist: + except ObjectDoesNotExist as err: adapter.job.logger.error( - f"Failed to assign lag {attrs['lag__interface__name']}. An interface with " - f"attributes: [device__name: {ids['device__name']} name: {ids['name']}] was not found." + f"Failed to assign lag: [{attrs['lag__interface__name']}]. " + f"An interface with identifiers: [{ids}] was not found." ) - raise diffsync_exceptions.ObjectNotCreated - if interface: - try: - lag_interface = Interface.objects.get( - name=attrs["lag__interface__name"], device=interface.device, type=InterfaceTypeChoices.TYPE_LAG - ) - interface.lag = lag_interface - interface.validated_save() - except ObjectDoesNotExist: - adapter.job.logger.error( - f"Failed to assign lag to {interface.device}:{interface}, unable to locate a lag interface " - f"with attributes [name: {attrs['lag__interface__name']}, device: {interface.device.name} " - f"type: {InterfaceTypeChoices.TYPE_LAG}]" - ) - raise diffsync_exceptions.ObjectNotCreated - except ValidationError as err: - adapter.job.logger.error( - f"Failed to assign lag {lag_interface} to {interface} on {interface.device}, {err}" - ) - raise diffsync_exceptions.ObjectNotCreated + raise diffsync_exceptions.ObjectNotCreated(err) + cls._get_and_assign_lag(adapter, attrs, interface, diff_method_type="create") + try: + interface.validated_save() + except ValidationError as err: + adapter.job.logger.error( + f"Failed to assign lag: [{attrs['lag__interface__name']}] " + f"to interface: [{interface}] on device: [{interface.device}], {err}" + ) + raise diffsync_exceptions.ObjectNotCreated(err) return super().create(adapter, ids, attrs) def update(self, attrs): """Update and interface lag.""" + # An interface must exist before lag can be updated + try: + interface = Interface.objects.get(**self.get_identifiers()) + except ObjectDoesNotExist as err: + self.adapter.job.logger.error( + f"Failed to update lag, an interface with identifiers: [{self.get_identifiers()}] was not found." + ) + raise diffsync_exceptions.ObjectNotUpdated(err) + # Assign lag to an interface if attrs.get("lag__interface__name"): + self._get_and_assign_lag(self.adapter, attrs, interface, diff_method_type="update") try: - interface = Interface.objects.get(**self.get_identifiers()) - except ObjectDoesNotExist: + interface.validated_save() + except ValidationError as err: self.adapter.job.logger.error( - f"Failed to assign untagged lag {attrs['lag__interface__name']}. " - f"An interface with attributes: [{self.get_identifiers}] was not found." + f"Failed to assign lag: [{attrs['lag__interface__name']}] " + f"to interface: [{interface}] on device: [{interface.device}], {err}" ) - raise diffsync_exceptions.ObjectNotUpdated - try: - lag_interface = Interface.objects.get( - name=attrs["lag__interface__name"], device=interface.device, type=InterfaceTypeChoices.TYPE_LAG - ) - interface.lag = lag_interface - interface.validated_save() - except ObjectDoesNotExist: - self.adapter.job.logger.error( - f"Failed to assign lag to {interface}, unable to locate a lag interface " - f"with attributes [name: {attrs['lag__interface__name']}, device: {interface.device.name} " - f"type: {InterfaceTypeChoices.TYPE_LAG}]" - ) - raise diffsync_exceptions.ObjectNotUpdated - except ValidationError as err: - self.adapter.job.logger.error( - f"Failed to assign lag {lag_interface} to {interface} on {interface.device}, {err}" - ) - raise diffsync_exceptions.ObjectNotUpdated - + raise diffsync_exceptions.ObjectNotUpdated(err) + # Remove lag from an interface + if not attrs.get("lag__interface__name"): + interface.lag = None + try: + interface.validated_save() + except ValidationError as err: + self.adapter.job.logger.error( + f"Failed to remove lag from interface: [{interface}] on device: [{interface.device}], {err}" + ) + raise diffsync_exceptions.ObjectNotUpdated(err) return super().update(attrs) @@ -488,35 +545,42 @@ class SyncNetworkDataVrfToInterface(DiffSyncModel): vrf: Optional[dict] = None @classmethod - def _get_and_assign_vrf(cls, adapter, attrs, interface): + def _get_and_assign_vrf(cls, adapter, attrs, interface, diff_method_type): """Assign a vrf to an interface.""" try: vrf = VRF.objects.get( name=attrs["vrf"]["name"], namespace=adapter.job.namespace, ) - except ObjectDoesNotExist: + except ObjectDoesNotExist as err: adapter.job.logger.error( - f"Failed to assign vrf to {interface.device}:{interface}, unable to locate a vrf with attributes " - f"[name: {attrs['vrf']['name']} " - f"namespace: {adapter.job.namespace}]" + f"Failed to assign vrf to interface: [{interface}] on device: [{interface.device}]. " + f"Unable to locate a vrf with name: [{attrs['vrf']['name']}] in namespace: [{adapter.job.namespace}]" ) - raise diffsync_exceptions.ObjectNotCreated - except MultipleObjectsReturned: + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) + except MultipleObjectsReturned as err: adapter.job.logger.error( - f"Failed to assign vrf to {interface.device}:{interface}, there are multipple vrfs with attributes " - f"[name: {attrs['vrf']['name']} " - f"namespace: {adapter.job.namespace}]. " + f"Failed to assign vrf to interface: [{interface}] on device: [{interface.device}]. " + f"There are multipple vrfs with name: [{attrs['vrf']['name']}] in namespace: [{adapter.job.namespace}]. " "Unsure which to assign." ) - raise diffsync_exceptions.ObjectNotCreated + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) try: vrf.devices.add(interface.device) vrf.validated_save() + interface.vrf = vrf except Exception as err: - adapter.logger.error(f"Failed to assign device: {interface.device} to vrf: {vrf}, {err}") - raise diffsync_exceptions.ObjectNotCreated - interface.vrf = vrf + adapter.logger.error(f"Failed to assign device: [{interface.device}] to vrf: [{vrf}], {err}") + if diff_method_type == "create": + raise diffsync_exceptions.ObjectNotCreated(err) + if diff_method_type == "update": + raise diffsync_exceptions.ObjectNotUpdated(err) @classmethod def create(cls, adapter, ids, attrs): @@ -524,41 +588,53 @@ def create(cls, adapter, ids, attrs): if attrs.get("vrf"): try: interface = Interface.objects.get(device__name=ids["device__name"], name=ids["name"]) - except ObjectDoesNotExist: + except ObjectDoesNotExist as err: adapter.job.logger.error( - f"Failed to assign vrf {attrs['vrf']}. An interface with attributes: " - f"[device__name: {ids['device__name']} name: {ids['name']}] was not found." + f"Failed to assign vrf: [{attrs['vrf']['name']}]. " + f"An interface with identifiers: [{ids}] was not found." ) - raise diffsync_exceptions.ObjectNotCreated - cls._get_and_assign_vrf(adapter, attrs, interface) + raise diffsync_exceptions.ObjectNotCreated(err) + cls._get_and_assign_vrf(adapter, attrs, interface, diff_method_type="create") try: interface.validated_save() except ValidationError as err: adapter.job.logger.error( - f"Failed to assign vrf {attrs['vrf']} to {interface} on {interface.device}, {err}" + f"Failed to assign vrf: [{attrs['vrf']}] " + f"to interface: [{interface}] on device: [{interface.device}], {err}" ) - raise diffsync_exceptions.ObjectNotCreated + raise diffsync_exceptions.ObjectNotCreated(err) return super().create(adapter, ids, attrs) def update(self, attrs): """Update the vrf on an interface.""" + # An interface must exist before vrf can be updated + try: + interface = Interface.objects.get(**self.get_identifiers()) + except ObjectDoesNotExist as err: + self.adapter.job.logger.error( + f"Failed to update vrf, an interface with identifiers: [{self.get_identifiers()}] was not found." + ) + raise diffsync_exceptions.ObjectNotUpdated(err) if attrs.get("vrf"): + # Assign a vrf to an interface + self._get_and_assign_vrf(self.adapter, attrs, interface, diff_method_type="update") try: - interface = Interface.objects.get(**self.get_identifiers()) - except ObjectDoesNotExist: + interface.validated_save() + except ValidationError as err: self.adapter.job.logger.error( - f"Failed to assign vrf {attrs['vrf']['name']}. " - f"An interface with attributes: [{self.get_identifiers}] was not found." + f"Failed to assign vrf: [{attrs['vrf']}] " + f"to interface: [{interface}] on device: [{interface.device}], {err}" ) - raise diffsync_exceptions.ObjectNotUpdated - self._get_and_assign_vrf(self.adapter, attrs, interface) + raise diffsync_exceptions.ObjectNotUpdated(err) + if not attrs.get("vrf"): + interface.vrf = None try: interface.validated_save() except ValidationError as err: self.adapter.job.logger.error( - f"Failed to assign vrf {attrs['vrf']} to {interface} on {interface.device}, {err}" + f"Failed to remove vrf from interface: [{interface}] on device: [{interface.device}], {err}" ) - raise diffsync_exceptions.ObjectNotUpdated + raise diffsync_exceptions.ObjectNotUpdated(err) return super().update(attrs) From 7fcf6f1a4f56884eae6e688a70a4dccf37931aec Mon Sep 17 00:00:00 2001 From: Michael Sheinberg Date: Mon, 10 Feb 2025 13:00:28 -0800 Subject: [PATCH 5/7] Ensure that 'connectivity_test' kwargs always passed downstream (#314) --- changes/313.fixed | 1 + nautobot_device_onboarding/jobs.py | 50 +++++++++++-------- .../nornir_plays/command_getter.py | 2 +- .../tests/fixtures/all_required_fields.csv | 2 + nautobot_device_onboarding/tests/test_jobs.py | 50 ++++++++++++++++++- 5 files changed, 81 insertions(+), 24 deletions(-) create mode 100644 changes/313.fixed create mode 100644 nautobot_device_onboarding/tests/fixtures/all_required_fields.csv diff --git a/changes/313.fixed b/changes/313.fixed new file mode 100644 index 00000000..46303025 --- /dev/null +++ b/changes/313.fixed @@ -0,0 +1 @@ +Fixed issue running a sync job via CSV would raise an exception. diff --git a/nautobot_device_onboarding/jobs.py b/nautobot_device_onboarding/jobs.py index 25b0ebd1..60ca84bd 100755 --- a/nautobot_device_onboarding/jobs.py +++ b/nautobot_device_onboarding/jobs.py @@ -488,6 +488,11 @@ def run( self.memory_profiling = memory_profiling self.debug = debug + self.job_result.task_kwargs = { + "debug": debug, + "connectivity_test": kwargs["connectivity_test"], + } + if csv_file: self.processed_csv_data = self._process_csv_data(csv_file=csv_file) if self.processed_csv_data: @@ -496,10 +501,11 @@ def run( for ip_address in self.processed_csv_data: self.ip_addresses.append(ip_address) # prepare the task_kwargs needed by the CommandGetterDO job - self.job_result.task_kwargs = { - "debug": debug, - "csv_file": self.task_kwargs_csv_data, - } + self.job_result.task_kwargs.update( + { + "csv_file": self.task_kwargs_csv_data, + } + ) else: raise ValidationError(message="CSV check failed. No devices will be synced.") @@ -541,24 +547,24 @@ def run( self.secrets_group = secrets_group self.platform = platform - self.job_result.task_kwargs = { - "debug": debug, - "location": location, - "namespace": namespace, - "ip_addresses": ip_addresses, - "set_mgmt_only": set_mgmt_only, - "update_devices_without_primary_ip": update_devices_without_primary_ip, - "device_role": device_role, - "device_status": device_status, - "interface_status": interface_status, - "ip_address_status": ip_address_status, - "port": port, - "timeout": timeout, - "secrets_group": secrets_group, - "platform": platform, - "csv_file": "", - "connectivity_test": kwargs["connectivity_test"], - } + self.job_result.task_kwargs.update( + { + "location": location, + "namespace": namespace, + "ip_addresses": ip_addresses, + "set_mgmt_only": set_mgmt_only, + "update_devices_without_primary_ip": update_devices_without_primary_ip, + "device_role": device_role, + "device_status": device_status, + "interface_status": interface_status, + "ip_address_status": ip_address_status, + "port": port, + "timeout": timeout, + "secrets_group": secrets_group, + "platform": platform, + "csv_file": "", + } + ) super().run(dryrun, memory_profiling, *args, **kwargs) diff --git a/nautobot_device_onboarding/nornir_plays/command_getter.py b/nautobot_device_onboarding/nornir_plays/command_getter.py index 07255690..fc2e0fb4 100755 --- a/nautobot_device_onboarding/nornir_plays/command_getter.py +++ b/nautobot_device_onboarding/nornir_plays/command_getter.py @@ -118,7 +118,7 @@ def netmiko_send_commands( return Result( host=task.host, result=f"{task.host.name} has missing definitions in command_mapper YAML file.", failed=True ) - if orig_job_kwargs["connectivity_test"]: + if orig_job_kwargs.get("connectivity_test", False): if not tcp_ping(task.host.hostname, task.host.port): return Result( host=task.host, result=f"{task.host.name} failed connectivity check via tcp_ping.", failed=True diff --git a/nautobot_device_onboarding/tests/fixtures/all_required_fields.csv b/nautobot_device_onboarding/tests/fixtures/all_required_fields.csv new file mode 100644 index 00000000..9c4e7d46 --- /dev/null +++ b/nautobot_device_onboarding/tests/fixtures/all_required_fields.csv @@ -0,0 +1,2 @@ +ip_address_host,location_name,device_role_name,namespace,device_status_name,interface_status_name,ip_address_status_name,secrets_group_name,set_mgmt_only,update_devices_without_primary_ip,port,timeout +172.23.0.8,Site A Parent,Network,Global,Active,Active,Active,test secrets group,True,False,22,30 diff --git a/nautobot_device_onboarding/tests/test_jobs.py b/nautobot_device_onboarding/tests/test_jobs.py index bb81d950..023fbc1e 100644 --- a/nautobot_device_onboarding/tests/test_jobs.py +++ b/nautobot_device_onboarding/tests/test_jobs.py @@ -1,11 +1,13 @@ """Test Jobs.""" -from unittest.mock import patch +from unittest.mock import ANY, patch +from django.core.files.base import ContentFile from nautobot.apps.testing import create_job_result_and_run_job from nautobot.core.testing import TransactionTestCase from nautobot.dcim.models import Device, Interface, Manufacturer, Platform from nautobot.extras.choices import JobResultStatusChoices +from nautobot.extras.models import FileProxy from nautobot_device_onboarding import jobs from nautobot_device_onboarding.tests import utils @@ -120,6 +122,52 @@ def test_process_csv_data__empty_file(self): processed_csv_data = onboarding_job._process_csv_data(csv_file=csv_file) # pylint: disable=protected-access self.assertEqual(processed_csv_data, None) + @patch("nautobot_device_onboarding.diffsync.adapters.sync_devices_adapters.sync_devices_command_getter") + @patch.dict("os.environ", {"DEVICE_USER": "test_user", "DEVICE_PASS": "test_password"}) + def test_csv_process_pass_connectivity_test_flag(self, mock_sync_devices_command_getter): + """Ensure the 'connectivity_test' option is passed to the command_getter when a CSV is in-play.""" + with open("nautobot_device_onboarding/tests/fixtures/all_required_fields.csv", "rb") as csv_file: + csv_contents = csv_file.read() + + job_form_inputs = { + "debug": True, + "connectivity_test": "AnyWackyValueHere", + "dryrun": False, + "csv_file": FileProxy.objects.create( + name="onboarding.csv", file=ContentFile(csv_contents, name="onboarding.csv") + ).id, + "location": None, + "namespace": None, + "ip_addresses": None, + "port": None, + "timeout": None, + "set_mgmt_only": None, + "update_devices_without_primary_ip": None, + "device_role": None, + "device_status": None, + "interface_status": None, + "ip_address_status": None, + "secrets_group": None, + "platform": None, + "memory_profiling": False, + } + + create_job_result_and_run_job( + module="nautobot_device_onboarding.jobs", name="SSOTSyncDevices", **job_form_inputs + ) + self.assertEqual( + mock_sync_devices_command_getter.mock_calls[0].args, + ( + ANY, + 10, + { + "debug": True, + "connectivity_test": "AnyWackyValueHere", + "csv_file": {"172.23.0.8": {"port": 22, "timeout": 30, "secrets_group": ANY, "platform": ""}}, + }, + ), + ) + class SSOTSyncNetworkDataTestCase(TransactionTestCase): """Test SSOTSyncNetworkData class.""" From 97d1d5772b50b81ee62a19114a47f353cb914dc5 Mon Sep 17 00:00:00 2001 From: Michael Sheinberg Date: Tue, 11 Feb 2025 07:15:09 -0800 Subject: [PATCH 6/7] Expand tests to cover ssh logic (#315) * Expand tests to cover ssh logic --------- --- .github/workflows/ci.yml | 3 - changes/315.housekeeping | 1 + .../nornir_plays/formatter.py | 8 ++- .../tests/fakenos/custom_ios.yaml | 69 +++++++++++++++++++ nautobot_device_onboarding/tests/test_jobs.py | 59 ++++++++++++++++ poetry.lock | 37 +++++++++- pyproject.toml | 2 + 7 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 changes/315.housekeeping create mode 100644 nautobot_device_onboarding/tests/fakenos/custom_ios.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 135a19a5..30191f55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,9 +146,6 @@ jobs: - python-version: "3.11" db-backend: "postgresql" nautobot-version: "2.2.3" - # - python-version: "3.12" - # db-backend: "mysql" - # nautobot-version: "stable" runs-on: "ubuntu-22.04" env: INVOKE_NAUTOBOT_DEVICE_ONBOARDING_PYTHON_VER: "${{ matrix.python-version }}" diff --git a/changes/315.housekeeping b/changes/315.housekeeping new file mode 100644 index 00000000..c369a8d7 --- /dev/null +++ b/changes/315.housekeeping @@ -0,0 +1 @@ +Added fake SSH devices to tests to increase coverage. diff --git a/nautobot_device_onboarding/nornir_plays/formatter.py b/nautobot_device_onboarding/nornir_plays/formatter.py index d62620e5..1752c567 100755 --- a/nautobot_device_onboarding/nornir_plays/formatter.py +++ b/nautobot_device_onboarding/nornir_plays/formatter.py @@ -4,6 +4,7 @@ import logging from json.decoder import JSONDecodeError +import jinja2 from django.template import engines from django.utils.module_loading import import_string from jdiff import extract_data_from_json @@ -106,7 +107,12 @@ def extract_and_post_process(parsed_command_output, yaml_command_element, j2_dat # j2 context data changes obj(hostname) -> extracted_value for post_processor j2_data_context["obj"] = extracted_value template = j2_env.from_string(yaml_command_element["post_processor"]) - extracted_processed = template.render(**j2_data_context) + try: + extracted_processed = template.render(**j2_data_context) + except jinja2.exceptions.UndefinedError: + raise ValueError( + f"Failure Jinja parsing, context: {j2_data_context}. processor: {yaml_command_element['post_processor']}" + ) else: extracted_processed = extracted_value post_processed_data = normalize_processed_data(extracted_processed, iter_type) diff --git a/nautobot_device_onboarding/tests/fakenos/custom_ios.yaml b/nautobot_device_onboarding/tests/fakenos/custom_ios.yaml new file mode 100644 index 00000000..c9b71ebc --- /dev/null +++ b/nautobot_device_onboarding/tests/fakenos/custom_ios.yaml @@ -0,0 +1,69 @@ +--- +name: "tweaked_cisco_ios" +initial_prompt: "{base_prompt}>" +enable_prompt: "{base_prompt}#" +config_prompt: "{base_prompt}(config)#" +commands: + enable: + output: "null" + new_prompt: "{base_prompt}#" + help: "enter enable mode" + prompt: "{base_prompt}>" + show interfaces: + output: + "TenGigabitEthernet1/1/15 is up, line protocol is down (disabled)\n Hardware\ + \ is Ten Gigabit Ethernet Port, address is 6c41.6aba.b44e (bia 6c41.6aba.b44e)\n\ + \ Internet address is 127.0.0.1/32\n MTU 1500 bytes, BW 10000000 Kbit/sec,\ + \ DLY 10 usec,\n reliability 255/255, txload 1/255, rxload 1/255\n Encapsulation\ + \ ARPA, loopback not set\n Keepalive set (10 sec)\n Full-duplex, Auto-speed,\ + \ link type is auto, media type is No XCVR\n input flow-control is off, output\ + \ flow-control is off\n ARP type: ARPA, ARP Timeout 04:00:00\n Last input\ + \ never, output never, output hang never\n Last clearing of \"show interface\"\ + \ counters never\n Input queue: 0/2000/0/0 (size/max/drops/flushes); Total\ + \ output drops: 0\n Queueing strategy: fifo\n Output queue: 0/40 (size/max)\n\ + \ 5 minute input rate 0 bits/sec, 0 packets/sec\n 5 minute output rate 0\ + \ bits/sec, 0 packets/sec\n 0 packets input, 0 bytes, 0 no buffer\n \ + \ Received 0 broadcasts (0 multicasts)\n 0 runts, 0 giants, 0 throttles\n\ + \ 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored\n 0 input packets\ + \ with dribble condition detected\n 0 packets output, 0 bytes, 0 underruns\n\ + \ 0 output errors, 0 collisions, 1 interface resets\n 0 unknown protocol\ + \ drops\n 0 babbles, 0 late collision, 0 deferred\n 0 lost carrier,\ + \ 0 no carrier\n 0 output buffer failures, 0 output buffers swapped out" + help: "execute the command 'show interfaces'" + prompt: + - "{base_prompt}>" + - "{base_prompt}#" + show version: + output: + "Cisco IOS Software, IOSv Software (VIOS-ADVENTERPRISEK9-M), Version 15.8(3)M2,\ + \ RELEASE SOFTWARE (fc2)\nTechnical Support: http://www.cisco.com/techsupport\n\ + \ Copyright (c) 1986-2019 by Cisco Systems, Inc.\nCompiled Thu 28-Mar-19 14:06\ + \ by prod_rel_team\n\n\nROM: Bootstrap program is IOSv\n\nfake-ios-01 uptime is 1\ + \ week, 3 days, 16 hours, 11 minutes\nSystem returned to ROM by reload\nSystem\ + \ image file is \"flash0:/vios-adventerprisek9-m\"\nLast reload reason: Unknown\ + \ reason\n \n\n\nThis product contains cryptographic features and is subject\ + \ to United\n States and local country laws governing import, export, transfer\ + \ and\nuse. Delivery of Cisco cryptographic products does not imply\nthird-party\ + \ authority to import, export, distribute or use encryption.\nImporters, exporters,\ + \ distributors and users are responsible for\ncompliance with U.S. and local\ + \ country laws. By using this product you\nagree to comply with applicable laws\ + \ and regulations. If you are unable\nto comply with U.S. and local laws, return\ + \ this product immediately.\n \nA summary of U.S. laws governing Cisco cryptographic\ + \ products may be found at:\nhttp://www.cisco.com/wwl/export/crypto/tool/stqrg.html\n\ + \nIf you require further assistance please contact us by sending email to\n\ + export@cisco.com.\n \nCisco IOSv (revision 1.0) with with 460137K/62464K bytes\ + \ of memory.\nProcessor board ID 991UCMIHG4UAJ1J010CQG\n4 Gigabit Ethernet interfaces\n\ + DRAM configuration is 72 bits wide with parity disabled.\n256K bytes of non-volatile\ + \ configuration memory.\n2097152K bytes of ATA System CompactFlash 0 (Read/Write)\n\ + 0K bytes of ATA CompactFlash 1 (Read/Write)\n11217K bytes of ATA CompactFlash\ + \ 2 (Read/Write)\n 0K bytes of ATA CompactFlash 3 (Read/Write)\n\n\n\nConfiguration\ + \ register is 0x0" + help: "execute the command 'show version'" + prompt: + - "{base_prompt}>" + - "{base_prompt}#" + _default_: + output: "% Invalid input detected at '^' marker." + help: "Output to print for unknown commands" + terminal width 511: {"output":"", "help":"Set terminal width to 511"} + terminal length 0: {"output":"", "help":"Set terminal length to 0"} diff --git a/nautobot_device_onboarding/tests/test_jobs.py b/nautobot_device_onboarding/tests/test_jobs.py index 023fbc1e..b2fd19cb 100644 --- a/nautobot_device_onboarding/tests/test_jobs.py +++ b/nautobot_device_onboarding/tests/test_jobs.py @@ -1,13 +1,18 @@ """Test Jobs.""" +import os from unittest.mock import ANY, patch from django.core.files.base import ContentFile +from django.test import override_settings +from fakenos import FakeNOS +from fakenos.core.host import Host from nautobot.apps.testing import create_job_result_and_run_job from nautobot.core.testing import TransactionTestCase from nautobot.dcim.models import Device, Interface, Manufacturer, Platform from nautobot.extras.choices import JobResultStatusChoices from nautobot.extras.models import FileProxy +from nautobot.ipam.models import IPAddress from nautobot_device_onboarding import jobs from nautobot_device_onboarding.tests import utils @@ -174,6 +179,10 @@ class SSOTSyncNetworkDataTestCase(TransactionTestCase): databases = ("default", "job_logs") + @classmethod + def setUpClass(cls): + super().setUpClass() + def setUp(self): # pylint: disable=invalid-name """Initialize test case.""" # Setup Nautobot Objects @@ -236,3 +245,53 @@ def test_sync_network_data__success(self, device_data): if interface_data["vrf"]: self.assertEqual(interface.vrf.name, interface_data["vrf"]["name"]) + + @override_settings(CELERY_TASK_ALWAYS_EAGER=True) + @patch.dict("os.environ", {"DEVICE_USER": "admin", "DEVICE_PASS": "admin"}) + def test_sync_network_devices_with_full_ssh(self): + """Use the fakeNOS library to expand test coverage to cover SSH connectivity.""" + job_form_inputs = { + "debug": False, + "connectivity_test": False, + "dryrun": False, + "csv_file": None, + "location": self.testing_objects["location"].pk, + "namespace": self.testing_objects["namespace"].pk, + "ip_addresses": "127.0.0.1", + "port": 6222, + "timeout": 30, + "set_mgmt_only": True, + "update_devices_without_primary_ip": True, + "device_role": self.testing_objects["device_role"].pk, + "device_status": self.testing_objects["status"].pk, + "interface_status": self.testing_objects["status"].pk, + "ip_address_status": self.testing_objects["status"].pk, + "default_prefix_status": self.testing_objects["status"].pk, + "secrets_group": self.testing_objects["secrets_group"].pk, + "platform": self.testing_objects["platform_1"].pk, + "memory_profiling": False, + } + current_file_path = os.path.dirname(os.path.abspath(__file__)) + fake_ios_inventory = { + "hosts": { + "dev1": { + "username": "admin", + "password": "admin", + "platform": "tweaked_cisco_ios", + "port": 6222, + } + } + } + # This is hacky, theres clearly a bug in the fakenos library + # https://github.com/fakenos/fakenos/issues/19 + with patch.object(Host, "_check_if_platform_is_supported"): + with FakeNOS( + inventory=fake_ios_inventory, plugins=[os.path.join(current_file_path, "fakenos/custom_ios.yaml")] + ): + create_job_result_and_run_job( + module="nautobot_device_onboarding.jobs", name="SSOTSyncDevices", **job_form_inputs + ) + + newly_imported_device = Device.objects.get(name="fake-ios-01") + self.assertEqual(str(IPAddress.objects.get(id=newly_imported_device.primary_ip4_id)), "127.0.0.1/32") + self.assertEqual(newly_imported_device.serial, "991UCMIHG4UAJ1J010CQG") diff --git a/poetry.lock b/poetry.lock index b02bcf1d..12dacbec 100644 --- a/poetry.lock +++ b/poetry.lock @@ -816,6 +816,16 @@ files = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] +[[package]] +name = "detect" +version = "2020.12.3" +description = "detect OS and Python versions" +optional = false +python-versions = "*" +files = [ + {file = "detect-2020.12.3.tar.gz", hash = "sha256:eecd6c41c17072b4db8dbfa850d979bda40b33b4f349ab4378205bceb74d712e"}, +] + [[package]] name = "diffsync" version = "2.0.1" @@ -1353,6 +1363,30 @@ files = [ [package.extras] tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +[[package]] +name = "fakenos" +version = "1.1.0" +description = "Fake Network Operating System" +optional = false +python-versions = ">=3.8,<3.13" +files = [] +develop = false + +[package.dependencies] +detect = "2020.12.*" +paramiko = "<4.0" +pydantic = "<3.0" +pyyaml = "<7.0" + +[package.extras] +test = [] + +[package.source] +type = "git" +url = "https://github.com/fakenos/fakenos" +reference = "master" +resolved_reference = "b465bc28b478cf72582191ee77eb8e968864a0da" + [[package]] name = "future" version = "1.0.0" @@ -3092,7 +3126,6 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, - {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, @@ -4791,4 +4824,4 @@ all = [] [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.13" -content-hash = "8a645ab31340a5d29395f4c3f60cdefd86914701fe3464c2ec32607294713ab7" +content-hash = "4c234809ca69ce7c409b94934bbc84377e8b93bff549d7b4ee92a7f22ce424a0" diff --git a/pyproject.toml b/pyproject.toml index f8a02996..73616547 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,8 @@ mkdocstrings = "0.25.2" mkdocstrings-python = "1.10.8" griffe = "1.1.1" towncrier = "~23.6.0" +# Used in integration tests +fakenos = { git = "https://github.com/fakenos/fakenos", branch = "master" } [tool.poetry.extras] all = [ From d873f78d440467a3a01a4e5e8147870a7c40b3c2 Mon Sep 17 00:00:00 2001 From: scetron Date: Tue, 11 Feb 2025 10:40:56 -0500 Subject: [PATCH 7/7] Release 4.2.1 --- changes/306.fixed | 1 - changes/307.dependencies | 1 - changes/311.fixed | 1 - changes/313.fixed | 1 - changes/315.housekeeping | 1 - docs/admin/release_notes/version_4.2.md | 22 +- poetry.lock | 537 ++++++++++++------------ pyproject.toml | 2 +- 8 files changed, 298 insertions(+), 268 deletions(-) delete mode 100644 changes/306.fixed delete mode 100644 changes/307.dependencies delete mode 100644 changes/311.fixed delete mode 100644 changes/313.fixed delete mode 100644 changes/315.housekeeping diff --git a/changes/306.fixed b/changes/306.fixed deleted file mode 100644 index a1a7b17f..00000000 --- a/changes/306.fixed +++ /dev/null @@ -1 +0,0 @@ -Fixed error with logging message in SyncNetworkDataIPAddress.update() \ No newline at end of file diff --git a/changes/307.dependencies b/changes/307.dependencies deleted file mode 100644 index dceedf73..00000000 --- a/changes/307.dependencies +++ /dev/null @@ -1 +0,0 @@ -Updated ntc-templates to 7.x \ No newline at end of file diff --git a/changes/311.fixed b/changes/311.fixed deleted file mode 100644 index d459f9a8..00000000 --- a/changes/311.fixed +++ /dev/null @@ -1 +0,0 @@ -Fixed issue with Lags, VRFs and Untagged Vlans not being removed from interfaces \ No newline at end of file diff --git a/changes/313.fixed b/changes/313.fixed deleted file mode 100644 index 46303025..00000000 --- a/changes/313.fixed +++ /dev/null @@ -1 +0,0 @@ -Fixed issue running a sync job via CSV would raise an exception. diff --git a/changes/315.housekeeping b/changes/315.housekeeping deleted file mode 100644 index c369a8d7..00000000 --- a/changes/315.housekeeping +++ /dev/null @@ -1 +0,0 @@ -Added fake SSH devices to tests to increase coverage. diff --git a/docs/admin/release_notes/version_4.2.md b/docs/admin/release_notes/version_4.2.md index 692233fd..a94e3e98 100755 --- a/docs/admin/release_notes/version_4.2.md +++ b/docs/admin/release_notes/version_4.2.md @@ -7,8 +7,26 @@ Versioning](https://semver.org/spec/v2.0.0.html). ## Release Overview -- Major features or milestones -- Changes to compatibility with Nautobot and/or other apps, libraries etc. +- [#200](https://github.com/nautobot/nautobot-app-device-onboarding/issues/200) - Added basic connectivity checker using Netutils tcp_ping method. +- [#274](https://github.com/nautobot/nautobot-app-device-onboarding/issues/274) - Added TTP Parser support. +- [#274](https://github.com/nautobot/nautobot-app-device-onboarding/issues/274) - Added Sync Device from Network support for Palo Alto Panos. + +## [v4.2.1 (2025-02-11)](https://github.com/nautobot/nautobot-app-device-onboarding/releases/tag/v4.2.1) + +### Fixed + +- [#306](https://github.com/nautobot/nautobot-app-device-onboarding/issues/306) - Fixed error with logging message in SyncNetworkDataIPAddress.update() +- [#311](https://github.com/nautobot/nautobot-app-device-onboarding/issues/311) - Fixed issue with Lags, VRFs and Untagged Vlans not being removed from interfaces +- [#313](https://github.com/nautobot/nautobot-app-device-onboarding/issues/313) - Fixed issue running a sync job via CSV would raise an exception. + +### Dependencies + +- [#307](https://github.com/nautobot/nautobot-app-device-onboarding/issues/307) - Updated ntc-templates to 7.x + +### Housekeeping + +- [#315](https://github.com/nautobot/nautobot-app-device-onboarding/issues/315) - Added fake SSH devices to tests to increase coverage. + ## [v4.2.0 (2025-01-17)](https://github.com/nautobot/nautobot-app-device-onboarding/releases/tag/v4.2.0) diff --git a/poetry.lock b/poetry.lock index 12dacbec..5e8f2d86 100644 --- a/poetry.lock +++ b/poetry.lock @@ -151,13 +151,13 @@ files = [ [[package]] name = "attrs" -version = "24.3.0" +version = "25.1.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" files = [ - {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, - {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, + {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, + {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, ] [package.extras] @@ -185,20 +185,20 @@ tomli = {version = "*", markers = "python_version < \"3.11\""} [[package]] name = "babel" -version = "2.16.0" +version = "2.17.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" files = [ - {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, - {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, + {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, + {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, ] [package.dependencies] pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} [package.extras] -dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +dev = ["backports.zoneinfo", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata"] [[package]] name = "backcall" @@ -349,13 +349,13 @@ zstd = ["zstandard (==0.22.0)"] [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, - {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, + {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, + {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] @@ -864,13 +864,13 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "django" -version = "4.2.17" +version = "4.2.19" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.8" files = [ - {file = "Django-4.2.17-py3-none-any.whl", hash = "sha256:3a93350214ba25f178d4045c0786c61573e7dbfa3c509b3551374f1e11ba8de0"}, - {file = "Django-4.2.17.tar.gz", hash = "sha256:6b56d834cc94c8b21a8f4e775064896be3b4a4ca387f2612d4406a5927cd2fdc"}, + {file = "Django-4.2.19-py3-none-any.whl", hash = "sha256:a104e13f219fc55996a4e416ef7d18ab4eeb44e0aa95174c192f16cda9f94e75"}, + {file = "Django-4.2.19.tar.gz", hash = "sha256:6c833be4b0ca614f0a919472a1028a3bbdeb6f056fa04023aeb923346ba2c306"}, ] [package.dependencies] @@ -1306,13 +1306,13 @@ sidecar = ["drf-spectacular-sidecar"] [[package]] name = "drf-spectacular-sidecar" -version = "2024.12.1" +version = "2025.2.1" description = "Serve self-contained distribution builds of Swagger UI and Redoc with Django" optional = false python-versions = ">=3.6" files = [ - {file = "drf_spectacular_sidecar-2024.12.1-py3-none-any.whl", hash = "sha256:e30821d150d29294f3be2018aab31b55cd724158e9e690b51a215264751aa8c7"}, - {file = "drf_spectacular_sidecar-2024.12.1.tar.gz", hash = "sha256:6be31df38bcf95681224b6550faa9344ee6dd5360dcf2b44afcc3f7460385613"}, + {file = "drf_spectacular_sidecar-2025.2.1-py3-none-any.whl", hash = "sha256:674e1336810c7cf117442300b5c213c4fee1e984ba48689502c947a6ecd25d0c"}, + {file = "drf_spectacular_sidecar-2025.2.1.tar.gz", hash = "sha256:ca9507c5fe708680d6b8eda96928f3cf3ffc07e8d67678778bcd2e80f9f2baae"}, ] [package.dependencies] @@ -1351,13 +1351,13 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "2.1.0" +version = "2.2.0" description = "Get the currently executing AST node of a frame, and other information" optional = false python-versions = ">=3.8" files = [ - {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, - {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, + {file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"}, + {file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"}, ] [package.extras] @@ -1975,157 +1975,157 @@ files = [ [[package]] name = "lxml" -version = "5.3.0" +version = "5.3.1" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" files = [ - {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, - {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, - {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, - {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, - {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, - {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, - {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, - {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, - {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, - {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, - {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, - {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, - {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, - {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, - {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, - {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, - {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, - {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, - {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, - {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, - {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, - {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, - {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, - {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, - {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, - {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, - {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, - {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, - {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, - {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, - {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, - {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, - {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, - {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, - {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, - {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, - {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, - {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, - {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, - {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, - {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, - {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, - {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, - {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, - {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, - {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, - {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, - {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, - {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, - {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, - {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4058f16cee694577f7e4dd410263cd0ef75644b43802a689c2b3c2a7e69453b"}, + {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:364de8f57d6eda0c16dcfb999af902da31396949efa0e583e12675d09709881b"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:528f3a0498a8edc69af0559bdcf8a9f5a8bf7c00051a6ef3141fdcf27017bbf5"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4743e30d6f5f92b6d2b7c86b3ad250e0bad8dee4b7ad8a0c44bfb276af89a3"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b5d7f8acf809465086d498d62a981fa6a56d2718135bb0e4aa48c502055f5c"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:928e75a7200a4c09e6efc7482a1337919cc61fe1ba289f297827a5b76d8969c2"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a997b784a639e05b9d4053ef3b20c7e447ea80814a762f25b8ed5a89d261eac"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7b82e67c5feb682dbb559c3e6b78355f234943053af61606af126df2183b9ef9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:f1de541a9893cf8a1b1db9bf0bf670a2decab42e3e82233d36a74eda7822b4c9"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:de1fc314c3ad6bc2f6bd5b5a5b9357b8c6896333d27fdbb7049aea8bd5af2d79"}, + {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c0536bd9178f754b277a3e53f90f9c9454a3bd108b1531ffff720e082d824f2"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68018c4c67d7e89951a91fbd371e2e34cd8cfc71f0bb43b5332db38497025d51"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa826340a609d0c954ba52fd831f0fba2a4165659ab0ee1a15e4aac21f302406"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:796520afa499732191e39fc95b56a3b07f95256f2d22b1c26e217fb69a9db5b5"}, + {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3effe081b3135237da6e4c4530ff2a868d3f80be0bda027e118a5971285d42d0"}, + {file = "lxml-5.3.1-cp310-cp310-win32.whl", hash = "sha256:a22f66270bd6d0804b02cd49dae2b33d4341015545d17f8426f2c4e22f557a23"}, + {file = "lxml-5.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bcfadea3cdc68e678d2b20cb16a16716887dd00a881e16f7d806c2138b8ff0c"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e220f7b3e8656ab063d2eb0cd536fafef396829cafe04cb314e734f87649058f"}, + {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f2cfae0688fd01f7056a17367e3b84f37c545fb447d7282cf2c242b16262607"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67d2f8ad9dcc3a9e826bdc7802ed541a44e124c29b7d95a679eeb58c1c14ade8"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db0c742aad702fd5d0c6611a73f9602f20aec2007c102630c06d7633d9c8f09a"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:198bb4b4dd888e8390afa4f170d4fa28467a7eaf857f1952589f16cfbb67af27"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2a3e412ce1849be34b45922bfef03df32d1410a06d1cdeb793a343c2f1fd666"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8969dbc8d09d9cd2ae06362c3bad27d03f433252601ef658a49bd9f2b22d79"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5be8f5e4044146a69c96077c7e08f0709c13a314aa5315981185c1f00235fe65"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:133f3493253a00db2c870d3740bc458ebb7d937bd0a6a4f9328373e0db305709"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:52d82b0d436edd6a1d22d94a344b9a58abd6c68c357ed44f22d4ba8179b37629"}, + {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b6f92e35e2658a5ed51c6634ceb5ddae32053182851d8cad2a5bc102a359b33"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:203b1d3eaebd34277be06a3eb880050f18a4e4d60861efba4fb946e31071a295"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:155e1a5693cf4b55af652f5c0f78ef36596c7f680ff3ec6eb4d7d85367259b2c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22ec2b3c191f43ed21f9545e9df94c37c6b49a5af0a874008ddc9132d49a2d9c"}, + {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eda194dd46e40ec745bf76795a7cccb02a6a41f445ad49d3cf66518b0bd9cff"}, + {file = "lxml-5.3.1-cp311-cp311-win32.whl", hash = "sha256:fb7c61d4be18e930f75948705e9718618862e6fc2ed0d7159b2262be73f167a2"}, + {file = "lxml-5.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c809eef167bf4a57af4b03007004896f5c60bd38dc3852fcd97a26eae3d4c9e6"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e69add9b6b7b08c60d7ff0152c7c9a6c45b4a71a919be5abde6f98f1ea16421c"}, + {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e52e1b148867b01c05e21837586ee307a01e793b94072d7c7b91d2c2da02ffe"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b382e0e636ed54cd278791d93fe2c4f370772743f02bcbe431a160089025c9"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e49dc23a10a1296b04ca9db200c44d3eb32c8d8ec532e8c1fd24792276522a"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4399b4226c4785575fb20998dc571bc48125dc92c367ce2602d0d70e0c455eb0"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5412500e0dc5481b1ee9cf6b38bb3b473f6e411eb62b83dc9b62699c3b7b79f7"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c93ed3c998ea8472be98fb55aed65b5198740bfceaec07b2eba551e55b7b9ae"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63d57fc94eb0bbb4735e45517afc21ef262991d8758a8f2f05dd6e4174944519"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:b450d7cabcd49aa7ab46a3c6aa3ac7e1593600a1a0605ba536ec0f1b99a04322"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:4df0ec814b50275ad6a99bc82a38b59f90e10e47714ac9871e1b223895825468"}, + {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d184f85ad2bb1f261eac55cddfcf62a70dee89982c978e92b9a74a1bfef2e367"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b725e70d15906d24615201e650d5b0388b08a5187a55f119f25874d0103f90dd"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a31fa7536ec1fb7155a0cd3a4e3d956c835ad0a43e3610ca32384d01f079ea1c"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c3c8b55c7fc7b7e8877b9366568cc73d68b82da7fe33d8b98527b73857a225f"}, + {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d61ec60945d694df806a9aec88e8f29a27293c6e424f8ff91c80416e3c617645"}, + {file = "lxml-5.3.1-cp312-cp312-win32.whl", hash = "sha256:f4eac0584cdc3285ef2e74eee1513a6001681fd9753b259e8159421ed28a72e5"}, + {file = "lxml-5.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:29bfc8d3d88e56ea0a27e7c4897b642706840247f59f4377d81be8f32aa0cfbf"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e"}, + {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8"}, + {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5"}, + {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252"}, + {file = "lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78"}, + {file = "lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332"}, + {file = "lxml-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:016b96c58e9a4528219bb563acf1aaaa8bc5452e7651004894a973f03b84ba81"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82a4bb10b0beef1434fb23a09f001ab5ca87895596b4581fd53f1e5145a8934a"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d68eeef7b4d08a25e51897dac29bcb62aba830e9ac6c4e3297ee7c6a0cf6439"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:f12582b8d3b4c6be1d298c49cb7ae64a3a73efaf4c2ab4e37db182e3545815ac"}, + {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2df7ed5edeb6bd5590914cd61df76eb6cce9d590ed04ec7c183cf5509f73530d"}, + {file = "lxml-5.3.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:585c4dc429deebc4307187d2b71ebe914843185ae16a4d582ee030e6cfbb4d8a"}, + {file = "lxml-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:06a20d607a86fccab2fc15a77aa445f2bdef7b49ec0520a842c5c5afd8381576"}, + {file = "lxml-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:057e30d0012439bc54ca427a83d458752ccda725c1c161cc283db07bcad43cf9"}, + {file = "lxml-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4867361c049761a56bd21de507cab2c2a608c55102311d142ade7dab67b34f32"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dddf0fb832486cc1ea71d189cb92eb887826e8deebe128884e15020bb6e3f61"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bcc211542f7af6f2dfb705f5f8b74e865592778e6cafdfd19c792c244ccce19"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaca5a812f050ab55426c32177091130b1e49329b3f002a32934cd0245571307"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:236610b77589faf462337b3305a1be91756c8abc5a45ff7ca8f245a71c5dab70"}, + {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:aed57b541b589fa05ac248f4cb1c46cbb432ab82cbd467d1c4f6a2bdc18aecf9"}, + {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:75fa3d6946d317ffc7016a6fcc44f42db6d514b7fdb8b4b28cbe058303cb6e53"}, + {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:96eef5b9f336f623ffc555ab47a775495e7e8846dde88de5f941e2906453a1ce"}, + {file = "lxml-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:ef45f31aec9be01379fc6c10f1d9c677f032f2bac9383c827d44f620e8a88407"}, + {file = "lxml-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0611da6b07dd3720f492db1b463a4d1175b096b49438761cc9f35f0d9eaaef5"}, + {file = "lxml-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2aca14c235c7a08558fe0a4786a1a05873a01e86b474dfa8f6df49101853a4e"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82fce1d964f065c32c9517309f0c7be588772352d2f40b1574a214bd6e6098"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7aae7a3d63b935babfdc6864b31196afd5145878ddd22f5200729006366bc4d5"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8e0d177b1fe251c3b1b914ab64135475c5273c8cfd2857964b2e3bb0fe196a7"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:6c4dd3bfd0c82400060896717dd261137398edb7e524527438c54a8c34f736bf"}, + {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f1208c1c67ec9e151d78aa3435aa9b08a488b53d9cfac9b699f15255a3461ef2"}, + {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c6aacf00d05b38a5069826e50ae72751cb5bc27bdc4d5746203988e429b385bb"}, + {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5881aaa4bf3a2d086c5f20371d3a5856199a0d8ac72dd8d0dbd7a2ecfc26ab73"}, + {file = "lxml-5.3.1-cp38-cp38-win32.whl", hash = "sha256:45fbb70ccbc8683f2fb58bea89498a7274af1d9ec7995e9f4af5604e028233fc"}, + {file = "lxml-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:7512b4d0fc5339d5abbb14d1843f70499cab90d0b864f790e73f780f041615d7"}, + {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5885bc586f1edb48e5d68e7a4b4757b5feb2a496b64f462b4d65950f5af3364f"}, + {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1b92fe86e04f680b848fff594a908edfa72b31bfc3499ef7433790c11d4c8cd8"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a091026c3bf7519ab1e64655a3f52a59ad4a4e019a6f830c24d6430695b1cf6a"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ffb141361108e864ab5f1813f66e4e1164181227f9b1f105b042729b6c15125"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3715cdf0dd31b836433af9ee9197af10e3df41d273c19bb249230043667a5dfd"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88b72eb7222d918c967202024812c2bfb4048deeb69ca328363fb8e15254c549"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa59974880ab5ad8ef3afaa26f9bda148c5f39e06b11a8ada4660ecc9fb2feb3"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3bb8149840daf2c3f97cebf00e4ed4a65a0baff888bf2605a8d0135ff5cf764e"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:0d6b2fa86becfa81f0a0271ccb9eb127ad45fb597733a77b92e8a35e53414914"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:136bf638d92848a939fd8f0e06fcf92d9f2e4b57969d94faae27c55f3d85c05b"}, + {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:89934f9f791566e54c1d92cdc8f8fd0009447a5ecdb1ec6b810d5f8c4955f6be"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8ade0363f776f87f982572c2860cc43c65ace208db49c76df0a21dde4ddd16e"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bfbbab9316330cf81656fed435311386610f78b6c93cc5db4bebbce8dd146675"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:172d65f7c72a35a6879217bcdb4bb11bc88d55fb4879e7569f55616062d387c2"}, + {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3c623923967f3e5961d272718655946e5322b8d058e094764180cdee7bab1af"}, + {file = "lxml-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ce0930a963ff593e8bb6fda49a503911accc67dee7e5445eec972668e672a0f0"}, + {file = "lxml-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7b64fcd670bca8800bc10ced36620c6bbb321e7bc1214b9c0c0df269c1dddc2"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:afa578b6524ff85fb365f454cf61683771d0170470c48ad9d170c48075f86725"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f5e80adf0aafc7b5454f2c1cb0cde920c9b1f2cbd0485f07cc1d0497c35c5d"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd0b80ac2d8f13ffc906123a6f20b459cb50a99222d0da492360512f3e50f84"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:422c179022ecdedbe58b0e242607198580804253da220e9454ffe848daa1cfd2"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:524ccfded8989a6595dbdda80d779fb977dbc9a7bc458864fc9a0c2fc15dc877"}, + {file = "lxml-5.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48fd46bf7155def2e15287c6f2b133a2f78e2d22cdf55647269977b873c65499"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:05123fad495a429f123307ac6d8fd6f977b71e9a0b6d9aeeb8f80c017cb17131"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a243132767150a44e6a93cd1dde41010036e1cbc63cc3e9fe1712b277d926ce3"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c92ea6d9dd84a750b2bae72ff5e8cf5fdd13e58dda79c33e057862c29a8d5b50"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2f1be45d4c15f237209bbf123a0e05b5d630c8717c42f59f31ea9eae2ad89394"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a83d3adea1e0ee36dac34627f78ddd7f093bb9cfc0a8e97f1572a949b695cb98"}, + {file = "lxml-5.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3edbb9c9130bac05d8c3fe150c51c337a471cc7fdb6d2a0a7d3a88e88a829314"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2f23cf50eccb3255b6e913188291af0150d89dab44137a69e14e4dcb7be981f1"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df7e5edac4778127f2bf452e0721a58a1cfa4d1d9eac63bdd650535eb8543615"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:094b28ed8a8a072b9e9e2113a81fda668d2053f2ca9f2d202c2c8c7c2d6516b1"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:514fe78fc4b87e7a7601c92492210b20a1b0c6ab20e71e81307d9c2e377c64de"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8fffc08de02071c37865a155e5ea5fce0282e1546fd5bde7f6149fcaa32558ac"}, + {file = "lxml-5.3.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4b0d5cdba1b655d5b18042ac9c9ff50bda33568eb80feaaca4fc237b9c4fbfde"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3031e4c16b59424e8d78522c69b062d301d951dc55ad8685736c3335a97fc270"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb659702a45136c743bc130760c6f137870d4df3a9e14386478b8a0511abcfca"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a11b16a33656ffc43c92a5343a28dc71eefe460bcc2a4923a96f292692709f6"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5ae125276f254b01daa73e2c103363d3e99e3e10505686ac7d9d2442dd4627a"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c76722b5ed4a31ba103e0dc77ab869222ec36efe1a614e42e9bcea88a36186fe"}, + {file = "lxml-5.3.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:33e06717c00c788ab4e79bc4726ecc50c54b9bfb55355eae21473c145d83c2d2"}, + {file = "lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] -html-clean = ["lxml-html-clean"] +html-clean = ["lxml_html_clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=3.0.11)"] +source = ["Cython (>=3.0.11,<3.1.0)"] [[package]] name = "markdown" @@ -2541,13 +2541,13 @@ nornir-nautobot = ">=3.0.0,<4.0.0" [[package]] name = "nautobot-ssot" -version = "3.4.0" +version = "3.5.0" description = "Nautobot Single Source of Truth" optional = false python-versions = "<3.13,>=3.8" files = [ - {file = "nautobot_ssot-3.4.0-py3-none-any.whl", hash = "sha256:df33ca0004ca31fa7acb786691c520e4586c7d98abeb7e133ab2b0f78946fc7d"}, - {file = "nautobot_ssot-3.4.0.tar.gz", hash = "sha256:5d45f5d5060e7425bcb3271a3397070d73f5208ef51ceb2074adc98ad32afbcf"}, + {file = "nautobot_ssot-3.5.0-py3-none-any.whl", hash = "sha256:a20801c4e04bc65268de7e95f746a66d0c1739d85237658aa7c3fa628478d3a6"}, + {file = "nautobot_ssot-3.5.0.tar.gz", hash = "sha256:a5f26df1730863c78996ab4a8c7ba97ebf85d5121717b659690bb27312841405"}, ] [package.dependencies] @@ -2560,7 +2560,7 @@ retry = ">=0.9.2,<0.10.0" [package.extras] aci = ["PyYAML (>=6)"] -all = ["Jinja2 (>=2.11.3)", "PyYAML (>=6)", "cloudvision (>=1.9.0,<2.0.0)", "cvprac (>=1.2.2,<2.0.0)", "dnacentersdk (>=2.5.6,<3.0.0)", "dnspython (>=2.1.0,<3.0.0)", "ijson (>=2.5.1)", "ipfabric (>=6.0.0,<7.0.0)", "meraki (>=1.37.2,<1.46.0)", "nautobot-device-lifecycle-mgmt (>=2.0.0,<3.0.0)", "netutils (>=1.9.0,<2.0.0)", "oauthlib (>=3.1.0)", "orionsdk (>=0.4.0,<0.5.0)", "python-magic (>=0.4.15)", "pytz (>=2019.3)", "requests (>=2.21.0)", "requests-oauthlib (>=1.3.0)", "six (>=1.13.0)", "slurpit-sdk (>=0.9.58,<0.10.0)", "urllib3 (>=2.2.3)"] +all = ["Jinja2 (>=2.11.3)", "PyYAML (>=6)", "cloudvision (>=1.9.0,<2.0.0)", "cvprac (>=1.2.2,<2.0.0)", "dnacentersdk (>=2.5.6,<3.0.0)", "dnspython (>=2.1.0,<3.0.0)", "ijson (>=2.5.1)", "ipfabric (>=6.0.0,<7.0.0)", "meraki (>=1.37.2,<1.46.0)", "nautobot-device-lifecycle-mgmt (>=2.0.0,<3.0.0)", "netutils (>=1.9.0,<2.0.0)", "oauthlib (>=3.1.0)", "python-magic (>=0.4.15)", "pytz (>=2019.3)", "requests (>=2.21.0)", "requests-oauthlib (>=1.3.0)", "six (>=1.13.0)", "slurpit-sdk (>=0.9.58,<0.10.0)", "urllib3 (>=2.2.3)"] aristacv = ["cloudvision (>=1.9.0,<2.0.0)", "cvprac (>=1.2.2,<2.0.0)"] bootstrap = ["pytz (>=2019.3)"] citrix-adm = ["netutils (>=1.9.0,<2.0.0)", "requests (>=2.21.0)", "urllib3 (>=2.2.3)"] @@ -2573,7 +2573,6 @@ nautobot-device-lifecycle-mgmt = ["nautobot-device-lifecycle-mgmt (>=2.0.0,<3.0. pysnow = ["ijson (>=2.5.1)", "oauthlib (>=3.1.0)", "python-magic (>=0.4.15)", "pytz (>=2019.3)", "requests (>=2.21.0)", "requests-oauthlib (>=1.3.0)", "six (>=1.13.0)"] servicenow = ["Jinja2 (>=2.11.3)", "PyYAML (>=6)", "ijson (>=2.5.1)", "oauthlib (>=3.1.0)", "python-magic (>=0.4.15)", "pytz (>=2019.3)", "requests (>=2.21.0)", "requests-oauthlib (>=1.3.0)", "six (>=1.13.0)"] slurpit = ["slurpit-sdk (>=0.9.58,<0.10.0)"] -solarwinds = ["orionsdk (>=0.4.0,<0.5.0)"] [[package]] name = "ncclient" @@ -2628,17 +2627,17 @@ textfsm = ">=1.1.3" [[package]] name = "netutils" -version = "1.11.0" +version = "1.12.0" description = "Common helper functions useful in network automation." optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "netutils-1.11.0-py3-none-any.whl", hash = "sha256:863674eb7dce2b85972d52079b4884fb30e498ccf1dd581abc28b4d69bfdf0cd"}, - {file = "netutils-1.11.0.tar.gz", hash = "sha256:1631152256db1623675d9087d4327b2f4633d294f758518742a974e868a50ae8"}, + {file = "netutils-1.12.0-py3-none-any.whl", hash = "sha256:7cb37796ce86637814f8c899f64db2b054986b0eda719d3fcadc293d451a4db1"}, + {file = "netutils-1.12.0.tar.gz", hash = "sha256:96a790d11921063a6a64ee79c6e8c5a5ffcd05cbee07dd2b614d98c4416cffdd"}, ] [package.extras] -optionals = ["jsonschema (>=4.17.3,<5.0.0)", "napalm (>=4.0.0,<5.0.0)"] +optionals = ["jsonschema (>=4.17.3,<5.0.0)", "legacycrypt (==0.3)", "napalm (>=4.0.0,<5.0.0)"] [[package]] name = "nh3" @@ -2775,13 +2774,13 @@ nornir = ">=3,<4" [[package]] name = "ntc-templates" -version = "7.6.0" +version = "7.7.0" description = "TextFSM Templates for Network Devices, and Python wrapper for TextFSM's CliTable." optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "ntc_templates-7.6.0-py3-none-any.whl", hash = "sha256:6e855a443cd9ad28192bc766994cbfef58bcaae3ebaf19005a55c6f76e9ab6b5"}, - {file = "ntc_templates-7.6.0.tar.gz", hash = "sha256:b70ccaaf74014344a8446f13744691cfbf2e603101481c71decc8ee53eefea5d"}, + {file = "ntc_templates-7.7.0-py3-none-any.whl", hash = "sha256:314850358394f4edbc3170ce9d3b69f51c2877c67cd9c4c8fe21227cb81f8ab1"}, + {file = "ntc_templates-7.7.0.tar.gz", hash = "sha256:c7b9c2f8306ff6ff1133b5a1614f9627b520bc27c3c514c4e95bf27e221f2a2d"}, ] [package.dependencies] @@ -2845,13 +2844,13 @@ lint = ["black"] [[package]] name = "paramiko" -version = "3.5.0" +version = "3.5.1" description = "SSH2 protocol library" optional = false python-versions = ">=3.6" files = [ - {file = "paramiko-3.5.0-py3-none-any.whl", hash = "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9"}, - {file = "paramiko-3.5.0.tar.gz", hash = "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124"}, + {file = "paramiko-3.5.1-py3-none-any.whl", hash = "sha256:43b9a0501fc2b5e70680388d9346cf252cfb7d00b0667c39e80eb43a408b8f61"}, + {file = "paramiko-3.5.1.tar.gz", hash = "sha256:b2c665bc45b2b215bd7d7f039901b14b067da00f3a11e6640995fd58f2664822"}, ] [package.dependencies] @@ -3060,13 +3059,13 @@ test = ["coveralls", "futures", "mock", "pytest (>=2.7.3)", "pytest-benchmark", [[package]] name = "prompt-toolkit" -version = "3.0.48" +version = "3.0.50" description = "Library for building powerful interactive command lines in Python" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e"}, - {file = "prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90"}, + {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, + {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, ] [package.dependencies] @@ -3126,6 +3125,7 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, @@ -3208,13 +3208,13 @@ files = [ [[package]] name = "pydantic" -version = "2.10.5" +version = "2.10.6" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, - {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, + {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, + {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, ] [package.dependencies] @@ -3466,13 +3466,13 @@ pylint = ">=1.7" [[package]] name = "pymdown-extensions" -version = "10.14" +version = "10.14.3" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" files = [ - {file = "pymdown_extensions-10.14-py3-none-any.whl", hash = "sha256:202481f716cc8250e4be8fce997781ebf7917701b59652458ee47f2401f818b5"}, - {file = "pymdown_extensions-10.14.tar.gz", hash = "sha256:741bd7c4ff961ba40b7528d32284c53bc436b8b1645e8e37c3e57770b8700a34"}, + {file = "pymdown_extensions-10.14.3-py3-none-any.whl", hash = "sha256:05e0bee73d64b9c71a4ae17c72abc2f700e8bc8403755a00580b49a4e9f189e9"}, + {file = "pymdown_extensions-10.14.3.tar.gz", hash = "sha256:41e576ce3f5d650be59e900e4ceff231e0aed2a88cf30acaee41e02f063a061b"}, ] [package.dependencies] @@ -3635,13 +3635,13 @@ postgresql = ["psycopg2"] [[package]] name = "pytz" -version = "2024.2" +version = "2025.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, - {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, + {file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"}, + {file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"}, ] [[package]] @@ -4359,15 +4359,18 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "structlog" -version = "24.4.0" +version = "25.1.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" files = [ - {file = "structlog-24.4.0-py3-none-any.whl", hash = "sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610"}, - {file = "structlog-24.4.0.tar.gz", hash = "sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4"}, + {file = "structlog-25.1.0-py3-none-any.whl", hash = "sha256:843fe4f254540329f380812cbe612e1af5ec5b8172205ae634679cd35a6d6321"}, + {file = "structlog-25.1.0.tar.gz", hash = "sha256:2ef2a572e0e27f09664965d31a576afe64e46ac6084ef5cec3c2b8cd6e4e3ad3"}, ] +[package.dependencies] +typing-extensions = {version = "*", markers = "python_version < \"3.11\""} + [package.extras] dev = ["freezegun (>=0.2.8)", "mypy (>=1.4)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "rich", "simplejson", "twisted"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] @@ -4574,13 +4577,13 @@ files = [ [[package]] name = "tzdata" -version = "2024.2" +version = "2025.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, - {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, + {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, + {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, ] [[package]] @@ -4695,76 +4698,90 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "wrapt" -version = "1.17.0" +version = "1.17.2" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.8" files = [ - {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, - {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, - {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, - {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, - {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, - {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, - {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, - {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, - {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, - {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, - {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, - {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, - {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, - {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, - {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, - {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, - {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, - {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, - {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, - {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, - {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, - {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, - {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, - {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, - {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, - {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, - {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, - {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, - {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, - {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, - {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, - {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, - {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, - {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, - {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, - {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, - {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, - {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, - {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, - {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, - {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, - {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, - {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, - {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, - {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, - {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, - {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, - {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, - {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, - {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, - {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, - {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, - {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, - {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, - {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, - {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, - {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, - {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, - {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, - {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, - {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, - {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, - {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, - {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, - {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62"}, + {file = "wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563"}, + {file = "wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"}, + {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"}, + {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"}, + {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"}, + {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"}, + {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"}, + {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"}, + {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"}, + {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f"}, + {file = "wrapt-1.17.2-cp38-cp38-win32.whl", hash = "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7"}, + {file = "wrapt-1.17.2-cp38-cp38-win_amd64.whl", hash = "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9"}, + {file = "wrapt-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb"}, + {file = "wrapt-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb"}, + {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"}, + {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 73616547..f7b53426 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nautobot-device-onboarding" -version = "4.2.1a0" +version = "4.2.1" description = "A app for Nautobot to easily onboard new devices." authors = ["Network to Code, LLC "] license = "Apache-2.0"