geobox 1.2.1__tar.gz → 1.2.2__tar.gz

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 (69) hide show
  1. {geobox-1.2.1 → geobox-1.2.2}/PKG-INFO +1 -1
  2. {geobox-1.2.1 → geobox-1.2.2}/geobox/file.py +50 -45
  3. {geobox-1.2.1 → geobox-1.2.2}/geobox.egg-info/PKG-INFO +1 -1
  4. {geobox-1.2.1 → geobox-1.2.2}/pyproject.toml +1 -1
  5. {geobox-1.2.1 → geobox-1.2.2}/tests/test_file.py +11 -3
  6. {geobox-1.2.1 → geobox-1.2.2}/LICENSE +0 -0
  7. {geobox-1.2.1 → geobox-1.2.2}/README.md +0 -0
  8. {geobox-1.2.1 → geobox-1.2.2}/geobox/__init__.py +0 -0
  9. {geobox-1.2.1 → geobox-1.2.2}/geobox/api.py +0 -0
  10. {geobox-1.2.1 → geobox-1.2.2}/geobox/apikey.py +0 -0
  11. {geobox-1.2.1 → geobox-1.2.2}/geobox/attachment.py +0 -0
  12. {geobox-1.2.1 → geobox-1.2.2}/geobox/base.py +0 -0
  13. {geobox-1.2.1 → geobox-1.2.2}/geobox/basemap.py +0 -0
  14. {geobox-1.2.1 → geobox-1.2.2}/geobox/dashboard.py +0 -0
  15. {geobox-1.2.1 → geobox-1.2.2}/geobox/enums.py +0 -0
  16. {geobox-1.2.1 → geobox-1.2.2}/geobox/exception.py +0 -0
  17. {geobox-1.2.1 → geobox-1.2.2}/geobox/feature.py +0 -0
  18. {geobox-1.2.1 → geobox-1.2.2}/geobox/field.py +0 -0
  19. {geobox-1.2.1 → geobox-1.2.2}/geobox/log.py +0 -0
  20. {geobox-1.2.1 → geobox-1.2.2}/geobox/map.py +0 -0
  21. {geobox-1.2.1 → geobox-1.2.2}/geobox/model3d.py +0 -0
  22. {geobox-1.2.1 → geobox-1.2.2}/geobox/mosaic.py +0 -0
  23. {geobox-1.2.1 → geobox-1.2.2}/geobox/plan.py +0 -0
  24. {geobox-1.2.1 → geobox-1.2.2}/geobox/query.py +0 -0
  25. {geobox-1.2.1 → geobox-1.2.2}/geobox/raster.py +0 -0
  26. {geobox-1.2.1 → geobox-1.2.2}/geobox/route.py +0 -0
  27. {geobox-1.2.1 → geobox-1.2.2}/geobox/scene.py +0 -0
  28. {geobox-1.2.1 → geobox-1.2.2}/geobox/settings.py +0 -0
  29. {geobox-1.2.1 → geobox-1.2.2}/geobox/task.py +0 -0
  30. {geobox-1.2.1 → geobox-1.2.2}/geobox/tile3d.py +0 -0
  31. {geobox-1.2.1 → geobox-1.2.2}/geobox/tileset.py +0 -0
  32. {geobox-1.2.1 → geobox-1.2.2}/geobox/usage.py +0 -0
  33. {geobox-1.2.1 → geobox-1.2.2}/geobox/user.py +0 -0
  34. {geobox-1.2.1 → geobox-1.2.2}/geobox/utils.py +0 -0
  35. {geobox-1.2.1 → geobox-1.2.2}/geobox/vectorlayer.py +0 -0
  36. {geobox-1.2.1 → geobox-1.2.2}/geobox/version.py +0 -0
  37. {geobox-1.2.1 → geobox-1.2.2}/geobox/view.py +0 -0
  38. {geobox-1.2.1 → geobox-1.2.2}/geobox/workflow.py +0 -0
  39. {geobox-1.2.1 → geobox-1.2.2}/geobox.egg-info/SOURCES.txt +0 -0
  40. {geobox-1.2.1 → geobox-1.2.2}/geobox.egg-info/dependency_links.txt +0 -0
  41. {geobox-1.2.1 → geobox-1.2.2}/geobox.egg-info/requires.txt +0 -0
  42. {geobox-1.2.1 → geobox-1.2.2}/geobox.egg-info/top_level.txt +0 -0
  43. {geobox-1.2.1 → geobox-1.2.2}/setup.cfg +0 -0
  44. {geobox-1.2.1 → geobox-1.2.2}/tests/test_api.py +0 -0
  45. {geobox-1.2.1 → geobox-1.2.2}/tests/test_apikey.py +0 -0
  46. {geobox-1.2.1 → geobox-1.2.2}/tests/test_attachment.py +0 -0
  47. {geobox-1.2.1 → geobox-1.2.2}/tests/test_basemap.py +0 -0
  48. {geobox-1.2.1 → geobox-1.2.2}/tests/test_dashboard.py +0 -0
  49. {geobox-1.2.1 → geobox-1.2.2}/tests/test_feature.py +0 -0
  50. {geobox-1.2.1 → geobox-1.2.2}/tests/test_field.py +0 -0
  51. {geobox-1.2.1 → geobox-1.2.2}/tests/test_log.py +0 -0
  52. {geobox-1.2.1 → geobox-1.2.2}/tests/test_map.py +0 -0
  53. {geobox-1.2.1 → geobox-1.2.2}/tests/test_model3d.py +0 -0
  54. {geobox-1.2.1 → geobox-1.2.2}/tests/test_mosaic.py +0 -0
  55. {geobox-1.2.1 → geobox-1.2.2}/tests/test_plan.py +0 -0
  56. {geobox-1.2.1 → geobox-1.2.2}/tests/test_query.py +0 -0
  57. {geobox-1.2.1 → geobox-1.2.2}/tests/test_raster.py +0 -0
  58. {geobox-1.2.1 → geobox-1.2.2}/tests/test_route.py +0 -0
  59. {geobox-1.2.1 → geobox-1.2.2}/tests/test_scene.py +0 -0
  60. {geobox-1.2.1 → geobox-1.2.2}/tests/test_settings.py +0 -0
  61. {geobox-1.2.1 → geobox-1.2.2}/tests/test_task.py +0 -0
  62. {geobox-1.2.1 → geobox-1.2.2}/tests/test_tile3d.py +0 -0
  63. {geobox-1.2.1 → geobox-1.2.2}/tests/test_tileset.py +0 -0
  64. {geobox-1.2.1 → geobox-1.2.2}/tests/test_usage.py +0 -0
  65. {geobox-1.2.1 → geobox-1.2.2}/tests/test_user.py +0 -0
  66. {geobox-1.2.1 → geobox-1.2.2}/tests/test_vectorlayer.py +0 -0
  67. {geobox-1.2.1 → geobox-1.2.2}/tests/test_version.py +0 -0
  68. {geobox-1.2.1 → geobox-1.2.2}/tests/test_view.py +0 -0
  69. {geobox-1.2.1 → geobox-1.2.2}/tests/test_workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geobox
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: SDK for Geobox's APIs
5
5
  Author-email: Hamid Heydari <heydari.h62@gmail.com>
