onvif-python 0.4.2__tar.gz → 0.4.3__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.
Files changed (170) hide show
  1. onvif_python-0.4.2/LICENSE.md → onvif_python-0.4.3/LICENSE +1 -1
  2. onvif_python-0.4.3/NOTICE +11 -0
  3. {onvif_python-0.4.2/onvif_python.egg-info → onvif_python-0.4.3}/PKG-INFO +34 -34
  4. {onvif_python-0.4.2 → onvif_python-0.4.3}/README.md +10 -15
  5. onvif_python-0.4.3/onvif/cli/__init__.py +1 -0
  6. onvif_python-0.4.3/onvif/cli/interactive/__init__.py +5 -0
  7. onvif_python-0.4.3/onvif/cli/interactive/context.py +55 -0
  8. onvif_python-0.4.3/onvif/cli/interactive/information.py +175 -0
  9. onvif_python-0.4.3/onvif/cli/interactive/navigation.py +185 -0
  10. onvif_python-0.4.3/onvif/cli/interactive/reference.py +204 -0
  11. onvif_python-0.4.3/onvif/cli/interactive/service.py +325 -0
  12. onvif_python-0.4.3/onvif/cli/interactive/shell.py +246 -0
  13. onvif_python-0.4.3/onvif/cli/interactive/utils.py +313 -0
  14. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/main.py +1 -1
  15. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/client.py +2 -0
  16. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/db/products.db +1 -1
  17. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/meta.py +1 -1
  18. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/operator.py +92 -2
  19. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/deviceio.py +3 -3
  20. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/devicemgmt.py +3 -3
  21. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/media2.py +25 -6
  22. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/ptz.py +1 -1
  23. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/recording.py +5 -4
  24. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/tlsserver.py +9 -12
  25. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/error_handlers.py +2 -0
  26. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/exceptions.py +3 -1
  27. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/service.py +39 -1
  28. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/zeep.py +2 -0
  29. {onvif_python-0.4.2 → onvif_python-0.4.3/onvif_python.egg-info}/PKG-INFO +34 -34
  30. onvif_python-0.4.3/onvif_python.egg-info/SOURCES.txt +90 -0
  31. onvif_python-0.4.3/onvif_python.egg-info/requires.txt +24 -0
  32. {onvif_python-0.4.2 → onvif_python-0.4.3}/pyproject.toml +43 -24
  33. {onvif_python-0.4.2 → onvif_python-0.4.3}/tests/test_client.py +156 -2
  34. onvif_python-0.4.3/tests/test_client_services.py +121 -0
  35. onvif_python-0.4.3/tests/test_core.py +140 -0
  36. onvif_python-0.4.3/tests/test_meta.py +26 -0
  37. onvif_python-0.4.3/tests/test_operator.py +946 -0
  38. onvif_python-0.4.2/MANIFEST.in +0 -3
  39. onvif_python-0.4.2/onvif/cli/__init__.py +0 -5
  40. onvif_python-0.4.2/onvif/cli/interactive.py +0 -1335
  41. onvif_python-0.4.2/onvif/wsdl/schema/common/b-2.xsd +0 -580
  42. onvif_python-0.4.2/onvif/wsdl/schema/common/bf-2.xsd +0 -84
  43. onvif_python-0.4.2/onvif/wsdl/schema/common/bw-2.wsdl +0 -448
  44. onvif_python-0.4.2/onvif/wsdl/schema/common/include +0 -13
  45. onvif_python-0.4.2/onvif/wsdl/schema/common/mpqf.xsd +0 -1109
  46. onvif_python-0.4.2/onvif/wsdl/schema/common/r-2.xsd +0 -50
  47. onvif_python-0.4.2/onvif/wsdl/schema/common/rw-2.wsdl +0 -54
  48. onvif_python-0.4.2/onvif/wsdl/schema/common/soap-envelope +0 -165
  49. onvif_python-0.4.2/onvif/wsdl/schema/common/t-1.xsd +0 -185
  50. onvif_python-0.4.2/onvif/wsdl/schema/common/ws-addr.xsd +0 -144
  51. onvif_python-0.4.2/onvif/wsdl/schema/common/xml.xsd +0 -287
  52. onvif_python-0.4.2/onvif/wsdl/schema/common/xmlmime +0 -49
  53. onvif_python-0.4.2/onvif/wsdl/ver10/accesscontrol/wsdl/index.html +0 -7
  54. onvif_python-0.4.2/onvif/wsdl/ver10/accessrules/wsdl/accessrules.wsdl +0 -702
  55. onvif_python-0.4.2/onvif/wsdl/ver10/accessrules/wsdl/index.html +0 -7
  56. onvif_python-0.4.2/onvif/wsdl/ver10/actionengine.wsdl +0 -1265
  57. onvif_python-0.4.2/onvif/wsdl/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl +0 -4205
  58. onvif_python-0.4.2/onvif/wsdl/ver10/advancedsecurity/wsdl/index.html +0 -7
  59. onvif_python-0.4.2/onvif/wsdl/ver10/analyticsdevice.wsdl +0 -709
  60. onvif_python-0.4.2/onvif/wsdl/ver10/appmgmt/wsdl/appmgmt.wsdl +0 -502
  61. onvif_python-0.4.2/onvif/wsdl/ver10/appmgmt/wsdl/index.html +0 -7
  62. onvif_python-0.4.2/onvif/wsdl/ver10/authenticationbehavior/wsdl/authenticationbehavior.wsdl +0 -1382
  63. onvif_python-0.4.2/onvif/wsdl/ver10/authenticationbehavior/wsdl/index.html +0 -7
  64. onvif_python-0.4.2/onvif/wsdl/ver10/credential/wsdl/credential.wsdl +0 -2018
  65. onvif_python-0.4.2/onvif/wsdl/ver10/credential/wsdl/index.html +0 -7
  66. onvif_python-0.4.2/onvif/wsdl/ver10/device/wsdl/devicemgmt.wsdl +0 -4786
  67. onvif_python-0.4.2/onvif/wsdl/ver10/deviceio.wsdl +0 -1414
  68. onvif_python-0.4.2/onvif/wsdl/ver10/display/display.wsdl +0 -383
  69. onvif_python-0.4.2/onvif/wsdl/ver10/display/wsdl/index.htm +0 -383
  70. onvif_python-0.4.2/onvif/wsdl/ver10/display.wsdl +0 -521
  71. onvif_python-0.4.2/onvif/wsdl/ver10/doorcontrol/wsdl/index.html +0 -7
  72. onvif_python-0.4.2/onvif/wsdl/ver10/events/wsdl/bw-2-vs-mod.wsdl +0 -449
  73. onvif_python-0.4.2/onvif/wsdl/ver10/events/wsdl/event-vs.wsdl +0 -947
  74. onvif_python-0.4.2/onvif/wsdl/ver10/events/wsdl/event.wsdl +0 -947
  75. onvif_python-0.4.2/onvif/wsdl/ver10/events/wsdl/index.html +0 -7
  76. onvif_python-0.4.2/onvif/wsdl/ver10/federatedsearch.wsdl +0 -344
  77. onvif_python-0.4.2/onvif/wsdl/ver10/media/wsdl/media.wsdl +0 -3684
  78. onvif_python-0.4.2/onvif/wsdl/ver10/pacs/accesscontrol.wsdl +0 -1942
  79. onvif_python-0.4.2/onvif/wsdl/ver10/pacs/doorcontrol.wsdl +0 -1792
  80. onvif_python-0.4.2/onvif/wsdl/ver10/pacs/types.xsd +0 -181
  81. onvif_python-0.4.2/onvif/wsdl/ver10/provisioning/wsdl/provisioning.wsdl +0 -588
  82. onvif_python-0.4.2/onvif/wsdl/ver10/receiver.wsdl +0 -398
  83. onvif_python-0.4.2/onvif/wsdl/ver10/recording.wsdl +0 -1442
  84. onvif_python-0.4.2/onvif/wsdl/ver10/replay.wsdl +0 -221
  85. onvif_python-0.4.2/onvif/wsdl/ver10/schedule/wsdl/index.html +0 -7
  86. onvif_python-0.4.2/onvif/wsdl/ver10/schedule/wsdl/schedule.wsdl +0 -1383
  87. onvif_python-0.4.2/onvif/wsdl/ver10/schema/common.xsd +0 -431
  88. onvif_python-0.4.2/onvif/wsdl/ver10/schema/metadatastream.xsd +0 -534
  89. onvif_python-0.4.2/onvif/wsdl/ver10/schema/onvif.xsd +0 -9743
  90. onvif_python-0.4.2/onvif/wsdl/ver10/search.wsdl +0 -1114
  91. onvif_python-0.4.2/onvif/wsdl/ver10/thermal/wsdl/index.html +0 -7
  92. onvif_python-0.4.2/onvif/wsdl/ver10/thermal/wsdl/thermal.wsdl +0 -777
  93. onvif_python-0.4.2/onvif/wsdl/ver10/topics/topicns.xml +0 -13
  94. onvif_python-0.4.2/onvif/wsdl/ver10/uplink/wsdl/index.html +0 -7
  95. onvif_python-0.4.2/onvif/wsdl/ver10/uplink/wsdl/uplink.wsdl +0 -256
  96. onvif_python-0.4.2/onvif/wsdl/ver20/analytics/humanbody.xsd +0 -490
  97. onvif_python-0.4.2/onvif/wsdl/ver20/analytics/humanface.xsd +0 -501
  98. onvif_python-0.4.2/onvif/wsdl/ver20/analytics/index.html +0 -7
  99. onvif_python-0.4.2/onvif/wsdl/ver20/analytics/radiometry.xsd +0 -389
  100. onvif_python-0.4.2/onvif/wsdl/ver20/analytics/rules.xsd +0 -127
  101. onvif_python-0.4.2/onvif/wsdl/ver20/analytics/wsdl/analytics.wsdl +0 -757
  102. onvif_python-0.4.2/onvif/wsdl/ver20/analytics/wsdl/index.html +0 -7
  103. onvif_python-0.4.2/onvif/wsdl/ver20/imaging/wsdl/imaging.wsdl +0 -603
  104. onvif_python-0.4.2/onvif/wsdl/ver20/media/wsdl/index.html +0 -7
  105. onvif_python-0.4.2/onvif/wsdl/ver20/media/wsdl/media.wsdl +0 -3126
  106. onvif_python-0.4.2/onvif/wsdl/ver20/ptz/wsdl/ptz.wsdl +0 -1450
  107. onvif_python-0.4.2/onvif/wsdl/ver20/util/federated_search_documentation.html +0 -1647
  108. onvif_python-0.4.2/onvif/wsdl/ver20/util/fedsearch-docu-viewer.xsl +0 -8
  109. onvif_python-0.4.2/onvif/wsdl/ver20/util/onvif-wsdl-viewer.xsl +0 -2580
  110. onvif_python-0.4.2/onvif/wsdl/ver20/util/operationIndex.html +0 -97
  111. onvif_python-0.4.2/onvif_python.egg-info/SOURCES.txt +0 -152
  112. onvif_python-0.4.2/onvif_python.egg-info/requires.txt +0 -22
  113. onvif_python-0.4.2/tests/test_core.py +0 -386
  114. onvif_python-0.4.2/tests/test_error_handlers.py +0 -362
  115. onvif_python-0.4.2/tests/test_exceptions.py +0 -340
  116. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/__init__.py +0 -0
  117. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/__main__.py +0 -0
  118. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/helpers/__init__.py +0 -0
  119. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/helpers/discovery.py +0 -0
  120. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/helpers/execution.py +0 -0
  121. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/helpers/files.py +0 -0
  122. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/helpers/messages.py +0 -0
  123. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/helpers/products.py +0 -0
  124. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/helpers/wsdl_parser.py +0 -0
  125. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/cli/utils.py +0 -0
  126. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/db/companies.db +0 -0
  127. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/__init__.py +0 -0
  128. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/accesscontrol.py +0 -0
  129. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/accessrules.py +0 -0
  130. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/actionengine.py +0 -0
  131. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/analytics/__init__.py +0 -0
  132. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/analytics/analytics.py +0 -0
  133. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/analytics/ruleengine.py +0 -0
  134. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/analyticsdevice.py +0 -0
  135. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/appmgmt.py +0 -0
  136. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/authenticationbehavior.py +0 -0
  137. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/credential.py +0 -0
  138. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/display.py +0 -0
  139. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/doorcontrol.py +0 -0
  140. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/events/__init__.py +0 -0
  141. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/events/events.py +0 -0
  142. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/events/notification.py +0 -0
  143. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/events/pausable_subscription.py +0 -0
  144. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/events/pullpoint.py +0 -0
  145. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/events/subscription.py +0 -0
  146. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/imaging.py +0 -0
  147. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/media.py +0 -0
  148. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/provisioning.py +0 -0
  149. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/receiver.py +0 -0
  150. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/replay.py +0 -0
  151. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/schedule.py +0 -0
  152. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/search.py +0 -0
  153. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/__init__.py +0 -0
  154. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/advancedsecurity.py +0 -0
  155. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/authorizationserver.py +0 -0
  156. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/dot1x.py +0 -0
  157. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/jwt.py +0 -0
  158. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/keystore.py +0 -0
  159. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/security/mediasigning.py +0 -0
  160. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/thermal.py +0 -0
  161. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/services/uplink.py +0 -0
  162. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/__init__.py +0 -0
  163. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/discovery.py +0 -0
  164. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/plugins.py +0 -0
  165. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif/utils/wsdl.py +0 -0
  166. /onvif_python-0.4.2/onvif/wsdl/LICENSE.md → /onvif_python-0.4.3/onvif/wsdl/LICENSE +0 -0
  167. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif_python.egg-info/dependency_links.txt +0 -0
  168. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif_python.egg-info/entry_points.txt +0 -0
  169. {onvif_python-0.4.2 → onvif_python-0.4.3}/onvif_python.egg-info/top_level.txt +0 -0
  170. {onvif_python-0.4.2 → onvif_python-0.4.3}/setup.cfg +0 -0
