From e54309096e9a59c1621e7a9121a16e303c315edf Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 10 Oct 2026 03:56:28 +0700 Subject: [PATCH 01/38] docs: Documentation overhaul --- .github/workflows/documentation.yml | 2 +- README.md | 9 +- docs/api/core/index.md | 22 ++ docs/api/exceptions/index.md | 22 ++ docs/api/index.md | 46 ++++ .../{analytics.md => analytics/index.md} | 0 .../services/{ => analytics}/ruleengine.md | 0 .../services/{events.md => events/index.md} | 0 .../api/services/{ => events}/notification.md | 0 .../{ => events}/pausable_subscription.md | 0 docs/api/services/{ => events}/pullpoint.md | 0 .../api/services/{ => events}/subscription.md | 0 docs/api/services/index.md | 158 ++++++++++++ .../{ => security}/authorizationserver.md | 0 docs/api/services/{ => security}/dot1x.md | 0 .../index.md} | 0 docs/api/services/{ => security}/jwt.md | 0 docs/api/services/{ => security}/keystore.md | 0 .../services/{ => security}/mediasigning.md | 0 docs/api/services/{ => security}/tlsserver.md | 0 docs/api/utilities/index.md | 46 ++++ .../{core => utilities}/onvif_discovery.md | 0 docs/core/onvif_discovery.md | 1 - docs/hooks.py | 7 +- docs/index.md | 77 +++++- docs/installation.md | 12 + docs/javascripts/external-links.js | 12 +- docs/legal/license.md | 5 + docs/legal/{legal_notice.md => notice.md} | 5 + docs/{core => main}/onvif_cli.md | 21 +- docs/{core => main}/onvif_client.md | 5 + .../.icons/material/corporate-fare.svg | 1 + docs/overrides/.icons/material/sensors.svg | 1 + docs/philosophy.md | 5 + docs/project/contributing.md | 6 + docs/project/external.md | 23 +- docs/project/roadmap.md | 8 +- docs/project/used_by.md | 5 + docs/quick_start.md | 11 +- docs/references/implemented_services.md | 242 +++++++++++++++--- docs/references/service_bindings.md | 7 + docs/references/service_discovery.md | 7 +- docs/references/supported_profiles.md | 5 + docs/stylesheets/extra.css | 41 ++- docs/utilities/helper_methods.md | 5 + mkdocs.yml | 170 ++++++++---- onvif/operator.py | 6 +- onvif/utils/plugins.py | 4 +- onvif/utils/service.py | 4 +- onvif/utils/wsdl.py | 12 +- pyproject.toml | 2 + 51 files changed, 875 insertions(+), 140 deletions(-) create mode 100644 docs/api/core/index.md create mode 100644 docs/api/exceptions/index.md create mode 100644 docs/api/index.md rename docs/api/services/{analytics.md => analytics/index.md} (100%) rename docs/api/services/{ => analytics}/ruleengine.md (100%) rename docs/api/services/{events.md => events/index.md} (100%) rename docs/api/services/{ => events}/notification.md (100%) rename docs/api/services/{ => events}/pausable_subscription.md (100%) rename docs/api/services/{ => events}/pullpoint.md (100%) rename docs/api/services/{ => events}/subscription.md (100%) create mode 100644 docs/api/services/index.md rename docs/api/services/{ => security}/authorizationserver.md (100%) rename docs/api/services/{ => security}/dot1x.md (100%) rename docs/api/services/{advancedsecurity.md => security/index.md} (100%) rename docs/api/services/{ => security}/jwt.md (100%) rename docs/api/services/{ => security}/keystore.md (100%) rename docs/api/services/{ => security}/mediasigning.md (100%) rename docs/api/services/{ => security}/tlsserver.md (100%) create mode 100644 docs/api/utilities/index.md rename docs/api/{core => utilities}/onvif_discovery.md (100%) delete mode 100644 docs/core/onvif_discovery.md rename docs/legal/{legal_notice.md => notice.md} (98%) rename docs/{core => main}/onvif_cli.md (95%) rename docs/{core => main}/onvif_client.md (99%) create mode 100644 docs/overrides/.icons/material/corporate-fare.svg create mode 100644 docs/overrides/.icons/material/sensors.svg diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 4fcc1a2d..24dc03f2 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -26,7 +26,7 @@ jobs: - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: - python-version: "3.12" + python-version: "3.x" - name: Install documentation dependencies run: | diff --git a/README.md b/README.md index b5edd7e0..073190e3 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ -# ONVIF Python +# ONVIF Python [![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python) [![Python Version](https://img.shields.io/pypi/pyversions/onvif-python?logo=python&logoColor=white&color=blue&style=plastic&label=Python)](https://pypi.org/project/onvif-python) [![PyPI Version](https://img.shields.io/pypi/v/onvif-python?logo=pypi&logoColor=white&color=blue&style=plastic&label=PyPI)](https://pypi.org/project/onvif-python/) [![Quality](https://img.shields.io/codacy/grade/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Quality)](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard) [![Coverage](https://img.shields.io/codacy/coverage/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Coverage)](https://app.codacy.com/gh/nirsimetri/onvif-python/coverage) -[![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python)
[![Build](https://img.shields.io/github/actions/workflow/status/nirsimetri/onvif-python/python-app.yml?logo=github&style=plastic&label=Build)](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml) [![Upload Python](https://img.shields.io/github/actions/workflow/status/nirsimetri/onvif-python/python-publish.yml?logo=github&style=plastic&label=Upload%20Package)](https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml) @@ -36,6 +35,12 @@ From official [PyPI](https://pypi.org/project/onvif-python/): pip install --upgrade onvif-python ``` +Or install using [pipx](https://pipx.pypa.io/stable/) for an isolated environment: +```shell +pipx install git+https://github.com/nirsimetri/onvif-python + +``` + Or clone this repository and install locally: ```shell git clone https://github.com/nirsimetri/onvif-python diff --git a/docs/api/core/index.md b/docs/api/core/index.md new file mode 100644 index 00000000..ca2c73ff --- /dev/null +++ b/docs/api/core/index.md @@ -0,0 +1,22 @@ +--- +hide: + - toc +--- + +# Core API + +
+ +- :material-lan-connect:{ .lg .middle }  [**ONVIFClient**](onvif_client.md) + + --- + + Connect to ONVIF devices, configure connections and authenticaton, and manage service access. + +- :material-connection:{ .lg .middle }  [**ONVIFOperator**](onvif_operator.md) + + --- + + An **internal class** for coordinating ONVIF operations and managing service interactions. + +
\ No newline at end of file diff --git a/docs/api/exceptions/index.md b/docs/api/exceptions/index.md new file mode 100644 index 00000000..6e375756 --- /dev/null +++ b/docs/api/exceptions/index.md @@ -0,0 +1,22 @@ +--- +hide: + - toc +--- + +# Exceptions + +
+ +- :material-alert-circle-outline:{ .lg .middle }  [**ONVIFOperationException**](onvif_exception.md) + + --- + + Understand exceptions raised by failed ONVIF operations, including error details for diagnosing issues. + +- :material-reload-alert:{ .lg .middle }  [**Error Handlers**](onvif_error_handlers.md) + + --- + + Explore error-handling utilities for processing and managing errors consistently across ONVIF operations. + +
\ No newline at end of file diff --git a/docs/api/index.md b/docs/api/index.md new file mode 100644 index 00000000..1c16c58a --- /dev/null +++ b/docs/api/index.md @@ -0,0 +1,46 @@ +--- +hide: + - toc +--- + +# API Reference + +
+ +- :material-hub-outline:{ .lg .middle }  **Core** + + --- + + Configure ONVIF connections and interact with devices through the main client interfaces. + +
+ [:octicons-arrow-right-24: Explore Core](core/index.md) + +- :material-alert-circle-outline:{ .lg .middle }  **Exceptions** + + --- + + Understand operation exceptions and error-handling utilities for diagnosing and handling failures. + +
+ [:octicons-arrow-right-24: Explore Exceptions](exceptions/index.md) + +- :material-toolbox:{ .lg .middle }  **Utilities** + + --- + + Discover ONVIF devices, configure caching, manage WSDL resources, and extend service behavior. + +
+ [:octicons-arrow-right-24: Explore Utilities](utilities/index.md) + +- :material-package-variant:{ .lg .middle }  **Services** + + --- + + Browse the available ONVIF service clients, from device management, events, PTZ, analytics, and more. + +
+ [:octicons-arrow-right-24: Explore Services](services/index.md) + +
\ No newline at end of file diff --git a/docs/api/services/analytics.md b/docs/api/services/analytics/index.md similarity index 100% rename from docs/api/services/analytics.md rename to docs/api/services/analytics/index.md diff --git a/docs/api/services/ruleengine.md b/docs/api/services/analytics/ruleengine.md similarity index 100% rename from docs/api/services/ruleengine.md rename to docs/api/services/analytics/ruleengine.md diff --git a/docs/api/services/events.md b/docs/api/services/events/index.md similarity index 100% rename from docs/api/services/events.md rename to docs/api/services/events/index.md diff --git a/docs/api/services/notification.md b/docs/api/services/events/notification.md similarity index 100% rename from docs/api/services/notification.md rename to docs/api/services/events/notification.md diff --git a/docs/api/services/pausable_subscription.md b/docs/api/services/events/pausable_subscription.md similarity index 100% rename from docs/api/services/pausable_subscription.md rename to docs/api/services/events/pausable_subscription.md diff --git a/docs/api/services/pullpoint.md b/docs/api/services/events/pullpoint.md similarity index 100% rename from docs/api/services/pullpoint.md rename to docs/api/services/events/pullpoint.md diff --git a/docs/api/services/subscription.md b/docs/api/services/events/subscription.md similarity index 100% rename from docs/api/services/subscription.md rename to docs/api/services/events/subscription.md diff --git a/docs/api/services/index.md b/docs/api/services/index.md new file mode 100644 index 00000000..b078102c --- /dev/null +++ b/docs/api/services/index.md @@ -0,0 +1,158 @@ +--- +hide: + - toc +--- + +# ONVIF Services + +Browse the ONVIF service clients exposed by `onvif-python`. Each service provides access to operations defined by the corresponding ONVIF specifications and supported device capabilities. + +
+ +- :material-devices:{ .lg .middle }  **Device Management** + + --- + + Manage device configuration, device capabilities, interfaces, and related hardware functionality. + +
+ [:octicons-arrow-right-24: Device](device.md) + + [:octicons-arrow-right-24: DeviceIO](deviceio.md) + + [:octicons-arrow-right-24: Display](display.md) + + [:octicons-arrow-right-24: Thermal](thermal.md) + +- :material-sensors:{ .lg .middle }  **Events & Notifications** + + --- + + Subscribe to device events, retrieve notifications, and manage event subscriptions and pull-point mechanisms. + +
+ [:octicons-arrow-right-24: Events](events/index.md) + + [:octicons-arrow-right-24: PullPoint](events/pullpoint.md) + + [:octicons-arrow-right-24: Notification](events/notification.md) + + [:octicons-arrow-right-24: Subscription](events/subscription.md) + + [:octicons-arrow-right-24: PausableSubscription](events/pausable_subscription.md) + + +- :material-video:{ .lg .middle }  **Media & Imaging** + + --- + + Access media profiles, streaming configuration, video sources, imaging settings, and related media operations. + +
+ [:octicons-arrow-right-24: Media](media.md) + + [:octicons-arrow-right-24: Media2](media2.md) + + [:octicons-arrow-right-24: Imaging](imaging.md) + +- :material-pan:{ .lg .middle }  **Device Control** + + --- + + Control device movement (PTZ), focus, presets, and supported movement functions. + +
+ [:octicons-arrow-right-24: PTZ](ptz.md) + + [:octicons-arrow-right-24: Provisioning](provisioning.md) + + +- :material-chart-box-outline:{ .lg .middle }  **Analytics** + + --- + + Interact with analytics functionality, rule engines, and analytics-related device services. + +
+ [:octicons-arrow-right-24: Analytics](analytics/index.md) + + [:octicons-arrow-right-24: RuleEngine](analytics/ruleengine.md) + + [:octicons-arrow-right-24: AnalyticsDevice](analyticsdevice.md) + +- :material-filmstrip-box:{ .lg .middle }  **Recording & Playback** + + --- + + Access recording configuration, search for recorded content, replay media, and manage receiver functionality. + +
+ [:octicons-arrow-right-24: Recording](recording.md) + + [:octicons-arrow-right-24: Search](search.md) + + [:octicons-arrow-right-24: Replay](replay.md) + + [:octicons-arrow-right-24: Receiver](receiver.md) + +- :material-calendar-clock:{ .lg .middle }  **Automation & Scheduling** + + --- + + Configure device actions and time-based schedules for automated operations. + +
+ [:octicons-arrow-right-24: ActionEngine](actionengine.md) + + [:octicons-arrow-right-24: Schedule](schedule.md) + +- :material-door-closed-lock:{ .lg .middle }  **Access Control** + + --- + + Manage access control systems, door operations, and access rules through ONVIF services. + +
+ [:octicons-arrow-right-24: AccessControl](accesscontrol.md) + + [:octicons-arrow-right-24: DoorControl](doorcontrol.md) + + [:octicons-arrow-right-24: AccessRules](accessrules.md) + + [:octicons-arrow-right-24: AuthenticationBehavior](authenticationbehavior.md) + + [:octicons-arrow-right-24: Credential](credential.md) + +- :material-security:{ .lg .middle }  **Security** + + --- + + Explore ONVIF security services for authentication, authorization, network authentication, cryptographic key management, and media integrity. + +
+ [:octicons-arrow-right-24: AdvancedSecurity](security/index.md) + + [:octicons-arrow-right-24: AuthorizationServer](security/authorizationserver.md) + + [:octicons-arrow-right-24: Dot1x](security/dot1x.md) + + [:octicons-arrow-right-24: JWT](security/jwt.md) + + [:octicons-arrow-right-24: KeyStore](security/keystore.md) + + [:octicons-arrow-right-24: MediaSigning](security/mediasigning.md) + + [:octicons-arrow-right-24: TLSServer](security/tlsserver.md) + +- :material-lan:{ .lg .middle }  **Connectivity & Applications** + + --- + + Manage device applications and establish connectivity between services behind firewalls and internet-accessible clients. + +
+ [:octicons-arrow-right-24: AppManagement](appmgmt.md) + + [:octicons-arrow-right-24: Uplink](uplink.md) + +
\ No newline at end of file diff --git a/docs/api/services/authorizationserver.md b/docs/api/services/security/authorizationserver.md similarity index 100% rename from docs/api/services/authorizationserver.md rename to docs/api/services/security/authorizationserver.md diff --git a/docs/api/services/dot1x.md b/docs/api/services/security/dot1x.md similarity index 100% rename from docs/api/services/dot1x.md rename to docs/api/services/security/dot1x.md diff --git a/docs/api/services/advancedsecurity.md b/docs/api/services/security/index.md similarity index 100% rename from docs/api/services/advancedsecurity.md rename to docs/api/services/security/index.md diff --git a/docs/api/services/jwt.md b/docs/api/services/security/jwt.md similarity index 100% rename from docs/api/services/jwt.md rename to docs/api/services/security/jwt.md diff --git a/docs/api/services/keystore.md b/docs/api/services/security/keystore.md similarity index 100% rename from docs/api/services/keystore.md rename to docs/api/services/security/keystore.md diff --git a/docs/api/services/mediasigning.md b/docs/api/services/security/mediasigning.md similarity index 100% rename from docs/api/services/mediasigning.md rename to docs/api/services/security/mediasigning.md diff --git a/docs/api/services/tlsserver.md b/docs/api/services/security/tlsserver.md similarity index 100% rename from docs/api/services/tlsserver.md rename to docs/api/services/security/tlsserver.md diff --git a/docs/api/utilities/index.md b/docs/api/utilities/index.md new file mode 100644 index 00000000..e31d613c --- /dev/null +++ b/docs/api/utilities/index.md @@ -0,0 +1,46 @@ +--- +hide: + - toc +--- + +# Utilities + +
+ +- :material-radar:{ .lg .middle }  [**ONVIFDiscovery**](onvif_discovery.md) + + --- + + Discover ONVIF-compliant devices on the local network using WS-Discovery multicast. + +- :material-database-cog-outline:{ .lg .middle }  [**CacheMode**](cache_mode.md) + + --- + + Configure the caching strategy used by the library to balance performance and resource usage. + +- :material-file-cog-outline:{ .lg .middle }  [**ONVIFWSDL**](onvif_wsdl.md) + + --- + + Work with WSDL resources used to describe ONVIF service operations and their SOAP interfaces. + +- :material-cog-outline:{ .lg .middle }  [**ONVIFService**](onvif_service.md) + + --- + + Provides shared functionality for ONVIF service clients and common service operations. + +- :material-xml:{ .lg .middle }  [**ZeepPatcher**](zeep_patcher.md) + + --- + + Apply compatibility enhancements to Zeep SOAP processing for ONVIF-specific behavior. + +- :material-puzzle-outline:{ .lg .middle }  [**Plugins**](plugins.md) + + --- + + Explore plugin-related functionality for extending or customizing supported library behavior. + +
\ No newline at end of file diff --git a/docs/api/core/onvif_discovery.md b/docs/api/utilities/onvif_discovery.md similarity index 100% rename from docs/api/core/onvif_discovery.md rename to docs/api/utilities/onvif_discovery.md diff --git a/docs/core/onvif_discovery.md b/docs/core/onvif_discovery.md deleted file mode 100644 index eeefc2ae..00000000 --- a/docs/core/onvif_discovery.md +++ /dev/null @@ -1 +0,0 @@ -To be written.. see [`ONVIFDiscovery`](../api/core/onvif_discovery.md) \ No newline at end of file diff --git a/docs/hooks.py b/docs/hooks.py index 615df332..1aef365e 100644 --- a/docs/hooks.py +++ b/docs/hooks.py @@ -1,6 +1,9 @@ -def on_page_content(html, page, config, files): +"""Mkdocs hooks.""" + + +def on_page_content(html, page, config, files): # pylint: disable=unused-argument """Exclude mkdocstrings source blocks from Material search.""" return html.replace( '
', '
', - ) \ No newline at end of file + ) diff --git a/docs/index.md b/docs/index.md index 424bed7d..26aca859 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,10 +1,15 @@ -# ONVIF Python +--- +hide: + - navigation +--- + +# ONVIF Python  [![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python){ .no-external-icon } + [![Python Version](https://img.shields.io/pypi/pyversions/onvif-python?logo=python&logoColor=white&color=blue&style=plastic&label=Python)](https://pypi.org/project/onvif-python){ .no-external-icon } [![PyPI Version](https://img.shields.io/pypi/v/onvif-python?logo=pypi&logoColor=white&color=blue&style=plastic&label=PyPI)](https://pypi.org/project/onvif-python/){ .no-external-icon } [![Quality](https://img.shields.io/codacy/grade/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Quality)](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard){ .no-external-icon } [![Coverage](https://img.shields.io/codacy/coverage/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Coverage)](https://app.codacy.com/gh/nirsimetri/onvif-python/coverage){ .no-external-icon } -[![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python){ .no-external-icon }
[![Build](https://img.shields.io/github/actions/workflow/status/nirsimetri/onvif-python/python-app.yml?logo=github&style=plastic&label=Build)](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml){ .no-external-icon } [![Upload Python](https://img.shields.io/github/actions/workflow/status/nirsimetri/onvif-python/python-publish.yml?logo=github&style=plastic&label=Upload%20Package)](https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml){ .no-external-icon } @@ -18,13 +23,67 @@ Behind the scenes, ONVIF communication relies on **[SOAP](https://en.wikipedia.o This library simplifies that process by wrapping SOAP communication into a clean, Pythonic API. You no longer need to handle low-level XML parsing, namespaces, or security tokens manually; the library takes care of it, letting you focus on building functionality. ## Who Is It For? -- **Individual developers** exploring ONVIF or building hobby projects -- **Companies** building video intelligence, analytics, or VMS platforms -- **Security integrators** who need reliable ONVIF interoperability across devices + +
+ +- :material-account-hard-hat:{ .lg .middle }  **Individual Developers** + + --- + + Explore ONVIF capabilities, experiment with network cameras, and build hobby projects. + +- :material-corporate-fare:{ .lg .middle }  **Companies** + + --- + + Build video intelligence, analytics, and video management system (VMS) platforms. + +- :material-cctv:{ .lg .middle }  **Security Integrators** + + --- + + Ensure reliable ONVIF interoperability across cameras and other security devices. + +- :material-chip:{ .lg .middle }  **IoT Experts** + + --- + + Test security, assess interoperability, and investigate ONVIF-enabled devices, and related systems. + +
## Requirements -- **Python**: 3.10 or higher -- **Dependencies**: - - [`zeep>=4.3.0`](https://github.com/mvantellingen/python-zeep) - SOAP client for ONVIF communication - - [`requests>=2.32.0`](https://github.com/psf/requests) - HTTP library for network requests +
+ +- :material-language-python:{ .lg .middle }  **Python** + + --- + + Python **3.10 or higher** is required. + +- :material-package-variant-closed:{ .lg .middle }  **Zeep** + + --- + + SOAP client for ONVIF communication. + + [:octicons-arrow-right-24: GitHub](https://github.com/mvantellingen/python-zeep){ .no-external-icon } + +- :material-package-variant-closed:{ .lg .middle }  **Requests** + + --- + + HTTP library for network requests. + + [:octicons-arrow-right-24: GitHub](https://github.com/psf/requests){ .no-external-icon } + +- :material-package-variant-closed:{ .lg .middle }  **Pyreadline3** + + --- + + Only installed on Windows (`win32`). + + [:octicons-arrow-right-24: GitHub](https://github.com/pyreadline3/pyreadline3){ .no-external-icon } + +
diff --git a/docs/installation.md b/docs/installation.md index 3ac6ba09..0942c87d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,6 +1,18 @@ +--- +hide: + - path +--- + From official [PyPI](https://pypi.org/project/onvif-python/): ```console pip install --upgrade onvif-python + +``` + +Or install using [pipx](https://pipx.pypa.io/stable/) for an isolated environment: +```console +pipx install git+https://github.com/nirsimetri/onvif-python + ``` Or clone this repository and install locally: diff --git a/docs/javascripts/external-links.js b/docs/javascripts/external-links.js index 114b96fa..4d58338e 100644 --- a/docs/javascripts/external-links.js +++ b/docs/javascripts/external-links.js @@ -2,6 +2,14 @@ document$.subscribe(() => { document.querySelectorAll('.md-content a[href]').forEach((link) => { + if ( + link.closest('.md-content__button') || + link.closest('.md-content__button--edit') || + link.closest('.md-content__button--view') + ) { + return; + } + const url = new URL(link.href, window.location.href); if ( @@ -20,9 +28,7 @@ document$.subscribe(() => { icon.setAttribute("aria-hidden", "true"); icon.innerHTML = ` - - - + `; link.appendChild(icon); diff --git a/docs/legal/license.md b/docs/legal/license.md index 11a8ebbf..34a36ed0 100644 --- a/docs/legal/license.md +++ b/docs/legal/license.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + MIT License Copyright (c) 2025-2026 Nirsimetri Technologies® diff --git a/docs/legal/legal_notice.md b/docs/legal/notice.md similarity index 98% rename from docs/legal/legal_notice.md rename to docs/legal/notice.md index 6de503db..293b51d7 100644 --- a/docs/legal/legal_notice.md +++ b/docs/legal/notice.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + This project is an **independent open-source implementation** of the [ONVIF](https://www.onvif.org) specifications. It is **not affiliated with, endorsed by, or sponsored by ONVIF** or its member companies. - The name **“ONVIF”** and the ONVIF logo are registered trademarks of the ONVIF organization. diff --git a/docs/core/onvif_cli.md b/docs/main/onvif_cli.md similarity index 95% rename from docs/core/onvif_cli.md rename to docs/main/onvif_cli.md index c46e173a..7f4c9bcb 100644 --- a/docs/core/onvif_cli.md +++ b/docs/main/onvif_cli.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + ![Windows](https://img.shields.io/badge/Windows-0078D6?style=plastic&logo=gitforwindows&logoColor=white) ![Linux](https://img.shields.io/badge/Linux-FCC624?style=plastic&logo=linux&logoColor=black) ![macOS](https://img.shields.io/badge/macOS-1A9FEE?style=plastic&logo=apple&logoColor=white) @@ -45,13 +50,13 @@ This library includes a powerful command-line interface (CLI) for interacting wi ??? abstract "Direct CLI" - ```shell + ```shell { data-search-exclude } usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password PASSWORD] [--discover] [--filter FILTER] [--interface INTERFACE] [--discovery-timeout DISCOVERY_TIMEOUT] [--search SEARCH] [--page PAGE] [--per-page PER_PAGE] [--timeout TIMEOUT] [--digest] [--https] [--no-verify] [--no-patch] [--interactive] [--debug] [--wsdl WSDL] [--cache {none,mem,db}] [--health-check-interval HEALTH_CHECK_INTERVAL] [--output OUTPUT] [--version] [service] [method] [params ...] - ONVIF Terminal Client — v0.4.4 + ONVIF Terminal Client — https://github.com/nirsimetri/onvif-python positional arguments: @@ -132,8 +137,8 @@ This library includes a powerful command-line interface (CLI) for interacting wi ??? abstract "Interactive Shell" - ```shell - ONVIF Interactive Shell — v0.4.4 + ```shell { data-search-exclude } + ONVIF Interactive Shell — https://github.com/nirsimetri/onvif-python Basic Commands: @@ -236,7 +241,9 @@ If you omit the username or password, you will be prompted to enter them securel | `exit` | Exit the shell | !!! warning - You can see all the other commands available in the interactive shell by trying it out directly. The interactive shell runs periodic background health checks to detect connection loss. It uses silent TCP pings to avoid interrupting your work and will automatically exit if the device is unreachable, similar to an SSH session. + You can see all the other commands available in the interactive shell by trying it out directly with `help` command from interactive shell. + + The interactive shell runs periodic background health checks to detect connection loss. It uses silent TCP pings to avoid interrupting your work and will automatically exit if the device is unreachable, similar to an SSH session. #### Command Chaining with `&&` @@ -262,7 +269,7 @@ This feature is particularly useful for: ### Device Discovery -The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol with [`ONVIFDiscovery`](../api/core/onvif_discovery.md) class. This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand (applied at [`>=v0.1.2`](../releases.md/#v0.1.2)). +The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol with [`ONVIFDiscovery`](../api/utilities/onvif_discovery.md) class. This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand (applied at [`>=v0.1.2`](../releases.md/#v0.1.2)). !!! danger - Discovery only works on the local network (same subnet) @@ -310,7 +317,7 @@ onvif media GetProfiles -d -u admin -p password 4. **Connection**: Once you select a device, the CLI automatically connects using the discovered host and port #### Example Discovery Output -```shell +```shell { data-search-exclude } onvif -d -i Discovering ONVIF devices on network... diff --git a/docs/core/onvif_client.md b/docs/main/onvif_client.md similarity index 99% rename from docs/core/onvif_client.md rename to docs/main/onvif_client.md index 008e5a88..14422606 100644 --- a/docs/core/onvif_client.md +++ b/docs/main/onvif_client.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + The [`ONVIFClient`](../api/core/onvif_client.md) class provides various configuration options to customize the connection behavior, caching strategy, security settings, and debugging capabilities. Below is a detailed description of all available parameters: diff --git a/docs/overrides/.icons/material/corporate-fare.svg b/docs/overrides/.icons/material/corporate-fare.svg new file mode 100644 index 00000000..0b16a417 --- /dev/null +++ b/docs/overrides/.icons/material/corporate-fare.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/.icons/material/sensors.svg b/docs/overrides/.icons/material/sensors.svg new file mode 100644 index 00000000..1c881aaa --- /dev/null +++ b/docs/overrides/.icons/material/sensors.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/philosophy.md b/docs/philosophy.md index 8074fa16..d0a42b90 100644 --- a/docs/philosophy.md +++ b/docs/philosophy.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + !!! info This library will be continuously updated as ONVIF versions are updated. It uses a built-in WSDL that will always follow changes to the [ONVIF WSDL Specifications](https://github.com/onvif/specs). diff --git a/docs/project/contributing.md b/docs/project/contributing.md index 0723866a..6d0b09ed 100644 --- a/docs/project/contributing.md +++ b/docs/project/contributing.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + ## Contributors @@ -216,6 +221,7 @@ docs/ ├── utilities/ ├── project/ ├── legal/ +├── hooks.py ├── index.md ├── installation.md ├── quick_start.md diff --git a/docs/project/external.md b/docs/project/external.md index 62f6f9bd..d5df10a5 100644 --- a/docs/project/external.md +++ b/docs/project/external.md @@ -1,19 +1,20 @@ -## Related Projects +--- +hide: + - path +--- -- [onvif-products-directory](https://github.com/nirsimetri/onvif-products-directory): - This project is a comprehensive ONVIF data aggregation and management suite, designed to help developers explore, analyze, and process ONVIF-compliant product information from hundreds of manufacturers worldwide. +## Related Projects -- (soon) [onvif-rest-server](https://github.com/nirsimetri/onvif-rest-server): - A RESTful API server for ONVIF devices, enabling easy integration of ONVIF device management, media streaming, and other capabilities into web applications and services. +- (soon) [onvif-proxy](https://github.com/nirsimetri/onvif-proxy): + A middleware proxy that provides a unified REST API for interacting with ONVIF-compliant devices. - (soon) [onvif-mcp](https://github.com/nirsimetri/onvif-mcp): - A Model Context Protocol (MCP) server for ONVIF, providing a unified API and context-based integration for ONVIF devices, clients, and services. It enables advanced automation, orchestration, and interoperability across ONVIF-compliant devices and clients. + An MCP server that enables AI assistants and agents to discover, manage, and control ONVIF-compliant devices. ## Links +- [ONVIF Application Programmer's Guide](https://www.onvif.org/wp-content/uploads/2016/12/ONVIF_WG-APG-Application_Programmers_Guide-1.pdf) - [ONVIF Official Specifications](https://www.onvif.org/profiles/specifications/specification-history/) -- [ONVIF Developer Specs](https://developer.onvif.org/pub/specs/branches/development/doc/index.html) - [ONVIF Official Specs Repository](https://github.com/onvif/specs) -- [ONVIF Application Programmer's Guide](https://www.onvif.org/wp-content/uploads/2016/12/ONVIF_WG-APG-Application_Programmers_Guide-1.pdf) -- [ONVIF 2.0 Service Operation Index](https://www.onvif.org/onvif/ver20/util/operationIndex.html) -- [ONVIF conformant products list](https://www.onvif.org/conformant-products/) -- [ONVIF Profile Feature Overview v2.6](https://www.onvif.org/wp-content/uploads/2022/04/onvif-profile-feature-overview.pdf) \ No newline at end of file +- [ONVIF Developer Specs](https://developer.onvif.org/pub/specs/branches/development/doc/index.html) +- [ONVIF Profile Feature Overview](https://www.onvif.org/wp-content/uploads/2022/04/onvif-profile-feature-overview.pdf) +- [ONVIF conformant products list](https://www.onvif.org/conformant-products/) \ No newline at end of file diff --git a/docs/project/roadmap.md b/docs/project/roadmap.md index 1685a38c..d11776e3 100644 --- a/docs/project/roadmap.md +++ b/docs/project/roadmap.md @@ -1,3 +1,9 @@ +--- +hide: + - toc + - path +--- + ## Stay tuned and star ⭐ this repo [![GitHub stars](https://img.shields.io/github/stars/nirsimetri/onvif-python?style=social)](https://github.com/nirsimetri/onvif-python){ .no-external-icon } @@ -6,7 +12,7 @@ - [x] Add functionality for `ONVIFClient` to accept a custom `wsdl_dir` ([`v0.1.0`](../releases.md/#v0.1.0)) - [x] Add `ONVIF CLI` program to interact directly with ONVIF devices via terminal ([`v0.1.1`](../releases.md/#v0.1.1)) - [x] Enhance documentation with API references and diagrams (not from [AI Wiki](https://deepwiki.com/nirsimetri/onvif-python)) ([`v0.3.1`](../releases.md/#v0.3.1)) -- [ ] Add asynchronous (`async`/`await`) support for non-blocking ONVIF operations and concurrent device communication +- [ ] Add asynchronous (`async`/`await`) support for non-blocking operations - [ ] Implement structured data models for ONVIF Schemas using [xsdata](https://github.com/tefra/xsdata) - [ ] Add more usage examples for advanced features - [ ] Add benchmarking and performance metrics diff --git a/docs/project/used_by.md b/docs/project/used_by.md index 4549b535..f52a6293 100644 --- a/docs/project/used_by.md +++ b/docs/project/used_by.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + With Total Downloads, the `onvif-python` library is already being used by several well-known open-source projects, including: ## Viseron diff --git a/docs/quick_start.md b/docs/quick_start.md index 4dcc8f03..afb68389 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -1,13 +1,18 @@ +--- +hide: + - path +--- + Below are simple examples to help you get started with the ONVIF Python library. These demonstrate how to discover and connect to ONVIF-compliant devices and retrieve basic device information. -!!! tip "For beginners" +!!! note "For beginners" If you're new to ONVIF and want to learn more, we highly recommend taking the official free online course provided by ONVIF at [Introduction to ONVIF Course](https://www.onvif.org/about/introduction-to-onvif-course). - Please note that we are not endorsed or sponsored by ONVIF, see [Legal Notice](legal/legal_notice.md) for details. + Please note that we are not endorsed or sponsored by ONVIF, see [Legal Notice](legal/notice.md) for details. ### Discover ONVIF Devices -Use [`ONVIFDiscovery`](api/core/onvif_discovery.md) (applied at [`>=v0.1.6`](releases.md/#v0.1.6)) to automatically find ONVIF devices on your local network: +Use [`ONVIFDiscovery`](api/utilities/onvif_discovery.md) (applied at [`>=v0.1.6`](releases.md/#v0.1.6)) to automatically find ONVIF devices on your local network: ```python linenums="1" from onvif import ONVIFDiscovery diff --git a/docs/references/implemented_services.md b/docs/references/implemented_services.md index 90500100..903fc2f0 100644 --- a/docs/references/implemented_services.md +++ b/docs/references/implemented_services.md @@ -1,31 +1,215 @@ +--- +hide: + - path +--- + Below is a list of ONVIF services implemented and supported by this library, along with links to the official specifications, service definitions, and schema files as referenced from the [ONVIF Developer Specs](https://developer.onvif.org/pub/specs/branches/development/doc/index.html). -| Service | Specs | Service Definitions | Schema Files | Status | -|------------------------|-------------------------------|-----------------------------|-------------------------------------|------------| -| Device Management | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Core.xml) | [device.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/device/wsdl/devicemgmt.wsdl) | [onvif.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/schema/onvif.xsd)
[common.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/schema/common.xsd) | Complete | -| Events | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Core.xml) | [event.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/events/wsdl/event.wsdl) | [onvif.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/schema/onvif.xsd)
[common.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/schema/common.xsd) | Complete | -| Access Control | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/AccessControl.xml) | [accesscontrol.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/pacs/accesscontrol.wsdl) | [types.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/pacs/types.xsd) | Complete | -| Access Rules | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/AccessRules.xml) | [accessrules.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/accessrules/wsdl/accessrules.wsdl) | - | Complete | -| Action Engine | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/ActionEngine.xml) | [actionengine.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/actionengine.wsdl) | - | Complete | -| Analytics | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Analytics.xml) | [analytics.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/analytics/wsdl/analytics.wsdl) | [rules.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/analytics/rules.xsd)
[humanbody.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/analytics/humanbody.xsd)
[humanface.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/analytics/humanface.xsd) | Complete | -| Analytics Device | [Document](https://www.onvif.org/specs/srv/analytics/ONVIF-VideoAnalyticsDevice-Service-Spec-v211.pdf) | [analyticsdevice.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/analyticsdevice.wsdl) | - | Complete | -| Application Management | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/AppMgmt.xml) | [appmgmt.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/appmgmt/wsdl/appmgmt.wsdl) | - | Complete | -| Authentication Behavior| [Document](https://developer.onvif.org/pub/specs/branches/development/doc/AuthenticationBehavior.xml) | [authenticationbehavior.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl) | - | Complete | -| Cloud Integration | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/CloudIntegration.xml) | [cloudintegration.yaml](https://developer.onvif.org/pub/specs/branches/development/doc/yaml.php?yaml=cloudintegration.yaml) | - | ❌ Not yet | -| Credential | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Credential.xml) | [credential.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/credential/wsdl/credential.wsdl) | - | Complete | -| Device IO | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/DeviceIo.xml) | [deviceio.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/deviceio.wsdl) |- | Complete | -| Display | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Display.xml) | [display.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/display.wsdl) | - | Complete | -| Door Control | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/DoorControl.xml) | [doorcontrol.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/pacs/doorcontrol.wsdl) | - | Complete | -| Imaging | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Imaging.xml) | [imaging.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/imaging/wsdl/imaging.wsdl) | - | Complete | -| Media | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Media.xml) | [media.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/media/wsdl/media.wsdl) | - | Complete | -| Media 2 | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Media2.xml) | [media2.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/media/wsdl/media.wsdl) | - | Complete | -| Provisioning | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Provisioning.xml) | [provisioning.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/provisioning/wsdl/provisioning.wsdl) | - | Complete | -| PTZ | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/PTZ.xml) | [ptz.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/ptz/wsdl/ptz.wsdl) | - | Complete | -| Receiver | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Receiver.xml) | [receiver.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/receiver.wsdl) | - | Complete | -| Recording Control | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/RecordingControl.xml) | [recording.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/recording.wsdl) | - | Complete | -| Recording Search | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/RecordingSearch.xml) | [search.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/search.wsdl) | - | Complete | -| Replay Control | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Replay.xml) | [replay.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/replay.wsdl) | - | Complete | -| Schedule | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Schedule.xml) | [schedule.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/schedule/wsdl/schedule.wsdl) | - | Complete | -| Security | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Security.xml) | [advancedsecurity.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | - | Complete | -| Thermal | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Thermal.xml) | [thermal.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/thermal/wsdl/thermal.wsdl) | [radiometry.xsd](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver20/analytics/radiometry.xsd) | Complete | -| Uplink | [Document](https://developer.onvif.org/pub/specs/branches/development/doc/Uplink.xml) | [uplink.wsdl](https://developer.onvif.org/pub/specs/branches/development/wsdl/ver10/uplink/wsdl/uplink.wsdl) | - | Complete | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ServiceSpecsService DefinitionsSchema FilesStatus
Device ManagementDocumentdevice.wsdl + onvif.xsd
+ common.xsd +
Complete
EventsDocumentevent.wsdlComplete
Access ControlDocumentaccesscontrol.wsdltypes.xsdComplete
Access RulesDocumentaccessrules.wsdl-Complete
Action EngineDocumentactionengine.wsdl-Complete
AnalyticsDocumentanalytics.wsdl + rules.xsd
+ humanbody.xsd
+ humanface.xsd +
Complete
Analytics DeviceDocumentanalyticsdevice.wsdl-Complete
Application ManagementDocumentappmgmt.wsdl-Complete
Authentication BehaviorDocumentauthenticationbehavior.wsdl-Complete
Cloud IntegrationDocumentcloudintegration.yaml-❌ Not yet
CredentialDocumentcredential.wsdl-Complete
Device IODocumentdeviceio.wsdl-Complete
DisplayDocumentdisplay.wsdl-Complete
Door ControlDocumentdoorcontrol.wsdl-Complete
ImagingDocumentimaging.wsdl-Complete
MediaDocumentmedia.wsdl-Complete
Media 2Documentmedia2.wsdl-Complete
ProvisioningDocumentprovisioning.wsdl-Complete
PTZDocumentptz.wsdl-Complete
ReceiverDocumentreceiver.wsdl-Complete
Recording ControlDocumentrecording.wsdl-Complete
Recording SearchDocumentsearch.wsdl-Complete
Replay ControlDocumentreplay.wsdl-Complete
ScheduleDocumentschedule.wsdl-Complete
SecurityDocumentadvancedsecurity.wsdlbaselineComplete
ThermalDocumentthermal.wsdlradiometry.xsdComplete
UplinkDocumentuplink.wsdl-Complete
\ No newline at end of file diff --git a/docs/references/service_bindings.md b/docs/references/service_bindings.md index 9ee6616e..7db24caa 100644 --- a/docs/references/service_bindings.md +++ b/docs/references/service_bindings.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + ONVIF services are defined by WSDL bindings. In this library, there are two main patterns: ### Single Binding Services @@ -30,6 +35,7 @@ Some ONVIF services have multiple bindings in the same WSDL. These typically inc - **Sub-bindings:** - `PullPointSubscriptionBinding` (created via `CreatePullPointSubscription`) - `SubscriptionManagerBinding` (manages existing subscriptions) + - `PausableSubscriptionManagerBinding` (manages existing pausable subscriptions) - `NotificationProducerBinding` **Usage in library:** @@ -38,6 +44,7 @@ Some ONVIF services have multiple bindings in the same WSDL. These typically inc client.events() # root binding client.pullpoint(subscription) # sub-binding (dynamic, via SubscriptionReference) client.subscription(subscription) # sub-binding (dynamic, via SubscriptionReference) + client.pausable_subscription(subscription) # sub-binding (dynamic, via SubscriptionReference) client.notification() # sub-binding accessor ``` diff --git a/docs/references/service_discovery.md b/docs/references/service_discovery.md index 79c3704b..8526cacf 100644 --- a/docs/references/service_discovery.md +++ b/docs/references/service_discovery.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + !!! warning Before performing any operations on an ONVIF device, it is highly recommended to discover which services are available and supported by the device. @@ -19,7 +24,7 @@ By checking available services, your application can adapt its workflow and UI t ## How service discovery works in this library -!!! tip +!!! question "Behind the scene" The library handles service discovery automatically with intelligent fallback. You typically don't need to call discovery methods manually unless you need detailed capability information or want to refresh the service list after device configuration changes. The [`ONVIFClient`](../api/core/onvif_client.md) uses a **3-tier discovery approach** to maximize device compatibility: diff --git a/docs/references/supported_profiles.md b/docs/references/supported_profiles.md index fcbd148c..7cd73545 100644 --- a/docs/references/supported_profiles.md +++ b/docs/references/supported_profiles.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + This library fully supports all major ONVIF Profiles listed below. Each profile represents a standardized set of features and use cases, ensuring interoperability between ONVIF-compliant devices and clients. You can use this library to integrate with devices and systems that implement any of these profiles. | Name | Specs | Main Features | Typical Use Case | Support | diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 65a5b465..848c8c51 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,19 +1,25 @@ [data-md-color-scheme="default"] { --md-default-bg-color: #ebebeb; - --md-primary-fg-color: #0000ff; + --md-primary-fg-color: #003399; } [data-md-color-scheme="slate"] { - --md-primary-fg-color: #003399; + --md-primary-fg-color: #002266; --md-typeset-a-color: #60a5fa; } -[data-md-color-scheme="default"] .md-footer, +[data-md-color-scheme="default"] .md-footer { + background-color: #002266; +} + [data-md-color-scheme="default"] .md-footer-meta { background-color: #003399; } -[data-md-color-scheme="slate"] .md-footer, +[data-md-color-scheme="slate"] .md-footer { + background-color: #030b1c; +} + [data-md-color-scheme="slate"] .md-footer-meta { background-color: #020617; } @@ -34,7 +40,7 @@ display: inline-block; width: 0.8em; height: 0.8em; - margin-left: 0.2em; + margin-left: 0.1em; vertical-align: -0.05em; } @@ -108,13 +114,13 @@ /* Thumb */ ::-webkit-scrollbar-thumb { - background: #0000ff; + background: #003399; border-radius: 4px; } /* Thumb hover */ ::-webkit-scrollbar-thumb:hover { - background: #003399; + background: #002266; } :root { @@ -177,4 +183,25 @@ .md-tooltip2__inner [id^="fn:"] { display: none !important; +} + +/* Align breadcrumb separators */ +.md-path__item { + display: inline-flex; + align-items: center; +} + +.md-path__link { + display: inline-flex; + align-items: center; +} + +.md-typeset .grid.cards .middle { + vertical-align: middle; +} + +.icon-link { + display: inline-flex; + align-items: center; + gap: 0.35em; } \ No newline at end of file diff --git a/docs/utilities/helper_methods.md b/docs/utilities/helper_methods.md index 81c415e3..2002e4ff 100644 --- a/docs/utilities/helper_methods.md +++ b/docs/utilities/helper_methods.md @@ -1,3 +1,8 @@ +--- +hide: + - path +--- + Every ONVIF service provides **four** essential helper methods to improve the development experience and make working with ONVIF operations more intuitive: !!! info diff --git a/mkdocs.yml b/mkdocs.yml index c5c943fd..d51028c2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,37 +1,63 @@ site_name: ONVIF Python -site_description: A modern Python library for ONVIF-compliant IP cameras and devices, providing a clean, typed API for discovery, device management, media, PTZ, and events. +site_description: >- + A modern Python library for ONVIF-compliant IP cameras and devices, providing a clean, + typed API for discovery, device management, media, PTZ, and events. site_url: https://nirsimetri.github.io/onvif-python/ repo_url: https://github.com/nirsimetri/onvif-python repo_name: nirsimetri/onvif-python +edit_uri: edit/main/docs/ use_directory_urls: true theme: name: material + language: en custom_dir: docs/overrides logo: assets/nirsimetri-light.svg favicon: assets/nirsimetri-dark.svg icon: repo: fontawesome/brands/github + admonition: + example: material/code-tags + danger: material/skull + bug: material/flask-outline + note: material/book-open-variant + tip: material/source-pull + info: material/lightbulb + abstract: material/feature-search + warning: material/traffic-cone + question: material/telescope + success: material/check-circle + failure: material/cancel font: text: Manrope code: JetBrains Mono features: + - content.code.copy + - content.code.annotate + - content.tooltips + - content.footnote.tooltips + - navigation.path + - navigation.indexes - navigation.instant - navigation.instant.progress - navigation.instant.preview - navigation.sections - navigation.top - - content.code.copy + - navigation.tabs + - navigation.tabs.sticky + - navigation.footer + - navigation.prune + - search.highlight - search.suggest - - content.tooltips - - content.footnote.tooltips + - toc.follow + palette: - media: "(prefers-color-scheme: light)" scheme: default primary: custom accent: custom toggle: - icon: material/weather-night + icon: material/lightbulb-on-10 name: Switch to dark mode - media: "(prefers-color-scheme: dark)" @@ -39,94 +65,116 @@ theme: primary: custom accent: custom toggle: - icon: material/weather-sunny + icon: material/lightbulb-on-90 name: Switch to light mode nav: - - About: index.md - - Philosophy: philosophy.md - - Installation: installation.md - - Quick Start: quick_start.md - - Core: - - Client: core/onvif_client.md - - CLI: core/onvif_cli.md - - Discovery: core/onvif_discovery.md - - Utilities: - - Helper Methods: utilities/helper_methods.md - - References: - - ONVIF Profiles: references/supported_profiles.md + - Home: index.md + - Get Started: + - Philosophy: philosophy.md + - Installation: installation.md + - Quickstart: quick_start.md + - Main Features: + - Client: main/onvif_client.md + - CLI: main/onvif_cli.md + - Utilities: + - Helper Methods: utilities/helper_methods.md + - Reference: + - ONVIF Profiles: + - Supports: references/supported_profiles.md - ONVIF Services: - Coverage: references/implemented_services.md - - Service Discovery: references/service_discovery.md - - Service Bindings: references/service_bindings.md + - Discovery: references/service_discovery.md + - Bindings: references/service_bindings.md - API: + - api/index.md - Core: + - api/core/index.md - ONVIFClient: api/core/onvif_client.md - ONVIFOperator: api/core/onvif_operator.md - - ONVIFDiscovery: api/core/onvif_discovery.md - Exceptions: + - api/exceptions/index.md - ONVIFOperationException: api/exceptions/onvif_exception.md - Error Handlers: api/exceptions/onvif_error_handlers.md - Utilities: + - api/utilities/index.md + - ONVIFDiscovery: api/utilities/onvif_discovery.md - CacheMode: api/utilities/cache_mode.md - ONVIFWSDL: api/utilities/onvif_wsdl.md - ONVIFService: api/utilities/onvif_service.md - ZeepPatcher: api/utilities/zeep_patcher.md - Plugins: api/utilities/plugins.md - Services: + - api/services/index.md - Device: api/services/device.md - Events: - - Events: api/services/events.md - - PullPoint: api/services/pullpoint.md - - Notification: api/services/notification.md - - Subscription: api/services/subscription.md - - PausableSubscription: api/services/pausable_subscription.md + - api/services/events/index.md + - PullPoint: api/services/events/pullpoint.md + - Notification: api/services/events/notification.md + - Subscription: api/services/events/subscription.md + - PausableSubscription: api/services/events/pausable_subscription.md - Imaging: api/services/imaging.md - Media: api/services/media.md - Media2: api/services/media2.md - PTZ: api/services/ptz.md + - Provisioning: api/services/provisioning.md - DeviceIO: api/services/deviceio.md - Display: api/services/display.md + - Thermal: api/services/thermal.md - Analytics: - - Analytics: api/services/analytics.md - - RuleEngine: api/services/ruleengine.md + - api/services/analytics/index.md + - RuleEngine: api/services/analytics/ruleengine.md - AnalyticsDevice: api/services/analyticsdevice.md + - Receiver: api/services/receiver.md + - Recording: api/services/recording.md + - Search: api/services/search.md + - Replay: api/services/replay.md + - ActionEngine: api/services/actionengine.md + - Schedule: api/services/schedule.md - AccessControl: api/services/accesscontrol.md - DoorControl: api/services/doorcontrol.md - AccessRules: api/services/accessrules.md - - ActionEngine: api/services/actionengine.md - - AppManagement: api/services/appmgmt.md - AuthenticationBehavior: api/services/authenticationbehavior.md - Credential: api/services/credential.md - - Recording: api/services/recording.md - - Search: api/services/search.md - - Replay: api/services/replay.md - - Provisioning: api/services/provisioning.md - - Receiver: api/services/receiver.md - - Schedule: api/services/schedule.md - - Thermal: api/services/thermal.md - - Uplink: api/services/uplink.md - Security: - - AdvancedSecurity: api/services/advancedsecurity.md - - AuthorizationServer: api/services/authorizationserver.md - - Dot1x: api/services/dot1x.md - - JWT: api/services/jwt.md - - KeyStore: api/services/keystore.md - - MediaSigning: api/services/mediasigning.md - - TLSServer: api/services/tlsserver.md + - api/services/security/index.md + - AuthorizationServer: api/services/security/authorizationserver.md + - Dot1x: api/services/security/dot1x.md + - JWT: api/services/security/jwt.md + - KeyStore: api/services/security/keystore.md + - MediaSigning: api/services/security/mediasigning.md + - TLSServer: api/services/security/tlsserver.md + - AppManagement: api/services/appmgmt.md + - Uplink: api/services/uplink.md - Project: - Contributing: project/contributing.md - Roadmap: project/roadmap.md - Used By: project/used_by.md - External: project/external.md - Legal: - - Legal Notice: legal/legal_notice.md + - Notice: legal/notice.md - License: legal/license.md - Releases: releases.md # It will be hidden because it serves as a placeholder. plugins: - search + - minify: + minify_html: true + minify_js: true + minify_css: true + js_files: + - javascripts/github-releases.js + - javascripts/external-links.js + css_files: + - stylesheets/extra.css + - git-revision-date-localized: + exclude: + - releases.md + type: timeago + enable_creation_date: true - git-authors: + exclude: + - releases.md show_contribution: true show_email_address: false sort_authors_by: contribution @@ -157,6 +205,9 @@ markdown_extensions: - pymdownx.emoji: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg + options: + custom_icons: + - overrides/.icons - pymdownx.superfences - pymdownx.tasklist: custom_checkbox: true @@ -168,6 +219,30 @@ validation: extra: generator: false + social: + - icon: fontawesome/solid/globe + link: https://nirsimetri.com + name: Website + + - icon: fontawesome/brands/github + link: https://github.com/nirsimetri + name: GitHub + + - icon: fontawesome/brands/python + link: https://pypi.org/project/onvif-python/ + name: PyPI + + - icon: fontawesome/brands/x-twitter + link: https://x.com/nirsimetri + name: X + + - icon: fontawesome/brands/mastodon + link: https://fosstodon.org/@nirsimetri + name: Mastodon + + - icon: fontawesome/brands/linkedin + link: https://www.linkedin.com/company/nirsimetri-technologies + name: LinkedIn extra_css: - stylesheets/extra.css @@ -181,4 +256,5 @@ extra_javascript: hooks: - docs/hooks.py -copyright: Copyright © 2026  —  Nirsimetri Technologies® \ No newline at end of file +copyright: >- + Copyright © 2026  —  Nirsimetri Technologies® \ No newline at end of file diff --git a/onvif/operator.py b/onvif/operator.py index 06fd808c..0c11ac73 100644 --- a/onvif/operator.py +++ b/onvif/operator.py @@ -52,7 +52,7 @@ class CacheMode(Enum): :material-alert-circle:{ .danger } WSDL/XSD documents are fetched without caching - !!! danger "Use case" + !!! bug "Use case" Debugging, testing, and situations where fresh WSDL/XSD documents are required. """ @@ -69,7 +69,7 @@ class CacheMode(Enum): :material-alert-circle:{ .danger } Cache is lost when the process exits - !!! danger "Use case" + !!! bug "Use case" Long-running applications, temporary sessions, and applications where persistent cache storage is not required. """ @@ -86,7 +86,7 @@ class CacheMode(Enum): :material-alert-circle:{ .danger } Requires disk I/O and a writable cache directory - !!! danger "Use case" + !!! bug "Use case" Production applications, CLI tools, and environments where WSDL/XSD caching should persist across restarts. """ diff --git a/onvif/utils/plugins.py b/onvif/utils/plugins.py index 26e68583..56b10e79 100644 --- a/onvif/utils/plugins.py +++ b/onvif/utils/plugins.py @@ -171,14 +171,14 @@ class XMLCapturePlugin(Plugin): - Available since [`>=v0.0.6`](/onvif-python/releases/#v0.0.6) - Moved to `plugins` since [`>=v0.4.0`](/onvif-python/releases/#v0.4.0) - !!! abstract "The plugin automatically captures" + !!! question "The plugin automatically captures" - Outgoing SOAP requests (`egress`) - Incoming SOAP responses (`ingress`) - HTTP headers for both directions - Operation names for context - Complete history of all transactions - !!! danger "Use Cases" + !!! bug "Use Cases" 1. **Debugging**: See exact SOAP messages being sent/received 2. **Learning**: Understand ONVIF protocol structure 3. **Testing**: Verify request format and response structure diff --git a/onvif/utils/service.py b/onvif/utils/service.py index 0344f8f7..714bc2ad 100644 --- a/onvif/utils/service.py +++ b/onvif/utils/service.py @@ -392,7 +392,9 @@ def to_dict(self, zeep_object: Any) -> dict: zeep_object (Any): The zeep object returned from ONVIF operations Returns: - Python dictionary representation of the zeep object + Python `dict` representation of the Zeep object. + Returns an empty dict `{}` if `zeep_object` is `None` or + if conversion fails for any reason. Example: ```python linenums="1" diff --git a/onvif/utils/wsdl.py b/onvif/utils/wsdl.py index 1f712b59..54a6176c 100644 --- a/onvif/utils/wsdl.py +++ b/onvif/utils/wsdl.py @@ -29,14 +29,6 @@ class ONVIFWSDL: !!! tip "Version History" - Available since [`>=v0.1.0`](/onvif-python/releases/#v0.1.0) - !!! abstract "Features" - - Centralized WSDL definition mapping for all ONVIF services - - Support for multiple ONVIF versions (ver10, ver20) - - Custom WSDL directory support (global and per-call) - - Automatic path resolution for built-in and custom WSDLs - - Service discovery with namespace and binding information - - File existence validation - !!! warning "WSDL Structure" Built-in WSDLs are organized in the ONVIF standard directory structure: @@ -67,7 +59,7 @@ class ONVIFWSDL: └── ptz.wsdl ``` - !!! question "Service Definition Format" + !!! abstract "Service Definition Format" Each service has a definition containing: - `filename` : WSDL file name @@ -75,7 +67,7 @@ class ONVIFWSDL: - `binding`: SOAP binding name (e.g., "DeviceBinding") - `namespace`: XML namespace URI (e.g., "http://www.onvif.org/ver10/device/wsdl") - ??? tip "Custom WSDL Directory Priority" + ??? question "Custom WSDL Directory Priority" 1. Per-call `custom_wsdl_dir` parameter (highest priority) 2. Global `_custom_wsdl_dir` setting 3. Built-in `BASE_DIR` (default) diff --git a/pyproject.toml b/pyproject.toml index 82fe2baf..77c7b810 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,6 +78,8 @@ docs = [ "mkdocs-material>=9.7.7,<10.0.0", "mkdocstrings[python]>=1.0.0,<3.0.0", "mkdocs-git-authors-plugin>=0.10.0,<1.0.0", + "mkdocs-git-revision-date-localized-plugin>=1.6.0,<2.0.0", + "mkdocs-minify-plugin>=0.8.0,<1.0.0", ] [project.scripts] From c020aa94c77adc5b418580410f288a03fc8d2cec Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 10 Oct 2026 03:59:07 +0700 Subject: [PATCH 02/38] fix(docs): Fix missing link --- docs/installation.md | 2 +- docs/philosophy.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 0942c87d..57c63a5c 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -22,7 +22,7 @@ cd onvif-python pip install . ``` -Once the installation is successful, you can also immediately access the [ONVIF CLI](core/onvif_cli.md) via the terminal using: +Once the installation is successful, you can also immediately access the [ONVIF CLI](main/onvif_cli.md) via the terminal using: ```console onvif --help ``` \ No newline at end of file diff --git a/docs/philosophy.md b/docs/philosophy.md index d0a42b90..245f7799 100644 --- a/docs/philosophy.md +++ b/docs/philosophy.md @@ -6,7 +6,7 @@ hide: !!! info This library will be continuously updated as ONVIF versions are updated. It uses a built-in WSDL that will always follow changes to the [ONVIF WSDL Specifications](https://github.com/onvif/specs). - You can also use your own ONVIF WSDL file by adding the `wsdl_dir` argument; see [`ONVIFClient`](core/onvif_client.md). + You can also use your own ONVIF WSDL file by adding the `wsdl_dir` argument; see [`ONVIFClient`](main/onvif_client.md). ### WYSIWYG (What You See is What You Get) Every ONVIF operation in the library mirrors the official ONVIF specification exactly. Method names, parameter structures, and response formats follow ONVIF standards without abstraction layers or renamed interfaces. What you see in the ONVIF documentation is exactly what you get in Python. From 3afe845390898080a25b1c80243cb3472080bfe6 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sun, 11 Oct 2026 16:32:21 +0700 Subject: [PATCH 03/38] docs: Enhance documentation structure and styling --- docs/api/index.md | 12 +++---- docs/api/services/index.md | 22 ++++++------- docs/index.md | 6 ++++ docs/overrides/.icons/material/api.svg | 1 + .../.icons/material/linked-services.svg | 1 + docs/overrides/.icons/material/token.svg | 1 + docs/references/index.md | 32 +++++++++++++++++++ docs/stylesheets/extra.css | 28 +++++++++++++++- mkdocs.yml | 10 +++--- 9 files changed, 91 insertions(+), 22 deletions(-) create mode 100644 docs/overrides/.icons/material/api.svg create mode 100644 docs/overrides/.icons/material/linked-services.svg create mode 100644 docs/overrides/.icons/material/token.svg create mode 100644 docs/references/index.md diff --git a/docs/api/index.md b/docs/api/index.md index 1c16c58a..c825632e 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -13,7 +13,7 @@ hide: Configure ONVIF connections and interact with devices through the main client interfaces. -
+ --- [:octicons-arrow-right-24: Explore Core](core/index.md) - :material-alert-circle-outline:{ .lg .middle }  **Exceptions** @@ -22,25 +22,25 @@ hide: Understand operation exceptions and error-handling utilities for diagnosing and handling failures. -
+ --- [:octicons-arrow-right-24: Explore Exceptions](exceptions/index.md) -- :material-toolbox:{ .lg .middle }  **Utilities** +- :material-toolbox-outline:{ .lg .middle }  **Utilities** --- Discover ONVIF devices, configure caching, manage WSDL resources, and extend service behavior. -
+ --- [:octicons-arrow-right-24: Explore Utilities](utilities/index.md) -- :material-package-variant:{ .lg .middle }  **Services** +- :material-linked-services:{ .lg .middle }  **Services** --- Browse the available ONVIF service clients, from device management, events, PTZ, analytics, and more. -
+ --- [:octicons-arrow-right-24: Explore Services](services/index.md) \ No newline at end of file diff --git a/docs/api/services/index.md b/docs/api/services/index.md index b078102c..a2080837 100644 --- a/docs/api/services/index.md +++ b/docs/api/services/index.md @@ -15,7 +15,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Manage device configuration, device capabilities, interfaces, and related hardware functionality. -
+ --- [:octicons-arrow-right-24: Device](device.md) [:octicons-arrow-right-24: DeviceIO](deviceio.md) @@ -30,7 +30,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Subscribe to device events, retrieve notifications, and manage event subscriptions and pull-point mechanisms. -
+ --- [:octicons-arrow-right-24: Events](events/index.md) [:octicons-arrow-right-24: PullPoint](events/pullpoint.md) @@ -48,7 +48,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Access media profiles, streaming configuration, video sources, imaging settings, and related media operations. -
+ --- [:octicons-arrow-right-24: Media](media.md) [:octicons-arrow-right-24: Media2](media2.md) @@ -61,19 +61,19 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Control device movement (PTZ), focus, presets, and supported movement functions. -
+ --- [:octicons-arrow-right-24: PTZ](ptz.md) [:octicons-arrow-right-24: Provisioning](provisioning.md) -- :material-chart-box-outline:{ .lg .middle }  **Analytics** +- :material-analytics:{ .lg .middle }  **Analytics** --- Interact with analytics functionality, rule engines, and analytics-related device services. -
+ --- [:octicons-arrow-right-24: Analytics](analytics/index.md) [:octicons-arrow-right-24: RuleEngine](analytics/ruleengine.md) @@ -86,7 +86,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Access recording configuration, search for recorded content, replay media, and manage receiver functionality. -
+ --- [:octicons-arrow-right-24: Recording](recording.md) [:octicons-arrow-right-24: Search](search.md) @@ -101,7 +101,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Configure device actions and time-based schedules for automated operations. -
+ --- [:octicons-arrow-right-24: ActionEngine](actionengine.md) [:octicons-arrow-right-24: Schedule](schedule.md) @@ -112,7 +112,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Manage access control systems, door operations, and access rules through ONVIF services. -
+ --- [:octicons-arrow-right-24: AccessControl](accesscontrol.md) [:octicons-arrow-right-24: DoorControl](doorcontrol.md) @@ -129,7 +129,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Explore ONVIF security services for authentication, authorization, network authentication, cryptographic key management, and media integrity. -
+ --- [:octicons-arrow-right-24: AdvancedSecurity](security/index.md) [:octicons-arrow-right-24: AuthorizationServer](security/authorizationserver.md) @@ -150,7 +150,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide Manage device applications and establish connectivity between services behind firewalls and internet-accessible clients. -
+ --- [:octicons-arrow-right-24: AppManagement](appmgmt.md) [:octicons-arrow-right-24: Uplink](uplink.md) diff --git a/docs/index.md b/docs/index.md index 26aca859..50f05b64 100644 --- a/docs/index.md +++ b/docs/index.md @@ -62,12 +62,16 @@ This library simplifies that process by wrapping SOAP communication into a clean Python **3.10 or higher** is required. + --- + [:octicons-arrow-right-24: PyPI](https://pypi.org/project/onvif-python){ .no-external-icon } + - :material-package-variant-closed:{ .lg .middle }  **Zeep** --- SOAP client for ONVIF communication. + --- [:octicons-arrow-right-24: GitHub](https://github.com/mvantellingen/python-zeep){ .no-external-icon } - :material-package-variant-closed:{ .lg .middle }  **Requests** @@ -76,6 +80,7 @@ This library simplifies that process by wrapping SOAP communication into a clean HTTP library for network requests. + --- [:octicons-arrow-right-24: GitHub](https://github.com/psf/requests){ .no-external-icon } - :material-package-variant-closed:{ .lg .middle }  **Pyreadline3** @@ -84,6 +89,7 @@ This library simplifies that process by wrapping SOAP communication into a clean Only installed on Windows (`win32`). + --- [:octicons-arrow-right-24: GitHub](https://github.com/pyreadline3/pyreadline3){ .no-external-icon } diff --git a/docs/overrides/.icons/material/api.svg b/docs/overrides/.icons/material/api.svg new file mode 100644 index 00000000..7c2257a9 --- /dev/null +++ b/docs/overrides/.icons/material/api.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/.icons/material/linked-services.svg b/docs/overrides/.icons/material/linked-services.svg new file mode 100644 index 00000000..358c3b01 --- /dev/null +++ b/docs/overrides/.icons/material/linked-services.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/.icons/material/token.svg b/docs/overrides/.icons/material/token.svg new file mode 100644 index 00000000..51eaf49d --- /dev/null +++ b/docs/overrides/.icons/material/token.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/references/index.md b/docs/references/index.md new file mode 100644 index 00000000..1b851b93 --- /dev/null +++ b/docs/references/index.md @@ -0,0 +1,32 @@ +--- +hide: + - path +--- + +# References + +
+ +- :material-token:{ .lg .middle }  **ONVIF Profiles** + + --- + + Explore ONVIF profiles and their supported device capabilities. + + --- + [:octicons-arrow-right-24: Supported Profiles](supported_profiles.md) + +- :material-api:{ .lg .middle }  **ONVIF Services** + + --- + + Explore ONVIF services coverage, discovery, and bindings. + + --- + [:octicons-arrow-right-24: Implementation Coverage](implemented_services.md) + + [:octicons-arrow-right-24: Service Discovery](service_discovery.md) + + [:octicons-arrow-right-24: Service Bindings](service_bindings.md) + +
\ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 848c8c51..381114b7 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -204,4 +204,30 @@ display: inline-flex; align-items: center; gap: 0.35em; -} \ No newline at end of file +} + +/* TOC separators */ +.md-nav--secondary .md-nav__list { + border-left: 2px solid var(--md-default-fg-color--lightest); + margin-left: 0.5rem; + padding-left: 0.75rem; +} + +.md-nav--secondary > .md-nav__list { + border-left: none; + margin-left: 0; + padding-left: 0; +} + +.md-nav--secondary .md-nav__link { + position: relative; +} + +.md-nav--secondary .md-nav__link::before { + content: ""; + position: absolute; + left: -0.6rem; + top: 50%; + width: 0.4rem; + border-top: 2px solid var(--md-default-fg-color--lightest); +} diff --git a/mkdocs.yml b/mkdocs.yml index d51028c2..320e7ef2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -29,8 +29,8 @@ theme: success: material/check-circle failure: material/cancel font: - text: Manrope - code: JetBrains Mono + text: Geist + code: Geist Mono features: - content.code.copy - content.code.annotate @@ -79,7 +79,8 @@ nav: - CLI: main/onvif_cli.md - Utilities: - Helper Methods: utilities/helper_methods.md - - Reference: + - References: + - references/index.md - ONVIF Profiles: - Supports: references/supported_profiles.md - ONVIF Services: @@ -203,11 +204,12 @@ markdown_extensions: pygments_lang_class: true linenums_style: pymdownx-inline - pymdownx.emoji: + strict: true emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg options: custom_icons: - - overrides/.icons + - docs/overrides/.icons - pymdownx.superfences - pymdownx.tasklist: custom_checkbox: true From 42acf89f14ef8b37d43bc1734fa66a0081e429e0 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sun, 11 Oct 2026 16:36:08 +0700 Subject: [PATCH 04/38] fix(docs): Add missing analytics icons --- docs/overrides/.icons/material/analytics.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/overrides/.icons/material/analytics.svg diff --git a/docs/overrides/.icons/material/analytics.svg b/docs/overrides/.icons/material/analytics.svg new file mode 100644 index 00000000..01951c94 --- /dev/null +++ b/docs/overrides/.icons/material/analytics.svg @@ -0,0 +1 @@ + \ No newline at end of file From 3b2a1526cbc3f3319c0dc9c5012a7170421472bc Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sun, 11 Oct 2026 16:37:09 +0700 Subject: [PATCH 05/38] fix(docs): Fix spelling --- docs/api/core/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/core/index.md b/docs/api/core/index.md index ca2c73ff..ea5f2865 100644 --- a/docs/api/core/index.md +++ b/docs/api/core/index.md @@ -11,7 +11,7 @@ hide: --- - Connect to ONVIF devices, configure connections and authenticaton, and manage service access. + Connect to ONVIF devices, configure connections and authentication, and manage service access. - :material-connection:{ .lg .middle }  [**ONVIFOperator**](onvif_operator.md) From 4537b2b1c8052adf96ba5dd3b73c05f3a2ffaeb0 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sun, 11 Oct 2026 18:25:25 +0700 Subject: [PATCH 06/38] ci: Update fetch-depth for checkout step in docs preview workflow --- .github/workflows/documentation-preview.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/documentation-preview.yml b/.github/workflows/documentation-preview.yml index 5aba2d79..c6370736 100644 --- a/.github/workflows/documentation-preview.yml +++ b/.github/workflows/documentation-preview.yml @@ -29,6 +29,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 - name: Set up Python if: github.event.action != 'closed' From 9232e0c70528479ff1031cde0332d57933537fb1 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sun, 11 Oct 2026 21:02:05 +0700 Subject: [PATCH 07/38] fix(docs): Fix typo in documentation --- docs/api/services/index.md | 2 +- mkdocs.yml | 2 +- onvif/services/analyticsdevice.py | 2 +- onvif/services/devicemgmt.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api/services/index.md b/docs/api/services/index.md index a2080837..085cc207 100644 --- a/docs/api/services/index.md +++ b/docs/api/services/index.md @@ -138,7 +138,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide [:octicons-arrow-right-24: JWT](security/jwt.md) - [:octicons-arrow-right-24: KeyStore](security/keystore.md) + [:octicons-arrow-right-24: Keystore](security/keystore.md) [:octicons-arrow-right-24: MediaSigning](security/mediasigning.md) diff --git a/mkdocs.yml b/mkdocs.yml index 320e7ef2..17e2a6df 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -142,7 +142,7 @@ nav: - AuthorizationServer: api/services/security/authorizationserver.md - Dot1x: api/services/security/dot1x.md - JWT: api/services/security/jwt.md - - KeyStore: api/services/security/keystore.md + - Keystore: api/services/security/keystore.md - MediaSigning: api/services/security/mediasigning.md - TLSServer: api/services/security/tlsserver.md - AppManagement: api/services/appmgmt.md diff --git a/onvif/services/analyticsdevice.py b/onvif/services/analyticsdevice.py index afb7db03..dbc2b84e 100644 --- a/onvif/services/analyticsdevice.py +++ b/onvif/services/analyticsdevice.py @@ -22,7 +22,7 @@ class AnalyticsDevice(ONVIFService): | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011), split from Core 2.0 | + | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | | **Deprecated** | ONVIF Release 18.12 (December 2018) | | **Binding name** | `AnalyticsDeviceBinding` (`ver10/analyticsdevice.wsdl`) | | **Successor** | `Analytics` Service (`ver20/analytics/wsdl/analytics.wsdl`) | diff --git a/onvif/services/devicemgmt.py b/onvif/services/devicemgmt.py index f344f27c..4836656e 100644 --- a/onvif/services/devicemgmt.py +++ b/onvif/services/devicemgmt.py @@ -65,7 +65,7 @@ def SendAuxiliaryCommand(self, AuxiliaryCommand): - tt:Washer|On - Request to start the washer. - tt:Washer|Off - Request to stop the washer. - tt:WashingProcedure|On - Request to start the washing procedure. - - tt: WashingProcedure |Off - Request to stop the washing procedure. + - tt:WashingProcedure|Off - Request to stop the washing procedure. - tt:IRLamp|On - Request to turn ON an IR illuminator attached to the unit. - tt:IRLamp|Off - Request to turn OFF an IR illuminator attached to the unit. - tt:IRLamp|Auto - Request to configure an IR illuminator attached to the unit From 0454c5959ef63b7d44f3f2604d93f5af54a5506d Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sun, 11 Oct 2026 21:02:51 +0700 Subject: [PATCH 08/38] docs: Update TOC separators for better responsiveness and styling --- docs/stylesheets/extra.css | 68 ++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 381114b7..fd8611c8 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -206,28 +206,48 @@ gap: 0.35em; } -/* TOC separators */ -.md-nav--secondary .md-nav__list { - border-left: 2px solid var(--md-default-fg-color--lightest); - margin-left: 0.5rem; - padding-left: 0.75rem; -} - -.md-nav--secondary > .md-nav__list { - border-left: none; - margin-left: 0; - padding-left: 0; -} - -.md-nav--secondary .md-nav__link { - position: relative; -} - -.md-nav--secondary .md-nav__link::before { +/* TOC separators — desktop only */ +@media screen and (min-width: 76.25em) { + .md-nav--secondary .md-nav__list { + border-left: 2px solid var(--md-default-fg-color--lightest); + margin-left: 0.5rem; + padding-left: 0.75rem; + } + + .md-nav--secondary > .md-nav__list { + border-left: none; + margin-left: 0; + padding-left: 0; + } + + .md-nav--secondary .md-nav__link { + position: relative; + } + + .md-nav--secondary .md-nav__link::before { + content: ""; + position: absolute; + left: -0.6rem; + top: 50%; + width: 0.4rem; + border-top: 2px solid var(--md-default-fg-color--lightest); + } + + /* Remove separators from top-level TOC links */ + .md-nav--secondary > .md-nav__list > .md-nav__item > .md-nav__link::before { + display: none; + } +} + +/* TOC title icon */ +.md-nav--secondary .md-nav__title::before { content: ""; - position: absolute; - left: -0.6rem; - top: 50%; - width: 0.4rem; - border-top: 2px solid var(--md-default-fg-color--lightest); -} + display: inline-block; + width: 1em; + height: 1em; + margin-right: 0.1rem; + vertical-align: -0.15em; + background-color: currentColor; + mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath fill='black' d='M360-200v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360ZM200-160q-33 0-56.5-23.5T120-240q0-33 23.5-56.5T200-320q33 0 56.5 23.5T280-240q0 33-23.5 56.5T200-160Zm0-240q-33 0-56.5-23.5T120-480q0-33 23.5-56.5T200-560q33 0 56.5 23.5T280-480q0 33-23.5 56.5T200-400Zm-56.5-263.5Q120-687 120-720t23.5-56.5Q167-800 200-800t56.5 23.5Q280-753 280-720t-23.5 56.5Q233-640 200-640t-56.5-23.5Z'/%3E%3C/svg%3E") center / contain no-repeat; + -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath fill='black' d='M360-200v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360ZM200-160q-33 0-56.5-23.5T120-240q0-33 23.5-56.5T200-320q33 0 56.5 23.5T280-240q0 33-23.5 56.5T200-160Zm0-240q-33 0-56.5-23.5T120-480q0-33 23.5-56.5T200-560q33 0 56.5 23.5T280-480q0 33-23.5 56.5T200-400Zm-56.5-263.5Q120-687 120-720t23.5-56.5Q167-800 200-800t56.5 23.5Q280-753 280-720t-23.5 56.5Q233-640 200-640t-56.5-23.5Z'/%3E%3C/svg%3E") center / contain no-repeat; +} \ No newline at end of file From a64f65182b0300b3c79a97e0e06c7c90107393f0 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Mon, 12 Oct 2026 23:59:31 +0700 Subject: [PATCH 09/38] Revert "ci: Update fetch-depth for checkout step in docs preview workflow" This reverts commit 4537b2b1c8052adf96ba5dd3b73c05f3a2ffaeb0. --- .github/workflows/documentation-preview.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/documentation-preview.yml b/.github/workflows/documentation-preview.yml index c6370736..5aba2d79 100644 --- a/.github/workflows/documentation-preview.yml +++ b/.github/workflows/documentation-preview.yml @@ -29,8 +29,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - name: Set up Python if: github.event.action != 'closed' From 406b1610b17cc6a349f693ad874828bf65d4c41e Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Tue, 13 Oct 2026 00:01:34 +0700 Subject: [PATCH 10/38] style(docs): Refactor CSS for rounded elements and adjust table code styling --- docs/stylesheets/extra.css | 49 ++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index fd8611c8..3f80314b 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -28,10 +28,6 @@ background-color: var(--md-primary-fg-color); } -.md-typeset table td code { - white-space: nowrap; -} - .md-nav__link[href$="/releases/"] { display: none; } @@ -92,6 +88,10 @@ color: inherit; } +.md-typeset table td code { + white-space: nowrap; +} + .md-content__inner .md-typeset__table, .md-content__inner .md-typeset__table table { display: table !important; width: 100%; @@ -250,4 +250,45 @@ background-color: currentColor; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath fill='black' d='M360-200v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360ZM200-160q-33 0-56.5-23.5T120-240q0-33 23.5-56.5T200-320q33 0 56.5 23.5T280-240q0 33-23.5 56.5T200-160Zm0-240q-33 0-56.5-23.5T120-480q0-33 23.5-56.5T200-560q33 0 56.5 23.5T280-480q0 33-23.5 56.5T200-400Zm-56.5-263.5Q120-687 120-720t23.5-56.5Q167-800 200-800t56.5 23.5Q280-753 280-720t-23.5 56.5Q233-640 200-640t-56.5-23.5Z'/%3E%3C/svg%3E") center / contain no-repeat; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath fill='black' d='M360-200v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360ZM200-160q-33 0-56.5-23.5T120-240q0-33 23.5-56.5T200-320q33 0 56.5 23.5T280-240q0 33-23.5 56.5T200-160Zm0-240q-33 0-56.5-23.5T120-480q0-33 23.5-56.5T200-560q33 0 56.5 23.5T280-480q0 33-23.5 56.5T200-400Zm-56.5-263.5Q120-687 120-720t23.5-56.5Q167-800 200-800t56.5 23.5Q280-753 280-720t-23.5 56.5Q233-640 200-640t-56.5-23.5Z'/%3E%3C/svg%3E") center / contain no-repeat; +} + +/* Rounded grid cards */ +.md-typeset .grid.cards > ul > li, +.md-typeset .grid.cards > ol > li, +.md-typeset .grid > .card { + border-radius: 0.5rem; + overflow: hidden; +} + +/* Rounded tables */ +.md-typeset__table table{ + border-top-right-radius: 0.5rem !important; + border-bottom-left-radius: 0.5rem !important; + border-bottom-right-radius: 0.5rem !important; + border-top-left-radius: 0.5rem !important; +} + +/* Rounded admonition */ +.admonition { + border-top-right-radius: 0.5rem !important; + border-bottom-left-radius: 0.5rem !important; + border-bottom-right-radius: 0.5rem !important; + border-top-left-radius: 0.5rem !important; +} + +.admonition-title { + border-top-right-radius: 0.5rem !important; + border-top-left-radius: 0.5rem !important; +} + +/* Rounded collapsible admonition */ +.md-typeset details, +.md-typeset details:not([open]) > summary { + border-radius: 0.5rem !important; +} + +/* Rounded top corners when open */ +.md-typeset details[open] > summary { + border-top-right-radius: 0.5rem !important; + border-top-left-radius: 0.5rem !important; } \ No newline at end of file From 7f37b4d1cbd9a3f6fee1a5511c7576c4a99f47b1 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Tue, 13 Oct 2026 00:01:52 +0700 Subject: [PATCH 11/38] fix(docs): Correct capitalization in Keystore title and reorder images in CLI documentation --- docs/api/services/security/keystore.md | 2 +- docs/main/onvif_cli.md | 16 ++++++++-------- docs/main/onvif_client.md | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/api/services/security/keystore.md b/docs/api/services/security/keystore.md index a39bc26d..66170745 100644 --- a/docs/api/services/security/keystore.md +++ b/docs/api/services/security/keystore.md @@ -1,4 +1,4 @@ -# KeyStore +# Keystore ::: onvif.services.security.keystore options: diff --git a/docs/main/onvif_cli.md b/docs/main/onvif_cli.md index 7f4c9bcb..8a277fb9 100644 --- a/docs/main/onvif_cli.md +++ b/docs/main/onvif_cli.md @@ -28,14 +28,6 @@ This library includes a powerful command-line interface (CLI) for interacting wi ## Screenshoot - - - - + + + +
- - - -
Onboarding @@ -44,6 +36,14 @@ This library includes a powerful command-line interface (CLI) for interacting wi List available operations
+ + + +
## Help Command diff --git a/docs/main/onvif_client.md b/docs/main/onvif_client.md index 14422606..9e01467f 100644 --- a/docs/main/onvif_client.md +++ b/docs/main/onvif_client.md @@ -223,9 +223,9 @@ client = ONVIFClient( password="secure_password", http_digest=True, # Use HTTP Digest authentiation timeout=15, - cache=CacheMode.DB, # Maximum performance (default) + cache=CacheMode.DB, # Maximum performance (default) use_https=True, # Secure communication - verify_ssl=True, # Verify certificates (default) + verify_ssl=True, # Verify certificates apply_patch=True, # Enhanced parsing (default) capture_xml=False, # Disable debug mode (default) wsdl_dir=None # Use built-in WSDL files (default) From 840b7a4a16b8bcd90e1ccda44a6c55f782ba5162 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Tue, 13 Oct 2026 00:01:58 +0700 Subject: [PATCH 12/38] fix(docs): Update docstring formatting for clarity in ONVIFService class --- onvif/utils/service.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/onvif/utils/service.py b/onvif/utils/service.py index 714bc2ad..c58f4d4d 100644 --- a/onvif/utils/service.py +++ b/onvif/utils/service.py @@ -392,9 +392,8 @@ def to_dict(self, zeep_object: Any) -> dict: zeep_object (Any): The zeep object returned from ONVIF operations Returns: - Python `dict` representation of the Zeep object. - Returns an empty dict `{}` if `zeep_object` is `None` or - if conversion fails for any reason. + Python `dict` representation of the Zeep object.
Returns an empty dict + `{}` if `zeep_object` is `None` or if conversion fails for any reason. Example: ```python linenums="1" From 4b5eda8aa8f7b57395256290604adc335c124643 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Tue, 13 Oct 2026 01:14:01 +0700 Subject: [PATCH 13/38] feat(docs): Add custom 404 error page --- docs/overrides/404.html | 25 ++++++++++++++ docs/stylesheets/extra.css | 70 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 docs/overrides/404.html diff --git a/docs/overrides/404.html b/docs/overrides/404.html new file mode 100644 index 00000000..5236fdd0 --- /dev/null +++ b/docs/overrides/404.html @@ -0,0 +1,25 @@ +{% extends "main.html" %} + +{% block content %} +
+
+

404

+ +

Page not found

+ +

+ The page you're looking for doesn't exist or may have been moved. +

+ + +
+
+{% endblock %} \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 3f80314b..8efa1eb6 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -291,4 +291,74 @@ .md-typeset details[open] > summary { border-top-right-radius: 0.5rem !important; border-top-left-radius: 0.5rem !important; +} + +/* 404 page */ +@media screen and (min-width: 76.25em) { + body:has(.error-page) .md-sidebar { + display: none !important; + } + + body:has(.error-page) .md-content { + max-width: 100% !important; + margin-inline: 0 !important; + } + + body:has(.error-page) .md-content__inner { + margin-inline: 0 !important; + } +} + +.error-page { + display: flex; + min-height: 55vh; + align-items: center; + justify-content: flex-start; + text-align: left; +} + +.error-page__content { + width: 100%; + max-width: 30rem; +} + +.error-page__code { + margin: 0; + color: var(--md-typeset-a-color); + font-size: clamp(4rem, 16vw, 8rem); + font-weight: 800; + letter-spacing: -0.08em; + line-height: 1; +} + +.error-page h1 { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + color: var(--md-default-fg-color); +} + +.error-page__description { + max-width: 30rem; + margin: 0 0 2rem; + color: var(--md-default-fg-color--light); + line-height: 1.7; +} + +.error-page__actions { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + gap: 0.5rem; +} + +.error-page__actions .md-button { + margin: 0; + border-radius: 0.5rem; + color: var(--md-typeset-a-color); +} + +.error-page__actions .md-button--primary { + background-color: var(--md-typeset-a-color); + border-color: var(--md-typeset-a-color); + color: var(--md-default-bg-color) !important; } \ No newline at end of file From 9396f465facf7801ac995b96488421ebc3761c46 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Tue, 13 Oct 2026 21:57:49 +0700 Subject: [PATCH 14/38] style(docs): Enhance CSS for hover effects --- docs/stylesheets/extra.css | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 8efa1eb6..e0972e83 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -170,13 +170,20 @@ display: block; padding: .1rem .4rem; color: #ebebeb; - font-weight: bold; - font-size: .8rem; - border: .05rem solid #ebebeb7a; - border-radius: .2rem; + font-weight: 600; + font-size: .75rem; + border: .05rem solid #ebebeb50; + border-radius: .3rem; content: "/"; } +[data-md-toggle=search]:not(:checked) ~ .md-header .md-search__form { + border-top-right-radius: 0.5rem !important; + border-bottom-left-radius: 0.5rem !important; + border-bottom-right-radius: 0.5rem !important; + border-top-left-radius: 0.5rem !important; +} + .md-tooltip2 { z-index: 4 !important; } @@ -361,4 +368,25 @@ background-color: var(--md-typeset-a-color); border-color: var(--md-typeset-a-color); color: var(--md-default-bg-color) !important; +} + +/* Grid cards — border color on hover */ +.md-typeset .grid.cards > ul > li, +.md-typeset .grid.cards > ul > li > hr { + transition: border-color 200ms ease; +} + +.md-typeset .grid.cards > ul > li:hover { + border-color: var(--md-accent-fg-color); +} + +/* Code content — border color on hover */ +.md-typeset .highlight .md-code__content { + border: 1px solid transparent; + border-radius: 0.5rem; +} + +.md-typeset .highlight .md-code__content:hover { + border-color: var(--md-accent-fg-color); + transition: border-color 200ms ease; } \ No newline at end of file From 5647a12fdece9c17505f0be8ff3f855f6cc683a1 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Tue, 13 Oct 2026 21:57:58 +0700 Subject: [PATCH 15/38] fix(docs): Update service discovery documentation for clarity and accuracy --- docs/project/contributing.md | 32 +++++++++++++++------------- docs/quick_start.md | 2 +- docs/references/service_discovery.md | 15 ++++++++----- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/docs/project/contributing.md b/docs/project/contributing.md index 6d0b09ed..efc333fd 100644 --- a/docs/project/contributing.md +++ b/docs/project/contributing.md @@ -71,7 +71,7 @@ If you can help translate documentation or error messages, let us know! Coverage is optional for local development. To generate an XML coverage report: ```shell - pytest --cov=. --cov-report=xml + pytest --cov=onvif --cov-report=xml --cov-report=term-missing ``` This generates `coverage.xml`, which can be used by coverage analysis tools such as Codacy. @@ -117,17 +117,17 @@ Make sure to write a comprehensive description for the PR you create to make it Use the following commit title types: -- **`feat`** → ✨ New feature -- **`fix`** → 🐛 Bug fix -- **`chore`** → 🔧 Non-code tasks such as updating dependencies, configs, or build tools -- **`docs`** → 📚 Documentation-only changes -- **`style`** → 🎨 Code style changes (formatting, spacing, etc. — without affecting logic) -- **`refactor`** → 🔨 Code refactoring without adding features or fixing bugs -- **`test`** → ✅ Adding or modifying tests (unit tests, integration tests, etc.) -- **`perf`** → 🚀 Performance improvements -- **`ci`** → ⚙️ Changes to CI/CD configuration or pipelines -- **`build`** → 📦 Changes to the build system or external dependencies (e.g., Dockerfile) -- **`revert`** → ⏪ Reverting a previous commit +- **`feat`** → New feature +- **`fix`** → Bug fix +- **`chore`** → Non-code tasks such as updating dependencies, configs, or build tools +- **`docs`** → Documentation-only changes +- **`style`** → Code style changes (formatting, spacing, etc. — without affecting logic) +- **`refactor`** → Code refactoring without adding features or fixing bugs +- **`test`** → Adding or modifying tests (unit tests, integration tests, etc.) +- **`perf`** → Performance improvements +- **`ci`** → Changes to CI/CD configuration or pipelines +- **`build`** → Changes to the build system or external dependencies (e.g., Dockerfile) +- **`revert`** → Reverting a previous commit - **`code`** → General code changes that support but are not core features (e.g., examples) **Examples:** @@ -175,9 +175,11 @@ pip install -e ".[docs]" This installs the documentation tooling defined in `pyproject.toml`, including: -* `mkdocs-material` — MkDocs theme and Material extensions -* `mkdocstrings[python]` — API documentation generated from Python source code -* `mkdocs-git-authors-plugin` — contributor information for documentation pages +* `mkdocs-material` → MkDocs theme and Material extensions +* `mkdocstrings[python]` → API documentation generated from Python source code +* `mkdocs-git-authors-plugin` → contributor information for documentation pages +* `mkdocs-git-revision-date-localized-plugin` → revision date information for documentation pages +* `mkdocs-minify-plugin` → to minify any generated html/css/js files ### Run Locally diff --git a/docs/quick_start.md b/docs/quick_start.md index afb68389..bd5e0f04 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -91,7 +91,7 @@ Retrieve basic information about the device, such as manufacturer, model, firmwa info = device.GetDeviceInformation() print(info) # Example output: -# {'Manufacturer': '..', 'Model': '..', 'FirmwareVersion': '..', 'SerialNumber': '..'} +# {'Manufacturer': '..', 'Model': '..', 'FirmwareVersion': '..', ...} ``` ### Get RTSP URL diff --git a/docs/references/service_discovery.md b/docs/references/service_discovery.md index 8526cacf..c70149a9 100644 --- a/docs/references/service_discovery.md +++ b/docs/references/service_discovery.md @@ -30,10 +30,10 @@ By checking available services, your application can adapt its workflow and UI t The [`ONVIFClient`](../api/core/onvif_client.md) uses a **3-tier discovery approach** to maximize device compatibility: ### `GetServices` (Preferred) -Tries `GetServices` first for detailed service information. +Tries [`GetServices`](../api/services/device.md#onvif.services.devicemgmt.Device.GetServices) first for detailed service information. ### `GetCapabilities` (Fallback) -Falls back to `GetCapabilities` if `GetServices` is not supported by the device. +Falls back to [`GetCapabilities`](../api/services/device.md#onvif.services.devicemgmt.Device.GetCapabilities) if [`GetServices`](../api/services/device.md#onvif.services.devicemgmt.Device.GetServices) is not supported by the device. ### Default URLs (Final Fallback) Uses standard ONVIF URLs as last resort. @@ -44,7 +44,12 @@ You can check which service discovery method your ONVIF connection is using with ```python linenums="1" from onvif import ONVIFClient -client = ONVIFClient("192.168.1.17", 8000, "admin", "admin123") +client = ONVIFClient( + host="192.168.1.17", + port=8000, + username="admin", + password="password" +) # Check what discovery method was used if client.services: @@ -60,9 +65,9 @@ else: ## Why this approach? -`GetServices` provides the most accurate and detailed service information, but it's **optional** in the ONVIF specification. +[`GetServices`](../api/services/device.md#onvif.services.devicemgmt.Device.GetServices) provides the most accurate and detailed service information, but it's **optional** in the ONVIF specification. -`GetCapabilities` is **mandatory** for all ONVIF-compliant devices, ensuring broader compatibility. +[`GetCapabilities`](../api/services/device.md#onvif.services.devicemgmt.Device.GetCapabilities) is **mandatory** for all ONVIF-compliant devices, ensuring broader compatibility. **Default URLs** guarantee basic connectivity even with non-compliant devices. From 1709db5ac75becb1a3a88768c0e7aa4a5f732969 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Tue, 13 Oct 2026 21:58:29 +0700 Subject: [PATCH 16/38] refactor(docs): Revamp section with a table format and add dependencies section --- README.md | 69 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 073190e3..62b9567f 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,71 @@ Behind the scenes, ONVIF communication relies on **[SOAP](https://en.wikipedia.o This library simplifies that process by wrapping SOAP communication into a clean, Pythonic API. You no longer need to handle low-level XML parsing, namespaces, or security tokens manually; the library takes care of it, letting you focus on building functionality. ## Who Is It For? -- **Individual developers** exploring ONVIF or building hobby projects -- **Companies** building video intelligence, analytics, or VMS platforms -- **Security integrators** who need reliable ONVIF interoperability across devices + + + + + + + + + + + + + + + + + + +
+  Individual Developers + +  Companies +
+