6
6
  License: MIT
@@ -2,13 +2,16 @@ from urllib.parse import urljoin
2
2
  from typing import Optional, Dict, List, Union, TYPE_CHECKING
3
3
  import os
4
4
  import mimetypes
5
+ from geobox.exception import ValidationError
5
6
  import requests
6
7
  import sys
8
+ from pathlib import Path
7
9
 
8
10
  from .base import Base
9
11
  from .enums import FileFormat, PublishFileType, InputGeomType, FileType
10
12
  from .utils import clean_data
11
13
  from .task import Task
14
+ from .feature import Feature
12
15
 
13
16
  if TYPE_CHECKING:
14
17
  from . import GeoboxClient
@@ -221,9 +224,9 @@ class File(Base):
221
224
  >>> from geobox import GeoboxClient
222
225
  >>> from geobox.file import File
223
226
  >>> client = GeoboxClient()
224
- >>> files = File.get_file_by_name(client, name='test')
227
+ >>> files = File.get_files_by_name(client, name='test')
225
228
  or
226
- >>> files = client.get_file_by_name(name='test')
229
+ >>> files = client.get_files_by_name(name='test')
227
230
  """
228
231
  return cls.get_files(api, q=f"name = '{name}'", user_id=user_id)
229
232
 
@@ -248,44 +251,34 @@ class File(Base):
248
251
  >>> client = GeoboxClient()
249
252
  >>> file_path = File.get_file(client, uuid="12345678-1234-5678-1234-567812345678")
250
253
  """
