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,117 @@
1
+ # Modelos y excepciones de error extraídos de models.py
2
+ import json
3
+
4
+ from pydantic import AliasChoices, Field, ValidationError
5
+
6
+ from mtx_api.models.base import ImmutableBaseModel
7
+
8
+
9
+ class ApiErrorReason(ImmutableBaseModel):
10
+ """
11
+ Represents detailed information about an error from the platform.
12
+
13
+ This model captures the complete error context including HTTP status code,
14
+ platform-specific error code, and a human-readable description. It is used
15
+ to provide structured error information when operations fail.
16
+ """
17
+
18
+ status_code: int = Field(
19
+ description="The HTTP status code of the error response (e.g., 400, 404, 500).",
20
+ )
21
+ code: int | None = Field(
22
+ default=None,
23
+ validation_alias=AliasChoices("error_code", "code"),
24
+ description="Platform-specific error code for programmatic error handling.",
25
+ )
26
+ description: str | None = Field(
27
+ default=None,
28
+ validation_alias=AliasChoices("error_msg", "description", "message"),
29
+ description="Human-readable description of the error explaining what went wrong.",
30
+ )
31
+
32
+
33
+ class ApiError(Exception):
34
+ def __init__(self, body: str, status_code: int):
35
+ super().__init__()
36
+ self.reason = self.parse_reason(body, status_code)
37
+
38
+ @staticmethod
39
+ def parse_reason(body: str, status_code: int) -> ApiErrorReason | None:
40
+ if body:
41
+ try:
42
+ obj = json.loads(body)
43
+ if isinstance(obj, list):
44
+ obj = obj[0] if obj else {}
45
+ if obj is None or not isinstance(obj, dict):
46
+ obj = {}
47
+ if "status_code" not in obj:
48
+ obj["status_code"] = status_code
49
+ reason = ApiErrorReason.model_validate(obj)
50
+ except (ValidationError, ValueError):
51
+ reason = ApiErrorReason(description=str(body), status_code=status_code)
52
+ else:
53
+ reason = ApiErrorReason(status_code=status_code)
54
+ return reason
55
+
56
+ @property
57
+ def code(self) -> int | None:
58
+ return self.reason.code if self.reason else None
59
+
60
+ @property
61
+ def description(self) -> str | None:
62
+ return self.reason.description if self.reason else None
63
+
64
+ @property
65
+ def status_code(self) -> int | None:
66
+ return self.reason.status_code if self.reason else None
67
+
68
+ def __str__(self) -> str:
69
+ parts = []
70
+ if self.status_code:
71
+ parts.append(str(self.status_code))
72
+ if self.code:
73
+ parts.append(str(self.code))
74
+ if self.description:
75
+ parts.append(self.description)
76
+ return " ".join(parts)
77
+
78
+
79
+ class ApiDecodingError(Exception):
80
+ pass
81
+
82
+
83
+ class InvalidEmailError(ValueError):
84
+ pass
85
+
86
+
87
+ class MissingBaseUrlError(ValueError):
88
+ pass
89
+
90
+
91
+ class MissingClientIdError(ValueError):
92
+ pass
93
+
94
+
95
+ class MissingJwtSecretError(ValueError):
96
+ pass
97
+
98
+
99
+ class MissingJurisdictionCodesError(ValueError):
100
+ pass
101
+
102
+
103
+ class MissingServiceIdError(ValueError):
104
+ pass
105
+
106
+
107
+ class MissingRequestIdError(ValueError):
108
+ pass
109
+
110
+
111
+ class MissingJurisdictionElementIdError(ValueError):
112
+ pass
113
+
114
+
115
+ class MissingArgumentError(ValueError):
116
+ def __init__(self, arg: str):
117
+ super().__init__(arg)
@@ -0,0 +1,101 @@
1
+ from pydantic import AliasChoices, Field, RootModel
2
+
3
+ from mtx_api.models.base import ImmutableBaseModel
4
+
5
+
6
+ class OriginDevice(ImmutableBaseModel):
7
+ """
8
+ Represents the type of origin device associated with a jurisdiction.
9
+ """
10
+
11
+ id: str | None = Field(
12
+ default=None,
13
+ description="Unique identifier for the origin device.",
14
+ min_length=1,
15
+ )
16
+ options: list[str] | None = Field(
17
+ default=None,
18
+ description="List of configuration options available for the device."
19
+ "Can be one of 'android', 'email', 'facebook', 'inperson', 'internal', 'ios', "
20
+ "'twitter', 'web_channel', 'bot_whatsapp', 'bot_telegram', 'bot_web',",
21
+ )
22
+
23
+
24
+ class JurisdictionElement(ImmutableBaseModel):
25
+ """
26
+ Represents a specific component or administrative division within a jurisdiction.
27
+ """
28
+
29
+ id: str | None = Field(
30
+ default=None,
31
+ description="Unique identifier for the jurisdiction element.",
32
+ min_length=1,
33
+ )
34
+ name: str | None = Field(
35
+ default=None,
36
+ description="Name of the jurisdiction element.",
37
+ min_length=1,
38
+ )
39
+ type: str | None = Field(
40
+ default=None,
41
+ description="Type classification of the element. It can be 'city' or 'building'",
42
+ min_length=1,
43
+ )
44
+ visible_name: str | None = Field(
45
+ default=None,
46
+ description="Human-readable name.",
47
+ min_length=1,
48
+ )
49
+ is_main: bool | None = Field(
50
+ default=None,
51
+ description="Indicates whether this is the primary element for the jurisdiction.",
52
+ )
53
+
54
+
55
+ class Jurisdiction(ImmutableBaseModel):
56
+ """
57
+ Represents a geographical or administrative jurisdiction entity
58
+ within the platform, usually a city.
59
+ """
60
+
61
+ id: str | None = Field(
62
+ default=None,
63
+ description="Unique identifier for the jurisdiction.",
64
+ min_length=1,
65
+ )
66
+ name: str | None = Field(
67
+ default=None,
68
+ description="Official name of the jurisdiction.",
69
+ min_length=1,
70
+ )
71
+ jurisdiction_code: str | None = Field(
72
+ default=None,
73
+ validation_alias=AliasChoices("jurisdiction_id", "jurisdiction_code"),
74
+ serialization_alias="jurisdiction_id",
75
+ description="Code identifying the jurisdiction within the platform",
76
+ min_length=1,
77
+ )
78
+ jurisdiction_elements: list[JurisdictionElement] | None = Field(
79
+ default=None,
80
+ description="Administrative elements that belong to this jurisdiction.",
81
+ )
82
+ origin_devices: list[OriginDevice] | None = Field(
83
+ default=None,
84
+ description="List of devices associated with this jurisdiction.",
85
+ )
86
+
87
+
88
+ class JurisdictionElementList(RootModel[list[JurisdictionElement]]):
89
+ """
90
+ A collection of JurisdictionElement objects.
91
+ """
92
+
93
+ pass
94
+
95
+
96
+ class JurisdictionList(RootModel[list[Jurisdiction]]):
97
+ """
98
+ A collection of Jurisdiction objects.
99
+ """
100
+
101
+ pass
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import Field
4
+
5
+ from mtx_api.models.additional_data import AdditionalDataAnswer
6
+ from mtx_api.models.base import ImmutableBaseModel
7
+ from mtx_api.models.common import Tag
8
+
9
+
10
+ class MediaMetadata(ImmutableBaseModel):
11
+ """
12
+ Represents metadata information associated with media files.
13
+
14
+ This model contains additional contextual data about media, including
15
+ location-based information and creation timestamps.
16
+ """
17
+
18
+ location_additional_data: list[AdditionalDataAnswer] | None = Field(
19
+ default=None,
20
+ description="Additional location-based data associated with where the media was captured.",
21
+ )
22
+ created: str | None = Field(
23
+ default=None,
24
+ description="The timestamp when the media metadata was created, in ISO format.",
25
+ )
26
+
27
+
28
+ class File(ImmutableBaseModel):
29
+ """
30
+ Represents a file resource with its identifier and access URL.
31
+
32
+ This model provides basic file information for accessing uploaded or
33
+ stored files on the platform.
34
+ """
35
+
36
+ id: str | None = Field(
37
+ default=None,
38
+ description="Unique identifier for the file.",
39
+ )
40
+ url: str | None = Field(
41
+ default=None,
42
+ description="The URL where the file can be accessed or downloaded.",
43
+ )
44
+
45
+
46
+ class Media(ImmutableBaseModel):
47
+ """
48
+ Represents media content such as images or videos attached to platform entities.
49
+
50
+ This model contains comprehensive information about media files including
51
+ their visibility, type, metadata, and validation checks.
52
+ """
53
+
54
+ id: str | None = Field(
55
+ default=None,
56
+ description="Unique identifier for the media item.",
57
+ )
58
+ public: bool | None = Field(
59
+ default=None,
60
+ description="Whether the media is publicly visible or restricted to authorized users.",
61
+ )
62
+ type: str | None = Field(
63
+ default=None,
64
+ description="The media type, such as 'image', 'video', or other content types.",
65
+ )
66
+ media_url: str | None = Field(
67
+ default=None,
68
+ description="The URL where the media content can be accessed.",
69
+ )
70
+ created_datetime: str | None = Field(
71
+ default=None,
72
+ description="The timestamp when the media was created or uploaded, in ISO format.",
73
+ )
74
+ deleted: bool | None = Field(
75
+ default=None,
76
+ description="Whether the media has been marked as deleted.",
77
+ )
78
+ media_code: str | None = Field(
79
+ default=None,
80
+ description="A code or reference identifier for the media item.",
81
+ )
82
+ check_distance: str | None = Field(
83
+ default=None,
84
+ description="Distance-based validation check value for media verification.",
85
+ )
86
+ check_time: str | None = Field(
87
+ default=None,
88
+ description="Time-based validation check value for media verification.",
89
+ )
90
+ media_metadata: MediaMetadata | None = Field(
91
+ default=None,
92
+ description="Additional metadata information associated with the media.",
93
+ )
94
+ tags: list[Tag] | None = Field(
95
+ default=None,
96
+ description="Classification tags associated with the media for categorization.",
97
+ )
@@ -0,0 +1,253 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import AliasChoices, Field, RootModel
4
+
5
+ from mtx_api.models.additional_data import AdditionalDataAnswer
6
+ from mtx_api.models.base import DatetimeField, ImmutableBaseModel
7
+ from mtx_api.models.common import Tag, User
8
+ from mtx_api.models.jurisdiction import JurisdictionElement
9
+ from mtx_api.models.medias import File, Media
10
+ from mtx_api.models.service import StatusNode
11
+ from mtx_api.models.typology import Typology
12
+
13
+
14
+ class Following(ImmutableBaseModel):
15
+ """
16
+ Represents whether a user is following a request.
17
+
18
+ This model indicates if the current user has subscribed to receive
19
+ notifications about updates to a particular request.
20
+ """
21
+
22
+ is_following: bool | None = Field(
23
+ default=None,
24
+ alias="isFollowing",
25
+ description="Whether the current user is following this request.",
26
+ )
27
+
28
+
29
+ class CreatedRequest(ImmutableBaseModel):
30
+ """
31
+ Represents a newly created request with basic information.
32
+
33
+ This model contains the essential identifiers and status information
34
+ returned immediately after creating a request.
35
+ """
36
+
37
+ id: str | None = Field(
38
+ default=None,
39
+ validation_alias=AliasChoices("token", "id"),
40
+ serialization_alias="token",
41
+ description="Unique identifier token for the created request.",
42
+ )
43
+ service_request_id: str | None = Field(
44
+ default=None,
45
+ description="Human-readable identifier for the request.",
46
+ )
47
+ status_node: StatusNode | None = Field(
48
+ default=None,
49
+ description="The initial status node of the newly created request.",
50
+ )
51
+
52
+
53
+ class CreatedRequestList(RootModel[list[CreatedRequest]]):
54
+ pass
55
+
56
+
57
+ class Request(CreatedRequest):
58
+ """
59
+ Represents a complete request with all its details and metadata.
60
+
61
+ This model extends CreatedRequest with comprehensive information including
62
+ location data, timestamps, status, media attachments, user interactions,
63
+ and additional configurable fields.
64
+ """
65
+
66
+ description: str | None = Field(
67
+ default=None,
68
+ description="The detailed description of the request provided by the user.",
69
+ )
70
+ address: str | None = Field(
71
+ default=None,
72
+ description="The physical address associated with the request.",
73
+ )
74
+ address_string: str | None = Field(
75
+ default=None,
76
+ description="Alternative formatted address string for the request location.",
77
+ )
78
+ lat: float | None = Field(
79
+ default=None,
80
+ description="Latitude coordinate of the request location.",
81
+ )
82
+ lng: float | None = Field(
83
+ default=None,
84
+ alias="long",
85
+ description="Longitude coordinate of the request location.",
86
+ )
87
+ status_node_type: str | None = Field(
88
+ default=None,
89
+ description="The type of the current status node (e.g., 'initial_node', 'final_node').",
90
+ )
91
+ typology: Typology | None = Field(
92
+ default=None,
93
+ description="The typology classification of the request.",
94
+ )
95
+ jurisdiction_id: str | None = Field(
96
+ default=None,
97
+ description="Code of the jurisdiction where the request was created.",
98
+ )
99
+ jurisdiction_element: JurisdictionElement | None = Field(
100
+ default=None,
101
+ description="The specific jurisdiction element associated with the request.",
102
+ )
103
+ service_id: str | None = Field(
104
+ default=None,
105
+ description="Unique identifier of the service this request belongs to.",
106
+ )
107
+ service_name: str | None = Field(
108
+ default=None,
109
+ description="Internal name of the service.",
110
+ )
111
+ service_code: str | None = Field(
112
+ default=None,
113
+ description="Code identifier of the service.",
114
+ )
115
+ requested_datetime: DatetimeField | None = Field(
116
+ default=None,
117
+ description="Timestamp when the request was created, in ISO format with timezone.",
118
+ )
119
+ updated_datetime: DatetimeField | None = Field(
120
+ default=None,
121
+ description=("Timestamp when the request was last updated, in ISO format with timezone."),
122
+ )
123
+ current_node_estimated_final_datetime: DatetimeField | None = Field(
124
+ default=None,
125
+ description=(
126
+ "Estimated completion time for the current status node, in ISO format with timezone."
127
+ ),
128
+ )
129
+ current_node_estimated_start_datetime: DatetimeField | None = Field(
130
+ default=None,
131
+ description=(
132
+ "Estimated start time for the current status node, in ISO format with timezone."
133
+ ),
134
+ )
135
+ estimated_final_datetime: DatetimeField | None = Field(
136
+ default=None,
137
+ description=(
138
+ "Estimated completion time for the entire request, in ISO format with timezone."
139
+ ),
140
+ )
141
+ estimated_start_datetime: DatetimeField | None = Field(
142
+ default=None,
143
+ description=(
144
+ "Estimated start time for processing the request, in ISO format with timezone."
145
+ ),
146
+ )
147
+ reiterations_count: int | None = Field(
148
+ default=None,
149
+ description="Number of times the request has been reiterated by users.",
150
+ )
151
+ complaints_count: int | None = Field(
152
+ default=None,
153
+ description="Number of complaints filed about this request.",
154
+ )
155
+ comments_count: int | None = Field(
156
+ default=None,
157
+ description="Number of comments posted on this request.",
158
+ )
159
+ worknotes_count: int | None = Field(
160
+ default=None,
161
+ description="Number of internal work notes on this request.",
162
+ )
163
+ evaluation: int | None = Field(
164
+ default=None,
165
+ description="User's evaluation rating for this request.",
166
+ )
167
+ evaluations_count: int | None = Field(
168
+ default=None,
169
+ description="Total number of evaluations received for this request.",
170
+ )
171
+ evaluations_avg: int | None = Field(
172
+ default=None,
173
+ description="Average evaluation rating across all evaluations.",
174
+ )
175
+ public_visibility: bool | None = Field(
176
+ default=None,
177
+ description="Whether this request is visible to the public.",
178
+ )
179
+ complaining: bool | None = Field(
180
+ default=None,
181
+ description="Whether the current user has filed a complaint about this request.",
182
+ )
183
+ supporting: bool | None = Field(
184
+ default=None,
185
+ description="Whether the current user is supporting this request.",
186
+ )
187
+ supporting_count: int | None = Field(
188
+ default=None,
189
+ description="Number of users supporting this request.",
190
+ )
191
+ following_count: int | None = Field(
192
+ default=None,
193
+ description="Number of users following this request.",
194
+ )
195
+ following: Following | None = Field(
196
+ default=None,
197
+ description="Information about whether the current user is following this request.",
198
+ )
199
+ deleted: bool | None = Field(
200
+ default=None,
201
+ description="Whether this request has been marked as deleted.",
202
+ )
203
+ jurisdiction_name: str | None = Field(
204
+ default=None,
205
+ description="Name of the jurisdiction where the request was created.",
206
+ )
207
+ is_evaluable: bool | None = Field(
208
+ default=None,
209
+ description="Whether this request can be evaluated by the user.",
210
+ )
211
+ accepted: bool | None = Field(
212
+ default=None,
213
+ description="Whether this request has been accepted for processing.",
214
+ )
215
+ files: list[File] | None = Field(
216
+ default=None,
217
+ description="List of file attachments associated with this request.",
218
+ )
219
+ medias: list[Media] | None = Field(
220
+ default=None,
221
+ description="List of media items (images/videos) attached to this request.",
222
+ )
223
+ tags: list[Tag] | None = Field(
224
+ default=None,
225
+ description="Classification tags associated with this request.",
226
+ )
227
+ media_url: str | None = Field(
228
+ default=None,
229
+ description="URL to a primary media item for this request.",
230
+ )
231
+ additional_data: list[AdditionalDataAnswer] | None = Field(
232
+ default=None,
233
+ description="Answers to additional configurable questions for this request.",
234
+ )
235
+ location_additional_data: list[AdditionalDataAnswer] | None = Field(
236
+ default=None,
237
+ description="Location-specific additional data answers for this request.",
238
+ )
239
+ user: User | None = Field(
240
+ default=None,
241
+ description="Reference to the user who created this request.",
242
+ )
243
+
244
+
245
+ class RequestList(RootModel[list[Request]]):
246
+ """
247
+ A collection of Request objects.
248
+
249
+ This model represents a list of requests returned when querying
250
+ multiple requests from the platform.
251
+ """
252
+
253
+ pass
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import AliasChoices, Field
4
+
5
+ from mtx_api.models.base import DatetimeField, ImmutableBaseModel
6
+
7
+
8
+ class RequestCommentMedia(ImmutableBaseModel):
9
+ """
10
+ Represents media content attached to a request comment.
11
+
12
+ This model contains information about images, videos, or other media files
13
+ that have been attached to a comment on a request.
14
+ """
15
+
16
+ id: str | None = Field(
17
+ default=None,
18
+ description="Unique identifier for the comment media item.",
19
+ )
20
+ media_url: str | None = Field(
21
+ default=None,
22
+ description="The URL where the media content can be accessed.",
23
+ )
24
+
25
+
26
+ class RequestComment(ImmutableBaseModel):
27
+ """
28
+ Represents a comment or note attached to a request.
29
+
30
+ This model contains user-submitted comments on requests, which can
31
+ include text descriptions and attached media files for additional context.
32
+ """
33
+
34
+ created_datetime: DatetimeField | None = Field(
35
+ default=None,
36
+ description="The timestamp when the comment was created, in ISO format with timezone.",
37
+ )
38
+ id: str | None = Field(
39
+ default=None,
40
+ validation_alias=AliasChoices("comment_code", "id"),
41
+ serialization_alias="comment_code",
42
+ description="Unique identifier for the comment.",
43
+ )
44
+ description: str | None = Field(
45
+ default=None,
46
+ description="The text content of the comment.",
47
+ )
48
+ medias: list[RequestCommentMedia] | None = Field(
49
+ default=None,
50
+ validation_alias=AliasChoices("medias_urls", "medias"),
51
+ serialization_alias="medias_urls",
52
+ description="List of media items attached to the comment.",
53
+ )
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import Field
4
+
5
+ from mtx_api.models.base import DatetimeField, ImmutableBaseModel
6
+
7
+
8
+ class RequestMedia(ImmutableBaseModel):
9
+ """
10
+ Represents media content attached to a request.
11
+
12
+ This model contains information about images, videos, or other media files
13
+ that have been uploaded and associated with a request for
14
+ documentation or evidence purposes.
15
+ """
16
+
17
+ type: str | None = Field(
18
+ default=None,
19
+ description="The media type, such as 'image', 'video', or other content types.",
20
+ )
21
+ media_url: str | None = Field(
22
+ default=None,
23
+ description="The URL where the media content can be accessed.",
24
+ )
25
+ created_datetime: DatetimeField | None = Field(
26
+ default=None,
27
+ description="The timestamp when the media was uploaded, in ISO format with timezone.",
28
+ )
29
+ media_code: str | None = Field(
30
+ default=None,
31
+ description="A unique code or reference identifier for the media item.",
32
+ )