geobox 2.3.0__py3-none-any.whl → 2.4.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 (65) hide show
  1. geobox/aio/api.py +153 -7
  2. geobox/aio/apikey.py +0 -26
  3. geobox/aio/attachment.py +5 -31
  4. geobox/aio/basemap.py +2 -30
  5. geobox/aio/dashboard.py +0 -26
  6. geobox/aio/feature.py +172 -17
  7. geobox/aio/field.py +0 -27
  8. geobox/aio/file.py +0 -26
  9. geobox/aio/layout.py +0 -26
  10. geobox/aio/log.py +0 -27
  11. geobox/aio/map.py +0 -26
  12. geobox/aio/model3d.py +0 -26
  13. geobox/aio/mosaic.py +0 -26
  14. geobox/aio/plan.py +0 -26
  15. geobox/aio/query.py +0 -26
  16. geobox/aio/raster.py +0 -26
  17. geobox/aio/scene.py +1 -26
  18. geobox/aio/settings.py +0 -28
  19. geobox/aio/table.py +644 -55
  20. geobox/aio/task.py +0 -27
  21. geobox/aio/tile3d.py +0 -26
  22. geobox/aio/tileset.py +1 -26
  23. geobox/aio/usage.py +0 -32
  24. geobox/aio/user.py +0 -59
  25. geobox/aio/vector_tool.py +49 -0
  26. geobox/aio/vectorlayer.py +8 -34
  27. geobox/aio/version.py +1 -25
  28. geobox/aio/view.py +5 -35
  29. geobox/aio/workflow.py +0 -26
  30. geobox/api.py +152 -7
  31. geobox/apikey.py +0 -26
  32. geobox/attachment.py +0 -26
  33. geobox/basemap.py +0 -28
  34. geobox/dashboard.py +0 -26
  35. geobox/enums.py +11 -1
  36. geobox/feature.py +170 -15
  37. geobox/field.py +0 -28
  38. geobox/file.py +0 -26
  39. geobox/layout.py +0 -26
  40. geobox/log.py +0 -26
  41. geobox/map.py +0 -26
  42. geobox/model3d.py +0 -26
  43. geobox/mosaic.py +0 -26
  44. geobox/plan.py +1 -26
  45. geobox/query.py +1 -26
  46. geobox/raster.py +1 -31
  47. geobox/scene.py +1 -27
  48. geobox/settings.py +1 -29
  49. geobox/table.py +640 -55
  50. geobox/task.py +2 -29
  51. geobox/tile3d.py +0 -26
  52. geobox/tileset.py +1 -26
  53. geobox/usage.py +2 -33
  54. geobox/user.py +1 -59
  55. geobox/vector_tool.py +49 -0
  56. geobox/vectorlayer.py +9 -36
  57. geobox/version.py +1 -26
  58. geobox/view.py +4 -34
  59. geobox/workflow.py +1 -26
  60. {geobox-2.3.0.dist-info → geobox-2.4.0.dist-info}/METADATA +1 -1
  61. geobox-2.4.0.dist-info/RECORD +74 -0
  62. {geobox-2.3.0.dist-info → geobox-2.4.0.dist-info}/WHEEL +1 -1
  63. geobox-2.3.0.dist-info/RECORD +0 -74
  64. {geobox-2.3.0.dist-info → geobox-2.4.0.dist-info}/licenses/LICENSE +0 -0
  65. {geobox-2.3.0.dist-info → geobox-2.4.0.dist-info}/top_level.txt +0 -0
geobox/api.py CHANGED
@@ -5,7 +5,7 @@ from urllib.parse import urljoin
5
5
  from typing import Dict, List, Optional, Union
6
6
  from datetime import datetime
7
7
 
8
- from geobox.enums import AnalysisDataType, AnalysisResampleMethod
8
+ from geobox.enums import AnalysisDataType, AnalysisResampleMethod, RelationshipCardinality
9
9
 