251
- # Get the original filename from data or use uuid
252
- if self.name:
253
- filename = f"{self.name.split('.')[0]}" if len(self.name.split('.')) > 1 else f'{self.name}'
254
- else:
255
- filename = f'{self.uuid}'
256
-
257
254
  # If save_path is provided, check if it ends with a '/'
258
255
  if save_path and save_path.endswith('/'):
259
- return f'{save_path}{filename}'
256
+ return f'{save_path}'
260
257
 
261
258
  if save_path and not save_path.endswith('/'):
262
259
  raise ValueError("save_path must end with a '/'")
263
260
 
264
- return os.path.join(os.getcwd(), filename)
261
+ return os.getcwd()
265
262
 
266
263
 
267
- def _get_file_ext(self, response: requests.Response) -> str:
264
+ def _get_file_name(self, response: requests.Response) -> str:
268
265
  """
269
- Get the file extension of the response.
266
+ Get the file name from the response.
270
267
 
271
268
  Args:
272
269
  response (requests.Response): The response of the request.
273
270
 
274
271
  Returns:
275
- str: The file extension of the response.
272
+ str: The file name
276
273
  """
277
- ext = ""
278
- if 'Content-Disposition' in response.headers:
279
- content_disposition = response.headers['Content-Disposition']
280
- if 'filename=' in content_disposition:
281
- filename = content_disposition.split('filename=')[-1].strip().strip('"')
282
- ext = f".{filename.split('.')[-1]}"
274
+ if 'Content-Disposition' in response.headers and 'filename=' in response.headers['Content-Disposition']:
275
+ file_name = response.headers['Content-Disposition'].split('filename=')[-1].strip().strip('"')
283
276
 
284
- else:
285
- content_type = response.headers.get("Content-Type", "")
286
- ext = mimetypes.guess_extension(content_type.split(";")[0])
277
+ else:
278
+ content_type = response.headers.get("Content-Type", "")
279
+ file_name = f'{self.name}.{mimetypes.guess_extension(content_type.split(";")[0])}'
287
280
 
288
- return ext
281
+ return file_name
289
282
 
290
283
 
291
284
  def _create_progress_bar(self) -> 'tqdm':
@@ -338,20 +331,20 @@ class File(Base):
338
331
  save_path = self._get_save_path(save_path)
339
332
  os.makedirs(os.path.dirname(save_path), exist_ok=True)
340
333
 
341
- with self.api.get(f"{self.endpoint}download/", stream=True) as response, \
342
- open(save_path, 'wb') as f:
343
- pbar = self._create_progress_bar() if progress_bar else None
344
- for chunk in response.iter_content(chunk_size=8192):
345
- f.write(chunk)
334
+ with self.api.get(f"{self.endpoint}download/", stream=True) as response:
335
+ file_name = self._get_file_name(response)
336
+ full_path = f"{save_path}/{file_name}"
337
+ with open(full_path, 'wb') as f:
338
+ pbar = self._create_progress_bar() if progress_bar else None
339
+ for chunk in response.iter_content(chunk_size=8192):
340
+ f.write(chunk)
341
+ if pbar:
342
+ pbar.update(len(chunk))
343
+ pbar.refresh()
346
344
  if pbar:
