geobox 2.0.1__py3-none-any.whl → 2.2.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.
Files changed (70) hide show
  1. geobox/__init__.py +61 -63
  2. geobox/aio/__init__.py +61 -63
  3. geobox/aio/api.py +489 -473
  4. geobox/aio/apikey.py +263 -263
  5. geobox/aio/attachment.py +341 -339
  6. geobox/aio/base.py +261 -262
  7. geobox/aio/basemap.py +196 -196
  8. geobox/aio/dashboard.py +340 -342
  9. geobox/aio/feature.py +23 -33
  10. geobox/aio/field.py +315 -321
  11. geobox/aio/file.py +72 -72
  12. geobox/aio/layout.py +340 -341
  13. geobox/aio/log.py +23 -23
  14. geobox/aio/map.py +1033 -1034
  15. geobox/aio/model3d.py +415 -415
  16. geobox/aio/mosaic.py +696 -696
  17. geobox/aio/plan.py +314 -314
  18. geobox/aio/query.py +693 -693
  19. geobox/aio/raster.py +907 -869
  20. geobox/aio/raster_analysis.py +740 -0
  21. geobox/aio/route.py +4 -4
  22. geobox/aio/scene.py +340 -342
  23. geobox/aio/settings.py +18 -18
  24. geobox/aio/task.py +404 -402
  25. geobox/aio/tile3d.py +337 -339
  26. geobox/aio/tileset.py +102 -103
  27. geobox/aio/usage.py +52 -51
  28. geobox/aio/user.py +506 -507
  29. geobox/aio/vector_tool.py +1968 -0
  30. geobox/aio/vectorlayer.py +315 -306
  31. geobox/aio/version.py +272 -273
  32. geobox/aio/view.py +1019 -983
  33. geobox/aio/workflow.py +340 -341
  34. geobox/api.py +18 -2
  35. geobox/apikey.py +262 -262
  36. geobox/attachment.py +336 -337
  37. geobox/base.py +384 -384
  38. geobox/basemap.py +194 -194
  39. geobox/dashboard.py +339 -341
  40. geobox/enums.py +432 -348
  41. geobox/feature.py +5 -5
  42. geobox/field.py +320 -320
  43. geobox/file.py +4 -4
  44. geobox/layout.py +339 -340
  45. geobox/log.py +4 -4
  46. geobox/map.py +1031 -1032
  47. geobox/model3d.py +410 -410
  48. geobox/mosaic.py +696 -696
  49. geobox/plan.py +313 -313
  50. geobox/query.py +691 -691
  51. geobox/raster.py +907 -863
  52. geobox/raster_analysis.py +737 -0
  53. geobox/scene.py +341 -342
  54. geobox/settings.py +194 -194
  55. geobox/task.py +399 -400
  56. geobox/tile3d.py +337 -338
  57. geobox/tileset.py +4 -4
  58. geobox/usage.py +3 -3
  59. geobox/user.py +503 -503
  60. geobox/vector_tool.py +1968 -0
  61. geobox/vectorlayer.py +5 -5
  62. geobox/version.py +272 -272
  63. geobox/view.py +981 -981
  64. geobox/workflow.py +338 -339
  65. {geobox-2.0.1.dist-info → geobox-2.2.0.dist-info}/METADATA +15 -1
  66. geobox-2.2.0.dist-info/RECORD +72 -0
  67. geobox-2.0.1.dist-info/RECORD +0 -68
  68. {geobox-2.0.1.dist-info → geobox-2.2.0.dist-info}/WHEEL +0 -0
  69. {geobox-2.0.1.dist-info → geobox-2.2.0.dist-info}/licenses/LICENSE +0 -0
  70. {geobox-2.0.1.dist-info → geobox-2.2.0.dist-info}/top_level.txt +0 -0
