mms-client 1.1.0__py3-none-any.whl → 1.2.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.
@@ -10,6 +10,7 @@ from typing import Optional
10
10
  from typing import Protocol
11
11
  from typing import Tuple
12
12
  from typing import Type
13
+ from typing import Union
13
14
 
14
15
  from mms_client.security.crypto import Certificate
15
16
  from mms_client.security.crypto import CryptoWrapper
@@ -119,7 +120,7 @@ class ClientProto(Protocol):
119
120
  def request_many(
120
121
  self,
121
122
  envelope: E,
122
- data: P,
123
+ data: Union[P, List[P]],
123
124
  config: EndpointConfiguration,
124
125
  ) -> Tuple[MultiResponse[E, P], Dict[str, bytes]]:
125
126
  """Submit a request to the MMS server and return the multi-response.
@@ -361,7 +362,7 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
361
362
  def request_many(
362
363
  self,
363
364
  envelope: E,
364
- payload: P,
365
+ payload: Union[P, List[P]],
365
366
  config: EndpointConfiguration[E, P],
366
367
  ) -> Tuple[MultiResponse[E, P], Dict[str, bytes]]:
367
368
  """Submit a request to the MMS server and return the multi-response.
@@ -374,13 +375,20 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
374
375
  Returns: The multi-response from the MMS server.
375
376
  """
376
377
  # First, create the MMS request from the payload and data.
378
+ is_list = isinstance(payload, list)
379
+ data_type = type(payload[0]) if is_list else type(payload) # type: ignore[index]
377
380
  self._logger.debug(
378
381
  (
379
382
  f"{config.name}: Starting multi-request. Envelope: {type(envelope).__name__}, "
380
- f"Data: {type(payload).__name__}"
383
+ f"Data: {data_type.__name__}"
381
384
  ),
382
385
  )
383
- request = self._to_mms_request(config.request_type, config.service.serializer.serialize(envelope, payload))
386
+ serialized = (
387
+ config.service.serializer.serialize_multi(envelope, payload, data_type) # type: ignore[arg-type]
388
+ if is_list
389
+ else config.service.serializer.serialize(envelope, payload) # type: ignore[type-var]
390
+ )
391
+ request = self._to_mms_request(config.request_type, serialized)
384
392
 
385
393
  # Next, submit the request to the MMS server and get and verify the response.
386
394
  resp = self._get_wrapper(config.service).submit(request)
@@ -391,8 +399,12 @@ class BaseClient: # pylint: disable=too-many-instance-attributes
391
399
 
392
400
  # Finally, deserialize and verify the response
393
401
  envelope_type = config.response_envelope_type or type(envelope)
394
- data_type = config.response_data_type or type(payload)
395
- data: MultiResponse[E, P] = config.service.serializer.deserialize_multi(resp.payload, envelope_type, data_type)
402
+ data_type = config.response_data_type or data_type
403
+ data: MultiResponse[E, P] = config.service.serializer.deserialize_multi(
404
+ resp.payload,
405
+ envelope_type,
406
+ data_type, # type: ignore[arg-type]
407
+ )
396
408
  self._verify_multi_response(data, config)
397
409
 
398
410
  # Return the response data and any attachments
@@ -54,6 +54,32 @@ class MarketClientMixin: # pylint: disable=unused-argument
54
54
  days=days,
55
55
  )
56
56
 
57
+ @mms_multi_endpoint("MarketSubmit_OfferData", config, RequestType.INFO, ClientType.BSP)
58
+ def put_offers(
59
+ self: ClientProto, requests: List[OfferData], market_type: MarketType, days: int, date: Optional[Date] = None
60
+ ) -> List[OfferData]:
61
+ """Submit multiple offers to the MMS server.
62
+
63
+ This endpoint is only accessible to BSPs.
64
+
65
+ Arguments:
66
+ requests (List[OfferData]): The offers to submit to the MMS server.
67
+ market_type (MarketType): The type of market for which the offers are being submitted.
68
+ days (int): The number of days ahead for which the offers are being submitted.
69
+ date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
70
+ current date.
71
+
72
+ Returns: A list of offers that have been registered with the MMS server.
73
+ """
74
+ # Note: the return type does not match the method definition but the decorator will return the correct type
75
+ return MarketSubmit( # type: ignore[return-value]
76
+ date=date or Date.today(),
77
+ participant=self.participant,
78
+ user=self.user,
79
+ market_type=market_type,
80
+ days=days,
81
+ )
82
+
57
83
  @mms_multi_endpoint(
58
84
  "MarketQuery_OfferQuery", config, RequestType.INFO, resp_envelope_type=MarketSubmit, resp_data_type=OfferData
59
85
  )
@@ -4,6 +4,7 @@ from functools import lru_cache
4
4
  from io import BytesIO
5
5
  from pathlib import Path
6
6
  from typing import Dict
7
+ from typing import List
7
8
  from typing import Optional
8
9
  from typing import Tuple
9
10
  from typing import Type
@@ -62,8 +63,33 @@ class Serializer:
62
63
  # First, create our payload class from the payload and data types
63
64
  payload_cls = _create_request_payload_type(
64
65
  self._payload_key,
65
- type(request_envelope), # type: ignore[arg-type]
66
- type(request_data), # type: ignore[arg-type]
66
+ type(request_envelope),
67
+ type(request_data),
68
+ False, # type: ignore[arg-type]
69
+ )
70
+
71
+ # Next, inject the payload and data into the payload class
72
+ # Note: this returns a type that inherits from PayloadBase and the arguments provided to the initializer
73
+ # here are correct, but mypy thinks they are incorrect because it doesn't understand the the inherited type
74
+ payload = payload_cls(request_envelope, request_data, self._xsd.value) # type: ignore[call-arg, misc]
75
+
76
+ # Finally, convert the payload to XML and return it
77
+ # Note: we provided the encoding here so this will return bytes, not a string
78
+ return payload.to_xml(skip_empty=True, encoding="utf-8", xml_declaration=True) # type: ignore[return-value]
79
+
80
+ def serialize_multi(self, request_envelope: E, request_data: List[P], request_type: Type[P]) -> bytes:
81
+ """Serialize the envelope and data to a byte string for sending to the MMS server.
82
+
83
+ Arguments:
84
+ request_envelope (Envelope): The envelope to be serialized.
85
+ request_data (List[Payload]): The data to be serialized.
86
+ request_type (Type[Payload]): The type of data to be serialized.
87
+
88
+ Returns: A byte string containing the XML-formatted data to be sent to the MMS server.
89
+ """
90
+ # First, create our payload class from the payload and data types
91
+ payload_cls = _create_request_payload_type(
92
+ self._payload_key, type(request_envelope), request_type, True # type: ignore[arg-type]
67
93
  )
68
94
 
69
95
  # Next, inject the payload and data into the payload class
@@ -439,7 +465,12 @@ def _create_response_common_type(tag_type: Type[Union[E, P]]) -> Type[ResponseCo
439
465
 
440
466
 
441
467
  @lru_cache(maxsize=None)
442
- def _create_request_payload_type(key: str, envelope_type: Type[E], data_type: Type[P]) -> Type[PayloadBase]:
468
+ def _create_request_payload_type(
469
+ key: str,
470
+ envelope_type: Type[E],
471
+ data_type: Type[Union[P, List[P]]],
472
+ multi: bool,
473
+ ) -> Type[PayloadBase]:
443
474
  """Create a new payload type for the given payload and data types.
