mtx-api-py 0.4.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.
@@ -0,0 +1,207 @@
1
+ from pydantic import AliasChoices, Field, RootModel
2
+
3
+ from mtx_api.models.additional_data import AdditionalData
4
+ from mtx_api.models.base import ImmutableBaseModel
5
+ from mtx_api.models.typology import Typology
6
+
7
+
8
+ class MandatoryInformantField(ImmutableBaseModel):
9
+ """
10
+ Represents a required field configuration for informant information.
11
+ This model defines which fields must be provided by the person reporting
12
+ a request, along with validation messages.
13
+ """
14
+
15
+ field: str | None = Field(
16
+ default=None,
17
+ description="The name of the field that is required (e.g., 'first_name', 'email').",
18
+ )
19
+ message: str | None = Field(
20
+ default=None,
21
+ description="The validation message if the field is missing or invalid.",
22
+ )
23
+ required: bool | None = Field(
24
+ default=None,
25
+ description="Whether this field is mandatory for submission.",
26
+ )
27
+
28
+
29
+ class StatusNode(ImmutableBaseModel):
30
+ """
31
+ Represents a status node in the request lifecycle workflow.
32
+
33
+ Status nodes define the different stages a request can be in,
34
+ such as 'new', 'in progress', 'resolved', etc. They form a workflow
35
+ that tracks request progression.
36
+ """
37
+
38
+ status_node_type: str | None = Field(
39
+ default=None,
40
+ description=(
41
+ "The type of status node (e.g., 'initial_node', 'intermediate_node', 'final_node')."
42
+ ),
43
+ )
44
+ name: str | None = Field(
45
+ default=None,
46
+ description="Internal name of the status node.",
47
+ )
48
+ typology_node_id: str | None = Field(
49
+ default=None,
50
+ description="Identifier linking this status node to a typology node.",
51
+ )
52
+ visible_name: str | None = Field(
53
+ default=None,
54
+ description="Human-readable name given to users for this status.",
55
+ )
56
+ id: str | None = Field(
57
+ default=None,
58
+ description="Unique identifier for the status node.",
59
+ )
60
+ order: int | None = Field(
61
+ default=None,
62
+ description="The showing order of this status in the workflow sequence.",
63
+ )
64
+ planned: bool | None = Field(
65
+ default=None,
66
+ description="Whether this status represents a planned or scheduled state.",
67
+ )
68
+
69
+
70
+ class Service(ImmutableBaseModel):
71
+ """
72
+ Represents a service category for citizen reports.
73
+
74
+ A Service defines a specific category of issues or requests that citizens
75
+ can report to a jurisdiction. It configures what information is required from reporters,
76
+ upload requirements, visibility settings, the workflow status progression, etc.
77
+ """
78
+
79
+ id: str | None = Field(
80
+ default=None,
81
+ description="Unique identifier for the service.",
82
+ )
83
+ visible_name: str | None = Field(
84
+ default=None,
85
+ description="Human-readable name given to users.",
86
+ )
87
+ service_name: str | None = Field(
88
+ default=None,
89
+ description="Internal name of the service.",
90
+ )
91
+ description: str | None = Field(
92
+ default=None,
93
+ description="Detailed description of what the service provides.",
94
+ )
95
+ parent_service_name: str | None = Field(
96
+ default=None,
97
+ description="Name of the parent service if this is a sub-service.",
98
+ )
99
+ jurisdiction_code: str | None = Field(
100
+ default=None,
101
+ validation_alias=AliasChoices("jurisdiction_id", "jurisdiction_code"),
102
+ serialization_alias="jurisdiction_id",
103
+ description="Code of the jurisdiction where this service is available.",
104
+ )
105
+ typology: Typology | None = Field(
106
+ default=None,
107
+ description="The typology classification associated with this service.",
108
+ )
109
+ keywords: str | None = Field(
110
+ default=None,
111
+ description="Comma-separated keywords for searching and categorizing the service.",
112
+ )
113
+ mandatory_description: bool | None = Field(
114
+ default=None,
115
+ description=(
116
+ "Whether a text description is required when submitting a request for this service."
117
+ ),
118
+ )
119
+ mandatory_files: bool | None = Field(
120
+ default=None,
121
+ description="Whether file uploads are required when submitting a request for this service.",
122
+ )
123
+ mandatory_medias: bool | None = Field(
124
+ default=None,
125
+ description="Whether media uploads (images/videos) are required when submitting a request.",
126
+ )
127
+ max_upload_files: int | None = Field(
128
+ default=None,
129
+ description="Maximum number of files that can be uploaded with a request.",
130
+ )
131
+ max_upload_medias: int | None = Field(
132
+ default=None,
133
+ description="Maximum number of media items that can be uploaded with a request.",
134
+ )
135
+ public: bool | None = Field(
136
+ default=None,
137
+ description="Whether this service is publicly visible and available to all users.",
138
+ )
139
+ public_requests: bool | None = Field(
140
+ default=None,
141
+ description="Whether requests made for this service are publicly visible.",
142
+ )
143
+ deleted: bool | None = Field(
144
+ default=None,
145
+ description="Whether this service has been marked as deleted.",
146
+ )
147
+ social: bool | None = Field(
148
+ default=None,
149
+ description="Whether this service has social features enabled.",
150
+ )
151
+ evaluation: bool | None = Field(
152
+ default=None,
153
+ description="Whether users can evaluate or rate this service.",
154
+ )
155
+ hide_estimated_date: bool | None = Field(
156
+ default=None,
157
+ alias="hideEstimatedDate",
158
+ description="Whether to hide the estimated completion date from users.",
159
+ )
160
+ additional_data: AdditionalData | None = Field(
161
+ default=None,
162
+ alias="additionalData",
163
+ description="Additional configurable questions and data fields for this service.",
164
+ )
165
+ mandatory_informant_config: list[MandatoryInformantField] | None = Field(
166
+ default=None,
167
+ description="Configuration defining which informant fields are required.",
168
+ )
169
+ public_requests_internal: bool | None = Field(
170
+ default=None,
171
+ description="Whether requests are visible internally to authorized users.",
172
+ )
173
+ allow_changing_request_privacy: bool | None = Field(
174
+ default=None,
175
+ description="Whether users can change the privacy settings of their requests.",
176
+ )
177
+ service_code: str | None = Field(
178
+ default=None,
179
+ description="A unique code identifier for the service.",
180
+ )
181
+ status_node: list[StatusNode] | None = Field(
182
+ default=None,
183
+ description="List of status nodes defining the request lifecycle workflow.",
184
+ )
185
+ with_informant: bool | None = Field(
186
+ default=None,
187
+ description="Whether this service requires informant details.",
188
+ )
189
+ with_internal_informant: bool | None = Field(
190
+ default=None,
191
+ description="Whether this service supports internal informant submissions.",
192
+ )
193
+ with_authorized_internal_users: bool | None = Field(
194
+ default=None,
195
+ description="Whether authorized internal users can access this service.",
196
+ )
197
+
198
+
199
+ class ServiceList(RootModel[list[Service]]):
200
+ """
201
+ A collection of Service objects.
202
+
203
+ This model represents a list of services returned when querying
204
+ available services for a jurisdiction.
205
+ """
206
+
207
+ pass
@@ -0,0 +1,69 @@
1
+ from pydantic import Field, RootModel
2
+
3
+ from mtx_api.models.base import ImmutableBaseModel
4
+
5
+
6
+ class Typology(ImmutableBaseModel):
7
+ """
8
+ Represents a classification or category for a service within the platform.
9
+ """
10
+
11
+ id: str | None = Field(
12
+ default=None,
13
+ description="Unique identifier for the typology.",
14
+ )
15
+ name: str | None = Field(
16
+ default=None,
17
+ description="Internal system name for the typology.",
18
+ )
19
+ visible_name: str | None = Field(
20
+ default=None,
21
+ description="Human-readable name of the typology given to the user.",
22
+ )
23
+ description_legend: str | None = Field(
24
+ default=None,
25
+ description="Short descriptive legend associated with the typology, "
26
+ "used to prompt the user when creating a request",
27
+ )
28
+ typology_description: str | None = Field(
29
+ default=None,
30
+ description="Describes the intent of the user when creating a request of this typology.",
31
+ )
32
+ order: int | None = Field(
33
+ default=None,
34
+ description="Numeric value used to determine the sorting order of the typology in lists.",
35
+ )
36
+ public: bool | None = Field(
37
+ default=None,
38
+ description="Flag indicating whether this typology is publicly accessible.",
39
+ )
40
+ has_location: bool | None = Field(
41
+ default=None,
42
+ alias="hasLocation",
43
+ description="Flag indicating if this typology requires or supports location data.",
44
+ )
45
+ location_type: str | None = Field(
46
+ default=None,
47
+ description="Specifies the type of location associated with this typology, if applicable."
48
+ "It can be one of: 'geolocation', 'indoor' or 'none'.",
49
+ )
50
+ with_description: bool | None = Field(
51
+ default=None,
52
+ description="Flag indicating if a description input is enabled when creating requests.",
53
+ )
54
+ with_files: bool | None = Field(
55
+ default=None,
56
+ description="Flag indicating if file attachments are supported for this typology.",
57
+ )
58
+ with_medias: bool | None = Field(
59
+ default=None,
60
+ description="Flag indicating if media (images/videos) support is enabled.",
61
+ )
62
+
63
+
64
+ class TypologyList(RootModel[list[Typology]]):
65
+ """
66
+ A collection of Typology objects.
67
+ """
68
+
69
+ pass
mtx_api/py.typed ADDED
File without changes
mtx_api/settings.py ADDED
@@ -0,0 +1,11 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic_settings import BaseSettings, SettingsConfigDict
4
+
5
+
6
+ class MTXSettings(BaseSettings):
7
+ model_config = SettingsConfigDict(env_prefix="MTX_")
8
+
9
+ base_url: str | None = None
10
+ client_id: str | None = None
11
+ jwt_secret: str | None = None
@@ -0,0 +1,323 @@
1
+ Metadata-Version: 2.4
2
+ Name: mtx-api-py
3
+ Version: 0.4.0
4
+ Summary: SDK (wrapper) en Python para la API externa de MTX
5
+ Project-URL: Repository, https://bitbucket.org/radmas/mtx_api_py
6
+ Author-email: Álvaro Martín Rodríguez <alvaro.martin@radmas.com>
7
+ License: MIT
8
+ License-File: LICENSE.txt
9
+ Keywords: api,mtx,sdk
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.12.0
20
+ Requires-Dist: httpx~=0.28.1
21
+ Requires-Dist: pydantic-settings~=2.12.0
22
+ Requires-Dist: pydantic~=2.12.4
23
+ Requires-Dist: pyjwt~=2.10.1
24
+ Description-Content-Type: text/markdown
25
+
26
+ # MTX API PY
27
+
28
+ Python SDK (wrapper) to consume the MTX API.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install mtx-api-py
34
+ ```
35
+
36
+ ## Quick start
37
+
38
+ ```python
39
+ import asyncio
40
+ from mtx_api import MTXClient
41
+
42
+
43
+ async def main():
44
+ async with MTXClient(
45
+ base_url="https://api.mtx.example.com",
46
+ client_id="YOUR_CLIENT_ID",
47
+ jwt_secret="BASE64_SECRET", # optional; only if you will use auth.login_jwt
48
+ ) as client:
49
+ ok = await client.base.status(access_token="<ACCESS_TOKEN>")
50
+ print(ok)
51
+
52
+
53
+ asyncio.run(main())
54
+ ```
55
+
56
+ ## Configure via environment variables (.env)
57
+
58
+ You can configure the client using environment variables or a `.env` file at the project root:
59
+
60
+ ```bash
61
+ # .env
62
+ MTX_BASE_URL=https://api.mtx.example.com
63
+ MTX_CLIENT_ID=YOUR_CLIENT_ID
64
+ MTX_JWT_SECRET=BASE64_SECRET # Optional: only needed if you will use login_jwt
65
+ ```
66
+
67
+ ```python
68
+ import asyncio
69
+ from mtx_api import MTXClient
70
+ from dotenv import load_dotenv
71
+
72
+ load_dotenv() # Load environment variables from .env
73
+
74
+
75
+ async def main():
76
+ async with MTXClient() as client:
77
+ ok = await client.base.status(access_token="<ACCESS_TOKEN>")
78
+ print(ok)
79
+
80
+
81
+ asyncio.run(main())
82
+ ```
83
+
84
+ ## Available functions
85
+
86
+ All available functions accept their parameters as keyword arguments.
87
+ You can omit arguments that are not needed and accept None.
88
+
89
+ ### client.base:
90
+
91
+ ```
92
+ status(
93
+ access_token: str | None
94
+ ) -> bool
95
+ ```
96
+ ```
97
+ openapi() -> str
98
+ ```
99
+
100
+ ### client.auth:
101
+
102
+ ```
103
+ login_anonymous(
104
+ device_id: str
105
+ ) -> Authentication
106
+ ```
107
+ ```
108
+ login_jwt(
109
+ email: str,
110
+ first_name: str | None,
111
+ last_name: str | None,
112
+ register: bool | None,
113
+ legal_terms_accepted: bool | None
114
+ ) -> Authentication
115
+ ```
116
+ ```
117
+ login_refresh(
118
+ refresh_token: str
119
+ ) -> Authentication
120
+ ```
121
+ ```
122
+ register(
123
+ username: str,
124
+ password: str,
125
+ first_name: str,
126
+ last_name: str,
127
+ legal_terms_accepted: bool,
128
+ jurisdiction_code: str | None
129
+ ) -> Authentication
130
+ ```
131
+ ```
132
+ login(
133
+ username: str,
134
+ password: str
135
+ ) -> Authentication
136
+ ```
137
+
138
+ ### client.user:
139
+
140
+ ```
141
+ profile(
142
+ access_token: str | None
143
+ ) -> Profile
144
+ ```
145
+ ```
146
+ update_profile(
147
+ access_token: str | None,
148
+ email: str | None,
149
+ username: str | None,
150
+ first_name: str | None,
151
+ last_name: str | None,
152
+ twitter_nickname: str | None,
153
+ phone: str | None,
154
+ gender: str | None,
155
+ birthday: str | None
156
+ ) -> Profile
157
+ ```
158
+
159
+ ```
160
+ accept_terms(
161
+ access_token: str
162
+ ) -> bool
163
+ ```
164
+ ```
165
+ legal_terms() -> LegalTerms
166
+ ```
167
+
168
+ ### client.services:
169
+
170
+ ```
171
+ list(
172
+ access_token: str | None,
173
+ jurisdiction_codes: list[str],
174
+ lat: float | None,
175
+ lng: float | None,
176
+ typology_ids: list[str] | None
177
+ ) -> ServiceList
178
+ ```
179
+ ```
180
+ detail(
181
+ access_token: str | None,
182
+ service_id: str,
183
+ jurisdiction_code: str
184
+ ) -> Service
185
+ ```
186
+
187
+ ### client.typologies:
188
+
189
+ ```
190
+ list(
191
+ access_token: str | None,
192
+ jurisdiction_codes: list[str],
193
+ jurisdiction_element_id: str | None,
194
+ typology_ids: list[str] | None,
195
+ lat: float | None,
196
+ lng: float | None,
197
+ page: int | None,
198
+ limit: int | None
199
+ ) -> TypologyList
200
+ ```
201
+ ### client.jurisdictions:
202
+ ```
203
+ list(
204
+ access_token: str | None,
205
+ lat: float | None,
206
+ lng: float | None
207
+ ) -> JurisdictionList
208
+ ```
209
+ ```
210
+ detail(
211
+ access_token: str | None,
212
+ jurisdiction_code: str
213
+ ) -> Jurisdiction
214
+ ```
215
+ ### client.jurisdiction_elements:
216
+ ```
217
+ list(
218
+ access_token: str | None,
219
+ jurisdiction_code: str
220
+ ) -> JurisdictionElementList
221
+ ```
222
+
223
+ ### client.location:
224
+ ```
225
+ resolve(
226
+ jurisdiction_element_id: str,
227
+ formatted_address: str | None,
228
+ lat: float | None,
229
+ lng: float | None
230
+ ) -> LocationAdditionalDataList
231
+ ```
232
+
233
+ ### client.requests:
234
+
235
+ ```
236
+ list(
237
+ access_token: str | None,
238
+ jurisdiction_codes: list[str] | None,
239
+ service_request_ids: list[str] | None,
240
+ service_ids: list[str] | None,
241
+ start_date: str | None,
242
+ end_date: str | None,
243
+ own: bool | None,
244
+ lat: float | None,
245
+ lng: float | None,
246
+ page: int | None,
247
+ limit: int | None,
248
+ address_and_service_request_id: str | None,
249
+ status: list[str] | None,
250
+ typology_ids: list[str] | None,
251
+ distance: int | None,
252
+ following: bool | None,
253
+ order: str | None,
254
+ complaints: bool | None,
255
+ reiterations: bool | None,
256
+ user_reiterated: bool | None,
257
+ user_complaint: bool | None,
258
+ jurisdiction_element_ids: list[str] | None,
259
+ level: int | None,
260
+ polygon: list[float] | None,
261
+ final_ok: bool | None,
262
+ final_not_ok: bool | None,
263
+ final_status: bool | None,
264
+ interested: bool | None,
265
+ timezone: str | None
266
+ ) -> RequestList
267
+ ```
268
+ ```
269
+ detail(
270
+ access_token: str | None,
271
+ request_id: str
272
+ ) -> Request
273
+ ```
274
+ ```
275
+ create(
276
+ access_token: str | None,
277
+ service_id: str,
278
+ jurisdiction_code: str,
279
+ jurisdiction_element_id: str | None,
280
+ origin_device_id: str | None,
281
+ description: str | None,
282
+ public: bool | None,
283
+ lat: float | None,
284
+ lng: float | None,
285
+ address_string: str | None,
286
+ email: str | None,
287
+ first_name: str | None,
288
+ last_name: str | None,
289
+ phone: str | None,
290
+ twitter_nickname: str | None,
291
+ additional_data: Sequence[AdditionalDataValue] | None
292
+ ) -> CreatedRequest
293
+ ```
294
+ ```
295
+ attach_media(
296
+ access_token: str | None,
297
+ request_id: str,
298
+ jurisdiction_code: str,
299
+ file: tuple[str, bytes]
300
+ ) -> RequestMedia
301
+ ```
302
+ ```
303
+ attach_comment(
304
+ access_token: str | None,
305
+ request_id: str,
306
+ comment: str | None,
307
+ files: Sequence[tuple[str, bytes]]
308
+ ) -> RequestComment
309
+ ```
310
+
311
+ ## Errors
312
+
313
+ - HTTP errors raise `ApiError` with fields `status_code`, `code`, and `description`.
314
+ - Response model decoding/validation errors raise `ApiDecodingError`.
315
+ - SDK parameter validation errors raise specific exceptions (all extend `ValueError`):
316
+ - `MissingBaseUrlError`: missing `base_url` configuration (via `MTX_BASE_URL` or `base_url` parameter).
317
+ - `MissingClientIdError`: missing `client_id` configuration (via `MTX_CLIENT_ID` or `client_id` parameter).
318
+ - `MissingJwtSecretError`: missing JWT secret configuration (via `MTX_JWT_SECRET` or `jwt_secret` parameter) when using `auth.login_jwt`.
319
+ - `MissingJurisdictionCodesError`: missing `jurisdiction_codes`/`jurisdiction_code` in calls that require it.
320
+ - `MissingServiceIdError`: missing `service_id` in calls that require it.
321
+ - `MissingRequestIdError`: missing `request_id` in calls that require it.
322
+ - `MissingArgumentError`: a required argument is missing.
323
+ - `InvalidEmailError`: the email is not valid.
@@ -0,0 +1,32 @@
1
+ mtx_api/__init__.py,sha256=iYbppDpBJAKmAZbLJ5cq_GW2KZmo4QU53Ux8pmMg4WM,535
2
+ mtx_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ mtx_api/settings.py,sha256=Er8CgeyLIWackgKozoLWe_Jnv7lL_lfvKLhlwqSTb_Y,291
4
+ mtx_api/client/__init__.py,sha256=vFT4n8Uu34_30JNo2QI3Uh4wL0Yhs8mcDEEgdZ76-ew,73
5
+ mtx_api/client/_auth_client.py,sha256=644gdPGGSlLs9EyD6HVZBoWiJ0Kecgf_7-8t8bY2GMM,7725
6
+ mtx_api/client/_base_client.py,sha256=CtQFWDL-cba5JXxpJmmaiTqQlSwI4no0hZv1Q5Mo4KI,1573
7
+ mtx_api/client/_jurisdiction_client.py,sha256=ZYkLpSu2GwBbi3ZI_VgkMqZUcQXYnhOTg6-B9LcQI_o,2708
8
+ mtx_api/client/_jurisdiction_elements_client.py,sha256=6sZMh3VtiPmZ-dDSTHZj4V7o2xklCu3EXGU1W_Y08-Y,1531
9
+ mtx_api/client/_location_client.py,sha256=OFFl0yhutOiz_vTvd0Rm46LZwnLj_2BSJ5Merl2bzkc,2807
10
+ mtx_api/client/_mtx_http_client.py,sha256=Z_hSw-auehVe-R5_9_Oxlr-1xWNpvFv18hXIJUGvRqw,6608
11
+ mtx_api/client/_request_client.py,sha256=Ku8wuvu3GAxtWBi949pZYbLVAeHFY1OTVkLjIHWp-T4,15245
12
+ mtx_api/client/_service_client.py,sha256=cAJTCSUOSiZKpePhn9j-aLY0sKPuNqygYexQK-M6fZA,3461
13
+ mtx_api/client/_typology_client.py,sha256=Z3WW6WDUOTX9hlkv0DkMfxgMo-Rn2mL2lhqcx4gEATw,2514
14
+ mtx_api/client/_user_client.py,sha256=Uk4qF8-bqRWdOwfEDR_hRsJcgGUuA255YFAofqJZEv8,5033
15
+ mtx_api/client/mtx_client.py,sha256=wKMyNJXuFbFCO6FJ313Ixad4nI-5QGSgE_I4ez7w2LY,1935
16
+ mtx_api/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ mtx_api/models/additional_data.py,sha256=LfLwVOwdj616BG20fzXAiWhQeIxDVlrOXiUyHlRBrcY,10843
18
+ mtx_api/models/auth.py,sha256=K5GD-HN4szBepU8E8B8tMlluwKtvSLsYe8WiqmtQh0I,2831
19
+ mtx_api/models/base.py,sha256=1v_evJGBIZlGNGvlvQKGgVxLuB4hsLapPhbJNULyiNs,448
20
+ mtx_api/models/common.py,sha256=ADopwxoQqXuzloIZCx4tTnJMLd0rFwgSngfTnnGTd8o,3043
21
+ mtx_api/models/errors.py,sha256=ehuHh3j2hAFzrFXsxDPLKjNZd1cyRyjr8l_TbeNTsjs,3228
22
+ mtx_api/models/jurisdiction.py,sha256=CU7N6QCvsjTcQ4QlSjohW0h-qIDPQ5eTrH5cR-Ps-RU,2933
23
+ mtx_api/models/medias.py,sha256=vn4LRH5-p2MWWu2wi7KasPNelV5cnONA0wVHhhAhzZo,3170
24
+ mtx_api/models/request.py,sha256=kZswmrySyrm7ik8OcU0__jZBn2PIvF3xQymo51avwhk,8673
25
+ mtx_api/models/request_comment.py,sha256=xja_rjWm4gHvlIdpdPz31srmSGrx05N3onbfATt87TM,1706
26
+ mtx_api/models/request_media.py,sha256=Lnk_KHBLBSIoaIsMP7NRpFB1oNzhbG2ZDK5DiskBdyU,1025
27
+ mtx_api/models/service.py,sha256=ZMKVpI15JEnbUqBeNG2yv5O7p_ckrrwP0aMN3_1iZpM,7282
28
+ mtx_api/models/typology.py,sha256=6KvxRpl9Y3JgBS0QVKpX2DZR5_tvJ14fHjLDdXBKCI4,2294
29
+ mtx_api_py-0.4.0.dist-info/METADATA,sha256=iV2Dfv9Ic0N4OJ4WpBIVYgR44NC5sJYSfxVsW8tbubs,7115
30
+ mtx_api_py-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ mtx_api_py-0.4.0.dist-info/licenses/LICENSE.txt,sha256=ZLROmkgKwdLBPR2aFrjVZIxbJMNEc_2QMYuAlAnnBq8,1080
32
+ mtx_api_py-0.4.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Radmas Technologies S.L.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.