geobox 1.3.1__tar.gz → 1.3.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.3.1 → geobox-1.3.2}/PKG-INFO +1 -1
  2. {geobox-1.3.1 → geobox-1.3.2}/geobox/query.py +1 -1
  3. {geobox-1.3.1 → geobox-1.3.2}/geobox/raster.py +8 -2
  4. {geobox-1.3.1 → geobox-1.3.2}/geobox/user.py +4 -7
  5. {geobox-1.3.1 → geobox-1.3.2}/geobox/utils.py +7 -0
  6. {geobox-1.3.1 → geobox-1.3.2}/geobox/vectorlayer.py +30 -0
  7. {geobox-1.3.1 → geobox-1.3.2}/geobox.egg-info/PKG-INFO +1 -1
  8. {geobox-1.3.1 → geobox-1.3.2}/pyproject.toml +1 -1
  9. {geobox-1.3.1 → geobox-1.3.2}/tests/test_user.py +4 -3
  10. {geobox-1.3.1 → geobox-1.3.2}/tests/test_vectorlayer.py +11 -0
  11. {geobox-1.3.1 → geobox-1.3.2}/LICENSE +0 -0
  12. {geobox-1.3.1 → geobox-1.3.2}/README.md +0 -0
  13. {geobox-1.3.1 → geobox-1.3.2}/geobox/__init__.py +0 -0
  14. {geobox-1.3.1 → geobox-1.3.2}/geobox/api.py +0 -0
  15. {geobox-1.3.1 → geobox-1.3.2}/geobox/apikey.py +0 -0
  16. {geobox-1.3.1 → geobox-1.3.2}/geobox/attachment.py +0 -0
  17. {geobox-1.3.1 → geobox-1.3.2}/geobox/base.py +0 -0
  18. {geobox-1.3.1 → geobox-1.3.2}/geobox/basemap.py +0 -0
  19. {geobox-1.3.1 → geobox-1.3.2}/geobox/dashboard.py +0 -0
  20. {geobox-1.3.1 → geobox-1.3.2}/geobox/enums.py +0 -0
  21. {geobox-1.3.1 → geobox-1.3.2}/geobox/exception.py +0 -0
  22. {geobox-1.3.1 → geobox-1.3.2}/geobox/feature.py +0 -0
  23. {geobox-1.3.1 → geobox-1.3.2}/geobox/field.py +0 -0
  24. {geobox-1.3.1 → geobox-1.3.2}/geobox/file.py +0 -0
  25. {geobox-1.3.1 → geobox-1.3.2}/geobox/log.py +0 -0
  26. {geobox-1.3.1 → geobox-1.3.2}/geobox/map.py +0 -0
  27. {geobox-1.3.1 → geobox-1.3.2}/geobox/model3d.py +0 -0
  28. {geobox-1.3.1 → geobox-1.3.2}/geobox/mosaic.py +0 -0
  29. {geobox-1.3.1 → geobox-1.3.2}/geobox/plan.py +0 -0
  30. {geobox-1.3.1 → geobox-1.3.2}/geobox/route.py +0 -0
  31. {geobox-1.3.1 → geobox-1.3.2}/geobox/scene.py +0 -0
  32. {geobox-1.3.1 → geobox-1.3.2}/geobox/settings.py +0 -0
  33. {geobox-1.3.1 → geobox-1.3.2}/geobox/task.py +0 -0
  34. {geobox-1.3.1 → geobox-1.3.2}/geobox/tile3d.py +0 -0
  35. {geobox-1.3.1 → geobox-1.3.2}/geobox/tileset.py +0 -0
  36. {geobox-1.3.1 → geobox-1.3.2}/geobox/usage.py +0 -0
  37. {geobox-1.3.1 → geobox-1.3.2}/geobox/version.py +0 -0
  38. {geobox-1.3.1 → geobox-1.3.2}/geobox/view.py +0 -0
  39. {geobox-1.3.1 → geobox-1.3.2}/geobox/workflow.py +0 -0
  40. {geobox-1.3.1 → geobox-1.3.2}/geobox.egg-info/SOURCES.txt +0 -0
  41. {geobox-1.3.1 → geobox-1.3.2}/geobox.egg-info/dependency_links.txt +0 -0
  42. {geobox-1.3.1 → geobox-1.3.2}/geobox.egg-info/requires.txt +0 -0
  43. {geobox-1.3.1 → geobox-1.3.2}/geobox.egg-info/top_level.txt +0 -0
  44. {geobox-1.3.1 → geobox-1.3.2}/setup.cfg +0 -0
  45. {geobox-1.3.1 → geobox-1.3.2}/tests/test_api.py +0 -0
  46. {geobox-1.3.1 → geobox-1.3.2}/tests/test_apikey.py +0 -0
  47. {geobox-1.3.1 → geobox-1.3.2}/tests/test_attachment.py +0 -0
  48. {geobox-1.3.1 → geobox-1.3.2}/tests/test_basemap.py +0 -0
  49. {geobox-1.3.1 → geobox-1.3.2}/tests/test_dashboard.py +0 -0
  50. {geobox-1.3.1 → geobox-1.3.2}/tests/test_feature.py +0 -0
  51. {geobox-1.3.1 → geobox-1.3.2}/tests/test_field.py +0 -0
  52. {geobox-1.3.1 → geobox-1.3.2}/tests/test_file.py +0 -0
  53. {geobox-1.3.1 → geobox-1.3.2}/tests/test_log.py +0 -0
  54. {geobox-1.3.1 → geobox-1.3.2}/tests/test_map.py +0 -0
  55. {geobox-1.3.1 → geobox-1.3.2}/tests/test_model3d.py +0 -0
  56. {geobox-1.3.1 → geobox-1.3.2}/tests/test_mosaic.py +0 -0
  57. {geobox-1.3.1 → geobox-1.3.2}/tests/test_plan.py +0 -0
  58. {geobox-1.3.1 → geobox-1.3.2}/tests/test_query.py +0 -0
  59. {geobox-1.3.1 → geobox-1.3.2}/tests/test_raster.py +0 -0
  60. {geobox-1.3.1 → geobox-1.3.2}/tests/test_route.py +0 -0
  61. {geobox-1.3.1 → geobox-1.3.2}/tests/test_scene.py +0 -0
  62. {geobox-1.3.1 → geobox-1.3.2}/tests/test_settings.py +0 -0
  63. {geobox-1.3.1 → geobox-1.3.2}/tests/test_task.py +0 -0
  64. {geobox-1.3.1 → geobox-1.3.2}/tests/test_tile3d.py +0 -0
  65. {geobox-1.3.1 → geobox-1.3.2}/tests/test_tileset.py +0 -0
  66. {geobox-1.3.1 → geobox-1.3.2}/tests/test_usage.py +0 -0
  67. {geobox-1.3.1 → geobox-1.3.2}/tests/test_version.py +0 -0
  68. {geobox-1.3.1 → geobox-1.3.2}/tests/test_view.py +0 -0
  69. {geobox-1.3.1 → geobox-1.3.2}/tests/test_workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geobox