10
10
  from .exception import AuthenticationError, ApiRequestError, NotFoundError, ValidationError, ServerError, AuthorizationError
11
11
  from .vectorlayer import VectorLayer, LayerType
@@ -35,7 +35,7 @@ from .attachment import Attachment
35
35
  from .apikey import ApiKey
36
36
  from .log import Log
37
37
  from .usage import Usage, UsageScale, UsageParam
38
- from .table import Table
38
+ from .table import RelationshipEndpoint, Table, Relationship
39
39
 
40
40
  logger = logging.getLogger(__name__)
41
41
 
@@ -188,10 +188,10 @@ class GeoboxClient:
188
188
  >>> client = GeoboxClient(apikey="apikey")
189
189
  >>> client = GeoboxClient(access_token="access_token")
190
190
  """
191
- self.username = os.getenv('GEOBOX_USERNAME') if os.getenv('GEOBOX_USERNAME') else username
192
- self.password = os.getenv('GEOBOX_PASSWORD') if os.getenv('GEOBOX_PASSWORD') else password
193
- self.access_token = os.getenv('GEOBOX_ACCESS_TOKEN') if os.getenv('GEOBOX_ACCESS_TOKEN') else access_token
194
- self.apikey = os.getenv('GEOBOX_APIKEY') if os.getenv('GEOBOX_APIKEY') else apikey
191
+ self.username = username if username else os.getenv('GEOBOX_USERNAME')
192
+ self.password = password if password else os.getenv('GEOBOX_PASSWORD')
193
+ self.access_token = access_token if access_token else os.getenv('GEOBOX_ACCESS_TOKEN')
194
+ self.apikey = apikey if apikey else os.getenv('GEOBOX_APIKEY')
195
195
  self.verify = verify
196
196
  self.session = _RequestSession(access_token=self.access_token)
197
197
 
@@ -2752,4 +2752,149 @@ class GeoboxClient:
2752
2752
  >>> table = client.get_table_by_name(name='test')
2753
2753
 
2754
2754
  """