347
- pbar.update(len(chunk))
348
- pbar.refresh()
349
- if pbar:
350
- pbar.close()
345
+ pbar.close()
351
346
 
352
- final_path = os.path.abspath(save_path) + self._get_file_ext(response)
353
- os.rename(os.path.abspath(save_path), os.path.abspath(final_path))
354
- return os.path.abspath(final_path)
347
+ return os.path.abspath(full_path)
355
348
 
356
349
 
357
350
  def delete(self) -> None:
@@ -378,8 +371,8 @@ class File(Base):
378
371
  input_layer: str = None,
379
372
  input_dataset: str = None,
380
373
  user_id: int = None,
381
- input_srid: int = None,
382
- file_encoding: str = "utf-8",
374
+ input_srid: int = Feature.BASE_SRID,
375
+ file_encoding: str = "UTF-8",
383
376
  replace_domain_codes_by_values: bool = False,
384
377
  report_errors: bool = True,
385
378
  as_terrain: bool = False) -> 'Task':
@@ -393,7 +386,7 @@ class File(Base):
393
386
  input_layer (str, optional): The name of the input layer.
394
387
  input_dataset (str, optional): The name of the input dataset.
395
388
  user_id (int, optional): Specific user. privileges required.
396
- input_srid (int, optional): The SRID of the layer.
389
+ input_srid (int, optional): The SRID of the layer. default is: 3857
397
390
  file_encoding (str, optional): The encoding of the file. default is "utf-8".
398
391
  replace_domain_codes_by_values (bool, optional): Whether to replace domain codes by values. default is False.
399
392
  report_errors (bool, optional): Whether to report errors. default is True.
@@ -404,6 +397,7 @@ class File(Base):
404
397
 
405
398
  Raises:
406
399
  ValueError: If the publish_as is not a valid PublishFileType.
400
+ ValidationError: if the zipped file doesn't have any layers to publish.
407
401
 
408
402
  Example:
409
403
  >>> from geobox import GeoboxClient
@@ -416,30 +410,41 @@ class File(Base):
416
410
  ... input_layer='layer1',
417
411
  ... input_dataset='dataset1',
418
412
  ... input_srid=4326,
