mms-client 1.0.5__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/__init__.py +0 -0
- mms_client/client.py +14 -0
- mms_client/py.typed +0 -0
- mms_client/schemas/wsdl/mi-web-service-jbms.wsdl +276 -0
- mms_client/schemas/wsdl/omi-web-service.wsdl +262 -0
- mms_client/schemas/xsd/mi-market.xsd +2395 -0
- mms_client/schemas/xsd/mi-outbnd-reports.xsd +1489 -0
- mms_client/schemas/xsd/mi-report.xsd +379 -0
- mms_client/schemas/xsd/mpr.xsd +1817 -0
- mms_client/schemas/xsd/omi.xsd +793 -0
- mms_client/security/__init__.py +0 -0
- mms_client/security/certs.py +44 -0
- mms_client/security/crypto.py +57 -0
- mms_client/services/__init__.py +0 -0
- mms_client/services/base.py +591 -0
- mms_client/services/market.py +107 -0
- mms_client/services/omi.py +13 -0
- mms_client/services/registration.py +13 -0
- mms_client/services/report.py +13 -0
- mms_client/types/__init__.py +0 -0
- mms_client/types/base.py +272 -0
- mms_client/types/enums.py +18 -0
- mms_client/types/fields.py +153 -0
- mms_client/types/market.py +61 -0
- mms_client/types/offer.py +163 -0
- mms_client/types/transport.py +130 -0
- mms_client/utils/__init__.py +0 -0
- mms_client/utils/errors.py +66 -0
- mms_client/utils/serialization.py +513 -0
- mms_client/utils/web.py +220 -0
- mms_client-1.0.5.dist-info/LICENSE +24 -0
- mms_client-1.0.5.dist-info/METADATA +202 -0
- mms_client-1.0.5.dist-info/RECORD +34 -0
- mms_client-1.0.5.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Contains the client layer for making market requests to the MMS server."""
|
|
2
|
+
|
|
3
|
+
from datetime import date as Date
|
|
4
|
+
from typing import List
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from mms_client.services.base import ClientProto
|
|
8
|
+
from mms_client.services.base import ServiceConfiguration
|
|
9
|
+
from mms_client.services.base import mms_endpoint
|
|
10
|
+
from mms_client.services.base import mms_multi_endpoint
|
|
11
|
+
from mms_client.types.market import MarketCancel
|
|
12
|
+
from mms_client.types.market import MarketQuery
|
|
13
|
+
from mms_client.types.market import MarketSubmit
|
|
14
|
+
from mms_client.types.market import MarketType
|
|
15
|
+
from mms_client.types.offer import OfferCancel
|
|
16
|
+
from mms_client.types.offer import OfferData
|
|
17
|
+
from mms_client.types.offer import OfferQuery
|
|
18
|
+
from mms_client.types.transport import RequestType
|
|
19
|
+
from mms_client.utils.serialization import SchemaType
|
|
20
|
+
from mms_client.utils.serialization import Serializer
|
|
21
|
+
from mms_client.utils.web import ClientType
|
|
22
|
+
from mms_client.utils.web import Interface
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MarketClientMixin: # pylint: disable=unused-argument
|
|
26
|
+
"""Market client for the MMS server."""
|
|
27
|
+
|
|
28
|
+
# The configuration for the market service
|
|
29
|
+
config = ServiceConfiguration(Interface.MI, Serializer(SchemaType.MARKET, "MarketData"))
|
|
30
|
+
|
|
31
|
+
@mms_endpoint("MarketSubmit_OfferData", config, RequestType.INFO, ClientType.BSP)
|
|
32
|
+
def put_offer(
|
|
33
|
+
self: ClientProto, request: OfferData, market_type: MarketType, days: int, date: Optional[Date] = None
|
|
34
|
+
) -> OfferData:
|
|
35
|
+
"""Submit an offer to the MMS server.
|
|
36
|
+
|
|
37
|
+
This endpoint is only accessible to BSPs.
|
|
38
|
+
|
|
39
|
+
Arguments:
|
|
40
|
+
request (OfferData): The offer to submit to the MMS server.
|
|
41
|
+
market_type (MarketType): The type of market for which the offer is being submitted.
|
|
42
|
+
days (int): The number of days ahead for which the offer is being submitted.
|
|
43
|
+
date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
|
|
44
|
+
current date.
|
|
45
|
+
|
|
46
|
+
Returns: The offer that has been registered with the MMS server.
|
|
47
|
+
"""
|
|
48
|
+
# Note: the return type does not match the method definition but the decorator will return the correct type
|
|
49
|
+
return MarketSubmit( # type: ignore[return-value]
|
|
50
|
+
date=date or Date.today(),
|
|
51
|
+
participant=self.participant,
|
|
52
|
+
user=self.user,
|
|
53
|
+
market_type=market_type,
|
|
54
|
+
days=days,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@mms_multi_endpoint(
|
|
58
|
+
"MarketQuery_OfferQuery", config, RequestType.INFO, resp_envelope_type=MarketSubmit, resp_data_type=OfferData
|
|
59
|
+
)
|
|
60
|
+
def query_offers(
|
|
61
|
+
self: ClientProto, request: OfferQuery, market_type: MarketType, days: int, date: Optional[Date] = None
|
|
62
|
+
) -> List[OfferData]:
|
|
63
|
+
"""Query the MMS server for offers.
|
|
64
|
+
|
|
65
|
+
This endpoint is accessible to all client types.
|
|
66
|
+
|
|
67
|
+
Arguments:
|
|
68
|
+
request (OfferQuery): The query to submit to the MMS server.
|
|
69
|
+
market_type (MarketType): The type of market for which the offer was submitted.
|
|
70
|
+
days (int): The number of days ahead for which the data is being queried.
|
|
71
|
+
date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
|
|
72
|
+
current date.
|
|
73
|
+
|
|
74
|
+
Returns: A list of offers that match the query.
|
|
75
|
+
"""
|
|
76
|
+
# Note: the return type does not match the method definition but the decorator will return the correct type
|
|
77
|
+
return MarketQuery( # type: ignore[return-value]
|
|
78
|
+
date=date or Date.today(),
|
|
79
|
+
participant=self.participant,
|
|
80
|
+
user=self.user,
|
|
81
|
+
market_type=market_type,
|
|
82
|
+
days=days,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
@mms_endpoint("MarketCancel_OfferCancel", config, RequestType.INFO, ClientType.BSP)
|
|
86
|
+
def cancel_offer(
|
|
87
|
+
self: ClientProto, request: OfferCancel, market_type: MarketType, days: int, date: Optional[Date] = None
|
|
88
|
+
) -> OfferCancel:
|
|
89
|
+
"""Cancel an offer in the MMS server.
|
|
90
|
+
|
|
91
|
+
This endpoint is only accessible to BSPs.
|
|
92
|
+
|
|
93
|
+
Arguments:
|
|
94
|
+
request (OfferCancel): The offer to cancel in the MMS server.
|
|
95
|
+
market_type (MarketType): The type of market for which the offer was submitted.
|
|
96
|
+
days (int): The number of days ahead for which the data is being cancelled.
|
|
97
|
+
date (Date): The date of the transaction in the format "YYYY-MM-DD". This value defaults to the
|
|
98
|
+
current date.
|
|
99
|
+
"""
|
|
100
|
+
# Note: the return type does not match the method definition but the decorator will return the correct type
|
|
101
|
+
return MarketCancel( # type: ignore[return-value]
|
|
102
|
+
date=date or Date.today(),
|
|
103
|
+
participant=self.participant,
|
|
104
|
+
user=self.user,
|
|
105
|
+
market_type=market_type,
|
|
106
|
+
days=days,
|
|
107
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Contains the client layer for making OMI requests to the MMS server."""
|
|
2
|
+
|
|
3
|
+
from mms_client.services.base import ServiceConfiguration
|
|
4
|
+
from mms_client.utils.serialization import SchemaType
|
|
5
|
+
from mms_client.utils.serialization import Serializer
|
|
6
|
+
from mms_client.utils.web import Interface
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OMIClientMixin: # pylint: disable=unused-argument
|
|
10
|
+
"""OMI client for the MMS server."""
|
|
11
|
+
|
|
12
|
+
# The configuration for the OMI service
|
|
13
|
+
config = ServiceConfiguration(Interface.OMI, Serializer(SchemaType.OMI, "MarketData"))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Contains the client layer for making registration requests to the MMS server."""
|
|
2
|
+
|
|
3
|
+
from mms_client.services.base import ServiceConfiguration
|
|
4
|
+
from mms_client.utils.serialization import SchemaType
|
|
5
|
+
from mms_client.utils.serialization import Serializer
|
|
6
|
+
from mms_client.utils.web import Interface
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RegistrationClientMixin: # pylint: disable=unused-argument
|
|
10
|
+
"""Registration client for the MMS server."""
|
|
11
|
+
|
|
12
|
+
# The configuration for the registration service
|
|
13
|
+
config = ServiceConfiguration(Interface.MI, Serializer(SchemaType.REGISTRATION, "RegistrationData"))
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Contains the client layer for making report requests to the MMS server."""
|
|
2
|
+
|
|
3
|
+
from mms_client.services.base import ServiceConfiguration
|
|
4
|
+
from mms_client.utils.serialization import SchemaType
|
|
5
|
+
from mms_client.utils.serialization import Serializer
|
|
6
|
+
from mms_client.utils.web import Interface
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ReportClientMixin: # pylint: disable=unused-argument
|
|
10
|
+
"""Report client for the MMS server."""
|
|
11
|
+
|
|
12
|
+
# The configuration for the report service
|
|
13
|
+
config = ServiceConfiguration(Interface.MI, Serializer(SchemaType.REPORT, "MarketReport"))
|
|
File without changes
|
mms_client/types/base.py
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"""Contains the base types necessary for communication with the MMS server."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Dict
|
|
6
|
+
from typing import Generic
|
|
7
|
+
from typing import List
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from typing import TypeVar
|
|
10
|
+
|
|
11
|
+
from pydantic import PrivateAttr
|
|
12
|
+
from pydantic_extra_types.pendulum_dt import DateTime
|
|
13
|
+
from pydantic_xml import BaseXmlModel
|
|
14
|
+
from pydantic_xml import attr
|
|
15
|
+
from pydantic_xml import element
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ValidationStatus(Enum):
|
|
19
|
+
"""Represents the status of the validation check done on an element."""
|
|
20
|
+
|
|
21
|
+
PASSED = "PASSED" # The validation check for all data within the element has succeeded.
|
|
22
|
+
WARNING = "WARNING" # There are data within the element that have triggered warnings during the validation check.
|
|
23
|
+
PASSED_PARTIAL = "PASSED_PARTIAL" # Some data within the element has failed the validation check.
|
|
24
|
+
FAILED = "FAILED" # The data inside the element failed the validation check.
|
|
25
|
+
NOT_DONE = "NOT_DONE" # There are data with incomplete validation checks within the element.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Message(BaseXmlModel):
|
|
29
|
+
"""Represents a message returned with a payload."""
|
|
30
|
+
|
|
31
|
+
# The message text. Not sure why this is called code in the XML.
|
|
32
|
+
code: str = attr(default="", name="Code", min_length=2, max_length=50, pattern=r"^[a-zA-Z_0-9\-]*$")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Messages(BaseXmlModel, search_mode="unordered"):
|
|
36
|
+
"""Represents a collection of messages returned with a payload."""
|
|
37
|
+
|
|
38
|
+
# A list of information messages returned with a payload
|
|
39
|
+
information: List[Message] = element(default=[], tag="Information", nillable=True)
|
|
40
|
+
|
|
41
|
+
# A list of warning messages returned with a payload
|
|
42
|
+
warnings: List[Message] = element(default=[], tag="Warning", nillable=True)
|
|
43
|
+
|
|
44
|
+
# A list of error messages returned with a payload
|
|
45
|
+
errors: List[Message] = element(default=[], tag="Error", nillable=True)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ProcessingStatistics(BaseXmlModel):
|
|
49
|
+
"""Represents the statistics returned with a payload."""
|
|
50
|
+
|
|
51
|
+
# The number of objects received with the request
|
|
52
|
+
received: Optional[int] = attr(default=None, name="Received")
|
|
53
|
+
|
|
54
|
+
# The number of objects that passed validation
|
|
55
|
+
valid: Optional[int] = attr(default=None, name="Valid")
|
|
56
|
+
|
|
57
|
+
# The number of objects that failed validation
|
|
58
|
+
invalid: Optional[int] = attr(default=None, name="Invalid")
|
|
59
|
+
|
|
60
|
+
# The number of objects that were successfully processed
|
|
61
|
+
successful: Optional[int] = attr(default=None, name="Successful")
|
|
62
|
+
|
|
63
|
+
# The number of objects that were unsuccessfully processed
|
|
64
|
+
unsuccessful: Optional[int] = attr(default=None, name="Unsuccessful")
|
|
65
|
+
|
|
66
|
+
# The amount of time it took to process the request in milliseconds
|
|
67
|
+
time_ms: Optional[int] = attr(default=None, name="ProcessingTimeMs")
|
|
68
|
+
|
|
69
|
+
# The transaction ID of the request
|
|
70
|
+
transaction_id: Optional[str] = attr(default=None, name="TransactionID", min_length=8, max_length=10)
|
|
71
|
+
|
|
72
|
+
# When the request was received, in the format "DDD MMM DD HH:MM:SS TZ YYYY"
|
|
73
|
+
timestamp: str = attr(default="", name="TimeStamp")
|
|
74
|
+
|
|
75
|
+
# When the request was received, in the format "YYYY-MM-DD HH:MM:SSZ"
|
|
76
|
+
timestamp_xml: Optional[DateTime] = attr(default=None, name="XmlTimeStamp")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class ResponseCommon(BaseXmlModel, search_mode="unordered"):
|
|
80
|
+
"""Contains fields common to many (but not all) market DTOs."""
|
|
81
|
+
|
|
82
|
+
# Whether the request was successful. This field will certainly be present in responses, but should not be present
|
|
83
|
+
# in requests.
|
|
84
|
+
success: bool = attr(default=True, name="Success")
|
|
85
|
+
|
|
86
|
+
# The status of the validation check done on the element. This field is not required for requests, and will be
|
|
87
|
+
# populated in responses. For responses, the default value is "NOT_DONE".
|
|
88
|
+
validation: ValidationStatus = attr(default=ValidationStatus.NOT_DONE, name="Validation")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class Payload(BaseXmlModel, search_mode="unordered"):
|
|
92
|
+
"""Represents the base fields for MMS request data."""
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# Define a generic type used to identify the data type. This type will be used to create the MarketData class.
|
|
96
|
+
P = TypeVar("P", bound=Payload)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Envelope(BaseXmlModel):
|
|
100
|
+
"""Represents the base fields for an MMS request data envelope."""
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Define a generic type used to identify the payload type. This type will be used to create the MarketData class.
|
|
104
|
+
E = TypeVar("E", bound=Envelope)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class SchemaType(Enum):
|
|
108
|
+
"""Represents the type of schema to be used for validation."""
|
|
109
|
+
|
|
110
|
+
MARKET = "mi-market.xsd"
|
|
111
|
+
REPORT = "mi-report.xsd"
|
|
112
|
+
REGISTRATION = "mpr.xsd"
|
|
113
|
+
OMI = "omi.xsd"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class PayloadBase(BaseXmlModel, nsmap={"xsi": "http://www.w3.org/2001/XMLSchema"}):
|
|
117
|
+
"""Represents the base fields for an MMS request payload."""
|
|
118
|
+
|
|
119
|
+
# The XML schema to use for validation
|
|
120
|
+
location: SchemaType = attr(name="noNamespaceSchemaLocation", ns="xsi")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class BaseResponse(BaseXmlModel, Generic[E], tag="BaseResponse"):
|
|
124
|
+
"""Contains the base data extracted from the MMS response in a format we can use."""
|
|
125
|
+
|
|
126
|
+
# The processing statistics returned with the payload. This will not be present in requests, and will be populated
|
|
127
|
+
# in responses.
|
|
128
|
+
statistics: ProcessingStatistics = element(tag="ProcessingStatistics")
|
|
129
|
+
|
|
130
|
+
# The request payload, containing the request data
|
|
131
|
+
_envelope: E = PrivateAttr()
|
|
132
|
+
|
|
133
|
+
# The validation information for the request payload
|
|
134
|
+
_envelope_validation: ResponseCommon = PrivateAttr()
|
|
135
|
+
|
|
136
|
+
# The messages returned with the payload. Each object will likely have its own so these
|
|
137
|
+
# will be parsed separately.
|
|
138
|
+
_messages: Dict[str, Messages] = PrivateAttr()
|
|
139
|
+
|
|
140
|
+
def __init__(self, **data):
|
|
141
|
+
"""Create a new BaseResponse object.
|
|
142
|
+
|
|
143
|
+
Arguments:
|
|
144
|
+
**data: The data to use to create the object.
|
|
145
|
+
"""
|
|
146
|
+
super().__init__(**data)
|
|
147
|
+
self._envelope = None
|
|
148
|
+
self._envelope_validation = None
|
|
149
|
+
self._messages = {}
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def envelope(self) -> E:
|
|
153
|
+
"""Return the request payload."""
|
|
154
|
+
return self._envelope
|
|
155
|
+
|
|
156
|
+
@envelope.setter
|
|
157
|
+
def envelope(self, value: E) -> None:
|
|
158
|
+
"""Set the request payload.
|
|
159
|
+
|
|
160
|
+
Arguments:
|
|
161
|
+
value (E): The request payload.
|
|
162
|
+
"""
|
|
163
|
+
self._envelope = value
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def envelope_validation(self) -> ResponseCommon:
|
|
167
|
+
"""Return the validation information for the request payload."""
|
|
168
|
+
return self._envelope_validation
|
|
169
|
+
|
|
170
|
+
@envelope_validation.setter
|
|
171
|
+
def envelope_validation(self, value: ResponseCommon) -> None:
|
|
172
|
+
"""Set the validation information for the request payload.
|
|
173
|
+
|
|
174
|
+
Arguments:
|
|
175
|
+
value (ResponseCommon): The validation information for the request payload.
|
|
176
|
+
"""
|
|
177
|
+
self._envelope_validation = value
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def messages(self) -> Dict[str, Messages]:
|
|
181
|
+
"""Return the messages returned with the payload."""
|
|
182
|
+
return self._messages
|
|
183
|
+
|
|
184
|
+
@messages.setter
|
|
185
|
+
def messages(self, value: Dict[str, Messages]) -> None:
|
|
186
|
+
"""Set the messages returned with the payload.
|
|
187
|
+
|
|
188
|
+
Arguments:
|
|
189
|
+
value (Dict[str, Messages]): The messages returned with the payload.
|
|
190
|
+
"""
|
|
191
|
+
self._messages = value
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@dataclass
|
|
195
|
+
class ResponseData(Generic[P]):
|
|
196
|
+
"""Contains the actual payload data extracted from the MMS response in a format we can use."""
|
|
197
|
+
|
|
198
|
+
# The data extracted from the response
|
|
199
|
+
data: P
|
|
200
|
+
|
|
201
|
+
# The validation information for the data extracted from the response
|
|
202
|
+
data_validation: ResponseCommon
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class Response(BaseResponse[E], Generic[E, P]):
|
|
206
|
+
"""Contains all the data extracted from the MMS response in a format we can use."""
|
|
207
|
+
|
|
208
|
+
# The payload data extracted from the response
|
|
209
|
+
_payload_data: Optional[ResponseData[P]] = PrivateAttr()
|
|
210
|
+
|
|
211
|
+
def __init__(self, **data):
|
|
212
|
+
"""Create a new Response object.
|
|
213
|
+
|
|
214
|
+
Arguments:
|
|
215
|
+
**data: The data to use to create the object.
|
|
216
|
+
"""
|
|
217
|
+
super().__init__(**data)
|
|
218
|
+
self._payload_data = None
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def data(self) -> Optional[P]:
|
|
222
|
+
"""Return the data extracted from the response."""
|
|
223
|
+
return self._payload_data.data if self._payload_data else None # pylint: disable=no-member
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def payload(self) -> Optional[ResponseData[P]]:
|
|
227
|
+
"""Return the response payload."""
|
|
228
|
+
return self._payload_data
|
|
229
|
+
|
|
230
|
+
@payload.setter
|
|
231
|
+
def payload(self, value: Optional[ResponseData[P]]) -> None:
|
|
232
|
+
"""Set the payload extracted from the response.
|
|
233
|
+
|
|
234
|
+
Arguments:
|
|
235
|
+
value (ResponseData[P]): The payload extracted from the response.
|
|
236
|
+
"""
|
|
237
|
+
self._payload_data = value
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class MultiResponse(BaseResponse[E], Generic[E, P]):
|
|
241
|
+
"""Contains all the data extracted from the MMS response in a format we can use."""
|
|
242
|
+
|
|
243
|
+
# The payload data extracted from the response
|
|
244
|
+
_payload_data: List[ResponseData[P]] = PrivateAttr()
|
|
245
|
+
|
|
246
|
+
def __init__(self, **data):
|
|
247
|
+
"""Create a new MultiResponse object.
|
|
248
|
+
|
|
249
|
+
Arguments:
|
|
250
|
+
**data: The data to use to create the object.
|
|
251
|
+
"""
|
|
252
|
+
super().__init__(**data)
|
|
253
|
+
self._payload_data = []
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def data(self) -> List[P]:
|
|
257
|
+
"""Return the data extracted from the response."""
|
|
258
|
+
return [response.data for response in self._payload_data] # pylint: disable=not-an-iterable
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def payload(self) -> List[ResponseData[P]]:
|
|
262
|
+
"""Return the response payload."""
|
|
263
|
+
return self._payload_data
|
|
264
|
+
|
|
265
|
+
@payload.setter
|
|
266
|
+
def payload(self, values: List[Optional[ResponseData[P]]]) -> None:
|
|
267
|
+
"""Set the payload extracted from the response.
|
|
268
|
+
|
|
269
|
+
Arguments:
|
|
270
|
+
values (List[ResponseData[P]]): The payload extracted from the response.
|
|
271
|
+
"""
|
|
272
|
+
self._payload_data = [value for value in values if value]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Contains enums common to all MMS types."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AreaCode(Enum):
|
|
7
|
+
"""Represents the area code of the market."""
|
|
8
|
+
|
|
9
|
+
HOKKAIDO = "01"
|
|
10
|
+
TOHOKU = "02"
|
|
11
|
+
TOKYO = "03"
|
|
12
|
+
CHUBU = "04"
|
|
13
|
+
HOKURIKU = "05"
|
|
14
|
+
KANSAI = "06"
|
|
15
|
+
CHUGOKU = "07"
|
|
16
|
+
SHIKOKU = "08"
|
|
17
|
+
KYUSHU = "09"
|
|
18
|
+
OKINAWA = "10"
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Contains the definitions for various fields used in the MMS API."""
|
|
2
|
+
|
|
3
|
+
from pydantic_core import PydanticUndefined
|
|
4
|
+
from pydantic_xml import attr
|
|
5
|
+
|
|
6
|
+
# Describes the regular expression required by the MMS API for Japanese text
|
|
7
|
+
JAPANESE_TEXT = r"^[\u3000-\u30FF\uFF00-\uFF60\uFFA0-\uFFEF\u4E00-\u9FEA]*$"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def participant(alias: str, optional: bool = False):
|
|
11
|
+
"""Create a field for a participant ID.
|
|
12
|
+
|
|
13
|
+
Arguments:
|
|
14
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
15
|
+
to the JSON/XML key.
|
|
16
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
17
|
+
required, with no default.
|
|
18
|
+
|
|
19
|
+
Returns: A Pydantic Field object for the participant ID.
|
|
20
|
+
"""
|
|
21
|
+
return attr(
|
|
22
|
+
default=None if optional else PydanticUndefined,
|
|
23
|
+
name=alias,
|
|
24
|
+
min_length=4,
|
|
25
|
+
max_length=4,
|
|
26
|
+
pattern=r"^[A-Z]([0-9]{2}[1-9]|[0-9][1-9][0-9]|[1-9][0-9]{2})$",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def operator_code(alias: str, optional: bool = False):
|
|
31
|
+
"""Create a field for an operator code.
|
|
32
|
+
|
|
33
|
+
Arguments:
|
|
34
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
35
|
+
to the JSON/XML key.
|
|
36
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
37
|
+
required, with no default.
|
|
38
|
+
|
|
39
|
+
Returns: A Pydantic Field object for the operator code.
|
|
40
|
+
"""
|
|
41
|
+
return attr(
|
|
42
|
+
default=None if optional else PydanticUndefined, name=alias, min_length=4, max_length=4, pattern=r"^[A-Z0-9]*$"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def power_positive(alias: str, optional: bool = False):
|
|
47
|
+
"""Create a field for a positive power value.
|
|
48
|
+
|
|
49
|
+
Arguments:
|
|
50
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
51
|
+
to the JSON/XML key.
|
|
52
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
53
|
+
required, with no default.
|
|
54
|
+
|
|
55
|
+
Returns: A Pydantic Field object for the power value.
|
|
56
|
+
"""
|
|
57
|
+
return attr(default=None if optional else PydanticUndefined, name=alias, gt=0, le=10000000)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def price(alias: str, optional: bool = False):
|
|
61
|
+
"""Create a field for a price value.
|
|
62
|
+
|
|
63
|
+
Arguments:
|
|
64
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
65
|
+
to the JSON/XML key.
|
|
66
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
67
|
+
required, with no default.
|
|
68
|
+
|
|
69
|
+
Returns: A Pydantic Field object for the price value.
|
|
70
|
+
"""
|
|
71
|
+
return attr(default=None if optional else PydanticUndefined, name=alias, ge=0.00, le=10000.00, decimal_places=2)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def dr_patter_number(alias: str, optional: bool = False):
|
|
75
|
+
"""Create a field for a DR pattern number.
|
|
76
|
+
|
|
77
|
+
Arguments:
|
|
78
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
79
|
+
to the JSON/XML key.
|
|
80
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
81
|
+
required, with no default.
|
|
82
|
+
|
|
83
|
+
Returns: A Pydantic Field object for the DR pattern number.
|
|
84
|
+
"""
|
|
85
|
+
return attr(default=None if optional else PydanticUndefined, name=alias, ge=1, le=20)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def company_short_name(alias: str, optional: bool = False):
|
|
89
|
+
"""Create a field for a company short name.
|
|
90
|
+
|
|
91
|
+
Arguments:
|
|
92
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
93
|
+
to the JSON/XML key.
|
|
94
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
95
|
+
required, with no default.
|
|
96
|
+
|
|
97
|
+
Returns: A Pydantic Field object for the company short name.
|
|
98
|
+
"""
|
|
99
|
+
return attr(
|
|
100
|
+
default=None if optional else PydanticUndefined, name=alias, min_length=1, max_length=10, pattern=JAPANESE_TEXT
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def resource_name(alias: str, optional: bool = False):
|
|
105
|
+
"""Create a field for a resource name.
|
|
106
|
+
|
|
107
|
+
Arguments:
|
|
108
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
109
|
+
to the JSON/XML key.
|
|
110
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
111
|
+
required, with no default.
|
|
112
|
+
|
|
113
|
+
Returns: A Pydantic Field object for the resource name.
|
|
114
|
+
"""
|
|
115
|
+
return attr(
|
|
116
|
+
default=None if optional else PydanticUndefined,
|
|
117
|
+
name=alias,
|
|
118
|
+
min_length=1,
|
|
119
|
+
max_length=10,
|
|
120
|
+
pattern=r"^[A-Z0-9_\-]*$",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def resource_short_name(alias: str, optional: bool = False):
|
|
125
|
+
"""Create a field for a resource short name.
|
|
126
|
+
|
|
127
|
+
Arguments:
|
|
128
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
129
|
+
to the JSON/XML key.
|
|
130
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
131
|
+
required, with no default.
|
|
132
|
+
|
|
133
|
+
Returns: A Pydantic Field object for the resource short name.
|
|
134
|
+
"""
|
|
135
|
+
return attr(
|
|
136
|
+
default=None if optional else PydanticUndefined, name=alias, min_length=1, max_length=10, pattern=JAPANESE_TEXT
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def system_code(alias: str, optional: bool = False):
|
|
141
|
+
"""Create a field for a system code.
|
|
142
|
+
|
|
143
|
+
Arguments:
|
|
144
|
+
alias (str): The name of the alias to assign to the Pydanitc field. This value will be used to map the field
|
|
145
|
+
to the JSON/XML key.
|
|
146
|
+
optional (bool): If True, the field will be optional with a default of None. If False, the field will be
|
|
147
|
+
required, with no default.
|
|
148
|
+
|
|
149
|
+
Returns: A Pydantic Field object for the system code.
|
|
150
|
+
"""
|
|
151
|
+
return attr(
|
|
152
|
+
default=None if optional else PydanticUndefined, name=alias, min_length=5, max_length=5, pattern=r"^[A-Z0-9]*$"
|
|
153
|
+
)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Contains objects for market information."""
|
|
2
|
+
|
|
3
|
+
# Have to use this becasue pydantic doesn't like pendulum.Date. I've submitted a PR to address this but it hasn't been
|
|
4
|
+
# merged or released yet.
|
|
5
|
+
from datetime import date as Date
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from pydantic_xml import attr
|
|
10
|
+
|
|
11
|
+
from mms_client.types.base import Envelope
|
|
12
|
+
from mms_client.types.fields import participant
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MarketType(Enum):
|
|
16
|
+
"""Represents the type of market for which the data is being submitted."""
|
|
17
|
+
|
|
18
|
+
DAY_AHEAD = "DAM"
|
|
19
|
+
WEEK_AHEAD = "WAM"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BaseMarketRequest(Envelope):
|
|
23
|
+
"""Represents the header of a market request."""
|
|
24
|
+
|
|
25
|
+
# Date of the transaction in the format "YYYY-MM-DD"
|
|
26
|
+
date: Date = attr(name="Date")
|
|
27
|
+
|
|
28
|
+
# MMS code of the business entity to which the requesting user belongs, and will be used to track the user who made
|
|
29
|
+
# the request. This value will be checked against the certificate used to make the request.
|
|
30
|
+
participant: str = participant("ParticipantName")
|
|
31
|
+
|
|
32
|
+
# The user name of the person making the request. This value is used to track the user who made the request, and
|
|
33
|
+
# will be checked against the certificate used to make the request.
|
|
34
|
+
user: str = attr(name="UserName", min_length=1, max_length=12, pattern=r"^[A-Z0-9]*$")
|
|
35
|
+
|
|
36
|
+
# The type of market for which the data is being submitted
|
|
37
|
+
market_type: Optional[MarketType] = attr(default=None, name="MarketType")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class MarketQuery(BaseMarketRequest):
|
|
41
|
+
"""Represents the base fields for a market query."""
|
|
42
|
+
|
|
43
|
+
# If the market type is specified as "DAM" (day-ahead market), the number of days should be specified as "1".
|
|
44
|
+
# Otherwise, this field indicates the number of days ahead for which the data is being queried.
|
|
45
|
+
days: int = attr(default=1, name="NumOfDays", ge=1, le=7)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class MarketSubmit(BaseMarketRequest):
|
|
49
|
+
"""Represents the base fields for a market registration request."""
|
|
50
|
+
|
|
51
|
+
# If the market type is specified as "DAM" (day-ahead market), the number of days should be specified as "1".
|
|
52
|
+
# Otherwise, this field indicates the number of days ahead for which the data is being submitted.
|
|
53
|
+
days: int = attr(default=1, name="NumOfDays", ge=1, le=31)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class MarketCancel(BaseMarketRequest):
|
|
57
|
+
"""Represents the base fields for a market cancellation request."""
|
|
58
|
+
|
|
59
|
+
# If the market type is specified as "DAM" (day-ahead market), the number of days should be specified as "1".
|
|
60
|
+
# Otherwise, this field indicates the number of days ahead for which the data is being cancelled.
|
|
61
|
+
days: int = attr(default=1, name="NumOfDays", ge=1, le=31)
|