2755
- return Table.get_table_by_name(self, name, user_id)
2755
+ return Table.get_table_by_name(self, name, user_id)
2756
+
2757
+
2758
+ def get_relationships(
2759
+ self,
2760
+ **kwargs,
2761
+ ) -> Union[List['Relationship'], int]:
2762
+ """
2763
+ Get a list of relationships with optional filtering and pagination.
2764
+
2765
+ Keyword Args:
2766
+ q (str): query filter based on OGC CQL standard. e.g. "field1 LIKE '%GIS%' AND created_at > '2021-01-01'"
2767
+ 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
2768
+ search_fields (str): comma separated list of fields for searching
2769
+ 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.
2770
+ return_count (bool): Whether to return total count. default: False.
2771
+ skip (int): Number of items to skip. default: 0
2772
+ limit (int): Number of items to return. default: 10
2773
+ user_id (int): Specific user. privileges required
2774
+ shared (bool): Whether to return shared tables. default: False
2775
+
2776
+ Returns:
2777
+ List[Relationship] | int: A list of relationship instances or the total number of relationships.
2778
+
2779
+ Example:
2780
+ >>> from geobox import GeoboxClient
2781
+ >>> from geobox.table import Relatinship
2782
+ >>> client = GeoboxClient()
2783
+ >>> relationships = client.get_relationships(q="name LIKE '%My relationship%'")
2784
+ """
2785
+ return Relationship.get_relationships(self, **kwargs)
2786
+
2787
+
2788
+ def create_relationship(
2789
+ self,
2790
+ name: str,
2791
+ cardinality: 'RelationshipCardinality',
2792
+ *,
2793
+ source: 'RelationshipEndpoint',
2794
+ target: 'RelationshipEndpoint',
2795
+ relation_table: Optional['Table'] = None,
2796
+ display_name: Optional[str] = None,
2797
+ description: Optional[str] = None,
2798
+ user_id: Optional[int] = None,
2799
+ ) -> 'Relationship':
2800
+ """
2801
+ Create a new Relationship
2802
+
2803
+ Args:
2804
+ name (str): name of the relationship
2805
+ cardinality (RelationshipCardinality): One to One, One to Many, or Many to Many
2806
+
2807
+ Keyword Args:
2808
+ source (RelationshipEndpoint): Definition of the source side of the relationship, including the table (or layer), field, and foreign-key field
2809
+ target (RelationshipEndpoint): Definition of the target side of the relationship, including the table (or layer), field, and foreign-key field
2810
+ relation_table (Table, optional): The table that stores the relationship metadata or join records. (Required for Many-to-Many relationships)
2811
+ display_name (str, optional): Human-readable name for the relationship
2812
+ description (str, optional): the description of the relationship
2813
+ user_id (int, optional): Specific user. privileges required.
2814
+
2815
+ Returns:
2816
+ Relationship: a relationship instance
2817
+
2818
+ Example:
2819
+ >>> from geobox import GeoboxClient
2820
+ >>> from geobox.table import RelationshipEndpoint, RelationshipCardinality
2821
+ >>> client = GeoboxClient()
2822
+ >>> source = RelationshipEndpoint(
2823
+ ... table=client.get_table_by_name('owner'),
2824
+ ... field="name", # on source table
2825
+ ... fk_field="book_name", # on relation table
2826
+ ... )
2827
+ >>> target = RelationshipEndpoint(
2828
+ ... table=client.get_table_by_name('parcel'),
2829
+ ... field="name", # on target table
2830
+ ... fk_field="author_name", # on relation table
2831
+ ... )
2832
+ >>> relationship = client.create_relationship(
2833
+ ... name="owner_parcel",
2834
+ ... cardinality=RelationshipCardinality.ManytoMany,
2835
+ ... source=source,
2836
+ ... target=target,
2837
+ ... relation_table=client.get_table_by_name('owner_parcel'),
2838
+ ... )
2839
+ """
2840
+ return Relationship.create_relationship(
2841
+ self,
2842
+ name=name,
2843
+ cardinality=cardinality,
2844
+ source=source,
2845
+ target=target,
2846
+ relation_table=relation_table,
2847
+ display_name=display_name,
2848
+ description=description,
2849
+ user_id=user_id,
2850
+ )
2851
+
2852
+
2853
+ def get_relationship(
2854
+ self,
2855
+ uuid: str,
2856
+ user_id: Optional[int] = None,
2857
+ ) -> 'Relationship':
2858
+ """
2859
+ Get a relationship by UUID.
2860
+
2861
+ Args:
2862
+ uuid (str): The UUID of the relationship to get.
2863
+ user_id (int, optional): Specific user. privileges required.
2864
+
2865
+ Returns:
2866
+ Relationship: The Relationship object.
2867
+
2868
+ Raises:
2869
+ NotFoundError: If the Relationship with the specified UUID is not found.
2870
+
2871
+ Example:
2872
+ >>> from geobox import GeoboxClient
2873
+ >>> client = GeoboxClient()
2874
+ >>> relationship = client.get_relationship(uuid="12345678-1234-5678-1234-567812345678")
2875
+ """
2876
+ return Relationship.get_relationship(
2877
+ self,
2878
+ uuid=uuid,
2879
+ user_id=user_id,
2880
+ )
2881
+
2882
+
2883
+ def get_relationship_by_name(self, name: str, user_id: int = None) -> Union['Relationship', None]:
2884
+ """
2885
+ Get a relationship by name
2886
+
2887
+ Args:
2888
+ name (str): the name of the relationship to get
2889
+ user_id (int, optional): specific user. privileges required.
2890
+
2891
+ Returns:
2892
+ Relationship | None: returns the relationship if a relationship matches the given name, else None
2893
+
2894
+ Example:
2895
+ >>> from geobox import GeoboxClient
2896
+ >>> from geobox.relationship import Relationship
2897
+ >>> client = GeoboxClient()
2898
+ >>> relationship = client.get_relationship_by_name(name='test')
2899
+ """
2900
+ return Relationship.get_relationship_by_name(self, name=name, user_id=user_id)
geobox/apikey.py CHANGED
@@ -6,8 +6,6 @@ from .utils import clean_data
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from . import GeoboxClient
9
- from .aio import AsyncGeoboxClient
10
- from .aio.apikey import AsyncApiKey
11
9
 