444
475
 
445
476
  This method is intended to save us the overhead of writing a new class for each payload type. Instead, we can
@@ -453,17 +484,21 @@ def _create_request_payload_type(key: str, envelope_type: Type[E], data_type: Ty
453
484
  key: str The tag to use for the parent element of the payload.
454
485
  envelope_type (Type[Envelope]): The type of payload to be constructed.
455
486
  data_type (Type[Payload]): The type of data to be constructed.
487
+ multi (bool): If True, the payload will be a list; otherwise, it will be a singleton.
456
488
 
457
489
  Returns: A new payload type that can be used for serialization.
458
490
  """ # fmt: skip
459
- # First, create a wrapper for our data type that will be used to store the data in the payload
491
+ # First, create our data type
492
+ payload_type = List[data_type] if multi else data_type # type: ignore[valid-type]
493
+
494
+ # Next, create a wrapper for our data type that will be used to store the data in the payload
460
495
  class Envelope(envelope_type): # type: ignore[valid-type, misc]
461
496
  """Wrapper for the data type that will be used to store the data in the payload."""
462
497
 
463
498
  # The data to be stored in the payload
464
- data: data_type = element(tag=get_tag(data_type)) # type: ignore[valid-type]
499
+ data: payload_type = element(tag=get_tag(data_type)) # type: ignore[valid-type, type-var]
465
500
 
466
- def __init__(self, envelope: envelope_type, data: data_type): # type: ignore[valid-type]
501
+ def __init__(self, envelope: envelope_type, data: payload_type): # type: ignore[valid-type]
467
502
  """Create a new envelope to store payload data.
468
503
 
469
504
  Arguments:
@@ -474,14 +509,14 @@ def _create_request_payload_type(key: str, envelope_type: Type[E], data_type: Ty
474
509
  obj["data"] = data
475
510
  super().__init__(**obj)
476
511
 
477
- # Next, create our payload type that actually contains all the XML data
512
+ # Now, create our payload type that actually contains all the XML data
478
513
  class RQPayload(PayloadBase, tag=key): # type: ignore[call-arg]
479
514
  """The payload type that will be used for serialization."""
480
515
 
481
516
  # The payload containing our request object and any data
482
517
  envelope: Envelope = element(tag=envelope_type.__name__)
483
518
 
484
- def __init__(self, envelope: envelope_type, data: data_type, schema: str): # type: ignore[valid-type]
519
+ def __init__(self, envelope: envelope_type, data: payload_type, schema: str): # type: ignore[valid-type]
485
520
  """Create a new payload containing the request object and any data.
486
521
 
487
522
  Arguments:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mms-client
3
- Version: 1.1.0
3
+ Version: 1.2.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
@@ -12,8 +12,8 @@ mms_client/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
12
12
  mms_client/security/certs.py,sha256=kNCUFmy18YIxkWKu3mdMmlxmHdft4a6BvtyJ46rA9I4,1489
13
13
  mms_client/security/crypto.py,sha256=M7aIllM3_ZwZgm9nH6QQ6Ig14XCAd6e6WGwqqUbbI1Q,2149
14
14
  mms_client/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- mms_client/services/base.py,sha256=8yWBeDoBimY9BZeMOkMDV-ggvPTzZHnlqXiv9eo8fIQ,25363
16
- mms_client/services/market.py,sha256=kwcbXz1Op4hwXbOn_Xsx_qBNuHfvWAxBH6G2f4AWzPI,4892
15
+ mms_client/services/base.py,sha256=mcUL-AZpaJETVkzAOoazmKfI5O3cJ0KWzIYQ5bjpNuE,25839
16
+ mms_client/services/market.py,sha256=juYIZuSsJ10srzDK4N6s8guoGqdDuQXGohecF43WQh8,6169
17
17
  mms_client/services/omi.py,sha256=h6cM5U3-iSm0YiIaJwqYTZeI5uhLbA7FPxh_qy_3qww,521
18
18
  mms_client/services/registration.py,sha256=9pNZdgwRbJJCnmsVgESNnc3ywkn-wdQryumUhLn6Xvg,3419
19
19
  mms_client/services/report.py,sha256=HYVJNwEHo6ZC6497UqO5y1IqZ2ga3kVH5AepdxhYfug,537
@@ -28,9 +28,9 @@ mms_client/types/resource.py,sha256=_pRNAqOX8A0lUXmU8qO_8QwRtRx9BwZDdrN-w_Fnu38,
28
28
  mms_client/types/transport.py,sha256=vyosoeGSdYthqlmiyDAkZusYa8yVHUwOzfTqwZne2Ik,4407
29
29
  mms_client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  mms_client/utils/errors.py,sha256=jYdlG4OPI82s0fJcXCRNlKeEixDUSSAxjs_7C16qVL4,2306
31
- mms_client/utils/serialization.py,sha256=7DW-xD89DNukcwk6rgS4eBHsMP5kBdiwkvVM4kv2_F8,25438
31
+ mms_client/utils/serialization.py,sha256=TqkucFL1rvMu49sxsWDwCZSvWMDd75Gj9kZmm1FYUzc,27203
32
32
  mms_client/utils/web.py,sha256=fcdCtdDrHBPyhIlTcyiuAk3D3TlW8HmUw-wGfpG4KTA,9653
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,,
33
+ mms_client-1.2.0.dist-info/LICENSE,sha256=awOCsWJ58m_2kBQwBUGWejVqZm6wuRtCL2hi9rfa0X4,1211
34
+ mms_client-1.2.0.dist-info/METADATA,sha256=xTwJZuKbEW7HKg_C5zw-uVYVXjnI112CiYxEPxGmoWA,14742
35
+ mms_client-1.2.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
36
+ mms_client-1.2.0.dist-info/RECORD,,