3
- Version: 1.3.1
3
+ Version: 1.3.2
4
4
  Summary: SDK for Geobox's APIs
5
5
  Author-email: Hamid Heydari <heydari.h62@gmail.com>
6
6
  License: MIT
@@ -582,7 +582,7 @@ class Query(Base):
582
582
  super()._unshare(self.endpoint, users)
583
583
 
584
584
 
585
- def get_shared_users(self, search: str, skip: int = 0, limit: int = 10) -> List['User']:
585
+ def get_shared_users(self, search: str = None, skip: int = 0, limit: int = 10) -> List['User']:
586
586
  """
587
587
  Retrieves the list of users the query is shared with.
588
588
 
@@ -510,13 +510,13 @@ class Raster(Base):
510
510
  'colormap_name': kwargs.get('colormap_name'),
511
511
  'colormap': kwargs.get('colormap')
512
512
  })
513
- query_string = urlencode(clean_data(params))
513
+ query_string = urlencode(params)
514
514
  endpoint = urljoin(self.api.base_url, f'{self.endpoint}render/{z}/{x}/{y}.png')
515
515
  endpoint = urljoin(endpoint, f'?{query_string}')
516
516
  return endpoint
517
517
 
518
518
 
519
- def get_tile_pbf_url(self, x: int, y: int, z: int) -> str:
519
+ def get_tile_pbf_url(self, x: int, y: int, z: int, indexes: str = None) -> str:
520
520
  """
521
521
  Get the URL of the tile.
522
522
 
@@ -524,6 +524,7 @@ class Raster(Base):
524
524
  x (int): The x coordinate of the tile.
525
525
  y (int): The y coordinate of the tile.
526
526
  z (int): The zoom level of the tile.