12
10
 
13
11
  class ApiKey(Base):
@@ -237,27 +235,3 @@ class ApiKey(Base):
237
235
  endpoint = f"{self.endpoint}/grant"
238
236
  self.api.post(endpoint)
239
237
  self.data['revoked'] = False
240
-
241
-
242
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncApiKey':
243
- """
244
- Switch to async version of the apikey instance to have access to the async methods
245
-
246
- Args:
247
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
248
-
249
- Returns:
250
- AsyncApiKey: the async instance of the apikey.
251
-
252
- Example:
253
- >>> from geobox import Geoboxclient
254
- >>> from geobox.aio import AsyncGeoboxClient
255
- >>> from geobox.apikey import ApiKey
256
- >>> client = GeoboxClient()
257
- >>> apikey = ApiKey.get_apikey(client, key_id=1)
258
- >>> async with AsyncGeoboxClient() as async_client:
259
- >>> async_apikey = apikey.to_async(async_client)
260
- """
261
- from .aio.apikey import AsyncApiKey
262
-
263
- return AsyncApiKey(api=async_client, key_id=self.key_id, data=self.data)
geobox/attachment.py CHANGED
@@ -11,8 +11,6 @@ from .file import File
11
11
  if TYPE_CHECKING:
12
12
  from . import GeoboxClient
13
13
  from .feature import Feature
14
- from .aio import AsyncGeoboxClient
15
- from .aio.attachment import AsyncAttachment
16
14
 
17
15
 
18
16
  class Attachment(Base):
@@ -311,27 +309,3 @@ class Attachment(Base):
311
309
  >>> attachment.thumbnail
