From a20660ed515b4ed546d5f6864381522b37a4d93c Mon Sep 17 00:00:00 2001 From: Kaburagi Date: Tue, 23 Dec 2025 13:27:50 +0700 Subject: [PATCH 1/3] feat(service): Add ONVIFResponse wrapper for zeep objects with serialization support --- onvif/utils/service.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/onvif/utils/service.py b/onvif/utils/service.py index ef7fe26..add7632 100644 --- a/onvif/utils/service.py +++ b/onvif/utils/service.py @@ -1,12 +1,43 @@ # onvif/utils/service.py import logging +import zeep.helpers from .exceptions import ONVIFOperationException logger = logging.getLogger(__name__) logger.addHandler(logging.NullHandler()) +class ONVIFResponse: + """Transparent wrapper that adds to_dict() to zeep objects.""" + + def __init__(self, wrapped_object): + object.__setattr__(self, "_wrapped", wrapped_object) + + def __getattr__(self, name): + return getattr(self._wrapped, name) + + def __setattr__(self, name, value): + if name == "_wrapped": + object.__setattr__(self, name, value) + else: + setattr(self._wrapped, name, value) + + def __repr__(self): + return repr(self._wrapped) + + def __str__(self): + return str(self._wrapped) + + def to_dict(self): + """Convert zeep object to Python dictionary.""" + return ( + {} + if self._wrapped is None + else zeep.helpers.serialize_object(self._wrapped) + ) + + def _is_zeep_object(obj): """Check if an object is a Zeep-generated object. @@ -104,7 +135,7 @@ def wrapped_method(*args, **kwargs): logger.debug(f"Calling wrapped ONVIF method: {name}") result = attr(*args, **kwargs) logger.debug(f"ONVIF method {name} completed successfully") - return result + return ONVIFResponse(result) if result is not None else result except ONVIFOperationException as oe: # Re-raise ONVIF exceptions as-is service_name = getattr(self.operator, "service_name", "Unknown") From f600ef45f86c5d7f151f40b4ce5433829ac1e403 Mon Sep 17 00:00:00 2001 From: Kaburagi Date: Tue, 23 Dec 2025 13:40:26 +0700 Subject: [PATCH 2/3] docs(examples): Added example implementation of to_dict() --- examples/check_device.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/check_device.py b/examples/check_device.py index 2242c4b..300f475 100644 --- a/examples/check_device.py +++ b/examples/check_device.py @@ -6,12 +6,14 @@ This script connects to an ONVIF-compliant device and retrieves basic information such as device details and scopes using the Core (Device Management) service. +And using to_dict() (>= v0.2.8 patch) function to convert the response to a dictionary. """ +import json from onvif import ONVIFClient HOST = "192.168.1.3" -PORT = 80 +PORT = 8000 USERNAME = "admin" PASSWORD = "admin123" @@ -20,9 +22,9 @@ device = client.devicemgmt() # print device information - print(device.GetDeviceInformation()) + print(json.dumps(device.GetDeviceInformation().to_dict(), indent=4)) # print device scopes - print(device.GetScopes()) + print(json.dumps(device.GetScopes().to_dict(), indent=4)) except Exception as e: print(e) From 20e543547d8ce074529a05295d84ba84177fa1ee Mon Sep 17 00:00:00 2001 From: Kaburagi Date: Tue, 23 Dec 2025 13:44:14 +0700 Subject: [PATCH 3/3] =?UTF-8?q?Bump=20version=200.2.7=20=E2=86=92=200.2.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- README_ID.md | 6 +++--- onvif/__init__.py | 2 +- pyproject.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7185ffe..53c70b3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@
Ask DeepWiki -PyPI Version +PyPI Version Pepy Total Downloads
Build @@ -319,7 +319,7 @@ usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password [--cache {all,db,mem,none}] [--health-check-interval HEALTH_CHECK_INTERVAL] [--output OUTPUT] [--version] [service] [method] [params ...] -ONVIF Terminal Client — v0.2.7 +ONVIF Terminal Client — v0.2.8 https://github.com/nirsimetri/onvif-python positional arguments: @@ -400,7 +400,7 @@ Examples: 2. Interactive Shell ```bash -ONVIF Interactive Shell — v0.2.7 +ONVIF Interactive Shell — v0.2.8 https://github.com/nirsimetri/onvif-python Basic Commands: diff --git a/README_ID.md b/README_ID.md index d96d024..5d6e5bd 100644 --- a/README_ID.md +++ b/README_ID.md @@ -3,7 +3,7 @@
Ask DeepWiki -PyPI Version +PyPI Version Pepy Total Downloads
Build @@ -319,7 +319,7 @@ usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password [--cache {all,db,mem,none}] [--health-check-interval HEALTH_CHECK_INTERVAL] [--output OUTPUT] [--version] [service] [method] [params ...] -ONVIF Terminal Client — v0.2.7 +ONVIF Terminal Client — v0.2.8 https://github.com/nirsimetri/onvif-python positional arguments: @@ -401,7 +401,7 @@ Examples: ```bash -ONVIF Interactive Shell — v0.2.7 +ONVIF Interactive Shell — v0.2.8 https://github.com/nirsimetri/onvif-python Basic Commands: diff --git a/onvif/__init__.py b/onvif/__init__.py index ab72746..a4e7b3a 100644 --- a/onvif/__init__.py +++ b/onvif/__init__.py @@ -1,6 +1,6 @@ # onvif/__init__.py -__version__ = "0.2.7" +__version__ = "0.2.8" from .client import ONVIFClient from .operator import CacheMode diff --git a/pyproject.toml b/pyproject.toml index 921078f..8ef1484 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "onvif-python" -version = "0.2.7" +version = "0.2.8" description = "A modern Python library for ONVIF-compliant devices" readme = "README.md" requires-python = ">=3.9"