527
+ indexes (str, optional): list of comma separated band indexes to be rendered. e.g. 1, 2, 3
527
528
 
528
529
  Returns:
529
530
  str: The URL of the tile.
@@ -535,7 +536,12 @@ class Raster(Base):
535
536
  >>> raster = Raster.get_raster(client, uuid="12345678-1234-5678-1234-567812345678")
536
537
  >>> raster.get_tile_pbf_url(x=10, y=20, z=1)
537
538
  """
539
+ params = clean_data({
540
+ 'indexes': indexes
541
+ })
542
+ query_string = urlencode(params)
538
543
  endpoint = urljoin(self.api.base_url, f'{self.endpoint}tiles/{z}/{x}/{y}.pbf')
544
+ endpoint = urljoin(endpoint, f'?{query_string}')
539
545
  return endpoint
540
546
 
541
547
 
@@ -2,7 +2,7 @@ from typing import List, Any, TYPE_CHECKING, Union, Dict
2
2
  from urllib.parse import urlencode, urljoin
3
3
 
4
4
  from .base import Base
5
- from .utils import clean_data
5
+ from .utils import clean_data, xor_encode
6
6
  from .enums import UserRole, UserStatus
7
7
  from .plan import Plan
8
8
 
@@ -113,11 +113,9 @@ class User(Base):
113
113
  'return_count': kwargs.get('return_count', False),
114
114
  'skip': kwargs.get('skip', 0),
115
115
  'limit': kwargs.get('limit', 10),
116
- 'user_id': kwargs.get('user_id'),
117
- 'shared': kwargs.get('shared', False)
116
+ 'user_id': kwargs.get('user_id')
118
117
  }
119
118
  return super()._get_list(api, cls.BASE_ENDPOINT, params, factory_func=lambda api, item: User(api, item['id'], item))
120
-
121
119
 
122
120
 
123
121
  @classmethod
@@ -174,7 +172,7 @@ class User(Base):
174
172
  data = {
175
173
  "username": username,
176
174
  "email": email,
177
- "password": password,
175
+ "password": xor_encode(password),
178
176
  "role": role.value,
179
177
  "first_name": first_name,
180
178
  "last_name": last_name,
@@ -184,7 +182,6 @@ class User(Base):
184
182
  return super()._create(api, cls.BASE_ENDPOINT, data, factory_func=lambda api, item: User(api, item['id'], item))
185
183
 
186
184
 
187
-
188
185
  @classmethod
189
186
  def search_users(cls, api: 'GeoboxClient', search: str = None, skip: int = 0, limit: int = 10) -> List['User']:
190
187
  """
@@ -377,7 +374,7 @@ class User(Base):
377
374
  >>> user.change_password(new_password='user_new_password')