312
310
  """
313
311
  return super()._thumbnail(format='')
314
-
315
-
316
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncAttachment':
317
- """
318
- Switch to async version of the attachment instance to have access to the async methods
319
-
320
- Args:
321
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
322
-
323
- Returns:
324
- AsyncAttachment: the async instance of the attachment.
325
-
326
- Example:
327
- >>> from geobox import Geoboxclient
328
- >>> from geobox.aio import AsyncGeoboxClient
329
- >>> from geobox.attachment import Attachment
330
- >>> client = GeoboxClient()
331
- >>> attachment = Attachment.get_attachment(client, uuid="12345678-1234-5678-1234-567812345678")
332
- >>> async with AsyncGeoboxClient() as async_client:
333
- >>> async_attachment = attachment.to_async(async_client)
334
- """
335
- from .aio.attachment import AsyncAttachment
336
-
337
- return AsyncAttachment(api=async_client, attachment_id=self.attachment_id, data=self.data)
geobox/basemap.py CHANGED
@@ -7,8 +7,6 @@ from .utils import clean_data
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from . import GeoboxClient
10
- from .aio import AsyncGeoboxClient
11
- from .aio.basemap import AsyncBasemap
12
10
 
13
11
 
14
12
  class Basemap(Base):
@@ -167,29 +165,3 @@ class Basemap(Base):
167
165
  query_string = urlencode(param)
168
166
  endpoint = urljoin(cls.BASE_ENDPOINT, f"?{query_string}")
169
167
  api.get(endpoint)
170
-
171
-
172
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncBasemap':
173
- """
174
- Switch to async version of the basemap instance to have access to the async methods
175
-
176
- Args:
177
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
178
-
179
- Returns:
180
- AsyncBasemap: the async instance of the basemap.
181
-
182
- Example:
183
- >>> from geobox import Geoboxclient
184
- >>> from geobox.aio import AsyncGeoboxClient
185
- >>> from geobox.basemap import Basemap
186
- >>> client = GeoboxClient()
187
- >>> basemap = Basemap.get_basemap(client, name='test')
188
- or
189
- >>> basemap = client.get_basemap(name='test')
190
- >>> async with AsyncGeoboxClient() as async_client:
191
- >>> async_basemap = basemap.to_async(async_client)
192
- """
193
- from .aio.basemap import AsyncBasemap
194
-
195
- return AsyncBasemap(api=async_client, data=self.data)
geobox/dashboard.py CHANGED
@@ -5,8 +5,6 @@ from .base import Base
5
5
  if TYPE_CHECKING:
6
6
  from . import GeoboxClient
7
7
  from .user import User
8
- from .aio import AsyncGeoboxClient
9
- from .aio.dashboard import AsyncDashboard
10
8
 
11
9
 
12
10
  class Dashboard(Base):
@@ -314,27 +312,3 @@ class Dashboard(Base):
314
312
  'limit': limit
315
313
  }
316
314
  return super()._get_shared_users(self.endpoint, params)
317
-
318
-
319
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncDashboard':
320
- """
321
- Switch to async version of the dashboard instance to have access to the async methods
322
-
323
- Args:
324
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
325
-
326
- Returns:
327
- AsyncDashboard: the async instance of the dashboard.
328
-
329
- Example:
330
- >>> from geobox import Geoboxclient
331
- >>> from geobox.aio import AsyncGeoboxClient
332
- >>> from geobox.dashboard import Dashboard
333
- >>> client = GeoboxClient()
334
- >>> dashboard = Dashboard.get_dashboard(client, uuid="12345678-1234-5678-1234-567812345678")
335
- >>> async with AsyncGeoboxClient() as async_client:
336
- >>> async_dashboard = dashboard.to_async(async_client)
337
- """
338
- from .aio.dashboard import AsyncDashboard
339
-
340
- return AsyncDashboard(api=async_client, uuid=self.uuid, data=self.data)
geobox/enums.py CHANGED
@@ -228,6 +228,10 @@ class QueryParamType(Enum):
228
228
  """
229
229
  A layer parameter.
230
230
  """
231
+ TABLE = "Table"
232
+ """
233
+ A table parameter.
234
+ """
231
235
  ATTRIBUTE = "Attribute"
232
236
  """
233
237
  A Attribute parameter.
@@ -433,4 +437,10 @@ class SpatialPredicate(Enum):
433
437
 
434
438
 
435
439
  class TableExportFormat(Enum):
436
- CSV = 'CSV'
440
+ CSV = 'CSV'
441
+
442
+
443
+ class RelationshipCardinality(Enum):
444
+ OnetoOne = '1-1'
445
+ OnetoMany = '1-M'
446
+ ManytoMany = 'M-N'
geobox/feature.py CHANGED
@@ -1,13 +1,12 @@
1
1
  from urllib.parse import urljoin
2
- from typing import Optional, List, Dict, Any, TYPE_CHECKING
2
+ from typing import Optional, List, Dict, Any, TYPE_CHECKING, Union
3
3
 
4
4
  from .base import Base
5
5
  from .enums import FeatureType
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from .vectorlayer import VectorLayer
9
- from .aio import AsyncGeoboxClient
10
- from .aio.feature import AsyncFeature
9
+ from .table import Table, TableRow, Relationship
11
10
 
12
11
 
13
12
  class Feature(Base):
@@ -545,26 +544,182 @@ class Feature(Base):
545
544
  return self
546
545
 
547
546
 
