mms-client 1.0.6__py3-none-any.whl → 1.1.0__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.
- mms_client/services/registration.py +64 -0
- mms_client/types/base.py +3 -1
- mms_client/types/enums.py +8 -0
- mms_client/types/fields.py +150 -2
- mms_client/types/offer.py +16 -4
- mms_client/types/registration.py +47 -0
- mms_client/types/resource.py +1064 -0
- mms_client/types/transport.py +1 -1
- mms_client/utils/serialization.py +18 -8
- {mms_client-1.0.6.dist-info → mms_client-1.1.0.dist-info}/METADATA +18 -2
- {mms_client-1.0.6.dist-info → mms_client-1.1.0.dist-info}/RECORD +13 -11
- {mms_client-1.0.6.dist-info → mms_client-1.1.0.dist-info}/LICENSE +0 -0
- {mms_client-1.0.6.dist-info → mms_client-1.1.0.dist-info}/WHEEL +0 -0
mms_client/types/transport.py
CHANGED
|
@@ -129,7 +129,7 @@ class Serializer:
|
|
|
129
129
|
# Now, verify that the response doesn't contain an unexpected data type and then retrieve the payload data
|
|
130
130
|
# from within the envelope
|
|
131
131
|
self._verify_tree_data_tag(envelope_node, data_type)
|
|
132
|
-
resp.payload = self._from_tree_data(envelope_node.find(data_type
|
|
132
|
+
resp.payload = self._from_tree_data(envelope_node.find(get_tag(data_type)), data_type)
|
|
133
133
|
|
|
134
134
|
# Finally, attempt to extract the messages from within the payload
|
|
135
135
|
resp.messages = self._from_tree_messages(raw, envelope_type, data_type, self._payload_key, False)
|
|
@@ -167,7 +167,7 @@ class Serializer:
|
|
|
167
167
|
# Note: apparently, mypy doesn't know about setter-getter properties either...
|
|
168
168
|
self._verify_tree_data_tag(env_node, data_type)
|
|
169
169
|
resp.payload = [
|
|
170
|
-
self._from_tree_data(item, data_type) for item in env_node.findall(data_type
|
|
170
|
+
self._from_tree_data(item, data_type) for item in env_node.findall(get_tag(data_type)) # type: ignore[misc]
|
|
171
171
|
]
|
|
172
172
|
|
|
173
173
|
# Finally, attempt to extract the messages from within the payload
|
|
@@ -216,7 +216,7 @@ class Serializer:
|
|
|
216
216
|
ValueError: If the expected data type is not found in the response.
|
|
217
217
|
"""
|
|
218
218
|
data_tags = set(node.tag for node in raw)
|
|
219
|
-
if not data_tags.issubset([data_type.__name__, "Messages"]):
|
|
219
|
+
if not data_tags.issubset([data_type.__name__, data_type.__xml_tag__, "Messages"]):
|
|
220
220
|
raise ValueError(f"Expected data type '{data_type.__name__}' not found in response")
|
|
221
221
|
|
|
222
222
|
def _from_tree_data(self, raw: Optional[Element], data_type: Type[P]) -> Optional[ResponseData[P]]:
|
|
@@ -291,8 +291,7 @@ class Serializer:
|
|
|
291
291
|
)
|
|
292
292
|
else:
|
|
293
293
|
# Iterate over each field on the current type...
|
|
294
|
-
for
|
|
295
|
-
print(f"Checking field {name} with type {field.annotation}...")
|
|
294
|
+
for field in current_type.model_fields.values():
|
|
296
295
|
|
|
297
296
|
# First, get the arguments and origin of the field's annotation
|
|
298
297
|
args = get_args(field.annotation)
|
|
@@ -420,7 +419,7 @@ def _create_response_payload_type(key: str, envelope_type: Type[E], data_type: T
|
|
|
420
419
|
|
|
421
420
|
|
|
422
421
|
@lru_cache(maxsize=None)
|
|
423
|
-
def _create_response_common_type(tag_type: Type) -> Type[ResponseCommon]:
|
|
422
|
+
def _create_response_common_type(tag_type: Type[Union[E, P]]) -> Type[ResponseCommon]:
|
|
424
423
|
"""Create a new wrapper for the ResponseCommon type with the given tag.
|
|
425
424
|
|
|
426
425
|
This method is intended to save us the overhead of writing a new class for each tag type. Instead, we can
|
|
@@ -432,7 +431,7 @@ def _create_response_common_type(tag_type: Type) -> Type[ResponseCommon]:
|
|
|
432
431
|
Returns: The wrapper type that will be used for deserialization.
|
|
433
432
|
""" # fmt: skip
|
|
434
433
|
# First, create a new wrapper type that contains the ResponseCommon type with the appropriate XML tag
|
|
435
|
-
class Wrapper(ResponseCommon, tag=tag_type
|
|
434
|
+
class Wrapper(ResponseCommon, tag=get_tag(tag_type)): # type: ignore[call-arg]
|
|
436
435
|
"""Wrapper for the validation object with the proper XML tag."""
|
|
437
436
|
|
|
438
437
|
# Finally, return the wrapper type so we can instantiate it
|
|
@@ -462,7 +461,7 @@ def _create_request_payload_type(key: str, envelope_type: Type[E], data_type: Ty
|
|
|
462
461
|
"""Wrapper for the data type that will be used to store the data in the payload."""
|
|
463
462
|
|
|
464
463
|
# The data to be stored in the payload
|
|
465
|
-
data: data_type = element(tag=data_type
|
|
464
|
+
data: data_type = element(tag=get_tag(data_type)) # type: ignore[valid-type]
|
|
466
465
|
|
|
467
466
|
def __init__(self, envelope: envelope_type, data: data_type): # type: ignore[valid-type]
|
|
468
467
|
"""Create a new envelope to store payload data.
|
|
@@ -511,3 +510,14 @@ def _find_or_fail(node: Element, tag: str) -> Element:
|
|
|
511
510
|
if found is None:
|
|
512
511
|
raise ValueError(f"Expected tag '{tag}' not found in node") # pragma: no cover
|
|
513
512
|
return found
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def get_tag(data_type: Type[P]) -> str:
|
|
516
|
+
"""Get the tag for the given data type.
|
|
517
|
+
|
|
518
|
+
Arguments:
|
|
519
|
+
data_type (Type[Payload]): The data type to get the tag for.
|
|
520
|
+
|
|
521
|
+
Returns: The tag for the given data type.
|
|
522
|
+
"""
|
|
523
|
+
return data_type.__xml_tag__ or data_type.__name__
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mms-client
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: API client for accessing the MMS
|
|
5
|
+
Home-page: https://github.com/ElectroRoute-Japan/mms-client
|
|
5
6
|
Author: Ryan Wood
|
|
6
7
|
Author-email: ryan.wood@electroroute.co.jp
|
|
7
8
|
Requires-Python: >=3.11,<4.0
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Framework :: Pydantic :: 2
|
|
11
|
+
Classifier: Framework :: Pytest
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: The Unlicense (Unlicense)
|
|
14
|
+
Classifier: Natural Language :: English
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
8
16
|
Classifier: Programming Language :: Python :: 3
|
|
9
17
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
10
21
|
Requires-Dist: backoff (>=2.2.1,<3.0.0)
|
|
11
22
|
Requires-Dist: cryptography (>=42.0.5,<43.0.0)
|
|
12
23
|
Requires-Dist: lxml (>=5.1.0,<6.0.0)
|
|
@@ -32,6 +43,9 @@ The underlying API sends and receives XML documents. Each of these request or re
|
|
|
32
43
|
|
|
33
44
|
After the data has been converted and added to the outer request object, it is sent to the appropriate server endpoint via a Zeep client. The client certificate is also injected into the request using a PCKS12 adaptor.
|
|
34
45
|
|
|
46
|
+
# Serialization
|
|
47
|
+
This library relies on Pydantic 2 and the pydantic-xml library for serialization/deserialization. As such, any type in this library can be converted to not only XML, but to JSON as well. This is extremely useful if you're trying to build a pass-through API service or something similar.
|
|
48
|
+
|
|
35
49
|
## Client Types
|
|
36
50
|
Clients cannot call any and all endpoints in this API, willy-nilly. Some endpoints are restricted to particular clients. At the moment, there are two clients: Balance Service Providers (BSPs) and Transmission Service Operators (TSOs). Most likely you're operating as a BSP, in which case you'll have access to all endpoints. However, it makes little sense for a TSO to be able to submit bids on their own power, so they are restricted to a read-only role in most cases.
|
|
37
51
|
|
|
@@ -43,7 +57,7 @@ The MMS has two separate endpoints, depending on whether you want to access mark
|
|
|
43
57
|
# Object Hierarchy
|
|
44
58
|
The object hierarchy contained in this project is not trivial, and perhaps that reflects a bit of overengineering on our part. However, we chose the paradigm we did to reduce the number of types which had to be exposed to the user. The diagram below indicates how this hierarchy works:
|
|
45
59
|
|
|
46
|
-

|
|
47
61
|
|
|
48
62
|
Note that there are some types here that are shared between the request and response: mainly, anything inheriting from `mms_client.types.base.Envelop` or `mms_client.types.base.Payload`. For users of the client, only the Payload types need ever be used. Everything else has been obfuscated away, so it is unecessary for the user to have access to these. However, we will explain our reasoning here to provide additional context.
|
|
49
63
|
|
|
@@ -184,6 +198,8 @@ This client is not complete. Currently, it supports the following endpoints:
|
|
|
184
198
|
- MarketSubmit_OfferData
|
|
185
199
|
- MarketQuery_OfferQuery
|
|
186
200
|
- MarketCancel_OfferCancel
|
|
201
|
+
- RegistrationSubmit_Resource
|
|
202
|
+
- RegistrationQuery_Resource
|
|
187
203
|
|
|
188
204
|
We can add support for additional endpoints as time goes on, and independent contribution is, of course, welcome. However, support for attachments is currently limited because none of the endpoints we support currently require them. We have implemented attachment support up to the client level, but we haven't developed an architecture for submitting them through an endpoint yet.
|
|
189
205
|
|
|
@@ -15,20 +15,22 @@ mms_client/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
|
15
15
|
mms_client/services/base.py,sha256=8yWBeDoBimY9BZeMOkMDV-ggvPTzZHnlqXiv9eo8fIQ,25363
|
|
16
16
|
mms_client/services/market.py,sha256=kwcbXz1Op4hwXbOn_Xsx_qBNuHfvWAxBH6G2f4AWzPI,4892
|
|
17
17
|
mms_client/services/omi.py,sha256=h6cM5U3-iSm0YiIaJwqYTZeI5uhLbA7FPxh_qy_3qww,521
|
|
18
|
-
mms_client/services/registration.py,sha256=
|
|
18
|
+
mms_client/services/registration.py,sha256=9pNZdgwRbJJCnmsVgESNnc3ywkn-wdQryumUhLn6Xvg,3419
|
|
19
19
|
mms_client/services/report.py,sha256=HYVJNwEHo6ZC6497UqO5y1IqZ2ga3kVH5AepdxhYfug,537
|
|
20
20
|
mms_client/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
-
mms_client/types/base.py,sha256=
|
|
22
|
-
mms_client/types/enums.py,sha256=
|
|
23
|
-
mms_client/types/fields.py,sha256=
|
|
21
|
+
mms_client/types/base.py,sha256=wrDPn9io30in_w2qKa4A503gX_gAaMT7a1MpZ3HcmIc,9701
|
|
22
|
+
mms_client/types/enums.py,sha256=wXlXvifWXWm9dowfG5iQlkax_6OX6z2nHid94WkhQwE,464
|
|
23
|
+
mms_client/types/fields.py,sha256=SAvrDJGSvOVtbGvaaqLFBx2mCr0AxzqVFUTJgPSEDOY,12065
|
|
24
24
|
mms_client/types/market.py,sha256=OKjBIx9aIgaLUci6b5WoB4NZbFncRbbd2FxeAvW1iWw,2588
|
|
25
|
-
mms_client/types/offer.py,sha256=
|
|
26
|
-
mms_client/types/
|
|
25
|
+
mms_client/types/offer.py,sha256=orlohxAWZlW2rwPJpGAoiy1knoCT2x2sXJyzThkXYVY,7693
|
|
26
|
+
mms_client/types/registration.py,sha256=Nir73S3ffpk0O_fnTD2alFaqV1k67_8dcyyduXvPBI4,1381
|
|
27
|
+
mms_client/types/resource.py,sha256=_pRNAqOX8A0lUXmU8qO_8QwRtRx9BwZDdrN-w_Fnu38,66466
|
|
28
|
+
mms_client/types/transport.py,sha256=vyosoeGSdYthqlmiyDAkZusYa8yVHUwOzfTqwZne2Ik,4407
|
|
27
29
|
mms_client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
30
|
mms_client/utils/errors.py,sha256=jYdlG4OPI82s0fJcXCRNlKeEixDUSSAxjs_7C16qVL4,2306
|
|
29
|
-
mms_client/utils/serialization.py,sha256=
|
|
31
|
+
mms_client/utils/serialization.py,sha256=7DW-xD89DNukcwk6rgS4eBHsMP5kBdiwkvVM4kv2_F8,25438
|
|
30
32
|
mms_client/utils/web.py,sha256=fcdCtdDrHBPyhIlTcyiuAk3D3TlW8HmUw-wGfpG4KTA,9653
|
|
31
|
-
mms_client-1.0.
|
|
32
|
-
mms_client-1.0.
|
|
33
|
-
mms_client-1.0.
|
|
34
|
-
mms_client-1.0.
|
|
33
|
+
mms_client-1.1.0.dist-info/LICENSE,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
|
|
34
|
+
mms_client-1.1.0.dist-info/METADATA,sha256=jb3k6RPJGTpxMiIAaJTKzGfZcgoEgrrxeOPNrSoRoUM,14742
|
|
35
|
+
mms_client-1.1.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
|
36
|
+
mms_client-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|