cacholong-cloud-cli 0.3.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 (39) hide show
  1. cacholong_cli/AsyncTyper.py +17 -0
  2. cacholong_cli/__init__.py +0 -0
  3. cacholong_cli/cli.py +110 -0
  4. cacholong_cli/commands/accounts.py +105 -0
  5. cacholong_cli/commands/addresses.py +280 -0
  6. cacholong_cli/commands/companies.py +100 -0
  7. cacholong_cli/commands/dns_records.py +275 -0
  8. cacholong_cli/commands/dns_templates.py +141 -0
  9. cacholong_cli/commands/dns_zones.py +277 -0
  10. cacholong_cli/commands/products.py +121 -0
  11. cacholong_cli/commands/purchases.py +127 -0
  12. cacholong_cli/common.py +179 -0
  13. cacholong_cli/connection.py +18 -0
  14. cacholong_cloud_cli-0.3.0.dist-info/METADATA +115 -0
  15. cacholong_cloud_cli-0.3.0.dist-info/RECORD +39 -0
  16. cacholong_cloud_cli-0.3.0.dist-info/WHEEL +4 -0
  17. cacholong_cloud_cli-0.3.0.dist-info/entry_points.txt +3 -0
  18. cacholong_sdk/__init__.py +18 -0
  19. cacholong_sdk/account.py +14 -0
  20. cacholong_sdk/address.py +14 -0
  21. cacholong_sdk/api_schema.py +124 -0
  22. cacholong_sdk/common.py +119 -0
  23. cacholong_sdk/company.py +14 -0
  24. cacholong_sdk/connection.py +22 -0
  25. cacholong_sdk/dns_record.py +14 -0
  26. cacholong_sdk/dns_template.py +14 -0
  27. cacholong_sdk/dns_zone.py +14 -0
  28. cacholong_sdk/exception.py +7 -0
  29. cacholong_sdk/product.py +14 -0
  30. cacholong_sdk/purchase.py +14 -0
  31. jsonapi_client/__init__.py +42 -0
  32. jsonapi_client/common.py +186 -0
  33. jsonapi_client/document.py +161 -0
  34. jsonapi_client/exceptions.py +62 -0
  35. jsonapi_client/filter.py +155 -0
  36. jsonapi_client/objects.py +187 -0
  37. jsonapi_client/relationships.py +447 -0
  38. jsonapi_client/resourceobject.py +656 -0
  39. jsonapi_client/session.py +755 -0