548
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncFeature':
547
+ def _get_other_side_of_relationship(
548
+ self,
549
+ relationship: 'Relationship',
550
+ ) -> Union['Table', 'VectorLayer']:
549
551
  """
550
- Switch to async version of the feature instance to have access to the async methods
552
+ Determine which side of a relationship this table is on and return the opposite side.
553
+
554
+ Used internally to navigate bidirectional relationships.
555
+
556
+ Args:
557
+ relationship (Relationship): The relationship to examine.
558
+
559
+ Returns:
560
+ Table | VectorLayer: The endpoint (table or layer) on the opposite side
561
+ of the relationship from this table.
562
+
563
+ Raises:
564
+ ValueError: If this table is not part of the given relationship.
565
+
566
+ Note:
567
+ This method assumes the table is either the source or target,
568
+ not the relation table in Many-to-Many relationships.
569
+ """
570
+ if relationship.source_id == self.layer.id:
571
+ return relationship.get_target()
572
+
573
+ if relationship.target_id == self.layer.id:
574
+ return relationship.get_source()
551
575
 
576
+ raise ValueError("Relationship does not involve this table.")
577
+
578
+
579
+ def _fetch_related_from_target(
580
+ self,
581
+ target: Union['Table', 'VectorLayer'],
582
+ relationship_uuid: str,
583
+ ) -> Union[List['TableRow'], List['Feature']]:
584
+ """
585
+ Fetch related rows/features from a relationship target.
586
+
587
+ Internal helper that dispatches to the appropriate API method
588
+ based on target type.
589
+
552
590
  Args:
553
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
591
+ target (Table | VectorLayer): The target endpoint (Table or VectorLayer) to query.
592
+ relationship_uuid (str): UUID of the relationship to traverse.
593
+
594
+ Raises:
595
+ TypeError: If target is not a Table or VectorLayer.
554
596
 
555
597
  Returns:
556
- AsyncFeature: the async instance of the feature.
598
+ List[TableRow] | List[Feature]: Related rows or features.
599
+ """
600
+ from .table import Table
601
+ from .vectorlayer import VectorLayer
602
+
603
+ if isinstance(target, Table):
604
+ return target.get_rows(
605
+ relationship_uuid=relationship_uuid,
606
+ related_record_id=self.id,
607
+ )
608
+
609
+ if isinstance(target, VectorLayer):
610
+ return target.get_features(
611
+ relationship_uuid=relationship_uuid,
612
+ related_record_id=self.id,
613
+ )
614
+
615
+ raise TypeError(f"Unsupported target type: {type(target)}")
616
+
617
+
618
+ def get_related_records(self,
619
+ relationship_uuid: str,
620
+ ) -> Union[List['TableRow'], List['Feature']]:
621
+ """
622
+ Get the related records on the *other side* of the relationship that are linked to this row
623
+
624
+ Args:
625
+ relationship_uuid (str): The uuid of relationship
626
+
627
+ Returns:
628
+ List[TableRow] | List[Feature]: a list of the related records
629
+
630
+ Raises:
631
+ ValueError:
632
+ If the given relationship does not involve the current table
633
+ (i.e., this row is neither the source nor the target of the relationship).
634
+
635
+ TypeError:
636
+ If the relationship target type is not supported for fetching
637
+ related records.
557
638
 
558
639
  Example:
559
- >>> from geobox import Geoboxclient
560
- >>> from geobox.aio import AsyncGeoboxClient
640
+ >>> from geobox import GeoboxClient
561
641
  >>> client = GeoboxClient()
562
642
  >>> layer = client.get_vector(uuid="12345678-1234-5678-1234-567812345678")
563
- >>> feature = layer.get_feature(id=1, srid=3857)
564
- >>> async with AsyncGeoboxClient() as async_client:
565
- >>> async_feature = feature.to_async(async_client)
643
+ >>> feature = layer.get_feature(feature_id=1)
644
+ >>> related_records = feature.get_related_records(relationship_uuid="12345678-1234-5678-1234-567812345678")
566
645
  """