@@ -1,4 +1,4 @@
1
- The MIT License (MIT)
1
+ MIT License
2
2
 
3
3
  Copyright (c) 2025-2026 Nirsimetri Technologies®
4
4
 
@@ -0,0 +1,11 @@
1
+ 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.
2
+
3
+ - The name “ONVIF” and the ONVIF logo are registered trademarks of the ONVIF organization.
4
+ - Any references to ONVIF within this project are made strictly for the purpose of describing interoperability with ONVIF-compliant devices and services.
5
+ - Use of the ONVIF trademark in this repository is solely nominative and does not imply any partnership, certification, or official status.
6
+ - This project includes WSDL/XSD/HTML files from the official ONVIF specifications.
7
+ - These files are © ONVIF and are redistributed here for interoperability purposes.
8
+ - The WSDL files in the https://github.com/nirsimetri/onvif-python/tree/main/onvif/wsdl folder are distributed under the ONVIF Contributor License Agreement and Apache License 2.0. See https://github.com/nirsimetri/onvif-python/tree/main/onvif/wsdl/LICENSE for details.
9
+ - All rights to the ONVIF specifications are reserved by ONVIF.
10
+
11
+ If you require certified ONVIF-compliant devices or clients, please refer to the official https://www.onvif.org/conformant-products. For authoritative reference and the latest official ONVIF specifications, please consult the https://www.onvif.org/profiles/specifications/specification-history.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onvif-python
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: A modern Python library for ONVIF-compliant devices
5
5
  Author-email: Nirsimetri Technologies® <open@nirsimetri.com>
