From 3c0e70b3200e3f4216c471941f88a682eca1e913 Mon Sep 17 00:00:00 2001 From: IluaAir Date: Thu, 11 Jun 2026 23:47:17 +0300 Subject: [PATCH] Update project configuration and dependencies - Added `.vscode` to `.gitignore` to exclude Visual Studio Code settings. - Updated `pyproject.toml` to include `ruff` for linting and configured its settings. - Modified `uv.lock` to include `ruff` in both optional and development dependencies. - Refactored type hints in several files to use `str | None` for optional parameters. - Cleaned up unused imports and whitespace in various modules for improved code clarity. --- .gitignore | 2 +- oxi/__init__.py | 1 - oxi/adapter.py | 3 +-- oxi/conf.py | 5 ++-- oxi/core.py | 10 ++++---- oxi/exception.py | 4 ++-- oxi/interfaces/__init__.py | 4 ++-- oxi/interfaces/base.py | 21 ++++++++--------- oxi/interfaces/contract.py | 1 + oxi/interfaces/models/__init__.py | 2 +- oxi/interfaces/models/h3c.py | 2 +- oxi/interfaces/models/keenetic.py | 1 + oxi/node.py | 1 - oxi/view.py | 1 - pyproject.toml | 8 +++++++ tests/test_models.py | 2 +- tests/test_network.py | 4 ++-- tests/test_units.py | 3 +-- uv.lock | 38 ++++++++++++++++++++++++++++++- 19 files changed, 76 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index ab9f627..7f3e0c2 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,6 @@ main.py .venv .idea .DS_Store - +.vscode # etc files *.txt \ No newline at end of file diff --git a/oxi/__init__.py b/oxi/__init__.py index c6ef94b..492517d 100644 --- a/oxi/__init__.py +++ b/oxi/__init__.py @@ -1,6 +1,5 @@ from .core import OxiAPI - __all__ = [ "OxiAPI", ] diff --git a/oxi/adapter.py b/oxi/adapter.py index 87786ad..d8b26cc 100644 --- a/oxi/adapter.py +++ b/oxi/adapter.py @@ -1,4 +1,3 @@ -from typing import Optional from requests.adapters import HTTPAdapter from urllib3.util import Retry @@ -6,7 +5,7 @@ from urllib3.util import Retry class OxiAdapter(HTTPAdapter): def __init__( self, - timeout: Optional[int] = None, + timeout: int | None = None, max_retries: int = 3, *args, **kwargs, diff --git a/oxi/conf.py b/oxi/conf.py index acc2b70..d354396 100644 --- a/oxi/conf.py +++ b/oxi/conf.py @@ -1,6 +1,7 @@ -from functools import cached_property import json -from typing import TYPE_CHECKING, Generic, Iterator, TypeVar +from collections.abc import Iterator +from functools import cached_property +from typing import TYPE_CHECKING, Generic, TypeVar from pydantic import BaseModel diff --git a/oxi/core.py b/oxi/core.py index 5662c85..d28017c 100644 --- a/oxi/core.py +++ b/oxi/core.py @@ -1,8 +1,8 @@ -from typing import Optional from requests import HTTPError, Session from oxi.adapter import OxiAdapter from oxi.exception import OxiAPIError + from .node import Node @@ -10,8 +10,8 @@ class OxiAPI: def __init__( self, url: str, - username: Optional[str] = None, - password: Optional[str] = None, + username: str | None = None, + password: str | None = None, verify: bool = True, ): self.base_url = url.rstrip("/") @@ -20,8 +20,8 @@ class OxiAPI: def __create_session( self, - username: Optional[str] = None, - password: Optional[str] = None, + username: str | None = None, + password: str | None = None, verify: bool = True, ) -> Session: session = Session() diff --git a/oxi/exception.py b/oxi/exception.py index be3adaf..f55ed78 100644 --- a/oxi/exception.py +++ b/oxi/exception.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING if TYPE_CHECKING: from requests import HTTPError @@ -35,7 +35,7 @@ def _looks_like_node_not_found_html(e: "HTTPError") -> bool: class OxiAPIError(Exception): - def __init__(self, message: str, status_code: Optional[int] = None): + def __init__(self, message: str, status_code: int | None = None): super().__init__(message) self.status_code = status_code self.message = message diff --git a/oxi/interfaces/__init__.py b/oxi/interfaces/__init__.py index c5f11ea..f401ed6 100644 --- a/oxi/interfaces/__init__.py +++ b/oxi/interfaces/__init__.py @@ -1,4 +1,4 @@ -from typing import Callable, Type +from collections.abc import Callable from .base import BaseDevice @@ -7,7 +7,7 @@ device_registry = {} def register_parser( name: list[str] | str, -) -> Callable[[Type[BaseDevice]], Type[BaseDevice]]: +) -> Callable[[type[BaseDevice]], type[BaseDevice]]: def wrapper(cls): name_list = [] if isinstance(name, str): diff --git a/oxi/interfaces/base.py b/oxi/interfaces/base.py index 3d51188..5c5667b 100644 --- a/oxi/interfaces/base.py +++ b/oxi/interfaces/base.py @@ -1,10 +1,11 @@ +import xml.etree.ElementTree as ET from abc import ABC, abstractmethod from pathlib import Path + from ttp import ttp + from oxi.exception import OxiAPIError -from oxi.interfaces.contract import Device -import xml.etree.ElementTree as ET -from oxi.interfaces.contract import Interfaces, System, Vlans +from oxi.interfaces.contract import Device, Interfaces, System, Vlans class BaseDevice(ABC): @@ -40,7 +41,7 @@ class BaseDevice(ABC): Raises: ValueError: if raw data cannot be validated by the contract. - """ + """ # noqa: E501 return self.raw.get("vlans", []) def interfaces(self) -> list[dict]: @@ -52,7 +53,7 @@ class BaseDevice(ABC): Raises: ValueError: if raw data cannot be validated by the contract. - """ + """ # noqa: E501 return self.raw.get("interfaces", []) def system(self) -> dict: @@ -82,11 +83,7 @@ class BaseDevice(ABC): def _validate_contract(self) -> dict: if self.raw is None: - msg = ( - f"Node {self.name} not found" - if self.name - else "Node not found" - ) + msg = f"Node {self.name} not found" if self.name else "Node not found" raise OxiAPIError(msg, status_code=404) system_data = self.system() interfaces_data = self._as_list(self.interfaces()) @@ -99,8 +96,8 @@ class BaseDevice(ABC): if "vlans" in self._declared_sections: if "vlans" not in self.raw: raise ValueError( - f"{self.__class__.__name__}: template '{self.template}' declares optional group " - f"'vlans', but TTP did not return it." + f"{self.__class__.__name__}: template '{self.template}' " + f"declares optional group 'vlans', but TTP did not return it." ) vlans_data = self._as_list(self.vlans()) result["vlans"] = [Vlans(**item) for item in vlans_data] diff --git a/oxi/interfaces/contract.py b/oxi/interfaces/contract.py index d5bbb24..44a289f 100644 --- a/oxi/interfaces/contract.py +++ b/oxi/interfaces/contract.py @@ -1,4 +1,5 @@ from ipaddress import IPv4Address + from pydantic import BaseModel, ConfigDict, Field diff --git a/oxi/interfaces/models/__init__.py b/oxi/interfaces/models/__init__.py index a3a9678..af8e78a 100644 --- a/oxi/interfaces/models/__init__.py +++ b/oxi/interfaces/models/__init__.py @@ -3,5 +3,5 @@ import pkgutil package = __package__ -for loader, module_name, is_pkg in pkgutil.iter_modules(__path__): +for _, module_name, _ in pkgutil.iter_modules(__path__): importlib.import_module(f"{package}.{module_name}") diff --git a/oxi/interfaces/models/h3c.py b/oxi/interfaces/models/h3c.py index 3ad40da..f956607 100644 --- a/oxi/interfaces/models/h3c.py +++ b/oxi/interfaces/models/h3c.py @@ -14,4 +14,4 @@ class H3C(BaseDevice): vlans.append(item) continue vlans.extend({"vlan_id": vlan_id} for vlan_id in vlan_ids) - return vlans \ No newline at end of file + return vlans diff --git a/oxi/interfaces/models/keenetic.py b/oxi/interfaces/models/keenetic.py index 5764f23..41d5248 100644 --- a/oxi/interfaces/models/keenetic.py +++ b/oxi/interfaces/models/keenetic.py @@ -1,4 +1,5 @@ from ipaddress import ip_interface + from oxi.interfaces import register_parser from oxi.interfaces.base import BaseDevice from oxi.interfaces.utils import decode_utf diff --git a/oxi/node.py b/oxi/node.py index 828970f..c88df7e 100644 --- a/oxi/node.py +++ b/oxi/node.py @@ -6,7 +6,6 @@ from oxi.exception import OxiAPIError from .view import NodeView - if TYPE_CHECKING: from requests import Session diff --git a/oxi/view.py b/oxi/view.py index 88e4885..951b234 100644 --- a/oxi/view.py +++ b/oxi/view.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING from .conf import NodeConfig - if TYPE_CHECKING: from requests import Session diff --git a/pyproject.toml b/pyproject.toml index de41b3f..e1a6eb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,4 +47,12 @@ include-package-data = true dev = [ "pytest>=9.0.3", "responses>=0.26.1", + "ruff>=0.15.17", ] + +[tool.ruff] +target-version = "py310" +line-length = 88 + +[tool.ruff.lint] +select = ["E", "F", "I", "UP", "B"] diff --git a/tests/test_models.py b/tests/test_models.py index d2222a3..95f8860 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,8 +1,8 @@ import json import pytest - from conftest import FIXTURES, load + from oxi.interfaces import device_registry MODEL_CASES = [ diff --git a/tests/test_network.py b/tests/test_network.py index c314048..92e54c7 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -1,7 +1,7 @@ import pytest import responses - from conftest import load + from oxi import OxiAPI from oxi.exception import OxiAPIError @@ -84,4 +84,4 @@ def test_unknown_model_raises_value_error(): api = OxiAPI(url=BASE) with pytest.raises(ValueError, match="not found in registry"): - api.node("HQ").config + _ = api.node("HQ").config diff --git a/tests/test_units.py b/tests/test_units.py index 0df7e8e..846e7fa 100644 --- a/tests/test_units.py +++ b/tests/test_units.py @@ -1,10 +1,9 @@ import pytest - from conftest import load + from oxi.exception import OxiAPIError from oxi.interfaces import device_registry from oxi.interfaces.base import BaseDevice -from oxi.interfaces.contract import Interfaces, System from oxi.interfaces.utils import decode_utf, expand_vlan_range diff --git a/uv.lock b/uv.lock index 36a43d8..0e2bfb7 100644 --- a/uv.lock +++ b/uv.lock @@ -158,23 +158,34 @@ dependencies = [ { name = "ttp" }, ] -[package.dev-dependencies] +[package.optional-dependencies] dev = [ { name = "pytest" }, { name = "responses" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "responses" }, + { name = "ruff" }, +] + [package.metadata] requires-dist = [ { name = "pydantic", specifier = ">=2.12.5" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=9.0.3" }, { name = "requests", specifier = ">=2.32.5" }, + { name = "responses", marker = "extra == 'dev'", specifier = ">=0.26.1" }, { name = "ttp", specifier = ">=0.10.0" }, ] +provides-extras = ["dev"] [package.metadata.requires-dev] dev = [ { name = "pytest", specifier = ">=9.0.3" }, { name = "responses", specifier = ">=0.26.1" }, + { name = "ruff", specifier = ">=0.15.17" }, ] [[package]] @@ -448,6 +459,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3a/31/6a620b4427d546b9e7cca8b3b8c5f0559d9cef2bb9eedcda7f73c1473c19/responses-0.26.1-py3-none-any.whl", hash = "sha256:8aacc4586eb08fb2208ef64a9eb4258d9b0c6e6f4260845f2f018ab847495345", size = 35502, upload-time = "2026-05-21T19:56:38.046Z" }, ] +[[package]] +name = "ruff" +version = "0.15.17" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" }, + { url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" }, + { url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" }, + { url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" }, + { url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" }, + { url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" }, + { url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" }, + { url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" }, +] + [[package]] name = "tomli" version = "2.4.1"