567
- from .aio.feature import AsyncFeature
646
+ relationship = self.api.get_relationship(relationship_uuid)
647
+
648
+ other_side = self._get_other_side_of_relationship(relationship)
649
+
650
+ return self._fetch_related_from_target(
651
+ target=other_side,
652
+ relationship_uuid=relationship_uuid,
653
+ )
654
+
655
+
656
+ def associate_with(
657
+ self,
658
+ relationship_uuid: str,
659
+ *,
660
+ target_ids: Optional[List[int]] = None,
661
+ q: Optional[str] = None,
662
+ ) -> Dict:
663
+ """
664
+ Create relationships between the source record and target records
665
+
666
+ Args:
667
+ relationship_uuid (str): the relationship uuid
668
+ target_ids (List[int], optional): a list of target record ids to be associated with the current record
669
+ q (str, optional): query filter on target layer or table to select which target features or rows that are going to be related to the current record
670
+
671
+ Returns:
672
+ Dict: the record association result
568
673
 
569
- async_layer = self.layer.to_async(async_client=async_client)
570
- return AsyncFeature(layer=async_layer, srid=self.srid, data=self.data)
674
+ Example:
675
+ >>> from geobox import GeoboxClient
676
+ >>> client = GeoboxClient()
677
+ >>> layer = client.get_vector(uuid="12345678-1234-5678-1234-567812345678")
678
+ >>> feature = layer.get_feature(feature_id=1)
679
+ >>> feature.associate_with(
680
+ ... relationship_uuid="12345678-1234-5678-1234-567812345678",
681
+ ... target_ids=[1, 2, 3],
682
+ ... )
683
+ """
684
+ relationship = self.api.get_relationship(uuid=relationship_uuid)
685
+ return relationship.associate_records(
686
+ source_id=self.id,
687
+ target_ids=target_ids,
688
+ q=q,
689
+ )
690
+
691
+
692
+ def disassociate_with(
693
+ self,
694
+ relationship_uuid: str,
695
+ *,
696
+ target_ids: Optional[List[int]] = None,
697
+ q: Optional[str] = None,
698
+ ) -> Dict:
699
+ """
700
+ Remove relationships between the source record and target records
701
+
702
+ Args:
703
+ relationship_uuid (str): the relationship uuid
704
+ target_ids (List[int], optional): a list of target record ids to be disassociated with the current record
705
+ q (str, optional): query filter on target layer or table to select which target features or rows that are going to be related to the current record
706
+
707
+ Returns:
708
+ Dict: the record association result
709
+
710
+ Example:
711
+ >>> from geobox import GeoboxClient
712
+ >>> client = GeoboxClient()
713
+ >>> layer = client.get_vector(uuid="12345678-1234-5678-1234-567812345678")
714
+ >>> feature = layer.get_feature(feature_id=1)
715
+ >>> feature.disassociate_with(
716
+ ... relationship_uuid="12345678-1234-5678-1234-567812345678",
717
+ ... target_ids=[1, 2, 3],
718
+ ... )
719
+ """
720
+ relationship = self.api.get_relationship(uuid=relationship_uuid)
721
+ return relationship.disassociate_records(
722
+ source_id=self.id,
723
+ target_ids=target_ids,
724
+ q=q,
725
+ )
geobox/field.py CHANGED
@@ -8,8 +8,6 @@ from .enums import FieldType
8
8
  if TYPE_CHECKING:
9
9
  from .api import GeoboxClient
10
10
  from .vectorlayer import VectorLayer
11
- from .aio import AsyncGeoboxClient
12
- from .aio.field import AsyncField
13
11
 
14
12
 
15
13
  class Field(Base):
@@ -304,29 +302,3 @@ class Field(Base):
304
302
 
305
303
  self.update(domain=self.domain)
306
304
  return self.domain