6
6
  Maintainer: Kaburagi
@@ -12,15 +12,17 @@ Project-URL: Issues, https://github.com/nirsimetri/onvif-python/issues
12
12
  Keywords: onvif,Camera,onvif python,ip camera,cctv,soap,surveillance,cctv cameras,soap client,onvif client,onvif library,onvif specifications
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Information Technology
17
+ Classifier: Intended Audience :: Science/Research
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python
20
+ Classifier: Programming Language :: Python :: 3 :: Only
15
21
  Classifier: Programming Language :: Python :: 3.10
16
22
  Classifier: Programming Language :: Python :: 3.11
17
23
  Classifier: Programming Language :: Python :: 3.12
18
24
  Classifier: Programming Language :: Python :: 3.13
19
25
  Classifier: Programming Language :: Python :: 3.14
20
- Classifier: Operating System :: OS Independent
21
- Classifier: Intended Audience :: Developers
22
- Classifier: Intended Audience :: Information Technology
23
- Classifier: Intended Audience :: Science/Research
24
26
  Classifier: Topic :: Software Development :: Libraries
25
27
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
28
  Classifier: Topic :: Security
@@ -30,44 +32,42 @@ Classifier: Topic :: Communications
30
32
  Classifier: Topic :: Text Processing :: Markup :: XML
