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.
Files changed (38) hide show
  1. {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/PKG-INFO +1 -1
  2. {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/SOURCES.txt +1 -0
  3. {contentstack-2.3.0 → contentstack-2.4.1}/PKG-INFO +1 -1
  4. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/__init__.py +1 -1
  5. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/asset.py +3 -2
  6. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/basequery.py +10 -5
  7. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/contenttype.py +5 -7
  8. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/controller.py +3 -2
  9. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/deep_merge_lp.py +3 -1
  10. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/entry.py +9 -9
  11. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/entryqueryable.py +3 -2
  12. contentstack-2.4.1/contentstack/error_messages.py +59 -0
  13. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/query.py +10 -11
  14. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/stack.py +11 -10
  15. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/utility.py +3 -2
  16. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/variants.py +2 -1
  17. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_assets.py +2 -2
  18. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_entry.py +2 -2
  19. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_stack.py +10 -0
  20. {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/dependency_links.txt +0 -0
  21. {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/not-zip-safe +0 -0
  22. {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/requires.txt +0 -0
  23. {contentstack-2.3.0 → contentstack-2.4.1}/Contentstack.egg-info/top_level.txt +0 -0
  24. {contentstack-2.3.0 → contentstack-2.4.1}/LICENSE +0 -0
  25. {contentstack-2.3.0 → contentstack-2.4.1}/README.md +0 -0
  26. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/assetquery.py +0 -0
  27. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/globalfields.py +0 -0
  28. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/https_connection.py +0 -0
  29. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/image_transform.py +0 -0
  30. {contentstack-2.3.0 → contentstack-2.4.1}/contentstack/taxonomy.py +0 -0
  31. {contentstack-2.3.0 → contentstack-2.4.1}/setup.cfg +0 -0
  32. {contentstack-2.3.0 → contentstack-2.4.1}/setup.py +0 -0
  33. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_early_fetch.py +0 -0
  34. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_early_find.py +0 -0
  35. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_global_fields.py +0 -0
  36. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_live_preview.py +0 -0
  37. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_query.py +0 -0
  38. {contentstack-2.3.0 → contentstack-2.4.1}/tests/test_taxonomies.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Contentstack
3
- Version: 2.3.0
3
+ Version: 2.4.1
4
4
  Summary: Contentstack is a headless CMS with an API-first approach.
5
5
  Home-page: https://github.com/contentstack/contentstack-python
6
6
  Author: Contentstack
@@ -16,6 +16,7 @@ contentstack/controller.py
16
16
  contentstack/deep_merge_lp.py
17
17
  contentstack/entry.py
18
18
  contentstack/entryqueryable.py
19
+ contentstack/error_messages.py
19
20
  contentstack/globalfields.py
20
21
  contentstack/https_connection.py
21
22
  contentstack/image_transform.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Contentstack
3
- Version: 2.3.0
3
+ Version: 2.4.1
4
4
  Summary: Contentstack is a headless CMS with an API-first approach.
5
5
  Home-page: https://github.com/contentstack/contentstack-python
6
6
  Author: Contentstack
@@ -22,7 +22,7 @@ __all__ = (
22
22
  __title__ = 'contentstack-delivery-python'
23
23
  __author__ = 'contentstack'
24
24
  __status__ = 'debug'
25
- __version__ = 'v2.3.0'
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('Please provide valid uid')
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('Kindly provide valid params')
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 None in (key, value):
141
- raise KeyError('Invalid key or value')
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 None in (key, value):
168
- raise KeyError('Invalid key or value')
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('Kindly provide valid key')
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('Please provide valid content_type_uid')
50
+ raise PermissionError(ErrorMessages.INVALID_CONTENT_TYPE_UID)
50
51
  if entry_uid is None:
51
- raise PermissionError(json.dumps({
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('Kindly provide content_type_uid')
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': f"Failed to connect to {url}: {str(e)}",
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': f"An unexpected error while making request to {url}, '400', {str(e)}",
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("Both entry_response and lp_response must be lists of dictionaries")
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('Kindly provide a valid environment')
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('Kindly provide a valid version')
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('Kindly provide valid key and value arguments')
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('Requesting fallback....')
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(f"entry_response must be a list of dictionaries. Got: {entry_response}")
220
+ raise TypeError(ErrorMessages.INVALID_ENTRY_RESPONSE)
221
221
  if not all(isinstance(item, dict) for item in lp_entry):
222
- raise TypeError(f"lp_entry must be a list of dictionaries. Got: {lp_entry}")
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("Missing required keys in live_preview data")
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("Invalid field_uid provided")
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("Invalid field_uid provided")
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('deprecated in 1.7.0, Use regex function instead')
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('Invalid Key or Value provided')
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('Invalid Key or Value provided')
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(f"JSON decode error: {e}")
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(f"Error: 'entries' key missing in response: {response}")
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(f"Warning: Missing 'entry' key in lp_response: {lp_resp}")
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("Missing required keys in live_preview data")
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('Please provide a valid uid')
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("params must be a dictionary")
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("base_url must be a string and params must be a dictionary")
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("entry_uid is required")
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('Please provide a valid uid', inst.args[0])
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('Kindly provide valid params', inst.args[0])
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 field_UID provided", e.args[0])
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 field_UID provided", e.args[0])
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