Contentstack 2.3.0__tar.gz → 2.4.1__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.
- {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/PKG-INFO +1 -1
- {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/SOURCES.txt +1 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/PKG-INFO +1 -1
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/__init__.py +1 -1
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/asset.py +3 -2
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/basequery.py +10 -5
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/contenttype.py +5 -7
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/controller.py +3 -2
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/deep_merge_lp.py +3 -1
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/entry.py +9 -9
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/entryqueryable.py +3 -2
- contentstack-2.4.1/contentstack/error_messages.py +59 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/query.py +10 -11
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/stack.py +11 -10
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/utility.py +3 -2
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/variants.py +2 -1
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_assets.py +2 -2
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_entry.py +2 -2
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_stack.py +10 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/dependency_links.txt +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/not-zip-safe +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/requires.txt +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/top_level.txt +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/LICENSE +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/README.md +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/assetquery.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/globalfields.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/https_connection.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/image_transform.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/taxonomy.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/setup.cfg +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/setup.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_early_fetch.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_early_find.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_global_fields.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_live_preview.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_query.py +0 -0
- {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_taxonomies.py +0 -0
|
@@ -22,7 +22,7 @@ __all__ = (
|
|
|
22
22
|
__title__ = 'contentstack-delivery-python'
|
|
23
23
|
__author__ = 'contentstack'
|
|
24
24
|
__status__ = 'debug'
|
|
25
|
-
__version__ = 'v2.
|
|
25
|
+
__version__ = 'v2.4.1'
|
|
26
26
|
__endpoint__ = 'cdn.contentstack.io'
|
|
27
27
|
__email__ = 'support@contentstack.com'
|
|
28
28
|
__developer_email__ = 'mobile@contentstack.com'
|
|
@@ -6,6 +6,7 @@ These files can be attached and used in multiple entries.
|
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
8
|
from urllib import parse
|
|
9
|
+
from contentstack.error_messages import ErrorMessages
|
|
9
10
|
|
|
10
11
|
class Asset:
|
|
11
12
|
r"""`Asset` refer to all the media files (images, videos, PDFs, audio files, and so on)."""
|
|
@@ -15,7 +16,7 @@ class Asset:
|
|
|
15
16
|
self.asset_params = {}
|
|
16
17
|
self.__uid = uid
|
|
17
18
|
if self.__uid is None or self.__uid.strip() == 0:
|
|
18
|
-
raise KeyError(
|
|
19
|
+
raise KeyError(ErrorMessages.INVALID_UID)
|
|
19
20
|
self.base_url = f'{self.http_instance.endpoint}/assets/{self.__uid}'
|
|
20
21
|
if 'environment' in self.http_instance.headers:
|
|
21
22
|
self.asset_params['environment'] = self.http_instance.headers['environment']
|
|
@@ -68,7 +69,7 @@ class Asset:
|
|
|
68
69
|
-----------------------------
|
|
69
70
|
"""
|
|
70
71
|
if None in (key, value) or not isinstance(key, str):
|
|
71
|
-
raise KeyError(
|
|
72
|
+
raise KeyError(ErrorMessages.INVALID_PARAMS)
|
|
72
73
|
self.asset_params[key] = value
|
|
73
74
|
return self
|
|
74
75
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import enum
|
|
2
2
|
import logging
|
|
3
|
+
from contentstack.error_messages import ErrorMessages
|
|
3
4
|
|
|
4
5
|
class QueryOperation(enum.Enum):
|
|
5
6
|
"""
|
|
@@ -137,8 +138,10 @@ class BaseQuery:
|
|
|
137
138
|
|
|
138
139
|
-----------------------------------
|
|
139
140
|
"""
|
|
140
|
-
if
|
|
141
|
-
raise KeyError(
|
|
141
|
+
if key is None:
|
|
142
|
+
raise KeyError(ErrorMessages.INVALID_KEY)
|
|
143
|
+
if value is None:
|
|
144
|
+
raise KeyError(ErrorMessages.INVALID_VALUE)
|
|
142
145
|
self.query_params[key] = str(value)
|
|
143
146
|
return self
|
|
144
147
|
|
|
@@ -164,8 +167,10 @@ class BaseQuery:
|
|
|
164
167
|
Returns:
|
|
165
168
|
self-- Class instance, So that method chaining can be performed
|
|
166
169
|
"""
|
|
167
|
-
if
|
|
168
|
-
raise KeyError(
|
|
170
|
+
if key is None:
|
|
171
|
+
raise KeyError(ErrorMessages.INVALID_KEY)
|
|
172
|
+
if value is None:
|
|
173
|
+
raise KeyError(ErrorMessages.INVALID_VALUE)
|
|
169
174
|
self.parameters[key] = str(value)
|
|
170
175
|
return self
|
|
171
176
|
|
|
@@ -186,7 +191,7 @@ class BaseQuery:
|
|
|
186
191
|
----------------------------------
|
|
187
192
|
"""
|
|
188
193
|
if key is None:
|
|
189
|
-
raise ValueError(
|
|
194
|
+
raise ValueError(ErrorMessages.INVALID_KEY)
|
|
190
195
|
if key in self.query_params:
|
|
191
196
|
self.query_params.pop(key, None)
|
|
192
197
|
return self
|
|
@@ -10,6 +10,7 @@ content type.
|
|
|
10
10
|
import json
|
|
11
11
|
import logging
|
|
12
12
|
from urllib import parse
|
|
13
|
+
from contentstack.error_messages import ErrorMessages
|
|
13
14
|
|
|
14
15
|
from contentstack.entry import Entry
|
|
15
16
|
from contentstack.query import Query
|
|
@@ -46,11 +47,9 @@ class ContentType:
|
|
|
46
47
|
--------------------------------
|
|
47
48
|
"""
|
|
48
49
|
if self.__content_type_uid is None:
|
|
49
|
-
raise PermissionError(
|
|
50
|
+
raise PermissionError(ErrorMessages.INVALID_CONTENT_TYPE_UID)
|
|
50
51
|
if entry_uid is None:
|
|
51
|
-
raise PermissionError(
|
|
52
|
-
"message": 'Please provide valid entry uid',
|
|
53
|
-
"message_detail": 'Entry UID can not be None'}))
|
|
52
|
+
raise PermissionError(ErrorMessages.INVALID_UID)
|
|
54
53
|
entry = Entry(self.http_instance,
|
|
55
54
|
self.__content_type_uid, entry_uid=entry_uid)
|
|
56
55
|
return entry
|
|
@@ -69,7 +68,7 @@ class ContentType:
|
|
|
69
68
|
------------------------------
|
|
70
69
|
"""
|
|
71
70
|
if self.__content_type_uid is None:
|
|
72
|
-
raise PermissionError(
|
|
71
|
+
raise PermissionError(ErrorMessages.CONTENT_TYPE_UID_REQUIRED)
|
|
73
72
|
return Query(self.http_instance, self.__content_type_uid)
|
|
74
73
|
|
|
75
74
|
def fetch(self):
|
|
@@ -87,8 +86,7 @@ class ContentType:
|
|
|
87
86
|
------------------------------
|
|
88
87
|
"""
|
|
89
88
|
if self.__content_type_uid is None:
|
|
90
|
-
raise KeyError(
|
|
91
|
-
'content_type_uid can not be None to fetch contenttype')
|
|
89
|
+
raise KeyError(ErrorMessages.CONTENT_TYPE_UID_REQUIRED)
|
|
92
90
|
self.local_param['environment'] = self.http_instance.headers['environment']
|
|
93
91
|
uri = f'{self.http_instance.endpoint}/content_types/{self.__content_type_uid}'
|
|
94
92
|
encoded_params = parse.urlencode(self.local_param)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import requests
|
|
2
2
|
from requests.utils import guess_json_utf
|
|
3
|
+
from contentstack.error_messages import ErrorMessages
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class RequestError(Exception):
|
|
@@ -18,14 +19,14 @@ def get_request(session, url, headers, timeout):
|
|
|
18
19
|
response.encoding = 'utf-8'
|
|
19
20
|
except requests.exceptions.RequestException as e:
|
|
20
21
|
error = {
|
|
21
|
-
'error':
|
|
22
|
+
'error': ErrorMessages.CONNECTION_FAILED.format(url=url, error=str(e)),
|
|
22
23
|
'error_code': '400',
|
|
23
24
|
'error_message': {str(e)}
|
|
24
25
|
}
|
|
25
26
|
raise RequestError(error)
|
|
26
27
|
except Exception as e:
|
|
27
28
|
error = {
|
|
28
|
-
'error':
|
|
29
|
+
'error': ErrorMessages.OPERATION_FAILED.format(url=url, error=str(e)),
|
|
29
30
|
'error_code': '400',
|
|
30
31
|
'error_message': {str(e)}
|
|
31
32
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
from contentstack.error_messages import ErrorMessages
|
|
2
|
+
|
|
1
3
|
class DeepMergeMixin:
|
|
2
4
|
|
|
3
5
|
def __init__(self, entry_response, lp_response):
|
|
4
6
|
if not isinstance(entry_response, list) or not isinstance(lp_response, list):
|
|
5
|
-
raise TypeError(
|
|
7
|
+
raise TypeError(ErrorMessages.INVALID_RESPONSE_TYPE)
|
|
6
8
|
|
|
7
9
|
self.entry_response = entry_response
|
|
8
10
|
self.lp_response = lp_response
|
|
@@ -5,6 +5,7 @@ API Reference: https://www.contentstack.com/docs/developers/apis/content-deliver
|
|
|
5
5
|
#min-similarity-lines=10
|
|
6
6
|
import logging
|
|
7
7
|
from urllib import parse
|
|
8
|
+
from contentstack.error_messages import ErrorMessages
|
|
8
9
|
|
|
9
10
|
from contentstack.deep_merge_lp import DeepMergeMixin
|
|
10
11
|
from contentstack.entryqueryable import EntryQueryable
|
|
@@ -49,7 +50,7 @@ class Entry(EntryQueryable):
|
|
|
49
50
|
------------------------------
|
|
50
51
|
"""
|
|
51
52
|
if environment is None:
|
|
52
|
-
raise KeyError(
|
|
53
|
+
raise KeyError(ErrorMessages.INVALID_ENVIRONMENT)
|
|
53
54
|
self.http_instance.headers['environment'] = environment
|
|
54
55
|
return self
|
|
55
56
|
|
|
@@ -72,7 +73,7 @@ class Entry(EntryQueryable):
|
|
|
72
73
|
------------------------------
|
|
73
74
|
"""
|
|
74
75
|
if version is None:
|
|
75
|
-
raise KeyError(
|
|
76
|
+
raise KeyError(ErrorMessages.INVALID_VERSION)
|
|
76
77
|
self.entry_param['version'] = version
|
|
77
78
|
return self
|
|
78
79
|
|
|
@@ -94,7 +95,7 @@ class Entry(EntryQueryable):
|
|
|
94
95
|
-----------------------------
|
|
95
96
|
"""
|
|
96
97
|
if None in (key, value) and not isinstance(key, str):
|
|
97
|
-
raise ValueError(
|
|
98
|
+
raise ValueError(ErrorMessages.INVALID_KEY_VALUE_ARGS)
|
|
98
99
|
self.entry_param[key] = value
|
|
99
100
|
return self
|
|
100
101
|
|
|
@@ -113,7 +114,7 @@ class Entry(EntryQueryable):
|
|
|
113
114
|
>>> result = entry.fetch()
|
|
114
115
|
----------------------------
|
|
115
116
|
"""
|
|
116
|
-
print(
|
|
117
|
+
print(ErrorMessages.REQUESTING_FALLBACK)
|
|
117
118
|
self.entry_param['include_fallback'] = 'true'
|
|
118
119
|
return self
|
|
119
120
|
|
|
@@ -157,8 +158,7 @@ class Entry(EntryQueryable):
|
|
|
157
158
|
if endpoint is not None and endpoint.strip(): # .strip() removes leading/trailing whitespace
|
|
158
159
|
self.http_instance.endpoint = endpoint
|
|
159
160
|
if None in (self.http_instance, self.content_type_id, self.entry_uid):
|
|
160
|
-
raise KeyError(
|
|
161
|
-
'Provide valid http_instance, content_type_uid or entry_uid')
|
|
161
|
+
raise KeyError(ErrorMessages.INVALID_KEY_OR_VALUE)
|
|
162
162
|
url = f'{self.http_instance.endpoint}/content_types/{self.content_type_id}/entries/{self.entry_uid}'
|
|
163
163
|
return url
|
|
164
164
|
|
|
@@ -217,12 +217,12 @@ class Entry(EntryQueryable):
|
|
|
217
217
|
if not isinstance(lp_entry, list):
|
|
218
218
|
lp_entry = [lp_entry] # Wrap in a list if it's a dict
|
|
219
219
|
if not all(isinstance(item, dict) for item in entry_response):
|
|
220
|
-
raise TypeError(
|
|
220
|
+
raise TypeError(ErrorMessages.INVALID_ENTRY_RESPONSE)
|
|
221
221
|
if not all(isinstance(item, dict) for item in lp_entry):
|
|
222
|
-
raise TypeError(
|
|
222
|
+
raise TypeError(ErrorMessages.INVALID_LP_ENTRY)
|
|
223
223
|
merged_response = DeepMergeMixin(entry_response, lp_entry).to_dict() # Convert to dictionary
|
|
224
224
|
return merged_response # Now correctly returns a dictionary
|
|
225
|
-
raise ValueError(
|
|
225
|
+
raise ValueError(ErrorMessages.MISSING_LIVE_PREVIEW_KEYS)
|
|
226
226
|
|
|
227
227
|
def variants(self, variant_uid: str | list[str], params: dict = None):
|
|
228
228
|
"""
|
|
@@ -3,6 +3,7 @@ EntryQueryable class contains common functions
|
|
|
3
3
|
that is used as parents class for the query and entry classes
|
|
4
4
|
"""
|
|
5
5
|
import logging
|
|
6
|
+
from contentstack.error_messages import ErrorMessages
|
|
6
7
|
|
|
7
8
|
class EntryQueryable:
|
|
8
9
|
"""
|
|
@@ -55,7 +56,7 @@ class EntryQueryable:
|
|
|
55
56
|
if isinstance(field_uid, str):
|
|
56
57
|
self.entry_queryable_param['only[BASE][]'] = field_uid
|
|
57
58
|
else:
|
|
58
|
-
raise KeyError(
|
|
59
|
+
raise KeyError(ErrorMessages.INVALID_FIELD_UID)
|
|
59
60
|
return self
|
|
60
61
|
|
|
61
62
|
def excepts(self, field_uid: str):
|
|
@@ -69,7 +70,7 @@ class EntryQueryable:
|
|
|
69
70
|
if isinstance(field_uid, str):
|
|
70
71
|
self.entry_queryable_param['except[BASE][]'] = field_uid
|
|
71
72
|
else:
|
|
72
|
-
raise KeyError(
|
|
73
|
+
raise KeyError(ErrorMessages.INVALID_FIELD_UID)
|
|
73
74
|
return self
|
|
74
75
|
|
|
75
76
|
def include_reference(self, field_uid):
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized error messages for the Contentstack Python SDK.
|
|
3
|
+
All error messages should be defined here and imported where needed.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
class ErrorMessages:
|
|
7
|
+
# BaseQuery errors
|
|
8
|
+
INVALID_KEY = "Invalid key. Provide a valid key and try again."
|
|
9
|
+
INVALID_VALUE = "Invalid value. Provide a valid value and try again."
|
|
10
|
+
INVALID_KEY_OR_VALUE = "Invalid key or value. Provide valid values and try again."
|
|
11
|
+
|
|
12
|
+
# ContentType errors
|
|
13
|
+
INVALID_CONTENT_TYPE_UID = "Content type UID is invalid. Provide a valid UID and try again."
|
|
14
|
+
CONTENT_TYPE_UID_REQUIRED = "Content type UID is required. Provide a UID and try again."
|
|
15
|
+
|
|
16
|
+
# EntryQueryable errors
|
|
17
|
+
INVALID_FIELD_UID = "Invalid field UID. Provide a valid UID and try again."
|
|
18
|
+
|
|
19
|
+
# DeepMergeLp errors
|
|
20
|
+
INVALID_RESPONSE_TYPE = "Invalid input. entry_response and lp_response must be lists of dictionaries. Update the values and try again."
|
|
21
|
+
|
|
22
|
+
# Entry errors
|
|
23
|
+
INVALID_ENVIRONMENT = "Invalid environment. Provide a valid environment and try again."
|
|
24
|
+
INVALID_VERSION = "Invalid version. Provide a valid version and try again."
|
|
25
|
+
INVALID_KEY_VALUE_ARGS = "Invalid key or value arguments. Provide valid values and try again."
|
|
26
|
+
REQUESTING_FALLBACK = "Requesting fallback content for the specified locale."
|
|
27
|
+
INVALID_ENTRY_RESPONSE = "Invalid entry_response format. Provide a list of dictionaries, each containing entry data, and try again."
|
|
28
|
+
INVALID_LP_ENTRY = "Invalid lp_entry. Provide a list of dictionaries and try again."
|
|
29
|
+
MISSING_LIVE_PREVIEW_KEYS = "Missing required keys in live preview data. Provide all required keys and try again."
|
|
30
|
+
|
|
31
|
+
# Asset errors
|
|
32
|
+
INVALID_UID = "Invalid UID. Provide a valid UID and try again."
|
|
33
|
+
INVALID_PARAMS = "Invalid parameters. Provide valid parameters and try again."
|
|
34
|
+
|
|
35
|
+
# Controller errors
|
|
36
|
+
CONNECTION_FAILED = "Connection failed. Unable to connect to {url}. Error: {error}. Check your connection and try again."
|
|
37
|
+
OPERATION_FAILED = "Operation failed. An unexpected error occurred while making request to {url}. Error: {error}. Check your inputs and try again."
|
|
38
|
+
|
|
39
|
+
# Query errors
|
|
40
|
+
DEPRECATED_SEARCH = """The search() method is deprecated since version 1.7.0. Use regex() instead.
|
|
41
|
+
Example: query.regex("title", "^Blog.*") to search for titles starting with "Blog"."""
|
|
42
|
+
INVALID_JSON = "Invalid JSON. Error: {error}. Provide valid JSON and try again."
|
|
43
|
+
MISSING_ENTRIES_KEY = "Invalid response. The 'entries' key is missing. Include the 'entries' key and try again."
|
|
44
|
+
MISSING_ENTRY_KEY = "Invalid lp_response. The 'entry' key is missing. Include the 'entry' key and try again."
|
|
45
|
+
|
|
46
|
+
# Variants errors
|
|
47
|
+
ENTRY_UID_REQUIRED = "Missing entry UID. Provide a valid UID and try again."
|
|
48
|
+
|
|
49
|
+
# Stack errors
|
|
50
|
+
INVALID_STACK_UID = "Invalid UID. Provide a valid UID and try again."
|
|
51
|
+
|
|
52
|
+
# Utility errors
|
|
53
|
+
INVALID_PARAMS_TYPE = "Invalid params. Provide a dictionary and try again."
|
|
54
|
+
INVALID_URL_PARAMS = "Invalid input. Provide base_url as a string and params as a dictionary, then try again."
|
|
55
|
+
|
|
56
|
+
# Stack errors
|
|
57
|
+
INVALID_API_KEY = "Invalid API key. Provide a valid API key and try again."
|
|
58
|
+
INVALID_DELIVERY_TOKEN = "Invalid delivery token. Provide a valid delivery token and try again."
|
|
59
|
+
INVALID_ENVIRONMENT_TOKEN = "Invalid environment. Provide a valid environment and try again."
|
|
@@ -6,6 +6,7 @@ import enum
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
import warnings
|
|
9
|
+
from contentstack.error_messages import ErrorMessages
|
|
9
10
|
from urllib import parse
|
|
10
11
|
|
|
11
12
|
from contentstack.basequery import BaseQuery
|
|
@@ -44,8 +45,7 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
44
45
|
self.content_type_uid = content_type_uid
|
|
45
46
|
self.http_instance = http_instance
|
|
46
47
|
if self.content_type_uid is None:
|
|
47
|
-
raise PermissionError(
|
|
48
|
-
'You are not allowed here without content_type_uid')
|
|
48
|
+
raise PermissionError(ErrorMessages.CONTENT_TYPE_UID_REQUIRED)
|
|
49
49
|
self.base_url = f'{self.http_instance.endpoint}/content_types/{self.content_type_uid}/entries'
|
|
50
50
|
self.base_url = self.__get_base_url()
|
|
51
51
|
self.logger = logger or logging.getLogger(__name__)
|
|
@@ -54,8 +54,7 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
54
54
|
if endpoint is not None and endpoint.strip(): # .strip() removes leading/trailing whitespace
|
|
55
55
|
self.http_instance.endpoint = endpoint
|
|
56
56
|
if None in (self.http_instance, self.content_type_uid):
|
|
57
|
-
raise KeyError(
|
|
58
|
-
'Provide valid http_instance, content_type_uid or entry_uid')
|
|
57
|
+
raise KeyError(ErrorMessages.INVALID_KEY_OR_VALUE)
|
|
59
58
|
url = f'{self.http_instance.endpoint}/content_types/{self.content_type_uid}/entries'
|
|
60
59
|
|
|
61
60
|
return url
|
|
@@ -138,7 +137,7 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
138
137
|
>>> result = query.find()
|
|
139
138
|
-------------------------------------
|
|
140
139
|
"""
|
|
141
|
-
warnings.warn(
|
|
140
|
+
warnings.warn(ErrorMessages.DEPRECATED_SEARCH)
|
|
142
141
|
if value is not None:
|
|
143
142
|
self.query_params["typeahead"] = value
|
|
144
143
|
return self
|
|
@@ -170,7 +169,7 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
170
169
|
self.query_params["query"] = {
|
|
171
170
|
key: {"$in_query": query_object.parameters}}
|
|
172
171
|
else:
|
|
173
|
-
raise ValueError(
|
|
172
|
+
raise ValueError(ErrorMessages.INVALID_KEY_OR_VALUE)
|
|
174
173
|
return self
|
|
175
174
|
|
|
176
175
|
def where_not_in(self, key, query_object):
|
|
@@ -200,7 +199,7 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
200
199
|
self.query_params["query"] = {
|
|
201
200
|
key: {"$nin_query": query_object.parameters}}
|
|
202
201
|
else:
|
|
203
|
-
raise ValueError(
|
|
202
|
+
raise ValueError(ErrorMessages.INVALID_KEY_OR_VALUE)
|
|
204
203
|
return self
|
|
205
204
|
|
|
206
205
|
def include_fallback(self):
|
|
@@ -330,14 +329,14 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
330
329
|
try:
|
|
331
330
|
response = json.loads(response) # Convert JSON string to dictionary
|
|
332
331
|
except json.JSONDecodeError as e:
|
|
333
|
-
print(
|
|
332
|
+
print(ErrorMessages.INVALID_JSON.format(error=str(e)))
|
|
334
333
|
return {"error": "Invalid JSON response"} # Return an error dictionary
|
|
335
334
|
|
|
336
335
|
if self.http_instance.live_preview is not None and 'errors' not in response:
|
|
337
336
|
if 'entries' in response:
|
|
338
337
|
self.http_instance.live_preview['entry_response'] = response['entries'][0] # Get first entry
|
|
339
338
|
else:
|
|
340
|
-
print(
|
|
339
|
+
print(ErrorMessages.MISSING_ENTRIES_KEY)
|
|
341
340
|
return {"error": "'entries' key missing in response"}
|
|
342
341
|
return self._merged_response()
|
|
343
342
|
return response
|
|
@@ -356,7 +355,7 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
356
355
|
if 'entry' in lp_resp:
|
|
357
356
|
self.http_instance.live_preview['lp_response'] = {'entry': lp_resp['entry']} # Extract entry
|
|
358
357
|
else:
|
|
359
|
-
print(
|
|
358
|
+
print(ErrorMessages.MISSING_ENTRY_KEY)
|
|
360
359
|
return None
|
|
361
360
|
return None
|
|
362
361
|
|
|
@@ -368,4 +367,4 @@ class Query(BaseQuery, EntryQueryable):
|
|
|
368
367
|
merged_response = DeepMergeMixin(entry_response, lp_response)
|
|
369
368
|
return merged_response # Return the merged dictionary
|
|
370
369
|
|
|
371
|
-
raise ValueError(
|
|
370
|
+
raise ValueError(ErrorMessages.MISSING_LIVE_PREVIEW_KEYS)
|
|
@@ -2,6 +2,7 @@ import enum
|
|
|
2
2
|
import logging
|
|
3
3
|
from urllib import parse
|
|
4
4
|
from urllib3.util import Retry
|
|
5
|
+
from contentstack.error_messages import ErrorMessages
|
|
5
6
|
|
|
6
7
|
from contentstack.asset import Asset
|
|
7
8
|
from contentstack.assetquery import AssetQuery
|
|
@@ -20,9 +21,11 @@ class ContentstackRegion(enum.Enum):
|
|
|
20
21
|
"""
|
|
21
22
|
US = 'us'
|
|
22
23
|
EU = 'eu'
|
|
24
|
+
AU = 'au'
|
|
23
25
|
AZURE_NA = 'azure-na'
|
|
24
26
|
AZURE_EU = 'azure-eu'
|
|
25
27
|
GCP_NA = 'gcp-na'
|
|
28
|
+
GCP_EU = 'gcp-eu'
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
class Stack:
|
|
@@ -110,26 +113,24 @@ class Stack:
|
|
|
110
113
|
|
|
111
114
|
def _validate_stack(self):
|
|
112
115
|
if self.api_key is None or self.api_key == '':
|
|
113
|
-
raise PermissionError(
|
|
114
|
-
'You are not permitted to the stack without valid APIKey'
|
|
115
|
-
)
|
|
116
|
+
raise PermissionError(ErrorMessages.INVALID_API_KEY)
|
|
116
117
|
if self.delivery_token is None or self.delivery_token == "":
|
|
117
|
-
raise PermissionError(
|
|
118
|
-
'You are not permitted to the stack without valid Delivery Token'
|
|
119
|
-
)
|
|
118
|
+
raise PermissionError(ErrorMessages.INVALID_DELIVERY_TOKEN)
|
|
120
119
|
if self.environment is None or self.environment == "":
|
|
121
|
-
raise PermissionError(
|
|
122
|
-
'You are not permitted to the stack without valid Environment'
|
|
123
|
-
)
|
|
120
|
+
raise PermissionError(ErrorMessages.INVALID_ENVIRONMENT_TOKEN)
|
|
124
121
|
|
|
125
122
|
if self.region.value == 'eu' and self.host == DEFAULT_HOST:
|
|
126
123
|
self.host = 'eu-cdn.contentstack.com'
|
|
124
|
+
elif self.region.value == 'au' and self.host == DEFAULT_HOST:
|
|
125
|
+
self.host = 'au-cdn.contentstack.com'
|
|
127
126
|
elif self.region.value == 'azure-na' and self.host == DEFAULT_HOST:
|
|
128
127
|
self.host = 'azure-na-cdn.contentstack.com'
|
|
129
128
|
elif self.region.value == 'azure-eu' and self.host == DEFAULT_HOST:
|
|
130
129
|
self.host = 'azure-eu-cdn.contentstack.com'
|
|
131
130
|
elif self.region.value == 'gcp-na' and self.host == DEFAULT_HOST:
|
|
132
131
|
self.host = 'gcp-na-cdn.contentstack.com'
|
|
132
|
+
elif self.region.value == 'gcp-eu' and self.host == DEFAULT_HOST:
|
|
133
|
+
self.host = 'gcp-eu-cdn.contentstack.com'
|
|
133
134
|
elif self.region.value != 'us':
|
|
134
135
|
self.host = f'{self.region.value}-{DEFAULT_HOST}'
|
|
135
136
|
self.endpoint = f'https://{self.host}/{self.version}'
|
|
@@ -238,7 +239,7 @@ class Stack:
|
|
|
238
239
|
-----------------------------
|
|
239
240
|
"""
|
|
240
241
|
if uid is None or not isinstance(uid, str):
|
|
241
|
-
raise KeyError(
|
|
242
|
+
raise KeyError(ErrorMessages.INVALID_UID)
|
|
242
243
|
return Asset(self.http_instance, uid=uid)
|
|
243
244
|
|
|
244
245
|
def asset_query(self):
|
|
@@ -7,6 +7,7 @@ Copyright 2019 Contentstack. All rights reserved.
|
|
|
7
7
|
import json
|
|
8
8
|
import logging
|
|
9
9
|
from urllib.parse import urlencode
|
|
10
|
+
from contentstack.error_messages import ErrorMessages
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def setup_logging(logging_type=logging.INFO, filename='app.log'):
|
|
@@ -65,7 +66,7 @@ class Utils:
|
|
|
65
66
|
:return: Encoded URL query string
|
|
66
67
|
"""
|
|
67
68
|
if not isinstance(params, dict):
|
|
68
|
-
raise ValueError(
|
|
69
|
+
raise ValueError(ErrorMessages.INVALID_PARAMS_TYPE)
|
|
69
70
|
return urlencode(params, doseq=True)
|
|
70
71
|
|
|
71
72
|
@staticmethod
|
|
@@ -79,7 +80,7 @@ class Utils:
|
|
|
79
80
|
:return: Complete URL
|
|
80
81
|
"""
|
|
81
82
|
if not isinstance(base_url, str) or not isinstance(params, dict):
|
|
82
|
-
raise ValueError(
|
|
83
|
+
raise ValueError(ErrorMessages.INVALID_URL_PARAMS)
|
|
83
84
|
|
|
84
85
|
if 'query' in params and not skip_encoding:
|
|
85
86
|
params["query"] = json.dumps(params["query"], separators=(',', ':'))
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from urllib import parse
|
|
3
|
+
from contentstack.error_messages import ErrorMessages
|
|
3
4
|
|
|
4
5
|
from contentstack.entryqueryable import EntryQueryable
|
|
5
6
|
|
|
@@ -74,7 +75,7 @@ class Variants(EntryQueryable):
|
|
|
74
75
|
:return: Entry, so you can chain this call.
|
|
75
76
|
"""
|
|
76
77
|
if self.entry_uid is None:
|
|
77
|
-
raise ValueError(
|
|
78
|
+
raise ValueError(ErrorMessages.ENTRY_UID_REQUIRED)
|
|
78
79
|
else:
|
|
79
80
|
headers = self.http_instance.headers.copy() # Create a local copy of headers
|
|
80
81
|
if isinstance(self.variant_uid, str):
|
|
@@ -102,14 +102,14 @@ class TestAsset(unittest.TestCase):
|
|
|
102
102
|
try:
|
|
103
103
|
self.asset = self.stack.asset(None)
|
|
104
104
|
except Exception as inst:
|
|
105
|
-
self.assertEqual('
|
|
105
|
+
self.assertEqual('Invalid UID. Provide a valid UID and try again.', inst.args[0])
|
|
106
106
|
|
|
107
107
|
def test_072_check_none_coverage_test(self):
|
|
108
108
|
try:
|
|
109
109
|
self.asset = self.stack.asset(uid=ASSET_UID)
|
|
110
110
|
self.asset.params(2, 'value')
|
|
111
111
|
except Exception as inst:
|
|
112
|
-
self.assertEqual('
|
|
112
|
+
self.assertEqual('Invalid parameters. Provide valid parameters and try again.', inst.args[0])
|
|
113
113
|
|
|
114
114
|
def test_08_support_include_fallback(self):
|
|
115
115
|
self.asset = self.stack.asset(uid=ASSET_UID)
|
|
@@ -91,7 +91,7 @@ class TestEntry(unittest.TestCase):
|
|
|
91
91
|
self.assertEqual(None, result['uid'])
|
|
92
92
|
except KeyError as e:
|
|
93
93
|
if hasattr(e, 'message'):
|
|
94
|
-
self.assertEqual("Invalid
|
|
94
|
+
self.assertEqual("Invalid field UID. Provide a valid UID and try again.", e.args[0])
|
|
95
95
|
|
|
96
96
|
def test_entry_queryable_excepts(self):
|
|
97
97
|
try:
|
|
@@ -100,7 +100,7 @@ class TestEntry(unittest.TestCase):
|
|
|
100
100
|
self.assertEqual(None, result['uid'])
|
|
101
101
|
except KeyError as e:
|
|
102
102
|
if hasattr(e, 'message'):
|
|
103
|
-
self.assertEqual("Invalid
|
|
103
|
+
self.assertEqual("Invalid field UID. Provide a valid UID and try again.", e.args[0])
|
|
104
104
|
|
|
105
105
|
def test_16_entry_queryable_include_content_type(self):
|
|
106
106
|
entry = self.stack.content_type('faq').entry(FAQ_UID).include_content_type()
|
|
@@ -36,6 +36,16 @@ class TestStack(unittest.TestCase):
|
|
|
36
36
|
API_KEY, DELIVERY_TOKEN, ENVIRONMENT, region=ContentstackRegion.GCP_NA)
|
|
37
37
|
self.assertEqual('gcp-na-cdn.contentstack.com', stack_region.host)
|
|
38
38
|
|
|
39
|
+
def test_02_stack_au_region(self):
|
|
40
|
+
stack_region = contentstack.Stack(
|
|
41
|
+
API_KEY, DELIVERY_TOKEN, ENVIRONMENT, region=ContentstackRegion.AU)
|
|
42
|
+
self.assertEqual('au-cdn.contentstack.com', stack_region.host)
|
|
43
|
+
|
|
44
|
+
def test_02_stack_gcp_eu_region(self):
|
|
45
|
+
stack_region = contentstack.Stack(
|
|
46
|
+
API_KEY, DELIVERY_TOKEN, ENVIRONMENT, region=ContentstackRegion.GCP_EU)
|
|
47
|
+
self.assertEqual('gcp-eu-cdn.contentstack.com', stack_region.host)
|
|
48
|
+
|
|
39
49
|
def test_03_stack_endpoint(self):
|
|
40
50
|
self.assertEqual(f"https://{config.HOST}/v3",
|
|
41
51
|
self.stack.endpoint)
|
|
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
|