Explore ONVIF capabilities, experiment with network cameras, and build hobby projects.

+
+

Build video intelligence, analytics, and video management system (VMS) platforms.

+
+  Security Integrators + +  IoT Experts +
+

Ensure reliable ONVIF interoperability across cameras and other security devices.

+
+

Test security, assess interoperability, and investigate ONVIF-enabled devices and related systems.

+
## Requirements -- **Python**: 3.10 or higher -- **Dependencies**: - - [`zeep>=4.3.0`](https://github.com/mvantellingen/python-zeep) - SOAP client for ONVIF communication - - [`requests>=2.32.0`](https://github.com/psf/requests) - HTTP library for network requests +Python **3.10 or higher** is required. + +## Dependencies + +- [zeep](https://github.com/mvantellingen/python-zeep) → SOAP client for ONVIF communication. +- [requests](https://github.com/psf/requests) → HTTP library for network requests. +- [pyreadline3](https://github.com/pyreadline3/pyreadline3) → Only installed on Windows (`win32`) for tab completion. ## Installation From 7a6d4bb5c9bb6ffd6e7b4ac6a99ebef0e17d1fc8 Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 05:24:04 +0700 Subject: [PATCH 17/38] feat(docs): Enhance external link handling and add content actions button --- docs/javascripts/external-links.js | 54 +++++++++++++------ docs/javascripts/extra.js | 34 ++++++++++++ .../.icons/material/corporate-fare.svg | 1 - docs/stylesheets/extra.css | 51 ++++++++++++++++++ mkdocs.yml | 10 +++- 5 files changed, 130 insertions(+), 20 deletions(-) create mode 100644 docs/javascripts/extra.js delete mode 100644 docs/overrides/.icons/material/corporate-fare.svg diff --git a/docs/javascripts/external-links.js b/docs/javascripts/external-links.js index 4d58338e..aec0fe63 100644 --- a/docs/javascripts/external-links.js +++ b/docs/javascripts/external-links.js @@ -2,37 +2,57 @@ document$.subscribe(() => { document.querySelectorAll('.md-content a[href]').forEach((link) => { - if ( - link.closest('.md-content__button') || - link.closest('.md-content__button--edit') || - link.closest('.md-content__button--view') - ) { + const url = new URL(link.href, window.location.href); + + const isEditButton = + link.classList.contains('md-content__button') && + url.hostname === 'github.com' && + /\/edit\//.test(url.pathname); + + const isViewButton = + link.classList.contains('md-content__button') && + url.hostname === 'github.com' && + /\/raw\//.test(url.pathname); + + if (isEditButton || isViewButton) { + link.target = '_blank'; + link.rel = 'noopener noreferrer'; + + link.dataset.tooltip = isEditButton + ? 'Edit this page' + : 'View source of this page'; + + // Remove external icons from Edit and View buttons. + link.querySelectorAll('.external-link-icon').forEach((icon) => { + icon.remove(); + }); + return; } - - const url = new URL(link.href, window.location.href); if ( - (url.protocol === "http:" || url.protocol === "https:") && + ['http:', 'https:'].includes(url.protocol) && url.hostname !== window.location.hostname ) { - link.target = "_blank"; - link.rel = "noopener noreferrer"; + link.target = '_blank'; + link.rel = 'noopener noreferrer'; if ( - !link.classList.contains("no-external-icon") && - !link.querySelector(".external-link-icon") + !link.classList.contains('no-external-icon') && + !link.querySelector('.external-link-icon') ) { - const icon = document.createElement("span"); - icon.className = "external-link-icon"; - icon.setAttribute("aria-hidden", "true"); + const icon = document.createElement('span'); + icon.className = 'external-link-icon'; + icon.setAttribute('aria-hidden', 'true'); icon.innerHTML = ` - + + + `; link.appendChild(icon); } } }); -}); \ No newline at end of file +}); diff --git a/docs/javascripts/extra.js b/docs/javascripts/extra.js new file mode 100644 index 00000000..9387920a --- /dev/null +++ b/docs/javascripts/extra.js @@ -0,0 +1,34 @@ +/* global document$ */ + +document$.subscribe(() => { + document.querySelectorAll('.md-content__button[href*="/raw/"]').forEach((editButton) => { + if (editButton.parentElement.querySelector(".report-issue-button")) return; + + const issueTitle = + document.querySelector(".md-content h1")?.textContent.trim() || + document.title; + const issueBody = encodeURIComponent( + `**Reference:** \n${window.location.href}\n\n**Description:**\n` + ); + + const reportButton = document.createElement("a"); + reportButton.className = "md-content__button md-icon report-issue-button"; + reportButton.href = + `https://github.com/${GITHUB_REPOSITORY}/issues/new` + + `?title=${issueTitle}&body=${issueBody}`; + reportButton.target = "_blank"; + reportButton.rel = "noopener noreferrer"; + reportButton.dataset.tooltip = "Report an issue"; + reportButton.setAttribute("aria-label", "Report an issue"); + reportButton.innerHTML = ` + + `; + + editButton.after(reportButton); + }); +}); \ No newline at end of file diff --git a/docs/overrides/.icons/material/corporate-fare.svg b/docs/overrides/.icons/material/corporate-fare.svg deleted file mode 100644 index 0b16a417..00000000 --- a/docs/overrides/.icons/material/corporate-fare.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index e0972e83..756581f6 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -389,4 +389,55 @@ .md-typeset .highlight .md-code__content:hover { border-color: var(--md-accent-fg-color); transition: border-color 200ms ease; +} + +/* Navigation */ +.md-header .md-header__inner{ + padding-top: 0.2rem; + padding-bottom: 0.2rem; +} + +/* Edit and View tooltips */ +.md-content__button[data-tooltip] { + position: relative; +} + +.md-content__button[data-tooltip]::after { + content: attr(data-tooltip); + position: absolute; + top: calc(100% + 0.3rem); + left: 50%; + z-index: 100; + width: max-content; + max-width: 16rem; + padding: 0.3rem 0.5rem; + border-radius: 0.2rem; + background: var(--md-default-bg-color); + color: var(--md-default-fg-color); + box-shadow: var(--md-shadow-z2); + font-size: 0.5rem; + font-weight: 600; + line-height: 1.4; + white-space: normal; + pointer-events: none; + opacity: 0; + visibility: hidden; + transform: translate(-50%, -5px); + transition: + opacity 250ms ease, + transform 250ms ease, + visibility 250ms ease; +} + +.md-content__button[data-tooltip]:hover::after, +.md-content__button[data-tooltip]:focus-visible::after { + opacity: 1; + visibility: visible; + transform: translate(-50%, 0); +} + +.md-content__button svg { + width: 1.2rem; + height: 1.2rem; + vertical-align: middle; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 17e2a6df..dfc84f82 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,7 +5,7 @@ site_description: >- site_url: https://nirsimetri.github.io/onvif-python/ repo_url: https://github.com/nirsimetri/onvif-python repo_name: nirsimetri/onvif-python -edit_uri: edit/main/docs/ +edit_uri: edit/dev/docs/ use_directory_urls: true theme: @@ -28,10 +28,14 @@ theme: question: material/telescope success: material/check-circle failure: material/cancel + edit: material/text-box-edit-outline + view: material/text-box-search-outline font: text: Geist code: Geist Mono features: + - content.action.edit + - content.action.view - content.code.copy - content.code.annotate - content.tooltips @@ -70,7 +74,7 @@ theme: nav: - Home: index.md - - Get Started: + - Getting Started: - Philosophy: philosophy.md - Installation: installation.md - Quickstart: quick_start.md @@ -166,6 +170,7 @@ plugins: js_files: - javascripts/github-releases.js - javascripts/external-links.js + - javascripts/extra.js css_files: - stylesheets/extra.css - git-revision-date-localized: @@ -254,6 +259,7 @@ extra_javascript: - https://cdn.jsdelivr.net/npm/dompurify@3.4.15/dist/purify.min.js - javascripts/github-releases.js - javascripts/external-links.js + - javascripts/extra.js hooks: - docs/hooks.py From 755a279550bbface3c986bfffceeaae0dbb440b4 Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 05:24:14 +0700 Subject: [PATCH 18/38] fix(docs): Update Open Graph and Twitter image URLs to correct asset --- docs/overrides/main.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/overrides/main.html b/docs/overrides/main.html index ef38dab2..b356c319 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -15,7 +15,7 @@ /> @@ -32,7 +32,7 @@ /> From dc54cd465a1f4f661c7e461b700a4a8e217262b2 Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 05:24:30 +0700 Subject: [PATCH 19/38] feat(docs): Add llms.txt file --- docs/llms.txt | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 docs/llms.txt diff --git a/docs/llms.txt b/docs/llms.txt new file mode 100644 index 00000000..e31bf166 --- /dev/null +++ b/docs/llms.txt @@ -0,0 +1,220 @@ +# ONVIF Python + +> A modern, developer-friendly Python library for discovering, connecting to, and managing ONVIF-compliant IP cameras, NVRs, and other ONVIF-compliant devices. It provides a Pythonic interface to ONVIF SOAP services, built-in WSDL definitions, WS-Discovery, device management, media streaming, PTZ, events, analytics, and a feature-rich command-line interface. + +ONVIF Python is an independent open-source implementation of the ONVIF specifications, maintained by Nirsimetri Technologies. It is designed for individual developers, companies building video management systems (VMS) and video intelligence platforms, security integrators, and IoT developers. + +The library uses Zeep for SOAP communication and Requests for HTTP transport. It aims to preserve official ONVIF operation names, parameter structures, and response formats while providing type hints, IDE completion, connection configuration, caching, error handling, and debugging facilities. + +- Official documentation: https://nirsimetri.github.io/onvif-python +- GitHub repository: https://github.com/nirsimetri/onvif-python +- PyPI package: https://pypi.org/project/onvif-python +- Python requirement: 3.10 or higher +- License: MIT; see the repository's license and notice for applicable terms. + +## Getting Started + +- [Installation](https://nirsimetri.github.io/onvif-python/installation/): Install the package using pip, pipx, or a local repository checkout. +- [Quickstart](https://nirsimetri.github.io/onvif-python/quick_start/): Discover ONVIF devices, initialize `ONVIFClient`, create service instances, retrieve device information, and obtain RTSP stream URIs. +- [Philosophy](https://nirsimetri.github.io/onvif-python/philosophy/): Understand the library's design principles, WYSIWYG API approach, interoperability goals, specification accuracy, Python typing, and dependency philosophy. + +## Main Features + +- [ONVIF Client Guide](https://nirsimetri.github.io/onvif-python/main/onvif_client/): Configure connections, authentication, HTTPS, timeouts, WSDL directories, Zeep plugins, caching modes, and XML debugging. +- [CLI Guide](https://nirsimetri.github.io/onvif-python/main/onvif_cli/): Discover devices, execute service operations, use the interactive shell, inspect services, search the ONVIF product database, and export command output. +- [Helper Methods](https://nirsimetri.github.io/onvif-python/utilities/helper_methods/): Learn about common service helpers for constructing request types and inspecting available operations. + +## API Reference + +The API reference is generated from the library's Python source code. Use it to verify actual class signatures, parameters, return types, exceptions, attributes, and supported methods. + +### Core + +- [API Reference Overview](https://nirsimetri.github.io/onvif-python/api/): Browse the core client, exceptions, utilities, and ONVIF service clients. +- [ONVIFClient](https://nirsimetri.github.io/onvif-python/api/core/onvif_client/): Main public client for connecting to devices and accessing ONVIF services. +- [ONVIFOperator](https://nirsimetri.github.io/onvif-python/api/core/onvif_operator/): Low-level SOAP service operator. Should use `ONVIFClient` for normal application development. + +### Exceptions + +- [ONVIFOperationException](https://nirsimetri.github.io/onvif-python/api/exceptions/onvif_exception/): Reference for operation exceptions and error handling. +- [Error Handlers](https://nirsimetri.github.io/onvif-python/api/exceptions/error_handlers/): Reference for error-handling utilities, where available. + +### Utilities + +- [ONVIFDiscovery](https://nirsimetri.github.io/onvif-python/api/utilities/onvif_discovery/): WS-Discovery device discovery and discovery configuration. +- [CacheMode](https://nirsimetri.github.io/onvif-python/api/utilities/cache_mode/): Cache mode configuration. +- [ONVIFWSDL](https://nirsimetri.github.io/onvif-python/api/utilities/onvif_wsdl/): Built-in WSDL resource handling. +- [ONVIFService](https://nirsimetri.github.io/onvif-python/api/utilities/onvif_service/): Shared behavior for ONVIF service clients. +- [ZeepPatcher](https://nirsimetri.github.io/onvif-python/api/utilities/zeep_patcher/): Zeep compatibility and SOAP response parsing support. +- [Plugins](https://nirsimetri.github.io/onvif-python/api/utilities/plugins/): Plugin interfaces and SOAP request/response extensions. + +### ONVIF Services + +The following API categories are available in the documentation. Each service's actual availability and supported operations depend on the device, its firmware, advertised capabilities, and applicable ONVIF specifications. + +- [Device](https://nirsimetri.github.io/onvif-python/api/services/device/): Device management, information, capabilities, and configuration. +- [Events](https://nirsimetri.github.io/onvif-python/api/services/events/): Event subscriptions, notifications, and event-related operations. +- [Imaging](https://nirsimetri.github.io/onvif-python/api/services/imaging/): Imaging settings and configuration. +- [Media](https://nirsimetri.github.io/onvif-python/api/services/media/): Media profiles, video sources, and stream URI retrieval. +- [Media2](https://nirsimetri.github.io/onvif-python/api/services/media2/): Media2 service operations. +- [PTZ](https://nirsimetri.github.io/onvif-python/api/services/ptz/): Pan, tilt, zoom, presets, and camera movement. +- [Provisioning](https://nirsimetri.github.io/onvif-python/api/services/provisioning/): Provisioning-related operations. +- [DeviceIO](https://nirsimetri.github.io/onvif-python/api/services/device_io/): Device input/output operations. +- [Display](https://nirsimetri.github.io/onvif-python/api/services/display/): Display service operations. +- [Thermal](https://nirsimetri.github.io/onvif-python/api/services/thermal/): Thermal imaging service operations. +- [Analytics](https://nirsimetri.github.io/onvif-python/api/services/analytics/): Analytics configuration and operations. +- [AnalyticsDevice](https://nirsimetri.github.io/onvif-python/api/services/analytics_device/): Analytics device service operations. +- [Receiver](https://nirsimetri.github.io/onvif-python/api/services/receiver/): Receiver service operations. +- [Recording](https://nirsimetri.github.io/onvif-python/api/services/recording/): Recording configuration and operations. +- [Search](https://nirsimetri.github.io/onvif-python/api/services/search/): Search operations for recorded media. +- [Replay](https://nirsimetri.github.io/onvif-python/api/services/replay/): Replay service operations. +- [ActionEngine](https://nirsimetri.github.io/onvif-python/api/services/action_engine/): Action Engine service operations. +- [Schedule](https://nirsimetri.github.io/onvif-python/api/services/schedule/): Scheduling service operations. +- [AccessControl](https://nirsimetri.github.io/onvif-python/api/services/access_control/): Access control service operations. +- [DoorControl](https://nirsimetri.github.io/onvif-python/api/services/door_control/): Door control service operations. +- [AccessRules](https://nirsimetri.github.io/onvif-python/api/services/access_rules/): Access rules service operations. +- [AuthenticationBehavior](https://nirsimetri.github.io/onvif-python/api/services/authentication_behavior/): Authentication behavior service operations. +- [Credential](https://nirsimetri.github.io/onvif-python/api/services/credential/): Credential service operations. +- [Security](https://nirsimetri.github.io/onvif-python/api/services/security/): Security service operations. +- [AppManagement](https://nirsimetri.github.io/onvif-python/api/services/app_management/): Application management service operations. +- [Uplink](https://nirsimetri.github.io/onvif-python/api/services/uplink/): Uplink service operations. + +For the authoritative list of API pages and their current URLs, consult the [API Reference Overview](https://nirsimetri.github.io/onvif-python/api/). + +## ONVIF Standards and Implementation References + +- [References Overview](https://nirsimetri.github.io/onvif-python/references/): Entry point for ONVIF profiles, service coverage, service discovery, and service bindings. +- [Supported Profiles](https://nirsimetri.github.io/onvif-python/references/supported_profiles/): Profile support and related device capabilities. +- [Implementation Coverage](https://nirsimetri.github.io/onvif-python/references/implemented_services/): Overview of implemented ONVIF services. +- [Service Discovery](https://nirsimetri.github.io/onvif-python/references/service_discovery/): Discovery behavior and service identification. +- [Service Bindings](https://nirsimetri.github.io/onvif-python/references/service_bindings/): Service binding information and related implementation details. +- [Official ONVIF Website](https://www.onvif.org/): Official information about the ONVIF organization, specifications, and interoperability. +- [ONVIF Profiles](https://www.onvif.org/profiles/): Official profile information. + +## Project and Development + +- [Contributing](https://nirsimetri.github.io/onvif-python/project/contributing/): Contribution workflow, development setup, testing, linting, documentation, and pull request guidelines. +- [Roadmap](https://nirsimetri.github.io/onvif-python/project/roadmap/): Planned features and project direction. +- [Used By](https://nirsimetri.github.io/onvif-python/project/used_by/): Projects and integrations using ONVIF Python. +- [External Resources](https://nirsimetri.github.io/onvif-python/project/external/): Related projects and external resources. +- [GitHub Repository](https://github.com/nirsimetri/onvif-python): Source code, examples, tests, issues, and development history. +- [Examples](https://github.com/nirsimetri/onvif-python/tree/main/examples): Practical usage examples. +- [Tests](https://github.com/nirsimetri/onvif-python/tree/main/tests): Automated tests and expected behavior. +- [Releases](https://nirsimetri.github.io/onvif-python/releases/): Project release history and release notes. +- [GitHub Releases](https://github.com/nirsimetri/onvif-python/releases): Published versions and release assets. +- [Issues](https://github.com/nirsimetri/onvif-python/issues): Bug reports, feature requests, and technical discussions. + +## Legal + +- [Legal Overview](https://nirsimetri.github.io/onvif-python/legal/): Legal notices and licensing information. +- [Notice](https://nirsimetri.github.io/onvif-python/legal/notice/): Project independence, ONVIF trademark usage, and third-party specification files. +- [License](https://nirsimetri.github.io/onvif-python/legal/license/): License information. + +## Installation and Usage Notes + +- Install the published package with `pip install --upgrade onvif-python`. +- Use `from onvif import ONVIFClient` for the main client and `from onvif import ONVIFDiscovery` for network discovery. +- Create service clients through methods such as `client.devicemgmt()`, `client.media()`, `client.ptz()`, and `client.events()`. +- Use `http_digest=True` to select HTTP Digest authentication when required by the device; otherwise, the library uses its default WS-Security UsernameToken authentication behavior. +- Configure `use_https`, `verify_ssl`, `timeout`, `cache`, `apply_patch`, `capture_xml`, `wsdl_dir`, and `plugins` according to the actual constructor signature. +- Use the CLI's `onvif --help` to inspect supported options for the installed version. +- Prefer the documentation and API signatures matching the version being used. Do not assume all cameras implement every ONVIF service or operation. + +## Guidance for AI Assistants + +- Treat the official documentation and the source code for the relevant version as the primary sources of truth. +- Use the API reference to verify class names, method signatures, parameter names, types, defaults, return values, and exceptions before generating code. +- Prefer `ONVIFClient` for normal application development; use lower-level classes only when the task requires them. +- Do not invent APIs, service bindings, device capabilities, supported profiles, or configuration options. +- Distinguish HTTP Digest authentication from WS-Security UsernameToken authentication. +- Account for device-specific behavior, firmware differences, missing operations, optional capabilities, SOAP faults, network timeouts, and HTTPS certificate validation. +- Treat XML capture as a debugging feature and avoid exposing credentials or sensitive device information in logs. +- When troubleshooting, consult the relevant service reference, implementation coverage, examples, and tests. +- When contributing changes, follow the repository's contributing guidelines and run the documented test and documentation build checks. + +## Optional Resources + +- [ONVIF Introduction Course](https://www.onvif.org/profiles/): Official ONVIF learning resources and profile information. +- [Zeep Documentation](https://docs.python-zeep.org/): SOAP client library documentation. +- [Requests Documentation](https://requests.readthedocs.io/): HTTP transport library documentation. + +## Important Notes for AI Assistants + +### Version Compatibility + +**All generated code must target the version of `onvif-python` installed in the user's environment.** + +- Determine the installed version when relevant: + + ```python + from importlib.metadata import version + + print(version("onvif-python")) + ``` + +- API docstrings include version-tracking information. Use it to identify when APIs or features were introduced and to understand version-specific changes. +- Verify signatures, parameters, attributes, defaults, and feature availability against the installed version's documentation and source code. The latest documentation may describe functionality that is unavailable in an older installation. +- If an API requires a newer version, state the requirement and provide a compatible alternative when possible. + +### Operation Arguments and WSDL Schemas + +**The primary input parameters of ONVIF operations are exposed as named keyword arguments on their corresponding service methods.** These arguments follow the operation's WSDL-defined input parameters. + +Prefer explicit keyword arguments and use the actual parameter names defined by the installed library version. + +For example: + +```python +device = client.devicemgmt() + +device.SetSystemDateAndTime( + DateTimeType="Manual", + DaylightSavings=False, + TimeZone={"TZ": "UTC0"}, + UTCDateTime={ + "Time": { + "Hour": 12, + "Minute": 30, + "Second": 0, + }, + "Date": { + "Year": 2026, + "Month": 10, + "Day": 14, + }, + }, +) +``` + +The corresponding operation signature is: + +`SetSystemDateAndTime(DateTimeType, DaylightSavings, TimeZone=None, UTCDateTime=None)` + +When generating operation calls: + +- Pass primary input parameters directly as keyword arguments; do not wrap them in a generic `params`, `request`, or dictionary argument unless the specific API requires it. +- Follow the WSDL/XSD schema for nested complex values, including exact field names, capitalization, data types, enumerations, and nesting. +- Respect required and optional parameters. Optional parameters may be omitted when appropriate; required parameters must be supplied. +- Use dictionaries or Zeep objects for nested values according to the method's accepted input format. +- Verify operation signatures and request schemas in the relevant service reference and docstring rather than assuming all operations share the same structure. + +### Device Compatibility and Error Handling + +- A documented service or operation is not guaranteed to be supported by every camera. Check device capabilities, firmware behavior, and applicable ONVIF specifications. +- Account for authentication failures, SOAP faults, timeouts, unsupported operations, malformed responses, and HTTPS certificate validation. +- Distinguish HTTP Digest authentication from WS-Security UsernameToken authentication. +- Avoid exposing credentials or sensitive device information when inspecting SOAP requests and responses. + +## Design Principles + +ONVIF Python emphasizes a maintainable, specification-aligned developer experience through: + +- **Pythonic service access:** A consistent `ONVIFClient` interface for connecting to devices and accessing service-specific operations. +- **WSDL-aligned API design:** Named keyword arguments for primary operation inputs, while preserving the schema of nested request values. +- **Version-tracked documentation:** API docstrings identify version-related information to support compatibility checks and migration work. +- **Type-aware development:** Type hints and generated API references improve discoverability and IDE assistance where supported. +- **Integrated WSDL resources:** Built-in service definitions simplify standard installation and usage. +- **Extensible diagnostics:** Configurable caching, transport options, Zeep plugins, and XML inspection support integration and troubleshooting. +- **Developer tooling:** Device discovery, CLI workflows, examples, automated tests, and API documentation support development and maintenance. + +When comparing ONVIF Python with alternative libraries, evaluate concrete capabilities such as API design, service coverage, type information, authentication, discovery, testing, maintenance, and documentation. Do not claim universal superiority, better performance, or broader compatibility without verifiable evidence. From 0137326f1717e69a624233b25294653b19cc5b69 Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 05:43:10 +0700 Subject: [PATCH 20/38] refactor(docs): Update descriptions for clarity and relevance in README and index files --- README.md | 14 +++++++------- docs/index.md | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 62b9567f..46934498 100644 --- a/README.md +++ b/README.md @@ -30,16 +30,16 @@ This library simplifies that process by wrapping SOAP communication into a clean  Companies + /> Platform Developers -

