summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Bertó <463349+robertoberto@users.noreply.github.com>2026-05-19 02:32:04 +0000
committerRoberto Bertó <463349+robertoberto@users.noreply.github.com>2026-05-19 02:32:04 +0000
commit0f76bcc7179976e893b1d9f296b1b1e7988b0031 (patch)
tree87fa89da92263bbe2af7303a0ab36433fdc6f5d3
parentffd5ba16eb1ada42a582db4ac8bdaf29f66a868f (diff)
downloadpyvyos-0f76bcc7179976e893b1d9f296b1b1e7988b0031.tar.gz
pyvyos-0f76bcc7179976e893b1d9f296b1b1e7988b0031.zip
refactor: remove unused specs, exceptions, and request_id
The pyvyos.specs Pydantic models were never imported by the runtime and had 0% test coverage. The pyvyos.exceptions hierarchy was defined but never raised anywhere. The request_id helper generated UUIDs that were attached to log records but never propagated to callers — half-implemented tracing is worse than none. This commit does not alter request/response logic or HTTP payloads. It only removes code that was never executed and tests for that code. Removed: - pyvyos/specs/ (Pydantic models package) - pyvyos/exceptions.py (SDKError, HttpError, ApiError, ValidationError) - pyvyos/utils/ids.py (request_id helper) - tests/test_exceptions.py - tests/utils/test_ids.py Edited: - pyvyos/core/rest_client.py: drop request_id import and log extras - pyvyos/utils/__init__.py: drop request_id export Tests: 66 -> 57 passing. Coverage: 54% -> 87%. Public API unchanged.
-rw-r--r--pyvyos/core/rest_client.py9
-rw-r--r--pyvyos/exceptions.py33
-rw-r--r--pyvyos/specs/__init__.py12
-rw-r--r--pyvyos/specs/commands/__init__.py13
-rw-r--r--pyvyos/specs/commands/config_file.py36
-rw-r--r--pyvyos/specs/commands/configure.py38
-rw-r--r--pyvyos/specs/commands/generate.py20
-rw-r--r--pyvyos/specs/commands/image.py33
-rw-r--r--pyvyos/specs/commands/reset.py20
-rw-r--r--pyvyos/specs/commands/retrieve.py27
-rw-r--r--pyvyos/specs/commands/show.py20
-rw-r--r--pyvyos/specs/commands/system.py27
-rw-r--r--pyvyos/specs/models.py31
-rw-r--r--pyvyos/utils/__init__.py3
-rw-r--r--pyvyos/utils/ids.py14
-rw-r--r--tests/test_exceptions.py51
-rw-r--r--tests/utils/test_ids.py25
17 files changed, 1 insertions, 411 deletions
diff --git a/pyvyos/core/rest_client.py b/pyvyos/core/rest_client.py
index eb77d9b..ddef7ca 100644
--- a/pyvyos/core/rest_client.py
+++ b/pyvyos/core/rest_client.py
@@ -232,18 +232,10 @@ class RestClient(ABC):
# Initialize mutable defaults safely
path = path or []
- # Generate request ID for tracing
- try:
- from ..utils.ids import request_id
- req_id = request_id()
- except ImportError:
- req_id = None
-
# Log request start (DEBUG level)
logger.debug(
"Request start",
extra={
- "request_id": req_id,
"command": command,
"op": op,
"has_path": bool(path),
@@ -261,7 +253,6 @@ class RestClient(ABC):
logger.info(
"Request completed",
extra={
- "request_id": req_id,
"command": command,
"op": op,
"status": status,
diff --git a/pyvyos/exceptions.py b/pyvyos/exceptions.py
deleted file mode 100644
index 5a79733..0000000
--- a/pyvyos/exceptions.py
+++ /dev/null
@@ -1,33 +0,0 @@
-"""PyVyOS exception hierarchy for typed error handling."""
-
-
-class SDKError(Exception):
- """Base exception for all PyVyOS SDK errors."""
- pass
-
-
-class HttpError(SDKError):
- """HTTP-level errors (network, timeout, status codes)."""
-
- def __init__(self, status: int, message: str):
- self.status = status
- self.message = message
- super().__init__(f"HTTP Error {status}: {message}")
-
-
-class ApiError(SDKError):
- """API-level errors (when VyOS API returns success=False)."""
-
- def __init__(self, message: str, details: dict = None):
- self.message = message
- self.details = details
- super().__init__(message)
-
-
-class ValidationError(SDKError):
- """Client-side validation errors (invalid parameters)."""
-
- def __init__(self, message: str):
- self.message = message
- super().__init__(message)
-
diff --git a/pyvyos/specs/__init__.py b/pyvyos/specs/__init__.py
deleted file mode 100644
index d12c764..0000000
--- a/pyvyos/specs/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""PyVyOS Pydantic specs for optional request/response validation."""
-
-# Feature detection: gracefully degrade if pydantic not available
-try:
- from pydantic import BaseModel
- PYDANTIC_AVAILABLE = True
-except ImportError:
- PYDANTIC_AVAILABLE = False
- BaseModel = None # type: ignore
-
-__all__ = ["PYDANTIC_AVAILABLE"]
-
diff --git a/pyvyos/specs/commands/__init__.py b/pyvyos/specs/commands/__init__.py
deleted file mode 100644
index 1d8e8b3..0000000
--- a/pyvyos/specs/commands/__init__.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""Pydantic models for individual VyOS API commands."""
-
-from .config_file import ConfigFileSaveRequest, ConfigFileLoadRequest
-from .configure import ConfigureSetRequest, ConfigureDeleteRequest, ConfigureMultipleOpRequest
-
-__all__ = [
- "ConfigFileSaveRequest",
- "ConfigFileLoadRequest",
- "ConfigureSetRequest",
- "ConfigureDeleteRequest",
- "ConfigureMultipleOpRequest",
-]
-
diff --git a/pyvyos/specs/commands/config_file.py b/pyvyos/specs/commands/config_file.py
deleted file mode 100644
index 911b094..0000000
--- a/pyvyos/specs/commands/config_file.py
+++ /dev/null
@@ -1,36 +0,0 @@
-"""Pydantic models for config-file operations."""
-
-from typing import List, Literal, Optional
-
-try:
- from pydantic import BaseModel, Field
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- Field = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class ConfigFileSaveRequest(ApiRequest):
- """Request model for config-file save operation."""
-
- op: Literal["save"] = "save"
- path: List[str] = Field(
- default_factory=list,
- description="Required by VyOS API, typically empty array"
- )
- file: Optional[str] = None
-
-
- class ConfigFileLoadRequest(ApiRequest):
- """Request model for config-file load operation."""
-
- op: Literal["load"] = "load"
- path: List[str] = Field(
- default_factory=list,
- description="Required by VyOS API, typically empty array"
- )
- file: str # Required for load
-
diff --git a/pyvyos/specs/commands/configure.py b/pyvyos/specs/commands/configure.py
deleted file mode 100644
index d80aa3f..0000000
--- a/pyvyos/specs/commands/configure.py
+++ /dev/null
@@ -1,38 +0,0 @@
-"""Pydantic models for configure operations."""
-
-from typing import Dict, List, Literal, Union, Any
-
-try:
- from pydantic import BaseModel, Field
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- Field = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class ConfigureSetRequest(ApiRequest):
- """Request model for configure set operation."""
-
- op: Literal["set"] = "set"
- path: Union[List[str], List[List[str]]] # Required
-
-
- class ConfigureDeleteRequest(ApiRequest):
- """Request model for configure delete operation."""
-
- op: Literal["delete"] = "delete"
- path: List[str] # Required
-
-
- class ConfigureMultipleOpRequest(BaseModel):
- """Request model for configure multiple operations."""
-
- op: Literal["set", "delete"]
- path: Union[List[str], List[List[str]]]
-
- class Config:
- extra = "allow"
-
diff --git a/pyvyos/specs/commands/generate.py b/pyvyos/specs/commands/generate.py
deleted file mode 100644
index 40aa2a4..0000000
--- a/pyvyos/specs/commands/generate.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""Pydantic models for generate operations."""
-
-from typing import List, Literal, Optional
-
-try:
- from pydantic import BaseModel
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class GenerateRequest(ApiRequest):
- """Request model for generate operation."""
-
- op: Literal["generate"] = "generate"
- path: Optional[List[str]] = None
-
diff --git a/pyvyos/specs/commands/image.py b/pyvyos/specs/commands/image.py
deleted file mode 100644
index 973bae4..0000000
--- a/pyvyos/specs/commands/image.py
+++ /dev/null
@@ -1,33 +0,0 @@
-"""Pydantic models for image operations."""
-
-from typing import List, Literal, Optional
-
-try:
- from pydantic import BaseModel
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class ImageAddRequest(ApiRequest):
- """Request model for image add operation."""
-
- op: Literal["add"] = "add"
- path: Optional[List[str]] = None
- url: Optional[str] = None
- file: Optional[str] = None
- name: Optional[str] = None
-
-
- class ImageDeleteRequest(ApiRequest):
- """Request model for image delete operation."""
-
- op: Literal["delete"] = "delete"
- path: Optional[List[str]] = None
- url: Optional[str] = None
- file: Optional[str] = None
- name: Optional[str] = None
-
diff --git a/pyvyos/specs/commands/reset.py b/pyvyos/specs/commands/reset.py
deleted file mode 100644
index ac02bfe..0000000
--- a/pyvyos/specs/commands/reset.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""Pydantic models for reset operations."""
-
-from typing import List, Literal, Optional
-
-try:
- from pydantic import BaseModel
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class ResetRequest(ApiRequest):
- """Request model for reset operation."""
-
- op: Literal["reset"] = "reset"
- path: Optional[List[str]] = None
-
diff --git a/pyvyos/specs/commands/retrieve.py b/pyvyos/specs/commands/retrieve.py
deleted file mode 100644
index 65efbbf..0000000
--- a/pyvyos/specs/commands/retrieve.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""Pydantic models for retrieve operations."""
-
-from typing import List, Literal, Optional
-
-try:
- from pydantic import BaseModel
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class RetrieveShowConfigRequest(ApiRequest):
- """Request model for retrieve showConfig operation."""
-
- op: Literal["showConfig"] = "showConfig"
- path: Optional[List[str]] = None
-
-
- class RetrieveReturnValuesRequest(ApiRequest):
- """Request model for retrieve returnValues operation."""
-
- op: Literal["returnValues"] = "returnValues"
- path: Optional[List[str]] = None
-
diff --git a/pyvyos/specs/commands/show.py b/pyvyos/specs/commands/show.py
deleted file mode 100644
index 2fb2b97..0000000
--- a/pyvyos/specs/commands/show.py
+++ /dev/null
@@ -1,20 +0,0 @@
-"""Pydantic models for show operations."""
-
-from typing import List, Literal, Optional
-
-try:
- from pydantic import BaseModel
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class ShowRequest(ApiRequest):
- """Request model for show operation."""
-
- op: Literal["show"] = "show"
- path: Optional[List[str]] = None
-
diff --git a/pyvyos/specs/commands/system.py b/pyvyos/specs/commands/system.py
deleted file mode 100644
index 9f5e5c9..0000000
--- a/pyvyos/specs/commands/system.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""Pydantic models for system operations (reboot, poweroff)."""
-
-from typing import List, Literal
-
-try:
- from pydantic import BaseModel
- from ..models import ApiRequest
-except ImportError:
- BaseModel = None # type: ignore
- ApiRequest = None # type: ignore
-
-
-if BaseModel:
-
- class RebootRequest(ApiRequest):
- """Request model for reboot operation."""
-
- op: Literal["reboot"] = "reboot"
- path: List[str] = ["now"]
-
-
- class PoweroffRequest(ApiRequest):
- """Request model for poweroff operation."""
-
- op: Literal["poweroff"] = "poweroff"
- path: List[str] = ["now"]
-
diff --git a/pyvyos/specs/models.py b/pyvyos/specs/models.py
deleted file mode 100644
index a57ac82..0000000
--- a/pyvyos/specs/models.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""Base Pydantic models for PyVyOS API requests and responses."""
-
-from typing import Any, Dict, List, Optional, Union
-
-if False: # type checking only
- from pydantic import BaseModel
-else:
- try:
- from pydantic import BaseModel, Field
- except ImportError:
- BaseModel = None # type: ignore
- Field = None # type: ignore
-
-
-class ApiRequest(BaseModel):
- """Base request model for VyOS API operations."""
-
- op: str
- path: Optional[Union[List[str], List[List[str]], List[Dict[str, Any]]]] = None
-
- class Config:
- extra = "allow" # Allow additional fields (file, url, name, etc.)
-
-
-class ApiResponse(BaseModel):
- """Base response model for VyOS API responses."""
-
- success: bool
- data: Union[Dict[str, Any], List[Any], str, None]
- error: Optional[str] = None
-
diff --git a/pyvyos/utils/__init__.py b/pyvyos/utils/__init__.py
index adff044..6290fc1 100644
--- a/pyvyos/utils/__init__.py
+++ b/pyvyos/utils/__init__.py
@@ -1,8 +1,7 @@
"""Utility functions for PyVyOS."""
from .json import redact_key, safe_dumps
-from .ids import request_id
from .paths import build_path
-__all__ = ["redact_key", "safe_dumps", "request_id", "build_path"]
+__all__ = ["redact_key", "safe_dumps", "build_path"]
diff --git a/pyvyos/utils/ids.py b/pyvyos/utils/ids.py
deleted file mode 100644
index 5807ddf..0000000
--- a/pyvyos/utils/ids.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""ID generation utilities."""
-
-import uuid
-
-
-def request_id() -> str:
- """
- Generate a unique request ID for tracing.
-
- Returns:
- UUID4 string formatted for logging
- """
- return str(uuid.uuid4())
-
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
deleted file mode 100644
index 22a4f34..0000000
--- a/tests/test_exceptions.py
+++ /dev/null
@@ -1,51 +0,0 @@
-"""Tests for pyvyos.exceptions module."""
-
-import pytest
-
-from pyvyos.exceptions import SDKError, HttpError, ApiError, ValidationError
-
-
-def test_sdk_error_base():
- """Test SDKError is base exception."""
- assert issubclass(HttpError, SDKError)
- assert issubclass(ApiError, SDKError)
- assert issubclass(ValidationError, SDKError)
-
-
-def test_http_error():
- """Test HttpError creation and attributes."""
- error = HttpError(status=404, message="Not Found")
- assert error.status == 404
- assert error.message == "Not Found"
- assert "404" in str(error)
- assert "Not Found" in str(error)
-
-
-def test_api_error():
- """Test ApiError creation."""
- error = ApiError(message="API failure")
- assert error.message == "API failure"
- assert "API failure" in str(error)
-
-
-def test_api_error_with_details():
- """Test ApiError with details."""
- details = {"code": "ERR001", "field": "path"}
- error = ApiError(message="Validation failed", details=details)
- assert error.message == "Validation failed"
- assert error.details == details
-
-
-def test_validation_error():
- """Test ValidationError creation."""
- error = ValidationError(message="Invalid path format")
- assert error.message == "Invalid path format"
- assert "Invalid path format" in str(error)
-
-
-def test_exceptions_raiseable():
- """Test that exceptions can be raised and caught."""
- with pytest.raises(HttpError) as exc_info:
- raise HttpError(status=500, message="Internal Error")
- assert exc_info.value.status == 500
-
diff --git a/tests/utils/test_ids.py b/tests/utils/test_ids.py
deleted file mode 100644
index 19ff3a7..0000000
--- a/tests/utils/test_ids.py
+++ /dev/null
@@ -1,25 +0,0 @@
-"""Tests for pyvyos.utils.ids module."""
-
-import uuid
-
-from pyvyos.utils.ids import request_id
-
-
-def test_request_id_returns_string():
- """Test that request_id returns a string."""
- rid = request_id()
- assert isinstance(rid, str)
-
-
-def test_request_id_valid_uuid():
- """Test that request_id returns a valid UUID."""
- rid = request_id()
- uuid.UUID(rid) # Should not raise
-
-
-def test_request_id_unique():
- """Test that request_id generates unique IDs."""
- id1 = request_id()
- id2 = request_id()
- assert id1 != id2
-