onvif-python 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl

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/__init__.py CHANGED
@@ -8,6 +8,7 @@ from .utils import (
8
8
  ONVIFErrorHandler,
9
9
  ZeepPatcher,
10
10
  ONVIFDiscovery,
11
+ ONVIFParser,
11
12
  )
12
13
  from .cli import main as ONVIFCLI
13
14
 
@@ -21,4 +22,5 @@ __all__ = [
21
22
  "ZeepPatcher",
22
23
  "ONVIFCLI",
23
24
  "ONVIFDiscovery",
25
+ "ONVIFParser",
24
26
  ]
onvif/cli/interactive.py CHANGED
@@ -194,7 +194,7 @@ class InteractiveShell(cmd.Cmd):
194
194
  " / __ \\/ | / / | / / _/ ____/",
195
195
  " / / / / |/ /| | / // // /_ ",
196
196
  "/ /_/ / /| / | |/ // // __/ ",
197
- "\\____/_/ |_/ |___/___/_/ v0.2.1",
197
+ "\\____/_/ |_/ |___/___/_/ v0.2.2",
198
198
  " ",
199
199
  ]
200
200
 
@@ -1400,7 +1400,7 @@ class InteractiveShell(cmd.Cmd):
1400
1400
  super().do_help(line)
1401
1401
  else:
1402
1402
  help_text = f"""
1403
- {colorize('ONVIF Interactive Shell — v0.2.1', 'cyan')}\n{colorize('https://github.com/nirsimetri/onvif-python', 'white')}
1403
+ {colorize('ONVIF Interactive Shell — v0.2.2', 'cyan')}\n{colorize('https://github.com/nirsimetri/onvif-python', 'white')}
1404
1404
 
1405
1405
  {colorize('Basic Commands:', 'yellow')}
1406
1406
  capabilities, caps - Show device capabilities
onvif/cli/main.py CHANGED
@@ -21,7 +21,7 @@ def create_parser():
21
21
  """Create argument parser for ONVIF CLI"""
22
22
  parser = argparse.ArgumentParser(
23
23
  prog="onvif",
24
- description=f"{colorize('ONVIF Terminal Client', 'yellow')} — v0.2.1\nhttps://github.com/nirsimetri/onvif-python",
24
+ description=f"{colorize('ONVIF Terminal Client', 'yellow')} — v0.2.2\nhttps://github.com/nirsimetri/onvif-python",
25
25
  formatter_class=argparse.RawDescriptionHelpFormatter,
26
26
  epilog=f"""
27
27
  Examples:
@@ -461,7 +461,7 @@ def main():
461
461
 
462
462
  # Show ONVIF CLI version
463
463
  if args.version:
464
- print(colorize("0.2.1", "yellow"))
464
+ print(colorize("0.2.2", "yellow"))
465
465
  sys.exit(0)
466
466
 
467
467
  # Handle product search
onvif/cli/utils.py CHANGED
@@ -618,7 +618,7 @@ def get_device_available_services(client) -> list:
618
618
  # Security namespace has multiple bindings
619
619
  available_services.extend(
620
620
  [
621
- "advancedsecurity",
621
+ "security",
622
622
  "jwt",
623
623
  "keystore",
624
624
  "tlsserver",
@@ -628,6 +628,100 @@ def get_device_available_services(client) -> list:
628
628
  ]
629
629
  )
630
630
 
