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.
@@ -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
@@ -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)