mms-client 1.3.0__tar.gz → 1.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.
Files changed (38) hide show
  1. {mms_client-1.3.0 → mms_client-1.4.0}/PKG-INFO +24 -3
  2. {mms_client-1.3.0 → mms_client-1.4.0}/README.md +23 -2
  3. {mms_client-1.3.0 → mms_client-1.4.0}/pyproject.toml +1 -1
  4. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/services/base.py +12 -1
  5. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/base.py +1 -1
  6. mms_client-1.4.0/src/mms_client/utils/auditing.py +54 -0
  7. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/utils/web.py +7 -0
  8. {mms_client-1.3.0 → mms_client-1.4.0}/LICENSE +0 -0
  9. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/__init__.py +0 -0
  10. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/client.py +0 -0
  11. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/py.typed +0 -0
  12. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/schemas/wsdl/mi-web-service-jbms.wsdl +0 -0
  13. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/schemas/wsdl/omi-web-service.wsdl +0 -0
  14. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/schemas/xsd/mi-market.xsd +0 -0
  15. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/schemas/xsd/mi-outbnd-reports.xsd +0 -0
  16. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/schemas/xsd/mi-report.xsd +0 -0
  17. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/schemas/xsd/mpr.xsd +0 -0
  18. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/schemas/xsd/omi.xsd +0 -0
  19. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/security/__init__.py +0 -0
  20. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/security/certs.py +0 -0
  21. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/security/crypto.py +0 -0
  22. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/services/__init__.py +0 -0
  23. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/services/market.py +0 -0
  24. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/services/omi.py +0 -0
  25. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/services/registration.py +0 -0
  26. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/services/report.py +0 -0
  27. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/__init__.py +0 -0
  28. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/award.py +0 -0
  29. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/enums.py +0 -0
  30. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/fields.py +0 -0
  31. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/market.py +0 -0
  32. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/offer.py +0 -0
  33. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/registration.py +0 -0
  34. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/resource.py +0 -0
  35. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/types/transport.py +0 -0
  36. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/utils/__init__.py +0 -0
  37. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/utils/errors.py +0 -0
  38. {mms_client-1.3.0 → mms_client-1.4.0}/src/mms_client/utils/serialization.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mms-client
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: API client for accessing the MMS
5
5
  Home-page: https://github.com/ElectroRoute-Japan/mms-client
6
6
  Author: Ryan Wood
@@ -174,14 +174,14 @@ There's a lot of code here but it's not terribly difficult to understand. All th
174
174
  If you want to test your MMS connection, you can try using the test server:
175
175
 
176
176
  ```python
177
- client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, is_admin=True)
177
+ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, test=True)
178
178
  ```
179
179
 
180
180
  ## Connecting as a Market Admin
181
181
  If you're connecting as a market operator (MO), you can connect in admin mode:
182
182
 
183
183
  ```python
184
- client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, test=True)
184
+ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, is_admin=True)
185
185
  ```
186
186
 
187
187
  ## Log Settings
@@ -193,6 +193,27 @@ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.B
193
193
 
194
194
  The client currently logs a number of informational, debug and error messages. You can freely change the logging level yourself.
195
195
 
196
+ ## Auditing XML Requests & Responses
197
+ A common requirement for this sort of library is recording or saving the raw XML requests and responses for audit/logging purposes. This library supports this workflow through the `mms_client.utils.auditing.AuditPlugin` object. This object intercepts the XML request at the Zeep client level right before it is sent to the MMS and, similarly, intercepts the XML response immediately after it is received from the MMS. Before passing these objects on, without modifying them, it records the XML data as a byte string and passes it to two methods: `audit_request` and `audit_response`. These can be overridden by any object that inherits from this class, allowing the user to direct this data to whatever store they prefer to use for auditing or logging.
198
+
199
+ ```python
200
+ class TestAuditPlugin(AuditPlugin):
201
+
202
+ def __init__(self):
203
+ self.request = None
204
+ self.response = None
205
+
206
+ def audit_request(self, mms_request: bytes) -> None:
207
+ self.request = mms_request
208
+
209
+ def audit_response(self, mms_response: bytes) -> None:
210
+ self.response = mms_response
211
+
212
+ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, plugins=[TestAuditPlugin()])
213
+ ```
214
+
215
+ This same input allows for the user to create their own plugins and add them to the Zeep client, allowing for a certain amount of extensibility.
216
+
196
217
  # Completeness
197
218
  This client is not complete. Currently, it supports the following endpoints:
198
219
  - MarketSubmit_OfferData