307
-
308
-
309
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncField':
310
- """
311
- Switch to async version of the field instance to have access to the async methods
312
-
313
- Args:
314
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
315
-
316
- Returns:
317
- AsyncField: the async instance of the field.
318
-
319
- Example:
320
- >>> from geobox import Geoboxclient
321
- >>> from geobox.aio import AsyncGeoboxClient
322
- >>> from geobox.field import Field
323
- >>> client = GeoboxClient()
324
- >>> layer = client.get_vector(uuid="12345678-1234-5678-1234-567812345678")
325
- >>> field = layer.get_field(name='test')
326
- >>> async with AsyncGeoboxClient() as async_client:
327
- >>> async_field = field.to_async(async_client)
328
- """
329
- from .aio.field import AsyncField
330
-
331
- async_layer = self.layer.to_async(async_client=async_client)
332
- return AsyncField(layer=async_layer, data_type=self.data_type, field_id=self.field_id, data=self.data)
geobox/file.py CHANGED
@@ -15,8 +15,6 @@ from .feature import Feature
15
15
  if TYPE_CHECKING:
16
16
  from . import GeoboxClient
17
17
  from .user import User
18
- from .aio import AsyncGeoboxClient
19
- from .aio.file import AsyncFile
20
18
 
21
19
 
22
20
  class File(Base):
@@ -491,27 +489,3 @@ class File(Base):
491
489
  'limit': limit
492
490
  }
493
491
  return super()._get_shared_users(self.endpoint, params)
494
-
495
-
496
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncFile':
497
- """
498
- Switch to async version of the file instance to have access to the async methods
499
-
500
- Args:
501
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
502
-
503
- Returns:
504
- AsyncFile: the async instance of the file.
505
-
506
- Example:
507
- >>> from geobox import Geoboxclient
508
- >>> from geobox.aio import AsyncGeoboxClient
509
- >>> from geobox.file import File
510
- >>> client = GeoboxClient()
511
- >>> file = File.get_file(client, uuid="12345678-1234-5678-1234-567812345678")
512
- >>> async with AsyncGeoboxClient() as async_client:
513
- >>> async_file = file.to_async(async_client)
514
- """
515
- from .aio.file import AsyncFile
516
-
517
- return AsyncFile(api=async_client, uuid=self.uuid, data=self.data)
geobox/layout.py CHANGED
@@ -5,8 +5,6 @@ from .base import Base
5
5
  if TYPE_CHECKING:
6
6
  from . import GeoboxClient
7
7
  from .user import User
8
- from .aio import AsyncGeoboxClient
9
- from .aio.layout import AsyncLayout
10
8
 
11
9
 
12
10
  class Layout(Base):
@@ -314,27 +312,3 @@ class Layout(Base):
314
312
  'limit': limit
315
313
  }
316
314
  return super()._get_shared_users(self.endpoint, params)
317
-
318
-
319
- def to_async(self, async_client: 'AsyncGeoboxClient') -> 'AsyncLayout':
320
- """
321
- Switch to async version of the layout instance to have access to the async methods
322
-
323
- Args:
324
- async_client (AsyncGeoboxClient): The async version of the GeoboxClient instance for making requests.
325
-
326
- Returns:
327
- AsyncLayout: the async instance of the layout.
328
-
329
- Example:
330
- >>> from geobox import Geoboxclient
331
- >>> from geobox.aio import AsyncGeoboxClient
332
- >>> from geobox.layout import Layout
333
- >>> client = GeoboxClient()
334
- >>> layout = Layout.get_layout(client, uuid="12345678-1234-5678-1234-567812345678")
335
- >>> async with AsyncGeoboxClient() as async_client:
336
- >>> async_layout = layout.to_async(async_client)
337
- """
338
- from .aio.layout import AsyncLayout
339
-
340
- return AsyncLayout(api=async_client, uuid=self.uuid, data=self.data)