631
+ # Additional check: Try to call security.GetServiceCapabilities() to verify availability
632
+ # This is necessary because Security service might not be reported in GetServices/GetCapabilities
633
+ # Use caching to avoid calling GetServiceCapabilities repeatedly
634
+ if "security" not in available_services:
635
+ # Check if we've already tried to get security capabilities
636
+ if not hasattr(client, "_security_capabilities_checked"):
637
+ client._security_capabilities_checked = False
638
+ client._security_capabilities = None
639
+
640
+ if not client._security_capabilities_checked:
641
+ # First time check - call GetServiceCapabilities and cache result
642
+ try:
643
+ security_service = client.security()
644
+ # Try to call GetServiceCapabilities to verify the service is actually available
645
+ caps = security_service.GetServiceCapabilities()
646
+
647
+ # Cache the capabilities for future use
648
+ client._security_capabilities = caps
649
+ client._security_capabilities_checked = True
650
+
651
+ except Exception:
652
+ # Security service not available, mark as checked
653
+ client._security_capabilities_checked = True
654
+ client._security_capabilities = None
655
+
656
+ # Use cached capabilities
657
+ if client._security_capabilities is not None:
658
+ caps = client._security_capabilities
659
+
660
+ # If successful, add main security service
661
+ available_services.append("security")
662
+
663
+ # Check each sub-service capability to determine availability
664
+ # Only add sub-services if their corresponding capability is not None
665
+ if (
666
+ hasattr(caps, "KeystoreCapabilities")
667
+ and caps.KeystoreCapabilities is not None
668
+ ):
669
+ available_services.append("keystore")
670
+
671
+ if (
672
+ hasattr(caps, "TLSServerCapabilities")
673
+ and caps.TLSServerCapabilities is not None
674
+ ):
675
+ available_services.append("tlsserver")
676
+
677
+ if (
678
+ hasattr(caps, "Dot1XCapabilities")
679
+ and caps.Dot1XCapabilities is not None
680
+ ):
681
+ available_services.append("dot1x")
682
+
683
+ if (
684
+ hasattr(caps, "AuthorizationServer")
685
+ and caps.AuthorizationServer is not None
686
+ ):
687
+ available_services.append("authorizationserver")
688
+
689
+ if hasattr(caps, "MediaSigning") and caps.MediaSigning is not None:
690
+ available_services.append("mediasigning")
691
+
692
+ # Additional check for JWT service: Try to call jwt.GetJWTConfiguration()
693
+ # JWT doesn't have a capability in GetServiceCapabilities, so we need to test it directly
694
+ if "jwt" not in available_services:
695
+ # Check if we've already tried to get JWT availability
696
+ if not hasattr(client, "_jwt_checked"):
697
+ client._jwt_checked = False
698
+ client._jwt_available = None
699
+
700
+ if not client._jwt_checked:
701
+ # First time check - try to call GetJWTConfiguration and cache result
702
+ try:
703
+ # JWT service requires xaddr from security service
704
+ # Try to construct xaddr from security service endpoint
705
+ protocol = "https" if client.common_args["use_https"] else "http"
706
+ default_xaddr = f"{protocol}://{client.common_args['host']}:{client.common_args['port']}/onvif/AdvancedSecurity"
707
+
708
+ # Try to call GetJWTConfiguration to verify JWT is available
709
+ jwt_service = client.jwt(xaddr=default_xaddr)
710
+ jwt_service.GetJWTConfiguration()
711
+
712
+ # If successful, JWT is available
713
+ client._jwt_available = True
714
+ client._jwt_checked = True
715
+
716
+ except Exception:
717
+ # JWT service not available, mark as checked
718
+ client._jwt_checked = True
719
+ client._jwt_available = False
720
+
721
+ # Use cached JWT availability
722
+ if client._jwt_available:
723
+ available_services.append("jwt")
724
+
631
725
  return sorted(list(set(available_services))) # Remove duplicates and sort
632
726
 
633
727
 
onvif/client.py CHANGED
@@ -111,6 +111,7 @@ class ONVIFClient:
111
111
  apply_patch: bool = True,
112
112
  capture_xml: bool = False,
113
113
  wsdl_dir: str = None,
114
+ plugins: list = None,
114
115
  ):
115
116
  logger.info(f"Initializing ONVIF client for {host}:{port}")
116
117
  logger.debug(
@@ -131,6 +132,15 @@ class ONVIFClient:
131
132
  logger.debug("Enabling XML capture plugin")
132
133
  self.xml_plugin = XMLCapturePlugin()
133
134
 
135
+ # Merge user plugins with xml_plugin
136
+ all_plugins = []
137
+ if plugins:
138
+ logger.debug(f"Adding {len(plugins)} user-provided plugins")
139
+ all_plugins.extend(plugins)
140
+ if self.xml_plugin:
141
+ logger.debug("Adding XML capture plugin")
142
+ all_plugins.append(self.xml_plugin)
143
+
134
144
  # Store custom WSDL directory if provided
135
145
  self.wsdl_dir = wsdl_dir
136
146
  if wsdl_dir:
@@ -148,7 +158,7 @@ class ONVIFClient:
148
158
  "use_https": use_https,
149
159
  "verify_ssl": verify_ssl,
150
160
  "apply_patch": apply_patch,
151
- "plugins": [self.xml_plugin] if self.xml_plugin else None,
161
+ "plugins": all_plugins if all_plugins else None,
152
162
  }