378
375
  """
379
376
  data = clean_data({
380
- "new_password": new_password
377
+ "new_password": xor_encode(new_password)
381
378
  })
382
379
  endpoint = urljoin(self.endpoint, 'change-password')
383
380
  self.api.post(endpoint, data, is_json=False)
@@ -1,4 +1,11 @@
1
1
  from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
2
+ import base64
3
+
4
+
5
+ def xor_encode(s, key=42):
6
+ xor_str = ''.join(chr(ord(c) ^ key) for c in s)
7
+ encoded_bytes = base64.b64encode(xor_str.encode('utf-8'))
8
+ return encoded_bytes.decode('utf-8')
2
9
 
3
10
 
4
11
  def clean_data(data: dict) -> dict:
@@ -439,6 +439,36 @@ class VectorLayer(Base):
439
439
  return super()._create(self.api, endpoint, data, factory_func=lambda api, item: VectorLayerVersion(api, item['uuid'], item))
440
440
 
441
441
 
442
+ def get_versions(self, **kwargs) -> List['VectorLayerVersion']:
443
+ """
444
+ Get list of versions of the current vector layer object with optional filtering and pagination.
445
+
446
+ Keyword Args:
447
+ q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'"
448
+ search (str): search term for keyword-based searching among search_fields or all textual fields if search_fields does not have value. NOTE: if q param is defined this param will be ignored.
449
+ search_fields (str): comma separated list of fields for searching.
450
+ 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.
451
+ return_count (bool): Whether to return total count. default is False.
452
+ skip (int): Number of items to skip. default is 0.
453
+ limit (int): Number of items to return. default is 10.
454
+ user_id (int): Specific user. privileges required.
455
+ shared (bool): Whether to return shared versions. default is False.
456
+
457
+ Returns:
458
+ List[VectorLayerVersion] | int: A list of vector layer version instances or the total number of versions.
459
+
460
+ Example:
461
+ >>> from geobox import GeoboxClient
462
+ >>> from geobox.version import VectorLayerVersion
463
+ >>> client = GeoboxClient()
464
+ >>> layer = client.get_vector(uuid="12345678-1234-5678-1234-567812345678")
465
+ >>> versions = layer.get_versions()
466
+ or
467
+ >>> versions = layer.get_versions()
468
+ """
469
+ return VectorLayerVersion.get_versions(self.api, layer_id=self.id, **kwargs)
470
+
471
+
442
472
  @property
443
473
  def wfs(self) -> str:
444
474
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geobox
3
- Version: 1.3.1
3
+ Version: 1.3.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.3.1"
7
+ version = "1.3.2"
8
8
  description = "SDK for Geobox's APIs"
9
9
  authors = [
10
10
  {name = "Hamid Heydari", email = "heydari.h62@gmail.com"}
@@ -5,6 +5,7 @@ from urllib.parse import urljoin, urlencode
5
5
  from geobox.user import User
6
6
  from geobox.enums import UserRole, UserStatus
7
7
  from geobox.plan import Plan
8
+ from geobox.utils import xor_encode
8
9
 
9
10
 
10
11
  def test_init(api, mock_user_data):
@@ -38,7 +39,7 @@ def test_get_users(api, mock_admin_user_data):
38
39
  result = User.get_users(api, search='test')
39
40
  assert isinstance(result, list)
40
41
  assert isinstance(result[0], User)
41
- api.get.assert_called_once_with('users/?f=json&search=test&return_count=False&skip=0&limit=10&shared=False')
42
+ api.get.assert_called_once_with('users/?f=json&search=test&return_count=False&skip=0&limit=10')
42
43
 
43
44
  def test_create_user(api, mock_admin_user_data):
44
45
  api.post.return_value = mock_admin_user_data
@@ -57,7 +58,7 @@ def test_create_user(api, mock_admin_user_data):
57
58
  expected_data = {
58
59
  "username": mock_admin_user_data['username'],
59
60
  "email": mock_admin_user_data['email'],
60
- "password": 'password',
61
+ "password": xor_encode('password'),
61
62
  "role": UserRole.ACCOUNT_ADMIN.value,
62
63
  "first_name": mock_admin_user_data['first_name'],
63
64
  "last_name": mock_admin_user_data['last_name'],
@@ -126,7 +127,7 @@ def test_change_password(api, mock_admin_user_data):
126
127
  with patch.object(api, 'post', return_value={"message": "success"}):
127
128
  user.change_password('new_password')
128
129
  expected_endpoint = urljoin(user.endpoint, 'change-password')
129
- api.post.assert_called_once_with(expected_endpoint, {'new_password': 'new_password'}, is_json=False)
130
+ api.post.assert_called_once_with(expected_endpoint, {'new_password': xor_encode('new_password')}, is_json=False)
130
131
 
131
132
 
132
133
  def test_renew_plan(api, mock_admin_user_data):
@@ -253,6 +253,17 @@ def test_create_version(api, mock_vector_data, layer_type, mock_version_data):
253
253
  api.post.assert_called_once_with(f'{layer.endpoint}versions', {'name': 'design_version', 'display_name': 'Design Version', 'description': 'This layer represents design version.'})
254
254
 
255
255
 
256
+ @pytest.mark.parametrize("layer_type", [type for type in LayerType])
257
+ def test_get_versions(api, mock_vector_data, layer_type, mock_version_data):
258
+ layer = VectorLayer(api, uuid=mock_vector_data['uuid'], data=mock_vector_data, layer_type=layer_type)
259
+ api.get.return_value = [mock_version_data]
260
+ versions = layer.get_versions()
261
+ assert len(versions) == 1
262
+ assert versions[0].uuid == mock_version_data['uuid']
263
+ assert versions[0].data == mock_version_data
264
+ api.get.assert_called_once_with(f'vectorLayerVersions/?layer_id={layer.id}&f=json&return_count=False&skip=0&limit=10&shared=False')
265
+
266
+
256
267
  @pytest.mark.parametrize("layer_type", [type for type in LayerType])
257
268
  def test_wfs_access_token(api, mock_vector_data, layer_type):
258
269
  layer = VectorLayer(api, uuid=mock_vector_data['uuid'], data=mock_vector_data, layer_type=layer_type)
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