@@ -0,0 +1,161 @@
1
+ """
2
+ JSON API Python client
3
+ https://github.com/qvantel/jsonapi-client
4
+
5
+ (see JSON API specification in http://jsonapi.org/)
6
+
7
+ Copyright (c) 2017, Qvantel
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are met:
12
+ * Redistributions of source code must retain the above copyright
13
+ notice, this list of conditions and the following disclaimer.
14
+ * Redistributions in binary form must reproduce the above copyright
15
+ notice, this list of conditions and the following disclaimer in the
16
+ documentation and/or other materials provided with the distribution.
17
+ * Neither the name of the Qvantel nor the
18
+ names of its contributors may be used to endorse or promote products
19
+ derived from this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL QVANTEL BE LIABLE FOR ANY
25
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ """
32
+
33
+ import logging
34
+ from typing import TYPE_CHECKING, Iterator, AsyncIterator, List
35
+
36
+ from .common import AbstractJsonObject
37
+ from .exceptions import ValidationError, DocumentError
38
+ from .objects import Meta, Links
39
+ from .resourceobject import ResourceObject
40
+
41
+ if TYPE_CHECKING:
42
+ from .session import Session
43
+
44
+
45
+ logger = logging.getLogger(__name__)
46
+
47
+
48
+ class Document(AbstractJsonObject):
49
+ """
50
+ Top level of JSON API document.
51
+ Contains one or more ResourceObjects.
52
+
53
+ http://jsonapi.org/format/#document-top-level
54
+ """
55
+
56
+ #: List of ResourceObjects contained in this Document
57
+ resources: List['ResourceObject']
58
+
59
+ def __init__(self, session: 'Session',
60
+ json_data: dict,
61
+ url: str,
62
+ no_cache: bool=False) -> None:
63
+ self._no_cache = no_cache # if true, do not store resources to session cache
64
+ self._url = url
65
+ super().__init__(session, json_data)
66
+
67
+ @property
68
+ def url(self) -> str:
69
+ return self._url
70
+
71
+ @property
72
+ def resource(self) -> 'ResourceObject':
73
+ """
74
+ If there is only 1 ResourceObject contained in this Document, return it.
75
+ """
76
+ if len(self.resources) > 1:
77
+ logger.warning('There are more than 1 item in document %s, please use '
78
+ '.resources!', self)
79
+ return self.resources[0]
80
+
81
+ def _handle_data(self, json_data):
82
+ data = json_data.get('data')
83
+
84
+ self.resources = []
85
+
86
+ if data:
87
+ if isinstance(data, list):
88
+ self.resources.extend([ResourceObject(self.session, i) for i in data])
89
+ elif isinstance(data, dict):
90
+ self.resources.append(ResourceObject(self.session, data))
91
+
92
+ self.errors = json_data.get('errors')
93
+ if [data, self.errors] == [None]*2:
94
+ raise ValidationError('Data or errors is needed')
95
+ if data and self.errors:
96
+ logger.error('Data and errors can not both exist in the same document')
97
+
98
+ self.meta = Meta(self.session, json_data.get('meta', {}))
99
+
100
+ self.jsonapi = json_data.get('jsonapi', {})
101
+ self.links = Links(self.session, json_data.get('links', {}))
102
+ if self.errors:
103
+ raise DocumentError(f'Error document was fetched. Details: {self.errors}',
104
+ errors=self.errors)
105
+ self.included = [ResourceObject(self.session, i)
106
+ for i in json_data.get('included', [])]
107
+ if not self._no_cache:
108
+ self.session.add_resources(*self.resources, *self.included)
109
+
110
+ def __str__(self):
111
+ return f'{self.resources}' if self.resources else f'{self.errors}'
112
+
113
+ def _iterator_sync(self) -> 'Iterator[ResourceObject]':
114
+ # if we currently have no items on the page, then there's no need to yield items
115
+ # and check the next page
116
+ # we do this because there are APIs that always have a 'next' link, even when
117
+ # there are no items on the page
118
+ if len(self.resources) == 0:
119
+ return
120
+
121
+ yield from self.resources
122
+
123
+ if self.links.next:
124
+ next_doc = self.links.next.fetch()
125
+ yield from next_doc.iterator()
126
+
127
+ async def _iterator_async(self) -> 'AsyncIterator[ResourceObject]':
128
+ # if we currently have no items on the page, then there's no need to yield items
129
+ # and check the next page
130
+ # we do this because there are APIs that always have a 'next' link, even when
131
+ # there are no items on the page
132
+ if len(self.resources) == 0:
133
+ return
134
+
135
+ for res in self.resources:
136
+ yield res
137
+
138
+ if self.links.next:
139
+ next_doc = await self.links.next.fetch()
140
+ async for res in next_doc.iterator():
141
+ yield res
142
+
143
+ def iterator(self):
144
+ """
145
+ Iterate through all resources of this Document and follow pagination until
146
+ there's no more resources.
147
+
148
+ If Session is in async mode, this needs to be used with async for.
149
+ """
150
+ if self.session.enable_async:
151
+ return self._iterator_async()
152
+ else:
153
+ return self._iterator_sync()
154
+
155
+ def mark_invalid(self):
156
+ """
157
+ Mark this Document and it's resources invalid.
158
+ """
159
+ super().mark_invalid()
160
+ for r in self.resources:
161
+ r.mark_invalid()
@@ -0,0 +1,62 @@
1
+ """
2
+ JSON API Python client
3
+ https://github.com/qvantel/jsonapi-client
4
+
5
+ (see JSON API specification in http://jsonapi.org/)
6
+
7
+ Copyright (c) 2017, Qvantel
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are met:
12
+ * Redistributions of source code must retain the above copyright
13
+ notice, this list of conditions and the following disclaimer.
14
+ * Redistributions in binary form must reproduce the above copyright
15
+ notice, this list of conditions and the following disclaimer in the
16
+ documentation and/or other materials provided with the distribution.
17
+ * Neither the name of the Qvantel nor the
18
+ names of its contributors may be used to endorse or promote products
19
+ derived from this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL QVANTEL BE LIABLE FOR ANY
25
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ """
32
+
33
+
34
+ class JsonApiClientError(Exception):
35
+ """
36
+ Generic exception class for jsonapi-client
37
+ """
38
+ pass
39
+
40
+
41
+ class ValidationError(JsonApiClientError):
42
+ pass
43
+
44
+
45
+ class DocumentError(JsonApiClientError):
46
+ """
47
+ Raised when 404 or other error takes place.
48
+ Status code is stored in errors['status_code'].
49
+ """
50
+ def __init__(self, *args, errors, **kwargs):
51
+ super().__init__(*args)
52
+ self.errors = errors
53
+ for key, value in kwargs.items():
54
+ setattr(self, key, value)
55
+
56
+
57
+ class DocumentInvalid(JsonApiClientError):
58
+ pass
59
+
60
+
61
+ class AsyncError(JsonApiClientError):
62
+ pass
@@ -0,0 +1,155 @@
1
+ """
2
+ JSON API Python client
3
+ https://github.com/qvantel/jsonapi-client
4
+
5
+ (see JSON API specification in http://jsonapi.org/)
6
+
7
+ Copyright (c) 2017, Qvantel
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are met:
12
+ * Redistributions of source code must retain the above copyright
13
+ notice, this list of conditions and the following disclaimer.
14
+ * Redistributions in binary form must reproduce the above copyright
15
+ notice, this list of conditions and the following disclaimer in the
16
+ documentation and/or other materials provided with the distribution.
17
+ * Neither the name of the Qvantel nor the
18
+ names of its contributors may be used to endorse or promote products
19
+ derived from this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL QVANTEL BE LIABLE FOR ANY
25
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ """
32
+
33
+ from typing import TYPE_CHECKING, Union, Dict, Sequence
34
+
35
+ if TYPE_CHECKING:
36
+ FilterKeywords = Dict[str, Union[str, Sequence[Union[str, int, float]]]]
37
+ IncludeKeywords = Sequence[str]
38
+
39
+
40
+ class Modifier:
41
+ """
42
+ Base class for query modifiers.
43
+ You can derive your own class and use it if you have custom syntax.
44
+ """
45
+ def __init__(self, query_str: str='') -> None:
46
+ self._query_str = query_str
47
+
48
+ def url_with_modifiers(self, base_url: str) -> str:
49
+ """
50
+ Returns url with modifiers appended.
51
+
52
+ Example:
53
+ Modifier('filter[attr1]=1,2&filter[attr2]=2').filtered_url('doc')
54
+ -> 'GET doc?filter[attr1]=1,2&filter[attr2]=2'
55
+ """
56
+ filter_query = self.appended_query()
57
+ fetch_url = f'{base_url}?{filter_query}'
58
+ return fetch_url
59
+
60
+ def appended_query(self) -> str:
61
+ return self._query_str
62
+
63
+ def __add__(self, other: 'Modifier') -> 'Modifier':
64
+ mods = []
65
+ for m in [self, other]:
66
+ if isinstance(m, ModifierSum):
67
+ mods += m.modifiers
68
+ else:
69
+ mods.append(m)
70
+ return ModifierSum(mods)
71
+
72
+
73
+ class ModifierSum(Modifier):
74
+ def __init__(self, modifiers):
75
+ self.modifiers = modifiers
76
+
77
+ def appended_query(self) -> str:
78
+ return '&'.join(m.appended_query() for m in self.modifiers)
79
+
80
+
81
+ class Filter(Modifier):
82
+ """
83
+ Implements query filtering for Session.get etc.
84
+ You can derive your own filter class and use it if you have a
85
+ custom filter query syntax.
86
+ """
87
+ def __init__(self, query_str: str='', **filter_kwargs: 'FilterKeywords') -> None:
88
+ """
89
+ :param query_str: Specify query string manually.
90
+ :param filter_kwargs: Specify required conditions on result.
91
+ Example: Filter(attribute='1', relation__attribute='2')
92
+ """
93
+ super().__init__(query_str)
94
+ self._filter_kwargs = filter_kwargs
95
+
96
+ # This and next method prevent any existing subclasses from breaking
97
+ def url_with_modifiers(self, base_url: str) -> str:
98
+ return self.filtered_url(base_url)
99
+
100
+ def filtered_url(self, base_url: str) -> str:
101
+ return super().url_with_modifiers(base_url)
102
+
103
+ def appended_query(self) -> str:
104
+ return super().appended_query() or self.format_filter_query(**self._filter_kwargs)
105
+
106
+ def format_filter_query(self, **kwargs: 'FilterKeywords') -> str:
107
+ """
108
+ Filter class that implements url filtering scheme according to JSONAPI
109
+ recommendations (http://jsonapi.org/recommendations/)
110
+ """
111
+ def jsonify_key(key):
112
+ return key.replace('__', '.').replace('_', '-')
113
+ return '&'.join(f'filter[{jsonify_key(key)}]={value}'
114
+ for key, value in kwargs.items())
115
+
116
+
117
+ class Inclusion(Modifier):
118
+ """
119
+ Implements query inclusion for Session.get etc.
120
+ """
121
+ def __init__(self, *include_args: 'IncludeKeywords') -> None:
122
+ super().__init__()
123
+ self._include_args = include_args
124
+
125
+ def appended_query(self) -> str:
126
+ includes = ','.join(self._include_args)
127
+ return f'include={includes}'
128
+
129
+
130
+ class Sort(Modifier):
131
+ """
132
+ Implements query inclusion for Session.get etc.
133
+ """
134
+ def __init__(self, *sort_args: 'SortKeywords') -> None:
135
+ super().__init__()
136
+ self._sort_args = sort_args
137
+
138
+ def appended_query(self) -> str:
139
+ sort_by = ','.join(self._sort_args)
140
+ return f'sort={sort_by}'
141
+
142
+
143
+ class SparseField(Modifier):
144
+ """
145
+ Implement sparse fields
146
+ """
147
+ def __init__(self, resource: str, *sparse_field_args: 'SparseFieldKeywords') -> None:
148
+ super().__init__()
149
+ self._resource = resource
150
+ self._sparse_field_args = sparse_field_args
151
+
152
+ def appended_query(self) -> str:
153
+ sparse_fields = ','.join(self._sparse_field_args)
154
+ resource = self._resource
155
+ return f'fields[{resource}]={sparse_fields}'
@@ -0,0 +1,187 @@
1
+ """
2
+ JSON API Python client
3
+ https://github.com/qvantel/jsonapi-client
4
+
5
+ (see JSON API specification in http://jsonapi.org/)
6
+
7
+ Copyright (c) 2017, Qvantel
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are met:
12
+ * Redistributions of source code must retain the above copyright
13
+ notice, this list of conditions and the following disclaimer.
14
+ * Redistributions in binary form must reproduce the above copyright
15
+ notice, this list of conditions and the following disclaimer in the
16
+ documentation and/or other materials provided with the distribution.
17
+ * Neither the name of the Qvantel nor the
18
+ names of its contributors may be used to endorse or promote products
19
+ derived from this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL QVANTEL BE LIABLE FOR ANY
25
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ """
32
+
33
+ import logging
34
+ from itertools import chain
35
+ from typing import Optional, Union, Awaitable, TYPE_CHECKING
36
+ from urllib.parse import urlparse
37
+
38
+ from .common import AbstractJsonObject, jsonify_attribute_name, ResourceTuple
39
+ from .resourceobject import ResourceObject
40
+
41
+ if TYPE_CHECKING:
42
+ from .document import Document
43
+
44
+ logger = logging.getLogger(__name__)
45
+
46
+
47
+ class Meta(AbstractJsonObject):
48
+ """
49
+ Object type for meta data
50
+
51
+ http://jsonapi.org/format/#document-meta
52
+ """
53
+ def _handle_data(self, data):
54
+ self.meta = data
55
+
56
+ def __getattr__(self, name):
57
+ return self.meta.get(jsonify_attribute_name(name))
58
+
59
+ def __getitem__(self, name):
60
+ return self.meta.get(name)
61
+
62
+ def __str__(self):
63
+ return str(self.meta)
64
+
65
+
66
+ class Link(AbstractJsonObject):
67
+ """
68
+ Object type for a single link
69
+
70
+ http://jsonapi.org/format/#document-links
71
+ """
72
+ def _handle_data(self, data):
73
+ if data:
74
+ if isinstance(data, str):
75
+ self.href = data
76
+ else:
77
+ self.href = data['href']
78
+ self.meta = Meta(self.session, data.get('meta', {}))
79
+ else:
80
+ self.href = ''
81
+
82
+ def __eq__(self, other):
83
+ return self.href == other.href
84
+
85
+ def __bool__(self):
86
+ return bool(self.href)
87
+
88
+ @property
89
+ def url(self) -> str:
90
+ if urlparse(self.href).scheme: # if href contains only relative link
91
+ return self.href
92
+ else:
93
+ return f'{self.session.server_url}{self.href}'
94
+
95
+ def __str__(self):
96
+ return self.url if self.href else ''
97
+
98
+ def fetch_sync(self) -> 'Optional[Document]':
99
+ self.session.assert_sync()
100
+ if self:
101
+ return self.session.fetch_document_by_url(self.url)
102
+
103
+ def fetch(self):
104
+ if self.session.enable_async:
105
+ return self.fetch_async()
106
+ else:
107
+ return self.fetch_sync()
108
+
109
+ async def fetch_async(self) -> 'Optional[Document]':
110
+ self.session.assert_async()
111
+ if self:
112
+ return await self.session.fetch_document_by_url_async(self.url)
113
+
114
+
115
+ class Links(AbstractJsonObject):
116
+ """
117
+ Object type for container of links
118
+
119
+ http://jsonapi.org/format/#document-links
120
+ """
121
+ def _handle_data(self, data):
122
+ self._links = {key: Link(self.session, value) for key, value in data.items()}
123
+
124
+ def __getattr__(self, item):
125
+ attr = self._links.get(item)
126
+ if not attr:
127
+ return Link(self.session, '')
128
+ return attr
129
+
130
+ def __bool__(self):
131
+ return bool(self._links)
132
+
133
+ def __dir__(self):
134
+ return chain(super().__dir__(), self._links.keys())
135
+
136
+ def __str__(self):
137
+ return str(self._links)
138
+
139
+
140
+ class ResourceIdentifier(AbstractJsonObject):
141
+ """
142
+ Object type for resource identifier
143
+
144
+ http://jsonapi.org/format/#document-resource-identifier-objects
145
+ """
146
+ def _handle_data(self, data):
147
+ self.id:str = data.get('id')
148
+ self.type:str = data.get('type')
149
+ self.meta = data.get('meta')
150
+
151
+ @property
152
+ def url(self):
153
+ return f'{self.session.url_prefix}/{self.type}/{self.id}'
154
+
155
+ def __str__(self):
156
+ return f'{self.type}: {self.id} ({self.meta})'
157
+
158
+ def fetch_sync(self, cache_only=True) -> 'ResourceObject':
159
+ return self.session.fetch_resource_by_resource_identifier(self, cache_only)
160
+
161
+ async def fetch_async(self, cache_only=True) -> 'ResourceObject':
162
+ return await self.session.fetch_resource_by_resource_identifier_async(self,
163
+ cache_only)
164
+
165
+ def fetch(self, cache_only=True) \
166
+ -> 'Union[Awaitable[ResourceObject], ResourceObject]':
167
+ if self.session.enable_async:
168
+ return self.fetch_async(cache_only)
169
+ else:
170
+ return self.fetch_sync(cache_only)
171
+
172
+ def as_resource_identifier_dict(self) -> dict:
173
+ if not self.id:
174
+ return None
175
+ res = {
176
+ 'id': self.id,
177
+ 'type': self.type,
178
+ }
179
+ if self.meta:
180
+ res['meta'] = self.meta
181
+ return res
182
+
183
+ def __bool__(self):
184
+ return self.id is not None
185
+
186
+ RESOURCE_TYPES = (ResourceObject, ResourceIdentifier, ResourceTuple)
187
+ ResourceTypes = Union[ResourceObject, ResourceIdentifier, ResourceTuple]