31
33
  Requires-Python: >=3.10
32
34
  Description-Content-Type: text/markdown
33
- License-File: LICENSE.md
34
- Requires-Dist: zeep>=4.3.0
35
- Requires-Dist: requests>=2.32.0
36
- Requires-Dist: pyreadline3>=3.5.4; sys_platform == "win32"
35
+ License-File: LICENSE
36
+ License-File: NOTICE
37
+ Requires-Dist: zeep<4.4.0,>=4.3.0
38
+ Requires-Dist: requests<3.0.0,>=2.32.0
39
+ Requires-Dist: pyreadline3<4.0.0,>=3.5.4; sys_platform == "win32"
37
40
  Provides-Extra: dev
38
- Requires-Dist: pytest>=7.0; extra == "dev"
39
- Requires-Dist: pytest-cov; extra == "dev"
40
- Requires-Dist: black; extra == "dev"
41
- Requires-Dist: mypy; extra == "dev"
42
- Requires-Dist: isort; extra == "dev"
43
- Requires-Dist: pylint; extra == "dev"
44
- Requires-Dist: docformatter; extra == "dev"
41
+ Requires-Dist: pytest<10.0,>=8.0; extra == "dev"
42
+ Requires-Dist: pytest-cov<7.0,>=6.0; extra == "dev"
43
+ Requires-Dist: black<27.0,>=26.0; extra == "dev"
44
+ Requires-Dist: mypy<2.0,>=1.0; extra == "dev"
45
+ Requires-Dist: isort<7.0,>=6.0; extra == "dev"
46
+ Requires-Dist: pylint<4.3.0,>=4.1.2; extra == "dev"
47
+ Requires-Dist: pylint-pytest<2.0,>=1.1; extra == "dev"
48
+ Requires-Dist: docformatter<2.0,>=1.0; extra == "dev"
49
+ Requires-Dist: codespell<3.0,>=2.0; extra == "dev"
45
50
  Requires-Dist: lxml-stubs; extra == "dev"
46
51
  Requires-Dist: types-setuptools; extra == "dev"
47
52
  Requires-Dist: types-requests; extra == "dev"
48
53
  Provides-Extra: docs
49
- Requires-Dist: mkdocs-material; extra == "docs"
50
- Requires-Dist: mkdocstrings[python]; extra == "docs"
51
- Requires-Dist: mkdocs-git-authors-plugin; extra == "docs"
54
+ Requires-Dist: mkdocs-material<10.0.0,>=9.7.7; extra == "docs"
55
+ Requires-Dist: mkdocstrings[python]<3.0.0,>=1.0.0; extra == "docs"
56
+ Requires-Dist: mkdocs-git-authors-plugin<1.0.0,>=0.10.0; extra == "docs"
52
57
  Dynamic: license-file
53
58
 
54
- <h1 align="center">ONVIF Python</h1>
59
+ # ONVIF Python
55
60
 
