matelab-python-sdk 0.1.0a1__py3-none-any.whl → 0.1.0a3__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.
- matelab/__init__.py +4 -68
- matelab/_generated/models.py +24 -7
- matelab/_transport.py +12 -12
- matelab/client.py +17 -24
- matelab/cloud_drive.py +48 -210
- matelab/groups.py +3 -5
- matelab/{literature.py → literature/__init__.py} +64 -233
- matelab/notebooks.py +33 -124
- matelab/{records.py → records/__init__.py} +369 -363
- matelab/streaming.py +3 -3
- matelab/templates.py +62 -188
- matelab/uploads.py +13 -38
- matelab/users.py +3 -6
- {matelab_python_sdk-0.1.0a1.dist-info → matelab_python_sdk-0.1.0a3.dist-info}/METADATA +141 -87
- matelab_python_sdk-0.1.0a3.dist-info/RECORD +22 -0
- matelab_python_sdk-0.1.0a1.dist-info/RECORD +0 -22
- {matelab_python_sdk-0.1.0a1.dist-info → matelab_python_sdk-0.1.0a3.dist-info}/WHEEL +0 -0
- {matelab_python_sdk-0.1.0a1.dist-info → matelab_python_sdk-0.1.0a3.dist-info}/licenses/LICENSE +0 -0
- {matelab_python_sdk-0.1.0a1.dist-info → matelab_python_sdk-0.1.0a3.dist-info}/licenses/NOTICE +0 -0
matelab/__init__.py
CHANGED
|
@@ -8,16 +8,10 @@ from matelab.cloud_drive import (
|
|
|
8
8
|
CloudDriveRootPermissions,
|
|
9
9
|
CloudDriveRootRef,
|
|
10
10
|
CloudFile,
|
|
11
|
-
CloudFileBindResult,
|
|
12
|
-
CloudFileMoveResult,
|
|
13
11
|
CloudFilePage,
|
|
14
|
-
CloudFilePermanentDeleteResult,
|
|
15
12
|
CloudFileRef,
|
|
16
|
-
CloudFileUpdateResult,
|
|
17
13
|
CloudFolder,
|
|
18
|
-
CloudFolderDeleteResult,
|
|
19
14
|
CloudFolderMetadata,
|
|
20
|
-
CloudFolderMoveResult,
|
|
21
15
|
CloudFolderRef,
|
|
22
16
|
CloudFolderSaveResult,
|
|
23
17
|
CloudFolderTree,
|
|
@@ -38,11 +32,8 @@ from matelab.literature import (
|
|
|
38
32
|
ExtractedLiteratureMetadata,
|
|
39
33
|
LiteratureCitation,
|
|
40
34
|
LiteratureComment,
|
|
41
|
-
LiteratureCommentDeleteResult,
|
|
42
35
|
LiteratureCommentDraft,
|
|
43
36
|
LiteratureCommentRef,
|
|
44
|
-
LiteratureCommentSaveResult,
|
|
45
|
-
LiteratureCreateResult,
|
|
46
37
|
LiteratureCreationSchema,
|
|
47
38
|
LiteratureDetail,
|
|
48
39
|
LiteratureField,
|
|
@@ -56,13 +47,8 @@ from matelab.literature import (
|
|
|
56
47
|
LiteratureNestedField,
|
|
57
48
|
LiteraturePage,
|
|
58
49
|
LiteraturePdf,
|
|
59
|
-
LiteraturePdfDeleteResult,
|
|
60
|
-
LiteraturePdfReplaceResult,
|
|
61
|
-
LiteraturePermanentDeleteResult,
|
|
62
|
-
LiteratureShareResult,
|
|
63
50
|
LiteratureSource,
|
|
64
51
|
LiteratureStoredMetadata,
|
|
65
|
-
LiteratureUpdateResult,
|
|
66
52
|
PendingLiteratureShare,
|
|
67
53
|
PendingLiteratureShareComment,
|
|
68
54
|
PendingLiteratureShareRef,
|
|
@@ -75,24 +61,18 @@ from matelab.literature import (
|
|
|
75
61
|
from matelab.models import Identity, Session, Token
|
|
76
62
|
from matelab.notebooks import (
|
|
77
63
|
NotebookCollection,
|
|
78
|
-
NotebookCreateResult,
|
|
79
64
|
NotebookListField,
|
|
80
65
|
NotebookMetadata,
|
|
81
66
|
NotebookRef,
|
|
82
67
|
NotebookShare,
|
|
83
68
|
NotebookSharePermissionGrant,
|
|
84
69
|
NotebookShareRef,
|
|
85
|
-
NotebookShareResult,
|
|
86
70
|
NotebookShares,
|
|
87
|
-
NotebookShareUpdateResult,
|
|
88
71
|
NotebookSummary,
|
|
89
|
-
NotebookUnshareResult,
|
|
90
|
-
NotebookUpdateResult,
|
|
91
72
|
PublicNotebookRef,
|
|
92
73
|
PublicNotebookSummary,
|
|
93
74
|
)
|
|
94
75
|
from matelab.records import (
|
|
95
|
-
BlankRecordCreateResult,
|
|
96
76
|
DeletedRecordPage,
|
|
97
77
|
DeletedRecordRef,
|
|
98
78
|
DeletedRecordSummary,
|
|
@@ -106,11 +86,9 @@ from matelab.records import (
|
|
|
106
86
|
RecordCollection,
|
|
107
87
|
RecordComment,
|
|
108
88
|
RecordCommentAttachmentRef,
|
|
109
|
-
RecordCommentDeleteResult,
|
|
110
89
|
RecordCommentDraft,
|
|
111
90
|
RecordCommentRef,
|
|
112
91
|
RecordComments,
|
|
113
|
-
RecordCommentSaveResult,
|
|
114
92
|
RecordCopyResult,
|
|
115
93
|
RecordDeleteResult,
|
|
116
94
|
RecordExport,
|
|
@@ -118,6 +96,7 @@ from matelab.records import (
|
|
|
118
96
|
RecordFilesAttachmentAppend,
|
|
119
97
|
RecordFilesAttachmentRemoval,
|
|
120
98
|
RecordFilesAttachmentReplacement,
|
|
99
|
+
RecordFormAttachmentFieldAddition,
|
|
121
100
|
RecordFormAttachmentRemoval,
|
|
122
101
|
RecordImportItem,
|
|
123
102
|
RecordImportResult,
|
|
@@ -131,8 +110,6 @@ from matelab.records import (
|
|
|
131
110
|
RecordPatch,
|
|
132
111
|
RecordRef,
|
|
133
112
|
RecordRelation,
|
|
134
|
-
RecordRelationAddResult,
|
|
135
|
-
RecordRelationDeleteResult,
|
|
136
113
|
RecordRelationRef,
|
|
137
114
|
RecordRelations,
|
|
138
115
|
RecordRestoreResult,
|
|
@@ -150,6 +127,7 @@ from matelab.records import (
|
|
|
150
127
|
RecordVersionRef,
|
|
151
128
|
RecordVersionSummary,
|
|
152
129
|
RelatedRecordIdentity,
|
|
130
|
+
StagedNotebookAttachment,
|
|
153
131
|
StagedRecordAttachment,
|
|
154
132
|
StagedRecordCommentAttachment,
|
|
155
133
|
)
|
|
@@ -157,30 +135,20 @@ from matelab.streaming import ByteRange, DownloadStream
|
|
|
157
135
|
from matelab.templates import (
|
|
158
136
|
TemplateCollection,
|
|
159
137
|
TemplateContent,
|
|
160
|
-
TemplateContentSaveResult,
|
|
161
|
-
TemplateCopyResult,
|
|
162
|
-
TemplateGroupAddResult,
|
|
163
|
-
TemplateGroupRemoveResult,
|
|
164
|
-
TemplateIntroUpdateResult,
|
|
165
138
|
TemplateLibraryEntryRef,
|
|
166
139
|
TemplateLibraryRelationKind,
|
|
167
|
-
TemplateLibraryRemovalResult,
|
|
168
|
-
TemplateMarketAcquireResult,
|
|
169
140
|
TemplateMarketEntry,
|
|
170
141
|
TemplateMarketPage,
|
|
171
|
-
TemplateMarketSubmissionResult,
|
|
172
142
|
TemplateMetadata,
|
|
173
143
|
TemplateMetadataResult,
|
|
174
144
|
TemplateModule,
|
|
175
145
|
TemplateRef,
|
|
176
|
-
TemplateShareResult,
|
|
177
146
|
TemplateSource,
|
|
178
147
|
TemplateSummary,
|
|
179
148
|
)
|
|
180
149
|
from matelab.uploads import (
|
|
181
150
|
StagedFile,
|
|
182
151
|
StagedFileFragment,
|
|
183
|
-
StagedUploadAbortResult,
|
|
184
152
|
StagedUploadSession,
|
|
185
153
|
UploadBindingRef,
|
|
186
154
|
)
|
|
@@ -188,7 +156,6 @@ from matelab.users import UserRef, UserSearchResult, UserSearchScope, UserSummar
|
|
|
188
156
|
|
|
189
157
|
__all__ = [
|
|
190
158
|
"AsyncMatelab",
|
|
191
|
-
"BlankRecordCreateResult",
|
|
192
159
|
"ByteRange",
|
|
193
160
|
"CloudDriveListing",
|
|
194
161
|
"CloudDriveLocation",
|
|
@@ -198,16 +165,10 @@ __all__ = [
|
|
|
198
165
|
"CloudDriveRootPermissions",
|
|
199
166
|
"CloudDriveRootRef",
|
|
200
167
|
"CloudFile",
|
|
201
|
-
"CloudFileBindResult",
|
|
202
|
-
"CloudFileMoveResult",
|
|
203
168
|
"CloudFilePage",
|
|
204
|
-
"CloudFilePermanentDeleteResult",
|
|
205
169
|
"CloudFileRef",
|
|
206
|
-
"CloudFileUpdateResult",
|
|
207
170
|
"CloudFolder",
|
|
208
|
-
"CloudFolderDeleteResult",
|
|
209
171
|
"CloudFolderMetadata",
|
|
210
|
-
"CloudFolderMoveResult",
|
|
211
172
|
"CloudFolderRef",
|
|
212
173
|
"CloudFolderSaveResult",
|
|
213
174
|
"CloudFolderTree",
|
|
@@ -226,11 +187,8 @@ __all__ = [
|
|
|
226
187
|
"Identity",
|
|
227
188
|
"LiteratureCitation",
|
|
228
189
|
"LiteratureComment",
|
|
229
|
-
"LiteratureCommentDeleteResult",
|
|
230
190
|
"LiteratureCommentDraft",
|
|
231
191
|
"LiteratureCommentRef",
|
|
232
|
-
"LiteratureCommentSaveResult",
|
|
233
|
-
"LiteratureCreateResult",
|
|
234
192
|
"LiteratureCreationSchema",
|
|
235
193
|
"LiteratureDetail",
|
|
236
194
|
"LiteratureField",
|
|
@@ -244,13 +202,8 @@ __all__ = [
|
|
|
244
202
|
"LiteratureNestedField",
|
|
245
203
|
"LiteraturePage",
|
|
246
204
|
"LiteraturePdf",
|
|
247
|
-
"LiteraturePdfDeleteResult",
|
|
248
|
-
"LiteraturePdfReplaceResult",
|
|
249
|
-
"LiteraturePermanentDeleteResult",
|
|
250
|
-
"LiteratureShareResult",
|
|
251
205
|
"LiteratureSource",
|
|
252
206
|
"LiteratureStoredMetadata",
|
|
253
|
-
"LiteratureUpdateResult",
|
|
254
207
|
"MatelabAuthenticationError",
|
|
255
208
|
"MatelabError",
|
|
256
209
|
"MatelabProtocolError",
|
|
@@ -259,19 +212,14 @@ __all__ = [
|
|
|
259
212
|
"MatelabUsageError",
|
|
260
213
|
"MatelabVerificationError",
|
|
261
214
|
"NotebookCollection",
|
|
262
|
-
"NotebookCreateResult",
|
|
263
215
|
"NotebookListField",
|
|
264
216
|
"NotebookMetadata",
|
|
265
217
|
"NotebookRef",
|
|
266
218
|
"NotebookShare",
|
|
267
219
|
"NotebookSharePermissionGrant",
|
|
268
220
|
"NotebookShareRef",
|
|
269
|
-
"NotebookShareResult",
|
|
270
|
-
"NotebookShareUpdateResult",
|
|
271
221
|
"NotebookShares",
|
|
272
222
|
"NotebookSummary",
|
|
273
|
-
"NotebookUnshareResult",
|
|
274
|
-
"NotebookUpdateResult",
|
|
275
223
|
"PendingLiteratureShare",
|
|
276
224
|
"PendingLiteratureShareComment",
|
|
277
225
|
"PendingLiteratureShareRef",
|
|
@@ -288,10 +236,8 @@ __all__ = [
|
|
|
288
236
|
"RecordCollection",
|
|
289
237
|
"RecordComment",
|
|
290
238
|
"RecordCommentAttachmentRef",
|
|
291
|
-
"RecordCommentDeleteResult",
|
|
292
239
|
"RecordCommentDraft",
|
|
293
240
|
"RecordCommentRef",
|
|
294
|
-
"RecordCommentSaveResult",
|
|
295
241
|
"RecordComments",
|
|
296
242
|
"RecordCopyResult",
|
|
297
243
|
"RecordDeleteResult",
|
|
@@ -300,6 +246,7 @@ __all__ = [
|
|
|
300
246
|
"RecordFilesAttachmentAppend",
|
|
301
247
|
"RecordFilesAttachmentRemoval",
|
|
302
248
|
"RecordFilesAttachmentReplacement",
|
|
249
|
+
"RecordFormAttachmentFieldAddition",
|
|
303
250
|
"RecordFormAttachmentRemoval",
|
|
304
251
|
"RecordImportItem",
|
|
305
252
|
"RecordImportResult",
|
|
@@ -313,8 +260,6 @@ __all__ = [
|
|
|
313
260
|
"RecordPatch",
|
|
314
261
|
"RecordRef",
|
|
315
262
|
"RecordRelation",
|
|
316
|
-
"RecordRelationAddResult",
|
|
317
|
-
"RecordRelationDeleteResult",
|
|
318
263
|
"RecordRelationRef",
|
|
319
264
|
"RecordRelations",
|
|
320
265
|
"RecordRestoreResult",
|
|
@@ -337,30 +282,21 @@ __all__ = [
|
|
|
337
282
|
"SharedLiteratureLibraryRef",
|
|
338
283
|
"StagedFile",
|
|
339
284
|
"StagedFileFragment",
|
|
285
|
+
"StagedNotebookAttachment",
|
|
340
286
|
"StagedPdfMetadataSource",
|
|
341
287
|
"StagedRecordAttachment",
|
|
342
288
|
"StagedRecordCommentAttachment",
|
|
343
|
-
"StagedUploadAbortResult",
|
|
344
289
|
"StagedUploadSession",
|
|
345
290
|
"TemplateCollection",
|
|
346
291
|
"TemplateContent",
|
|
347
|
-
"TemplateContentSaveResult",
|
|
348
|
-
"TemplateCopyResult",
|
|
349
|
-
"TemplateGroupAddResult",
|
|
350
|
-
"TemplateGroupRemoveResult",
|
|
351
|
-
"TemplateIntroUpdateResult",
|
|
352
292
|
"TemplateLibraryEntryRef",
|
|
353
293
|
"TemplateLibraryRelationKind",
|
|
354
|
-
"TemplateLibraryRemovalResult",
|
|
355
|
-
"TemplateMarketAcquireResult",
|
|
356
294
|
"TemplateMarketEntry",
|
|
357
295
|
"TemplateMarketPage",
|
|
358
|
-
"TemplateMarketSubmissionResult",
|
|
359
296
|
"TemplateMetadata",
|
|
360
297
|
"TemplateMetadataResult",
|
|
361
298
|
"TemplateModule",
|
|
362
299
|
"TemplateRef",
|
|
363
|
-
"TemplateShareResult",
|
|
364
300
|
"TemplateSource",
|
|
365
301
|
"TemplateSummary",
|
|
366
302
|
"Token",
|
matelab/_generated/models.py
CHANGED
|
@@ -7,7 +7,7 @@ from typing import Annotated, Any, Literal
|
|
|
7
7
|
|
|
8
8
|
from pydantic import BaseModel, ConfigDict, Field, RootModel, SecretStr
|
|
9
9
|
|
|
10
|
-
OPENAPI_INFO_VERSION = "0.1.
|
|
10
|
+
OPENAPI_INFO_VERSION = "0.1.1"
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class ResponseEnvelope(BaseModel):
|
|
@@ -108,9 +108,11 @@ class CloudDriveFile(BaseModel):
|
|
|
108
108
|
id: Annotated[int, Field(ge=1)]
|
|
109
109
|
filename: Annotated[str, Field(max_length=255, min_length=1)]
|
|
110
110
|
hash: Sha256
|
|
111
|
-
size: Annotated[
|
|
111
|
+
size: Annotated[int, Field(ge=0)]
|
|
112
112
|
"""
|
|
113
|
-
|
|
113
|
+
File size in bytes. The Provider fetches the unsigned BIGINT with
|
|
114
|
+
PDO::ATTR_STRINGIFY_FETCHES disabled and returns a JSON integer.
|
|
115
|
+
|
|
114
116
|
"""
|
|
115
117
|
userid: Annotated[int, Field(ge=1)]
|
|
116
118
|
date_time: Annotated[str | None, Field(pattern="^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$")]
|
|
@@ -263,19 +265,31 @@ class UploadAttachmentRequest(BaseModel):
|
|
|
263
265
|
)
|
|
264
266
|
eln: Annotated[str, Field(min_length=1)]
|
|
265
267
|
"""
|
|
266
|
-
Notebook title used to select its data
|
|
268
|
+
Notebook title used to check write permission and select its data
|
|
269
|
+
server. The value is not persisted on the staging row.
|
|
270
|
+
|
|
267
271
|
"""
|
|
268
272
|
user: Annotated[int | None, Field(ge=1)] = None
|
|
269
273
|
"""
|
|
270
|
-
Optional notebook owner identifier for a non-owned notebook.
|
|
274
|
+
Optional notebook owner identifier for a non-owned notebook. It
|
|
275
|
+
selects the notebook but never replaces the authenticated uploader
|
|
276
|
+
as the staging owner.
|
|
277
|
+
|
|
271
278
|
"""
|
|
272
279
|
uid: Annotated[str, Field(max_length=45, min_length=1)]
|
|
273
280
|
"""
|
|
274
|
-
|
|
281
|
+
Caller-generated upload-event key stored in `upload_temp.data`.
|
|
282
|
+
It is independent of, and need not equal, the UID of a record later
|
|
283
|
+
created or updated with this staged file.
|
|
284
|
+
|
|
275
285
|
"""
|
|
276
286
|
name: Annotated[str, Field(max_length=45)] = ""
|
|
277
287
|
"""
|
|
278
|
-
|
|
288
|
+
Caller-generated staging name stored in `upload_temp.unique_str`.
|
|
289
|
+
Missing or empty falls back to `uid`. On success, use the response
|
|
290
|
+
`name` once as `#file{name}` in the same user's same-notebook
|
|
291
|
+
import or update workflow.
|
|
292
|
+
|
|
279
293
|
"""
|
|
280
294
|
hash: Sha256
|
|
281
295
|
last: Literal[1] = 1
|
|
@@ -303,6 +317,9 @@ class UploadAttachmentResponse(BaseModel):
|
|
|
303
317
|
Provider-built legacy query string for the temporary file.
|
|
304
318
|
"""
|
|
305
319
|
name: Annotated[str, Field(min_length=1)]
|
|
320
|
+
"""
|
|
321
|
+
Resolved one-shot staging name used by `#file{name}`.
|
|
322
|
+
"""
|
|
306
323
|
filename: Annotated[str, Field(min_length=1)]
|
|
307
324
|
size: Annotated[int, Field(ge=0)]
|
|
308
325
|
hash: Sha256
|
matelab/_transport.py
CHANGED
|
@@ -7,10 +7,10 @@ from dataclasses import dataclass
|
|
|
7
7
|
from enum import StrEnum
|
|
8
8
|
from typing import IO, Generic, TypeAlias, TypeVar, cast
|
|
9
9
|
|
|
10
|
-
import
|
|
10
|
+
import httpx2
|
|
11
11
|
from pydantic import BaseModel, ValidationError
|
|
12
12
|
|
|
13
|
-
from matelab._generated
|
|
13
|
+
from matelab._generated import models as wire_models
|
|
14
14
|
from matelab.errors import (
|
|
15
15
|
MatelabAuthenticationError,
|
|
16
16
|
MatelabProtocolError,
|
|
@@ -152,7 +152,7 @@ _REFRESH_TOKENS = Operation(
|
|
|
152
152
|
method="POST",
|
|
153
153
|
path="/tokens/tokens_refresh",
|
|
154
154
|
encoding=Encoding.FORM,
|
|
155
|
-
response_model=TokenRefreshResponse,
|
|
155
|
+
response_model=wire_models.TokenRefreshResponse,
|
|
156
156
|
success_codes=frozenset({0}),
|
|
157
157
|
authenticated=False,
|
|
158
158
|
authentication_errors=True,
|
|
@@ -160,8 +160,8 @@ _REFRESH_TOKENS = Operation(
|
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
class SessionTransport:
|
|
163
|
-
def __init__(self, http_client:
|
|
164
|
-
self._http:
|
|
163
|
+
def __init__(self, http_client: httpx2.AsyncClient, *, session: Session | None = None) -> None:
|
|
164
|
+
self._http: httpx2.AsyncClient = http_client
|
|
165
165
|
self.session: Session | None = session
|
|
166
166
|
self._refresh_lock: asyncio.Lock = asyncio.Lock()
|
|
167
167
|
|
|
@@ -200,7 +200,7 @@ class SessionTransport:
|
|
|
200
200
|
if session.refresh.expires_at_ms <= self._now_ms():
|
|
201
201
|
raise MatelabAuthenticationError("Matelab refresh token expired.")
|
|
202
202
|
try:
|
|
203
|
-
request = TokenRefreshRequest(refresh_token=session.refresh.value)
|
|
203
|
+
request = wire_models.TokenRefreshRequest(refresh_token=session.refresh.value)
|
|
204
204
|
except ValidationError:
|
|
205
205
|
raise MatelabAuthenticationError("The Matelab refresh token is invalid.") from None
|
|
206
206
|
response = await self.request(_REFRESH_TOKENS, payload=request.model_dump(mode="json"))
|
|
@@ -307,7 +307,7 @@ class SessionTransport:
|
|
|
307
307
|
response = await self._http.request(operation.method, operation.path, headers=headers)
|
|
308
308
|
else:
|
|
309
309
|
raise MatelabProtocolError(f"Unsupported request encoding: {operation.encoding}.")
|
|
310
|
-
except
|
|
310
|
+
except httpx2.TransportError:
|
|
311
311
|
raise MatelabTransportError("Could not exchange data with the Matelab Provider.") from None
|
|
312
312
|
if not response.is_success:
|
|
313
313
|
raise MatelabTransportError(
|
|
@@ -329,7 +329,7 @@ class SessionTransport:
|
|
|
329
329
|
)
|
|
330
330
|
if code not in operation.success_codes:
|
|
331
331
|
try:
|
|
332
|
-
error_response = ErrorResponse.model_validate(response_payload)
|
|
332
|
+
error_response = wire_models.ErrorResponse.model_validate(response_payload)
|
|
333
333
|
except ValidationError:
|
|
334
334
|
raise MatelabProtocolError(
|
|
335
335
|
"Matelab error response does not match the Integration Contract.", payload=sanitized_payload
|
|
@@ -391,7 +391,7 @@ class SessionTransport:
|
|
|
391
391
|
)
|
|
392
392
|
try:
|
|
393
393
|
response = await self._http.send(request, stream=True)
|
|
394
|
-
except
|
|
394
|
+
except httpx2.TransportError:
|
|
395
395
|
raise MatelabTransportError("Could not exchange data with the Matelab Provider.") from None
|
|
396
396
|
|
|
397
397
|
if response.status_code not in {200, 206}:
|
|
@@ -423,7 +423,7 @@ class SessionTransport:
|
|
|
423
423
|
"Matelab returned a JSON success envelope instead of attachment bytes.", payload=sanitized_payload
|
|
424
424
|
)
|
|
425
425
|
try:
|
|
426
|
-
error_response = ErrorResponse.model_validate(response_payload)
|
|
426
|
+
error_response = wire_models.ErrorResponse.model_validate(response_payload)
|
|
427
427
|
except ValidationError:
|
|
428
428
|
raise MatelabProtocolError(
|
|
429
429
|
"Matelab download error response does not match the Integration Contract.",
|
|
@@ -466,7 +466,7 @@ class SessionTransport:
|
|
|
466
466
|
return DownloadStream(response, content_length=content_length)
|
|
467
467
|
|
|
468
468
|
@staticmethod
|
|
469
|
-
def _parse_content_length(response:
|
|
469
|
+
def _parse_content_length(response: httpx2.Response) -> int | None:
|
|
470
470
|
value = SessionTransport._header(response, "Content-Length")
|
|
471
471
|
if value is None:
|
|
472
472
|
return None
|
|
@@ -477,5 +477,5 @@ class SessionTransport:
|
|
|
477
477
|
return content_length if content_length >= 0 else None
|
|
478
478
|
|
|
479
479
|
@staticmethod
|
|
480
|
-
def _header(response:
|
|
480
|
+
def _header(response: httpx2.Response, name: str) -> str | None:
|
|
481
481
|
return cast(str | None, response.headers.get(name))
|
matelab/client.py
CHANGED
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
from typing import Self
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import httpx2
|
|
4
4
|
from pydantic import SecretStr, ValidationError
|
|
5
5
|
|
|
6
|
-
from matelab._generated
|
|
7
|
-
AppIdentityResponse,
|
|
8
|
-
AuthToken,
|
|
9
|
-
ChatSsoCodeExchangeRequest,
|
|
10
|
-
ChatSsoCodeExchangeResponse,
|
|
11
|
-
TokenLoginRequest,
|
|
12
|
-
TokenLoginResponse,
|
|
13
|
-
TokenRefreshRequest,
|
|
14
|
-
TokenRefreshResponse,
|
|
15
|
-
)
|
|
6
|
+
from matelab._generated import models as wire_models
|
|
16
7
|
from matelab._transport import Encoding, Operation, SessionTransport, multipart_fields
|
|
17
8
|
from matelab.cloud_drive import CloudDrive
|
|
18
9
|
from matelab.errors import MatelabAuthenticationError, MatelabUsageError
|
|
@@ -31,7 +22,7 @@ _LOGIN = Operation(
|
|
|
31
22
|
method="POST",
|
|
32
23
|
path="/tokens/tokens",
|
|
33
24
|
encoding=Encoding.MULTIPART,
|
|
34
|
-
response_model=TokenLoginResponse,
|
|
25
|
+
response_model=wire_models.TokenLoginResponse,
|
|
35
26
|
success_codes=frozenset({0}),
|
|
36
27
|
authenticated=False,
|
|
37
28
|
authentication_errors=True,
|
|
@@ -40,7 +31,7 @@ _EXTERNAL_TOKEN_REFRESH = Operation(
|
|
|
40
31
|
method="POST",
|
|
41
32
|
path="/tokens/tokens_refresh",
|
|
42
33
|
encoding=Encoding.FORM,
|
|
43
|
-
response_model=TokenRefreshResponse,
|
|
34
|
+
response_model=wire_models.TokenRefreshResponse,
|
|
44
35
|
success_codes=frozenset({0}),
|
|
45
36
|
authenticated=False,
|
|
46
37
|
authentication_errors=True,
|
|
@@ -49,7 +40,7 @@ _APP_IDENTITY = Operation(
|
|
|
49
40
|
method="GET",
|
|
50
41
|
path="/actions/app",
|
|
51
42
|
encoding=Encoding.NONE,
|
|
52
|
-
response_model=AppIdentityResponse,
|
|
43
|
+
response_model=wire_models.AppIdentityResponse,
|
|
53
44
|
success_codes=frozenset({0}),
|
|
54
45
|
authentication_errors=True,
|
|
55
46
|
retry_on_access_expired=True,
|
|
@@ -58,7 +49,7 @@ _CHAT_SSO = Operation(
|
|
|
58
49
|
method="POST",
|
|
59
50
|
path="/unlogin_eln/code_check",
|
|
60
51
|
encoding=Encoding.FORM,
|
|
61
|
-
response_model=ChatSsoCodeExchangeResponse,
|
|
52
|
+
response_model=wire_models.ChatSsoCodeExchangeResponse,
|
|
62
53
|
success_codes=frozenset({0}),
|
|
63
54
|
authenticated=False,
|
|
64
55
|
authentication_errors=True,
|
|
@@ -69,7 +60,7 @@ class AsyncMatelab:
|
|
|
69
60
|
"""One-user async client that owns at most one process-local Matelab Session.
|
|
70
61
|
|
|
71
62
|
Do not share one instance across logical user sessions. Separate instances may share an injected
|
|
72
|
-
``
|
|
63
|
+
``httpx2.AsyncClient`` while retaining independent Session state and refresh locks.
|
|
73
64
|
"""
|
|
74
65
|
|
|
75
66
|
def __init__(
|
|
@@ -78,7 +69,7 @@ class AsyncMatelab:
|
|
|
78
69
|
*,
|
|
79
70
|
session: Session | None = None,
|
|
80
71
|
timeout: float = 30.0,
|
|
81
|
-
http_client:
|
|
72
|
+
http_client: httpx2.AsyncClient | None = None,
|
|
82
73
|
) -> None:
|
|
83
74
|
"""Create a client without performing network I/O.
|
|
84
75
|
|
|
@@ -86,10 +77,10 @@ class AsyncMatelab:
|
|
|
86
77
|
the latest value exposed by :attr:`session`.
|
|
87
78
|
"""
|
|
88
79
|
self._owns_http_client: bool = http_client is None
|
|
89
|
-
self._http:
|
|
80
|
+
self._http: httpx2.AsyncClient = (
|
|
90
81
|
http_client
|
|
91
82
|
if http_client is not None
|
|
92
|
-
else
|
|
83
|
+
else httpx2.AsyncClient(base_url=base_url.rstrip("/"), timeout=timeout)
|
|
93
84
|
)
|
|
94
85
|
self._transport: SessionTransport = SessionTransport(self._http, session=session)
|
|
95
86
|
self.cloud_drive: CloudDrive = CloudDrive(self._transport)
|
|
@@ -119,7 +110,7 @@ class AsyncMatelab:
|
|
|
119
110
|
async def authenticate(self, username: str, password: str) -> Session:
|
|
120
111
|
"""Authenticate, install, and return the same latest instance Session."""
|
|
121
112
|
try:
|
|
122
|
-
request = TokenLoginRequest(username=username, password=SecretStr(password))
|
|
113
|
+
request = wire_models.TokenLoginRequest(username=username, password=SecretStr(password))
|
|
123
114
|
except ValidationError:
|
|
124
115
|
raise MatelabUsageError("Matelab username or password does not satisfy the Integration Contract.") from None
|
|
125
116
|
response = await self._transport.request(
|
|
@@ -134,7 +125,7 @@ class AsyncMatelab:
|
|
|
134
125
|
async def exchange_chat_sso_code(self, *, code: str, key: str) -> Session:
|
|
135
126
|
"""Consume one Chat SSO code, install its Session, and return that same Session."""
|
|
136
127
|
try:
|
|
137
|
-
request = ChatSsoCodeExchangeRequest(code=code, key=SecretStr(key))
|
|
128
|
+
request = wire_models.ChatSsoCodeExchangeRequest(code=code, key=SecretStr(key))
|
|
138
129
|
except ValidationError:
|
|
139
130
|
raise MatelabUsageError("Chat SSO credentials do not satisfy the Integration Contract.") from None
|
|
140
131
|
response = await self._transport.request(
|
|
@@ -175,15 +166,17 @@ class AsyncMatelab:
|
|
|
175
166
|
response = await self._transport.request(_APP_IDENTITY, bearer_token=access_token)
|
|
176
167
|
return Identity(userid=response.user.userid, username=response.user.username, email=response.user.email)
|
|
177
168
|
|
|
178
|
-
async def _exchange_external_refresh_token(self, refresh_token: str) -> TokenRefreshResponse:
|
|
169
|
+
async def _exchange_external_refresh_token(self, refresh_token: str) -> wire_models.TokenRefreshResponse:
|
|
179
170
|
try:
|
|
180
|
-
request = TokenRefreshRequest(refresh_token=refresh_token)
|
|
171
|
+
request = wire_models.TokenRefreshRequest(refresh_token=refresh_token)
|
|
181
172
|
except ValidationError:
|
|
182
173
|
raise MatelabAuthenticationError("The Matelab refresh token is invalid.") from None
|
|
183
174
|
return await self._transport.request(_EXTERNAL_TOKEN_REFRESH, payload=request.model_dump(mode="json"))
|
|
184
175
|
|
|
185
176
|
@staticmethod
|
|
186
|
-
def _session_from_wire(
|
|
177
|
+
def _session_from_wire(
|
|
178
|
+
access: wire_models.AuthToken, refresh: wire_models.AuthToken, *, identity: Identity | None
|
|
179
|
+
) -> Session:
|
|
187
180
|
return Session(
|
|
188
181
|
access=Token(value=access.token, expires_at_ms=access.expiredAt),
|
|
189
182
|
refresh=Token(value=refresh.token, expires_at_ms=refresh.expiredAt),
|