@@ -142,14 +142,14 @@ There's a lot of code here but it's not terribly difficult to understand. All th
142
142
  If you want to test your MMS connection, you can try using the test server:
143
143
 
144
144
  ```python
145
- client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, is_admin=True)
145
+ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, test=True)
146
146
  ```
147
147
 
148
148
  ## Connecting as a Market Admin
149
149
  If you're connecting as a market operator (MO), you can connect in admin mode:
150
150
 
151
151
  ```python
152
- client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, test=True)
152
+ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, is_admin=True)
153
153
  ```
154
154
 
155
155
  ## Log Settings
@@ -161,6 +161,27 @@ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.B
161
161
 
162
162
  The client currently logs a number of informational, debug and error messages. You can freely change the logging level yourself.
163
163
 
164
+ ## Auditing XML Requests & Responses
165
+ A common requirement for this sort of library is recording or saving the raw XML requests and responses for audit/logging purposes. This library supports this workflow through the `mms_client.utils.auditing.AuditPlugin` object. This object intercepts the XML request at the Zeep client level right before it is sent to the MMS and, similarly, intercepts the XML response immediately after it is received from the MMS. Before passing these objects on, without modifying them, it records the XML data as a byte string and passes it to two methods: `audit_request` and `audit_response`. These can be overridden by any object that inherits from this class, allowing the user to direct this data to whatever store they prefer to use for auditing or logging.
166
+
167
+ ```python
168
+ class TestAuditPlugin(AuditPlugin):
169
+
170
+ def __init__(self):
171
+ self.request = None
172
+ self.response = None
173
+
174
+ def audit_request(self, mms_request: bytes) -> None:
175
+ self.request = mms_request
176
+
177
+ def audit_response(self, mms_response: bytes) -> None:
178
+ self.response = mms_response
179
+
180
+ client = MmsClient(participant="F100", user="FAKEUSER", client_type=ClientType.BSP, cert, plugins=[TestAuditPlugin()])
181
+ ```
182
+
183
+ This same input allows for the user to create their own plugins and add them to the Zeep client, allowing for a certain amount of extensibility.
184
+
164
185
  # Completeness
165
186
  This client is not complete. Currently, it supports the following endpoints:
166
187
  - MarketSubmit_OfferData
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "mms_client"
3
- version = "v1.3.0"
3
+ version = "v1.4.0"
4
4
  description = "API client for accessing the MMS"
5
5
  authors = ["Ryan Wood <ryan.wood@electroroute.co.jp>"]
6
6
  readme = "README.md"
@@ -33,6 +33,7 @@ from mms_client.utils.errors import MMSValidationError
33
33
  from mms_client.utils.serialization import Serializer
34
34
  from mms_client.utils.web import ClientType
35
35
  from mms_client.utils.web import Interface
36
+ from mms_client.utils.web import Plugin
36
37
  from mms_client.utils.web import ZWrapper
37
38
 
38
39
  # Set the default logger for the MMS client
@@ -253,6 +254,7 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
253
254
  client_type: ClientType,
254
255
  cert: Certificate,
255
256
  logger: Optional[Logger] = None,
257
+ plugins: Optional[List[Plugin]] = None,
256
258
  is_admin: bool = False,
257
259
  test: bool = False,
258
260
  ):
@@ -265,6 +267,8 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
265
267
  cert (Certificate): The certificate to use for signing requests.
266
268
  logger (Logger): The logger to use for instrumentation. If this is not provided, then the default
267
269
  logger will be used.
270
+ plugins (List[Plugin]): A list of plugins to add to the Zeep client. This can be useful for auditing or
271
+ other purposes.
268
272
  is_admin (bool): Whether the user is an admin (i.e. is a market operator).
269
273
  test (bool): Whether to use the test server.