153
163
 
154
164
  # Device Management (Core) service is always available
@@ -162,6 +172,14 @@ class ONVIFClient:
162
172
  # Temporary variable to hold capabilities
163
173
  self.capabilities = None
164
174
 
175
+ # Cache for security service capabilities (lazy loaded)
176
+ self._security_capabilities = None
177
+ self._security_capabilities_checked = False
178
+
179
+ # Cache for JWT service availability (lazy loaded)
180
+ self._jwt_available = None
181
+ self._jwt_checked = False
182
+
165
183
  try:
166
184
  # Try GetServices first (preferred method)
167
185
  logger.debug("Attempting GetServices call for service discovery")
@@ -722,17 +740,15 @@ class ONVIFClient:
722
740
  if self._security is None:
723
741
  logger.debug("Initializing Security service")
724
742
  self._security = AdvancedSecurity(
725
- xaddr=self._get_xaddr("advancedsecurity", "Security"),
726
743
  **self.common_args,
727
744
  )
728
745
  return self._security
729
746
 
730
747
  @service
731
- def jwt(self, xaddr):
748
+ def jwt(self):
732
749
  if self._jwt is None:
733
750
  logger.debug("Initializing JWT service")
734
- xaddr = self._rewrite_xaddr_if_needed(xaddr)
735
- self._jwt = JWT(xaddr=xaddr, **self.common_args)
751
+ self._jwt = JWT(**self.common_args)
736
752
  return self._jwt
737
753
 
738
754
  @service
@@ -15,7 +15,7 @@ class AdvancedSecurity(ONVIFService):
15
15
  self.operator = ONVIFOperator(
16
16
  definition["path"],
17
17
  binding=f"{{{definition['namespace']}}}{definition['binding']}",
18
- service_path="Security", # fallback
18
+ service_path="device_service", # fallback
19
19
  xaddr=xaddr,
20
20
  **kwargs,
21
21
  )
onvif/utils/__init__.py CHANGED
@@ -7,6 +7,7 @@ from .xml_capture import XMLCapturePlugin
7
7
  from .error_handlers import ONVIFErrorHandler
8
8
  from .discovery import ONVIFDiscovery
9
9
  from .service import ONVIFService
10
+ from .parser import ONVIFParser
10
11
 
11
12
 
12
13
  __all__ = [
@@ -17,4 +18,5 @@ __all__ = [
17
18
  "ONVIFErrorHandler",
18
19
  "ONVIFDiscovery",
19
20
  "ONVIFService",
21
+ "ONVIFParser",
20
22
  ]
onvif/utils/parser.py ADDED
@@ -0,0 +1,136 @@
1
+ # onvif/utils/parser.py
2
+
3
+ import logging
4
+ from typing import List, Dict, Optional
5
+ from zeep import Plugin
6
+
7
+ logger = logging.getLogger(__name__)
8
+ logger.addHandler(logging.NullHandler())
9
+
10
+
11
+ class ONVIFParser(Plugin):
12
+ """
13
+ Lightweight Zeep plugin to extract XML elements from SOAP responses using XPath.
14
+
15
+ This plugin extracts specific XML elements from raw SOAP responses before zeep
16
+ parses them into Python objects. This is useful for extracting data that zeep
17
+ doesn't parse correctly, such as simpleContent elements with attributes (e.g., Topic).
18
+
19
+ Unlike XMLCapturePlugin which stores full XML history in memory, ONVIFParser only
20
+ extracts and caches specified element texts from the last response.
21
+
22
+ Usage Example 1 - Extract Topic from event notifications:
23
+ >>> from onvif import ONVIFClient
24
+ >>> from onvif.utils import ONVIFParser
25
+ >>>
26
+ >>> # Create parser to extract Topic elements
27
+ >>> parser = ONVIFParser(extract_xpaths={
28
+ ... 'topic': './/{http://docs.oasis-open.org/wsn/b-2}Topic'
29
+ ... })
30
+ >>>
31
+ >>> # Pass parser to client as plugin
32
+ >>> client = ONVIFClient(host, port, user, pass, plugins=[parser])
33
+ >>>
34
+ >>> # Make SOAP call
35
+ >>> pullpoint = client.pullpoint(subscription)
36
+ >>> msgs = pullpoint.PullMessages(Timeout="PT5S", MessageLimit=10)
37
+ >>>
38
+ >>> # Extract topic texts (cache auto-cleared on next SOAP call)
39
+ >>> topics = parser.get_extracted_texts('topic', count=10)
40
+ >>> for topic in topics:
41
+ ... print(f"Topic: {topic}")
42
+
43
+ Usage Example 2 - Extract multiple elements:
44
+ >>> parser = ONVIFParser(extract_xpaths={
45
+ ... 'topic': './/{http://docs.oasis-open.org/wsn/b-2}Topic',
46
+ ... 'custom': './/ns:CustomElement'
47
+ ... })
48
+ >>> client = ONVIFClient(host, port, user, pass, plugins=[parser])
49
+ >>>
50
+ >>> # After SOAP call
51
+ >>> topics = parser.get_extracted_texts('topic', count=5)
52
+ >>> customs = parser.get_extracted_texts('custom', count=5)
53
+
54
+ Notes:
55
+ - Uses ingress() hook to access raw XML before zeep parsing
56
+ - Cache automatically cleared on each SOAP response
57
+ - Thread-safe for single client usage
58
+ - Works with any XPath expression
59
+ """
60
+
61
+ def __init__(self, extract_xpaths: Dict[str, str]):
62
+ """
63
+ Initialize XML element parser.
64
+
65
+ Args:
66
+ extract_xpaths: Dictionary mapping names to XPath expressions. XPath expressions will be used to find elements in SOAP response.
67
+ Example: {
68
+ 'topic': './/{http://docs.oasis-open.org/wsn/b-2}Topic',
69
+ 'custom': './/ns:CustomElement'
70
+ }
71
+ """
72
+ self.extract_xpaths = extract_xpaths
73
+ self._extracted_elements = {}
74
+
75
+ logger.debug(
76
+ f"ONVIFParser initialized with XPaths: {list(extract_xpaths.keys())}"
77
+ )
78
+
79
+ def ingress(self, envelope, http_headers, operation):
80
+ """
81
+ Zeep plugin hook - called when SOAP response is received.
82
+
83
+ Extracts element texts from raw XML envelope using configured XPath expressions.
84
+ The envelope at this stage is an lxml Element tree, allowing XPath queries.
85
+
86
+ Cache is automatically cleared before extracting new elements to prevent memory accumulation.
87
+
88
+ Args:
89
+ envelope: lxml Element representing SOAP envelope
90
+ http_headers: HTTP response headers
91
+ operation: Zeep operation being executed
92
+
93
+ Returns:
94
+ Tuple of (envelope, http_headers) to pass to next plugin
95
+ """
96
+ # Auto-clear cache from previous response
97
+ self._extracted_elements = {}
98
+
99
+ try:
100
+ # Extract elements using XPath from raw XML envelope
101
+ for name, xpath in self.extract_xpaths.items():
102
+ elements = envelope.findall(xpath)
103
+
104
+ # Extract text content from found elements
105
+ texts = [elem.text for elem in elements if elem.text]
106
+
107
+ if texts:
108
+ self._extracted_elements[name] = texts
109
+ logger.debug(
110
+ f"ONVIFParser: Extracted {len(texts)} '{name}' elements"
111
+ )
112
+
113
+ except Exception as e:
114
+ logger.warning(f"ONVIFParser: Failed to extract elements: {e}")
115
+
116
+ return envelope, http_headers
117
+
118
+ def get_extracted_texts(self, name: str, count: int) -> List[Optional[str]]:
119
+ """
120
+ Get extracted element texts by name.
121
+
122
+ Args:
123
+ name: Name of the extracted elements (key from extract_xpaths dict)
124
+ count: Number of elements to return
125
+
126
+ Returns:
127
+ List of element text values, padded with None if fewer elements were found.
128
+ Example: If 3 elements found but count=5, returns [text1, text2, text3, None, None]
129
+ """
130
+ texts = self._extracted_elements.get(name, [])[:count]
131
+
132
+ # Pad with None if not enough elements
133
+ while len(texts) < count:
134
+ texts.append(None)
135
+
136
+ return texts
@@ -22,15 +22,6 @@ class XMLCapturePlugin(Plugin):
22
22
  - Operation names for context
23
23
  - Complete history of all transactions
24
24
 
25
- Key Features:
26
- - Pretty-printed XML with proper indentation
27
- - Last request/response quick access
28
- - Full transaction history storage
29
- - HTTP header capture
30
- - Operation name tracking
31
- - File export capability
32
- - Secure XML parsing (XXE protection)
33
-
34
25
  Use Cases:
35
26
  1. **Debugging**: See exact SOAP messages being sent/received
36
27
  2. **Learning**: Understand ONVIF protocol structure
onvif/utils/zeep.py CHANGED
@@ -360,8 +360,7 @@ class ZeepPatcher:
360
360
  )
361
361
 
362
362
  if should_flatten:
363
- # This is truly a wrapper - flatten by copying fields to parent
364
- # But still set the tag_name field to the inner_content
363
+ # This is truly a wrapper - flatten by extracting children to parent
365
364
  # Convert zeep object to dict to preserve manually added attributes
366
365
  if hasattr(inner_content, "__values__") or hasattr(
367
366
  inner_content, "__dict__"
@@ -369,8 +368,23 @@ class ZeepPatcher:
369
368
  inner_content = ZeepPatcher._zeep_object_to_dict(
370
369
  inner_content
371
370
  )
371
+
372
+ # Set the wrapper field itself
372
373
  values[tag_name] = inner_content
373
- # Don't copy fields up to parent - keep them in the structured object
374
+
375
+ # If inner_content is a dict with children, copy them to parent too
376
+ if isinstance(inner_content, dict):
377
+ for child_key, child_val in inner_content.items():
378
+ if child_key.startswith("_"):
379
+ continue
380
+ # Copy children to parent level if field exists and is None
381
+ if (
382
+ child_key in values
383
+ and values[child_key] is None
384
+ ):
385
+ values[child_key] = child_val
386
+ elif child_key not in values:
387
+ values[child_key] = child_val
374
388
  else:
375
389
  # Not a wrapper - just set the field directly
376
390
  # Convert zeep object to dict to preserve manually added attributes
@@ -448,6 +462,20 @@ class ZeepPatcher:
448
462
  inner_content
449
463
  )
450
464
  setattr(obj, tag_name, inner_content)
465
+
466
+ # If inner_content is a dict with children, copy them to parent too
467
+ if isinstance(inner_content, dict):
468
+ for child_key, child_val in inner_content.items():
469
+ if child_key.startswith("_"):
470
+ continue
471
+ # Copy children to parent level if field exists and is None
472
+ if (
473
+ hasattr(obj, child_key)
474
+ and getattr(obj, child_key) is None
475
+ ):
476
+ setattr(obj, child_key, child_val)
477
+ elif not hasattr(obj, child_key):
478
+ setattr(obj, child_key, child_val)
451
479
  else:
452
480
  # Not a wrapper - just set the field directly
453
481
  # Convert zeep object to dict to preserve manually added attributes
@@ -611,7 +639,14 @@ class ZeepPatcher:
611
639
  child_result[child_qname.localname] = parsed
612
640
 
613
641
  parsed_result[tag_name] = child_result
642
+ elif xmlelement.attrib:
643
+ # Element has attributes but no children - parse attributes
644
+ parsed_result[tag_name] = {
645
+ k: ZeepPatcher.parse_text_value(v)
646
+ for k, v in xmlelement.attrib.items()
647
+ }
614
648
  else:
649
+ # Element has no attributes and no children - just text content
615
650
  parsed_result[tag_name] = ZeepPatcher.parse_text_value(xmlelement.text)
616
651
 
617
652
  # Store original elements in a special key for later restoration
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onvif-python
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A modern Python library for ONVIF-compliant devices
5
5
  Author-email: Nirsimetri Technologies® <open@nirsimetri.com>
6
6
  Maintainer: Kaburagi
@@ -47,7 +47,7 @@ Dynamic: license-file
47
47
 