56
- <div align="center">
57
- <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>
58
- <a href="https://pypi.org/project/onvif-python/"><img alt="PyPI Version" src="https://img.shields.io/badge/Version-0.4.2-orange?logo=python&logoColor=white&color=yellow&style=plastic"></a>
59
- <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>
61
+ [![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)
62
+ [![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/)
63
+ [![Quality](https://img.shields.io/codacy/grade/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Quality)](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard)
64
+ [![Coverage](https://img.shields.io/codacy/coverage/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Coverage)](https://app.codacy.com/gh/nirsimetri/onvif-python/coverage)
65
+ [![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python)
60
66
  <br>
61
- <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>
62
- <a href="https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml"><img alt="Upload Python Package" src="https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml/badge.svg"></a>
63
- </div>
64
-
65
- <h1 align="center">
66
- <img src="https://raw.githubusercontent.com/nirsimetri/onvif-python/refs/heads/main/assets/images/carbon_onvif.png" alt="onvif" width="700px">
67
- <br>
68
- </h1>
67
+ [![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)
68
+ [![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)
69
+ [![CLI Cross-Platform](https://img.shields.io/github/actions/workflow/status/nirsimetri/onvif-python/cli-cross-platform.yml?logo=github&style=plastic&label=CLI%20Cross-Platform)](https://github.com/nirsimetri/onvif-python/actions/workflows/cli-cross-platform.yml)
69
70
 
70
- **This project provides a comprehensive and developer-friendly Python library for working with ONVIF-compliant devices.** It is designed to be reliable, easy to integrate, and flexible enough to support a wide range of ONVIF profiles and services.
71
71
 
72
72
  **[ONVIF](https://www.onvif.org) (Open Network Video Interface Forum)** is a global standard for the interface of IP-based physical security products, including network cameras, video recorders, and related systems.
73
73
 
@@ -112,4 +112,4 @@ For complete guide, including usage examples and API references, please visit th
112
112
 
113
113
  ## License
114
114
 
115
- This project is licensed under the MIT License. See [LICENSE](./LICENSE.md) for details.
115
+ This project is licensed under the MIT License. See [LICENSE](./LICENSE) for details.
@@ -1,20 +1,15 @@
1
- <h1 align="center">ONVIF Python</h1>
1
+ # ONVIF Python
2
2
 
3
- <div align="center">
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.4.2-orange?logo=python&logoColor=white&color=yellow&style=plastic"></a>
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>
3
+ [![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)
4
+ [![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/)
5
+ [![Quality](https://img.shields.io/codacy/grade/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Quality)](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard)
6
+ [![Coverage](https://img.shields.io/codacy/coverage/bff08a94e4d447b690cea49c6594826d?style=plastic&logo=codacy&label=Coverage)](https://app.codacy.com/gh/nirsimetri/onvif-python/coverage)
7
+ [![Downloads](https://img.shields.io/pepy/dt/onvif-python?label=Downloads&color=red&style=plastic)](https://pepy.tech/projects/onvif-python)
7
8
  <br>
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>
9
- <a href="https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml"><img alt="Upload Python Package" src="https://github.com/nirsimetri/onvif-python/actions/workflows/python-publish.yml/badge.svg"></a>
10
- </div>
9
+ [![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)
10
+ [![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)
11
+ [![CLI Cross-Platform](https://img.shields.io/github/actions/workflow/status/nirsimetri/onvif-python/cli-cross-platform.yml?logo=github&style=plastic&label=CLI%20Cross-Platform)](https://github.com/nirsimetri/onvif-python/actions/workflows/cli-cross-platform.yml)
11
12
 
12
- <h1 align="center">
13
- <img src="https://raw.githubusercontent.com/nirsimetri/onvif-python/refs/heads/main/assets/images/carbon_onvif.png" alt="onvif" width="700px">
14
- <br>
15
- </h1>
16
-
17
- **This project provides a comprehensive and developer-friendly Python library for working with ONVIF-compliant devices.** It is designed to be reliable, easy to integrate, and flexible enough to support a wide range of ONVIF profiles and services.
18
13
 
19
14
  **[ONVIF](https://www.onvif.org) (Open Network Video Interface Forum)** is a global standard for the interface of IP-based physical security products, including network cameras, video recorders, and related systems.
20
15
 
@@ -59,4 +54,4 @@ For complete guide, including usage examples and API references, please visit th
59
54
 
60
55
  ## License
61
56
 
62
- This project is licensed under the MIT License. See [LICENSE](./LICENSE.md) for details.
57
+ This project is licensed under the MIT License. See [LICENSE](./LICENSE) for details.
@@ -0,0 +1 @@
1
+ """ONVIF CLI."""
@@ -0,0 +1,5 @@
1
+ """ONVIF Interactive Shell."""
2
+
3
+ from onvif.cli.interactive.shell import InteractiveShell
4
+
5
+ __all__ = ["InteractiveShell"]
@@ -0,0 +1,55 @@
1
+ """ONVIF Interactive Shell context."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ from onvif.client import ONVIFClient
8
+
9
+
10
+ @dataclass
11
+ class ShellContext: # pylint: disable=too-many-instance-attributes
12
+ """Store shared state for the interactive shell."""
13
+
14
+ UNSET = object()
15
+
16
+ client: ONVIFClient
17
+ args: object
18
+
19
+ current_service: object | None = None
20
+ current_service_name: str | None = None
21
+ stored_data: dict[str, Any] = field(
22
+ default_factory=dict
23
+ ) # For storing command results
24
+ stored_metadata: dict[str, dict[str, Any]] = field(
25
+ default_factory=dict
26
+ ) # For storing metadata about stored data (service, method
27
+
28
+ last_result: Any = field(default=UNSET, repr=False)
29
+ last_method: str | None = None
30
+ last_service_name: str | None = None
31
+ last_operation_timestamp: datetime | None = None
32
+
33
+ base_commands: list[str] = field(
34
+ default_factory=lambda: [
35
+ "capabilities",
36
+ "caps",
37
+ "services",
38
+ "help",
39
+ "exit",
40
+ "store",
41
+ "rm",
42
+ "show",
43
+ "cls",
44
+ "clear",
45
+ "info",
46
+ "debug",
47
+ "ls",
48
+ "cd",
49
+ "shortcuts",
50
+ "desc",
51
+ "type",
52
+ ]
53
+ )
54
+
55
+ device_info_text: str | None = None
@@ -0,0 +1,175 @@
1
+ """Information commands implementation."""
2
+
3
+ import cmd
4
+ from typing import Callable
5
+
6
+ from requests.exceptions import RequestException
7
+ from zeep.exceptions import TransportError
8
+
9
+ from onvif.cli.helpers.messages import INTERACTIVE_HELP, INTERACTIVE_SHORTCUTS
10
+ from onvif.cli.utils import (
11
+ colorize,
12
+ format_capabilities_as_services,
13
+ format_services_list,
14
+ )
15
+ from onvif.utils.exceptions import ONVIFOperationException
16
+
17
+ from .context import ShellContext
18
+
19
+
20
+ class InformationCommands:
21
+ """Provide information commands."""
22
+
23
+ context: ShellContext
24
+ _handle_connection_error: Callable[..., None]
25
+
26
+ def do_help(self, arg):
27
+ """Show help information."""
28
+ if arg:
29
+ cmd.Cmd.do_help(self, arg)
30
+ else:
31
+ print(INTERACTIVE_HELP)
32
+
33
+ def do_shortcuts(self, _line):
34
+ """Show available shortcuts."""
35
+ print(INTERACTIVE_SHORTCUTS)
36
+
37
+ def do_info(self, _line):
38
+ """Show connection and device information."""
39
+ # Build connection and CLI options info
40
+ options_info = []
41
+
42
+ # Connection options
43
+ if hasattr(self.context.args, "https") and self.context.args.https:
44
+ options_info.append(f" Use HTTPS : {colorize('True', 'green')}")
45
+
46
+ if (
47
+ hasattr(self.context.args, "no_verify_ssl")
48
+ and self.context.args.no_verify_ssl
49
+ ):
50
+ options_info.append(f" Verify SSL : {colorize('False', 'red')}")
51
+
52
+ if (
53
+ hasattr(self.context.args, "timeout") and self.context.args.timeout != 10
54
+ ): # 10 is default
55
+ options_info.append(
56
+ f" Timeout : {colorize(f'{self.context.args.timeout}s', 'yellow')}"
57
+ )
58
+
59
+ # CLI options
60
+ if hasattr(self.context.args, "debug") and self.context.args.debug:
61
+ options_info.append(f" Debug Mode : {colorize('True', 'green')}")
62
+
63
+ if hasattr(self.context.args, "no_patch") and self.context.args.no_patch:
64
+ options_info.append(f" ZeepPatcher : {colorize('Disabled', 'red')}")
65
+
66
+ if hasattr(self.context.args, "wsdl") and self.context.args.wsdl:
67
+ options_info.append(
68
+ f" Custom WSDL : {colorize(self.context.args.wsdl, 'yellow')}"
69
+ )
70
+
71
+ if (
72
+ hasattr(self.context.args, "health_check_interval")
73
+ and self.context.args.health_check_interval != 10
74
+ ): # 10 is default
75
+ options_info.append(
76
+ f" Health Check : every {colorize(f'{self.context.args.health_check_interval}s', 'yellow')}"
77
+ )
78
+
79
+ # Format options info
80
+ options_display = ""
81
+ if options_info:
82
+ options_display = "\n" + "\n".join(options_info)
83
+
84
+ # Display connection and device information using stored data
85
+ print(
86
+ f"\n{colorize('[ONVIF Terminal Client]', 'yellow')}"
87
+ f"\n Connected to : "
88
+ f"{colorize(f'{self.context.args.host}:{self.context.args.port}', 'yellow')}"
89
+ f"\n Auth Method : "
90
+ f"{colorize('HTTP Digest' if self.context.args.digest else 'WS-UsernameToken', 'yellow')}"
91
+ f"{options_display}{self.context.device_info_text}"
92
+ )
93
+ print() # Extra newline for spacing
94
+
95
+ def do_capabilities(self, _line):
96
+ """Show device capabilities in service format."""
97
+ try:
98
+ if (
99
+ hasattr(self.context.client, "capabilities")
100
+ and self.context.client.capabilities
101
+ ):
102
+ result = self.context.client.capabilities
103
+ else:
104
+ result = self.context.client.devicemgmt().GetCapabilities(
105
+ Category="All"
106
+ )
107
+
108
+ self.context.stored_data["capabilities"] = result
109
+ self.context.stored_metadata["capabilities"] = {
110
+ "service": "devicemgmt",
111
+ "method": "GetCapabilities",
112
+ }
113
+
114
+ # Use special formatting for capabilities
115
+ output = format_capabilities_as_services(result)
116
+ print(output)
117
+ except ONVIFOperationException as e:
118
+ if isinstance(e.original_exception, (RequestException, TransportError)):
119
+ self._handle_connection_error()
120
+ else:
121
+ print(f"{colorize('Error:', 'red')} {e}")
122
+
123
+ def do_caps(self, line):
124
+ """Show device capabilities (alias for 'capabilities')"""
125
+ return self.do_capabilities(line)
126
+
127
+ def do_services(self, _line):
128
+ """Show available ONVIF services in service format."""
129
+ try:
130
+ if (
131
+ hasattr(self.context.client, "services")
132
+ and self.context.client.services
133
+ ):
134
+ result = self.context.client.services
135
+ else:
136
+ result = self.context.client.devicemgmt().GetServices(
137
+ IncludeCapability=False
138
+ )
139
+
140
+ self.context.stored_data["services"] = result
141
+ self.context.stored_metadata["services"] = {
142
+ "service": "devicemgmt",
143
+ "method": "GetServices",
144
+ }
145
+
146
+ # Use special formatting for services
147
+ output = format_services_list(result)
148
+ print(output)
149
+ except ONVIFOperationException as e:
150
+ if isinstance(e.original_exception, (RequestException, TransportError)):
151
+ self._handle_connection_error()
152
+ else:
153
+ print(f"{colorize('Error:', 'red')} {e}")
154
+
155
+ def do_debug(self, _line):
156
+ """Show debug information."""
157
+ if self.context.client.xml_plugin:
158
+ if self.context.last_method and self.context.last_operation_timestamp:
159
+ print(f"{colorize('Last Operation:', 'cyan')}")
160
+ print(
161
+ f" operation: {self.context.last_service_name}.{self.context.last_method}()"
162
+ )
163
+ print(
164
+ f" timestamp: {self.context.last_operation_timestamp.strftime('%Y-%m-%d %H:%M:%S')}\n"
165
+ )
166
+
167
+ print(f"{colorize('Last SOAP Request:', 'cyan')}")
168
+ print(self.context.client.xml_plugin.last_sent_xml or "None")
169
+ print(f"\n{colorize('Last SOAP Response:', 'cyan')}")
170
+ print(self.context.client.xml_plugin.last_received_xml or "None")
171
+ else:
172
+ print(f"{colorize('Debug mode not enabled', 'yellow')}")
173
+ print(
174
+ f"Start CLI with {colorize('--debug', 'white')} flag to enable XML capture"
175
+ )
@@ -0,0 +1,185 @@
1
+ """Navigation commands implementation."""
2
+
3
+ import traceback
4
+ from typing import Callable
5
+
6
+ from onvif.cli.utils import (
7
+ colorize,
8
+ get_device_available_services,
9
+ get_service_methods,
10
+ get_service_required_args,
11
+ parse_json_params,
12
+ )
13
+
14
+ from .context import ShellContext
15
+
16
+
17
+ class NavigationCommands:
18
+ """Provide navigation commands."""
19
+
20
+ context: ShellContext
21
+ _display_grid: Callable[..., None]
22
+ update_prompt: Callable[[], None]
23
+
24
+ def do_ls(self, _line):
25
+ """List available commands/services like TAB completion."""
26
+ if self.context.current_service:
27
+ # In service mode - show available methods
28
+ methods = get_service_methods(self.context.current_service)
29
+ # Add helper commands in service mode
30
+ methods.extend([colorize("type", "yellow"), colorize("desc", "yellow")])
31
+ if methods:
32
+ # Use the same display format as TAB completion
33
+ self._display_grid(methods)
34
+ else:
35
+ print("No methods available")
36
+ else:
37
+ # In root mode - show device-specific services and commands
38
+ services = get_device_available_services(self.context.client)
39
+ commands = self.context.base_commands
40
+ all_items = services + commands
41
+
42
+ if all_items:
43
+ # Use the same display format as TAB completion
44
+ self._display_grid(all_items)
45
+ else:
46
+ print("No commands available")
47
+
48
+ def do_cd(self, line):
49
+ """Change to service directory (alias for entering service)"""
50
+ if not line:
51
+ print("Usage: cd <service_name>")
52
+ available_services = get_device_available_services(self.context.client)
53
+ colored_services = [colorize(svc, "cyan") for svc in available_services]
54
+ print(f"Available services: {', '.join(colored_services)}")
55
+ return None
56
+ return self.do_enter_service(line)
57
+
58
+ def complete_cd(self, text, _line, _begidx, _endidx):
59
+ """Autocomplete service names for cd command."""
60
+ services = get_device_available_services(self.context.client)
61
+ return [s for s in services if s.lower().startswith(text.lower())]
62
+
63
+ def do_up(self, _line):
64
+ """Exit current service mode (go up one level)"""
65
+ if self.context.current_service:
66
+ print(
67
+ f"{colorize('Exited service:', 'yellow')} "
68
+ f"{colorize(f'{self.context.current_service_name}', 'cyan')}"
69
+ )
70
+ self.context.current_service = None
71
+ self.context.current_service_name = None
72
+ self.update_prompt()
73
+ else:
74
+ print("Not in service mode")
75
+
76
+ # pylint: disable=too-many-locals,too-many-branches,too-many-statements
77
+ def do_enter_service(self, line):
78
+ """Enter service mode with optional arguments for services that require them."""
79
+ # Parse service name and arguments
80
+ parts = line.split(None, 1)
81
+ service_name = parts[0] if parts else ""
82
+ args_str = parts[1] if len(parts) > 1 else ""
83
+
84
+ available_services = get_device_available_services(self.context.client)
85
+ if service_name not in available_services:
86
+ print(f"{colorize('Error:', 'red')} Unknown service '{service_name}'")
87
+ colored_services = [colorize(svc, "cyan") for svc in available_services]
88
+ print(f"Available services: {', '.join(colored_services)}")
89
+ return
90
+
91
+ try:
92
+ # Check if this service requires arguments
93
+ required_args = get_service_required_args(service_name)
94
+
95
+ if required_args:
96
+ # Service requires arguments
97
+ if not args_str:
98
+ # No arguments provided, show help
99
+ print(
100
+ f"{colorize('Error:', 'red')} Service '{service_name}' requires arguments"
101
+ )
102
+ print(
103
+ f"{colorize('Usage:', 'yellow')} {service_name} "
104
+ f"{' '.join([f'{arg}=<value>' for arg in required_args])}"
105
+ )
106
+ print(
107
+ f"{colorize('Example:', 'yellow')} "
108
+ f"{service_name} {required_args[0]}=$subscription"
109
+ )
110
+ return
111
+
112
+ # Parse arguments
113
+ try:
114
+ parsed_args = parse_json_params(args_str)
115
+ except (OSError, AttributeError, ValueError, TypeError) as e:
116
+ print(f"{colorize('Error parsing arguments:', 'red')} {e}")
117
+ return
118
+
119
+ # Check if all required arguments are provided
120
+ missing_args = [arg for arg in required_args if arg not in parsed_args]
121
+ if missing_args:
122
+ print(
123
+ f"{colorize('Error:', 'red')} "
124
+ f"Missing required arguments: {', '.join(missing_args)}"
125
+ )
126
+ print(
127
+ f"{colorize('Usage:', 'yellow')} {service_name} "
128
+ f"{' '.join([f'{arg}=<value>' for arg in required_args])}"
129
+ )
130
+ return
131
+
132
+ # Resolve stored references in arguments
133
+ for arg_name in required_args:
134
+ arg_value = parsed_args[arg_name]
135
+ if isinstance(arg_value, str) and arg_value.startswith("$"):
136
+ # Resolve stored reference
137
+ reference = arg_value[1:] # Remove $ prefix
138
+ resolved_value = self._resolve_stored_reference(reference)
139
+ if resolved_value is None:
140
+ print(
141
+ f"{colorize('Error:', 'red')} "
142
+ f"Could not resolve reference '{arg_value}'"
143
+ )
144
+ return
145
+ parsed_args[arg_name] = resolved_value
146
+
147
+ # Call service method with arguments
148
+ service_method = getattr(self.context.client, service_name)
149
+ service = service_method(**parsed_args)
150
+ else:
151
+ # Service doesn't require arguments
152
+ service = getattr(self.context.client, service_name)()
153
+
154
+ self.context.current_service = service
155
+ self.context.current_service_name = service_name
156
+ self.update_prompt()
157
+
158
+ print(
159
+ f"{colorize('Entered service:', 'yellow')} {colorize(service_name, 'cyan')}"
160
+ )
161
+
162
+ # Show available methods
163
+ methods = get_service_methods(service)
164
+ methods_preview = ", ".join(methods[:10])
165
+ if len(methods) > 10:
166
+ print(
167
+ f"{colorize('Available methods:', 'yellow')} {methods_preview} ... "
168
+ f"and {colorize(f'{len(methods) - 10} more.', 'yellow')}"
169
+ )
170
+ print(
171
+ f"Type {colorize('ls', 'cyan')}/press "
172
+ f"<{colorize('TAB', 'yellow')}> to see all."
173
+ )
174
+ else:
175
+ print(f"{colorize('Available methods:', 'yellow')} {methods_preview}")
176
+ print(f"Type {colorize('up', 'cyan')} to exit service mode.")
177
+
178
+ except (OSError, RuntimeError, ValueError, AttributeError) as e:
179
+ print(f"{colorize('Error entering service:', 'red')} {e}")
180
+ if self.context.args.debug:
181
+ traceback.print_exc()
182
+
183
+ def do_exit_service(self, line):
184
+ """Exit current service mode (alias for 'up')"""
185
+ return self.do_up(line)