419
- ... file_encoding='utf-8')
413
+ ... file_encoding='UTF-8')
420
414
  """
421
415
  if not publish_as:
422
- if self.file_type.value in ['GeoJSON', 'GPKG', 'DXF', 'GPX', 'Shapefile', 'KML', 'CSV', 'FileGDB']:
416
+ # checks the file format or file first layer format to dynamically set the publish_as
417
+ if self.file_type.value in ['GeoJSON', 'GPKG', 'DXF', 'GPX', 'Shapefile', 'KML', 'CSV', 'FileGDB'] or \
418
+ (self.file_type.value in ['Complex'] and self.layers and \
419
+ FileType(self.layers[0]['format']).value in ['GeoJSON', 'GPKG', 'DXF', 'GPX', 'Shapefile', 'KML', 'CSV', 'FileGDB']):
423
420
  publish_as = PublishFileType.VECTOR
424
- elif self.file_type.value in ['GeoTIFF']:
421
+
422
+ elif self.file_type.value in ['GeoTIFF'] or \
423
+ (self.file_type.value in ['Complex'] and self.layers and \
424
+ FileType(self.layers[0]['format']).value in ['GeoTIFF']):
425
425
  publish_as = PublishFileType.RASTER
426
- elif self.file_type.value in ['GLB']:
426
+
427
+ elif self.file_type.value in ['GLB'] or \
428
+ (self.file_type.value in ['Complex'] and self.layers and \
429
+ FileType(self.layers[0]['format']).value in ['GLB']):
427
430
  publish_as = PublishFileType.MODEL3D
428
431
 
432
+ else:
433
+ raise ValidationError('Unknown format')
434
+
429
435
  data = clean_data({
430
436
  "publish_as": publish_as.value if isinstance(publish_as, PublishFileType) else publish_as,
431
437
  "layer_name": name,
432
- "input_layer": input_layer,
438
+ "input_layer": self.layers[0]['layer'] if not input_layer and self.layers else input_layer,
433
439
  "input_geom_type": input_geom_type.value if isinstance(input_geom_type, InputGeomType) else input_geom_type,
434
440
  "replace_domain_codes_by_values": replace_domain_codes_by_values,
435
- "input_dataset": self.name if not input_dataset else input_dataset,
441
+ "input_dataset": self.layers[0]['dataset'] if not input_layer and self.layers else input_dataset,
436
442
  "user_id": user_id,
437
443
  "input_srid": input_srid,
438
444
  "file_encoding": file_encoding,
439
445
  "report_errors": report_errors,
440
446
  "as_terrain": as_terrain
441
447
  })
442
-
443
448
  endpoint = urljoin(self.endpoint, 'publish/')
444
449
  response = self.api.post(endpoint, data, is_json=False)
445
450
  task = Task.get_task(self.api, response.get('task_id'))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geobox
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: SDK for Geobox's APIs
5
5
  Author-email: Hamid Heydari <heydari.h62@gmail.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "geobox"
7
- version = "1.2.1"
7
+ version = "1.2.2"
8
8
  description = "SDK for Geobox's APIs"
9
9
  authors = [
10
10
  {name = "Hamid Heydari", email = "heydari.h62@gmail.com"}
@@ -6,7 +6,7 @@ import tempfile
6
6
  import zipfile
7
7
  import shutil
8
8
 
9
- from geobox.file import File, FileType
9
+ from geobox.file import File, FileType, ValidationError
10
10
  from geobox.enums import PublishFileType, InputGeomType
11
11
  from geobox.task import Task
12
12
  from geobox.user import User
@@ -254,7 +254,7 @@ def test_download_no_filename_in_content_disposition(api, mock_file_data):
254
254
  # Verify the expected behavior
255
255
  assert result.endswith('.png')
256
256
  mock_makedirs.assert_called_once()
257
- mock_rename.assert_called_once()
257
+ # mock_rename.assert_called_once()
258
258
 
259
259
 
260
260
  def test_delete(api, mock_file_data):
@@ -268,9 +268,10 @@ def test_delete(api, mock_file_data):
268
268
  @pytest.mark.parametrize("file_type", [
269
269
  (type)
270
270
  for type in FileType
271
+ if type not in [FileType.Compressed, FileType.Complex, FileType.Video, FileType.Image, FileType.Document]
271
272
  ])
272
273
  def test_publish(api, mock_file_data, mock_success_task_data, file_type):
273
- """Test file publishing with all combinations of publish types and geometry types."""
274
+ """Test file publishing with all combinations of publish types"""
274
275
  mock_response = {
275
276
  'task_id': mock_success_task_data['id']
276
277
  }
@@ -285,6 +286,13 @@ def test_publish(api, mock_file_data, mock_success_task_data, file_type):
285
286
  # Verify the response
286
287
  assert isinstance(result, Task)
287
288
  assert result.id == mock_success_task_data['id']
289
+
290
+
291
+ def test_publish_unkown_format(api, mock_file_data):
292
+ """Test file publishing with unknown format"""
293
+ mock_file_data['file_type'] = FileType.Document
294
+ with pytest.raises(ValidationError):
295
+ File(api, uuid=mock_file_data['uuid'], data=mock_file_data).publish(name='test')
288
296
 
289
297
 
290
298
  def test_share(api, mock_file_data, mock_user_data):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes