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.
- geobox/aio/api.py +153 -7
- geobox/aio/apikey.py +0 -26
- geobox/aio/attachment.py +5 -31
- geobox/aio/basemap.py +2 -30
- geobox/aio/dashboard.py +0 -26
- geobox/aio/feature.py +172 -17
- geobox/aio/field.py +0 -27
- geobox/aio/file.py +0 -26
- geobox/aio/layout.py +0 -26
- geobox/aio/log.py +0 -27
- geobox/aio/map.py +0 -26
- geobox/aio/model3d.py +0 -26
- geobox/aio/mosaic.py +0 -26
- geobox/aio/plan.py +0 -26
- geobox/aio/query.py +0 -26
- geobox/aio/raster.py +0 -26
- geobox/aio/scene.py +1 -26
- geobox/aio/settings.py +0 -28
- geobox/aio/table.py +644 -55
- geobox/aio/task.py +0 -27
- geobox/aio/tile3d.py +0 -26
- geobox/aio/tileset.py +1 -26
- geobox/aio/usage.py +0 -32
- geobox/aio/user.py +0 -59
- geobox/aio/vector_tool.py +49 -0
- geobox/aio/vectorlayer.py +8 -34
- geobox/aio/version.py +1 -25
- geobox/aio/view.py +5 -35
- geobox/aio/workflow.py +0 -26
- geobox/api.py +152 -7
- geobox/apikey.py +0 -26
- geobox/attachment.py +0 -26
- geobox/basemap.py +0 -28
- geobox/dashboard.py +0 -26
- geobox/enums.py +11 -1
- geobox/feature.py +170 -15
- geobox/field.py +0 -28
- geobox/file.py +0 -26
- geobox/layout.py +0 -26
- geobox/log.py +0 -26
- geobox/map.py +0 -26
- geobox/model3d.py +0 -26
- geobox/mosaic.py +0 -26
- geobox/plan.py +1 -26
- geobox/query.py +1 -26
- geobox/raster.py +1 -31
- geobox/scene.py +1 -27
- geobox/settings.py +1 -29
- geobox/table.py +640 -55
- geobox/task.py +2 -29
- geobox/tile3d.py +0 -26
- geobox/tileset.py +1 -26
- geobox/usage.py +2 -33
- geobox/user.py +1 -59
- geobox/vector_tool.py +49 -0
- geobox/vectorlayer.py +9 -36
- geobox/version.py +1 -26
- geobox/view.py +4 -34
- geobox/workflow.py +1 -26
- {geobox-2.3.0.dist-info → geobox-2.4.0.dist-info}/METADATA +1 -1
- geobox-2.4.0.dist-info/RECORD +74 -0
- {geobox-2.3.0.dist-info → geobox-2.4.0.dist-info}/WHEEL +1 -1
- geobox-2.3.0.dist-info/RECORD +0 -74
- {geobox-2.3.0.dist-info → geobox-2.4.0.dist-info}/licenses/LICENSE +0 -0
- {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 =
|
|
192
|
-
self.password =
|
|
193
|
-
self.access_token =
|
|
194
|
-
self.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 .
|
|
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
|
|
547
|
+
def _get_other_side_of_relationship(
|
|
548
|
+
self,
|
|
549
|
+
relationship: 'Relationship',
|
|
550
|
+
) -> Union['Table', 'VectorLayer']:
|
|
549
551
|
"""
|
|
550
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
564
|
-
>>>
|
|
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
|
-
|
|
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
|
-
|
|
570
|
-
|
|
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)
|