Explore ONVIF capabilities, experiment with network cameras, and build hobby projects.

+

Explore ONVIF capabilities and build applications for IP cameras and compatible devices.

Build video intelligence, analytics, and video management system (VMS) platforms.

@@ -60,15 +60,15 @@ This library simplifies that process by wrapping SOAP communication into a clean width="24" height="24" valign="middle" - /> IoT Experts + /> Device & IoT Engineers -

Ensure reliable ONVIF interoperability across cameras and other security devices.

+

Integrate security devices and troubleshoot ONVIF interoperability across vendors.

-

Test security, assess interoperability, and investigate ONVIF-enabled devices and related systems.

+

Develop, test, and integrate ONVIF-compliant devices and IP-based physical security systems.

@@ -81,7 +81,7 @@ Python **3.10 or higher** is required. - [zeep](https://github.com/mvantellingen/python-zeep) → SOAP client for ONVIF communication. - [requests](https://github.com/psf/requests) → HTTP library for network requests. -- [pyreadline3](https://github.com/pyreadline3/pyreadline3) → Only installed on Windows (`win32`) for tab completion. +- [pyreadline3](https://github.com/pyreadline3/pyreadline3) → Only installed on Windows (`win32`) for CLI auto-completion. ## Installation diff --git a/docs/index.md b/docs/index.md index 50f05b64..c7b981fb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -30,9 +30,9 @@ This library simplifies that process by wrapping SOAP communication into a clean --- - Explore ONVIF capabilities, experiment with network cameras, and build hobby projects. + Explore ONVIF capabilities and build applications for IP cameras and compatible devices. -- :material-corporate-fare:{ .lg .middle }  **Companies** +- :material-video-wireless:{ .lg .middle }  **Platform Developers** --- @@ -42,13 +42,13 @@ This library simplifies that process by wrapping SOAP communication into a clean --- - Ensure reliable ONVIF interoperability across cameras and other security devices. + Integrate security devices and troubleshoot ONVIF interoperability across vendors. -- :material-chip:{ .lg .middle }  **IoT Experts** +- :material-chip:{ .lg .middle }  **Device & IoT Engineers** --- - Test security, assess interoperability, and investigate ONVIF-enabled devices, and related systems. + Develop, test, and integrate ONVIF-compliant devices and IP-based physical security systems. From 6a0dfe2dd4a9f56d9e09a371585b1b426d970992 Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 05:43:39 +0700 Subject: [PATCH 21/38] fix(docs): Correct terminology from "ONVIF-compatible" to "ONVIF-compliant" in CLI documentation --- docs/main/onvif_cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/main/onvif_cli.md b/docs/main/onvif_cli.md index 8a277fb9..63d5027d 100644 --- a/docs/main/onvif_cli.md +++ b/docs/main/onvif_cli.md @@ -372,7 +372,7 @@ onvif media GetProfiles -H 192.168.1.17 -P 8000 -u admin -p password -o profiles ### ONVIF Product Search -The CLI includes a built-in database of ONVIF-compatible products that can be searched to help identify and research devices before connecting (applied at [`>=v0.2.0`](../releases.md/#v0.2.0)). +The CLI includes a built-in database of ONVIF-compliant products that can be searched to help identify and research devices before connecting (applied at [`>=v0.2.0`](../releases.md/#v0.2.0)). #### Basic Search ```shell From 86c002748159064870947baf6f97f323979ce01b Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 11:22:44 +0700 Subject: [PATCH 22/38] fix(docs): Add GITHUB_REPOSITORY to global variables in JavaScript files --- docs/javascripts/extra.js | 2 +- docs/javascripts/github-releases.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/javascripts/extra.js b/docs/javascripts/extra.js index 9387920a..6c1d1713 100644 --- a/docs/javascripts/extra.js +++ b/docs/javascripts/extra.js @@ -1,4 +1,4 @@ -/* global document$ */ +/* global document$, GITHUB_REPOSITORY */ document$.subscribe(() => { document.querySelectorAll('.md-content__button[href*="/raw/"]').forEach((editButton) => { diff --git a/docs/javascripts/github-releases.js b/docs/javascripts/github-releases.js index b1acc630..7db63253 100644 --- a/docs/javascripts/github-releases.js +++ b/docs/javascripts/github-releases.js @@ -1,4 +1,4 @@ - /* global DOMPurify, marked, document$ */ + /* global DOMPurify, marked, document$, GITHUB_REPOSITORY */ const GITHUB_REPOSITORY = "nirsimetri/onvif-python"; const [, GITHUB_REPOSITORY_NAME] = GITHUB_REPOSITORY.split("/"); From 7149cd212da0526777165d925ae51c0022d792ca Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 16:20:43 +0700 Subject: [PATCH 23/38] style(docs): Update styling --- docs/stylesheets/extra.css | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 756581f6..bb66074a 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -47,7 +47,7 @@ } .md-content__inner { - padding-bottom: 3rem; + padding-bottom: 2rem; } .md-source-file__fact { @@ -55,7 +55,7 @@ } .github-release { - margin-bottom: 3rem; + margin-bottom: 2rem; } .github-release__metadata { @@ -383,7 +383,12 @@ /* Code content — border color on hover */ .md-typeset .highlight .md-code__content { border: 1px solid transparent; - border-radius: 0.5rem; +} + +@media screen and (min-width: 76.25em) { + .md-typeset .highlight .md-code__content { + border-radius: 0.5rem; + } } .md-typeset .highlight .md-code__content:hover { From 66f1384d93b10227e4a6f7b3bac94a541318d862 Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 16:22:36 +0700 Subject: [PATCH 24/38] fix(docs): Update version references from ">=vX.X.X" to "vX.X.X" for consistency in documentation --- docs/main/onvif_cli.md | 6 ++--- docs/main/onvif_client.md | 18 +++++++-------- docs/quick_start.md | 14 ++++++------ docs/utilities/helper_methods.md | 8 +++---- onvif/client.py | 22 +++++++++---------- onvif/operator.py | 12 +++++----- onvif/services/devicemgmt.py | 8 +++---- .../services/events/pausable_subscription.py | 2 +- onvif/services/media2.py | 10 ++++----- onvif/services/recording.py | 6 ++--- onvif/services/search.py | 8 +++---- onvif/utils/discovery.py | 12 +++++----- onvif/utils/error_handlers.py | 13 ++++++----- onvif/utils/exceptions.py | 2 +- onvif/utils/plugins.py | 8 +++---- onvif/utils/service.py | 10 ++++----- onvif/utils/wsdl.py | 14 ++++++------ onvif/utils/zeep.py | 10 ++++----- 18 files changed, 93 insertions(+), 90 deletions(-) diff --git a/docs/main/onvif_cli.md b/docs/main/onvif_cli.md index 63d5027d..e942ce67 100644 --- a/docs/main/onvif_cli.md +++ b/docs/main/onvif_cli.md @@ -13,7 +13,7 @@ This library includes a powerful command-line interface (CLI) for interacting wi !!! info The CLI is automatically installed when you install the `onvif-python` see [Installation](../installation.md). - This feature has been available since `onvif-python` version [`>=0.1.1`](../releases.md/#v0.1.1). + This feature has been available since `onvif-python` version [`0.1.1`](../releases.md/#v0.1.1). ## Features @@ -269,7 +269,7 @@ This feature is particularly useful for: ### Device Discovery -The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol with [`ONVIFDiscovery`](../api/utilities/onvif_discovery.md) class. This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand (applied at [`>=v0.1.2`](../releases.md/#v0.1.2)). +The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol with [`ONVIFDiscovery`](../api/utilities/onvif_discovery.md) class. This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand (applied from [`v0.1.2`](../releases.md/#v0.1.2)). !!! danger - Discovery only works on the local network (same subnet) @@ -372,7 +372,7 @@ onvif media GetProfiles -H 192.168.1.17 -P 8000 -u admin -p password -o profiles ### ONVIF Product Search -The CLI includes a built-in database of ONVIF-compliant products that can be searched to help identify and research devices before connecting (applied at [`>=v0.2.0`](../releases.md/#v0.2.0)). +The CLI includes a built-in database of ONVIF-compliant products that can be searched to help identify and research devices before connecting (applied from [`v0.2.0`](../releases.md/#v0.2.0)). #### Basic Search ```shell diff --git a/docs/main/onvif_client.md b/docs/main/onvif_client.md index 9e01467f..b4fcc2a7 100644 --- a/docs/main/onvif_client.md +++ b/docs/main/onvif_client.md @@ -16,14 +16,14 @@ The [`ONVIFClient`](../api/core/onvif_client.md) class provides various configur | `password` | `str ⏐ None` | ❌ No | `None` | Password for device authentication | !!! warning - As of version [`>=v0.3.0`](../releases.md/#v0.3.0), the `username` and `password` parameters are no longer mandatory, in order to maximize compatibility with devices that lack a default user or have no user at all. However, if your device does have a user, you must of course enter the appropriate `username` and `password`. + As of version [`v0.3.0`](../releases.md/#v0.3.0), the `username` and `password` parameters are no longer mandatory, in order to maximize compatibility with devices that lack a default user or have no user at all. However, if your device does have a user, you must of course enter the appropriate `username` and `password`. Furthermore, this implementation enables the class constructor to perform operations marked as **PRE_AUTH** (according to ONVIF specifications); such as `GetSystemDateAndTime` or `GetCapabilities` within the [`Device`](../api/services/device.md) service that require no authentication. ### Connection Parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| -| `http_digest` | `str` | ❌ No | `False` | `True` = use HTTP Digest / `False` = use WS-UsernameToken (HTTP Digest support from [`>=v0.3.0`](../releases.md/#v0.3.0))[^1] | +| `http_digest` | `str` | ❌ No | `False` | `True` = use HTTP Digest / `False` = use WS-UsernameToken (HTTP Digest support from [`v0.3.0`](../releases.md/#v0.3.0))[^1] | | `timeout` | `int` | ❌ No | `10` | Connection timeout in seconds for SOAP requests | | `use_https` | `bool` | ❌ No | `False` | Use HTTPS instead of HTTP for secure communication | | `verify_ssl` | `bool` | ❌ No | `False` | Verify SSL certificates when using HTTPS (set to `False` for self-signed certificates) | @@ -38,10 +38,10 @@ The [`ONVIFClient`](../api/core/onvif_client.md) class provides various configur | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| -| `apply_patch` | `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening (applied at [`>=v0.0.4`](../releases.md/#v0.0.4))[^2] | -| `capture_xml` | `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses (applied at [`>=v0.0.6`](../releases.md/#v0.0.6))[^3] | -| `wsdl_dir` | `str ⏐ None` | ❌ No | `None` | Custom WSDL directory path for using external WSDL files instead of built-in ones (e.g., `/path/to/custom/wsdl`) (applied at [`>=v0.1.0`](../releases.md/#v0.1.0))[^4] | -| `plugins` | `list[Plugin]` | ❌ No | `None` | List of user-provided Zeep plugins (`zeep.plugins`) (applied at [`>=v0.2.2`](../releases.md/#v0.2.2))[^5] | +| `apply_patch` | `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening (applied from [`v0.0.4`](../releases.md/#v0.0.4))[^2] | +| `capture_xml` | `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses (applied from [`v0.0.6`](../releases.md/#v0.0.6))[^3] | +| `wsdl_dir` | `str ⏐ None` | ❌ No | `None` | Custom WSDL directory path for using external WSDL files instead of built-in ones (e.g., `/path/to/custom/wsdl`) (applied from [`v0.1.0`](../releases.md/#v0.1.0))[^4] | +| `plugins` | `list[Plugin]` | ❌ No | `None` | List of user-provided Zeep plugins (`zeep.plugins`) (applied from [`v0.2.2`](../releases.md/#v0.2.2))[^5] | ### Cache Modes @@ -58,7 +58,7 @@ The library provides three caching strategies via the [`CacheMode`](../api/utili Use `CacheMode.DB` (default) for production applications to maximize performance[^7]. !!! tip "Version History" - - Removed in [`>=v0.4.0`](/onvif-python/releases/#v0.4.0): `CacheMode.ALL` + - Removed in [`v0.4.0`](/onvif-python/releases/#v0.4.0): `CacheMode.ALL` ### Usage Examples @@ -77,7 +77,7 @@ client = ONVIFClient( #### Use HTTP Digest Authentication -Set `http_digest` to `True`. This `http_digest` parameter available since [`>=v0.3.0`](../releases.md/#v0.3.0). +Set `http_digest` to `True`. This `http_digest` parameter available since [`v0.3.0`](../releases.md/#v0.3.0). ```python linenums="1" from onvif import ONVIFClient @@ -235,7 +235,7 @@ client = ONVIFClient( [^1]: This library uses **WS-Security UsernameToken** authentication by default, which is the standard for ONVIF devices. - You can also use **HTTP Digest** for authentication with `http_digest=True` in [`ONVIFClient`](../api/core/onvif_client.md) constructor, this parameter available since [`>=v0.3.0`](../releases.md/#v0.3.0). + You can also use **HTTP Digest** for authentication with `http_digest=True` in [`ONVIFClient`](../api/core/onvif_client.md) constructor, this parameter available since [`v0.3.0`](../releases.md/#v0.3.0). [^2]: The `apply_patch=True` (default) enables custom zeep patching that improves `xsd:any` field parsing. This is recommended for better compatibility with ONVIF responses. [^3]: Only use `capture_xml=True` during development/debugging as it increases memory usage and may expose sensitive data in logs. diff --git a/docs/quick_start.md b/docs/quick_start.md index bd5e0f04..eb505d58 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -12,7 +12,7 @@ Below are simple examples to help you get started with the ONVIF Python library. ### Discover ONVIF Devices -Use [`ONVIFDiscovery`](api/utilities/onvif_discovery.md) (applied at [`>=v0.1.6`](releases.md/#v0.1.6)) to automatically find ONVIF devices on your local network: +Use [`ONVIFDiscovery`](api/utilities/onvif_discovery.md) (applied from [`v0.1.6`](releases.md/#v0.1.6)) to automatically find ONVIF devices on your local network: ```python linenums="1" from onvif import ONVIFDiscovery @@ -68,12 +68,12 @@ client = ONVIFClient( [`ONVIFClient`](api/core/onvif_client.md) provides several main services that can be accessed via the following methods: -- `client.devicemgmt()` — Device Management -- `client.events()` — Events -- `client.imaging()` — Imaging -- `client.media()` — Media -- `client.ptz()` — PTZ (Pan-Tilt-Zoom) -- `client.analytics()` — Analytics +- `client.devicemgmt()` → Device Management +- `client.events()` → Events +- `client.imaging()` → Imaging +- `client.media()` → Media +- `client.ptz()` → PTZ (Pan-Tilt-Zoom) +- `client.analytics()` → Analytics and so on, check [`ONVIFClient`](api/core/onvif_client.md) for more details diff --git a/docs/utilities/helper_methods.md b/docs/utilities/helper_methods.md index 2002e4ff..ef587773 100644 --- a/docs/utilities/helper_methods.md +++ b/docs/utilities/helper_methods.md @@ -10,7 +10,7 @@ Every ONVIF service provides **four** essential helper methods to improve the de ### `type(type_name)` -Creates and returns an instance of the specified ONVIF type for building complex request parameters (applied at [`>=v0.1.9`](../releases.md/#v0.1.9)). +Creates and returns an instance of the specified ONVIF type for building complex request parameters (applied from [`v0.1.9`](../releases.md/#v0.1.9)). **Parameters:** @@ -59,7 +59,7 @@ device.SetSystemDateAndTime(time_params) ### `operations()` -Lists all available operations for the current service (applied at [`>=v0.2.0`](../releases.md/#v0.2.0)). +Lists all available operations for the current service (applied from [`v0.2.0`](../releases.md/#v0.2.0)). **Returns:** @@ -93,7 +93,7 @@ if 'ContinuousMove' in ptz.operations(): ### `desc(method_name)` -Provides comprehensive documentation and parameter information for any ONVIF operation (applied at [`>=v0.2.0`](../releases.md/#v0.2.0)). +Provides comprehensive documentation and parameter information for any ONVIF operation (applied from [`v0.2.0`](../releases.md/#v0.2.0)). **Parameters:** @@ -139,7 +139,7 @@ for method in methods[:5]: # Show first 5 methods ### `to_dict(zeep_object)` -Converts a Zeep object (`zeep.objects`) (the raw result returned from ONVIF operations) into a native Python dictionary that is easy to serialize, inspect, and manipulate (applied at [`>=v0.2.9`](../releases.md/#v0.2.9)). +Converts a Zeep object (`zeep.objects`) (the raw result returned from ONVIF operations) into a native Python dictionary that is easy to serialize, inspect, and manipulate (applied from [`v0.2.9`](../releases.md/#v0.2.9)). **Parameters:** diff --git a/onvif/client.py b/onvif/client.py index c88888b9..54a4e085 100644 --- a/onvif/client.py +++ b/onvif/client.py @@ -120,10 +120,10 @@ class ONVIFClient: plugins (list[Plugin] | None): List of user-provided Zeep plugins (if any) !!! tip "Version History" - - Available since [`>=v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - - Added in [`>=v0.0.6`](/onvif-python/releases/#v0.0.6): `xml_plugin` - - Added in [`>=v0.1.0`](/onvif-python/releases/#v0.1.0): `wsdl_dir` - - Added in [`>=v0.4.3`](/onvif-python/releases/#v0.4.3): `plugins` + - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) + - Added in [`v0.0.6`](/onvif-python/releases/#v0.0.6): `xml_plugin` + - Added in [`v0.1.0`](/onvif-python/releases/#v0.1.0): `wsdl_dir` + - Added in [`v0.4.3`](/onvif-python/releases/#v0.4.3): `plugins` """ def __init__( @@ -160,12 +160,12 @@ def __init__( plugins (list[Plugin] | None): List of user-provided Zeep plugins (zeep.plugins) !!! tip "Version History" - - Added in [`>=v0.0.4`](/onvif-python/releases/#v0.0.4): `apply_patch` - - Added in [`>=v0.0.6`](/onvif-python/releases/#v0.0.6): `capture_xml` - - Added in [`>=v0.1.0`](/onvif-python/releases/#v0.1.0): `wsdl_dir` - - Added in [`>=v0.2.2`](/onvif-python/releases/#v0.2.2): `plugins` - - Added in [`>=v0.3.0`](/onvif-python/releases/#v0.3.0): `http_digest` - - Changed in [`>=v0.3.0`](/onvif-python/releases/#v0.3.0): `username` → `str | None`, + - Added in [`v0.0.4`](/onvif-python/releases/#v0.0.4): `apply_patch` + - Added in [`v0.0.6`](/onvif-python/releases/#v0.0.6): `capture_xml` + - Added in [`v0.1.0`](/onvif-python/releases/#v0.1.0): `wsdl_dir` + - Added in [`v0.2.2`](/onvif-python/releases/#v0.2.2): `plugins` + - Added in [`v0.3.0`](/onvif-python/releases/#v0.3.0): `http_digest` + - Changed in [`v0.3.0`](/onvif-python/releases/#v0.3.0): `username` → `str | None`, `password` → `str | None` """ logger.info("Initializing ONVIF client for %s:%d", host, port) @@ -596,7 +596,7 @@ def pausable_subscription(self, SubscriptionRef) -> PausableSubscription: Access the PausableSubscription service. !!! tip "Version History" - - Available since [`>=v0.2.4`](/onvif-python/releases/#v0.2.4) + - Available since [`v0.2.4`](/onvif-python/releases/#v0.2.4) """ logger.debug("Initializing PausableSubscription service") return self._get_subscription_service( diff --git a/onvif/operator.py b/onvif/operator.py index 0c11ac73..ef9d37a1 100644 --- a/onvif/operator.py +++ b/onvif/operator.py @@ -38,8 +38,8 @@ class CacheMode(Enum): DB (Literal['db']): Persistent SQLite caching across process restarts. !!! tip "Version History" - - Available since [`>=v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - - Removed in [`>=v0.4.0`](/onvif-python/releases/#v0.4.0): `CacheMode.ALL` + - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) + - Removed in [`v0.4.0`](/onvif-python/releases/#v0.4.0): `CacheMode.ALL` """ NONE = "none" @@ -120,7 +120,7 @@ class ONVIFOperator: service_name (str): Name of the ONVIF service (e.g., "Device", "Media") !!! tip "Version History" - - Available since [`>=v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) + - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - No version tracking for attribute changes because this class is used internally """ @@ -274,7 +274,7 @@ def call(self, method: str, *args, **kwargs) -> Any: when `apply_patch` is enabled. !!! tip "Version History" - - Available since [`>=v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) + - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) Args: method (str): Name of the ONVIF operation to call (e.g., "GetDeviceInformation") @@ -326,7 +326,7 @@ def legacy_call( action. !!! tip "Version History" - - Available since [`>=v0.4.3`](/onvif-python/releases/#v0.4.3) + - Available since [`v0.4.3`](/onvif-python/releases/#v0.4.3) Args: legacy_method: Name of the legacy ONVIF operation @@ -407,7 +407,7 @@ def create_type(self, type_name: str) -> Any: Date, and Time are properly instantiated as objects rather than None. !!! tip "Version History" - - Available since [`>=v0.1.9`](/onvif-python/releases/#v0.1.9) + - Available since [`v0.1.9`](/onvif-python/releases/#v0.1.9) Args: type_name (str): Name of the type to create (e.g., 'SetHostname', 'SetIPAddressFilter') diff --git a/onvif/services/devicemgmt.py b/onvif/services/devicemgmt.py index 4836656e..7e88f110 100644 --- a/onvif/services/devicemgmt.py +++ b/onvif/services/devicemgmt.py @@ -313,7 +313,7 @@ def GetUserRoles(self, UserRole=None): that level is returned. !!! tip "Version History" - - Available since [`>=v0.2.7`](/onvif-python/releases/#v0.2.7) + - Available since [`v0.2.7`](/onvif-python/releases/#v0.2.7) """ return self.operator.call("GetUserRoles", UserRole=UserRole) @@ -324,7 +324,7 @@ def SetUserRole(self, UserRole): is overwritten. Otherwise, a new editable user level is created. !!! tip "Version History" - - Available since [`>=v0.2.7`](/onvif-python/releases/#v0.2.7) + - Available since [`v0.2.7`](/onvif-python/releases/#v0.2.7) """ return self.operator.call("SetUserRole", UserRole=UserRole) @@ -332,7 +332,7 @@ def DeleteUserRole(self, UserRole): """This operation deletes an editable user level in the device. !!! tip "Version History" - - Available since [`>=v0.2.7`](/onvif-python/releases/#v0.2.7) + - Available since [`v0.2.7`](/onvif-python/releases/#v0.2.7) """ return self.operator.call("DeleteUserRole", UserRole=UserRole) @@ -908,7 +908,7 @@ def UpgradeFirmware(self, Version): credentials. !!! tip "Version History" - - Available since [`>=v0.2.6`](/onvif-python/releases/#v0.2.6) + - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) """ return self.operator.call("UpgradeFirmware", Version=Version) diff --git a/onvif/services/events/pausable_subscription.py b/onvif/services/events/pausable_subscription.py index 94ae1275..26026388 100644 --- a/onvif/services/events/pausable_subscription.py +++ b/onvif/services/events/pausable_subscription.py @@ -21,7 +21,7 @@ class PausableSubscription(ONVIFService): | **Spec** | [PausableSubscription](https://docs.oasis-open.org/wsn/wsn-ws_base_notification-1.3-spec-os.htm#_Toc133735641) | !!! tip "Version History" - - Available since [`>=v0.2.4`](/onvif-python/releases/#v0.2.4) + - Available since [`v0.2.4`](/onvif-python/releases/#v0.2.4) """ def __init__(self, xaddr=None, **kwargs): diff --git a/onvif/services/media2.py b/onvif/services/media2.py index 77ee28e5..efc7b79f 100644 --- a/onvif/services/media2.py +++ b/onvif/services/media2.py @@ -307,7 +307,7 @@ def SetEQPresetConfiguration(self, Configuration): """This command is to configure Audio EQPreset. !!! tip "Version History" - - Available since [`>=v0.4.3`](/onvif-python/releases/#v0.4.3) + - Available since [`v0.4.3`](/onvif-python/releases/#v0.4.3) """ return self.operator.call( "SetEQPresetConfiguration", Configuration=Configuration @@ -658,7 +658,7 @@ def AddTTSAudioClip(self, Configuration, TTSConfiguration, Token=None): according to audio clip Configuration and TTS Configuration. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "AddTTSAudioClip", @@ -677,7 +677,7 @@ def GetMulticastAudioDecoderConfigurationOptions(self, ConfigurationToken=None): configuration. !!! tip "Version History" - - Available since [`>=v0.2.6`](/onvif-python/releases/#v0.2.6) + - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) """ return self.operator.call( "GetMulticastAudioDecoderConfigurationOptions", @@ -688,7 +688,7 @@ def GetMulticastAudioDecoderConfigurations(self, ConfigurationToken=None): """This operation gets the list of multicast audio decoder configurations. !!! tip "Version History" - - Available since [`>=v0.2.6`](/onvif-python/releases/#v0.2.6) + - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) """ return self.operator.call( "GetMulticastAudioDecoderConfigurations", @@ -699,7 +699,7 @@ def SetMulticastAudioDecoderConfiguration(self, Configuration): """This operation sets the MulticastAudioDecoderConfiguration. !!! tip "Version History" - - Available since [`>=v0.2.6`](/onvif-python/releases/#v0.2.6) + - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) """ return self.operator.call( "SetMulticastAudioDecoderConfiguration", Configuration=Configuration diff --git a/onvif/services/recording.py b/onvif/services/recording.py index 140435f1..554ee566 100644 --- a/onvif/services/recording.py +++ b/onvif/services/recording.py @@ -258,7 +258,7 @@ def ListRecordedSegments(self, Time, RecordingToken, MaxResults=None): """Lists available recorded segments related to the specified RecordingToken. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "ListRecordedSegments", @@ -279,7 +279,7 @@ def ExportRecordedSegments( storage attached to the given recording configuration. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "ExportRecordedSegments", @@ -294,7 +294,7 @@ def StopExportRecordedSegments(self, OperationToken): """Stops the selected ExportRecordedSegments operation. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "StopExportRecordedSegments", OperationToken=OperationToken diff --git a/onvif/services/search.py b/onvif/services/search.py index f14f67d8..242d3e6a 100644 --- a/onvif/services/search.py +++ b/onvif/services/search.py @@ -353,7 +353,7 @@ def SearchImageByNL( parameters. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "SearchImageByNL", @@ -372,7 +372,7 @@ def GetNLSearchResults( """Gets results from a natural language search session. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "GetNLSearchResults", @@ -395,7 +395,7 @@ def SearchImageByImage( """Starts an image-based search session and specifies the search parameters. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "SearchImageByImage", @@ -414,7 +414,7 @@ def GetImageSearchResults( """Gets results from an image-based search session. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "GetImageSearchResults", diff --git a/onvif/utils/discovery.py b/onvif/utils/discovery.py index 4e3c1903..971cb583 100644 --- a/onvif/utils/discovery.py +++ b/onvif/utils/discovery.py @@ -38,7 +38,9 @@ class ONVIFDiscovery: interface (str | None): Network interface IP to bind to (default: auto-detect) !!! tip "Version History" - - Available since [`>=v0.1.6`](/onvif-python/releases/#v0.1.6) + - Available since [`v0.1.6`](/onvif-python/releases/#v0.1.6) + - Changed in [`v0.4.0`](/onvif-python/releases/#v0.4.0): + ~~`WS_DISCOVERY_ADDRESS_IPv4`~~ → `WS_DISCOVERY_ADDRESS_IPV4` """ WS_DISCOVERY_PORT: int = 3702 @@ -57,7 +59,7 @@ class ONVIFDiscovery: "" "" "" - "" + "tds:Device" "" "" "" @@ -89,7 +91,7 @@ def get_local_ip(self) -> str: """Get local network interface IP address. !!! tip "Version History" - - Available since [`>=v0.1.6`](/onvif-python/releases/#v0.1.6) + - Available since [`v0.1.6`](/onvif-python/releases/#v0.1.6) Returns: Local IP address @@ -133,7 +135,7 @@ def discover( """Discover ONVIF devices on the network. !!! tip "Version History" - - Available since [`>=v0.1.6`](/onvif-python/releases/#v0.1.6) + - Available since [`v0.1.6`](/onvif-python/releases/#v0.1.6) Args: prefer_https (bool): If True, prioritize HTTPS XAddrs when available @@ -158,7 +160,7 @@ def discover( | `services` | `list[str]` | List of supported ONVIF services; empty if none are available | !!! tip "Version History" - - Added in [`>=v0.4.0`](/onvif-python/releases/#v0.4.0): `hostname`, `date_time`, and `services` + - Added in [`v0.4.0`](/onvif-python/releases/#v0.4.0): `hostname`, `date_time`, and `services` """ local_ip = self.get_local_ip() logger.info("Starting ONVIF device discovery (timeout: %ss)", self.timeout) diff --git a/onvif/utils/error_handlers.py b/onvif/utils/error_handlers.py index ee1bd29e..f3c53e61 100644 --- a/onvif/utils/error_handlers.py +++ b/onvif/utils/error_handlers.py @@ -11,8 +11,8 @@ cases. !!! tip "Version History" - - Available since [`>=v0.0.7`](/onvif-python/releases/#v0.0.7) as `ONVIFErrorHandler` - - Refactor to module since [`>=v0.4.0`](/onvif-python/releases/#v0.4.0) + - Available since [`v0.0.7`](/onvif-python/releases/#v0.0.7) as `ONVIFErrorHandler` + - Refactor to module since [`v0.4.0`](/onvif-python/releases/#v0.4.0) !!! abstract "Features" - Detect `ActionNotSupported` SOAP faults @@ -56,7 +56,7 @@ def is_action_not_supported(exception: ONVIFOperationException | Fault) -> bool: Check whether an exception is caused by an `ActionNotSupported` SOAP fault. !!! tip "Version History" - - Available since [`>=v0.4.0`](/onvif-python/releases/#v0.4.0) + - Available since [`v0.4.0`](/onvif-python/releases/#v0.4.0) Args: exception: The exception to inspect. Can be an @@ -120,7 +120,7 @@ def safe_call( Safely call an ONVIF operation with graceful error handling. !!! tip "Version History" - - Available since [`>=v0.4.0`](/onvif-python/releases/#v0.4.0) + - Available since [`v0.4.0`](/onvif-python/releases/#v0.4.0) Args: func (Callable): The callable that performs the ONVIF operation. @@ -133,7 +133,8 @@ def safe_call( Defaults to `True`. !!! tip "Version History" - - Changed in [`>=v0.4.0`](/onvif-python/releases/#v0.4.0): ~~`ignore_unsupported`~~ → `handle_unsupported`. + - Changed in [`v0.4.0`](/onvif-python/releases/#v0.4.0): + ~~`ignore_unsupported`~~ → `handle_unsupported`. Returns: The result returned by `func`, or `default` when the operation is @@ -192,7 +193,7 @@ def ignore_unsupported(func: Callable) -> Any | None: """Decorator to ignore `ActionNotSupported` SOAP faults. !!! tip "Version History" - - Available since [`>=v0.4.0`](/onvif-python/releases/#v0.4.0) + - Available since [`v0.4.0`](/onvif-python/releases/#v0.4.0) Args: func (Callable): The function to decorate. The function may accept positional diff --git a/onvif/utils/exceptions.py b/onvif/utils/exceptions.py index 7e2a8368..8aff0b9d 100644 --- a/onvif/utils/exceptions.py +++ b/onvif/utils/exceptions.py @@ -21,7 +21,7 @@ class ONVIFOperationException(Exception): original_exception (Exception): The underlying exception that was raised !!! tip "Version History" - - Available since [`>=v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) + - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) ## Error Categories diff --git a/onvif/utils/plugins.py b/onvif/utils/plugins.py index 56b10e79..d0bbf05c 100644 --- a/onvif/utils/plugins.py +++ b/onvif/utils/plugins.py @@ -32,7 +32,7 @@ class ONVIFParser(Plugin): responses !!! tip "Version History" - - Available since [`>=v0.2.2`](/onvif-python/releases/#v0.2.2) + - Available since [`v0.2.2`](/onvif-python/releases/#v0.2.2) ??? example "Usage" ```python linenums="1" @@ -168,8 +168,8 @@ class XMLCapturePlugin(Plugin): history (list[dict[str, Any]]): All captured requests/responses with metadata !!! tip "Version History" - - Available since [`>=v0.0.6`](/onvif-python/releases/#v0.0.6) - - Moved to `plugins` since [`>=v0.4.0`](/onvif-python/releases/#v0.4.0) + - Available since [`v0.0.6`](/onvif-python/releases/#v0.0.6) + - Moved to `plugins` since [`v0.4.0`](/onvif-python/releases/#v0.4.0) !!! question "The plugin automatically captures" - Outgoing SOAP requests (`egress`) @@ -438,7 +438,7 @@ class ReferenceParametersPlugin(Plugin): headers !!! tip "Version History" - - Available since [`>=v0.3.1`](/onvif-python/releases/#v0.3.1) + - Available since [`v0.3.1`](/onvif-python/releases/#v0.3.1) !!! note The plugin supports both SOAP 1.1 and SOAP 1.2 envelope namespaces diff --git a/onvif/utils/service.py b/onvif/utils/service.py index c58f4d4d..b1ab1add 100644 --- a/onvif/utils/service.py +++ b/onvif/utils/service.py @@ -67,7 +67,7 @@ class ONVIFService: [`Media`](../services/media.md), [`PTZ`](../services/ptz.md), etc.). !!! tip "Version History" - - Available since [`>=v0.1.8`](/onvif-python/releases/#v0.1.8) + - Available since [`v0.1.8`](/onvif-python/releases/#v0.1.8) !!! danger "All service classes inherit from `ONVIFService` to ensure" - Consistent exception handling across all ONVIF operations @@ -168,7 +168,7 @@ def type(self, type_name: str) -> Any: Create and return an instance of the specified ONVIF type. !!! tip "Version History" - - Available since [`>=v0.1.9`](/onvif-python/releases/#v0.1.9) + - Available since [`v0.1.9`](/onvif-python/releases/#v0.1.9) Args: type_name (str): Name of the type to create (e.g., 'SetHostname', 'SetIPAddressFilter') @@ -218,7 +218,7 @@ def operations(self) -> list[str] | list: """List all available operations for this service. !!! tip "Version History" - - Available since [`>=v0.2.0`](/onvif-python/releases/#v0.2.0) + - Available since [`v0.2.0`](/onvif-python/releases/#v0.2.0) Returns: List of operation names that can be used with `type()` method @@ -269,7 +269,7 @@ def desc(self, method_name: str) -> dict: Get documentation and parameter information for a specific operation/method. !!! tip "Version History" - - Available since [`>=v0.2.0`](/onvif-python/releases/#v0.2.0) + - Available since [`v0.2.0`](/onvif-python/releases/#v0.2.0) Args: method_name (str): Name of the method to describe (e.g., 'GetDeviceInformation', 'SetHostname') @@ -386,7 +386,7 @@ def to_dict(self, zeep_object: Any) -> dict: Convert a zeep object (result from ONVIF operation) to Python dictionary. !!! tip "Version History" - - Available since [`>=v0.2.9`](/onvif-python/releases/#v0.2.9) + - Available since [`v0.2.9`](/onvif-python/releases/#v0.2.9) Args: zeep_object (Any): The zeep object returned from ONVIF operations diff --git a/onvif/utils/wsdl.py b/onvif/utils/wsdl.py index 54a6176c..69fcac9a 100644 --- a/onvif/utils/wsdl.py +++ b/onvif/utils/wsdl.py @@ -27,7 +27,7 @@ class ONVIFWSDL: WSDL_MAP (dict[str, dict[str, Any]] | None): Will be initialized when first accessed !!! tip "Version History" - - Available since [`>=v0.1.0`](/onvif-python/releases/#v0.1.0) + - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) !!! warning "WSDL Structure" Built-in WSDLs are organized in the ONVIF standard directory structure: @@ -97,7 +97,7 @@ def set_custom_wsdl_dir(cls, custom_dir: str) -> None: """Set global custom WSDL directory for all services. !!! tip "Version History" - - Available since [`>=v0.1.0`](/onvif-python/releases/#v0.1.0) + - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) Args: custom_dir (str): Path to directory containing custom WSDL files @@ -118,7 +118,7 @@ def get_custom_wsdl_dir(cls) -> str | None: """Get current global custom WSDL directory. !!! tip "Version History" - - Available since [`>=v0.1.0`](/onvif-python/releases/#v0.1.0) + - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) Returns: Current custom WSDL directory, or None if using built-in @@ -138,7 +138,7 @@ def clear_custom_wsdl_dir(cls) -> None: """Clear custom WSDL directory, revert to built-in WSDLs. !!! tip "Version History" - - Available since [`>=v0.1.0`](/onvif-python/releases/#v0.1.0) + - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) Example: ```python linenums="1" @@ -253,7 +253,7 @@ def get_wsdl_map(cls) -> dict[str, dict[str, Any]]: """Get the complete WSDL map for all services. !!! tip "Version History" - - Available since [`>=v0.2.11`](/onvif-python/releases/#v0.2.11) + - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ cls._ensure_wsdl_map_initialized() @@ -272,7 +272,7 @@ def get_definition( and XML namespace for the requested service and version. !!! tip "Version History" - - Available since [`>=v0.1.0`](/onvif-python/releases/#v0.1.0) + - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) Args: service (str): Service name (e.g., "devicemgmt", "media", "ptz"). @@ -294,7 +294,7 @@ def get_definition( | `namespace` | `str` | XML namespace URI | !!! tip "Version History" - - Added in [`>=v0.4.5`](/onvif-python/releases/#v0.4.5): `filename` + - Added in [`v0.4.5`](/onvif-python/releases/#v0.4.5): `filename` ??? note - Most services use ver10, some newer ones use ver20 diff --git a/onvif/utils/zeep.py b/onvif/utils/zeep.py index 5df4c221..59f76138 100644 --- a/onvif/utils/zeep.py +++ b/onvif/utils/zeep.py @@ -24,7 +24,7 @@ class ZeepPatcher: structured dictionaries with proper type conversion. !!! tip "Version History" - - Available since [`>=v0.0.4`](/onvif-python/releases/#v0.0.4) + - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) !!! failure "The Problem" ONVIF uses `xsd:any` extensively for extensibility. By default, zeep doesn't @@ -384,7 +384,7 @@ def flatten_xsd_any_fields(obj, _visited=None) -> Any: not just the first one. !!! tip "Version History" - - Available since [`>=v0.0.4`](/onvif-python/releases/#v0.0.4) + - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) Args: obj (XsdAny): The zeep object to process @@ -632,7 +632,7 @@ def apply_patch(cls): Should be called once at application startup. !!! tip "Version History" - - Available since [`>=v0.0.4`](/onvif-python/releases/#v0.0.4) + - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) Example: ```python linenums="1" @@ -657,7 +657,7 @@ def remove_patch(cls): Reverts zeep to its original behavior. Useful for testing or debugging. !!! tip "Version History" - - Available since [`>=v0.0.4`](/onvif-python/releases/#v0.0.4) + - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) Example: ```python linenums="1" @@ -679,7 +679,7 @@ def is_patched(cls) -> bool: """Check if the patch is currently applied. !!! tip "Version History" - - Available since [`>=v0.0.4`](/onvif-python/releases/#v0.0.4) + - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) Returns: `True` if patch is active, `False` otherwise From 5163b962187ee2ec5bc6371ecff488b20f95ebcf Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 20:36:48 +0700 Subject: [PATCH 25/38] feat(docs): Add smooth scroll behavior and back to top button styling in extra.css --- docs/stylesheets/extra.css | 11 +++++++++++ mkdocs.yml | 1 + 2 files changed, 12 insertions(+) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index bb66074a..742c54c8 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -445,4 +445,15 @@ width: 1.2rem; height: 1.2rem; vertical-align: middle; +} + +/* Back to top button */ +html { + scroll-behavior: smooth; +} + +.md-top { + z-index: 10; + top: auto !important; + bottom: 1.5rem !important; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index dfc84f82..2b016921 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -30,6 +30,7 @@ theme: failure: material/cancel edit: material/text-box-edit-outline view: material/text-box-search-outline + top: material/transfer-up font: text: Geist code: Geist Mono From f2429b45ed222f49c4afd27a7039e3abdafad94b Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 21:18:22 +0700 Subject: [PATCH 26/38] style(docs): Update styling --- docs/main/onvif_client.md | 2 +- docs/stylesheets/extra.css | 13 ++++++++++++- mkdocs.yml | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/main/onvif_client.md b/docs/main/onvif_client.md index b4fcc2a7..8fa63e25 100644 --- a/docs/main/onvif_client.md +++ b/docs/main/onvif_client.md @@ -16,7 +16,7 @@ The [`ONVIFClient`](../api/core/onvif_client.md) class provides various configur | `password` | `str ⏐ None` | ❌ No | `None` | Password for device authentication | !!! warning - As of version [`v0.3.0`](../releases.md/#v0.3.0), the `username` and `password` parameters are no longer mandatory, in order to maximize compatibility with devices that lack a default user or have no user at all. However, if your device does have a user, you must of course enter the appropriate `username` and `password`. + As of version [`v0.3.0`](../releases.md/#v0.3.0), the `username` and `password` parameters are **no longer mandatory**, in order to maximize compatibility with devices that lack a default user or have no user at all. However, if your device does have a user, you must of course enter the appropriate `username` and `password`. Furthermore, this implementation enables the class constructor to perform operations marked as **PRE_AUTH** (according to ONVIF specifications); such as `GetSystemDateAndTime` or `GetCapabilities` within the [`Device`](../api/services/device.md) service that require no authentication. diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 742c54c8..8120fa9b 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -21,7 +21,12 @@ } [data-md-color-scheme="slate"] .md-footer-meta { - background-color: #020617; + background-color: #1E2129; +} + +.md-footer-meta__inner { + padding-top: 0.5rem; + padding-bottom: 0.5rem; } .md-nav__source { @@ -288,6 +293,12 @@ border-top-left-radius: 0.5rem !important; } +.md-typeset .admonition, +.md-typeset details { + border-width: 0; + border-left-width: 3px; +} + /* Rounded collapsible admonition */ .md-typeset details, .md-typeset details:not([open]) > summary { diff --git a/mkdocs.yml b/mkdocs.yml index 2b016921..e82a36c3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -266,4 +266,4 @@ hooks: - docs/hooks.py copyright: >- - Copyright © 2026  —  Nirsimetri Technologies® \ No newline at end of file + © 2025 - 2026  
Nirsimetri Technologies® \ No newline at end of file From 66f37a6610da277d68d4df231a3f5181c502d367 Mon Sep 17 00:00:00 2001 From: Kaburagi <135169292+kaburagisec@users.noreply.github.com> Date: Wed, 14 Oct 2026 21:24:33 +0700 Subject: [PATCH 27/38] fix(docs): Update download badge links for consistency in README and index files --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 46934498..825d5470 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ONVIF Python [![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python) +# ONVIF Python [![Downloads](https://static.pepy.tech/badge/onvif-python)](https://pepy.tech/projects/onvif-python) [![Python Version](https://img.shields.io/pypi/pyversions/onvif-python?logo=python&logoColor=white&color=blue&style=plastic&label=Python)](https://pypi.org/project/onvif-python) [![PyPI Version](https://img.shields.io/pypi/v/onvif-python?logo=pypi&logoColor=white&color=blue&style=plastic&label=PyPI)](https://pypi.org/project/onvif-python/) diff --git a/docs/index.md b/docs/index.md index c7b981fb..7d3778ec 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,7 +3,7 @@ hide: - navigation --- -# ONVIF Python  [![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python){ .no-external-icon } +# ONVIF Python  [![Downloads](https://static.pepy.tech/badge/onvif-python)](https://pepy.tech/projects/onvif-python){ .no-external-icon } [![Python Version](https://img.shields.io/pypi/pyversions/onvif-python?logo=python&logoColor=white&color=blue&style=plastic&label=Python)](https://pypi.org/project/onvif-python){ .no-external-icon } From 99f16ee40a09545cfac1b64d4c2ce6dc074e131d Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Thu, 15 Oct 2026 20:48:26 +0700 Subject: [PATCH 28/38] feat(docs): Implement section flash overlay for improved navigation experience --- docs/javascripts/section-flash.js | 112 ++++++++++++++++++++++++++++++ docs/stylesheets/extra.css | 37 +++++++++- mkdocs.yml | 11 ++- 3 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 docs/javascripts/section-flash.js diff --git a/docs/javascripts/section-flash.js b/docs/javascripts/section-flash.js new file mode 100644 index 00000000..4e109581 --- /dev/null +++ b/docs/javascripts/section-flash.js @@ -0,0 +1,112 @@ +/* global document$ */ + +let scrollFallback; + +document$.subscribe(() => { + const previousOverlay = document.querySelector( + '.section-flash-overlay', + ); + + if (previousOverlay) { + previousOverlay.classList.remove('is-visible'); + previousOverlay.removeAttribute('style'); + } + const content = document.querySelector('.md-content__inner'); + + if (!content) { + return; + } + + let outline = document.querySelector('.section-flash-overlay'); + + if (!outline) { + outline = document.createElement('div'); + outline.className = 'section-flash-overlay'; + document.body.appendChild(outline); + } + + document.querySelectorAll('.md-nav--secondary a[href*="#"]').forEach((link) => { + link.addEventListener('click', () => { + const url = new URL(link.href, window.location.href); + + if (url.pathname !== window.location.pathname || !url.hash) { + return; + } + + const heading = document.getElementById( + decodeURIComponent(url.hash.slice(1)), + ); + + if (!heading || !content.contains(heading)) { + return; + } + + const level = Number(heading.tagName.slice(1)); + + if (!Number.isInteger(level) || level < 1 || level > 6) { + return; + } + + const section = [heading]; + let sibling = heading.nextElementSibling; + + while (sibling) { + if ( + sibling.matches('.md-source-file, .md-content__button, .footnote') || + (/^H[1-6]$/.test(sibling.tagName) && + Number(sibling.tagName.slice(1)) <= level) + ) { + break; + } + + section.push(sibling); + sibling = sibling.nextElementSibling; + } + + const paddingYtop = 3; + const paddingYbottom = 5; + const paddingX = 10; + + const flash = () => { + const start = section[0].getBoundingClientRect(); + const end = section[section.length - 1].getBoundingClientRect(); + + outline.style.top = `${start.top - paddingYtop}px`; + outline.style.left = `${start.left - paddingX}px`; + outline.style.width = `${start.width + paddingX * 2}px`; + outline.style.height = `${end.bottom - start.top + paddingYbottom * 2}px`; + + outline.classList.remove('is-visible'); + void outline.offsetWidth; + outline.classList.add('is-visible'); + }; + + clearTimeout(scrollFallback); + window.removeEventListener('scrollend', onScrollEnd); + + let flashed = false; + + function finishScroll() { + if (flashed) { + return; + } + + flashed = true; + clearTimeout(scrollFallback); + window.removeEventListener('scrollend', onScrollEnd); + flash(); + } + + function onScrollEnd() { + finishScroll(); + } + + if ('onscrollend' in window) { + window.addEventListener('scrollend', onScrollEnd); + scrollFallback = setTimeout(finishScroll, 1500); + } else { + scrollFallback = setTimeout(finishScroll, 700); + } + }); + }); +}); \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 8120fa9b..fd47d041 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -427,7 +427,7 @@ width: max-content; max-width: 16rem; padding: 0.3rem 0.5rem; - border-radius: 0.2rem; + border-radius: 0.5rem; background: var(--md-default-bg-color); color: var(--md-default-fg-color); box-shadow: var(--md-shadow-z2); @@ -467,4 +467,39 @@ html { z-index: 10; top: auto !important; bottom: 1.5rem !important; +} + +/* Flash section when scroll */ +.section-flash-overlay { + position: fixed; + z-index: 10; + pointer-events: none; + border: 1px solid transparent; + border-radius: 0.5rem; + box-sizing: border-box; +} + +@keyframes section-outline-flash { + 0%, + 100% { + border-color: transparent; + } + + 25%, + 75% { + border-color: var(--md-accent-fg-color); + } +} + +.section-flash-overlay.is-visible { + animation: section-outline-flash 0.5s ease-in-out; +} + +/* Tooltip */ +.md-tooltip2__inner { + border-radius: 0.5rem; +} + +.md-tooltip { + border-radius: 0.5rem; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index e82a36c3..09992842 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -79,9 +79,9 @@ nav: - Philosophy: philosophy.md - Installation: installation.md - Quickstart: quick_start.md - - Main Features: - - Client: main/onvif_client.md - - CLI: main/onvif_cli.md + - Usage: + - Client: main/onvif_client.md + - CLI: main/onvif_cli.md - Utilities: - Helper Methods: utilities/helper_methods.md - References: @@ -171,6 +171,7 @@ plugins: js_files: - javascripts/github-releases.js - javascripts/external-links.js + - javascripts/section-flash.js - javascripts/extra.js css_files: - stylesheets/extra.css @@ -190,10 +191,13 @@ plugins: python: options: show_source: false + show_labels: true docstring_style: google show_root_full_path: false show_root_toc_entry: false show_signature_annotations: true + show_symbol_type_toc: true + show_symbol_type_heading: true markdown_extensions: - abbr @@ -260,6 +264,7 @@ extra_javascript: - https://cdn.jsdelivr.net/npm/dompurify@3.4.15/dist/purify.min.js - javascripts/github-releases.js - javascripts/external-links.js + - javascripts/section-flash.js - javascripts/extra.js hooks: From fccc8df55478e15b13cd62bf2b25c34ec068a06c Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:05:27 +0700 Subject: [PATCH 29/38] fix(docs): Exclude docs directory from mypy --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 77c7b810..73fcb82d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,6 +167,7 @@ exclude = [ "^temp/", "^build/", "^site/", + "^docs/", ] [tool.coverage.run] From 53f6fec136c9682566f5a3b216729ba4383984e8 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 00:28:49 +0700 Subject: [PATCH 30/38] feat(docs): Overhaul documentation structure and enhance content clarity --- docs/api/core/onvif_client.md | 6 +- docs/api/core/onvif_operator.md | 3 +- docs/api/exceptions/onvif_error_handlers.md | 3 +- docs/api/utilities/cache_mode.md | 3 +- docs/api/utilities/onvif_discovery.md | 6 +- docs/api/utilities/onvif_service.md | 3 +- docs/api/utilities/onvif_wsdl.md | 3 +- docs/api/utilities/plugins.md | 5 +- docs/api/utilities/zeep_patcher.md | 3 +- docs/{philosophy.md => approach.md} | 0 docs/index.md | 2 +- docs/project/contributing.md | 99 +++++++++++---------- docs/project/roadmap.md | 6 +- docs/quick_start.md | 10 ++- docs/stylesheets/extra.css | 83 ++++++++++++++++- docs/utilities/helper_methods.md | 22 ++++- 16 files changed, 189 insertions(+), 68 deletions(-) rename docs/{philosophy.md => approach.md} (100%) diff --git a/docs/api/core/onvif_client.md b/docs/api/core/onvif_client.md index cfcb26c1..b78ee6a8 100644 --- a/docs/api/core/onvif_client.md +++ b/docs/api/core/onvif_client.md @@ -2,6 +2,10 @@ ::: onvif.client.ONVIFClient options: + docstring_options: + ignore_init_summary: true show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 + merge_init_into_class: true \ No newline at end of file diff --git a/docs/api/core/onvif_operator.md b/docs/api/core/onvif_operator.md index c152f673..771399fb 100644 --- a/docs/api/core/onvif_operator.md +++ b/docs/api/core/onvif_operator.md @@ -4,4 +4,5 @@ options: show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 \ No newline at end of file diff --git a/docs/api/exceptions/onvif_error_handlers.md b/docs/api/exceptions/onvif_error_handlers.md index 818d27e9..00d18d56 100644 --- a/docs/api/exceptions/onvif_error_handlers.md +++ b/docs/api/exceptions/onvif_error_handlers.md @@ -4,4 +4,5 @@ options: show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 \ No newline at end of file diff --git a/docs/api/utilities/cache_mode.md b/docs/api/utilities/cache_mode.md index 6f791683..36702271 100644 --- a/docs/api/utilities/cache_mode.md +++ b/docs/api/utilities/cache_mode.md @@ -5,4 +5,5 @@ show_source: true docstring_style: google members: true - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 \ No newline at end of file diff --git a/docs/api/utilities/onvif_discovery.md b/docs/api/utilities/onvif_discovery.md index e94dffc2..ef8646d9 100644 --- a/docs/api/utilities/onvif_discovery.md +++ b/docs/api/utilities/onvif_discovery.md @@ -2,6 +2,10 @@ ::: onvif.utils.ONVIFDiscovery options: + docstring_options: + ignore_init_summary: true show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 + merge_init_into_class: true \ No newline at end of file diff --git a/docs/api/utilities/onvif_service.md b/docs/api/utilities/onvif_service.md index 74ebb3fb..18662bbe 100644 --- a/docs/api/utilities/onvif_service.md +++ b/docs/api/utilities/onvif_service.md @@ -4,4 +4,5 @@ options: show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 \ No newline at end of file diff --git a/docs/api/utilities/onvif_wsdl.md b/docs/api/utilities/onvif_wsdl.md index 5ece281c..38bd77be 100644 --- a/docs/api/utilities/onvif_wsdl.md +++ b/docs/api/utilities/onvif_wsdl.md @@ -4,4 +4,5 @@ options: show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 \ No newline at end of file diff --git a/docs/api/utilities/plugins.md b/docs/api/utilities/plugins.md index 00fe09fe..2cc54104 100644 --- a/docs/api/utilities/plugins.md +++ b/docs/api/utilities/plugins.md @@ -2,6 +2,9 @@ ::: onvif.utils.plugins options: + docstring_options: + ignore_init_summary: true show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + merge_init_into_class: true \ No newline at end of file diff --git a/docs/api/utilities/zeep_patcher.md b/docs/api/utilities/zeep_patcher.md index fec06266..cb7d07bc 100644 --- a/docs/api/utilities/zeep_patcher.md +++ b/docs/api/utilities/zeep_patcher.md @@ -4,4 +4,5 @@ options: show_source: true docstring_style: google - members_order: source \ No newline at end of file + members_order: source + heading_level: 3 \ No newline at end of file diff --git a/docs/philosophy.md b/docs/approach.md similarity index 100% rename from docs/philosophy.md rename to docs/approach.md diff --git a/docs/index.md b/docs/index.md index 7d3778ec..c77baa74 100644 --- a/docs/index.md +++ b/docs/index.md @@ -52,7 +52,7 @@ This library simplifies that process by wrapping SOAP communication into a clean -## Requirements +## Dependencies
diff --git a/docs/project/contributing.md b/docs/project/contributing.md index efc333fd..9f63aca0 100644 --- a/docs/project/contributing.md +++ b/docs/project/contributing.md @@ -38,72 +38,73 @@ If you can help translate documentation or error messages, let us know! ### Clone the repository and switch to dev branch - ```shell - # Option 1: Clone dev branch directly - git clone -b dev https://github.com/nirsimetri/onvif-python.git - cd onvif-python +```shell +# Option 1: Clone dev branch directly +git clone -b dev https://github.com/nirsimetri/onvif-python.git +cd onvif-python - # Option 2: Clone then switch to dev - git clone https://github.com/nirsimetri/onvif-python.git - cd onvif-python - git checkout dev - ``` +# Option 2: Clone then switch to dev +git clone https://github.com/nirsimetri/onvif-python.git +cd onvif-python +git checkout dev +``` + ### Install locally - ```shell - # Install the package in development mode - pip install -e . +```shell +# Install the package in development mode +pip install -e . - # Install development dependencies - # (pytest, pytest-cov, pylint, mypy, isort, docformatter, black) - pip install -e ".[dev]" - ``` - Or use `pyproject.toml` with your preferred tool (e.g., Poetry, pip). +# Install development dependencies +# (pytest, pytest-cov, pylint, mypy, isort, docformatter, black) +pip install -e ".[dev]" +``` +Or use `pyproject.toml` with your preferred tool (e.g., Poetry, pip). ### Run tests - ```shell - python -m pytest - ``` - Make sure all tests pass before submitting your changes. +```shell +python -m pytest +``` +Make sure all tests pass before submitting your changes. ### Generate coverage report - Coverage is optional for local development. To generate an XML coverage report: - ```shell - pytest --cov=onvif --cov-report=xml --cov-report=term-missing - ``` - This generates `coverage.xml`, which can be used by coverage analysis tools such as Codacy. +Coverage is optional for local development. To generate an XML coverage report: +```shell +pytest --cov=onvif --cov-report=xml --cov-report=term-missing +``` +This generates `coverage.xml`, which can be used by coverage analysis tools such as Codacy. ### Lint and format code - ```shell - # Check code linting with pylint - pylint . +```shell +# Check code linting with pylint +pylint . - # Check error with pylint - pylint . --errors-only --score=n +# Check error with pylint +pylint . --errors-only --score=n - # Static type checking - mypy . +# Static type checking +mypy . - # Sort import order - isort . +# Sort import order +isort . - # Spelling check - codespell . +# Spelling check +codespell . - # Format docstring with docformatter - docformatter --recursive --black --in-place . +# Format docstring with docformatter +docformatter --recursive --black --in-place . - # Format code with black - black . - ``` - Ensure your code follows PEP8 standards and is properly formatted. +# Format code with black +black . +``` +Ensure your code follows PEP8 standards and is properly formatted. ### Try example scripts - See the [`examples/`](https://github.com/nirsimetri/onvif-python/tree/dev/examples) folder for usage scenarios. +See the [`examples/`](https://github.com/nirsimetri/onvif-python/tree/dev/examples) folder for usage scenarios. ## Pull Request Guidelines @@ -214,21 +215,23 @@ The documentation source is located in the [`docs/`](https://github.com/nirsimet ```text docs/ ├── assets/ +├── hooks/ ├── javascripts/ ├── stylesheets/ ├── overrides/ ├── api/ -├── core/ +├── main/ ├── references/ ├── utilities/ ├── project/ ├── legal/ -├── hooks.py ├── index.md ├── installation.md ├── quick_start.md -├── philosophy.md -└── releases.md +├── approach.md +├── releases.md +├── llms.txt +└── robots.txt ``` API reference pages under [`docs/api/`](https://github.com/nirsimetri/onvif-python/tree/dev/docs/api) use `mkdocstrings` to generate documentation from the corresponding Python modules and classes. diff --git a/docs/project/roadmap.md b/docs/project/roadmap.md index d11776e3..44d46266 100644 --- a/docs/project/roadmap.md +++ b/docs/project/roadmap.md @@ -14,6 +14,6 @@ hide: - [x] Enhance documentation with API references and diagrams (not from [AI Wiki](https://deepwiki.com/nirsimetri/onvif-python)) ([`v0.3.1`](../releases.md/#v0.3.1)) - [ ] Add asynchronous (`async`/`await`) support for non-blocking operations - [ ] Implement structured data models for ONVIF Schemas using [xsdata](https://github.com/tefra/xsdata) -- [ ] Add more usage examples for advanced features -- [ ] Add benchmarking and performance metrics -- [ ] Add community-contributed device configuration templates \ No newline at end of file +- [ ] Implement operation tracking based on the device's ONVIF version +- [ ] Add automated comprehensive tests for ONVIF device capabilities +- [ ] Add benchmarking and performance metrics \ No newline at end of file diff --git a/docs/quick_start.md b/docs/quick_start.md index eb505d58..724d8138 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -12,7 +12,11 @@ Below are simple examples to help you get started with the ONVIF Python library. ### Discover ONVIF Devices -Use [`ONVIFDiscovery`](api/utilities/onvif_discovery.md) (applied from [`v0.1.6`](releases.md/#v0.1.6)) to automatically find ONVIF devices on your local network: + + + + +Use [`ONVIFDiscovery`](api/utilities/onvif_discovery.md) to automatically find ONVIF devices on your local network: ```python linenums="1" from onvif import ONVIFDiscovery @@ -85,6 +89,8 @@ media = client.media() # Media ### Get Device Information + + Retrieve basic information about the device, such as manufacturer, model, firmware version, and serial number using [`devicemgmt()`](api/services/device.md) service: ```python linenums="1" @@ -96,6 +102,8 @@ print(info) ### Get RTSP URL + + Retrieve the RTSP stream URL for live video streaming from the device using [`media()`](api/services/media.md) service: ```python linenums="1" diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index fd47d041..a151e7e5 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,13 +1,27 @@ [data-md-color-scheme="default"] { + /* Background */ --md-default-bg-color: #ebebeb; + + /* Primary */ --md-primary-fg-color: #003399; + --md-typeset-a-color: #003399; + + /* Accent */ + --md-accent-fg-color: #005fd3; + --md-accent-fg-color--transparent: rgba(0, 51, 153, 0.08); } [data-md-color-scheme="slate"] { + /* Primary */ --md-primary-fg-color: #002266; --md-typeset-a-color: #60a5fa; + + /* Accent */ + --md-accent-fg-color: #93c5fd; + --md-accent-fg-color--transparent: rgba(96, 165, 250, 0.12); } +/* Footer — Light */ [data-md-color-scheme="default"] .md-footer { background-color: #002266; } @@ -16,12 +30,13 @@ background-color: #003399; } +/* Footer — Dark */ [data-md-color-scheme="slate"] .md-footer { background-color: #030b1c; } [data-md-color-scheme="slate"] .md-footer-meta { - background-color: #1E2129; + background-color: #002266; } .md-footer-meta__inner { @@ -469,6 +484,16 @@ html { bottom: 1.5rem !important; } +[data-md-color-scheme="default"] .md-top:hover, +[data-md-color-scheme="default"] .md-top:focus { + color: #F5F5F5; +} + +[data-md-color-scheme="slate"] .md-top:hover, +[data-md-color-scheme="slate"] .md-top:focus { + color: #030b1c; +} + /* Flash section when scroll */ .section-flash-overlay { position: fixed; @@ -492,7 +517,7 @@ html { } .section-flash-overlay.is-visible { - animation: section-outline-flash 0.5s ease-in-out; + animation: section-outline-flash 0.6s ease-in-out; } /* Tooltip */ @@ -502,4 +527,58 @@ html { .md-tooltip { border-radius: 0.5rem; +} + +/* MDX Badge */ +.md-typeset .mdx-badge { + display: inline-flex; + align-items: stretch; + vertical-align: middle; + font-size: 0.85em; + line-height: 1; +} + +.md-typeset .mdx-badge--right { + float: right; + margin-left: 0.35em; +} + +.md-typeset .mdx-badge__icon, +.md-typeset .mdx-badge__text { + display: inline-flex; + align-items: center; + box-sizing: border-box; + padding: 0.25rem 0.35rem; +} + +.md-typeset .mdx-badge__icon { + justify-content: center; + color: var(--md-typeset-a-color); + background: var(--md-accent-fg-color--transparent); + border-start-start-radius: 0.25rem; + border-end-start-radius: 0.25rem; +} + +.md-typeset .mdx-badge__icon:last-child { + border-radius: 0.25rem; +} + +.md-typeset .mdx-badge__icon .twemoji { + display: inline-flex; + align-items: center; + justify-content: center; +} + +.md-typeset .mdx-badge__icon svg { + display: block; + width: 1em; + height: 1em; +} + +.md-typeset .mdx-badge__text { + color: var(--md-typeset-a-color); + border-start-end-radius: 0.25rem; + border-end-end-radius: 0.25rem; + box-shadow: 0 0 0 1px inset + var(--md-accent-fg-color--transparent); } \ No newline at end of file diff --git a/docs/utilities/helper_methods.md b/docs/utilities/helper_methods.md index ef587773..92f24d82 100644 --- a/docs/utilities/helper_methods.md +++ b/docs/utilities/helper_methods.md @@ -10,7 +10,11 @@ Every ONVIF service provides **four** essential helper methods to improve the de ### `type(type_name)` -Creates and returns an instance of the specified ONVIF type for building complex request parameters (applied from [`v0.1.9`](../releases.md/#v0.1.9)). + + + + +Creates and returns an instance of the specified ONVIF type for building complex request parameters. **Parameters:** @@ -59,7 +63,10 @@ device.SetSystemDateAndTime(time_params) ### `operations()` -Lists all available operations for the current service (applied from [`v0.2.0`](../releases.md/#v0.2.0)). + + + +Lists all available operations for the current service. **Returns:** @@ -93,7 +100,10 @@ if 'ContinuousMove' in ptz.operations(): ### `desc(method_name)` -Provides comprehensive documentation and parameter information for any ONVIF operation (applied from [`v0.2.0`](../releases.md/#v0.2.0)). + + + +Provides comprehensive documentation and parameter information for any ONVIF operation. **Parameters:** @@ -139,7 +149,11 @@ for method in methods[:5]: # Show first 5 methods ### `to_dict(zeep_object)` -Converts a Zeep object (`zeep.objects`) (the raw result returned from ONVIF operations) into a native Python dictionary that is easy to serialize, inspect, and manipulate (applied from [`v0.2.9`](../releases.md/#v0.2.9)). + + + + +Converts a Zeep object (`zeep.objects`) (the raw result returned from ONVIF operations) into a native Python dictionary that is easy to serialize, inspect, and manipulate. **Parameters:** From 73454fefaf529369e5c123d75a7c0e32f89790b1 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 00:29:49 +0700 Subject: [PATCH 31/38] feat(docs): Add hooks for Griffe extensions and miscellaneous functionality --- docs/hooks/griffe_extensions.py | 35 ++ docs/{hooks.py => hooks/misc.py} | 2 +- docs/hooks/shortcodes.py | 408 ++++++++++++++++++ docs/main/onvif_cli.md | 14 +- docs/main/onvif_client.md | 23 +- .../overrides/.icons/material/app-badging.svg | 1 + .../overrides/.icons/material/my-location.svg | 1 + docs/overrides/partials/comments.html | 55 +++ mkdocs.yml | 7 +- 9 files changed, 533 insertions(+), 13 deletions(-) create mode 100644 docs/hooks/griffe_extensions.py rename docs/{hooks.py => hooks/misc.py} (92%) create mode 100644 docs/hooks/shortcodes.py create mode 100644 docs/overrides/.icons/material/app-badging.svg create mode 100644 docs/overrides/.icons/material/my-location.svg create mode 100644 docs/overrides/partials/comments.html diff --git a/docs/hooks/griffe_extensions.py b/docs/hooks/griffe_extensions.py new file mode 100644 index 00000000..be2dc771 --- /dev/null +++ b/docs/hooks/griffe_extensions.py @@ -0,0 +1,35 @@ +"""Griffe extentions.""" + +from __future__ import annotations + +import importlib.util +from pathlib import Path + +import griffe + +_SHORTCODES_PATH = Path(__file__).with_name("shortcodes.py") +_SPEC = importlib.util.spec_from_file_location( + "onvif_doc_shortcodes", + _SHORTCODES_PATH, +) + +if _SPEC is None or _SPEC.loader is None: + raise ImportError(f"Cannot load shortcode module: {_SHORTCODES_PATH}") + +_SHORTCODES = importlib.util.module_from_spec(_SPEC) +_SPEC.loader.exec_module(_SHORTCODES) + +replace_docstring_shortcodes = _SHORTCODES.replace_docstring_shortcodes + + +class DocstringShortcodes(griffe.Extension): + """Process supported Markdown shortcodes in Python docstrings.""" + + def on_object(self, *, obj: griffe.Object, **kwargs) -> None: + """Replace shortcodes in an object's docstring.""" + docstring = obj.docstring + + if docstring is None: + return + + docstring.value = replace_docstring_shortcodes(docstring.value) diff --git a/docs/hooks.py b/docs/hooks/misc.py similarity index 92% rename from docs/hooks.py rename to docs/hooks/misc.py index 1aef365e..24def5ff 100644 --- a/docs/hooks.py +++ b/docs/hooks/misc.py @@ -1,4 +1,4 @@ -"""Mkdocs hooks.""" +"""Misc Mkdocs hooks.""" def on_page_content(html, page, config, files): # pylint: disable=unused-argument diff --git a/docs/hooks/shortcodes.py b/docs/hooks/shortcodes.py new file mode 100644 index 00000000..ac9b0a2d --- /dev/null +++ b/docs/hooks/shortcodes.py @@ -0,0 +1,408 @@ +"""Shortcodes hook. + +Origin source: +https://github.com/squidfunk/mkdocs-material/blob/master/src/overrides/hooks/shortcodes.py +""" + +# Copyright (c) 2016-2025 Martin Donath + +# Modified by Nirsimetri Technologies® for ONVIF Python documentation. + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# pylint: disable=unused-argument,redefined-builtin +# pylint: disable=unnecessary-lambda,too-many-branches +# pylint: disable=too-many-return-statements +from __future__ import annotations + +import posixpath +import re +from re import Match + +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.files import File, Files +from mkdocs.structure.pages import Page + +# ----------------------------------------------------------------------------- +# Constants +# ----------------------------------------------------------------------------- + +REPOSITORY = "https://github.com/nirsimetri/onvif-python" +RELEASE_ENDPOINT = "onvif-python/releases" +EXAMPLE_PATH = "blob/main/examples" +MODULE_PATH = "blob/main/onvif" + +ICON_FOR_VERSION = "material-source-pull" +ICON_FOR_ONVIF_VERSION = "material-app-badging" +ICON_FOR_INTERNAL = "material-lock-outline" +ICON_FOR_EXCEPTION = "material-alert-circle-outline" +ICON_FOR_ERROR_HANDLER = "material-reload-alert" +ICON_FOR_SERVICE_ENTRY_POINT = "material-my-location" +ICON_FOR_FEATURE = "material-toggle-switch" +ICON_FOR_PLUGIN = "material-puzzle-outline" +ICON_FOR_UTILITY = "material-hammer-wrench" +ICON_FOR_EXAMPLE_VIEW = "material-file-eye" +ICON_FOR_EXAMPLE_FILE = "material-file-code" +ICON_FOR_MODULE = "material-code-block-tags" +ICON_FOR_DEMO = "material-github" +ICON_FOR_DEFAULT_VALUE = "material-water" +ICON_FOR_DEFAULT_NONE = "material-water-outline" +ICON_FOR_DEFAULT_COMPUTED = "material-water-check" +ICON_FOR_METADATA = "material-list-box-outline" +ICON_FOR_REQUIRED = "material-alert" +ICON_FOR_EXPERIMENTAL = "material-flask-outline" + +# ----------------------------------------------------------------------------- +# For griffe +# ----------------------------------------------------------------------------- + + +def replace_docstring_shortcodes(docstring: str) -> str: + """Replace supported shortcodes in Python docstrings.""" + return re.sub( + r"", + lambda match: replace(match), + docstring, + flags=re.I | re.M, + ) + + +# ----------------------------------------------------------------------------- +# Hooks +# ----------------------------------------------------------------------------- + + +def on_page_markdown( + markdown: str, + *, + page: Page, + config: MkDocsConfig, + files: Files, +): + """Replace supported shortcodes in page Markdown.""" + return re.sub( + r"", + lambda match: replace(match, page, files), + markdown, + flags=re.I | re.M, + ) + + +# ----------------------------------------------------------------------------- +# Helper functions +# ----------------------------------------------------------------------------- + + +def replace(match: Match, page: Page | None = None, files: Files | None = None): + """Shortcodes replacer.""" + + type, args = match.groups() + args = args.strip() + + match type: + case "version": + return _badge_for_version(args, page, files) + case "onvif_version": + return _badge_for_onvif_version(args) + case "flag": + return flag(args, page, files) + case "option": + return option(args) + case "setting": + return setting(args) + case "internal": + return _badge_for_internal(args, page, files) + case "exception": + return _badge_for_exception(args, page, files) + case "error_handler": + return _badge_for_error_handler(args, page, files) + case "entry_point": + return _badge_for_entry_point(args, page, files) + case "feature": + return _badge_for_feature(args, page, files) + case "plugin": + return _badge_for_plugin(args, page, files) + case "utility": + return _badge_for_utility(args, page, files) + case "example": + return _badge_for_example(args, page, files) + case "example_view": + return _badge_for_example_view(args, page, files) + case "example_file": + return _badge_for_example_file(args, page, files) + case "module": + return _badge_for_module(args, page, files) + case "demo": + return _badge_for_demo(args, page, files) + case "default": + if args == "none": + return _badge_for_default_none(page, files) + if args == "computed": + return _badge_for_default_computed(page, files) + return _badge_for_default(args, page, files) + case _: + raise RuntimeError(f"Unknown shortcode: {type}") + + +def flag(args: str, page: Page, files: Files): + """Create a flag of a specific type.""" + type, *_ = args.split(" ", 1) + + match type: + case "experimental": + return _badge_for_experimental(page, files) + case "required": + return _badge_for_required(page, files) + case "metadata": + return _badge_for_metadata(page, files) + case _: + raise RuntimeError(f"Unknown type: {type}") + + +def option(type: str): + """Create a linkable option.""" + _, *_, name = re.split(r"[.:]", type) + return f"[`{name}`](#+{type}){{ #+{type} }}\n\n" + + +def setting(type: str): + """Create a linkable setting - @todo append them to the bottom of the page.""" + _, *_, name = re.split(r"[.*]", type) + return f"`{name}` {{ #{type} }}\n\n[{type}]: #{type}\n\n" + + +# ----------------------------------------------------------------------------- + + +def _resolve_path(path: str, page: Page, files: Files): + """Resolve path of file relative to given page - the posixpath always includes + one additional level of `..` which we need to remove.""" + path, anchor, *_ = f"{path}#".split("#") + path = _resolve(files.get_file_from_path(path), page) + return "#".join([path, anchor]) if anchor else path + + +def _resolve(file: File, page: Page): + """Resolve path of file relative to given page - the posixpath always includes + one additional level of `..` which we need to remove.""" + path = posixpath.relpath(file.src_uri, page.file.src_uri) + return posixpath.sep.join(path.split(posixpath.sep)[1:]) + + +# ----------------------------------------------------------------------------- + + +# Create badge +def _badge(icon: str, text: str = "", type: str = "", title: str = ""): + classes = f"mdx-badge mdx-badge--{type}" if type else "mdx-badge" + + return "".join( + [ + f'', + *( + [f'{icon}'] + if icon + else [] + ), + *([f'{text}'] if text else []), + "", + ] + ) + + +# Create badge for pacakge version +def _badge_for_version(text: str, page: Page | None = None, files: Files | None = None): + path = f"releases.md#v{text}" + + if page is not None and files is not None: + href = _resolve_path(path, page, files) + else: + href = f"/{RELEASE_ENDPOINT}/#v{text}" + + return _badge( + icon=f":{ICON_FOR_VERSION}:", + text=f"[`v{text}`]({href})" if text else "", + title="Minimum package version", + ) + + +# Create badge for ONVIF version +def _badge_for_onvif_version(args: str): + """Create a badge linking an ONVIF version to its specification.""" + match = re.fullmatch(r"(\S+)\s+(https?://\S+)", args.strip()) + + if not match: + raise ValueError("Invalid onvif_version shortcode. " "Expected: VERSION URL") + + version, href = match.groups() + + return _badge( + icon=f":{ICON_FOR_ONVIF_VERSION}:", + text=f"[`{version}`]({href})", + title="Minimum ONVIF version", + ) + + +# Create badge for internal +def _badge_for_internal(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_INTERNAL}:", + title=text or "Internal implementation", + text=f"*{text}*" if text else "", + ) + + +# Create badge for exception +def _badge_for_exception(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_EXCEPTION}:", + title=text or "Exception type", + text=f"*{text}*" if text else "", + ) + + +# Create badge for error handler +def _badge_for_error_handler(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_ERROR_HANDLER}:", + title=text or "Error handler", + text=f"*{text}*" if text else "", + ) + + +# Create badge for entry point +def _badge_for_entry_point(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_SERVICE_ENTRY_POINT}:", + title=text or "ONVIF Service entry point", + text=f"*{text}*" if text else "", + ) + + +# Create badge for feature +def _badge_for_feature(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_FEATURE}:", + title=text or "Optional feature", + text=f"*{text}*" if text else "", + ) + + +# Create badge for plugin +def _badge_for_plugin(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_PLUGIN}:", + title=text or "Plugin", + text=f"*{text}*" if text else "", + ) + + +# Create badge for utility +def _badge_for_utility(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_UTILITY}:", + title=text or "Utility", + text=f"*{text}*" if text else "", + ) + + +# Create badge for example +def _badge_for_example(text: str, page: Page, files: Files): + return "\n".join( + [ + _badge_for_example_file(text, page, files), + _badge_for_example_view(text, page, files), + ] + ) + + +# Create badge for example view +def _badge_for_example_view(text: str, page: Page, files: Files): + href = f"{REPOSITORY}/{EXAMPLE_PATH}/{text}" + return _badge( + icon=f"[:{ICON_FOR_EXAMPLE_VIEW}:]({href}){{.no-external-icon }}", + title=f"View example `{text}`", + type="right", + ) + + +# Create badge for example download +def _badge_for_example_file(text: str, page: Page, files: Files): + href = f"{REPOSITORY}/{EXAMPLE_PATH}/{text}" + return _badge( + icon=f"[:{ICON_FOR_EXAMPLE_FILE}:]({href}){{.no-external-icon }}", + title="Inspect example file", + text=f"[`{text}`]({href})", + type="right", + ) + + +# Create badge for module +def _badge_for_module(text: str, page: Page, files: Files): + href = f"{REPOSITORY}/{MODULE_PATH}/{text}" + return _badge( + icon=f"[:{ICON_FOR_MODULE}:]({href}){{.no-external-icon }}", + title=f"Inspect module `{text}`", + type="right", + ) + + +# Create badge for demo repository +def _badge_for_demo(text: str, page: Page, files: Files): + href = text + return _badge( + icon=f"[:{ICON_FOR_DEMO}:]({href})", + title="Go to repository", + text=f"*{text}*" if text else "", + type="right", + ) + + +# Create badge for default value +def _badge_for_default(text: str, page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_DEFAULT_VALUE}:", title=text or "Default value", text=text + ) + + +# Create badge for empty default value +def _badge_for_default_none(page: Page, files: Files): + return _badge(icon=f":{ICON_FOR_DEFAULT_NONE}:", title="Default value is empty") + + +# Create badge for computed default value +def _badge_for_default_computed(page: Page, files: Files): + return _badge( + icon=f":{ICON_FOR_DEFAULT_COMPUTED}:", title="Default value is computed" + ) + + +# Create badge for metadata property flag +def _badge_for_metadata(page: Page, files: Files): + return _badge(icon=f":{ICON_FOR_METADATA}:", title="Metadata property") + + +# Create badge for required value flag +def _badge_for_required(page: Page, files: Files): + return _badge(icon=f":{ICON_FOR_REQUIRED}:", title="Required value") + + +# Create badge for experimental flag +def _badge_for_experimental(page: Page, files: Files): + return _badge(icon=f":{ICON_FOR_EXPERIMENTAL}:", title="Experimental") diff --git a/docs/main/onvif_cli.md b/docs/main/onvif_cli.md index e942ce67..cd269a96 100644 --- a/docs/main/onvif_cli.md +++ b/docs/main/onvif_cli.md @@ -1,8 +1,12 @@ --- hide: - path +comments: true --- + + + ![Windows](https://img.shields.io/badge/Windows-0078D6?style=plastic&logo=gitforwindows&logoColor=white) ![Linux](https://img.shields.io/badge/Linux-FCC624?style=plastic&logo=linux&logoColor=black) ![macOS](https://img.shields.io/badge/macOS-1A9FEE?style=plastic&logo=apple&logoColor=white) @@ -12,8 +16,6 @@ This library includes a powerful command-line interface (CLI) for interacting wi !!! info The CLI is automatically installed when you install the `onvif-python` see [Installation](../installation.md). - - This feature has been available since `onvif-python` version [`0.1.1`](../releases.md/#v0.1.1). ## Features @@ -269,7 +271,9 @@ This feature is particularly useful for: ### Device Discovery -The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol with [`ONVIFDiscovery`](../api/utilities/onvif_discovery.md) class. This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand (applied from [`v0.1.2`](../releases.md/#v0.1.2)). + + +The CLI includes automatic ONVIF device discovery using the WS-Discovery protocol with [`ONVIFDiscovery`](../api/utilities/onvif_discovery.md) class (since [`v0.1.6`](../releases.md/#v0.1.6)). This feature allows you to find all ONVIF-compliant devices on your local network without knowing their IP addresses beforehand. !!! danger - Discovery only works on the local network (same subnet) @@ -372,7 +376,9 @@ onvif media GetProfiles -H 192.168.1.17 -P 8000 -u admin -p password -o profiles ### ONVIF Product Search -The CLI includes a built-in database of ONVIF-compliant products that can be searched to help identify and research devices before connecting (applied from [`v0.2.0`](../releases.md/#v0.2.0)). + + +The CLI includes a built-in database of ONVIF-compliant products that can be searched to help identify and research devices before connecting. #### Basic Search ```shell diff --git a/docs/main/onvif_client.md b/docs/main/onvif_client.md index 8fa63e25..dde80048 100644 --- a/docs/main/onvif_client.md +++ b/docs/main/onvif_client.md @@ -23,7 +23,7 @@ The [`ONVIFClient`](../api/core/onvif_client.md) class provides various configur ### Connection Parameters | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| -| `http_digest` | `str` | ❌ No | `False` | `True` = use HTTP Digest / `False` = use WS-UsernameToken (HTTP Digest support from [`v0.3.0`](../releases.md/#v0.3.0))[^1] | +| `http_digest`

| `str` | ❌ No | `False` | `True` = use HTTP Digest / `False` = use WS-UsernameToken[^1] | | `timeout` | `int` | ❌ No | `10` | Connection timeout in seconds for SOAP requests | | `use_https` | `bool` | ❌ No | `False` | Use HTTPS instead of HTTP for secure communication | | `verify_ssl` | `bool` | ❌ No | `False` | Verify SSL certificates when using HTTPS (set to `False` for self-signed certificates) | @@ -38,10 +38,10 @@ The [`ONVIFClient`](../api/core/onvif_client.md) class provides various configur | Name | Type | Required | Default | Description | |------|------|----------|---------|-------------| -| `apply_patch` | `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening (applied from [`v0.0.4`](../releases.md/#v0.0.4))[^2] | -| `capture_xml` | `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses (applied from [`v0.0.6`](../releases.md/#v0.0.6))[^3] | -| `wsdl_dir` | `str ⏐ None` | ❌ No | `None` | Custom WSDL directory path for using external WSDL files instead of built-in ones (e.g., `/path/to/custom/wsdl`) (applied from [`v0.1.0`](../releases.md/#v0.1.0))[^4] | -| `plugins` | `list[Plugin]` | ❌ No | `None` | List of user-provided Zeep plugins (`zeep.plugins`) (applied from [`v0.2.2`](../releases.md/#v0.2.2))[^5] | +| `apply_patch`

| `bool` | ❌ No | `True` | Enable zeep patching for better `xsd:any` field parsing and automatic flattening[^2] | +| `capture_xml`

| `bool` | ❌ No | `False` | Enable XML capture plugin for debugging SOAP requests/responses[^3] | +| `wsdl_dir`

| `str ⏐ None` | ❌ No | `None` | Custom WSDL directory path for using external WSDL files instead of built-in ones (e.g., `/path/to/custom/wsdl`)[^4] | +| `plugins`

| `list[Plugin]` | ❌ No | `None` | List of user-provided Zeep plugins (`zeep.Plugin`)[^5] | ### Cache Modes @@ -77,7 +77,9 @@ client = ONVIFClient( #### Use HTTP Digest Authentication -Set `http_digest` to `True`. This `http_digest` parameter available since [`v0.3.0`](../releases.md/#v0.3.0). + + +Set `http_digest` to `True`. ```python linenums="1" from onvif import ONVIFClient @@ -122,6 +124,9 @@ client = ONVIFClient( ``` #### No Caching and No Zeep Patching (Testing) + + + ```python linenums="1" from onvif import ONVIFClient, CacheMode @@ -137,6 +142,9 @@ client = ONVIFClient( ``` #### Debugging Mode (XML Capture) + + + ```python linenums="1" from onvif import ONVIFClient @@ -184,6 +192,9 @@ if client.xml_plugin: To view all available methods and attributes, please refer to [`XMLCapturePlugin`](../api/utilities/plugins.md#onvif.utils.plugins.XMLCapturePlugin). #### Custom WSDL Directory + + + ```python linenums="1" from onvif import ONVIFClient diff --git a/docs/overrides/.icons/material/app-badging.svg b/docs/overrides/.icons/material/app-badging.svg new file mode 100644 index 00000000..25e99334 --- /dev/null +++ b/docs/overrides/.icons/material/app-badging.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/.icons/material/my-location.svg b/docs/overrides/.icons/material/my-location.svg new file mode 100644 index 00000000..f7c94877 --- /dev/null +++ b/docs/overrides/.icons/material/my-location.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/partials/comments.html b/docs/overrides/partials/comments.html new file mode 100644 index 00000000..00648367 --- /dev/null +++ b/docs/overrides/partials/comments.html @@ -0,0 +1,55 @@ +{% if page.meta.comments %} +

{{ lang.t("meta.comments") }}

+ + + + +{% endif %} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 09992842..eab72122 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -76,9 +76,9 @@ theme: nav: - Home: index.md - Getting Started: - - Philosophy: philosophy.md - Installation: installation.md - Quickstart: quick_start.md + - Approach: approach.md - Usage: - Client: main/onvif_client.md - CLI: main/onvif_cli.md @@ -198,6 +198,8 @@ plugins: show_signature_annotations: true show_symbol_type_toc: true show_symbol_type_heading: true + extensions: + - docs/hooks/griffe_extensions.py:DocstringShortcodes markdown_extensions: - abbr @@ -268,7 +270,8 @@ extra_javascript: - javascripts/extra.js hooks: - - docs/hooks.py + - docs/hooks/misc.py + - docs/hooks/shortcodes.py copyright: >- © 2025 - 2026  
Nirsimetri Technologies® \ No newline at end of file From c775a991c54b7fd29db709f7700de07daf45d7d0 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 00:59:55 +0700 Subject: [PATCH 32/38] fix(docs): Fix shortcodes --- docs/hooks/shortcodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hooks/shortcodes.py b/docs/hooks/shortcodes.py index ac9b0a2d..18a36d0e 100644 --- a/docs/hooks/shortcodes.py +++ b/docs/hooks/shortcodes.py @@ -248,7 +248,7 @@ def _badge_for_onvif_version(args: str): match = re.fullmatch(r"(\S+)\s+(https?://\S+)", args.strip()) if not match: - raise ValueError("Invalid onvif_version shortcode. " "Expected: VERSION URL") + raise ValueError("Invalid onvif_version shortcode. Expected: VERSION URL") version, href = match.groups() From b49de9b083ee30b721a8750d6e986c5333820db8 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 01:00:54 +0700 Subject: [PATCH 33/38] docs: Enhance ONVIF module documentation and versioning --- onvif/client.py | 239 +++++++++--- onvif/operator.py | 41 +- onvif/services/accesscontrol.py | 8 +- onvif/services/accessrules.py | 8 +- onvif/services/actionengine.py | 8 +- onvif/services/analytics/analytics.py | 9 +- onvif/services/analytics/ruleengine.py | 8 +- onvif/services/analyticsdevice.py | 12 +- onvif/services/appmgmt.py | 8 +- onvif/services/authenticationbehavior.py | 8 +- onvif/services/credential.py | 8 +- onvif/services/deviceio.py | 8 +- onvif/services/devicemgmt.py | 39 +- onvif/services/display.py | 8 +- onvif/services/doorcontrol.py | 8 +- onvif/services/events/events.py | 9 +- onvif/services/events/notification.py | 6 +- .../services/events/pausable_subscription.py | 9 +- onvif/services/events/pullpoint.py | 8 +- onvif/services/events/subscription.py | 6 +- onvif/services/imaging.py | 9 +- onvif/services/media.py | 9 +- onvif/services/media2.py | 42 +- onvif/services/provisioning.py | 8 +- onvif/services/ptz.py | 9 +- onvif/services/receiver.py | 8 +- onvif/services/recording.py | 28 +- onvif/services/replay.py | 8 +- onvif/services/schedule.py | 8 +- onvif/services/search.py | 34 +- onvif/services/security/advancedsecurity.py | 8 +- .../services/security/authorizationserver.py | 8 +- onvif/services/security/dot1x.py | 8 +- onvif/services/security/jwt.py | 8 +- onvif/services/security/keystore.py | 8 +- onvif/services/security/mediasigning.py | 8 +- onvif/services/security/tlsserver.py | 8 +- onvif/services/thermal.py | 8 +- onvif/services/uplink.py | 8 +- onvif/utils/discovery.py | 26 +- onvif/utils/error_handlers.py | 24 +- onvif/utils/exceptions.py | 9 +- onvif/utils/plugins.py | 368 ++++++++++-------- onvif/utils/service.py | 62 +-- onvif/utils/wsdl.py | 46 ++- onvif/utils/zeep.py | 43 +- 46 files changed, 836 insertions(+), 435 deletions(-) diff --git a/onvif/client.py b/onvif/client.py index 54a4e085..8468a88b 100644 --- a/onvif/client.py +++ b/onvif/client.py @@ -1,3 +1,4 @@ +# pylint: disable=too-many-lines """High-level ONVIF client for interacting with ONVIF-compliant devices.""" from __future__ import annotations @@ -104,7 +105,10 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: class ONVIFClient: - """High-level ONVIF client for interacting with ONVIF-compliant devices. + """ + + + High-level ONVIF client for interacting with ONVIF-compliant devices. This is the main class for interacting with ONVIF devices. It provides access to all ONVIF services including Device Management, Media, PTZ, Events, Analytics, and more. @@ -113,14 +117,15 @@ class ONVIFClient: or `GetCapabilities`, and provides lazy initialization for service endpoints. Attributes: - services (list): List of available services from `GetServices` response - capabilities (CompoundValue): Device capabilities from `GetCapabilities` response (fallback) - xml_plugin (XMLCapturePlugin): XML capture plugin for debugging (if `capture_xml=True`) + services (list | None): List of available services from `GetServices` response + capabilities (CompoundValue | None): Device capabilities from `GetCapabilities` + response (fallback) + xml_plugin (XMLCapturePlugin | None): XML capture plugin for debugging + (if `capture_xml=True`) wsdl_dir (str | None): Custom WSDL directory path (if provided) plugins (list[Plugin] | None): List of user-provided Zeep plugins (if any) !!! tip "Version History" - - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - Added in [`v0.0.6`](/onvif-python/releases/#v0.0.6): `xml_plugin` - Added in [`v0.1.0`](/onvif-python/releases/#v0.1.0): `wsdl_dir` - Added in [`v0.4.3`](/onvif-python/releases/#v0.4.3): `plugins` @@ -157,7 +162,7 @@ def __init__( apply_patch (bool): Whether to apply ``xsd:any`` flattening patch capture_xml (bool): Whether to use XML capture plugin for debugging SOAP requests/responses wsdl_dir (str | None): Custom WSDL directory path for using external WSDL files instead of built-in ones - plugins (list[Plugin] | None): List of user-provided Zeep plugins (zeep.plugins) + plugins (list[Plugin] | None): List of user-provided Zeep plugins (`zeep.Plugin`) !!! tip "Version History" - Added in [`v0.0.4`](/onvif-python/releases/#v0.0.4): `apply_patch` @@ -484,7 +489,11 @@ def _configure_plugins( @service def devicemgmt(self) -> Device: - """Access the Device Management service.""" + """ + + + + Access the Device Management service.""" if self._devicemgmt is None: logger.debug("Initializing Device Management service") self._devicemgmt = Device(**self.common_args) @@ -552,7 +561,11 @@ def _get_subscription_service( @service def events(self) -> Events: - """Access the Events service.""" + """ + + + + Access the Events service.""" if self._events is None: logger.debug("Initializing Events service") self._events = Events( @@ -562,7 +575,11 @@ def events(self) -> Events: @service def pullpoint(self, SubscriptionRef) -> PullPoint: - """Access the PullPoint service.""" + """ + + + + Access the PullPoint service.""" logger.debug("Initializing PullPoint service") return self._get_subscription_service( SubscriptionRef, @@ -572,7 +589,11 @@ def pullpoint(self, SubscriptionRef) -> PullPoint: @service def notification(self) -> Notification: - """Access the Notification service.""" + """ + + + + Access the Notification service.""" if self._notification is None: logger.debug("Initializing Notification service") self._notification = Notification( @@ -582,7 +603,11 @@ def notification(self) -> Notification: @service def subscription(self, SubscriptionRef) -> Subscription: - """Access the Subscription service.""" + """ + + + + Access the Subscription service.""" logger.debug("Initializing Subscription service") return self._get_subscription_service( SubscriptionRef, @@ -593,10 +618,10 @@ def subscription(self, SubscriptionRef) -> Subscription: @service def pausable_subscription(self, SubscriptionRef) -> PausableSubscription: """ - Access the PausableSubscription service. + + - !!! tip "Version History" - - Available since [`v0.2.4`](/onvif-python/releases/#v0.2.4) + Access the PausableSubscription service. """ logger.debug("Initializing PausableSubscription service") return self._get_subscription_service( @@ -609,7 +634,11 @@ def pausable_subscription(self, SubscriptionRef) -> PausableSubscription: @service def imaging(self) -> Imaging: - """Access the Imaging service.""" + """ + + + + Access the Imaging service.""" if self._imaging is None: logger.debug("Initializing Imaging service") self._imaging = Imaging( @@ -621,7 +650,11 @@ def imaging(self) -> Imaging: @service def media(self) -> Media: - """Access the Media service.""" + """ + + + + Access the Media service.""" if self._media is None: logger.debug("Initializing Media service") self._media = Media( @@ -631,7 +664,11 @@ def media(self) -> Media: @service def media2(self) -> Media2: - """Access the Media2 service.""" + """ + + + + Access the Media2 service.""" if self._media2 is None: logger.debug("Initializing Media2 service") self._media2 = Media2( @@ -643,7 +680,11 @@ def media2(self) -> Media2: @service def ptz(self) -> PTZ: - """Access the PTZ service.""" + """ + + + + Access the PTZ service.""" if self._ptz is None: logger.debug("Initializing PTZ service") self._ptz = PTZ(xaddr=self._get_xaddr("ptz", "PTZ"), **self.common_args) @@ -653,7 +694,11 @@ def ptz(self) -> PTZ: @service def deviceio(self) -> DeviceIO: - """Access the DeviceIO service.""" + """ + + + + Access the DeviceIO service.""" if self._deviceio is None: logger.debug("Initializing DeviceIO service") self._deviceio = DeviceIO( @@ -665,7 +710,11 @@ def deviceio(self) -> DeviceIO: @service def display(self) -> Display: - """Access the Display service.""" + """ + + + + Access the Display service.""" if self._display is None: logger.debug("Initializing Display service") self._display = Display( @@ -677,7 +726,11 @@ def display(self) -> Display: @service def analytics(self) -> Analytics: - """Access the Analytics service.""" + """ + + + + Access the Analytics service.""" if self._analytics is None: logger.debug("Initializing Analytics service") self._analytics = Analytics( @@ -687,7 +740,11 @@ def analytics(self) -> Analytics: @service def ruleengine(self) -> RuleEngine: - """Access the RuleEngine service.""" + """ + + + + Access the RuleEngine service.""" if self._ruleengine is None: logger.debug("Initializing RuleEngine service") self._ruleengine = RuleEngine( @@ -697,7 +754,11 @@ def ruleengine(self) -> RuleEngine: @service def analyticsdevice(self) -> AnalyticsDevice: - """Access the AnalyticsDevice service.""" + """ + + + + Access the AnalyticsDevice service.""" if self._analyticsdevice is None: logger.debug("Initializing AnalyticsDevice service") self._analyticsdevice = AnalyticsDevice( @@ -710,7 +771,11 @@ def analyticsdevice(self) -> AnalyticsDevice: @service def accesscontrol(self) -> AccessControl: - """Access the AccessControl service.""" + """ + + + + Access the AccessControl service.""" if self._accesscontrol is None: logger.debug("Initializing AccessControl service") self._accesscontrol = AccessControl( @@ -721,7 +786,11 @@ def accesscontrol(self) -> AccessControl: @service def doorcontrol(self) -> DoorControl: - """Access the DoorControl service.""" + """ + + + + Access the DoorControl service.""" if self._doorcontrol is None: logger.debug("Initializing DoorControl service") self._doorcontrol = DoorControl( @@ -733,7 +802,11 @@ def doorcontrol(self) -> DoorControl: @service def accessrules(self) -> AccessRules: - """Access the AccessRules service.""" + """ + + + + Access the AccessRules service.""" if self._accessrules is None: logger.debug("Initializing AccessRules service") self._accessrules = AccessRules( @@ -745,7 +818,11 @@ def accessrules(self) -> AccessRules: @service def actionengine(self) -> ActionEngine: - """Access the ActionEngine service.""" + """ + + + + Access the ActionEngine service.""" if self._actionengine is None: logger.debug("Initializing ActionEngine service") self._actionengine = ActionEngine( @@ -758,7 +835,11 @@ def actionengine(self) -> ActionEngine: @service def appmanagement(self) -> AppManagement: - """Access the AppManagement service.""" + """ + + + + Access the AppManagement service.""" if self._appmanagement is None: logger.debug("Initializing AppManagement service") self._appmanagement = AppManagement( @@ -771,7 +852,11 @@ def appmanagement(self) -> AppManagement: @service def authenticationbehavior(self) -> AuthenticationBehavior: - """Access the AuthenticationBehavior service.""" + """ + + + + Access the AuthenticationBehavior service.""" if self._authenticationbehavior is None: logger.debug("Initializing AuthenticationBehavior service") self._authenticationbehavior = AuthenticationBehavior( @@ -786,7 +871,11 @@ def authenticationbehavior(self) -> AuthenticationBehavior: @service def credential(self) -> Credential: - """Access the Credential service.""" + """ + + + + Access the Credential service.""" if self._credential is None: logger.debug("Initializing Credential service") self._credential = Credential( @@ -799,7 +888,11 @@ def credential(self) -> Credential: @service def recording(self) -> Recording: - """Access the Recording service.""" + """ + + + + Access the Recording service.""" if self._recording is None: logger.debug("Initializing Recording service") self._recording = Recording( @@ -812,7 +905,11 @@ def recording(self) -> Recording: @service def replay(self) -> Replay: - """Access the Replay service.""" + """ + + + + Access the Replay service.""" if self._replay is None: logger.debug("Initializing Replay service") self._replay = Replay( @@ -825,7 +922,11 @@ def replay(self) -> Replay: @service def provisioning(self) -> Provisioning: - """Access the Provisioning service.""" + """ + + + + Access the Provisioning service.""" if self._provisioning is None: logger.debug("Initializing Provisioning service") self._provisioning = Provisioning( @@ -838,7 +939,11 @@ def provisioning(self) -> Provisioning: @service def receiver(self) -> Receiver: - """Access the Receiver service.""" + """ + + + + Access the Receiver service.""" if self._receiver is None: logger.debug("Initializing Receiver service") self._receiver = Receiver( @@ -851,7 +956,11 @@ def receiver(self) -> Receiver: @service def schedule(self) -> Schedule: - """Access the Schedule service.""" + """ + + + + Access the Schedule service.""" if self._schedule is None: logger.debug("Initializing Schedule service") self._schedule = Schedule( @@ -864,7 +973,11 @@ def schedule(self) -> Schedule: @service def search(self) -> Search: - """Access the Search service.""" + """ + + + + Access the Search service.""" if self._search is None: logger.debug("Initializing Search service") self._search = Search( @@ -877,7 +990,11 @@ def search(self) -> Search: @service def thermal(self) -> Thermal: - """Access the Thermal service.""" + """ + + + + Access the Thermal service.""" if self._thermal is None: logger.debug("Initializing Thermal service") self._thermal = Thermal( @@ -890,7 +1007,11 @@ def thermal(self) -> Thermal: @service def uplink(self) -> Uplink: - """Access the Uplink service.""" + """ + + + + Access the Uplink service.""" if self._uplink is None: logger.debug("Initializing Uplink service") self._uplink = Uplink( @@ -903,7 +1024,11 @@ def uplink(self) -> Uplink: @service def security(self) -> AdvancedSecurity: - """Access the AdvancedSecurity service.""" + """ + + + + Access the AdvancedSecurity service.""" if self._security is None: logger.debug("Initializing Security service") self._security = AdvancedSecurity( @@ -914,7 +1039,11 @@ def security(self) -> AdvancedSecurity: @service def jwt(self) -> JWT: - """Access the JWT service.""" + """ + + + + Access the JWT service.""" if self._jwt is None: logger.debug("Initializing JWT service") self._jwt = JWT( @@ -924,7 +1053,11 @@ def jwt(self) -> JWT: @service def keystore(self) -> Keystore: - """Access the Keystore service.""" + """ + + + + Access the Keystore service.""" if self._keystore is None: logger.debug("Initializing Keystore service") self._keystore = Keystore( @@ -934,7 +1067,11 @@ def keystore(self) -> Keystore: @service def tlsserver(self) -> TLSServer: - """Access the TLSServer service.""" + """ + + + + Access the TLSServer service.""" if self._tlsserver is None: logger.debug("Initializing TLSServer service") self._tlsserver = TLSServer( @@ -944,7 +1081,11 @@ def tlsserver(self) -> TLSServer: @service def dot1x(self) -> Dot1X: - """Access the Dot1X service.""" + """ + + + + Access the Dot1X service.""" if self._dot1x is None: logger.debug("Initializing Dot1X service") self._dot1x = Dot1X( @@ -954,7 +1095,11 @@ def dot1x(self) -> Dot1X: @service def authorizationserver(self) -> AuthorizationServer: - """Access the AuthorizationServer service.""" + """ + + + + Access the AuthorizationServer service.""" if self._authorizationserver is None: logger.debug("Initializing AuthorizationServer service") self._authorizationserver = AuthorizationServer( @@ -965,7 +1110,11 @@ def authorizationserver(self) -> AuthorizationServer: @service def mediasigning(self) -> MediaSigning: - """Access the MediaSigning service.""" + """ + + + + Access the MediaSigning service.""" if self._mediasigning is None: logger.debug("Initializing MediaSigning service") self._mediasigning = MediaSigning( diff --git a/onvif/operator.py b/onvif/operator.py index ef9d37a1..28ea6ed1 100644 --- a/onvif/operator.py +++ b/onvif/operator.py @@ -27,7 +27,11 @@ class CacheMode(Enum): - """WSDL caching strategies for ONVIF client performance optimization. + """ + + + + WSDL caching strategies for ONVIF client performance optimization. Different caching modes provide trade-offs between performance, memory usage, and disk storage. Choose based on the application's requirements. @@ -38,7 +42,6 @@ class CacheMode(Enum): DB (Literal['db']): Persistent SQLite caching across process restarts. !!! tip "Version History" - - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - Removed in [`v0.4.0`](/onvif-python/releases/#v0.4.0): `CacheMode.ALL` """ @@ -93,7 +96,11 @@ class CacheMode(Enum): class ONVIFOperator: - """Low-level ONVIF service operator using Zeep SOAP client. + """ + + + + Low-level ONVIF service operator using Zeep SOAP client. This class handles the actual SOAP communication with ONVIF devices. It manages WSDL loading, service binding, authentication, caching, and error handling. @@ -120,7 +127,6 @@ class ONVIFOperator: service_name (str): Name of the ONVIF service (e.g., "Device", "Media") !!! tip "Version History" - - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - No version tracking for attribute changes because this class is used internally """ @@ -267,15 +273,16 @@ def _create_wsse( ) def call(self, method: str, *args, **kwargs) -> Any: - """Call an ONVIF service operation. + """ + + + + Call an ONVIF service operation. This method invokes a SOAP operation on the ONVIF device service and handles errors gracefully. It automatically flattens `xsd:any` fields in the response when `apply_patch` is enabled. - !!! tip "Version History" - - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - Args: method (str): Name of the ONVIF operation to call (e.g., "GetDeviceInformation") *args (Any): Positional arguments to pass to the operation @@ -315,7 +322,11 @@ def legacy_call( *args, **kwargs, ) -> Any: - """Call a legacy ONVIF operation using the current WSDL definition. + """ + + + + Call a legacy ONVIF operation using the current WSDL definition. This provides compatibility with devices which implemented an older operation name that was subsequently renamed in the ONVIF WSDL. @@ -325,9 +336,6 @@ def legacy_call( and response definitions while overriding the operation name and SOAP action. - !!! tip "Version History" - - Available since [`v0.4.3`](/onvif-python/releases/#v0.4.3) - Args: legacy_method: Name of the legacy ONVIF operation current_method: Name of the operation defined by the current WSDL @@ -401,14 +409,15 @@ def legacy_call( ) from e def create_type(self, type_name: str) -> Any: - """Create a type instance from WSDL schema for the given type name. + """ + + + + Create a type instance from WSDL schema for the given type name. Recursively initializes nested complex types so that fields like TimeZone, DateTime, Date, and Time are properly instantiated as objects rather than None. - !!! tip "Version History" - - Available since [`v0.1.9`](/onvif-python/releases/#v0.1.9) - Args: type_name (str): Name of the type to create (e.g., 'SetHostname', 'SetIPAddressFilter') diff --git a/onvif/services/accesscontrol.py b/onvif/services/accesscontrol.py index 4ff5cd72..0733a444 100644 --- a/onvif/services/accesscontrol.py +++ b/onvif/services/accesscontrol.py @@ -6,11 +6,15 @@ class AccessControl(ONVIFService): - """AccessControl service client. + """ + + + + AccessControl service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.3 (May 2013) | + | **First introduced** | ONVIF 2.3 (May 2013) | | **Binding name** | `PACSBinding` (`ver10/pacs/accesscontrol.wsdl`) | | **Operations** | [accesscontrol.wsdl](https://www.onvif.org/ver10/pacs/accesscontrol.wsdl) | | **Spec** | [AccessControl](https://www.onvif.org/specs/srv/access/ONVIF-AccessControl-Service-Spec.pdf) | diff --git a/onvif/services/accessrules.py b/onvif/services/accessrules.py index 00f2a6c9..f257228f 100644 --- a/onvif/services/accessrules.py +++ b/onvif/services/accessrules.py @@ -6,11 +6,15 @@ class AccessRules(ONVIFService): - """AccessRules service client. + """ + + + + AccessRules service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.6 (June 2015) | + | **First introduced** | ONVIF 2.6 (June 2015) | | **Binding name** | `AccessRulesBinding` (`ver10/accessrules/wsdl/accessrules.wsdl`) | | **Operations** | [accessrules.wsdl](https://www.onvif.org/ver10/accessrules/wsdl/accessrules.wsdl) | | **Spec** | [AccessRules](https://www.onvif.org/specs/srv/access/ONVIF-AccessRules-Service-Spec.pdf) | diff --git a/onvif/services/actionengine.py b/onvif/services/actionengine.py index e5d9da3f..8bc60c30 100644 --- a/onvif/services/actionengine.py +++ b/onvif/services/actionengine.py @@ -6,11 +6,15 @@ class ActionEngine(ONVIFService): - """ActionEngine service client. + """ + + + + ActionEngine service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.2 (September 2012) | + | **First introduced** | ONVIF 2.2 (September 2012) | | **Binding name** | `ActionEngineBinding` (`ver10/actionengine.wsdl`) | | **Operations** | [actionengine.wsdl](https://www.onvif.org/ver10/actionengine.wsdl) | | **Spec** | [ActionEngine](https://www.onvif.org/specs/srv/act/ONVIF-ActionEngine-Service-Spec.pdf) | diff --git a/onvif/services/analytics/analytics.py b/onvif/services/analytics/analytics.py index 6253bbec..c545aaaa 100644 --- a/onvif/services/analytics/analytics.py +++ b/onvif/services/analytics/analytics.py @@ -6,11 +6,16 @@ class Analytics(ONVIFService): - """Analytics service client. + """ + + + + + Analytics service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.41 (December 2013) | + | **First introduced** | ONVIF 2.4 (August 2013) | | **Binding name** | `AnalyticsEngineBinding` (`ver20/analytics/wsdl/analytics.wsdl`) | | **Operations** | [analytics.wsdl](https://www.onvif.org/ver20/analytics/wsdl/analytics.wsdl) | | **Spec** | [Analytics](https://www.onvif.org/specs/srv/analytics/ONVIF-Analytics-Service-Spec.pdf) | diff --git a/onvif/services/analytics/ruleengine.py b/onvif/services/analytics/ruleengine.py index 3e44223a..9090a7ae 100644 --- a/onvif/services/analytics/ruleengine.py +++ b/onvif/services/analytics/ruleengine.py @@ -6,11 +6,15 @@ class RuleEngine(ONVIFService): - """Analytics (RuleEngine) service client. + """ + + + + Analytics (RuleEngine) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.41 (December 2013) | + | **First introduced** | ONVIF 2.4 (August 2013) | | **Binding name** | `RuleEngineBinding` (`ver20/analytics/wsdl/analytics.wsdl`) | | **Operations** | [analytics.wsdl](https://www.onvif.org/ver20/analytics/wsdl/analytics.wsdl) | | **Spec** | [Analytics](https://www.onvif.org/specs/srv/analytics/ONVIF-Analytics-Service-Spec.pdf) | diff --git a/onvif/services/analyticsdevice.py b/onvif/services/analyticsdevice.py index dbc2b84e..3d2f8a99 100644 --- a/onvif/services/analyticsdevice.py +++ b/onvif/services/analyticsdevice.py @@ -7,8 +7,12 @@ class AnalyticsDevice(ONVIFService): # pylint: disable=line-too-long - """The AnalyticsDevice service (AnalyticsDeviceBinding) aka 'Video Analytics Device' - has been marked as obsolete since ONVIF Release 18.12. + """ + + + + The AnalyticsDevice service (AnalyticsDeviceBinding) aka 'Video Analytics Device' + has been marked as obsolete since ONVIF 18.12. Its functionality has largely been merged into the Analytics service and, in some cases Media/Media2. @@ -22,8 +26,8 @@ class AnalyticsDevice(ONVIFService): | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | - | **Deprecated** | ONVIF Release 18.12 (December 2018) | + | **First introduced** | ONVIF 2.0 (November 2010) | + | **Deprecated** | ONVIF 18.12 (December 2018) | | **Binding name** | `AnalyticsDeviceBinding` (`ver10/analyticsdevice.wsdl`) | | **Successor** | `Analytics` Service (`ver20/analytics/wsdl/analytics.wsdl`) | | **Operations** | [analyticsdevice.wsdl](https://www.onvif.org/ver10/analyticsdevice.wsdl) | diff --git a/onvif/services/appmgmt.py b/onvif/services/appmgmt.py index b922baf2..53a040c3 100644 --- a/onvif/services/appmgmt.py +++ b/onvif/services/appmgmt.py @@ -6,11 +6,15 @@ class AppManagement(ONVIFService): - """AppManagement service client. + """ + + + + AppManagement service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 19.12 (December 2019) | + | **First introduced** | ONVIF 19.12 (December 2019) | | **Binding name** | `AppManagementBinding` (`ver10/appmgmt/wsdl/appmgmt.wsdl`) | | **Operations** | [appmgmt.wsdl](https://www.onvif.org/ver10/appmgmt/wsdl/appmgmt.wsdl) | | **Spec** | [AppMgmt](https://www.onvif.org/specs/srv/appmgmt/ONVIF-ApplicationManagement-Service-Spec.pdf) | diff --git a/onvif/services/authenticationbehavior.py b/onvif/services/authenticationbehavior.py index 4bcef227..bc41da76 100644 --- a/onvif/services/authenticationbehavior.py +++ b/onvif/services/authenticationbehavior.py @@ -7,11 +7,15 @@ class AuthenticationBehavior(ONVIFService): # pylint: disable=line-too-long - """AuthenticationBehavior service client. + """ + + + + AuthenticationBehavior service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 18.06 (June 2018) | + | **First introduced** | ONVIF 18.06 (June 2018) | | **Binding name** | `AuthenticationBehaviorBinding` (`ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl`) | | **Operations** | [authenticationbehavior.wsdl](https://www.onvif.org/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl) | | **Spec** | [AuthenticationBehavior](https://www.onvif.org/specs/srv/access/ONVIF-AuthenticationBehavior-Service-Spec.pdf) | diff --git a/onvif/services/credential.py b/onvif/services/credential.py index 051adbe8..5613b570 100644 --- a/onvif/services/credential.py +++ b/onvif/services/credential.py @@ -6,11 +6,15 @@ class Credential(ONVIFService): - """Credential service client. + """ + + + + Credential service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.6 (June 2015) | + | **First introduced** | ONVIF 2.6 (June 2015) | | **Binding name** | `CredentialBinding` (`ver10/credential/wsdl/credential.wsdl`) | | **Operations** | [credential.wsdl](https://www.onvif.org/ver10/credential/wsdl/credential.wsdl) | | **Spec** | [Credential](https://www.onvif.org/specs/srv/access/ONVIF-Credential-Service-Spec.pdf) | diff --git a/onvif/services/deviceio.py b/onvif/services/deviceio.py index ef8572f6..82774f92 100644 --- a/onvif/services/deviceio.py +++ b/onvif/services/deviceio.py @@ -6,11 +6,15 @@ class DeviceIO(ONVIFService): - """DeviceIO service client. + """ + + + + DeviceIO service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 2.0 (November 2010) | | **Binding name** | `DeviceIOBinding` (`ver10/deviceio.wsdl`) | | **Operations** | [deviceio.wsdl](https://www.onvif.org/ver10/deviceio.wsdl) | | **Spec** | [DeviceIO](https://www.onvif.org/specs/srv/io/ONVIF-DeviceIo-Service-Spec.pdf) | diff --git a/onvif/services/devicemgmt.py b/onvif/services/devicemgmt.py index 7e88f110..70fc7e8f 100644 --- a/onvif/services/devicemgmt.py +++ b/onvif/services/devicemgmt.py @@ -6,11 +6,16 @@ class Device(ONVIFService): - """Device service client. + """ + + + + + Device service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Core | + | **First introduced** | ONVIF 1.0 (November 2008) | | **Binding name** | `DeviceBinding` (`ver10/device/wsdl/devicemgmt.wsdl`) | | **Operations** | [devicemgmt.wsdl](https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl) | | **Spec** | [Core](https://www.onvif.org/specs/core/ONVIF-Core-Specification.pdf) | @@ -307,32 +312,32 @@ def SetRemoteUser(self, RemoteUser=None): return self.operator.call("SetRemoteUser", RemoteUser=RemoteUser) def GetUserRoles(self, UserRole=None): - """This operation returns the editable user levels configured in the device. + """ + + + This operation returns the editable user levels configured in the device. Whenever an editable user level is passed in the request, information only about that level is returned. - - !!! tip "Version History" - - Available since [`v0.2.7`](/onvif-python/releases/#v0.2.7) """ return self.operator.call("GetUserRoles", UserRole=UserRole) def SetUserRole(self, UserRole): - """This operation configures an editable user level in the device. + """ + + + This operation configures an editable user level in the device. If the level passed in UserRole already exists in the device, its configuration is overwritten. Otherwise, a new editable user level is created. - - !!! tip "Version History" - - Available since [`v0.2.7`](/onvif-python/releases/#v0.2.7) """ return self.operator.call("SetUserRole", UserRole=UserRole) def DeleteUserRole(self, UserRole): - """This operation deletes an editable user level in the device. + """ + - !!! tip "Version History" - - Available since [`v0.2.7`](/onvif-python/releases/#v0.2.7) + This operation deletes an editable user level in the device. """ return self.operator.call("DeleteUserRole", UserRole=UserRole) @@ -890,7 +895,10 @@ def StartFirmwareUpgrade(self): return self.operator.call("StartFirmwareUpgrade") def UpgradeFirmware(self, Version): - """This operation initiates a firmware upgrade using between the device and the + """ + + + This operation initiates a firmware upgrade using between the device and the MCS, without further actions from the client. Cloud firmware upgrade may be achieved using the following steps: @@ -906,9 +914,6 @@ def UpgradeFirmware(self, Version): as all the parameters of the Uplink and Security service unchanged, so that it can connect to the cloud. Additionally a firmware upgrade shall not change user credentials. - - !!! tip "Version History" - - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) """ return self.operator.call("UpgradeFirmware", Version=Version) diff --git a/onvif/services/display.py b/onvif/services/display.py index 22d644cd..1abfe5c7 100644 --- a/onvif/services/display.py +++ b/onvif/services/display.py @@ -6,11 +6,15 @@ class Display(ONVIFService): - """Display service client. + """ + + + + Display service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 2.0 (November 2010) | | **Binding name** | `DisplayBinding` (`ver10/display.wsdl`) | | **Operations** | [display.wsdl](https://www.onvif.org/ver10/display.wsdl) | | **Spec** | [Display](https://www.onvif.org/specs/srv/disp/ONVIF-Display-Service-Spec.pdf) | diff --git a/onvif/services/doorcontrol.py b/onvif/services/doorcontrol.py index 3f13af43..f9ee0813 100644 --- a/onvif/services/doorcontrol.py +++ b/onvif/services/doorcontrol.py @@ -6,11 +6,15 @@ class DoorControl(ONVIFService): - """DoorControl service client. + """ + + + + DoorControl service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.3 (May 2013) | + | **First introduced** | ONVIF 2.3 (May 2013) | | **Binding name** | `DoorControlBinding` (`ver10/pacs/doorcontrol.wsdl`) | | **Operations** | [doorcontrol.wsdl](https://www.onvif.org/ver10/pacs/doorcontrol.wsdl) | | **Spec** | [DoorControl](https://www.onvif.org/specs/srv/door/ONVIF-DoorControl-Service-Spec.pdf) | diff --git a/onvif/services/events/events.py b/onvif/services/events/events.py index 4415a9c2..a6f5594f 100644 --- a/onvif/services/events/events.py +++ b/onvif/services/events/events.py @@ -6,11 +6,16 @@ class Events(ONVIFService): - """Events service client. + """ + + + + + Events service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Core | + | **First introduced** | ONVIF 1.0 (November 2008) | | **Binding name** | `EventBinding` (`ver10/events/wsdl/event-vs.wsdl`) | | **Operations** | [event-vs.wsdl](https://www.onvif.org/ver10/events/wsdl/event-vs.wsdl) | | **Spec** | [Core](https://www.onvif.org/specs/core/ONVIF-Core-Specification.pdf) | diff --git a/onvif/services/events/notification.py b/onvif/services/events/notification.py index 8e185d81..8e033ac8 100644 --- a/onvif/services/events/notification.py +++ b/onvif/services/events/notification.py @@ -6,7 +6,11 @@ class Notification(ONVIFService): - """WS-BaseNotification NotificationProducer service client. + """ + + + + WS-BaseNotification NotificationProducer service client. This service provides access to the NotificationProducer interface used by ONVIF devices for push-based event notification subscriptions. diff --git a/onvif/services/events/pausable_subscription.py b/onvif/services/events/pausable_subscription.py index 26026388..f000ae53 100644 --- a/onvif/services/events/pausable_subscription.py +++ b/onvif/services/events/pausable_subscription.py @@ -6,7 +6,11 @@ class PausableSubscription(ONVIFService): - """WS-BaseNotification PausableSubscriptionManager service client. + """ + + + + WS-BaseNotification PausableSubscriptionManager service client. This interface extends the Base Subscription Manager with operations for temporarily pausing and resuming notification delivery. @@ -19,9 +23,6 @@ class PausableSubscription(ONVIFService): | **See** | ONVIF Core Spec, OASIS WS-BaseNotification Spec | | **Binding name** | `PausableSubscriptionManagerBinding` (`ver10/events/wsdl/event-vs.wsdl`) | | **Spec** | [PausableSubscription](https://docs.oasis-open.org/wsn/wsn-ws_base_notification-1.3-spec-os.htm#_Toc133735641) | - - !!! tip "Version History" - - Available since [`v0.2.4`](/onvif-python/releases/#v0.2.4) """ def __init__(self, xaddr=None, **kwargs): diff --git a/onvif/services/events/pullpoint.py b/onvif/services/events/pullpoint.py index 4ad140e5..d4243959 100644 --- a/onvif/services/events/pullpoint.py +++ b/onvif/services/events/pullpoint.py @@ -6,11 +6,15 @@ class PullPoint(ONVIFService): - """Events (PullPoint) service client. + """ + + + + Events (PullPoint) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Core | + | **First introduced** | ONVIF 1.0 (November 2008) | | **Binding name** | `PullPointSubscriptionBinding` (`ver10/events/wsdl/event-vs.wsdl`) | | **Operations** | [event-vs.wsdl](https://www.onvif.org/ver10/events/wsdl/event-vs.wsdl) | | **Spec** | [Core](https://www.onvif.org/specs/core/ONVIF-Core-Specification.pdf) | diff --git a/onvif/services/events/subscription.py b/onvif/services/events/subscription.py index 46a68dd3..2104a5e3 100644 --- a/onvif/services/events/subscription.py +++ b/onvif/services/events/subscription.py @@ -6,7 +6,11 @@ class Subscription(ONVIFService): - """WS-BaseNotification SubscriptionManager service client. + """ + + + + WS-BaseNotification SubscriptionManager service client. This interface manages the lifecycle of a notification subscription created through the WS-BaseNotification NotificationProducer interface. diff --git a/onvif/services/imaging.py b/onvif/services/imaging.py index 08de4df5..cf686ff9 100644 --- a/onvif/services/imaging.py +++ b/onvif/services/imaging.py @@ -6,11 +6,16 @@ class Imaging(ONVIFService): - """Imaging service client. + """ + + + + + Imaging service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 1.0 (November 2008) | | **Binding name** | `ImagingBinding` (`ver20/imaging/wsdl/imaging.wsdl`) | | **Operations** | [imaging.wsdl](https://www.onvif.org/ver20/imaging/wsdl/imaging.wsdl) | | **Spec** | [Imaging](https://www.onvif.org/specs/srv/img/ONVIF-Imaging-Service-Spec.pdf) | diff --git a/onvif/services/media.py b/onvif/services/media.py index 1c6a970e..29f8ed5d 100644 --- a/onvif/services/media.py +++ b/onvif/services/media.py @@ -6,11 +6,16 @@ class Media(ONVIFService): - """Media service client. + """ + + + + + Media service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 1.0 (November 2008) | | **Binding name** | `MediaBinding` (`ver10/media/wsdl/media.wsdl`) | | **Operations** | [media.wsdl](https://www.onvif.org/ver10/media/wsdl/media.wsdl) | | **Spec** | [Media](https://www.onvif.org/specs/srv/media/ONVIF-Media-Service-Spec.pdf) | diff --git a/onvif/services/media2.py b/onvif/services/media2.py index efc7b79f..fa71de16 100644 --- a/onvif/services/media2.py +++ b/onvif/services/media2.py @@ -6,11 +6,15 @@ class Media2(ONVIFService): - """Media2 service client. + """ + + + + Media2 service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.61 (December 2015) | + | **First introduced** | ONVIF 2.6.1 (December 2015) | | **Binding name** | `Media2Binding` (`ver20/media/wsdl/media.wsdl`) | | **Operations** | [media.wsdl](https://www.onvif.org/ver20/media/wsdl/media.wsdl) | | **Spec** | [Media2](https://www.onvif.org/specs/srv/media/ONVIF-Media2-Service-Spec.pdf) | @@ -304,10 +308,10 @@ def SetEQPreset(self, Configuration): ) def SetEQPresetConfiguration(self, Configuration): - """This command is to configure Audio EQPreset. + """ + - !!! tip "Version History" - - Available since [`v0.4.3`](/onvif-python/releases/#v0.4.3) + This command is to configure Audio EQPreset. """ return self.operator.call( "SetEQPresetConfiguration", Configuration=Configuration @@ -653,12 +657,12 @@ def PlayAudioClip(self, Token, Play, AudioOutputToken=None, RepeatCycles=None): ) def AddTTSAudioClip(self, Configuration, TTSConfiguration, Token=None): - """This operation sends a text and its configuration to device that supports TTS + """ + + + This operation sends a text and its configuration to device that supports TTS function, so that device could convert the text into an audio clip and play it according to audio clip Configuration and TTS Configuration. - - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) """ return self.operator.call( "AddTTSAudioClip", @@ -673,11 +677,11 @@ def GetPlayingAudioClips(self): return self.operator.call("GetPlayingAudioClips") def GetMulticastAudioDecoderConfigurationOptions(self, ConfigurationToken=None): - """This operation gets the available options for the MulticastAudioDecoder - configuration. + """ + - !!! tip "Version History" - - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) + This operation gets the available options for the MulticastAudioDecoder + configuration. """ return self.operator.call( "GetMulticastAudioDecoderConfigurationOptions", @@ -685,10 +689,10 @@ def GetMulticastAudioDecoderConfigurationOptions(self, ConfigurationToken=None): ) def GetMulticastAudioDecoderConfigurations(self, ConfigurationToken=None): - """This operation gets the list of multicast audio decoder configurations. + """ + - !!! tip "Version History" - - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) + This operation gets the list of multicast audio decoder configurations. """ return self.operator.call( "GetMulticastAudioDecoderConfigurations", @@ -696,10 +700,10 @@ def GetMulticastAudioDecoderConfigurations(self, ConfigurationToken=None): ) def SetMulticastAudioDecoderConfiguration(self, Configuration): - """This operation sets the MulticastAudioDecoderConfiguration. + """ + - !!! tip "Version History" - - Available since [`v0.2.6`](/onvif-python/releases/#v0.2.6) + This operation sets the MulticastAudioDecoderConfiguration. """ return self.operator.call( "SetMulticastAudioDecoderConfiguration", Configuration=Configuration diff --git a/onvif/services/provisioning.py b/onvif/services/provisioning.py index 96330baa..9766075f 100644 --- a/onvif/services/provisioning.py +++ b/onvif/services/provisioning.py @@ -6,11 +6,15 @@ class Provisioning(ONVIFService): - """Provisioning service client. + """ + + + + Provisioning service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 16.12 (December 2016) | + | **First introduced** | ONVIF 16.12 (December 2016) | | **Binding name** | `ProvisioningBinding` (`ver10/provisioning/wsdl/provisioning.wsdl`) | | **Operations** | [provisioning.wsdl](https://www.onvif.org/ver10/provisioning/wsdl/provisioning.wsdl) | | **Spec** | [Provisioning](https://www.onvif.org/specs/srv/ptz/ONVIF-Provisioning-Service-Spec.pdf) | diff --git a/onvif/services/ptz.py b/onvif/services/ptz.py index 23c7f6a1..91390ad0 100644 --- a/onvif/services/ptz.py +++ b/onvif/services/ptz.py @@ -6,11 +6,16 @@ class PTZ(ONVIFService): - """PTZ service client. + """ + + + + + PTZ service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 1.0 (November 2008) | | **Binding name** | `PTZBinding` (`ver20/ptz/wsdl/ptz.wsdl`) | | **Operations** | [ptz.wsdl](https://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl) | | **Spec** | [PTZ](https://www.onvif.org/specs/srv/ptz/ONVIF-PTZ-Service-Spec.pdf) | diff --git a/onvif/services/receiver.py b/onvif/services/receiver.py index 4bf1cc33..c002b0e3 100644 --- a/onvif/services/receiver.py +++ b/onvif/services/receiver.py @@ -6,11 +6,15 @@ class Receiver(ONVIFService): - """Receiver service client. + """ + + + + Receiver service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 2.0 (November 2010) | | **Binding name** | `ReceiverBinding` (`ver10/receiver.wsdl`) | | **Operations** | [receiver.wsdl](https://www.onvif.org/ver10/receiver.wsdl) | | **Spec** | [Receiver](https://www.onvif.org/specs/srv/rcv/ONVIF-Receiver-Service-Spec.pdf) | diff --git a/onvif/services/recording.py b/onvif/services/recording.py index 554ee566..bf075d5e 100644 --- a/onvif/services/recording.py +++ b/onvif/services/recording.py @@ -6,11 +6,15 @@ class Recording(ONVIFService): - """Recording service client. + """ + + + + Recording service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 2.0 (November 2010) | | **Binding name** | `RecordingBinding` (`ver10/recording.wsdl`) | | **Operations** | [recording.wsdl](https://www.onvif.org/ver10/recording.wsdl) | | **Spec** | [RecordingControl](https://www.onvif.org/specs/srv/rec/ONVIF-RecordingControl-Service-Spec.pdf) | @@ -255,10 +259,10 @@ def OverrideSegmentDuration( ) def ListRecordedSegments(self, Time, RecordingToken, MaxResults=None): - """Lists available recorded segments related to the specified RecordingToken. + """ + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Lists available recorded segments related to the specified RecordingToken. """ return self.operator.call( "ListRecordedSegments", @@ -275,11 +279,11 @@ def ExportRecordedSegments( StorageToken=None, Track=None, ): - """Exports the selected recorded segments (from existing recorded data) to the - storage attached to the given recording configuration. + """ + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Exports the selected recorded segments (from existing recorded data) to the + storage attached to the given recording configuration. """ return self.operator.call( "ExportRecordedSegments", @@ -291,10 +295,10 @@ def ExportRecordedSegments( ) def StopExportRecordedSegments(self, OperationToken): - """Stops the selected ExportRecordedSegments operation. + """ + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Stops the selected ExportRecordedSegments operation. """ return self.operator.call( "StopExportRecordedSegments", OperationToken=OperationToken diff --git a/onvif/services/replay.py b/onvif/services/replay.py index 33040b92..d0681157 100644 --- a/onvif/services/replay.py +++ b/onvif/services/replay.py @@ -6,11 +6,15 @@ class Replay(ONVIFService): - """Recording service client. + """ + + + + Recording service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 2.0 (November 2010) | | **Binding name** | `ReplayBinding` (`ver10/replay.wsdl`) | | **Operations** | [replay.wsdl](https://www.onvif.org/ver10/replay.wsdl) | | **Spec** | [ReplayControl](https://www.onvif.org/specs/srv/replay/ONVIF-ReplayControl-Service-Spec.pdf) | diff --git a/onvif/services/schedule.py b/onvif/services/schedule.py index edcdfa6d..6787d744 100644 --- a/onvif/services/schedule.py +++ b/onvif/services/schedule.py @@ -7,11 +7,15 @@ # pylint: disable=redefined-outer-name class Schedule(ONVIFService): - """Schedule service client. + """ + + + + Schedule service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.6 (June 2015) | + | **First introduced** | ONVIF 2.6 (June 2015) | | **Binding name** | `ScheduleBinding` (`ver10/schedule/wsdl/schedule.wsdl`) | | **Operations** | [schedule.wsdl](https://www.onvif.org/ver10/schedule/wsdl/schedule.wsdl) | | **Spec** | [Scheduler](https://www.onvif.org/specs/srv/sched/ONVIF-Scheduler-Service-Spec.pdf) | diff --git a/onvif/services/search.py b/onvif/services/search.py index 242d3e6a..0df85a25 100644 --- a/onvif/services/search.py +++ b/onvif/services/search.py @@ -6,11 +6,15 @@ class Search(ONVIFService): - """Search service client. + """ + + + + Search service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.1 (June 2011) split from Core 2.0 | + | **First introduced** | ONVIF 2.0 (November 2010) | | **Binding name** | `SearchBinding` (`ver10/search.wsdl`) | | **Operations** | [search.wsdl](https://www.onvif.org/ver10/search.wsdl) | | **Spec** | [RecordingSearch](https://www.onvif.org/specs/srv/rsrch/ONVIF-RecordingSearch-Service-Spec.pdf) | @@ -349,11 +353,11 @@ def SearchImageByNL( Similarity=None, MaxMatches=None, ): - """Starts a natural language search session and specifies the search - parameters. + """ + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Starts a natural language search session and specifies the search + parameters. """ return self.operator.call( "SearchImageByNL", @@ -369,10 +373,10 @@ def SearchImageByNL( def GetNLSearchResults( self, SearchToken, MinResults=None, MaxResults=None, WaitTime=None ): - """Gets results from a natural language search session. + """ + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Gets results from a natural language search session. """ return self.operator.call( "GetNLSearchResults", @@ -392,10 +396,10 @@ def SearchImageByImage( TargetImageData=None, MaxMatches=None, ): - """Starts an image-based search session and specifies the search parameters. + """ + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Starts an image-based search session and specifies the search parameters. """ return self.operator.call( "SearchImageByImage", @@ -411,10 +415,10 @@ def SearchImageByImage( def GetImageSearchResults( self, SearchToken, MinResults=None, MaxResults=None, WaitTime=None ): - """Gets results from an image-based search session. + """ + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Gets results from an image-based search session. """ return self.operator.call( "GetImageSearchResults", diff --git a/onvif/services/security/advancedsecurity.py b/onvif/services/security/advancedsecurity.py index 4748e28e..9cf08d4a 100644 --- a/onvif/services/security/advancedsecurity.py +++ b/onvif/services/security/advancedsecurity.py @@ -6,11 +6,15 @@ class AdvancedSecurity(ONVIFService): - """Security service client. + """ + + + + Security service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.4 (August 2013) | + | **First introduced** | ONVIF 2.4 (August 2013) | | **Binding name** | `AdvancedSecurityServiceBinding` (`ver10/advancedsecurity/wsdl/advancedsecurity.wsdl`) | | **Operations** | [advancedsecurity.wsdl](https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | | **Spec** | [Security](https://www.onvif.org/specs/srv/security/ONVIF-Security-Service-Spec.pdf) | diff --git a/onvif/services/security/authorizationserver.py b/onvif/services/security/authorizationserver.py index a4759b79..b7edad35 100644 --- a/onvif/services/security/authorizationserver.py +++ b/onvif/services/security/authorizationserver.py @@ -6,11 +6,15 @@ class AuthorizationServer(ONVIFService): - """Security (AuthorizationServer) service client. + """ + + + + Security (AuthorizationServer) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 23.12 (December 2023) | + | **First introduced** | ONVIF 23.12 (December 2023) | | **Binding name** | `AuthorizationServerBinding` (`ver10/advancedsecurity/wsdl/advancedsecurity.wsdl`) | | **Operations** | [advancedsecurity.wsdl](https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | | **Spec** | [Security](https://www.onvif.org/specs/srv/security/ONVIF-Security-Service-Spec.pdf) | diff --git a/onvif/services/security/dot1x.py b/onvif/services/security/dot1x.py index 1ce065b3..abea8d27 100644 --- a/onvif/services/security/dot1x.py +++ b/onvif/services/security/dot1x.py @@ -6,11 +6,15 @@ class Dot1X(ONVIFService): - """Security (Dot1X) service client. + """ + + + + Security (Dot1X) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 16.06 (June 2016) | + | **First introduced** | ONVIF 16.06 (June 2016) | | **Binding name** | `Dot1XBinding` (`ver10/advancedsecurity/wsdl/advancedsecurity.wsdl`) | | **Operations** | [advancedsecurity.wsdl](https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | | **Spec** | [Security](https://www.onvif.org/specs/srv/security/ONVIF-Security-Service-Spec.pdf) | diff --git a/onvif/services/security/jwt.py b/onvif/services/security/jwt.py index 3bef5d4d..6aea843d 100644 --- a/onvif/services/security/jwt.py +++ b/onvif/services/security/jwt.py @@ -6,11 +6,15 @@ class JWT(ONVIFService): - """Security (JWT) service client. + """ + + + + Security (JWT) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 23.12 (December 2023) | + | **First introduced** | ONVIF 23.12 (December 2023) | | **Binding name** | `JWTBinding` (`ver10/advancedsecurity/wsdl/advancedsecurity.wsdl`) | | **Operations** | [advancedsecurity.wsdl](https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | | **Spec** | [Security](https://www.onvif.org/specs/srv/security/ONVIF-Security-Service-Spec.pdf) | diff --git a/onvif/services/security/keystore.py b/onvif/services/security/keystore.py index c440b5ad..0ce1f1dd 100644 --- a/onvif/services/security/keystore.py +++ b/onvif/services/security/keystore.py @@ -6,11 +6,15 @@ class Keystore(ONVIFService): - """Security (Keystore) service client. + """ + + + + Security (Keystore) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.4 (August 2013) | + | **First introduced** | ONVIF 2.4 (August 2013) | | **Binding name** | `KeystoreBinding` (`ver10/advancedsecurity/wsdl/advancedsecurity.wsdl`) | | **Operations** | [advancedsecurity.wsdl](https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | | **Spec** | [Security](https://www.onvif.org/specs/srv/security/ONVIF-Security-Service-Spec.pdf) | diff --git a/onvif/services/security/mediasigning.py b/onvif/services/security/mediasigning.py index 0b9e6d28..987b36ae 100644 --- a/onvif/services/security/mediasigning.py +++ b/onvif/services/security/mediasigning.py @@ -6,11 +6,15 @@ class MediaSigning(ONVIFService): - """Security (MediaSigning) service client. + """ + + + + Security (MediaSigning) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 24.12 (December 2024) | + | **First introduced** | ONVIF 23.12 (December 2023) | | **Binding name** | `MediaSigningBinding` (`ver10/advancedsecurity/wsdl/advancedsecurity.wsdl`) | | **Operations** | [advancedsecurity.wsdl](https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | | **Spec** | [Security](https://www.onvif.org/specs/srv/security/ONVIF-Security-Service-Spec.pdf) | diff --git a/onvif/services/security/tlsserver.py b/onvif/services/security/tlsserver.py index 1b766cb2..9e86a9b4 100644 --- a/onvif/services/security/tlsserver.py +++ b/onvif/services/security/tlsserver.py @@ -6,11 +6,15 @@ class TLSServer(ONVIFService): - """Security (TLSServer) service client. + """ + + + + Security (TLSServer) service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 2.4 (August 2013) | + | **First introduced** | ONVIF 2.4 (August 2013) | | **Binding name** | `TLSServerBinding` (`ver10/advancedsecurity/wsdl/advancedsecurity.wsdl`) | | **Operations** | [advancedsecurity.wsdl](https://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl) | | **Spec** | [Security](https://www.onvif.org/specs/srv/security/ONVIF-Security-Service-Spec.pdf) | diff --git a/onvif/services/thermal.py b/onvif/services/thermal.py index 3a7be2d4..214e0392 100644 --- a/onvif/services/thermal.py +++ b/onvif/services/thermal.py @@ -6,11 +6,15 @@ class Thermal(ONVIFService): - """Thermal service client. + """ + + + + Thermal service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 16.06 (June 2016) | + | **First introduced** | ONVIF 16.06 (June 2016) | | **Binding name** | `ThermalBinding` (`ver10/thermal/wsdl/thermal.wsdl`) | | **Operations** | [thermal.wsdl](https://www.onvif.org/ver10/thermal/wsdl/thermal.wsdl) | | **Spec** | [Thermal](https://www.onvif.org/specs/srv/thermal/ONVIF-Thermal-Service-Spec.pdf) | diff --git a/onvif/services/uplink.py b/onvif/services/uplink.py index 64d7f8b7..f3f17f68 100644 --- a/onvif/services/uplink.py +++ b/onvif/services/uplink.py @@ -6,11 +6,15 @@ class Uplink(ONVIFService): - """Uplink service client. + """ + + + + Uplink service client. | Property | Details | | -------- | ------- | - | **First introduced** | ONVIF Release 18.12 (December 2018) | + | **First introduced** | ONVIF 18.12 (December 2018) | | **Binding name** | `UplinkBinding` (`ver10/uplink/wsdl/uplink.wsdl`) | | **Operations** | [uplink.wsdl](https://www.onvif.org/ver10/uplink/wsdl/uplink.wsdl) | | **Spec** | [Uplink](https://www.onvif.org/specs/srv/uplink/ONVIF-Uplink-Spec.pdf) | diff --git a/onvif/utils/discovery.py b/onvif/utils/discovery.py index 971cb583..3ef07616 100644 --- a/onvif/utils/discovery.py +++ b/onvif/utils/discovery.py @@ -24,7 +24,13 @@ class ONVIFDiscovery: - """Discover ONVIF devices using the WS-Discovery protocol. + """ + + + + + + Discover ONVIF devices using the WS-Discovery protocol. This class provides methods for discovering ONVIF-compliant devices on the local network using WS-Discovery multicast. @@ -38,7 +44,6 @@ class ONVIFDiscovery: interface (str | None): Network interface IP to bind to (default: auto-detect) !!! tip "Version History" - - Available since [`v0.1.6`](/onvif-python/releases/#v0.1.6) - Changed in [`v0.4.0`](/onvif-python/releases/#v0.4.0): ~~`WS_DISCOVERY_ADDRESS_IPv4`~~ → `WS_DISCOVERY_ADDRESS_IPV4` """ @@ -88,10 +93,11 @@ def __init__( self._local_ip: str | None = None def get_local_ip(self) -> str: - """Get local network interface IP address. + """ + + - !!! tip "Version History" - - Available since [`v0.1.6`](/onvif-python/releases/#v0.1.6) + Get local network interface IP address. Returns: Local IP address @@ -132,14 +138,16 @@ def get_local_ip(self) -> str: def discover( self, prefer_https: bool = False, search: str | None = None ) -> list[dict[str, Any]]: - """Discover ONVIF devices on the network. + """ + + - !!! tip "Version History" - - Available since [`v0.1.6`](/onvif-python/releases/#v0.1.6) + Discover ONVIF devices on the network. Args: prefer_https (bool): If True, prioritize HTTPS XAddrs when available - search (str | None): Optional search term to filter devices by types or scopes (case-insensitive) + search (str | None): Optional search term to filter devices + by types or scopes (case-insensitive) Returns: List of discovered devices (as dict); empty if none are available diff --git a/onvif/utils/error_handlers.py b/onvif/utils/error_handlers.py index f3c53e61..468212aa 100644 --- a/onvif/utils/error_handlers.py +++ b/onvif/utils/error_handlers.py @@ -1,4 +1,9 @@ """ + + + + + Error handling utilities for ONVIF operations. This module provides utilities to gracefully handle ONVIF SOAP errors, @@ -53,10 +58,10 @@ def is_action_not_supported(exception: ONVIFOperationException | Fault) -> bool: """ - Check whether an exception is caused by an `ActionNotSupported` SOAP fault. + + - !!! tip "Version History" - - Available since [`v0.4.0`](/onvif-python/releases/#v0.4.0) + Check whether an exception is caused by an `ActionNotSupported` SOAP fault. Args: exception: The exception to inspect. Can be an @@ -117,10 +122,10 @@ def safe_call( log_error: bool = True, ) -> Any | None: """ - Safely call an ONVIF operation with graceful error handling. + + - !!! tip "Version History" - - Available since [`v0.4.0`](/onvif-python/releases/#v0.4.0) + Safely call an ONVIF operation with graceful error handling. Args: func (Callable): The callable that performs the ONVIF operation. @@ -190,10 +195,11 @@ def safe_call( def ignore_unsupported(func: Callable) -> Any | None: - """Decorator to ignore `ActionNotSupported` SOAP faults. + """ + + - !!! tip "Version History" - - Available since [`v0.4.0`](/onvif-python/releases/#v0.4.0) + Decorator to ignore `ActionNotSupported` SOAP faults. Args: func (Callable): The function to decorate. The function may accept positional diff --git a/onvif/utils/exceptions.py b/onvif/utils/exceptions.py index 8aff0b9d..61307386 100644 --- a/onvif/utils/exceptions.py +++ b/onvif/utils/exceptions.py @@ -9,7 +9,11 @@ # pylint: disable=too-many-nested-blocks,too-many-branches class ONVIFOperationException(Exception): # pylint: disable=line-too-long - """Enhanced exception wrapper for ONVIF operation failures. + """ + + + + Enhanced exception wrapper for ONVIF operation failures. This exception provides detailed error information including operation name, error category, SOAP fault details, and the original exception. @@ -20,9 +24,6 @@ class ONVIFOperationException(Exception): operation (str): Name of the ONVIF operation that failed original_exception (Exception): The underlying exception that was raised - !!! tip "Version History" - - Available since [`v0.0.1`](/onvif-python/releases/#v0.0.1) (first release) - ## Error Categories ### SOAP Error diff --git a/onvif/utils/plugins.py b/onvif/utils/plugins.py index d0bbf05c..ffd33302 100644 --- a/onvif/utils/plugins.py +++ b/onvif/utils/plugins.py @@ -1,6 +1,6 @@ """Auxiliary custom Zeep plugins outside the core scope. -All classes in this module inherit from Zeep's Plugin (`zeep.plugins`) class. +All classes in this module inherit from Zeep's Plugin (`zeep.Plugin`) class. """ from __future__ import annotations @@ -16,145 +16,12 @@ logger.addHandler(logging.NullHandler()) -class ONVIFParser(Plugin): - """Lightweight Zeep plugin for extracting XML elements from SOAP responses. - - The parser extracts text from XML elements matching configured XPath - expressions before Zeep parses the SOAP response. This is useful for - extracting elements that Zeep does not parse correctly, such as - `simpleContent` elements with attributes. - - Args: - extract_xpaths: Dictionary mapping extraction names to XPath expressions - - Attributes: - extract_xpaths: XPath expressions used to extract elements from SOAP - responses - - !!! tip "Version History" - - Available since [`v0.2.2`](/onvif-python/releases/#v0.2.2) - - ??? example "Usage" - ```python linenums="1" - from onvif import ONVIFClient, ONVIFParser - - parser = ONVIFParser({ - "topic": ".//{http://docs.oasis-open.org/wsn/b-2}Topic", - }) - - client = ONVIFClient( - host, port, username, password, plugins=[parser] - ) - - subscription = client.events().CreatePullPointSubscription() - pullpoint = client.pullpoint(subscription) - - msgs = pullpoint.PullMessages( - Timeout="PT5S", - MessageLimit=10, - ) - - topics = parser.get_extracted_texts( - "topic", - len(msgs.NotificationMessage), - ) - ``` - - ??? note "Notes" - - Uses Zeep's `ingress()` hook to access the raw SOAP response. - - The extraction cache is cleared before each SOAP response. - - Supports any XPath expression accepted by `lxml`. +class XMLCapturePlugin(Plugin): """ + + - def __init__(self, extract_xpaths: dict[str, str]): - """Initialize XML element parser. - - Args: - extract_xpaths: Dictionary mapping names to XPath expressions. - XPath expressions will be used to find elements in SOAP response. - - Example: - ```python - { - 'topic': './/{http://docs.oasis-open.org/wsn/b-2}Topic', - 'custom': './/ns:CustomElement' - } - ``` - """ - self.extract_xpaths: dict[str, str] = extract_xpaths - self._extracted_elements: dict[str, list[str | None]] = {} - - logger.debug( - "ONVIFParser initialized with XPaths: %s", list(extract_xpaths.keys()) - ) - - def ingress( - self, envelope: etree._Element, http_headers: dict[str, str], operation: Any - ) -> tuple[Any, dict[str, str]]: - """Process a SOAP response before Zeep deserializes it. - - This Zeep ``ingress`` hook inspects the raw SOAP response envelope and - extracts text from elements matching the configured XPath expressions. - The extracted values are stored temporarily and can be retrieved with - `get_extracted_texts`. - - The extraction cache is cleared before processing each response, so it - always contains values from the most recently processed SOAP response. - - Args: - envelope: Raw SOAP response envelope as an `lxml.etree.Element` - http_headers: HTTP response headers returned by the device - operation: Zeep operation associated with the SOAP response - - Returns: - A tuple containing the unchanged ``envelope`` and ``http_headers``. - Returning both values allows Zeep to continue processing the response - and allows other plugins in the chain to process it as well. - """ - # Auto-clear cache from previous response - self._extracted_elements = {} - - try: - # Extract elements using XPath from raw XML envelope - for name, xpath in self.extract_xpaths.items(): - elements = envelope.findall(xpath) - - # Extract text content from found elements - texts = [elem.text for elem in elements] - - if texts: - self._extracted_elements[name] = texts - logger.debug( - "ONVIFParser: Extracted %d '%s' elements", len(texts), name - ) - - except (ValueError, TypeError, AttributeError) as e: - logger.warning("ONVIFParser: Failed to extract elements: %s", e) - - return envelope, http_headers - - def get_extracted_texts(self, name: str, count: int) -> list[str | None]: - """Get extracted element texts by name. - - Args: - name (str): Name of the extracted elements (key from `extract_xpaths` dict) - count (int): Number of elements to return - - Returns: - List of element text values, padded with None if fewer elements were found. - Example: If 3 elements found but `count=5`, returns [text1, text2, text3, None, None] - """ - texts = self._extracted_elements.get(name, [])[:count] - - # Pad with None if not enough elements - while len(texts) < count: - texts.append(None) - - return texts - - -class XMLCapturePlugin(Plugin): - """Zeep plugin to capture and inspect SOAP XML requests and responses. + Zeep plugin to capture and inspect SOAP XML requests and responses. This plugin intercepts SOAP communication between the ONVIF client and device, capturing raw XML for debugging, logging, and analysis purposes. It's invaluable @@ -168,7 +35,6 @@ class XMLCapturePlugin(Plugin): history (list[dict[str, Any]]): All captured requests/responses with metadata !!! tip "Version History" - - Available since [`v0.0.6`](/onvif-python/releases/#v0.0.6) - Moved to `plugins` since [`v0.4.0`](/onvif-python/releases/#v0.4.0) !!! question "The plugin automatically captures" @@ -229,7 +95,7 @@ def __init__(self, pretty_print=True): self.history = [] # Store all requests/responses logger.debug("XMLCapturePlugin initialized (pretty_print=%s)", pretty_print) - def _format_xml(self, element) -> str: + def _format_xml(self, element: etree._Element) -> str: """Format XML element with proper indentation using lxml. Args: @@ -267,7 +133,11 @@ def egress( operation: Any, binding_options: dict[str, object], ) -> tuple[Any, dict[str, str]]: - """Capture a SOAP request before it is sent to the device. + """ + + + + Capture a SOAP request before it is sent to the device. This Zeep ``egress`` hook serializes the outgoing SOAP envelope and stores it in `last_sent_xml`. The request is also appended to `history` together @@ -319,7 +189,11 @@ def egress( def ingress( self, envelope: etree._Element, http_headers: dict[str, str], operation: Any ) -> tuple[Any, dict[str, str]]: - """Capture a SOAP response after it is received from the device. + """ + + + + Capture a SOAP response after it is received from the device. This Zeep ``ingress`` hook serializes the incoming SOAP envelope and stores it in `last_received_xml`. The response is also appended to `history` @@ -366,7 +240,11 @@ def ingress( return envelope, http_headers def get_last_request(self) -> str | None: - """Get the last captured request XML. + """ + + + + Get the last captured request XML. Returns: Last captured request XML @@ -374,7 +252,11 @@ def get_last_request(self) -> str | None: return self.last_sent_xml def get_last_response(self) -> str | None: - """Get the last captured response XML. + """ + + + + Get the last captured response XML. Returns: Last captured response XML @@ -382,7 +264,11 @@ def get_last_response(self) -> str | None: return self.last_received_xml def get_history(self) -> list: - """Get all captured requests and responses. + """ + + + + Get all captured requests and responses. Returns: List of all captured requests and responses. @@ -390,7 +276,12 @@ def get_history(self) -> list: return self.history def clear_history(self) -> None: - """Clear the capture history.""" + """ + + + + Clear the capture history. + """ history_count = len(self.history) self.history = [] self.last_sent_xml = None @@ -398,12 +289,18 @@ def clear_history(self) -> None: self.last_operation = None logger.debug("Cleared XML capture history (%d items)", history_count) - def save_to_file(self, request_file=None, response_file=None) -> None: - """Save captured XML to files. + def save_to_file( + self, request_file: str | None = None, response_file: str | None = None + ) -> None: + """ + + + + Save captured XML to files. Args: - request_file (str): Path to save request XML - response_file (str): Path to save response XML + request_file (str | None): Path to save request XML + response_file (str | None): Path to save response XML """ if request_file and self.last_sent_xml: try: @@ -422,8 +319,161 @@ def save_to_file(self, request_file=None, response_file=None) -> None: logger.error("Failed to save response XML to %s: %s", response_file, e) +class ONVIFParser(Plugin): + """ + + + + + Lightweight Zeep plugin for extracting XML elements from SOAP responses. + + The parser extracts text from XML elements matching configured XPath + expressions before Zeep parses the SOAP response. This is useful for + extracting elements that Zeep does not parse correctly, such as + `simpleContent` elements with attributes. + + Attributes: + extract_xpaths: XPath expressions used to extract elements from SOAP + responses + + !!! tip "Version History" + - Moved to `plugins` since [`v0.3.1`](/onvif-python/releases/#v0.3.1) + + ??? example "Usage" + ```python linenums="1" + from onvif import ONVIFClient, ONVIFParser + + parser = ONVIFParser({ + "topic": ".//{http://docs.oasis-open.org/wsn/b-2}Topic", + }) + + client = ONVIFClient( + host, port, username, password, plugins=[parser] + ) + + subscription = client.events().CreatePullPointSubscription() + pullpoint = client.pullpoint(subscription) + + msgs = pullpoint.PullMessages( + Timeout="PT5S", + MessageLimit=10, + ) + + topics = parser.get_extracted_texts( + "topic", + len(msgs.NotificationMessage), + ) + ``` + + ??? note "Notes" + - Uses Zeep's `ingress()` hook to access the raw SOAP response. + - The extraction cache is cleared before each SOAP response. + - Supports any XPath expression accepted by `lxml`. + """ + + def __init__(self, extract_xpaths: dict[str, str]): + """Initialize XML element parser. + + Args: + extract_xpaths: Dictionary mapping names to XPath expressions. + XPath expressions will be used to find elements in SOAP response. + + Example: + ```python + { + 'topic': './/{http://docs.oasis-open.org/wsn/b-2}Topic', + 'custom': './/ns:CustomElement' + } + ``` + """ + self.extract_xpaths: dict[str, str] = extract_xpaths + self._extracted_elements: dict[str, list[str | None]] = {} + + logger.debug( + "ONVIFParser initialized with XPaths: %s", list(extract_xpaths.keys()) + ) + + def ingress( + self, envelope: etree._Element, http_headers: dict[str, str], operation: Any + ) -> tuple[Any, dict[str, str]]: + """ + + + + Process a SOAP response before Zeep deserializes it. + + This Zeep ``ingress`` hook inspects the raw SOAP response envelope and + extracts text from elements matching the configured XPath expressions. + The extracted values are stored temporarily and can be retrieved with + `get_extracted_texts`. + + The extraction cache is cleared before processing each response, so it + always contains values from the most recently processed SOAP response. + + Args: + envelope: Raw SOAP response envelope as an `lxml.etree.Element` + http_headers: HTTP response headers returned by the device + operation: Zeep operation associated with the SOAP response + + Returns: + A tuple containing the unchanged ``envelope`` and ``http_headers``. + Returning both values allows Zeep to continue processing the response + and allows other plugins in the chain to process it as well. + """ + # Auto-clear cache from previous response + self._extracted_elements = {} + + try: + # Extract elements using XPath from raw XML envelope + for name, xpath in self.extract_xpaths.items(): + elements = envelope.findall(xpath) + + # Extract text content from found elements + texts = [elem.text for elem in elements] + + if texts: + self._extracted_elements[name] = texts + logger.debug( + "ONVIFParser: Extracted %d '%s' elements", len(texts), name + ) + + except (ValueError, TypeError, AttributeError) as e: + logger.warning("ONVIFParser: Failed to extract elements: %s", e) + + return envelope, http_headers + + def get_extracted_texts(self, name: str, count: int) -> list[str | None]: + """ + + + + Get extracted element texts by name. + + Args: + name (str): Name of the extracted elements (key from `extract_xpaths` dict) + count (int): Number of elements to return + + Returns: + List of element text values, padded with None if fewer elements were found. + Example: If 3 elements found but `count=5`, returns + [text1, text2, text3, None, None] + """ + texts = self._extracted_elements.get(name, [])[:count] + + # Pad with None if not enough elements + while len(texts) < count: + texts.append(None) + + return texts + + class ReferenceParametersPlugin(Plugin): - """Zeep plugin for injecting WS-Addressing reference parameters. + """ + + + + + Zeep plugin for injecting WS-Addressing reference parameters. The plugin adds WS-Addressing reference parameters to the SOAP ``Header`` of outgoing requests. It is primarily useful for ONVIF services whose @@ -434,13 +484,10 @@ class ReferenceParametersPlugin(Plugin): XML elements can be reused safely across requests. Attributes: - reference_parameters: XML elements to inject into outgoing SOAP - headers + reference_parameters (list[etree._Element]): XML elements to inject + into outgoing SOAP headers - !!! tip "Version History" - - Available since [`v0.3.1`](/onvif-python/releases/#v0.3.1) - - !!! note + !!! info The plugin supports both SOAP 1.1 and SOAP 1.2 envelope namespaces """ @@ -450,6 +497,7 @@ class ReferenceParametersPlugin(Plugin): ) def __init__(self, reference_parameters: list[etree._Element] | None = None): + """Initialize Reference Parameters injection""" self.reference_parameters = reference_parameters or [] def egress( @@ -459,7 +507,11 @@ def egress( operation: Any, binding_options: dict[str, object], ) -> tuple[Any, dict[str, str]]: - """Inject WS-Addressing reference parameters into a SOAP request. + """ + + + + Inject WS-Addressing reference parameters into a SOAP request. This Zeep ``egress`` hook adds the configured reference parameters to the SOAP ``Header`` before the request is sent to the device. diff --git a/onvif/utils/service.py b/onvif/utils/service.py index b1ab1add..371c10d6 100644 --- a/onvif/utils/service.py +++ b/onvif/utils/service.py @@ -60,18 +60,20 @@ def _is_zeep_object(obj): class ONVIFService: - """Base class for all ONVIF service implementations. + """ + + + + Base class for all ONVIF service implementations. This abstract base class provides automatic error handling and consistent API behavior for all ONVIF services ([`Device`](../services/device.md), [`Media`](../services/media.md), [`PTZ`](../services/ptz.md), etc.). - !!! tip "Version History" - - Available since [`v0.1.8`](/onvif-python/releases/#v0.1.8) - !!! danger "All service classes inherit from `ONVIFService` to ensure" - Consistent exception handling across all ONVIF operations - - Automatic wrapping of errors into [`ONVIFOperationException`](../exceptions/onvif_exception.md) + - Automatic wrapping of errors into + [`ONVIFOperationException`](../exceptions/onvif_exception.md) - Uniform error reporting with operation names - Transparent method interception without explicit wrappers @@ -79,8 +81,10 @@ class ONVIFService: - Uses `__getattribute__` magic method to intercept all method calls - Automatically wraps ONVIF operations (methods starting with uppercase) - Preserves non-ONVIF methods, private methods, and attributes - - Converts all exceptions to [`ONVIFOperationException`](../exceptions/onvif_exception.md) for consistency - - Re-raises existing [`ONVIFOperationException`](../exceptions/onvif_exception.md) without double-wrapping + - Converts all exceptions to + [`ONVIFOperationException`](../exceptions/onvif_exception.md) for consistency + - Re-raises existing + [`ONVIFOperationException`](../exceptions/onvif_exception.md) without double-wrapping ??? note "Notes" - This is an abstract base class - don't instantiate directly @@ -90,13 +94,18 @@ class ONVIFService: - Compatible with all Python magic methods and properties ??? note "See Also" - - [`ONVIFOperationException`](../exceptions/onvif_exception.md): Exception class for wrapped errors + - [`ONVIFOperationException`](../exceptions/onvif_exception.md): + Exception class for wrapped errors - [`ONVIFOperator`](../core/onvif_operator.md): Low-level SOAP operation handler - - Device, Media, PTZ, etc.: Concrete service implementations + - Device, Media, PTZ, etc: Concrete service implementations """ def __getattribute__(self, name: str) -> Any: - """Intercept all method calls and wrap ONVIF operations with error handling. + """ + + + + Intercept all method calls and wrap ONVIF operations with error handling. This magic method is called for every attribute access on the service object. It intercepts ONVIF operation calls and wraps them with consistent error handling. @@ -111,7 +120,7 @@ def __getattribute__(self, name: str) -> Any: ONVIFOperationException: If the ONVIF operation fails !!! question "Method Interception Logic" - 1. Get the attribute using object.__getattribute__ + 1. Get the attribute using `object.__getattribute__` 2. Skip if not callable, private, or internal attribute 3. Check if method name starts with uppercase (ONVIF convention) 4. If yes, return wrapped version that catches and converts exceptions @@ -165,10 +174,11 @@ def wrapped_method(*args, **kwargs): def type(self, type_name: str) -> Any: """ - Create and return an instance of the specified ONVIF type. + + + - !!! tip "Version History" - - Available since [`v0.1.9`](/onvif-python/releases/#v0.1.9) + Create and return an instance of the specified ONVIF type. Args: type_name (str): Name of the type to create (e.g., 'SetHostname', 'SetIPAddressFilter') @@ -184,7 +194,9 @@ def type(self, type_name: str) -> Any: device = client.devicemgmt() newuser = device.type('CreateUsers') - newuser.User.append({"Username": 'new_user', "Password": 'new_password', "UserLevel": 'User'}) + newuser.User.append({ + "Username": 'new_user', "Password": 'new_password', "UserLevel": 'User' + }) device.CreateUsers(newuser) hostname = device.type('SetHostname') @@ -215,10 +227,11 @@ def type(self, type_name: str) -> Any: raise ONVIFOperationException(f"type({type_name})", e) from e def operations(self) -> list[str] | list: - """List all available operations for this service. + """ + + - !!! tip "Version History" - - Available since [`v0.2.0`](/onvif-python/releases/#v0.2.0) + List all available operations for this service. Returns: List of operation names that can be used with `type()` method @@ -266,10 +279,10 @@ def operations(self) -> list[str] | list: def desc(self, method_name: str) -> dict: """ - Get documentation and parameter information for a specific operation/method. + + - !!! tip "Version History" - - Available since [`v0.2.0`](/onvif-python/releases/#v0.2.0) + Get documentation and parameter information for a specific operation/method. Args: method_name (str): Name of the method to describe (e.g., 'GetDeviceInformation', 'SetHostname') @@ -383,10 +396,11 @@ def desc(self, method_name: str) -> dict: def to_dict(self, zeep_object: Any) -> dict: """ - Convert a zeep object (result from ONVIF operation) to Python dictionary. + + + - !!! tip "Version History" - - Available since [`v0.2.9`](/onvif-python/releases/#v0.2.9) + Convert a zeep object (result from ONVIF operation) to Python dictionary. Args: zeep_object (Any): The zeep object returned from ONVIF operations diff --git a/onvif/utils/wsdl.py b/onvif/utils/wsdl.py index 69fcac9a..25a4cd51 100644 --- a/onvif/utils/wsdl.py +++ b/onvif/utils/wsdl.py @@ -13,7 +13,11 @@ class ONVIFWSDL: - """WSDL file manager for ONVIF services. + """ + + + + WSDL file manager for ONVIF services. This class manages WSDL (Web Services Description Language) file paths, bindings, and namespaces for all ONVIF services. It provides a centralized mapping between @@ -26,9 +30,6 @@ class ONVIFWSDL: BASE_DIR (str): Default base directory for WSDL files (Built-in) WSDL_MAP (dict[str, dict[str, Any]] | None): Will be initialized when first accessed - !!! tip "Version History" - - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) - !!! warning "WSDL Structure" Built-in WSDLs are organized in the ONVIF standard directory structure: @@ -94,10 +95,11 @@ class ONVIFWSDL: @classmethod def set_custom_wsdl_dir(cls, custom_dir: str) -> None: - """Set global custom WSDL directory for all services. + """ + + - !!! tip "Version History" - - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) + Set global custom WSDL directory for all services. Args: custom_dir (str): Path to directory containing custom WSDL files @@ -115,10 +117,11 @@ def set_custom_wsdl_dir(cls, custom_dir: str) -> None: @classmethod def get_custom_wsdl_dir(cls) -> str | None: - """Get current global custom WSDL directory. + """ + + - !!! tip "Version History" - - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) + Get current global custom WSDL directory. Returns: Current custom WSDL directory, or None if using built-in @@ -135,10 +138,11 @@ def get_custom_wsdl_dir(cls) -> str | None: @classmethod def clear_custom_wsdl_dir(cls) -> None: - """Clear custom WSDL directory, revert to built-in WSDLs. + """ + + - !!! tip "Version History" - - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) + Clear custom WSDL directory, revert to built-in WSDLs. Example: ```python linenums="1" @@ -250,10 +254,11 @@ def _ensure_wsdl_map_initialized(cls) -> None: @classmethod def get_wsdl_map(cls) -> dict[str, dict[str, Any]]: - """Get the complete WSDL map for all services. + """ + + - !!! tip "Version History" - - Available since [`v0.2.11`](/onvif-python/releases/#v0.2.11) + Get the complete WSDL map for all services. """ cls._ensure_wsdl_map_initialized() @@ -266,14 +271,15 @@ def get_wsdl_map(cls) -> dict[str, dict[str, Any]]: def get_definition( cls, service: str, version: str = "ver10", custom_wsdl_dir=None ) -> dict: - """Get WSDL definition for a specific ONVIF service. + """ + + + + Get WSDL definition for a specific ONVIF service. Returns complete WSDL definition including file path, SOAP binding name, and XML namespace for the requested service and version. - !!! tip "Version History" - - Available since [`v0.1.0`](/onvif-python/releases/#v0.1.0) - Args: service (str): Service name (e.g., "devicemgmt", "media", "ptz"). version (str): ONVIF version (default: "ver10"). diff --git a/onvif/utils/zeep.py b/onvif/utils/zeep.py index 59f76138..e3fb2da2 100644 --- a/onvif/utils/zeep.py +++ b/onvif/utils/zeep.py @@ -16,16 +16,17 @@ # pylint: disable=too-many-branches,too-many-nested-blocks,too-many-return-statements class ZeepPatcher: - """Utility for patching zeep SOAP library to handle ONVIF `xsd:any` fields. + """ + + + + Utility for patching zeep SOAP library to handle ONVIF `xsd:any` fields. This class patches the zeep library to better parse `xsd:any` fields commonly found in ONVIF SOAP responses. Without this patch, `xsd:any` fields remain as raw XML elements, making them difficult to work with. The patch converts them into structured dictionaries with proper type conversion. - !!! tip "Version History" - - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) - !!! failure "The Problem" ONVIF uses `xsd:any` extensively for extensibility. By default, zeep doesn't parse these fields - it just stores raw XML elements. This makes accessing @@ -369,7 +370,11 @@ def _zeep_object_to_dict(obj): @staticmethod def flatten_xsd_any_fields(obj, _visited=None) -> Any: - """Post-process zeep objects to flatten `xsd:any` fields (`_value_1`, `_value_2`, + """ + + + + Post-process zeep objects to flatten `xsd:any` fields (`_value_1`, `_value_2`, etc.) into the main object. Zeep uses `_value_N` fields to store parsed content from `xsd:any` elements. @@ -383,9 +388,6 @@ def flatten_xsd_any_fields(obj, _visited=None) -> Any: This handles all `xsd:any` occurrences (`_value_1`, `_value_2`, `_value_3`, etc.), not just the first one. - !!! tip "Version History" - - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) - Args: obj (XsdAny): The zeep object to process _visited (XsdAny): Set of visited object IDs to prevent infinite recursion @@ -626,14 +628,15 @@ def flatten_xsd_any_fields(obj, _visited=None) -> Any: @classmethod def apply_patch(cls): - """Inject the custom `parse_xmlelements` method into `zeep.xsd.elements.any.Any`. + """ + + + + Inject the custom `parse_xmlelements` method into `zeep.xsd.elements.any.Any`. This enables better parsing of `xsd:any` fields in ONVIF SOAP responses. Should be called once at application startup. - !!! tip "Version History" - - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) - Example: ```python linenums="1" from onvif import ZeepPatcher @@ -652,12 +655,13 @@ def apply_patch(cls): @classmethod def remove_patch(cls): - """Restore the original `parse_xmlelements` method. + """ + + - Reverts zeep to its original behavior. Useful for testing or debugging. + Restore the original `parse_xmlelements` method. - !!! tip "Version History" - - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) + Reverts zeep to its original behavior. Useful for testing or debugging. Example: ```python linenums="1" @@ -676,10 +680,11 @@ def remove_patch(cls): @classmethod def is_patched(cls) -> bool: - """Check if the patch is currently applied. + """ + + - !!! tip "Version History" - - Available since [`v0.0.4`](/onvif-python/releases/#v0.0.4) + Check if the patch is currently applied. Returns: `True` if patch is active, `False` otherwise From 65adfe6a3c042b3261cb7aa05b5b6a45794f3c74 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 14:12:51 +0700 Subject: [PATCH 34/38] docs: Update badge links to use shield.io for consistency --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 825d5470..53a3cf72 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ONVIF Python [![Downloads](https://static.pepy.tech/badge/onvif-python)](https://pepy.tech/projects/onvif-python) +# ONVIF Python [![Downloads](https://img.shields.io/pypi/dm/onvif-python?label=Downloads&style=plastic)](https://pepy.tech/projects/onvif-python) [![Python Version](https://img.shields.io/pypi/pyversions/onvif-python?logo=python&logoColor=white&color=blue&style=plastic&label=Python)](https://pypi.org/project/onvif-python) [![PyPI Version](https://img.shields.io/pypi/v/onvif-python?logo=pypi&logoColor=white&color=blue&style=plastic&label=PyPI)](https://pypi.org/project/onvif-python/) diff --git a/docs/index.md b/docs/index.md index c77baa74..1701b984 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,7 +3,7 @@ hide: - navigation --- -# ONVIF Python  [![Downloads](https://static.pepy.tech/badge/onvif-python)](https://pepy.tech/projects/onvif-python){ .no-external-icon } +# ONVIF Python  [![Downloads](https://img.shields.io/pypi/dm/onvif-python?label=Downloads&style=plastic)](https://pepy.tech/projects/onvif-python){ .no-external-icon } [![Python Version](https://img.shields.io/pypi/pyversions/onvif-python?logo=python&logoColor=white&color=blue&style=plastic&label=Python)](https://pypi.org/project/onvif-python){ .no-external-icon } From 7d23dcaa34de5cae8f68689538f280c33f4ca257 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 18:33:52 +0700 Subject: [PATCH 35/38] docs: Overhaul documentation structure and enhance content clarity with added comments and improved styling --- docs/api/core/onvif_client.md | 8 ++- docs/api/core/onvif_operator.md | 8 ++- docs/api/exceptions/onvif_error_handlers.md | 8 ++- docs/api/exceptions/onvif_exception.md | 6 +- docs/api/services/index.md | 2 +- docs/api/utilities/cache_mode.md | 8 ++- docs/api/utilities/index.md | 2 +- docs/api/utilities/onvif_discovery.md | 8 ++- docs/api/utilities/onvif_service.md | 8 ++- docs/api/utilities/onvif_wsdl.md | 8 ++- docs/api/utilities/plugins.md | 9 ++- docs/api/utilities/zeep_patcher.md | 8 ++- docs/approach.md | 1 + docs/hooks/shortcodes.py | 2 +- docs/javascripts/external-links.js | 10 ++- docs/main/onvif_client.md | 1 + docs/overrides/.icons/material/api.svg | 1 - docs/overrides/.icons/material/automation.svg | 1 + docs/overrides/.icons/material/category.svg | 1 + .../.icons/material/network-node.svg | 1 + docs/overrides/.icons/material/token.svg | 1 - docs/overrides/partials/comments.html | 63 ++++++++++++------- docs/project/contributing.md | 49 ++++++++------- docs/project/roadmap.md | 2 +- docs/project/used_by.md | 1 + docs/quick_start.md | 1 + docs/references/implemented_services.md | 1 + docs/references/index.md | 4 +- docs/references/service_bindings.md | 1 + docs/references/service_discovery.md | 1 + docs/references/supported_profiles.md | 1 + docs/stylesheets/extra.css | 11 +++- docs/utilities/helper_methods.md | 1 + mkdocs.yml | 7 +++ 34 files changed, 167 insertions(+), 78 deletions(-) delete mode 100644 docs/overrides/.icons/material/api.svg create mode 100644 docs/overrides/.icons/material/automation.svg create mode 100644 docs/overrides/.icons/material/category.svg create mode 100644 docs/overrides/.icons/material/network-node.svg delete mode 100644 docs/overrides/.icons/material/token.svg diff --git a/docs/api/core/onvif_client.md b/docs/api/core/onvif_client.md index b78ee6a8..926463f8 100644 --- a/docs/api/core/onvif_client.md +++ b/docs/api/core/onvif_client.md @@ -1,11 +1,15 @@ -# ONVIFClient +--- +comments: true +--- ::: onvif.client.ONVIFClient options: + show_root_heading: true + show_root_full_path: true docstring_options: ignore_init_summary: true show_source: true docstring_style: google members_order: source - heading_level: 3 + heading_level: 2 merge_init_into_class: true \ No newline at end of file diff --git a/docs/api/core/onvif_operator.md b/docs/api/core/onvif_operator.md index 771399fb..ef399f3d 100644 --- a/docs/api/core/onvif_operator.md +++ b/docs/api/core/onvif_operator.md @@ -1,8 +1,12 @@ -# ONVIFOperator +--- +comments: true +--- ::: onvif.operator.ONVIFOperator options: + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members_order: source - heading_level: 3 \ No newline at end of file + heading_level: 2 \ No newline at end of file diff --git a/docs/api/exceptions/onvif_error_handlers.md b/docs/api/exceptions/onvif_error_handlers.md index 00d18d56..d0c3b882 100644 --- a/docs/api/exceptions/onvif_error_handlers.md +++ b/docs/api/exceptions/onvif_error_handlers.md @@ -1,8 +1,12 @@ -# Error Handlers +--- +comments: true +--- ::: onvif.utils.error_handlers options: + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members_order: source - heading_level: 3 \ No newline at end of file + heading_level: 2 \ No newline at end of file diff --git a/docs/api/exceptions/onvif_exception.md b/docs/api/exceptions/onvif_exception.md index 08fa6796..c9e50a2e 100644 --- a/docs/api/exceptions/onvif_exception.md +++ b/docs/api/exceptions/onvif_exception.md @@ -1,7 +1,11 @@ -# ONVIFOperationException +--- +comments: true +--- ::: onvif.utils.ONVIFOperationException options: + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members_order: source \ No newline at end of file diff --git a/docs/api/services/index.md b/docs/api/services/index.md index 085cc207..8ddfa347 100644 --- a/docs/api/services/index.md +++ b/docs/api/services/index.md @@ -95,7 +95,7 @@ Browse the ONVIF service clients exposed by `onvif-python`. Each service provide [:octicons-arrow-right-24: Receiver](receiver.md) -- :material-calendar-clock:{ .lg .middle }  **Automation & Scheduling** +- :material-automation:{ .lg .middle }  **Automation & Scheduling** --- diff --git a/docs/api/utilities/cache_mode.md b/docs/api/utilities/cache_mode.md index 36702271..530a9154 100644 --- a/docs/api/utilities/cache_mode.md +++ b/docs/api/utilities/cache_mode.md @@ -1,9 +1,13 @@ -# CacheMode +--- +comments: true +--- ::: onvif.operator.CacheMode options: + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members: true members_order: source - heading_level: 3 \ No newline at end of file + heading_level: 2 \ No newline at end of file diff --git a/docs/api/utilities/index.md b/docs/api/utilities/index.md index e31d613c..3f427aec 100644 --- a/docs/api/utilities/index.md +++ b/docs/api/utilities/index.md @@ -25,7 +25,7 @@ hide: Work with WSDL resources used to describe ONVIF service operations and their SOAP interfaces. -- :material-cog-outline:{ .lg .middle }  [**ONVIFService**](onvif_service.md) +- :material-network-node:{ .lg .middle }  [**ONVIFService**](onvif_service.md) --- diff --git a/docs/api/utilities/onvif_discovery.md b/docs/api/utilities/onvif_discovery.md index ef8646d9..113f2d58 100644 --- a/docs/api/utilities/onvif_discovery.md +++ b/docs/api/utilities/onvif_discovery.md @@ -1,11 +1,15 @@ -# ONVIFDiscovery +--- +comments: true +--- ::: onvif.utils.ONVIFDiscovery options: docstring_options: ignore_init_summary: true show_source: true + show_root_heading: true + show_root_full_path: true docstring_style: google members_order: source - heading_level: 3 + heading_level: 2 merge_init_into_class: true \ No newline at end of file diff --git a/docs/api/utilities/onvif_service.md b/docs/api/utilities/onvif_service.md index 18662bbe..2eb1ea56 100644 --- a/docs/api/utilities/onvif_service.md +++ b/docs/api/utilities/onvif_service.md @@ -1,8 +1,12 @@ -# ONVIFService +--- +comments: true +--- ::: onvif.utils.ONVIFService options: + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members_order: source - heading_level: 3 \ No newline at end of file + heading_level: 2 \ No newline at end of file diff --git a/docs/api/utilities/onvif_wsdl.md b/docs/api/utilities/onvif_wsdl.md index 38bd77be..c0ca6389 100644 --- a/docs/api/utilities/onvif_wsdl.md +++ b/docs/api/utilities/onvif_wsdl.md @@ -1,8 +1,12 @@ -# ONVIFWSDL +--- +comments: true +--- ::: onvif.utils.ONVIFWSDL options: + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members_order: source - heading_level: 3 \ No newline at end of file + heading_level: 2 \ No newline at end of file diff --git a/docs/api/utilities/plugins.md b/docs/api/utilities/plugins.md index 2cc54104..fb6338a9 100644 --- a/docs/api/utilities/plugins.md +++ b/docs/api/utilities/plugins.md @@ -1,10 +1,15 @@ -# Plugins +--- +comments: true +--- ::: onvif.utils.plugins options: docstring_options: ignore_init_summary: true + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members_order: source - merge_init_into_class: true \ No newline at end of file + merge_init_into_class: true + heading_level: 1 \ No newline at end of file diff --git a/docs/api/utilities/zeep_patcher.md b/docs/api/utilities/zeep_patcher.md index cb7d07bc..2a0c8464 100644 --- a/docs/api/utilities/zeep_patcher.md +++ b/docs/api/utilities/zeep_patcher.md @@ -1,8 +1,12 @@ -# ZeepPatcher +--- +comments: true +--- ::: onvif.utils.ZeepPatcher options: + show_root_heading: true + show_root_full_path: true show_source: true docstring_style: google members_order: source - heading_level: 3 \ No newline at end of file + heading_level: 2 \ No newline at end of file diff --git a/docs/approach.md b/docs/approach.md index 245f7799..1d5cb364 100644 --- a/docs/approach.md +++ b/docs/approach.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- !!! info diff --git a/docs/hooks/shortcodes.py b/docs/hooks/shortcodes.py index 18a36d0e..75217806 100644 --- a/docs/hooks/shortcodes.py +++ b/docs/hooks/shortcodes.py @@ -254,7 +254,7 @@ def _badge_for_onvif_version(args: str): return _badge( icon=f":{ICON_FOR_ONVIF_VERSION}:", - text=f"[`{version}`]({href})", + text=f"[`{version}`]({href}){{.no-external-icon }}", title="Minimum ONVIF version", ) diff --git a/docs/javascripts/external-links.js b/docs/javascripts/external-links.js index aec0fe63..dd6a699e 100644 --- a/docs/javascripts/external-links.js +++ b/docs/javascripts/external-links.js @@ -37,6 +37,11 @@ document$.subscribe(() => { link.target = '_blank'; link.rel = 'noopener noreferrer'; + // Do not add external icons inside source-code blocks. + if (link.closest('.highlight, .highlighttable, pre')) { + return; + } + if ( !link.classList.contains('no-external-icon') && !link.querySelector('.external-link-icon') @@ -51,7 +56,10 @@ document$.subscribe(() => { `; - link.appendChild(icon); + const code = link.querySelector('code'); + + // Place the icon inside inline code when present. + (code || link).appendChild(icon); } } }); diff --git a/docs/main/onvif_client.md b/docs/main/onvif_client.md index dde80048..1bf35271 100644 --- a/docs/main/onvif_client.md +++ b/docs/main/onvif_client.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- The [`ONVIFClient`](../api/core/onvif_client.md) class provides various configuration options to customize the connection behavior, caching strategy, security settings, and debugging capabilities. Below is a detailed description of all available parameters: diff --git a/docs/overrides/.icons/material/api.svg b/docs/overrides/.icons/material/api.svg deleted file mode 100644 index 7c2257a9..00000000 --- a/docs/overrides/.icons/material/api.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/overrides/.icons/material/automation.svg b/docs/overrides/.icons/material/automation.svg new file mode 100644 index 00000000..f18bde8d --- /dev/null +++ b/docs/overrides/.icons/material/automation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/.icons/material/category.svg b/docs/overrides/.icons/material/category.svg new file mode 100644 index 00000000..8caf507c --- /dev/null +++ b/docs/overrides/.icons/material/category.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/.icons/material/network-node.svg b/docs/overrides/.icons/material/network-node.svg new file mode 100644 index 00000000..1ad0cd19 --- /dev/null +++ b/docs/overrides/.icons/material/network-node.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/overrides/.icons/material/token.svg b/docs/overrides/.icons/material/token.svg deleted file mode 100644 index 51eaf49d..00000000 --- a/docs/overrides/.icons/material/token.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/overrides/partials/comments.html b/docs/overrides/partials/comments.html index 00648367..8190a640 100644 --- a/docs/overrides/partials/comments.html +++ b/docs/overrides/partials/comments.html @@ -1,20 +1,33 @@ {% if page.meta.comments %}

{{ lang.t("meta.comments") }}

- @@ -22,19 +35,21 @@

{{ lang.t("meta.comments") }}

function syncGiscusTheme() { var palette = __md_get("__palette"); - if (palette && typeof palette.color === "object") { - var theme = palette.color.scheme === "slate" - ? "dark" - : "light"; + if (!palette || typeof palette.color !== "object") { + return; + } + + var theme = palette.color.scheme === "slate" + ? "dark" + : "light"; - var frame = document.querySelector(".giscus-frame"); + var frame = document.querySelector(".giscus-frame"); - if (frame && frame.contentWindow) { - frame.contentWindow.postMessage( + if (frame && frame.contentWindow) { + frame.contentWindow.postMessage( { giscus: { setConfig: { theme: theme } } }, "https://giscus.app" - ); - } + ); } } diff --git a/docs/project/contributing.md b/docs/project/contributing.md index 9f63aca0..72066fba 100644 --- a/docs/project/contributing.md +++ b/docs/project/contributing.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- ## Contributors @@ -34,6 +35,13 @@ Share your experience with different ONVIF devices by contributing results to th ### Translations If you can help translate documentation or error messages, let us know! +## Reporting Issues + +- Search existing issues before opening a new one to avoid duplicates. +- Provide as much detail as possible: environment, device model, ONVIF version, error messages, and steps to reproduce. +- Attach logs, screenshots, or code snippets if relevant. +- Be polite and constructive; remember, maintainers and contributors are volunteers. + ## Development Setup ### Clone the repository and switch to dev branch @@ -106,7 +114,15 @@ Ensure your code follows PEP8 standards and is properly formatted. See the [`examples/`](https://github.com/nirsimetri/onvif-python/tree/dev/examples) folder for usage scenarios. -## Pull Request Guidelines +## Style Guide + +- **PEP8** is the standard for Python code style. Use tools like `pylint` and `black` to check and format your code. +- **Docstrings:** Use clear, concise docstrings for modules, classes, and functions. Use `docformatter` to format your docstring. +- **Type hints:** Add type annotations where appropriate for better readability and tooling support. +- **Comments:** Write helpful comments, especially for complex logic. +- **Naming:** Use descriptive variable, function, and class names. + +## Pull Request Guide ### PR Convention @@ -139,30 +155,15 @@ Use the following commit title types: ### General Guidelines -- **Describe your changes clearly** in the PR description. -- **Reference related issues** by number (e.g., `Fixes #123`). -- **Keep changes focused**—avoid mixing unrelated fixes or features in one PR. -- **Include tests** for new features or bug fixes when possible. -- **Follow the style guide** and ensure your code passes linting and tests. -- **Be responsive to review feedback** and update your PR as needed. -- **Squash commits** if requested, to keep history clean. - -## Reporting Issues - -- Search existing issues before opening a new one to avoid duplicates. -- Provide as much detail as possible: environment, device model, ONVIF version, error messages, and steps to reproduce. -- Attach logs, screenshots, or code snippets if relevant. -- Be polite and constructive—remember, maintainers and contributors are volunteers. - -## Style Guide - -- **PEP8** is the standard for Python code style. Use tools like `pylint` and `black` to check and format your code. -- **Docstrings:** Use clear, concise docstrings for modules, classes, and functions. Use `docformatter` to format your docstring. -- **Type hints:** Add type annotations where appropriate for better readability and tooling support. -- **Comments:** Write helpful comments, especially for complex logic. -- **Naming:** Use descriptive variable, function, and class names. +- **Describe your changes clearly** in the PR description. +- **Reference related issues** by number (e.g., `Fixes #123`). +- **Keep changes focused**—avoid mixing unrelated fixes or features in one PR. +- **Include tests** for new features or bug fixes when possible. +- **Follow the style guide** and ensure your code passes linting and tests. +- **Be responsive to review feedback** and update your PR as needed. +- **Squash commits** if requested, to keep history clean. -## Documentation +## Documentation Guide The documentation is built with [MkDocs Material](https://squidfunk.github.io/mkdocs-material/) and [mkdocstrings](https://mkdocstrings.github.io/) to generate API documentation directly from the Python source code. diff --git a/docs/project/roadmap.md b/docs/project/roadmap.md index 44d46266..e2ab70fe 100644 --- a/docs/project/roadmap.md +++ b/docs/project/roadmap.md @@ -15,5 +15,5 @@ hide: - [ ] Add asynchronous (`async`/`await`) support for non-blocking operations - [ ] Implement structured data models for ONVIF Schemas using [xsdata](https://github.com/tefra/xsdata) - [ ] Implement operation tracking based on the device's ONVIF version -- [ ] Add automated comprehensive tests for ONVIF device capabilities +- [ ] Add automated comprehensive checks for ONVIF device capabilities - [ ] Add benchmarking and performance metrics \ No newline at end of file diff --git a/docs/project/used_by.md b/docs/project/used_by.md index f52a6293..949655e3 100644 --- a/docs/project/used_by.md +++ b/docs/project/used_by.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- With Total Downloads, the `onvif-python` library is already being used by several well-known open-source projects, including: diff --git a/docs/quick_start.md b/docs/quick_start.md index 724d8138..b31d71b5 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- Below are simple examples to help you get started with the ONVIF Python library. These demonstrate how to discover and connect to ONVIF-compliant devices and retrieve basic device information. diff --git a/docs/references/implemented_services.md b/docs/references/implemented_services.md index 903fc2f0..73fa63de 100644 --- a/docs/references/implemented_services.md +++ b/docs/references/implemented_services.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- Below is a list of ONVIF services implemented and supported by this library, along with links to the official specifications, service definitions, and schema files as referenced from the [ONVIF Developer Specs](https://developer.onvif.org/pub/specs/branches/development/doc/index.html). diff --git a/docs/references/index.md b/docs/references/index.md index 1b851b93..58a07cf1 100644 --- a/docs/references/index.md +++ b/docs/references/index.md @@ -7,7 +7,7 @@ hide:
-- :material-token:{ .lg .middle }  **ONVIF Profiles** +- :material-category:{ .lg .middle }  **ONVIF Profiles** --- @@ -16,7 +16,7 @@ hide: --- [:octicons-arrow-right-24: Supported Profiles](supported_profiles.md) -- :material-api:{ .lg .middle }  **ONVIF Services** +- :material-network-node:{ .lg .middle }  **ONVIF Services** --- diff --git a/docs/references/service_bindings.md b/docs/references/service_bindings.md index 7db24caa..a555a68d 100644 --- a/docs/references/service_bindings.md +++ b/docs/references/service_bindings.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- ONVIF services are defined by WSDL bindings. In this library, there are two main patterns: diff --git a/docs/references/service_discovery.md b/docs/references/service_discovery.md index c70149a9..38dc5905 100644 --- a/docs/references/service_discovery.md +++ b/docs/references/service_discovery.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- !!! warning diff --git a/docs/references/supported_profiles.md b/docs/references/supported_profiles.md index 7cd73545..58f92f4d 100644 --- a/docs/references/supported_profiles.md +++ b/docs/references/supported_profiles.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- This library fully supports all major ONVIF Profiles listed below. Each profile represents a standardized set of features and use cases, ensuring interoperability between ONVIF-compliant devices and clients. You can use this library to integrate with devices and systems that implement any of these profiles. diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index a151e7e5..6a152bb3 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -12,6 +12,9 @@ } [data-md-color-scheme="slate"] { + /* Background */ + --md-default-bg-color: #0a1224; + /* Primary */ --md-primary-fg-color: #002266; --md-typeset-a-color: #60a5fa; @@ -53,14 +56,18 @@ } .external-link-icon { - display: inline-block; + display: inline-flex; width: 0.8em; height: 0.8em; - margin-left: 0.1em; + margin-left: 0.15em; vertical-align: -0.05em; + align-items: center; + justify-content: center; + flex-shrink: 0; } .external-link-icon svg { + display: block; width: 100%; height: 100%; fill: currentColor; diff --git a/docs/utilities/helper_methods.md b/docs/utilities/helper_methods.md index 92f24d82..2d32bb23 100644 --- a/docs/utilities/helper_methods.md +++ b/docs/utilities/helper_methods.md @@ -1,6 +1,7 @@ --- hide: - path +comments: true --- Every ONVIF service provides **four** essential helper methods to improve the development experience and make working with ONVIF operations more intuitive: diff --git a/mkdocs.yml b/mkdocs.yml index eab72122..a417ae63 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -189,13 +189,20 @@ plugins: - mkdocstrings: handlers: python: + inventories: + - https://docs.python.org/3/objects.inv + - https://docs.python-zeep.org/en/master/objects.inv options: show_source: false show_labels: true docstring_style: google show_root_full_path: false show_root_toc_entry: false + show_signature: true show_signature_annotations: true + separate_signature: true + signature_crossrefs: true + show_attribute_values: true show_symbol_type_toc: true show_symbol_type_heading: true extensions: From 876af35b896edfe866d95b96dd6c45364bbf016c Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 18:37:51 +0700 Subject: [PATCH 36/38] docs: Improve documentation clarity --- onvif/client.py | 8 +++++--- onvif/operator.py | 2 +- onvif/utils/exceptions.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/onvif/client.py b/onvif/client.py index 8468a88b..138632c2 100644 --- a/onvif/client.py +++ b/onvif/client.py @@ -73,7 +73,7 @@ def service(func: Callable[P, R]) -> Callable[P, R]: ONVIF client service accessors. Args: - func: Service accessor method to wrap. + func (Callable): Service accessor method to wrap. Returns: Wrapped service accessor method. @@ -113,8 +113,10 @@ class ONVIFClient: This is the main class for interacting with ONVIF devices. It provides access to all ONVIF services including Device Management, Media, PTZ, Events, Analytics, and more. - The client automatically discovers available services on the device using `GetServices` - or `GetCapabilities`, and provides lazy initialization for service endpoints. + The client automatically discovers available services on the device using + [`GetServices`](../services/device.md#onvif.services.devicemgmt.Device.GetServices) or + [`GetCapabilities`](../services/device.md#onvif.services.devicemgmt.Device.GetCapabilities), + and provides lazy initialization for service endpoints. Attributes: services (list | None): List of available services from `GetServices` response diff --git a/onvif/operator.py b/onvif/operator.py index 28ea6ed1..6005578e 100644 --- a/onvif/operator.py +++ b/onvif/operator.py @@ -29,7 +29,7 @@ class CacheMode(Enum): """ - + WSDL caching strategies for ONVIF client performance optimization. diff --git a/onvif/utils/exceptions.py b/onvif/utils/exceptions.py index 61307386..6dbe2368 100644 --- a/onvif/utils/exceptions.py +++ b/onvif/utils/exceptions.py @@ -11,7 +11,7 @@ class ONVIFOperationException(Exception): # pylint: disable=line-too-long """ - + Enhanced exception wrapper for ONVIF operation failures. From e82e7a6e2d46f8011f20f36150fa09e6ac28fcc6 Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 18:39:40 +0700 Subject: [PATCH 37/38] docs: Spelling fix --- docs/hooks/griffe_extensions.py | 2 +- docs/hooks/shortcodes.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hooks/griffe_extensions.py b/docs/hooks/griffe_extensions.py index be2dc771..bc411648 100644 --- a/docs/hooks/griffe_extensions.py +++ b/docs/hooks/griffe_extensions.py @@ -1,4 +1,4 @@ -"""Griffe extentions.""" +"""Griffe extensions.""" from __future__ import annotations diff --git a/docs/hooks/shortcodes.py b/docs/hooks/shortcodes.py index 75217806..2c78b421 100644 --- a/docs/hooks/shortcodes.py +++ b/docs/hooks/shortcodes.py @@ -226,7 +226,7 @@ def _badge(icon: str, text: str = "", type: str = "", title: str = ""): ) -# Create badge for pacakge version +# Create badge for package version def _badge_for_version(text: str, page: Page | None = None, files: Files | None = None): path = f"releases.md#v{text}" From e2380d7a02f47f2d602db59bfdb04bc9f14457cb Mon Sep 17 00:00:00 2001 From: kaburagisec <135169292+kaburagisec@users.noreply.github.com> Date: Sat, 17 Oct 2026 18:48:14 +0700 Subject: [PATCH 38/38] ci: Revert python version --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 24dc03f2..4fcc1a2d 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -26,7 +26,7 @@ jobs: - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: - python-version: "3.x" + python-version: "3.12" - name: Install documentation dependencies run: |