evo-files 0.1.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.
- evo/files/__init__.py +26 -0
- evo/files/_model_config.py +20 -0
- evo/files/client.py +327 -0
- evo/files/data.py +74 -0
- evo/files/endpoints/__init__.py +35 -0
- evo/files/endpoints/api/__init__.py +12 -0
- evo/files/endpoints/api/file_v2_api.py +649 -0
- evo/files/endpoints/models.py +124 -0
- evo/files/io.py +190 -0
- evo_files-0.1.0.dist-info/METADATA +58 -0
- evo_files-0.1.0.dist-info/RECORD +14 -0
- evo_files-0.1.0.dist-info/WHEEL +5 -0
- evo_files-0.1.0.dist-info/licenses/LICENSE.md +190 -0
- evo_files-0.1.0.dist-info/top_level.txt +1 -0
evo/files/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
# See the License for the specific language governing permissions and
|
|
10
|
+
# limitations under the License.
|
|
11
|
+
|
|
12
|
+
"""FileAPI SDK
|
|
13
|
+
=====================
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .client import FileAPIClient
|
|
17
|
+
from .data import FileMetadata, FileVersion
|
|
18
|
+
from .io import FileAPIDownload, FileAPIUpload
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"FileAPIClient",
|
|
22
|
+
"FileAPIDownload",
|
|
23
|
+
"FileAPIUpload",
|
|
24
|
+
"FileMetadata",
|
|
25
|
+
"FileVersion",
|
|
26
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
# See the License for the specific language governing permissions and
|
|
10
|
+
# limitations under the License.
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel, ConfigDict
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CustomBaseModel(BaseModel):
|
|
16
|
+
"""Custom base model for providing a global configuration to generated models."""
|
|
17
|
+
|
|
18
|
+
model_config = ConfigDict(
|
|
19
|
+
extra="allow",
|
|
20
|
+
)
|
evo/files/client.py
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
# See the License for the specific language governing permissions and
|
|
10
|
+
# limitations under the License.
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from pathlib import PurePosixPath
|
|
15
|
+
from uuid import UUID
|
|
16
|
+
|
|
17
|
+
from evo import logging
|
|
18
|
+
from evo.common import APIConnector, BaseAPIClient, Environment, HealthCheckType, Page, ServiceHealth, ServiceUser
|
|
19
|
+
from evo.common.utils import get_service_health
|
|
20
|
+
|
|
21
|
+
from .data import FileMetadata, FileVersion
|
|
22
|
+
from .endpoints import FileV2Api
|
|
23
|
+
from .endpoints.models import DownloadFileResponse, FileVersionResponse, ListFile, UserInfo
|
|
24
|
+
from .io import FileAPIDownload, FileAPIUpload
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger("file.client")
|
|
27
|
+
|
|
28
|
+
__all__ = ["FileAPIClient"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _user_from_model(model: UserInfo | None) -> ServiceUser | None:
|
|
32
|
+
"""Create a ServiceUser instance from a generated UserInfo model.
|
|
33
|
+
|
|
34
|
+
:param model: The model to create the ServiceUser instance from, or None.
|
|
35
|
+
|
|
36
|
+
:return: A ServiceUser instance, or None if the model is None.
|
|
37
|
+
"""
|
|
38
|
+
return None if model is None else ServiceUser(id=model.id, name=model.name, email=model.email)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _versions_from_listed_versions(models: list[FileVersionResponse]) -> list[FileVersion]:
|
|
42
|
+
"""Create a list of FileVersion instances from a list of generated FileVersionResponse models.
|
|
43
|
+
|
|
44
|
+
:param models: The models to create the FileVersion instances from.
|
|
45
|
+
|
|
46
|
+
:return: A sorted list of FileVersion instances.
|
|
47
|
+
"""
|
|
48
|
+
versions = (
|
|
49
|
+
FileVersion(
|
|
50
|
+
version_id=model.version_id,
|
|
51
|
+
created_at=model.created_at,
|
|
52
|
+
created_by=_user_from_model(model.created_by),
|
|
53
|
+
)
|
|
54
|
+
for model in models
|
|
55
|
+
)
|
|
56
|
+
return sorted(versions, key=lambda v: v.created_at, reverse=True)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class FileAPIClient(BaseAPIClient):
|
|
60
|
+
def __init__(self, environment: Environment, connector: APIConnector) -> None:
|
|
61
|
+
"""
|
|
62
|
+
:param environment: The environment object
|
|
63
|
+
:param connector: The connector object.
|
|
64
|
+
"""
|
|
65
|
+
super().__init__(environment, connector)
|
|
66
|
+
self._api = FileV2Api(connector=connector)
|
|
67
|
+
|
|
68
|
+
async def get_service_health(self, check_type: HealthCheckType = HealthCheckType.FULL) -> ServiceHealth:
|
|
69
|
+
"""Get the health of the file service.
|
|
70
|
+
|
|
71
|
+
:param check_type: The type of health check to perform.
|
|
72
|
+
|
|
73
|
+
:return: A ServiceHealth object.
|
|
74
|
+
|
|
75
|
+
:raises EvoAPIException: If the API returns an unexpected status code.
|
|
76
|
+
:raises ClientValueError: If the response is not a valid service health check response.
|
|
77
|
+
"""
|
|
78
|
+
return await get_service_health(self._connector, "file", check_type=check_type)
|
|
79
|
+
|
|
80
|
+
def _metadata_from_listed_file(self, model: ListFile) -> FileMetadata:
|
|
81
|
+
"""Create a FileMetadata instance from a generated ListFile model.
|
|
82
|
+
|
|
83
|
+
:param model: The model to create the FileMetadata instance from.
|
|
84
|
+
|
|
85
|
+
:return: A FileMetadata instance.
|
|
86
|
+
"""
|
|
87
|
+
return FileMetadata(
|
|
88
|
+
environment=self._environment,
|
|
89
|
+
id=model.file_id,
|
|
90
|
+
name=model.name,
|
|
91
|
+
created_at=model.created_at,
|
|
92
|
+
created_by=_user_from_model(model.created_by),
|
|
93
|
+
modified_at=model.modified_at,
|
|
94
|
+
modified_by=_user_from_model(model.modified_by),
|
|
95
|
+
parent=model.path,
|
|
96
|
+
version_id=model.version_id,
|
|
97
|
+
size=model.size,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def _metadata_from_endpoint_model(self, model: DownloadFileResponse) -> FileMetadata:
|
|
101
|
+
"""Create a FileMetadata instance from a generated DownloadFileResponse model.
|
|
102
|
+
|
|
103
|
+
:param model: The model to create the FileMetadata instance from.
|
|
104
|
+
|
|
105
|
+
:return: A FileMetadata instance.
|
|
106
|
+
"""
|
|
107
|
+
file_path = PurePosixPath(model.path)
|
|
108
|
+
return FileMetadata(
|
|
109
|
+
environment=self._environment,
|
|
110
|
+
id=model.file_id,
|
|
111
|
+
name=model.name,
|
|
112
|
+
created_at=model.created_at,
|
|
113
|
+
created_by=_user_from_model(model.created_by),
|
|
114
|
+
modified_at=model.modified_at,
|
|
115
|
+
modified_by=_user_from_model(model.modified_by),
|
|
116
|
+
parent=str(file_path.parent),
|
|
117
|
+
version_id=model.version_id,
|
|
118
|
+
size=model.size,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
async def list_files(
|
|
122
|
+
self,
|
|
123
|
+
offset: int = 0,
|
|
124
|
+
limit: int = 5000,
|
|
125
|
+
name: str | None = None,
|
|
126
|
+
) -> Page[FileMetadata]:
|
|
127
|
+
"""List up to `limit` files in the workspace, starting at `offset`.
|
|
128
|
+
|
|
129
|
+
The files will be the latest version of the file.
|
|
130
|
+
If there are no files starting at `offset`, the page will be empty.
|
|
131
|
+
|
|
132
|
+
:param offset: The number of files to skip before listing.
|
|
133
|
+
:param limit: Max number of files to list.
|
|
134
|
+
:param name: Filter files by name.
|
|
135
|
+
|
|
136
|
+
:return: A page of all files from the query.
|
|
137
|
+
"""
|
|
138
|
+
assert limit > 0, "Limit must be a positive integer"
|
|
139
|
+
assert offset >= 0, "Offset must be a non-negative integer"
|
|
140
|
+
response = await self._api.list_files(
|
|
141
|
+
organisation_id=str(self._environment.org_id),
|
|
142
|
+
workspace_id=str(self._environment.workspace_id),
|
|
143
|
+
limit=limit,
|
|
144
|
+
offset=offset,
|
|
145
|
+
file_name=name,
|
|
146
|
+
)
|
|
147
|
+
return Page(
|
|
148
|
+
offset=offset,
|
|
149
|
+
limit=limit,
|
|
150
|
+
total=response.total,
|
|
151
|
+
items=[self._metadata_from_listed_file(file) for file in response.files],
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
async def list_all_files(self, limit_per_request: int = 5000, name: str | None = None) -> list[FileMetadata]:
|
|
155
|
+
"""List all files in the workspace.
|
|
156
|
+
|
|
157
|
+
This method makes multiple calls to the `list_files` endpoint until all files have been listed.
|
|
158
|
+
|
|
159
|
+
:param limit_per_request: The maximum number of files to list in one request.
|
|
160
|
+
:param name: Filter files by name.
|
|
161
|
+
|
|
162
|
+
:return: A list of all files in the workspace.
|
|
163
|
+
"""
|
|
164
|
+
items = []
|
|
165
|
+
offset = 0
|
|
166
|
+
while True:
|
|
167
|
+
page = await self.list_files(offset=offset, limit=limit_per_request, name=name)
|
|
168
|
+
items += page.items()
|
|
169
|
+
if page.is_last:
|
|
170
|
+
break
|
|
171
|
+
offset = page.next_offset
|
|
172
|
+
return items
|
|
173
|
+
|
|
174
|
+
async def get_file_by_path(self, path: str, version_id: str | None = None) -> FileMetadata:
|
|
175
|
+
"""Get a file by its path.
|
|
176
|
+
|
|
177
|
+
:param path: The path to the file.
|
|
178
|
+
:param version_id: ID of the desired file version. By default, the response will return the latest version.
|
|
179
|
+
:return: A FileMetadata representation of the file on the service.
|
|
180
|
+
"""
|
|
181
|
+
file_response = await self._api.get_file_by_path(
|
|
182
|
+
organisation_id=str(self._environment.org_id),
|
|
183
|
+
workspace_id=str(self._environment.workspace_id),
|
|
184
|
+
file_path=path,
|
|
185
|
+
version_id=version_id,
|
|
186
|
+
)
|
|
187
|
+
return self._metadata_from_endpoint_model(file_response)
|
|
188
|
+
|
|
189
|
+
async def get_file_by_id(self, file_id: UUID, version_id: str | None = None) -> FileMetadata:
|
|
190
|
+
"""Get a file by its ID.
|
|
191
|
+
|
|
192
|
+
:param file_id: UUID of a file
|
|
193
|
+
:param version_id: ID of the desired file version. By default, the response will return the latest version.
|
|
194
|
+
:return: A FileMetadata representation of the file on the service
|
|
195
|
+
"""
|
|
196
|
+
file_response = await self._api.get_file_by_id(
|
|
197
|
+
organisation_id=str(self._environment.org_id),
|
|
198
|
+
workspace_id=str(self._environment.workspace_id),
|
|
199
|
+
file_id=str(file_id),
|
|
200
|
+
version_id=version_id,
|
|
201
|
+
)
|
|
202
|
+
return self._metadata_from_endpoint_model(file_response)
|
|
203
|
+
|
|
204
|
+
async def list_versions_by_path(self, path: str) -> list[FileVersion]:
|
|
205
|
+
"""List the versions of a file by path.
|
|
206
|
+
|
|
207
|
+
:param path: The path to the file.
|
|
208
|
+
:return: A sorted list of file versions. The latest version is the first element of the list.
|
|
209
|
+
"""
|
|
210
|
+
file_response = await self._api.get_file_by_path(
|
|
211
|
+
organisation_id=str(self._environment.org_id),
|
|
212
|
+
workspace_id=str(self._environment.workspace_id),
|
|
213
|
+
file_path=path,
|
|
214
|
+
include_versions=True,
|
|
215
|
+
)
|
|
216
|
+
return _versions_from_listed_versions(file_response.versions)
|
|
217
|
+
|
|
218
|
+
async def list_versions_by_id(self, file_id: UUID) -> list[FileVersion]:
|
|
219
|
+
"""List the versions of a file by ID
|
|
220
|
+
|
|
221
|
+
:param file_id: UUID of the file.
|
|
222
|
+
:return: A sorted list of file versions. The latest version is the first element of the list.
|
|
223
|
+
"""
|
|
224
|
+
file_response = await self._api.get_file_by_id(
|
|
225
|
+
organisation_id=str(self._environment.org_id),
|
|
226
|
+
workspace_id=str(self._environment.workspace_id),
|
|
227
|
+
file_id=str(file_id),
|
|
228
|
+
include_versions=True,
|
|
229
|
+
)
|
|
230
|
+
return _versions_from_listed_versions(file_response.versions)
|
|
231
|
+
|
|
232
|
+
async def prepare_download_by_path(self, path: str, version_id: str | None = None) -> FileAPIDownload:
|
|
233
|
+
"""Prepares a file for download by path.
|
|
234
|
+
|
|
235
|
+
:param path: Path to the file.
|
|
236
|
+
:param version_id: Versions of the file.
|
|
237
|
+
|
|
238
|
+
:return: A FileAPIDownload object.
|
|
239
|
+
"""
|
|
240
|
+
response = await self._api.get_file_by_path(
|
|
241
|
+
organisation_id=str(self._environment.org_id),
|
|
242
|
+
workspace_id=str(self._environment.workspace_id),
|
|
243
|
+
file_path=path,
|
|
244
|
+
version_id=version_id,
|
|
245
|
+
)
|
|
246
|
+
metadata = self._metadata_from_endpoint_model(response)
|
|
247
|
+
return FileAPIDownload(connector=self._connector, metadata=metadata, initial_url=response.download)
|
|
248
|
+
|
|
249
|
+
async def prepare_download_by_id(self, file_id: UUID, version_id: str | None = None) -> FileAPIDownload:
|
|
250
|
+
"""Prepares a file for download by ID.
|
|
251
|
+
|
|
252
|
+
:param file_id: UUID of the file.
|
|
253
|
+
:param version_id: Version of the file.
|
|
254
|
+
|
|
255
|
+
:return: A FileAPIDownload object.
|
|
256
|
+
"""
|
|
257
|
+
response = await self._api.get_file_by_id(
|
|
258
|
+
organisation_id=str(self._environment.org_id),
|
|
259
|
+
workspace_id=str(self._environment.workspace_id),
|
|
260
|
+
file_id=str(file_id),
|
|
261
|
+
version_id=version_id,
|
|
262
|
+
)
|
|
263
|
+
metadata = self._metadata_from_endpoint_model(response)
|
|
264
|
+
return FileAPIDownload(connector=self._connector, metadata=metadata, initial_url=response.download)
|
|
265
|
+
|
|
266
|
+
async def prepare_upload_by_path(self, path: str) -> FileAPIUpload:
|
|
267
|
+
"""Prepares a file for upload by path. If the file already exists, a new version will be created.
|
|
268
|
+
|
|
269
|
+
:param path: Path the file is being uploaded to.
|
|
270
|
+
|
|
271
|
+
:return: A FileAPIUpload object.
|
|
272
|
+
"""
|
|
273
|
+
response = await self._api.upsert_file_by_path(
|
|
274
|
+
organisation_id=str(self._environment.org_id),
|
|
275
|
+
workspace_id=str(self._environment.workspace_id),
|
|
276
|
+
file_path=path,
|
|
277
|
+
)
|
|
278
|
+
return FileAPIUpload(
|
|
279
|
+
connector=self._connector,
|
|
280
|
+
environment=self._environment,
|
|
281
|
+
file_id=response.file_id,
|
|
282
|
+
version_id=response.version_id,
|
|
283
|
+
initial_url=response.upload,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
async def prepare_upload_by_id(self, file_id: UUID) -> FileAPIUpload:
|
|
287
|
+
"""Prepares a file for upload by ID. The file_id must be the ID of an existing file, for which a new version
|
|
288
|
+
will be created.
|
|
289
|
+
|
|
290
|
+
:param file_id: UUID of the file.
|
|
291
|
+
|
|
292
|
+
:return: A FileAPIUpload object.
|
|
293
|
+
"""
|
|
294
|
+
response = await self._api.update_file_by_id(
|
|
295
|
+
organisation_id=str(self._environment.org_id),
|
|
296
|
+
workspace_id=str(self._environment.workspace_id),
|
|
297
|
+
file_id=str(file_id),
|
|
298
|
+
)
|
|
299
|
+
return FileAPIUpload(
|
|
300
|
+
connector=self._connector,
|
|
301
|
+
environment=self._environment,
|
|
302
|
+
file_id=file_id,
|
|
303
|
+
version_id=response.version_id,
|
|
304
|
+
initial_url=response.upload,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
async def delete_file_by_path(self, path: str) -> None:
|
|
308
|
+
"""Deletes a file by path.
|
|
309
|
+
|
|
310
|
+
:param path: Path of the file to delete.
|
|
311
|
+
"""
|
|
312
|
+
await self._api.delete_file_by_path(
|
|
313
|
+
organisation_id=str(self._environment.org_id),
|
|
314
|
+
workspace_id=str(self._environment.workspace_id),
|
|
315
|
+
file_path=path,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
async def delete_file_by_id(self, file_id: UUID) -> None:
|
|
319
|
+
"""Deletes a file by ID.
|
|
320
|
+
|
|
321
|
+
:param file_id: UUID of the file to delete.
|
|
322
|
+
"""
|
|
323
|
+
await self._api.delete_file_by_id(
|
|
324
|
+
organisation_id=str(self._environment.org_id),
|
|
325
|
+
workspace_id=str(self._environment.workspace_id),
|
|
326
|
+
file_id=str(file_id),
|
|
327
|
+
)
|
evo/files/data.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
# See the License for the specific language governing permissions and
|
|
10
|
+
# limitations under the License.
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"FileMetadata",
|
|
16
|
+
"FileVersion",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
|
|
22
|
+
from evo.common import ResourceMetadata, ServiceUser
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass(frozen=True, kw_only=True)
|
|
26
|
+
class FileMetadata(ResourceMetadata):
|
|
27
|
+
"""Metadata about a file in the File API."""
|
|
28
|
+
|
|
29
|
+
parent: str
|
|
30
|
+
"""The parent path of the file."""
|
|
31
|
+
|
|
32
|
+
version_id: str
|
|
33
|
+
"""An arbitrary identifier for the file version."""
|
|
34
|
+
|
|
35
|
+
size: int
|
|
36
|
+
"""The size of the file in bytes."""
|
|
37
|
+
|
|
38
|
+
modified_at: datetime
|
|
39
|
+
"""The resource's last modified timestamp."""
|
|
40
|
+
|
|
41
|
+
modified_by: ServiceUser | None = None
|
|
42
|
+
"""The user who last modified the resource."""
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def path(self) -> str:
|
|
46
|
+
"""The full path of the file, formed by joining the parent and name, separated by a slash ('/')."""
|
|
47
|
+
return f"{self.parent.removesuffix('/')}/{self.name.removeprefix('/')}"
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def url(self) -> str:
|
|
51
|
+
"""The URL of the file in the File API."""
|
|
52
|
+
return (
|
|
53
|
+
"{hub_url}/file/v2/orgs/{org_id}/workspaces/{workspace_id}/files/{file_id}?version_id={version_id}".format(
|
|
54
|
+
hub_url=self.environment.hub_url.rstrip("/"),
|
|
55
|
+
org_id=self.environment.org_id,
|
|
56
|
+
workspace_id=self.environment.workspace_id,
|
|
57
|
+
file_id=self.id,
|
|
58
|
+
version_id=self.version_id,
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(frozen=True, kw_only=True)
|
|
64
|
+
class FileVersion:
|
|
65
|
+
"""Represents a version of a file."""
|
|
66
|
+
|
|
67
|
+
version_id: str
|
|
68
|
+
"""An arbitrary identifier for the file version."""
|
|
69
|
+
|
|
70
|
+
created_at: datetime
|
|
71
|
+
"""The date and time when the file version was created."""
|
|
72
|
+
|
|
73
|
+
created_by: ServiceUser | None
|
|
74
|
+
"""The user who uploaded the file version."""
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
# See the License for the specific language governing permissions and
|
|
10
|
+
# limitations under the License.
|
|
11
|
+
"""
|
|
12
|
+
File API
|
|
13
|
+
=============
|
|
14
|
+
|
|
15
|
+
The File API provides the ability to manage files of any type or size, associated with
|
|
16
|
+
your Evo workspace. Enable your product with Evo connected workflows by integrating with the Seequent Evo
|
|
17
|
+
File API. Most file formats and sizes are accepted.
|
|
18
|
+
|
|
19
|
+
Files can be referenced by their UUID, or by a user-defined file path. Files are versioned, so updating or
|
|
20
|
+
replacing them will create a new version of the file. The latest version of the file is always returned
|
|
21
|
+
unless a specific version is requested.
|
|
22
|
+
|
|
23
|
+
For more information on using the File API, see [Overview](https://developer.seequent.com/docs/guides/file/), or the API references here.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
This code is generated from the OpenAPI specification for File API.
|
|
27
|
+
API version: 2.8.0
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# Import endpoint apis.
|
|
31
|
+
from .api import FileV2Api
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"FileV2Api",
|
|
35
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
# See the License for the specific language governing permissions and
|
|
10
|
+
# limitations under the License.
|
|
11
|
+
|
|
12
|
+
from .file_v2_api import FileV2Api # noqa: F401
|