Releases: nirsimetri/onvif-python
v0.0.5 — 2025-10-12
Overview
This release introduces two major improvements to the ONVIF client library:
- Enhanced Zeep
xsd:anyParser: Improved parsing of XML elements with attributes, enabling proper data extraction from complex ONVIF responses - Service Discovery Migration: Changed from
GetCapabilitiestoGetServicesfor more reliable and accurate service endpoint resolution
Changelog Summary
PyPI
https://pypi.org/project/onvif-python/0.0.5 (18434660509)
Changed
- Service endpoint resolution now uses
GetServicesinstead ofGetCapabilities(60e3496) (6211651) - Enhanced
flatten_xsd_any_fieldsto preserve nested structures (8d24b9a)
Fixed
GetServices(IncludeCapability=True)returningNonefor capability fields (2284db9)
Full Changelog: v0.0.4...v0.0.5
v0.0.4 — 2025-10-11
Added
1. Smart XML Text Value Parser (parse_text_value) (e1995d6)
A new utility function that intelligently converts XML text values to appropriate Python types (boolean, integer, float, or string).
Features:
- Automatic type detection and conversion
- Handles boolean values (
"true"→True,"false"→False) - Converts numeric strings to
intorfloat - Falls back to string for non-numeric values
Example:
from onvif.utils.zeep import parse_text_value
# Boolean conversion
result = parse_text_value("true") # Returns: True
result = parse_text_value("false") # Returns: False
# Numeric conversion
result = parse_text_value("42") # Returns: 42 (int)
result = parse_text_value("3.14") # Returns: 3.14 (float)
# String fallback
result = parse_text_value("hello") # Returns: "hello" (str)2. XSD Any Fields Flattening (flatten_xsd_any_fields) (e1995d6)
A powerful post-processing function that automatically extracts and populates data from zeep's _value_N fields (xsd:any with maxOccurs) into their proper attributes.
Features:
- Recursively processes all zeep objects
- Handles multiple
_value_Nfields (_value_1, _value_2, _value_3, etc.) - Preserves original XML Elements in
_value_Nfields - Prevents infinite recursion with visited object tracking
- Maintains zeep object structure (no dict conversion)
Problem Solved:
Before this feature, ONVIF Extension fields like DeviceIO, AudioSource, etc., would be None even though the data existed in _value_1 as XML elements.
Example:
from onvif import ONVIFClient
# Create client (flatten_xsd_any_fields is automatically applied)
client = ONVIFClient('192.168.1.100', 80, 'admin', 'password')
# Get capabilities
capabilities = client.devicemgmt.GetCapabilities()
# Before v0.0.4: capabilities.Extension.DeviceIO would be None
# After v0.0.4: capabilities.Extension.DeviceIO is now populated!
print(capabilities.Extension.DeviceIO.XAddr)
# Output: http://192.168.1.100:80/onvif/device_io_service
# The original XML Elements are preserved
print(capabilities.Extension._value_1)
# Output: [<Element {http://www.onvif.org/ver10/schema}DeviceIO at 0x...>]
# Works recursively with nested extensions
print(capabilities.Extension.DeviceIO.RelayOutputs)
print(capabilities.Extension.DeviceIO.RelayOutputs[0].Properties.Mode)Manual Usage:
from onvif.utils.zeep import flatten_xsd_any_fields
# Manually process a zeep object
flattened_result = flatten_xsd_any_fields(some_zeep_object)3. Optional Zeep Patching (apply_patch Parameter) (e1995d6)
A new optional parameter in ONVIFClient that gives you control over whether to apply the zeep monkey patch and automatic flattening.
Features:
- Control patching behavior at client initialization
- Default is
True(patched behavior with automatic flattening) - Set to
Falseto use original zeep behavior - Global patch management functions:
apply_patch(),remove_patch(),is_patched()
Example:
from onvif import ONVIFClient
# Default behavior - with patch and automatic flattening
client = ONVIFClient('192.168.1.100', 80, 'admin', 'password')
capabilities = client.devicemgmt.GetCapabilities()
print(capabilities.Extension.DeviceIO) # Populated automatically
# Output: {'XAddr': 'http://192.168.1.100:80/onvif/device_io_service', ...}
# Without patch - original zeep behavior
client = ONVIFClient(
'192.168.1.100', 80, 'admin', 'password',
apply_patch=False
)
capabilities = client.devicemgmt.GetCapabilities()
print(capabilities.Extension.DeviceIO) # None
print(capabilities.Extension._value_1) # Data is here as XML Elements
# Output: [<Element {http://www.onvif.org/ver10/schema}DeviceIO at 0x...>]Global Patch Management:
from onvif import apply_patch, remove_patch, is_patched
# Check if patch is currently applied
if is_patched():
print("Zeep is patched")
# Manually apply patch
apply_patch()
# Manually remove patch
remove_patch()
# Check again
if not is_patched():
print("Zeep is unpatched")Changed
- Modified
ONVIFOperatorto support conditional flattening viaapply_flattenparameter - Enhanced monkey patch to store original XML Elements before parsing
- Improved handling of xsd:any elements with maxOccurs > 1
Technical Details
Zeep Internal Structure:
- Zeep objects use
__values__OrderedDict internally (not__dict__) - xsd:any elements are stored as
_value_1,_value_2, etc. - Original XML Elements are preserved in
__original_elements__during patching
Backward Compatibility:
- All changes are backward compatible
- Default behavior provides enhanced functionality
- Original zeep behavior available via
apply_patch=False
Migration Guide
No migration required. The default behavior now includes automatic flattening, which improves the usability of ONVIF Extension fields. If you need the original behavior, simply set apply_patch=False when creating the ONVIFClient.
PyPI
https://pypi.org/project/onvif-python/0.0.4 (18424895514)
Full Changelog: v0.0.3...v0.0.4
v0.0.3 — 2025-10-11
PyPI
https://pypi.org/project/onvif-python/0.0.3
Fixed
- Fix issue Incorrect call "DeleteKey" in CreatePKCS10CSR (#2) (7b9685f) at
Keystoreservice. Reported by @hsunner
Full Changelog: v0.0.2...v0.0.3
v0.0.2 — 2025-09-27
PyPI
https://pypi.org/project/onvif-python/0.0.2
Added
- Improved
xsd:anyparsing logic for child elements, allowing automatic dictionary conversion of ONVIF<Extension>blocks (via monkey patch onparse_xmlelements) (fce868e)
→ This implements behavior proposed in python-zeep#1473
→ Since the PR is not yet merged, this version includes a local monkey patch applied at runtime tozeep.xsd.elements.any.Any.parse_xmlelements
Fixed
ONVIFClient._get_xaddr()now supports resolving service addresses (XAddr) from nested_value_1dictionaries (common in normalized extensions) (4292fc4)- Added support for overriding
XAddrhost/port when device is behind NAT or proxy (d5f5b1e) - Changed fallback
service_pathforSearchservice to improve compatibility with some ONVIF devices (d5f5b1e)
Comparison
These improvements make this version of onvif-python significantly more capable in handling dynamic ONVIF service extensions than other popular forks such as:
...which still rely on the unpatched version of Zeep and require manual parsing of xsd:any elements.
Full Changelog: v0.0.1...v0.0.2
v0.0.1 — 2025-09-25
PyPI
https://pypi.org/project/onvif-python/0.0.1
Initial Release
- First public release of the ONVIF Python Library!
- Implements core ONVIF services: Device Management, Media, PTZ, Imaging, Events, Recording, and more.
- Supports ONVIF Profiles S, G, T, C, A, D, M.
- Provides a Pythonic API that wraps SOAP/XML communication for easy integration.
- Includes example scripts and tests for various ONVIF devices.
- Basic documentation and badges for PyPI, DeepWiki, and total downloads.
- Compatible with a wide range of ONVIF devices and firmware versions.
Please report bugs, suggestions, or contribute via GitHub Issues!