onvif-python 0.3.1__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {onvif_python-0.3.1/onvif_python.egg-info → onvif_python-0.4.0}/PKG-INFO +18 -8
- {onvif_python-0.3.1 → onvif_python-0.4.0}/README.md +10 -4
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/__init__.py +6 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/helpers/discovery.py +38 -6
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/helpers/files.py +17 -15
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/helpers/messages.py +3 -4
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/helpers/products.py +2 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/helpers/wsdl_parser.py +9 -4
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/interactive.py +7 -13
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/main.py +10 -4
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/utils.py +2 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/client.py +35 -25
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/meta.py +2 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/operator.py +73 -41
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/accesscontrol.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/accessrules.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/actionengine.py +2 -1
- onvif_python-0.4.0/onvif/services/analytics/__init__.py +1 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/analytics/analytics.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/analytics/ruleengine.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/analyticsdevice.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/appmgmt.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/authenticationbehavior.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/credential.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/deviceio.py +3 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/devicemgmt.py +5 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/display.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/doorcontrol.py +2 -1
- onvif_python-0.4.0/onvif/services/events/__init__.py +1 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/events/events.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/events/notification.py +5 -19
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/events/pausable_subscription.py +9 -5
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/events/pullpoint.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/events/subscription.py +6 -5
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/imaging.py +6 -3
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/media.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/media2.py +3 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/provisioning.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/ptz.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/receiver.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/recording.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/replay.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/schedule.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/search.py +9 -1
- onvif_python-0.4.0/onvif/services/security/__init__.py +1 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/security/advancedsecurity.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/security/authorizationserver.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/security/dot1x.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/security/jwt.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/security/keystore.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/security/mediasigning.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/security/tlsserver.py +3 -2
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/thermal.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/uplink.py +2 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/utils/__init__.py +9 -4
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/utils/discovery.py +132 -18
- onvif_python-0.4.0/onvif/utils/error_handlers.py +237 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/utils/exceptions.py +56 -41
- onvif_python-0.4.0/onvif/utils/plugins.py +500 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/utils/service.py +103 -84
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/utils/wsdl.py +61 -32
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/utils/zeep.py +262 -274
- {onvif_python-0.3.1 → onvif_python-0.4.0/onvif_python.egg-info}/PKG-INFO +18 -8
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif_python.egg-info/SOURCES.txt +0 -1
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif_python.egg-info/requires.txt +6 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/pyproject.toml +42 -6
- {onvif_python-0.3.1 → onvif_python-0.4.0}/tests/test_client.py +44 -60
- {onvif_python-0.3.1 → onvif_python-0.4.0}/tests/test_core.py +13 -34
- {onvif_python-0.3.1 → onvif_python-0.4.0}/tests/test_error_handlers.py +86 -70
- {onvif_python-0.3.1 → onvif_python-0.4.0}/tests/test_exceptions.py +16 -16
- onvif_python-0.3.1/onvif/services/analytics/__init__.py +0 -0
- onvif_python-0.3.1/onvif/services/events/__init__.py +0 -0
- onvif_python-0.3.1/onvif/services/security/__init__.py +0 -0
- onvif_python-0.3.1/onvif/utils/error_handlers.py +0 -130
- onvif_python-0.3.1/onvif/utils/plugins.py +0 -172
- onvif_python-0.3.1/onvif/utils/xml_capture.py +0 -219
- {onvif_python-0.3.1 → onvif_python-0.4.0}/LICENSE.md +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/MANIFEST.in +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/__init__.py +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/__main__.py +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/helpers/__init__.py +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/cli/helpers/execution.py +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/db/companies.db +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/db/products.db +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/services/__init__.py +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/LICENSE.md +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/b-2.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/bf-2.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/bw-2.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/include +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/mpqf.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/r-2.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/rw-2.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/soap-envelope +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/t-1.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/ws-addr.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/xml.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/schema/common/xmlmime +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/accesscontrol/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/accessrules/wsdl/accessrules.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/accessrules/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/actionengine.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/advancedsecurity/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/analyticsdevice.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/appmgmt/wsdl/appmgmt.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/appmgmt/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/authenticationbehavior/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/credential/wsdl/credential.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/credential/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/device/wsdl/devicemgmt.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/deviceio.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/display/display.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/display/wsdl/index.htm +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/display.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/doorcontrol/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/events/wsdl/bw-2-vs-mod.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/events/wsdl/event-vs.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/events/wsdl/event.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/events/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/federatedsearch.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/pacs/accesscontrol.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/pacs/doorcontrol.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/pacs/types.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/provisioning/wsdl/provisioning.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/receiver.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/recording.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/replay.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/schedule/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/schedule/wsdl/schedule.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/schema/common.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/schema/metadatastream.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/schema/onvif.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/search.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/thermal/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/thermal/wsdl/thermal.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/topics/topicns.xml +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/uplink/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver10/uplink/wsdl/uplink.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/analytics/humanbody.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/analytics/humanface.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/analytics/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/analytics/radiometry.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/analytics/rules.xsd +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/analytics/wsdl/analytics.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/analytics/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/imaging/wsdl/imaging.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/media/wsdl/index.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/media/wsdl/media.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/ptz/wsdl/ptz.wsdl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/util/federated_search_documentation.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/util/fedsearch-docu-viewer.xsl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/util/onvif-wsdl-viewer.xsl +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif/wsdl/ver20/util/operationIndex.html +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif_python.egg-info/dependency_links.txt +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif_python.egg-info/entry_points.txt +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/onvif_python.egg-info/top_level.txt +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/setup.cfg +0 -0
- {onvif_python-0.3.1 → onvif_python-0.4.0}/setup.py +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onvif-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A modern Python library for ONVIF-compliant devices
|
|
5
5
|
Author-email: Nirsimetri Technologies® <open@nirsimetri.com>
|
|
6
6
|
Maintainer: Kaburagi
|
|
7
7
|
License-Expression: MIT
|
|
8
8
|
Project-URL: Homepage, https://github.com/nirsimetri/onvif-python
|
|
9
|
-
Project-URL: Documentation, https://
|
|
9
|
+
Project-URL: Documentation, https://nirsimetri.github.io/onvif-python
|
|
10
10
|
Project-URL: Changelog, https://github.com/nirsimetri/onvif-python/releases
|
|
11
11
|
Keywords: onvif,Camera,onvif-python,ip-camera,cctv,soap,surveillance,cctv cameras,soap-client,onvif-client,onvif-library,onvif-specifications
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Environment :: Console
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -30,7 +29,7 @@ Classifier: Topic :: Communications
|
|
|
30
29
|
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
31
30
|
Classifier: Natural Language :: English
|
|
32
31
|
Classifier: Natural Language :: Indonesian
|
|
33
|
-
Requires-Python: >=3.
|
|
32
|
+
Requires-Python: >=3.10
|
|
34
33
|
Description-Content-Type: text/markdown
|
|
35
34
|
License-File: LICENSE.md
|
|
36
35
|
Requires-Dist: zeep>=4.3.0
|
|
@@ -38,18 +37,23 @@ Requires-Dist: requests>=2.32.0
|
|
|
38
37
|
Requires-Dist: pyreadline3>=3.5.4; sys_platform == "win32"
|
|
39
38
|
Provides-Extra: dev
|
|
40
39
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
41
41
|
Requires-Dist: black; extra == "dev"
|
|
42
42
|
Requires-Dist: mypy; extra == "dev"
|
|
43
43
|
Requires-Dist: isort; extra == "dev"
|
|
44
44
|
Requires-Dist: pylint; extra == "dev"
|
|
45
45
|
Requires-Dist: docformatter; extra == "dev"
|
|
46
|
+
Provides-Extra: docs
|
|
47
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
48
|
+
Requires-Dist: mkdocstrings[python]; extra == "docs"
|
|
49
|
+
Requires-Dist: mkdocs-git-authors-plugin; extra == "docs"
|
|
46
50
|
Dynamic: license-file
|
|
47
51
|
|
|
48
52
|
<h1 align="center">ONVIF Python</h1>
|
|
49
53
|
|
|
50
54
|
<div align="center">
|
|
51
55
|
<a href="https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://img.shields.io/codacy/grade/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Code%20Quality"/></a>
|
|
52
|
-
<a href="https://pypi.org/project/onvif-python/"><img alt="PyPI Version" src="https://img.shields.io/badge/Version-0.
|
|
56
|
+
<a href="https://pypi.org/project/onvif-python/"><img alt="PyPI Version" src="https://img.shields.io/badge/Version-0.4.0-orange?logo=python&logoColor=white&color=yellow&style=plastic"></a>
|
|
53
57
|
<a href="https://pepy.tech/projects/onvif-python"><img alt="Pepy Total Downloads" src="https://img.shields.io/pepy/dt/onvif-python?logo=pypi&logoColor=white&label=Downloads&color=red&style=plastic"></a>
|
|
54
58
|
<br>
|
|
55
59
|
<a href="https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml"><img alt="Build" src="https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml/badge.svg?branch=main"></a>
|
|
@@ -76,7 +80,7 @@ This library simplifies that process by wrapping SOAP communication into a clean
|
|
|
76
80
|
|
|
77
81
|
## Requirements
|
|
78
82
|
|
|
79
|
-
- **Python**: 3.
|
|
83
|
+
- **Python**: 3.10 or higher
|
|
80
84
|
- **Dependencies**:
|
|
81
85
|
- [`zeep>=4.3.0`](https://github.com/mvantellingen/python-zeep) - SOAP client for ONVIF communication
|
|
82
86
|
- [`requests>=2.32.0`](https://github.com/psf/requests) - HTTP library for network requests
|
|
@@ -84,16 +88,22 @@ This library simplifies that process by wrapping SOAP communication into a clean
|
|
|
84
88
|
## Installation
|
|
85
89
|
|
|
86
90
|
From official [PyPI](https://pypi.org/project/onvif-python/):
|
|
87
|
-
```
|
|
91
|
+
```shell
|
|
88
92
|
pip install --upgrade onvif-python
|
|
89
93
|
```
|
|
94
|
+
|
|
90
95
|
Or clone this repository and install locally:
|
|
91
|
-
```
|
|
96
|
+
```shell
|
|
92
97
|
git clone https://github.com/nirsimetri/onvif-python
|
|
93
98
|
cd onvif-python
|
|
94
99
|
pip install .
|
|
95
100
|
```
|
|
96
101
|
|
|
102
|
+
Once the installation is successful, you can also immediately access the [ONVIF CLI](https://nirsimetri.github.io/onvif-python/core/onvif_cli/) via the terminal using:
|
|
103
|
+
```shell
|
|
104
|
+
onvif --help
|
|
105
|
+
```
|
|
106
|
+
|
|
97
107
|
## Documentation
|
|
98
108
|
|
|
99
109
|
For complete guide, including usage examples and API references, please visit the [Documentation Page](https://nirsimetri.github.io/onvif-python/).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
<a href="https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img src="https://img.shields.io/codacy/grade/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Code%20Quality"/></a>
|
|
5
|
-
<a href="https://pypi.org/project/onvif-python/"><img alt="PyPI Version" src="https://img.shields.io/badge/Version-0.
|
|
5
|
+
<a href="https://pypi.org/project/onvif-python/"><img alt="PyPI Version" src="https://img.shields.io/badge/Version-0.4.0-orange?logo=python&logoColor=white&color=yellow&style=plastic"></a>
|
|
6
6
|
<a href="https://pepy.tech/projects/onvif-python"><img alt="Pepy Total Downloads" src="https://img.shields.io/pepy/dt/onvif-python?logo=pypi&logoColor=white&label=Downloads&color=red&style=plastic"></a>
|
|
7
7
|
<br>
|
|
8
8
|
<a href="https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml"><img alt="Build" src="https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml/badge.svg?branch=main"></a>
|
|
@@ -29,7 +29,7 @@ This library simplifies that process by wrapping SOAP communication into a clean
|
|
|
29
29
|
|
|
30
30
|
## Requirements
|
|
31
31
|
|
|
32
|
-
- **Python**: 3.
|
|
32
|
+
- **Python**: 3.10 or higher
|
|
33
33
|
- **Dependencies**:
|
|
34
34
|
- [`zeep>=4.3.0`](https://github.com/mvantellingen/python-zeep) - SOAP client for ONVIF communication
|
|
35
35
|
- [`requests>=2.32.0`](https://github.com/psf/requests) - HTTP library for network requests
|
|
@@ -37,16 +37,22 @@ This library simplifies that process by wrapping SOAP communication into a clean
|
|
|
37
37
|
## Installation
|
|
38
38
|
|
|
39
39
|
From official [PyPI](https://pypi.org/project/onvif-python/):
|
|
40
|
-
```
|
|
40
|
+
```shell
|
|
41
41
|
pip install --upgrade onvif-python
|
|
42
42
|
```
|
|
43
|
+
|
|
43
44
|
Or clone this repository and install locally:
|
|
44
|
-
```
|
|
45
|
+
```shell
|
|
45
46
|
git clone https://github.com/nirsimetri/onvif-python
|
|
46
47
|
cd onvif-python
|
|
47
48
|
pip install .
|
|
48
49
|
```
|
|
49
50
|
|
|
51
|
+
Once the installation is successful, you can also immediately access the [ONVIF CLI](https://nirsimetri.github.io/onvif-python/core/onvif_cli/) via the terminal using:
|
|
52
|
+
```shell
|
|
53
|
+
onvif --help
|
|
54
|
+
```
|
|
55
|
+
|
|
50
56
|
## Documentation
|
|
51
57
|
|
|
52
58
|
For complete guide, including usage examples and API references, please visit the [Documentation Page](https://nirsimetri.github.io/onvif-python/).
|
|
@@ -6,10 +6,12 @@ from onvif.operator import CacheMode
|
|
|
6
6
|
from onvif.utils import (
|
|
7
7
|
ONVIFWSDL,
|
|
8
8
|
ONVIFDiscovery,
|
|
9
|
-
ONVIFErrorHandler,
|
|
10
9
|
ONVIFOperationException,
|
|
11
10
|
ONVIFParser,
|
|
12
11
|
ZeepPatcher,
|
|
12
|
+
ignore_unsupported,
|
|
13
|
+
is_action_not_supported,
|
|
14
|
+
safe_call,
|
|
13
15
|
)
|
|
14
16
|
|
|
15
17
|
__all__ = [
|
|
@@ -17,9 +19,11 @@ __all__ = [
|
|
|
17
19
|
"CacheMode",
|
|
18
20
|
"ONVIFWSDL",
|
|
19
21
|
"ONVIFOperationException",
|
|
20
|
-
"ONVIFErrorHandler",
|
|
21
22
|
"ZeepPatcher",
|
|
22
23
|
"ONVIFCLI",
|
|
23
24
|
"ONVIFDiscovery",
|
|
24
25
|
"ONVIFParser",
|
|
26
|
+
"ignore_unsupported",
|
|
27
|
+
"is_action_not_supported",
|
|
28
|
+
"safe_call",
|
|
25
29
|
]
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""ONVIF discovery helpers."""
|
|
2
2
|
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
3
5
|
from onvif.cli.utils import colorize
|
|
4
6
|
from onvif.utils import ONVIFDiscovery
|
|
5
7
|
|
|
@@ -16,7 +18,7 @@ def discover_devices(
|
|
|
16
18
|
timeout (int): Discovery timeout in seconds
|
|
17
19
|
interface (str | None): Network interface to use for discovery
|
|
18
20
|
prefer_https (bool): If True, prioritize HTTPS XAddrs when available
|
|
19
|
-
filter_term (str | None): Optional search term to filter devices by types or scopes
|
|
21
|
+
filter_term (str | None): Optional search term to filter devices by types or scopes (case-insensitive)
|
|
20
22
|
|
|
21
23
|
Returns:
|
|
22
24
|
List of discovered devices with connection info
|
|
@@ -36,6 +38,7 @@ def discover_devices(
|
|
|
36
38
|
return devices
|
|
37
39
|
|
|
38
40
|
|
|
41
|
+
# pylint: disable=too-many-locals,too-many-statements,too-many-branches
|
|
39
42
|
def select_device_interactive(devices: list) -> tuple[str, int, bool] | None:
|
|
40
43
|
"""Display devices and allow user to select one interactively.
|
|
41
44
|
|
|
@@ -70,15 +73,43 @@ def select_device_interactive(devices: list) -> tuple[str, int, bool] | None:
|
|
|
70
73
|
epr_display = epr_display.replace("uuid:", "")
|
|
71
74
|
print(f" [uuid] {epr_display}")
|
|
72
75
|
|
|
73
|
-
if device
|
|
76
|
+
if device.get("hostname"):
|
|
77
|
+
print(f" [hostname] {device["hostname"]}")
|
|
78
|
+
|
|
79
|
+
if device.get("xaddrs"):
|
|
74
80
|
xaddrs_parts = [f"[{xaddr}]" for xaddr in device["xaddrs"]]
|
|
75
81
|
print(f" [xaddrs] {' '.join(xaddrs_parts)}")
|
|
76
82
|
|
|
77
|
-
if device
|
|
83
|
+
if device.get("date_time"):
|
|
84
|
+
utc = (
|
|
85
|
+
datetime.fromisoformat(device["date_time"].get("utc")).strftime(
|
|
86
|
+
"%H:%M:%S %d-%m-%Y"
|
|
87
|
+
)
|
|
88
|
+
if device["date_time"].get("utc")
|
|
89
|
+
else ""
|
|
90
|
+
)
|
|
91
|
+
local = (
|
|
92
|
+
datetime.fromisoformat(device["date_time"].get("local")).strftime(
|
|
93
|
+
"%H:%M:%S %d-%m-%Y"
|
|
94
|
+
)
|
|
95
|
+
if device["date_time"].get("local")
|
|
96
|
+
else ""
|
|
97
|
+
)
|
|
98
|
+
print(
|
|
99
|
+
f" [date_time]"
|
|
100
|
+
f'{" [UTC: " + utc + "]" if utc else ""}'
|
|
101
|
+
f'{" [Local: " + local + "]" if local else ""}'
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if device.get("types"):
|
|
78
105
|
types_parts = [f"[{t}]" for t in device["types"]]
|
|
79
106
|
print(f" [types] {' '.join(types_parts)}")
|
|
80
107
|
|
|
81
|
-
if device
|
|
108
|
+
if device.get("services"):
|
|
109
|
+
service = [colorize(f"[{t}]", "cyan") for t in device["services"]]
|
|
110
|
+
print(f" [services] {' '.join(service)}")
|
|
111
|
+
|
|
112
|
+
if device.get("scopes"):
|
|
82
113
|
scope_parts = []
|
|
83
114
|
for scope in device["scopes"]:
|
|
84
115
|
# Remove the prefix "onvif://www.onvif.org/" if present
|
|
@@ -110,13 +141,14 @@ def select_device_interactive(devices: list) -> tuple[str, int, bool] | None:
|
|
|
110
141
|
print(
|
|
111
142
|
f"\n{colorize('Selected:', 'green')} {colorize(protocol, 'cyan')}://{colorize(host_port, 'yellow')}"
|
|
112
143
|
)
|
|
144
|
+
|
|
113
145
|
return (
|
|
114
146
|
selected["host"],
|
|
115
147
|
selected["port"],
|
|
116
148
|
selected.get("use_https", False),
|
|
117
149
|
)
|
|
118
|
-
|
|
119
|
-
|
|
150
|
+
|
|
151
|
+
print(colorize("Invalid selection. Please try again.", "red"))
|
|
120
152
|
|
|
121
153
|
except ValueError:
|
|
122
154
|
print(colorize("Invalid input. Please enter a number.", "red"))
|
|
@@ -102,6 +102,7 @@ def save_output_to_file(
|
|
|
102
102
|
print(str(result))
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
# pylint: disable=too-many-return-statements,too-many-branches,too-many-nested-blocks
|
|
105
106
|
def _serialize_for_json(obj: Any) -> Any:
|
|
106
107
|
"""Recursively serialize ONVIF objects for JSON output.
|
|
107
108
|
|
|
@@ -113,17 +114,17 @@ def _serialize_for_json(obj: Any) -> Any:
|
|
|
113
114
|
"""
|
|
114
115
|
if obj is None:
|
|
115
116
|
return None
|
|
116
|
-
|
|
117
|
+
if isinstance(obj, (str, int, float, bool)):
|
|
117
118
|
return obj
|
|
118
|
-
|
|
119
|
+
if isinstance(obj, datetime):
|
|
119
120
|
return obj.isoformat()
|
|
120
|
-
|
|
121
|
+
if isinstance(obj, (list, tuple)):
|
|
121
122
|
return [_serialize_for_json(item) for item in obj]
|
|
122
|
-
|
|
123
|
+
if isinstance(obj, dict):
|
|
123
124
|
return {key: _serialize_for_json(value) for key, value in obj.items()}
|
|
124
125
|
|
|
125
126
|
# Check if this is a Zeep object (has _xsd_type attribute)
|
|
126
|
-
|
|
127
|
+
if hasattr(obj, "_xsd_type"):
|
|
127
128
|
result = {}
|
|
128
129
|
# Try to get all elements from XSD type
|
|
129
130
|
if hasattr(obj._xsd_type, "elements"): # pylint: disable=protected-access
|
|
@@ -154,7 +155,7 @@ def _serialize_for_json(obj: Any) -> Any:
|
|
|
154
155
|
|
|
155
156
|
return result
|
|
156
157
|
|
|
157
|
-
|
|
158
|
+
if hasattr(obj, "__dict__"):
|
|
158
159
|
# Handle regular objects with attributes
|
|
159
160
|
result = {}
|
|
160
161
|
for key, value in obj.__dict__.items():
|
|
@@ -176,14 +177,15 @@ def _serialize_for_json(obj: Any) -> Any:
|
|
|
176
177
|
pass
|
|
177
178
|
|
|
178
179
|
return result
|
|
179
|
-
|
|
180
|
+
|
|
181
|
+
if hasattr(obj, "_value_1"):
|
|
180
182
|
# Handle zeep objects with special structure
|
|
181
183
|
return _serialize_for_json(obj._value_1) # pylint: disable=protected-access
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
184
|
+
|
|
185
|
+
# Try to convert to dict using vars() if available
|
|
186
|
+
try:
|
|
187
|
+
obj_dict = vars(obj)
|
|
188
|
+
return _serialize_for_json(obj_dict)
|
|
189
|
+
except TypeError:
|
|
190
|
+
# Fallback to string representation
|
|
191
|
+
return str(obj)
|
|
@@ -69,7 +69,8 @@ def print_interactive_intro(args, device_info_text) -> str:
|
|
|
69
69
|
f"{banner}\n"
|
|
70
70
|
f"{repo_info}\n"
|
|
71
71
|
f"{terminal_header}\n"
|
|
72
|
-
f" Connected to : {colorize(f'{args.host}:{args.port}', 'yellow')}"
|
|
72
|
+
f" Connected to : {colorize(f'{args.host}:{args.port}', 'yellow')}\n"
|
|
73
|
+
f" Auth Method : {colorize(f'{'HTTP Digest' if args.digest else 'WS-UsernameToken'}', 'yellow')}"
|
|
73
74
|
f"{options_display}{device_info_text}\n\n"
|
|
74
75
|
f"{colorize('[Quick Start]', 'green')}\n"
|
|
75
76
|
f" - Type {colorize('dev', 'yellow')} + {colorize('TAB', 'yellow')} to see `devicemgmt` suggestion\n"
|
|
@@ -105,7 +106,6 @@ INTERACTIVE_HELP = f"""
|
|
|
105
106
|
cd <service> - Enter service mode (alias)
|
|
106
107
|
ls - List commands/services/methods in grid format
|
|
107
108
|
up - Exit current service mode (go up one level)
|
|
108
|
-
pwd - Show current service context
|
|
109
109
|
clear - Clear terminal screen
|
|
110
110
|
help <command> - Show help for a specific command
|
|
111
111
|
|
|
@@ -165,7 +165,6 @@ INTERACTIVE_SHORTCUTS = f"""
|
|
|
165
165
|
cd <service> - Enter service (same as '<service>')
|
|
166
166
|
ls - List commands/services in grid format (like TAB)
|
|
167
167
|
up - Go up one level
|
|
168
|
-
pwd - Show current context
|
|
169
168
|
clear - Clear terminal screen
|
|
170
169
|
help <command> - Show help for a command
|
|
171
170
|
|
|
@@ -193,7 +192,7 @@ Examples:
|
|
|
193
192
|
# Discover ONVIF devices on network
|
|
194
193
|
{colorize('onvif', 'yellow')} --discover --username admin --password admin123 --interactive
|
|
195
194
|
{colorize('onvif', 'yellow')} media GetProfiles --discover --username admin
|
|
196
|
-
{colorize('onvif', 'yellow')} -d -i
|
|
195
|
+
{colorize('onvif', 'yellow')} -d --interface 192.168.1.77 -i
|
|
197
196
|
|
|
198
197
|
# Discover with filtering
|
|
199
198
|
{colorize('onvif', 'yellow')} --discover --filter ptz --interactive
|
|
@@ -10,6 +10,8 @@ from pathlib import Path
|
|
|
10
10
|
from onvif.cli.utils import colorize
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
# pylint: disable=too-many-locals,too-many-nested-blocks
|
|
14
|
+
# pylint: disable=too-many-statements,too-many-branches
|
|
13
15
|
def search_products(search_term: str, page: int = 1, per_page: int = 20) -> None:
|
|
14
16
|
"""Search ONVIF products database and display results in table format with
|
|
15
17
|
pagination.
|
|
@@ -36,6 +36,7 @@ class OperationTypeInfo(TypedDict):
|
|
|
36
36
|
output: MessageInfo | None
|
|
37
37
|
|
|
38
38
|
|
|
39
|
+
# pylint: disable=too-many-locals,too-many-statements,too-many-branches
|
|
39
40
|
def get_method_documentation(service_obj, method_name: str) -> dict[str, Any] | None:
|
|
40
41
|
"""Extracts documentation from WSDL and parameters from the Python method signature.
|
|
41
42
|
|
|
@@ -45,7 +46,7 @@ def get_method_documentation(service_obj, method_name: str) -> dict[str, Any] |
|
|
|
45
46
|
required_args: list[str] = []
|
|
46
47
|
optional_args: list[str] = []
|
|
47
48
|
|
|
48
|
-
try:
|
|
49
|
+
try: # pylint: disable=too-many-nested-blocks
|
|
49
50
|
# 1. Get documentation from WSDL (existing logic)
|
|
50
51
|
wsdl_path = service_obj.operator.wsdl_path
|
|
51
52
|
|
|
@@ -308,8 +309,7 @@ def clean_documentation_html(doc_text: str) -> str:
|
|
|
308
309
|
text = match.group(2).strip() # Strip whitespace from link text
|
|
309
310
|
if text:
|
|
310
311
|
return f"{text} ({url})"
|
|
311
|
-
|
|
312
|
-
return url # If no text, just return URL
|
|
312
|
+
return url # If no text, just return URL
|
|
313
313
|
|
|
314
314
|
# Replace anchor tags - handle newlines and whitespace
|
|
315
315
|
doc_text = re.sub(
|
|
@@ -361,7 +361,9 @@ def extract_documentation_text(doc_elem) -> str:
|
|
|
361
361
|
def _load_imported_schemas(root, schema_context: dict, namespaces: dict):
|
|
362
362
|
"""Recursively load all imported and included schemas into the schema context."""
|
|
363
363
|
# Find all xs:import and xs:include in xs:schema elements
|
|
364
|
-
for schema in root.findall(
|
|
364
|
+
for schema in root.findall( # pylint: disable=too-many-nested-blocks
|
|
365
|
+
".//xs:schema", namespaces
|
|
366
|
+
):
|
|
365
367
|
# Process imports
|
|
366
368
|
for import_elem in schema.findall("xs:import", namespaces):
|
|
367
369
|
schema_location = import_elem.get("schemaLocation")
|
|
@@ -443,6 +445,7 @@ def _load_imported_schemas(root, schema_context: dict, namespaces: dict):
|
|
|
443
445
|
continue
|
|
444
446
|
|
|
445
447
|
|
|
448
|
+
# pylint: disable=too-many-locals,too-many-statements,too-many-branches
|
|
446
449
|
def resolve_element_type(
|
|
447
450
|
element_name: str,
|
|
448
451
|
namespaces: dict,
|
|
@@ -605,6 +608,7 @@ def resolve_element_type(
|
|
|
605
608
|
return parameters
|
|
606
609
|
|
|
607
610
|
|
|
611
|
+
# pylint: disable=too-many-locals,too-many-statements,too-many-branches
|
|
608
612
|
def resolve_complex_type(
|
|
609
613
|
type_name: str,
|
|
610
614
|
namespaces: dict,
|
|
@@ -794,6 +798,7 @@ def resolve_complex_type(
|
|
|
794
798
|
return children
|
|
795
799
|
|
|
796
800
|
|
|
801
|
+
# pylint: disable=too-many-locals,too-many-statements,too-many-branches
|
|
797
802
|
def parse_inline_complex_type(
|
|
798
803
|
complex_type,
|
|
799
804
|
namespaces: dict,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# pylint: disable=too-many-lines,too-many-instance-attributes,too-many-locals
|
|
2
|
+
# pylint: disable=too-many-statements,too-many-public-methods,too-many-branches
|
|
1
3
|
"""ONVIF CLI interactive shell implementation."""
|
|
2
4
|
|
|
3
5
|
import cmd
|
|
@@ -70,7 +72,6 @@ class InteractiveShell(cmd.Cmd):
|
|
|
70
72
|
"debug",
|
|
71
73
|
"ls",
|
|
72
74
|
"cd",
|
|
73
|
-
"pwd",
|
|
74
75
|
"shortcuts",
|
|
75
76
|
"desc",
|
|
76
77
|
"type",
|
|
@@ -274,6 +275,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
274
275
|
depth = max(0, depth - 1)
|
|
275
276
|
|
|
276
277
|
# Detect top-level &&
|
|
278
|
+
# pylint: disable=too-many-boolean-expressions
|
|
277
279
|
if (
|
|
278
280
|
not in_single
|
|
279
281
|
and not in_double
|
|
@@ -522,6 +524,8 @@ class InteractiveShell(cmd.Cmd):
|
|
|
522
524
|
print(f"{colorize('Unknown command:', 'red')} {line}")
|
|
523
525
|
print(f"Type {colorize('help', 'white')} for available commands")
|
|
524
526
|
|
|
527
|
+
return None
|
|
528
|
+
|
|
525
529
|
def get_suggestions(self, partial_cmd: str) -> list[str]:
|
|
526
530
|
"""Get command suggestions based on partial input."""
|
|
527
531
|
suggestions = []
|
|
@@ -1026,7 +1030,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
1026
1030
|
available_services = get_device_available_services(self.client)
|
|
1027
1031
|
colored_services = [colorize(svc, "cyan") for svc in available_services]
|
|
1028
1032
|
print(f"Available services: {', '.join(colored_services)}")
|
|
1029
|
-
return
|
|
1033
|
+
return None
|
|
1030
1034
|
return self.do_enter_service(line)
|
|
1031
1035
|
|
|
1032
1036
|
def complete_cd(
|
|
@@ -1036,17 +1040,6 @@ class InteractiveShell(cmd.Cmd):
|
|
|
1036
1040
|
services = get_device_available_services(self.client)
|
|
1037
1041
|
return [s for s in services if s.lower().startswith(text.lower())]
|
|
1038
1042
|
|
|
1039
|
-
def do_pwd(self, line): # pylint: disable=unused-argument
|
|
1040
|
-
"""Show current service context."""
|
|
1041
|
-
if self.current_service_name:
|
|
1042
|
-
print(
|
|
1043
|
-
f"{colorize('Current service:', 'yellow')} {colorize(self.current_service_name, 'cyan')}"
|
|
1044
|
-
)
|
|
1045
|
-
else:
|
|
1046
|
-
print(
|
|
1047
|
-
f"{colorize('Current context:', 'yellow')} {colorize('root', 'blue')}"
|
|
1048
|
-
)
|
|
1049
|
-
|
|
1050
1043
|
def do_shortcuts(self, line): # pylint: disable=unused-argument
|
|
1051
1044
|
"""Show available shortcuts."""
|
|
1052
1045
|
print(INTERACTIVE_SHORTCUTS)
|
|
@@ -1221,6 +1214,7 @@ class InteractiveShell(cmd.Cmd):
|
|
|
1221
1214
|
print(
|
|
1222
1215
|
f"\n{colorize('[ONVIF Terminal Client]', 'yellow')}"
|
|
1223
1216
|
f"\n Connected to : {colorize(f'{self.args.host}:{self.args.port}', 'yellow')}"
|
|
1217
|
+
f"\n Auth Method : {colorize(f'{'HTTP Digest' if self.args.digest else 'WS-UsernameToken'}', 'yellow')}"
|
|
1224
1218
|
f"{options_display}{self.device_info_text}"
|
|
1225
1219
|
)
|
|
1226
1220
|
print() # Extra newline for spacing
|
|
@@ -24,7 +24,6 @@ from onvif.operator import CacheMode
|
|
|
24
24
|
from onvif.utils import ONVIFOperationException
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
# pylint: disable=line-too-long
|
|
28
27
|
def create_parser() -> ArgumentParser:
|
|
29
28
|
"""Create argument parser for ONVIF CLI."""
|
|
30
29
|
parser = ArgumentParser(
|
|
@@ -97,6 +96,11 @@ def create_parser() -> ArgumentParser:
|
|
|
97
96
|
default=10,
|
|
98
97
|
help="ONVIF connection timeout in seconds (default: 10)",
|
|
99
98
|
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--digest",
|
|
101
|
+
action="store_true",
|
|
102
|
+
help="Use HTTP Digest instead of WS-UsernameToken",
|
|
103
|
+
)
|
|
100
104
|
parser.add_argument(
|
|
101
105
|
"--https", action="store_true", help="Use HTTPS instead of HTTP"
|
|
102
106
|
)
|
|
@@ -118,9 +122,9 @@ def create_parser() -> ArgumentParser:
|
|
|
118
122
|
parser.add_argument(
|
|
119
123
|
"--cache",
|
|
120
124
|
choices=[mode.value for mode in CacheMode],
|
|
121
|
-
default=CacheMode.
|
|
122
|
-
help="Caching mode for ONVIFClient (default:
|
|
123
|
-
"'
|
|
125
|
+
default=CacheMode.DB.value,
|
|
126
|
+
help="Caching mode for ONVIFClient (default: db). "
|
|
127
|
+
"'db': disk-only, 'mem': memory-only, 'none': disabled.",
|
|
124
128
|
)
|
|
125
129
|
parser.add_argument(
|
|
126
130
|
"--health-check-interval",
|
|
@@ -159,6 +163,7 @@ def create_parser() -> ArgumentParser:
|
|
|
159
163
|
return parser
|
|
160
164
|
|
|
161
165
|
|
|
166
|
+
# pylint: disable=too-many-statements,too-many-branches
|
|
162
167
|
def main() -> None:
|
|
163
168
|
"""Main CLI entry point."""
|
|
164
169
|
# Setup custom warning format for cleaner output
|
|
@@ -278,6 +283,7 @@ def main() -> None:
|
|
|
278
283
|
port=args.port,
|
|
279
284
|
username=args.username,
|
|
280
285
|
password=args.password,
|
|
286
|
+
http_digest=args.digest,
|
|
281
287
|
timeout=args.timeout,
|
|
282
288
|
cache=CacheMode(args.cache),
|
|
283
289
|
use_https=args.https,
|
|
@@ -80,6 +80,7 @@ def _is_valid_json(s: str) -> bool:
|
|
|
80
80
|
return True
|
|
81
81
|
|
|
82
82
|
|
|
83
|
+
# pylint: disable=too-many-statements,too-many-branches
|
|
83
84
|
def parse_json_params(params_str: str) -> dict[str, Any]:
|
|
84
85
|
"""Parse parameters from a JSON string or key=value pairs into a dict.
|
|
85
86
|
|
|
@@ -406,6 +407,7 @@ def format_services_list(services_list) -> str:
|
|
|
406
407
|
return result
|
|
407
408
|
|
|
408
409
|
|
|
410
|
+
# pylint: disable=too-many-statements,too-many-branches
|
|
409
411
|
def get_device_available_services(client) -> list:
|
|
410
412
|
"""Get list of services actually available on the connected device.
|
|
411
413
|
|