270
274
  """
@@ -281,6 +285,7 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
281
285
 
282
286
  # Now, set our logger to either the provided logger or the default logger
283
287
  self._logger = logger or default_logger
288
+ self._plugins = plugins or []
284
289
 
285
290
  # Finally, create a list of wrappers for the different interfaces
286
291
  self._wrappers: Dict[Interface, ZWrapper] = {}
@@ -598,6 +603,12 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
598
603
  if service.interface not in self._wrappers:
599
604
  self._logger.debug(f"Creating wrapper for {service.interface.name} interface.")
600
605
  self._wrappers[service.interface] = ZWrapper(
601
- self._client_type, service.interface, self._cert.to_adapter(), self._logger, True, self._test
606
+ self._client_type,
607
+ service.interface,
608
+ self._cert.to_adapter(),
609
+ self._logger,
610
+ self._plugins,
611
+ True,
612
+ self._test,
602
613
  )
603
614
  return self._wrappers[service.interface]
@@ -115,7 +115,7 @@ class SchemaType(Enum):
115
115
  OMI = "omi.xsd"
116
116
 
117
117
 
118
- class PayloadBase(BaseXmlModel, nsmap={"xsi": "http://www.w3.org/2001/XMLSchema"}):
118
+ class PayloadBase(BaseXmlModel, nsmap={"xsi": "http://www.w3.org/2001/XMLSchema-instance"}):
119
119
  """Represents the base fields for an MMS request payload."""
120
120
 
121
121
  # The XML schema to use for validation
@@ -0,0 +1,54 @@
1
+ """Contains functions for auditability plugins."""
2
+
3
+ from abc import ABC
4
+ from abc import abstractmethod
5
+
6
+ from lxml.etree import _Element as Element
7
+ from lxml.etree import tostring
8
+ from zeep import Plugin
9
+
10
+
11
+ class AuditPlugin(ABC, Plugin):
12
+ """Base class for audit plugins."""
13
+
14
+ def egress(self, envelope: Element, http_headers: dict, operation, binding_options):
15
+ """Handle the MMS request before it is sent.
16
+
17
+ Arguments are the same as in the egress method of the Plugin class.
18
+
19
+ Returns:
20
+ lxml.etree.Element: The XML message to send.
21
+ dict: The HTTP headers to send.
22
+ """
23
+ data = tostring(envelope, encoding="UTF-8", xml_declaration=True)
24
+ self.audit_request(data)
25
+ return envelope, http_headers
26
+
27
+ def ingress(self, envelope: Element, http_headers: dict, operation):
28
+ """Handle the MMS response before it is processed.
29
+
30
+ Arguments are the same as in the ingress method of the Plugin class.
31
+
32
+ Returns:
33
+ lxml.etree.Element: The XML message to process.
34
+ dict: The HTTP headers to process.
35
+ """
36
+ data = tostring(envelope, encoding="UTF-8", xml_declaration=True)
37
+ self.audit_response(data)
38
+ return envelope, http_headers
39
+
40
+ @abstractmethod
41
+ def audit_request(self, mms_request: bytes) -> None:
42
+ """Audit an MMS request.
43
+
44
+ Arguments:
45
+ mms_request (bytes): The MMS request XML to audit.
46
+ """
47
+
48
+ @abstractmethod
49
+ def audit_response(self, mms_response: bytes) -> None:
50
+ """Audit an MMS response.
51
+
52
+ Arguments:
53
+ mms_response (bytes): The MMS response XML to audit.
54
+ """
@@ -3,12 +3,15 @@
3
3
  from enum import Enum
4
4
  from logging import Logger
5
5
  from pathlib import Path
6
+ from typing import List
7
+ from typing import Optional
6
8
 
7
9
  from backoff import expo
8
10
  from backoff import on_exception
9
11
  from requests import Session
10
12
  from requests_pkcs12 import Pkcs12Adapter
11
13
  from zeep import Client
14
+ from zeep import Plugin
12
15
  from zeep import Transport
13
16
  from zeep.cache import SqliteCache
14
17
  from zeep.exceptions import TransportError
@@ -132,6 +135,7 @@ class ZWrapper:
132
135
  interface: Interface,
133
136
  adapter: Pkcs12Adapter,
134
137
  logger: Logger,
138
+ plugins: Optional[List[Plugin]] = None,
135
139
  cache: bool = True,
136
140
  test: bool = False,
137
141
  ):
@@ -147,6 +151,8 @@ class ZWrapper:
147
151
  adapter (Pkcs12Adapter): The PKCS12 adapter containing the certificate and private key to use for
148
152
  authenticating with the MMS server.
149
153
  logger (Logger): The logger to use for instrumentation.
154
+ plugins (List[Plugin]): A list of Zeep plugins to use with the client. This is useful for adding additional
155
+ functionality to the client, such as auditing or logging.
150
156
  cache (bool): If True, use a cache for the Zeep client. This is useful for avoiding repeated
151
157
  lookups of the WSDL file, which should result in lower latency.
152
158
  test (bool): If True, use the test service endpoint. This is useful for testing the client.
@@ -184,6 +190,7 @@ class ZWrapper:
184
190
  self._client = Client(
185
191
  wsdl=str(location.resolve()),
186
192
  transport=Transport(cache=SqliteCache() if cache else None, session=sess),
193
+ plugins=plugins,
187
194
  )
188
195
  self._create_service()
189
196
 
File without changes