48
48
  [![Codacy grade](https://img.shields.io/codacy/grade/bff08a94e4d447b690cea49c6594826d?label=Code%20Quality&logo=codacy)](https://app.codacy.com/gh/nirsimetri/onvif-python/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
49
49
  [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/nirsimetri/onvif-python)
50
- [![PyPI](https://img.shields.io/badge/PyPI-0.2.1-orange?logo=archive)](https://pypi.org/project/onvif-python/)
50
+ [![PyPI](https://img.shields.io/badge/PyPI-0.2.2-orange?logo=archive)](https://pypi.org/project/onvif-python/)
51
51
  [![Downloads](https://img.shields.io/pypi/dm/onvif-python?label=Downloads&color=red)](https://clickpy.clickhouse.com/dashboard/onvif-python)
52
52
  <br>
53
53
  [![Build](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml/badge.svg?branch=main)](https://github.com/nirsimetri/onvif-python/actions/workflows/python-app.yml)
@@ -356,7 +356,7 @@ usage: onvif [-h] [--host HOST] [--port PORT] [--username USERNAME] [--password
356
356
  [--no-verify] [--no-patch] [--interactive] [--debug] [--wsdl WSDL] [--cache {all,db,mem,none}] [--health-check-interval HEALTH_CHECK_INTERVAL] [--version]
357
357
  [service] [method] [params ...]
358
358
 
359
- ONVIF Terminal Client — v0.2.1
359
+ ONVIF Terminal Client — v0.2.2
360
360
  https://github.com/nirsimetri/onvif-python
361
361
 
362
362
  positional arguments:
@@ -429,7 +429,7 @@ Examples:
429
429
  <summary><b>2. Interactive Shell</b></summary>
430
430
 
431
431
  ```bash
432
- ONVIF Interactive Shell — v0.2.1
432
+ ONVIF Interactive Shell — v0.2.2
433
433
  https://github.com/nirsimetri/onvif-python
434
434
 
435
435
  Basic Commands:
@@ -1108,9 +1108,9 @@ Some ONVIF services have multiple bindings in the same WSDL. These typically inc
1108
1108
  2. **Security (Advanced Security)**
1109
1109
  - **Root:** `AdvancedSecurityServiceBinding`
1110
1110
  - **Sub-bindings:**
1111
+ - `JWTBinding`
1111
1112
  - `AuthorizationServerBinding`
1112
1113
  - `KeystoreBinding`
1113
- - `JWTBinding`
1114
1114
  - `Dot1XBinding`
1115
1115
  - `TLSServerBinding`
1116
1116
  - `MediaSigningBinding`
@@ -1118,9 +1118,9 @@ Some ONVIF services have multiple bindings in the same WSDL. These typically inc
1118
1118
  Usage in library:
1119
1119
  ```python
1120
1120
  client.security() # root binding
1121
+ client.jwt() # sub-binding accessor
1121
1122
  client.authorizationserver(xaddr) # sub-binding accessor (requires xAddr)
1122
1123
  client.keystore(xaddr) # ..
1123
- client.jwt(xaddr)
1124
1124
  client.dot1x(xaddr)
1125
1125
  client.tlsserver(xaddr)
1126
1126
  client.mediasigning(xaddr)
@@ -1,11 +1,11 @@
1
- onvif/__init__.py,sha256=BjW2KsafIGzybY_IeffeAPdmDDXuxA6G4uo5sl42Dtw,463
2
- onvif/client.py,sha256=ld5Gm7B-1XvNNcfS-FAILrnKs8bPbbXGpnKbU-7Vmrw,26198
1
+ onvif/__init__.py,sha256=JYjHyKme5ou0I63dBnArAwN1rAIFalHXv_AgIgLgT-Y,499
2
+ onvif/client.py,sha256=0G4AG-IJyaCheR2jXbZDWL_p5tx-wGRnXelMRKNS2bc,26693
3
3
  onvif/operator.py,sha256=fBaoWYC3ZVFdgd2S_cmztWiLAA-HaWwSflq278YNlTs,13970
4
4
  onvif/cli/__init__.py,sha256=y3hc-mo-Iwwxf8m5vo9P_0m2ISzGuOy-jaRPkdRY05A,68
5
5
  onvif/cli/__main__.py,sha256=IZyZcevWVKE1BzdFY53a3MjOOfybncGVVXQ_7lZ3TOQ,165
6
- onvif/cli/interactive.py,sha256=76Eh407wIPOzdudxqEzfls9ntLcCN_l9-JLFj29AXDE,59756
7
- onvif/cli/main.py,sha256=pBIEdsT2y1B-9mCMRNnSZ_W5fr4t8suCqmBdSxzDCoQ,27312
8
- onvif/cli/utils.py,sha256=FSu_fZGAMQTLb4h9HzNSgz8vHtLD8Mc540WSKlyVPHQ,54962
6
+ onvif/cli/interactive.py,sha256=vlcCbmCyB5nWv0LwG4DloR5n4Q9PTdXkTfZBk6jsNf4,59756
7
+ onvif/cli/main.py,sha256=G82DSIogd6Wc6KTIPmU6dS-mJna6z-0KYYPZYxSQGuE,27312
8
+ onvif/cli/utils.py,sha256=t84r0NkqqaaV0xWvBSgP9FYZIFYpJwPINAcrDVZ9Eq8,59109
9
9
  onvif/db/companies.db,sha256=yJ8bSHfGpxNnA5NRBhYOFS_1Pix-KgH8GnUFV3ytzPo,270336
10
10
  onvif/db/products.db,sha256=4BVPfy6i6pLMLQyfue238uRp6_NIDodu4QXd9iCoooY,81559552
11
11
  onvif/services/__init__.py,sha256=1CJDDq656ag8VR19Mnm_0N-1Avd0t2832Jze-30wnMY,2005
@@ -38,21 +38,22 @@ onvif/services/events/events.py,sha256=Km8fOEOLpWvNMDI4biAqSTPVEbs0FvXBGsMp_sAOA
38
38
  onvif/services/events/notification.py,sha256=l0RVuxpdGxss9CRcI8hOMP0E1gYD9e3nVISF_-hctwk,1263
39
39
  onvif/services/events/pullpoint.py,sha256=mSegFY3AJ4rLkO3nWJ-G37opEAiSKCj7TGh3RDWXKyU,1145
40
40
  onvif/services/events/subscription.py,sha256=a-rQgW4eSRlOCuitxnwJ7krTXyKfCHg4mn9S0_rTT8g,883
41
- onvif/services/security/advancedsecurity.py,sha256=pQmrJxyq4DAgNiePqSizttxWFxXygR9lA5juB81apkU,949
41
+ onvif/services/security/advancedsecurity.py,sha256=vA5l1894H2Kw_ZI-h3_prahWdmHvNeL0bJgMmtbvhVg,955
42
42
  onvif/services/security/authorizationserver.py,sha256=1eKd_wjGE1Ues7egLL54VLvJ7zUGTcBIZNbZxiPSdLc,1501
43
43
  onvif/services/security/dot1x.py,sha256=biQrWH6aCXwxK7Hy_BcH1SHMyp8J0BHQ5MHKai36sXE,1808
44
44
  onvif/services/security/jwt.py,sha256=_jiFliLK5pjErgAED5z6S2DTLEP8eezikq6KGJ96g08,976
45
45
  onvif/services/security/keystore.py,sha256=P9QYieCAZ3yf5Gq6DZKpG832XD-rNVateFxlZBiV0bk,7285
46
46
  onvif/services/security/mediasigning.py,sha256=7ia_NIdLM3kwZwwOM95WfR0TTXkZSYCt6j8wL5Vl7zI,1361
47
47
  onvif/services/security/tlsserver.py,sha256=UO_0VHtbu0Zx1cOsJePtEwPbmYL0RHyRhoInCWIzx_M,3412
48
- onvif/utils/__init__.py,sha256=IKQcaVblxuCyFzg0wFRuGyRcVboYpqjNBdp6_iExSTM,467
48
+ onvif/utils/__init__.py,sha256=5bXw0F0jOhBSYwF8lsy9GIA1JTRFKLeaB5UYc2MX-Bg,518
49
49
  onvif/utils/discovery.py,sha256=YO44KiQhfcyUECNrRe4qe03DSh14GGVByu1W5ekbAXU,14765
50
50
  onvif/utils/error_handlers.py,sha256=MwPNfUeDA6d_nNZ01P0Ut67ERBYVvjsYrRsQhIo28yc,4851
51
51
  onvif/utils/exceptions.py,sha256=5DxvqKAL7w038qPFeWmtkR5F3jWK0nz0qerzsOQPh0k,7788
52
+ onvif/utils/parser.py,sha256=QYzzIqsP1RuSIdx0SYPnighomYkLsfroRPMcjGOmgeo,5125
52
53
  onvif/utils/service.py,sha256=VTCOY5PMjaY9KgCznDomTcPLVIorIRnqBPd7VCoLxAM,12722
53
54
  onvif/utils/wsdl.py,sha256=9VqJwxjyrz_gtNQ5IHPQ0pjek6Y0aOOkencWXkUGKp4,27250
54
- onvif/utils/xml_capture.py,sha256=pZF-14QUG4gFcfZDvG6ykVEMI0xLNgUv4rtzNdR1GNI,8287
55
- onvif/utils/zeep.py,sha256=NFNL2f7Nrr6-CQyQ02n3jMCZ73EEPNct9IgAXzBgVk4,28593
55
+ onvif/utils/xml_capture.py,sha256=r8N2_D1hbKywMdftlTTMnxPhzxOsJDLkEJDKgudfpbo,7984
56
+ onvif/utils/zeep.py,sha256=a5naCxLg7PRrKFB59TOlJbGyFpxUh9HZ1zAs-r14ojs,30609
56
57
  onvif/wsdl/LICENSE.md,sha256=O0J5vlcNSuEulS5rESOZWYy-IEnH4QeJkQ4ebZZNkSQ,16439
57
58
  onvif/wsdl/ver10/actionengine.wsdl,sha256=mQCRdRMdh517EUkDCKEfBHl_GvX9dPABqtgwU9K8FWE,55762
58
59
  onvif/wsdl/ver10/analyticsdevice.wsdl,sha256=JCd2pab5RAgoPm_26Q3l6sda8cGkam4dsXeluJ4euyA,30999
@@ -112,9 +113,9 @@ onvif/wsdl/ver20/util/federated_search_documentation.html,sha256=GR6a4SPBsRDisaW
112
113
  onvif/wsdl/ver20/util/fedsearch-docu-viewer.xsl,sha256=8eP-uMZgsTtuU5WaVyCzs_DJZqWIFD7iRz_5-3ComPg,325
113
114
  onvif/wsdl/ver20/util/onvif-wsdl-viewer.xsl,sha256=Emauxs6rh69IxlxlU3k_LEH_i3SsRbwIKUk-VcMlVgk,94525
114
115
  onvif/wsdl/ver20/util/operationIndex.html,sha256=mUsAGgNUFCIQjVV9Rx_O5YUNW3EdWNhUkAbBY-xVMhQ,39290
115
- onvif_python-0.2.1.dist-info/licenses/LICENSE.md,sha256=ya8FumJeUkFWwCMkG9KdMxHWRWMNhtI3vHzzAWPQS8s,1091
116
- onvif_python-0.2.1.dist-info/METADATA,sha256=rR-QwCLigV-WgAtXUbTBaRrddC-XXkhPBiwNMVBU2uE,60787
117
- onvif_python-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
118
- onvif_python-0.2.1.dist-info/entry_points.txt,sha256=7xUdI64yzWh7YfNPQDKCW9cT8XIgWuNCloikP9-yjqY,46
119
- onvif_python-0.2.1.dist-info/top_level.txt,sha256=MqCi1uJmIvtVFJDz2IxLbpwq6FwDtWhqrWQtKwLaQg4,6
120
- onvif_python-0.2.1.dist-info/RECORD,,
116
+ onvif_python-0.2.2.dist-info/licenses/LICENSE.md,sha256=ya8FumJeUkFWwCMkG9KdMxHWRWMNhtI3vHzzAWPQS8s,1091
117
+ onvif_python-0.2.2.dist-info/METADATA,sha256=CN636idmdC-V40qde6INqJGTyONKJXBSWvmj6n9LxA4,60827
118
+ onvif_python-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
119
+ onvif_python-0.2.2.dist-info/entry_points.txt,sha256=7xUdI64yzWh7YfNPQDKCW9cT8XIgWuNCloikP9-yjqY,46
120
+ onvif_python-0.2.2.dist-info/top_level.txt,sha256=MqCi1uJmIvtVFJDz2IxLbpwq6FwDtWhqrWQtKwLaQg4,6
121
+ onvif_python-0.2.2.dist-info/RECORD,,