geobox/aio/attachment.py CHANGED
@@ -1,339 +1,341 @@
1
- from typing import List, Dict, Optional, TYPE_CHECKING, Union
2
- from urllib.parse import urljoin
3
-
4
- from .base import AsyncBase
5
- from .map import Map
6
- from .vectorlayer import VectorLayer
7
- from .view import VectorLayerView
8
- from .file import File
9
- from ..utils import clean_data
10
-
11
- if TYPE_CHECKING:
12
- from . import AsyncGeoboxClient
13
- from .feature import Feature
14
- from ..api import GeoboxClient as SyncGeoboxClient
15
- from ..attachment import Attachment as SyncAtachment
16
-
17
-
18
- class Attachment(AsyncBase):
19
-
20
- BASE_ENDPOINT = 'attachments/'
21
-
22
- def __init__(self,
23
- api: 'AsyncGeoboxClient',
24
- attachment_id: str,
25
- data: Optional[Dict] = {}):
26
- """
27
- Initialize an Attachment instance.
28
-
29
- Args:
30
- api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
31
- attachment_id (str): The id for the attachment.
32
- data (Dict, optional): The data of the attachment.
33
- """
34
- super().__init__(api, data=data)
35
- self.attachment_id = attachment_id
36
- self.endpoint = f"{self.BASE_ENDPOINT}{str(self.attachment_id)}/"
37
-
38
-
39
- def __repr__(self) -> str:
40
- """
41
- Return a string representation of the attachment.
42
-
43
- Returns:
44
- str: The string representation of the attachment.
45
- """
46
- return f"Attachment(id={self.attachment_id}, name={self.name})"
47
-
48
-
49
- @property
50
- def file(self) -> 'File':
51
- """
52
- Attachment file property
53
-
54
- Returns:
55
- File: the file object
56
- """
57
- return File(self.api, self.data['file'].get('uuid'), self.data['file'])
58
-
59
-
60
- @classmethod
61
- async def get_attachments(cls, api: 'AsyncGeoboxClient', resource: Union['Map', 'VectorLayer', 'VectorLayerView'], **kwargs) -> Union[List['Attachment'], int]:
62
- """
63
- [async] Get list of attachments with optional filtering and pagination.
64
-
65
- Args:
66
- api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
67
- resource (Map | VectorLayer | VectorLayerView): options are: Map, Vector, View objects
68
-
69
- Keyword Args:
70
- element_id (str): the id of the element with attachment.
71
- search (str): search term for keyword-based searching among all textual fields.
72
- order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
73
- skip (int): Number of items to skip. default is 0.
74
- limit (int): Number of items to return. default is 10.
75
- return_count (bool): Whether to return total count. default is False.
76
-
77
- Returns:
78
- List[Attachment] | int: A list of attachments instances or the total number of attachments.
79
-
80
- Raises:
81
- TypeError: if the resource type is not supported
82
-
83
- Example:
84
- >>> from geobox.aio import AsyncGeoboxClient
85
- >>> from geobox.aio.attachment import Attachment
86
- >>> async with AsyncGeoboxClient() as client:
87
- >>> maps = await client.get_maps()
88
- >>> map = maps[0]
89
- >>> attachments = await Attachment.get_attachments(client, resource=map, q="name LIKE '%My attachment%'")
90
- or
91
- >>> attachments = await client.get_attachments(resource=map, q="name LIKE '%My attachment%'")
92
- """
93
- if type(resource) == VectorLayer:
94
- resource_type = 'vector'
95
-
96
- elif type(resource) == VectorLayerView:
97
- resource_type = 'view'
98
-
99
- elif type(resource) == Map:
100
- resource_type = 'map'
101
-
102
- else:
103
- raise TypeError('resource must be a vectorlayer or view or map object')
104
-
105
-
106
- params = {
107
- 'resource_type': resource_type,
108
- 'resource_uuid': resource.uuid,
109
- 'element_id': kwargs.get('element_id'),
110
- 'search': kwargs.get('search'),
111
- 'order_by': kwargs.get('order_by'),
112
- 'skip': kwargs.get('skip', 0),
113
- 'limit': kwargs.get('limit', 10),
114
- 'return_count': kwargs.get('return_count')
115
- }
116
- return await super()._get_list(api, cls.BASE_ENDPOINT, params, factory_func=lambda api, item: Attachment(api, item['id'], item))
117
-
118
-
119
- @classmethod
120
- async def create_attachment(cls,
121
- api: 'AsyncGeoboxClient',
122
- name: str,
123
- loc_x: int,
124
- loc_y: int,
125
- resource: Union['Map', 'VectorLayer', 'VectorLayerView'],
126
- file: 'File',
127
- feature: 'Feature' = None,
128
- display_name: str = None,
129
- description: str = None, ) -> 'Attachment':
130
- """
131
- [async] Create a new Attachment.
132
-
133
- Args:
134
- api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
135
- name (str): The name of the scene.
136
- loc_x (int): x parameter of the attachment location.
137
- loc_y (int): y parameter of the attachment location.
138
- resource (Map | VectorLayer | VectorLayerView): the resource object.
139
- file (File): the file object.
140
- feature (Feature, optional): the feature object.
141
- display_name (str, optional): The display name of the scene.
142
- description (str, optional): The description of the scene.
143
-
144
- Returns:
145
- Attachment: The newly created Attachment instance.
146
-
147
- Raises:
148
- ValidationError: If the Attachment data is invalid.
149
-
150
- Example:
151
- >>> from geobox.aio import AsyncGeoboxClient
152
- >>> from geobox.aio.attachment import Attachment
153
- >>> async with AsyncGeoboxClient() as client:
154
- >>> layer = await client.get_vector(uuid="12345678-1234-5678-1234-567812345678")
155
- >>> feature = await layer.get_feature(feature_id=1)
156
- >>> file = await client.get_file(uuid="12345678-1234-5678-1234-567812345678")
157
- >>> attachment = await Attachment.create_attachment(client,
158
- ... name="my_attachment",
159
- ... loc_x=30,
160
- ... loc_y=50,
161
- ... resource=layer,
162
- ... file=file,
163
- ... feature=feature,
164
- ... display_name="My Attachment",
165
- ... description="Attachment Description")
166
- or
167
- >>> attachment = await client.create_attachment(name="my_attachment",
168
- ... loc_x=30,
169
- ... loc_y=50,
170
- ... resource=layer,
171
- ... file=file,
172
- ... feature=feature,
173
- ... display_name="My Attachment",
174
- ... description="Attachment Description")
175
- """
176
- if isinstance(resource, VectorLayer):
177
- resource_type = 'vector'
178
-
179
- if isinstance(resource, VectorLayerView):
180
- resource_type = 'view'
181
-
182
- if isinstance(resource, Map):
183
- resource_type = 'map'
184
-
185
- data = {
186
- "name": name,
187
- "display_name": display_name,
188
- "description": description,
189
- "loc_x": loc_x,
190
- "loc_y": loc_y,
191
- "resource_type": resource_type,
192
- "resource_uuid": resource.uuid,
193
- "element_id": feature.id if feature else None,
194
- "file_id": file.id
195
- }
196
- return await super()._create(api, cls.BASE_ENDPOINT, data, factory_func=lambda api, item: Attachment(api, item['id'], item))
197
-
198
-
199
- @classmethod
200
- async def update_attachment(cls, api: 'AsyncGeoboxClient', attachment_id: int, **kwargs) -> Dict:
201
- """
202
- [async] Update the attachment.
203
-
204
- Args:
205
- api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
206
- attachment_id (int): the attachment id.
207
-
208
- Keyword Args:
209
- name (str): The name of the attachment.
210
- display_name (str): The display name of the attachment.
211
- description (str): The description of the attachment.
212
- loc_x (int): x parameter of the attachment location.
213
- loc_y (int): y parameter of the attachment location.
214
-
215
- Returns:
216
- Dict: The updated attachment data.
217
-
218
- Raises:
219
- ValidationError: If the attachment data is invalid.
220
-
221
- Example:
222
- >>> from geobox.aio import AsyncGeoboxClient
223
- >>> from geobox.aio.attachment import Attachment
224
- >>> async with AsyncGeoboxClient() as client:
225
- >>> await Attachment.update_attachment(client, attachment_id=1, display_name="New Display Name")
226
- or
227
- >>> await client.update_attachment(attachment_id=1, display_name="New Display Name")
228
- """
229
- data = clean_data({
230
- "name": kwargs.get('name'),
231
- "display_name": kwargs.get('display_name'),
232
- "description": kwargs.get('description'),
233
- "loc_x": kwargs.get('loc_x'),
234
- "loc_y": kwargs.get('loc_y')
235
- })
236
- endpoint = urljoin(cls.BASE_ENDPOINT, str(attachment_id))
237
- response = await api.put(endpoint, data)
238
- return response
239
-
240
-
241
- async def update(self, **kwargs) -> Dict:
242
- """
243
- [async] Update the attachment.
244
-
245
- Keyword Args:
246
- name (str): The name of the attachment.
247
- display_name (str): The display name of the attachment.
248
- description (str): The description of the attachment.
249
- loc_x (int): x parameter of the attachment location.
250
- loc_y (int): y parameter of the attachment location.
251
-
252
- Returns:
253
- Dict: The updated attachment data.
254
-
255
- Raises:
256
- ValidationError: If the attachment data is invalid.
257
-
258
- Example:
259
- >>> from geobox.aio import AsyncGeoboxClient
260
- >>> from geobox.aio.attachment import Attachment
261
- >>> async with AsyncGeoboxClient() as client:
262
- >>> attachment = await Attachment.get_attachments(client)[0]
263
- >>> await attachment.update(display_name="New Display Name")
264
- """
265
- data = clean_data({
266
- "name": kwargs.get('name'),
267
- "display_name": kwargs.get('display_name'),
268
- "description": kwargs.get('description'),
269
- "loc_x": kwargs.get('loc_x'),
270
- "loc_y": kwargs.get('loc_y')
271
- })
272
- response = await self.api.put(self.endpoint, data)
273
- self._update_properties(response)
274
- return response
275
-
276
-
277
- async def delete(self) -> None:
278
- """
279
- [async] Delete the scene.
280
-
281
- Returns:
282
- None
283
-
284
- Raises:
285
- ApiRequestError: If the API request fails.
286
- ValidationError: If the scene data is invalid.
287
-
288
- Example:
289
- >>> from geobox.aio import AsyncGeoboxClient
290
- >>> from geobox.aio.attachment import Attachment
291
- >>> async with AsyncGeoboxClient() as client:
292
- >>> attachment = await Attachment.get_attachments(client)[0]
293
- >>> await attachment.delete()
294
- """
295
- await super().delete(self.endpoint)
296
- self.attachment_id = None
297
-
298
-
299
- @property
300
- def thumbnail(self) -> str:
301
- """
302
- Get the thumbnail URL of the attachment.
303
-
304
- Returns:
305
- str: The thumbnail of the scene.
306
-
307
- Example:
308
- >>> from geobox.aio import AsyncGeoboxClient
309
- >>> from geobox.aio.attachment import Attachment
310
- >>> async with AsyncGeoboxClient() as client:
311
- >>> attachment = await Attachment.get_attachment(client, uuid="12345678-1234-5678-1234-567812345678")
312
- >>> attachment.thumbnail
313
- 'https://example.com/thumbnail.png'
314
- """
315
- return super().thumbnail(format='')
316
-
317
-
318
- def to_sync(self, sync_client: 'SyncGeoboxClient') -> 'SyncAtachment':
319
- """
320
- Switch to sync version of the attachment instance to have access to the sync methods
321
-
322
- Args:
323
- sync_client (SyncGeoboxClient): The sync version of the GeoboxClient instance for making requests.
324
-
325
- Returns:
326
- geobox.attachment.Atachment: the sync instance of the attachment.
327
-
328
- Example:
329
- >>> from geobox import Geoboxclient
330
- >>> from geobox.aio import AsyncGeoboxClient
331
- >>> from geobox.aio.attachment import Attachment
332
- >>> client = GeoboxClient()
333
- >>> async with AsyncGeoboxClient() as async_client:
334
- >>> attachment = await Attachment.get_attachment(async_client, uuid="12345678-1234-5678-1234-567812345678")
335
- >>> sync_attachment = attachment.to_sync(client)
336
- """
337
- from ..attachment import Attachment as SyncAttachment
338
-
339
- return SyncAttachment(api=sync_client, attachment_id=self.attachment_id, data=self.data)
1
+ from typing import List, Dict, Optional, TYPE_CHECKING, Union
2
+ from urllib.parse import urljoin
3
+
4
+ from .base import AsyncBase
5
+ from .map import AsyncMap
6
+ from .vectorlayer import AsyncVectorLayer
7
+ from .view import AsyncVectorLayerView
8
+ from .file import AsyncFile
9
+ from ..utils import clean_data
10
+
11
+ if TYPE_CHECKING:
12
+ from . import AsyncGeoboxClient
13
+ from .feature import Feature
14
+ from ..api import GeoboxClient
15
+ from ..attachment import Attachment
16
+
17
+
18
+ class AsyncAttachment(AsyncBase):
19
+
20
+ BASE_ENDPOINT = 'attachments/'
21
+
22
+ def __init__(self,
23
+ api: 'AsyncGeoboxClient',
24
+ attachment_id: str,
25
+ data: Optional[Dict] = {}):
26
+ """
27
+ Initialize an Attachment instance.
28
+
29
+ Args:
30
+ api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
31
+ attachment_id (str): The id for the attachment.
32
+ data (Dict, optional): The data of the attachment.
33
+ """
34
+ super().__init__(api, data=data)
35
+ self.attachment_id = attachment_id
36
+ self.endpoint = f"{self.BASE_ENDPOINT}{str(self.attachment_id)}/"
37
+
38
+
39
+ def __repr__(self) -> str:
40
+ """
41
+ Return a string representation of the attachment.
42
+
43
+ Returns:
44
+ str: The string representation of the attachment.
45
+ """
46
+ return f"AsyncAttachment(id={self.attachment_id}, name={self.name})"
47
+
48
+
49
+ @property
50
+ def file(self) -> 'AsyncFile':
51
+ """
52
+ Attachment file property
53
+
54
+ Returns:
55
+ File: the file object
56
+ """
57
+ return AsyncFile(self.api, self.data['file'].get('uuid'), self.data['file'])
58
+
59
+
60
+ @classmethod
61
+ async def get_attachments(cls,
62
+ api: 'AsyncGeoboxClient',
63
+ resource: Union['AsyncMap', 'AsyncVectorLayer', 'AsyncVectorLayerView'],
64
+ **kwargs) -> Union[List['AsyncAttachment'], int]:
65
+ """
66
+ [async] Get list of attachments with optional filtering and pagination.
67
+
68
+ Args:
69
+ api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
70
+ resource (AsyncMap | AsyncVectorLayer | AsyncVectorLayerView): options are: Map, Vector, View objects
71
+
72
+ Keyword Args:
73
+ element_id (str): the id of the element with attachment.
74
+ search (str): search term for keyword-based searching among all textual fields.
75
+ order_by (str): comma separated list of fields for sorting results [field1 A|D, field2 A|D, …]. e.g. name A, type D. NOTE: "A" denotes ascending order and "D" denotes descending order.
76
+ skip (int): Number of items to skip. default is 0.
77
+ limit (int): Number of items to return. default is 10.
78
+ return_count (bool): Whether to return total count. default is False.
79
+
80
+ Returns:
81
+ List[AsyncAttachment] | int: A list of attachments instances or the total number of attachments.
82
+
83
+ Raises:
84
+ TypeError: if the resource type is not supported
85
+
86
+ Example:
87
+ >>> from geobox.aio import AsyncGeoboxClient
88
+ >>> from geobox.aio.attachment import AsyncAttachment
89
+ >>> async with AsyncGeoboxClient() as client:
90
+ >>> maps = await client.get_maps()
91
+ >>> map = maps[0]
92
+ >>> attachments = await AsyncAttachment.get_attachments(client, resource=map, q="name LIKE '%My attachment%'")
93
+ or
94
+ >>> attachments = await client.get_attachments(resource=map, q="name LIKE '%My attachment%'")
95
+ """
96
+ if type(resource) == AsyncVectorLayer:
97
+ resource_type = 'vector'
98
+
99
+ elif type(resource) == AsyncVectorLayerView:
100
+ resource_type = 'view'
101
+
102
+ elif type(resource) == AsyncMap:
103
+ resource_type = 'map'
104
+
105
+ else:
106
+ raise TypeError('resource must be a vectorlayer or view or map object')
107
+
108
+
109
+ params = {
110
+ 'resource_type': resource_type,
111
+ 'resource_uuid': resource.uuid,
112
+ 'element_id': kwargs.get('element_id'),
113
+ 'search': kwargs.get('search'),
114
+ 'order_by': kwargs.get('order_by'),
115
+ 'skip': kwargs.get('skip', 0),
116
+ 'limit': kwargs.get('limit', 10),
117
+ 'return_count': kwargs.get('return_count')
118
+ }
119
+ return await super()._get_list(api, cls.BASE_ENDPOINT, params, factory_func=lambda api, item: AsyncAttachment(api, item['id'], item))
120
+
121
+
122
+ @classmethod
123
+ async def create_attachment(cls,
124
+ api: 'AsyncGeoboxClient',
125
+ name: str,
126
+ loc_x: int,
127
+ loc_y: int,
128
+ resource: Union['AsyncMap', 'AsyncVectorLayer', 'AsyncVectorLayerView'],
129
+ file: 'File',
130
+ feature: 'Feature' = None,
131
+ display_name: str = None,
132
+ description: str = None, ) -> 'AsyncAttachment':
133
+ """
134
+ [async] Create a new Attachment.
135
+
136
+ Args:
137
+ api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
138
+ name (str): The name of the scene.
139
+ loc_x (int): x parameter of the attachment location.
140
+ loc_y (int): y parameter of the attachment location.
141
+ resource (AsyncMap | AsyncVectorLayer | AsyncVectorLayerView): the resource object.
142
+ file (File): the file object.
143
+ feature (Feature, optional): the feature object.
144
+ display_name (str, optional): The display name of the scene.
145
+ description (str, optional): The description of the scene.
146
+
147
+ Returns:
148
+ AsyncAttachment: The newly created Attachment instance.
149
+
150
+ Raises:
151
+ ValidationError: If the Attachment data is invalid.
152
+
153
+ Example:
154
+ >>> from geobox.aio import AsyncGeoboxClient
155
+ >>> from geobox.aio.attachment import AsyncAttachment
156
+ >>> async with AsyncGeoboxClient() as client:
157
+ >>> layer = await client.get_vector(uuid="12345678-1234-5678-1234-567812345678")
158
+ >>> feature = await layer.get_feature(feature_id=1)
159
+ >>> file = await client.get_file(uuid="12345678-1234-5678-1234-567812345678")
160
+ >>> attachment = await AsyncAttachment.create_attachment(client,
161
+ ... name="my_attachment",
162
+ ... loc_x=30,
163
+ ... loc_y=50,
164
+ ... resource=layer,
165
+ ... file=file,
166
+ ... feature=feature,
167
+ ... display_name="My Attachment",
168
+ ... description="Attachment Description")
169
+ or
170
+ >>> attachment = await client.create_attachment(name="my_attachment",
171
+ ... loc_x=30,
172
+ ... loc_y=50,
173
+ ... resource=layer,
174
+ ... file=file,
175
+ ... feature=feature,
176
+ ... display_name="My Attachment",
177
+ ... description="Attachment Description")
178
+ """
179
+ if isinstance(resource, AsyncVectorLayer):
180
+ resource_type = 'vector'
181
+
182
+ if isinstance(resource, AsyncVectorLayerView):
183
+ resource_type = 'view'
184
+
185
+ if isinstance(resource, AsyncMap):
186
+ resource_type = 'map'
187
+
188
+ data = {
189
+ "name": name,
190
+ "display_name": display_name,
191
+ "description": description,
192
+ "loc_x": loc_x,
193
+ "loc_y": loc_y,
194
+ "resource_type": resource_type,
195
+ "resource_uuid": resource.uuid,
196
+ "element_id": feature.id if feature else None,
197
+ "file_id": file.id
198
+ }
199
+ return await super()._create(api, cls.BASE_ENDPOINT, data, factory_func=lambda api, item: AsyncAttachment(api, item['id'], item))
200
+
201
+
202
+ @classmethod
203
+ async def update_attachment(cls, api: 'AsyncGeoboxClient', attachment_id: int, **kwargs) -> Dict:
204
+ """
205
+ [async] Update the attachment.
206
+
207
+ Args:
208
+ api (AsyncGeoboxClient): The AsyncGeoboxClient instance for making requests.
209
+ attachment_id (int): the attachment id.
210
+
211
+ Keyword Args:
212
+ name (str): The name of the attachment.
213
+ display_name (str): The display name of the attachment.
214
+ description (str): The description of the attachment.
215
+ loc_x (int): x parameter of the attachment location.
216
+ loc_y (int): y parameter of the attachment location.
217
+
218
+ Returns:
219
+ Dict: The updated attachment data.
220
+
221
+ Raises:
222
+ ValidationError: If the attachment data is invalid.
223
+
224
+ Example:
225
+ >>> from geobox.aio import AsyncGeoboxClient
226
+ >>> from geobox.aio.attachment import AsyncAttachment
227
+ >>> async with AsyncGeoboxClient() as client:
228
+ >>> await AsyncAttachment.update_attachment(client, attachment_id=1, display_name="New Display Name")
229
+ or
230
+ >>> await client.update_attachment(attachment_id=1, display_name="New Display Name")
231
+ """
232
+ data = clean_data({
233
+ "name": kwargs.get('name'),
234
+ "display_name": kwargs.get('display_name'),
235
+ "description": kwargs.get('description'),
236
+ "loc_x": kwargs.get('loc_x'),
237
+ "loc_y": kwargs.get('loc_y')
238
+ })
239
+ endpoint = urljoin(cls.BASE_ENDPOINT, str(attachment_id))
240
+ response = await api.put(endpoint, data)
241
+ return response
242
+
243
+
244
+ async def update(self, **kwargs) -> Dict:
245
+ """
246
+ [async] Update the attachment.
247
+
248
+ Keyword Args:
249
+ name (str): The name of the attachment.
250
+ display_name (str): The display name of the attachment.
251
+ description (str): The description of the attachment.
252
+ loc_x (int): x parameter of the attachment location.
253
+ loc_y (int): y parameter of the attachment location.
254
+
255
+ Returns:
256
+ Dict: The updated attachment data.
257
+
258
+ Raises:
259
+ ValidationError: If the attachment data is invalid.
260
+
261
+ Example:
262
+ >>> from geobox.aio import AsyncGeoboxClient
263
+ >>> from geobox.aio.attachment import AsyncAttachment
264
+ >>> async with AsyncGeoboxClient() as client:
265
+ >>> attachment = await AsyncAttachment.get_attachments(client)[0]
266
+ >>> await attachment.update(display_name="New Display Name")
267
+ """
268
+ data = clean_data({
269
+ "name": kwargs.get('name'),
270
+ "display_name": kwargs.get('display_name'),
271
+ "description": kwargs.get('description'),
272
+ "loc_x": kwargs.get('loc_x'),
273
+ "loc_y": kwargs.get('loc_y')
274
+ })
275
+ response = await self.api.put(self.endpoint, data)
276
+ self._update_properties(response)
277
+ return response
278
+
279
+
280
+ async def delete(self) -> None:
281
+ """
282
+ [async] Delete the scene.
283
+
284
+ Returns:
285
+ None
286
+
287
+ Raises:
288
+ ApiRequestError: If the API request fails.
289
+ ValidationError: If the scene data is invalid.
290
+
291
+ Example:
292
+ >>> from geobox.aio import AsyncGeoboxClient
293
+ >>> from geobox.aio.attachment import AsyncAttachment
294
+ >>> async with AsyncGeoboxClient() as client:
295
+ >>> attachment = await AsyncAttachment.get_attachments(client)[0]
296
+ >>> await attachment.delete()
297
+ """
298
+ await super()._delete(self.endpoint)
299
+ self.attachment_id = None
300
+
301
+
302
+ @property
303
+ def thumbnail(self) -> str:
304
+ """
305
+ Get the thumbnail URL of the attachment.
306
+
307
+ Returns:
308
+ str: The thumbnail of the scene.
309
+
310
+ Example:
311
+ >>> from geobox.aio import AsyncGeoboxClient
312
+ >>> from geobox.aio.attachment import AsyncAttachment
313
+ >>> async with AsyncGeoboxClient() as client:
314
+ >>> attachment = await AsyncAttachment.get_attachment(client, uuid="12345678-1234-5678-1234-567812345678")
315
+ >>> attachment.thumbnail
316
+ """
317
+ return super()._thumbnail(format='')
318
+
319
+
320
+ def to_sync(self, sync_client: 'GeoboxClient') -> 'Attachment':
321
+ """
322
+ Switch to sync version of the attachment instance to have access to the sync methods
323
+
324
+ Args:
325
+ sync_client (GeoboxClient): The sync version of the GeoboxClient instance for making requests.
326
+
327
+ Returns:
328
+ Attachment: the sync instance of the attachment.
329
+
330
+ Example:
331
+ >>> from geobox import Geoboxclient
332
+ >>> from geobox.aio import AsyncGeoboxClient
333
+ >>> from geobox.aio.attachment import AsyncAttachment
334
+ >>> client = GeoboxClient()
335
+ >>> async with AsyncGeoboxClient() as async_client:
336
+ >>> attachment = await AsyncAttachment.get_attachment(async_client, uuid="12345678-1234-5678-1234-567812345678")
337
+ >>> sync_attachment = attachment.to_sync(client)
338
+ """
339
+ from ..attachment import Attachment
340
+
341
+ return Attachment(api=sync_client, attachment_id=self.attachment_id, data=self.data)