Contentstack 2.4.1__py3-none-any.whl → 2.6.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.
contentstack/__init__.py CHANGED
@@ -6,23 +6,43 @@ from unintentionally hiding valid modules that occur later on the module search
6
6
  from .entry import Entry
7
7
  from .asset import Asset
8
8
  from .contenttype import ContentType
9
+ from .endpoint import Endpoint
9
10
  from .https_connection import HTTPSConnection
10
11
  from contentstack.stack import Stack
11
12
  from .utility import Utils
13
+ from .region_refresh import refresh_regions
12
14
 
13
15
  __all__ = (
14
16
  "Entry",
15
17
  "Asset",
16
18
  "ContentType",
19
+ "Endpoint",
17
20
  "HTTPSConnection",
18
21
  "Stack",
19
- "Utils"
22
+ "Utils",
23
+ "refresh_regions",
20
24
  )
21
25
 
26
+
27
+ def get_contentstack_endpoint(region='us', service='', omit_https=False):
28
+ """
29
+ Resolve a Contentstack service endpoint URL for a given region.
30
+
31
+ Proxy to :class:`Endpoint.get_contentstack_endpoint` for convenience —
32
+ mirrors ``Contentstack::getContentstackEndpoint()`` in the PHP SDK.
33
+
34
+ :param region: Region ID or alias ('us', 'eu', 'azure-na', 'gcp-eu', ...).
35
+ :param service: Service key ('contentDelivery', 'contentManagement', ...).
36
+ When empty, returns a dict of all endpoints for the region.
37
+ :param omit_https: When True, strips 'https://' from the returned URL(s).
38
+ :returns: str when service is provided, dict[str,str] otherwise.
39
+ """
40
+ return Endpoint.get_contentstack_endpoint(region, service, omit_https)
41
+
22
42
  __title__ = 'contentstack-delivery-python'
23
43
  __author__ = 'contentstack'
24
44
  __status__ = 'debug'
25
- __version__ = 'v2.4.1'
45
+ __version__ = 'v2.6.0'
26
46
  __endpoint__ = 'cdn.contentstack.io'
27
47
  __email__ = 'support@contentstack.com'
28
48
  __developer_email__ = 'mobile@contentstack.com'
contentstack/asset.py CHANGED
@@ -17,6 +17,7 @@ class Asset:
17
17
  self.__uid = uid
18
18
  if self.__uid is None or self.__uid.strip() == 0:
19
19
  raise KeyError(ErrorMessages.INVALID_UID)
20
+ self.uid = uid
20
21
  self.base_url = f'{self.http_instance.endpoint}/assets/{self.__uid}'
21
22
  if 'environment' in self.http_instance.headers:
22
23
  self.asset_params['environment'] = self.http_instance.headers['environment']
@@ -117,6 +118,35 @@ class Asset:
117
118
  self.asset_params['include_fallback'] = "true"
118
119
  return self
119
120
 
121
+ def asset_fields(self, *field_names):
122
+ r"""Include specific asset fields in the response.
123
+ Supported values: user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups.
124
+ Pass one or more field names. Can be called multiple times to add more fields.
125
+
126
+ :param field_names: One or more asset field names (user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups)
127
+ :return: `Asset`, so we can chain the call
128
+ ----------------------------
129
+ Example::
130
+ >>> import contentstack
131
+ >>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
132
+ >>> asset = stack.asset(uid='asset_uid')
133
+ >>> result = asset.asset_fields('user_defined_fields', 'visual_markups').fetch()
134
+ ----------------------------
135
+ """
136
+ if field_names:
137
+ values = []
138
+ for name in field_names:
139
+ if isinstance(name, (list, tuple)):
140
+ values.extend(str(v) for v in name)
141
+ else:
142
+ values.append(str(name))
143
+ if values:
144
+ existing = self.asset_params.get('asset_fields[]', [])
145
+ if not isinstance(existing, list):
146
+ existing = [existing]
147
+ self.asset_params['asset_fields[]'] = existing + values
148
+ return self
149
+
120
150
  def fetch(self):
121
151
  r"""This call fetches the latest version of a specific asset of a particular stack.
122
152
  :return: json response of asset
@@ -157,6 +157,36 @@ class AssetQuery(BaseQuery):
157
157
  self.asset_query_params['locale'] = locale
158
158
  return self
159
159
 
160
+ def asset_fields(self, *field_names):
161
+ r"""Include specific asset fields in the response.
162
+ Supported values: user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups.
163
+ Pass one or more field names. Can be called multiple times to add more fields.
164
+
165
+ :param field_names: One or more asset field names (user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups)
166
+ :return: AssetQuery: so we can chain the call
167
+
168
+ -----------------------------
169
+ [Example]:
170
+
171
+ >>> import contentstack
172
+ >>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
173
+ >>> result = stack.asset_query().asset_fields('user_defined_fields', 'visual_markups').find()
174
+ ------------------------------
175
+ """
176
+ if field_names:
177
+ values = []
178
+ for name in field_names:
179
+ if isinstance(name, (list, tuple)):
180
+ values.extend(str(v) for v in name)
181
+ else:
182
+ values.append(str(name))
183
+ if values:
184
+ existing = self.asset_query_params.get('asset_fields[]', [])
185
+ if not isinstance(existing, list):
186
+ existing = [existing]
187
+ self.asset_query_params['asset_fields[]'] = existing + values
188
+ return self
189
+
160
190
  def find(self):
161
191
  r"""This call fetches the list of all the assets of a particular stack.
162
192
  It also returns the content of each asset in JSON format.
@@ -7,6 +7,7 @@ content type.
7
7
 
8
8
  # ************* Module ContentType **************
9
9
  # Your code has been rated at 10.00/10 by pylint
10
+ from __future__ import annotations
10
11
  import json
11
12
  import logging
12
13
  from urllib import parse
@@ -0,0 +1,180 @@
1
+ """
2
+ Endpoint — Contentstack region-to-URL resolver.
3
+
4
+ Resolves Contentstack service endpoint URLs for any supported region.
5
+ Region data is loaded from contentstack/assets/regions.json (bundled) and
6
+ cached in-memory for the lifetime of the process. When the bundled file is
7
+ absent the class attempts a live download from the Contentstack CDN so the
8
+ SDK continues to work even when the file was not created during installation.
9
+ """
10
+
11
+ import json
12
+ import os
13
+ import re
14
+
15
+ REGIONS_URL = 'https://artifacts.contentstack.com/regions.json'
16
+
17
+
18
+ class Endpoint:
19
+ """
20
+ Resolves Contentstack service endpoint URLs for any supported region.
21
+
22
+ Usage::
23
+
24
+ from contentstack.endpoint import Endpoint
25
+
26
+ # Single service URL
27
+ url = Endpoint.get_contentstack_endpoint('eu', 'contentDelivery')
28
+ # 'https://eu-cdn.contentstack.com'
29
+
30
+ # All services for a region
31
+ endpoints = Endpoint.get_contentstack_endpoint('azure-na')
32
+ # {'contentDelivery': 'https://...', 'contentManagement': 'https://...', ...}
33
+
34
+ # Strip scheme (useful when setting host directly)
35
+ host = Endpoint.get_contentstack_endpoint('gcp-eu', 'contentDelivery', omit_https=True)
36
+ # 'gcp-eu-cdn.contentstack.com'
37
+ """
38
+
39
+ _regions_data = None # in-memory cache — shared across all instances
40
+
41
+ @staticmethod
42
+ def get_contentstack_endpoint(region='us', service='', omit_https=False):
43
+ """
44
+ Resolve a Contentstack service endpoint URL for a given region.
45
+
46
+ :param region: Region ID or alias ('us', 'eu', 'azure-na', 'gcp-eu', etc.).
47
+ Defaults to 'us' (AWS North America).
48
+ :param service: Service key ('contentDelivery', 'contentManagement', ...).
49
+ When empty, returns a dict of all endpoints for the region.
50
+ :param omit_https: When True, strips 'https://' prefix from returned URL(s).
51
+ :returns: str when service is provided, dict[str,str] otherwise.
52
+ :raises ValueError: When region is empty, unknown, or service is not found.
53
+ :raises RuntimeError: When regions.json cannot be read or parsed.
54
+ """
55
+ if not region:
56
+ raise ValueError('Empty region provided. Please put valid region.')
57
+
58
+ data = Endpoint._load_regions()
59
+ normalized = region.strip().lower()
60
+ region_row = Endpoint._find_region(data['regions'], normalized)
61
+
62
+ if region_row is None:
63
+ raise ValueError(f'Invalid region: {region}')
64
+
65
+ if service:
66
+ if service not in region_row['endpoints']:
67
+ raise ValueError(
68
+ f'Service "{service}" not found for region "{region_row["id"]}"'
69
+ )
70
+ url = region_row['endpoints'][service]
71
+ return Endpoint._strip_https(url) if omit_https else url
72
+
73
+ endpoints = region_row['endpoints']
74
+ if omit_https:
75
+ return {k: Endpoint._strip_https(v) for k, v in endpoints.items()}
76
+ return dict(endpoints)
77
+
78
+ @staticmethod
79
+ def _load_regions():
80
+ """
81
+ Load and cache regions.json.
82
+
83
+ Resolution order:
84
+ 1. In-memory static cache (zero I/O after first call)
85
+ 2. contentstack/assets/regions.json on disk (written by download script)
86
+ 3. Live download from artifacts.contentstack.com (fallback)
87
+ """
88
+ if Endpoint._regions_data is not None:
89
+ return Endpoint._regions_data
90
+
91
+ assets_dir = os.path.join(os.path.dirname(__file__), 'assets')
92
+ path = os.path.join(assets_dir, 'regions.json')
93
+
94
+ if not os.path.exists(path):
95
+ Endpoint._download_and_save(path)
96
+
97
+ if not os.path.exists(path):
98
+ raise RuntimeError(
99
+ 'contentstack: regions.json not found and could not be downloaded. '
100
+ 'Run "python scripts/download_regions.py" and ensure network access.'
101
+ )
102
+
103
+ try:
104
+ with open(path, 'r', encoding='utf-8') as f:
105
+ decoded = json.load(f)
106
+ except (OSError, json.JSONDecodeError) as exc:
107
+ raise RuntimeError(
108
+ f'contentstack: Could not read or parse regions.json: {exc}. '
109
+ 'Run "python scripts/download_regions.py" to re-download it.'
110
+ ) from exc
111
+
112
+ if not isinstance(decoded, dict) or 'regions' not in decoded:
113
+ raise RuntimeError(
114
+ 'contentstack: regions.json is corrupt. '
115
+ 'Run "python scripts/download_regions.py" to re-download it.'
116
+ )
117
+
118
+ Endpoint._regions_data = decoded
119
+ return Endpoint._regions_data
120
+
121
+ @staticmethod
122
+ def _download_and_save(dest):
123
+ """
124
+ Download regions.json from the Contentstack CDN and save to disk.
125
+ Uses the requests library (already an SDK dependency).
126
+ Silent on failure — the caller decides whether a missing file is fatal.
127
+
128
+ :param dest: Absolute path to write the file to.
129
+ """
130
+ os.makedirs(os.path.dirname(dest), exist_ok=True)
131
+
132
+ try:
133
+ import requests
134
+ response = requests.get(REGIONS_URL, timeout=30)
135
+ response.raise_for_status()
136
+ data = response.text
137
+ except Exception: # noqa: BLE001
138
+ return
139
+
140
+ try:
141
+ decoded = json.loads(data)
142
+ except json.JSONDecodeError:
143
+ return
144
+
145
+ if isinstance(decoded, dict) and 'regions' in decoded:
146
+ try:
147
+ with open(dest, 'w', encoding='utf-8') as f:
148
+ f.write(data)
149
+ except OSError:
150
+ pass
151
+
152
+ @staticmethod
153
+ def _find_region(regions, input_str):
154
+ """
155
+ Find a region entry by its id or any alias (case-insensitive).
156
+
157
+ Two-pass: exact id match first, then alias[] scan — mirrors PHP implementation.
158
+
159
+ :param regions: list of region dicts from regions.json
160
+ :param input_str: already-lowercased input
161
+ :returns: region dict or None
162
+ """
163
+ for row in regions:
164
+ if row['id'] == input_str:
165
+ return row
166
+ for row in regions:
167
+ for alias in row.get('alias', []):
168
+ if alias.lower() == input_str:
169
+ return row
170
+ return None
171
+
172
+ @staticmethod
173
+ def _strip_https(url):
174
+ """Strip the https:// (or http://) scheme from a URL string."""
175
+ return re.sub(r'^https?://', '', url)
176
+
177
+ @staticmethod
178
+ def reset_cache():
179
+ """Reset the internal region cache. Intended for testing only."""
180
+ Endpoint._regions_data = None
contentstack/entry.py CHANGED
@@ -3,6 +3,7 @@ The Get a single entry request fetches a particular entry of a content type.
3
3
  API Reference: https://www.contentstack.com/docs/developers/apis/content-delivery-api/#single-entry
4
4
  """
5
5
  #min-similarity-lines=10
6
+ from __future__ import annotations
6
7
  import logging
7
8
  from urllib import parse
8
9
  from contentstack.error_messages import ErrorMessages
@@ -54,6 +55,25 @@ class Entry(EntryQueryable):
54
55
  self.http_instance.headers['environment'] = environment
55
56
  return self
56
57
 
58
+ def remove_environment(self):
59
+ """Removes environment from the request headers
60
+ :return: Entry, so we can chain the call
61
+ -------------------------------
62
+ Example::
63
+
64
+ >>> import contentstack
65
+ >>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
66
+ >>> content_type = stack.content_type('content_type_uid')
67
+ >>> entry = content_type.entry(uid='entry_uid')
68
+ >>> entry = entry.environment('test')
69
+ >>> entry = entry.remove_environment()
70
+ >>> result = entry.fetch()
71
+ -------------------------------
72
+ """
73
+ if 'environment' in self.http_instance.headers:
74
+ self.http_instance.headers.pop('environment')
75
+ return self
76
+
57
77
  def version(self, version):
58
78
  """When no version is specified, it returns the latest version
59
79
  To retrieve a specific version, specify the version number under this parameter.
@@ -96,6 +116,9 @@ class Entry(EntryQueryable):
96
116
  """
97
117
  if None in (key, value) and not isinstance(key, str):
98
118
  raise ValueError(ErrorMessages.INVALID_KEY_VALUE_ARGS)
119
+ # Convert non-string values to strings
120
+ if not isinstance(value, str):
121
+ value = str(value)
99
122
  self.entry_param[key] = value
100
123
  return self
101
124
 
@@ -154,6 +177,26 @@ class Entry(EntryQueryable):
154
177
  self.entry_param['include_embedded_items[]'] = "BASE"
155
178
  return self
156
179
 
180
+ def asset_fields(self, *field_names):
181
+ """Include specific asset fields in the response.
182
+ Supported values: user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups.
183
+ Pass one or more field names. Can be called multiple times to add more fields.
184
+
185
+ :param field_names: One or more asset field names (user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups)
186
+ :return: Entry, so we can chain the call
187
+ ----------------------------
188
+ Example::
189
+
190
+ >>> import contentstack
191
+ >>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
192
+ >>> content_type = stack.content_type('content_type_uid')
193
+ >>> entry = content_type.entry(uid='entry_uid')
194
+ >>> entry = entry.asset_fields('user_defined_fields', 'visual_markups')
195
+ >>> result = entry.fetch()
196
+ ----------------------------
197
+ """
198
+ return super().asset_fields(*field_names)
199
+
157
200
  def __get_base_url(self, endpoint=''):
158
201
  if endpoint is not None and endpoint.strip(): # .strip() removes leading/trailing whitespace
159
202
  self.http_instance.endpoint = endpoint
@@ -167,6 +167,45 @@ class EntryQueryable:
167
167
  self.entry_queryable_param['include_metadata'] = 'true'
168
168
  return self
169
169
 
170
+ def asset_fields(self, *field_names):
171
+ """
172
+ Include specific asset fields in the response.
173
+ Supported values: user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups.
174
+ Pass one or more field names. Can be called multiple times to add more fields.
175
+
176
+ :param field_names: One or more asset field names (user_defined_fields, embedded_metadata, ai_generated_metadata, visual_markups)
177
+ :return: self: so you can chain this call.
178
+
179
+ Example (Query):
180
+ >>> import contentstack
181
+ >>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
182
+ >>> content_type = stack.content_type('content_type_uid')
183
+ >>> query = content_type.query()
184
+ >>> query = query.asset_fields('user_defined_fields', 'visual_markups')
185
+ >>> result = query.find()
186
+
187
+ Example (Entry):
188
+ >>> import contentstack
189
+ >>> stack = contentstack.Stack('api_key', 'delivery_token', 'environment')
190
+ >>> content_type = stack.content_type('content_type_uid')
191
+ >>> entry = content_type.entry('entry_uid')
192
+ >>> entry = entry.asset_fields('user_defined_fields', 'visual_markups')
193
+ >>> result = entry.fetch()
194
+ """
195
+ if field_names:
196
+ values = []
197
+ for name in field_names:
198
+ if isinstance(name, (list, tuple)):
199
+ values.extend(str(v) for v in name)
200
+ else:
201
+ values.append(str(name))
202
+ if values:
203
+ existing = self.entry_queryable_param.get('asset_fields[]', [])
204
+ if not isinstance(existing, list):
205
+ existing = [existing]
206
+ self.entry_queryable_param['asset_fields[]'] = existing + values
207
+ return self
208
+
170
209
  def add_param(self, key: str, value: str):
171
210
  """
172
211
  This method adds key and value to an Entry.
@@ -0,0 +1,81 @@
1
+ """
2
+ Utility to pull the latest regions.json from the Contentstack CDN and
3
+ overwrite the bundled copy at contentstack/assets/regions.json.
4
+
5
+ Exposed as a package-level function so tooling and CI pipelines can call it
6
+ programmatically instead of invoking the script directly:
7
+
8
+ from contentstack import refresh_regions
9
+ refresh_regions()
10
+ """
11
+
12
+ import json
13
+ import os
14
+ import sys
15
+ import urllib.request
16
+
17
+ _REGIONS_URL = "https://artifacts.contentstack.com/regions.json"
18
+ _ASSET_PATH = os.path.join(os.path.dirname(__file__), "assets", "regions.json")
19
+
20
+
21
+ def refresh_regions(
22
+ url: str = _REGIONS_URL,
23
+ dest: str = _ASSET_PATH,
24
+ *,
25
+ timeout: int = 30,
26
+ silent: bool = False,
27
+ ) -> dict:
28
+ """
29
+ Download the latest regions manifest from the Contentstack CDN and write
30
+ it to the bundled assets file so all consumers get the update.
31
+
32
+ @param url - URL to fetch regions.json from (defaults to Contentstack CDN)
33
+ @param dest - Destination file path (defaults to contentstack/assets/regions.json)
34
+ @param timeout - HTTP request timeout in seconds
35
+ @param silent - Suppress progress output when True
36
+ @returns The parsed regions dict on success
37
+ @raises RuntimeError on download failure, invalid JSON, or unexpected schema
38
+ """
39
+ dest = os.path.normpath(dest)
40
+
41
+ if not silent:
42
+ print(f"Fetching {url} ...")
43
+
44
+ try:
45
+ with urllib.request.urlopen(url, timeout=timeout) as resp:
46
+ data = resp.read().decode("utf-8")
47
+ except Exception as exc:
48
+ raise RuntimeError(f"Could not download regions.json: {exc}") from exc
49
+
50
+ try:
51
+ decoded = json.loads(data)
52
+ except json.JSONDecodeError as exc:
53
+ raise RuntimeError(f"Downloaded content is not valid JSON: {exc}") from exc
54
+
55
+ if not isinstance(decoded, dict) or "regions" not in decoded:
56
+ raise RuntimeError("Downloaded JSON does not contain a 'regions' key.")
57
+
58
+ os.makedirs(os.path.dirname(dest), exist_ok=True)
59
+ with open(dest, "w", encoding="utf-8") as fh:
60
+ json.dump(decoded, fh, indent=2, ensure_ascii=False)
61
+ fh.write("\n")
62
+
63
+ region_count = len(decoded["regions"])
64
+ if not silent:
65
+ print(f"OK: Wrote {region_count} regions to {dest}")
66
+
67
+ return decoded
68
+
69
+
70
+ def _cli_main() -> int:
71
+ """Entry point kept for backward compatibility with the scripts/ invocation."""
72
+ try:
73
+ refresh_regions()
74
+ return 0
75
+ except RuntimeError as exc:
76
+ print(f"ERROR: {exc}", file=sys.stderr)
77
+ return 1
78
+
79
+
80
+ if __name__ == "__main__":
81
+ sys.exit(_cli_main())
contentstack/stack.py CHANGED
@@ -7,6 +7,7 @@ from contentstack.error_messages import ErrorMessages
7
7
  from contentstack.asset import Asset
8
8
  from contentstack.assetquery import AssetQuery
9
9
  from contentstack.contenttype import ContentType
10
+ from contentstack.endpoint import Endpoint
10
11
  from contentstack.taxonomy import Taxonomy
11
12
  from contentstack.globalfields import GlobalField
12
13
  from contentstack.https_connection import HTTPSConnection
@@ -119,20 +120,15 @@ class Stack:
119
120
  if self.environment is None or self.environment == "":
120
121
  raise PermissionError(ErrorMessages.INVALID_ENVIRONMENT_TOKEN)
121
122
 
122
- if self.region.value == 'eu' and self.host == DEFAULT_HOST:
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'
126
- elif self.region.value == 'azure-na' and self.host == DEFAULT_HOST:
127
- self.host = 'azure-na-cdn.contentstack.com'
128
- elif self.region.value == 'azure-eu' and self.host == DEFAULT_HOST:
129
- self.host = 'azure-eu-cdn.contentstack.com'
130
- elif self.region.value == 'gcp-na' and self.host == DEFAULT_HOST:
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'
134
- elif self.region.value != 'us':
135
- self.host = f'{self.region.value}-{DEFAULT_HOST}'
123
+ if self.host == DEFAULT_HOST:
124
+ try:
125
+ self.host = Endpoint.get_contentstack_endpoint(
126
+ self.region.value, 'contentDelivery', omit_https=True)
127
+ except (ValueError, RuntimeError):
128
+ # Unknown/custom region — fall back to legacy pattern so
129
+ # code written before this feature was added continues to work.
130
+ if self.region.value != 'us':
131
+ self.host = f'{self.region.value}-{DEFAULT_HOST}'
136
132
  self.endpoint = f'https://{self.host}/{self.version}'
137
133
 
138
134
  def _setup_headers(self):
@@ -365,8 +361,14 @@ class Stack:
365
361
 
366
362
  def _setup_live_preview(self):
367
363
  if self.live_preview and self.live_preview.get("enable"):
368
- region_prefix = "" if self.region.value == "us" else f"{self.region.value}-"
369
- self.live_preview["host"] = f"{region_prefix}rest-preview.contentstack.com"
364
+ if not self.live_preview.get("host"):
365
+ try:
366
+ mgmt_host = Endpoint.get_contentstack_endpoint(
367
+ self.region.value, 'contentManagement', omit_https=True)
368
+ except (ValueError, RuntimeError):
369
+ region_prefix = "" if self.region.value == "us" else f"{self.region.value}-"
370
+ mgmt_host = f"{region_prefix}api.contentstack.io"
371
+ self.live_preview["host"] = mgmt_host
370
372
 
371
373
  if self.live_preview.get("preview_token"):
372
374
  self.headers["preview_token"] = self.live_preview["preview_token"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Contentstack
3
- Version: 2.4.1
3
+ Version: 2.6.0
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
@@ -188,7 +188,7 @@ Read through to understand how to use the Sync API with Contentstack Python SDK.
188
188
 
189
189
  ### The MIT License (MIT)
190
190
 
191
- Copyright © 2012-2025 [Contentstack](https://www.contentstack.com/). All Rights Reserved
191
+ Copyright © 2012-2026 [Contentstack](https://www.contentstack.com/). All Rights Reserved
192
192
 
193
193
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
194
194
  documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
@@ -0,0 +1,25 @@
1
+ contentstack/__init__.py,sha256=-wBJ7ZvV8CIaw8s8Uznb9NYHXkkGzMf8ZQARtBOYb_o,1680
2
+ contentstack/asset.py,sha256=GY-eC9Tg2uEDr9S7ggXCcrMjIdkcQGkP4UNgTfIqFs0,6977
3
+ contentstack/assetquery.py,sha256=FisGJ02MmH4sYvnHEJhYj4OWZBRORV8iKy38PdzLtxY,7954
4
+ contentstack/basequery.py,sha256=c_A7Pi45OHHfCpd8_ZjcIYAy9mhZ7CXlbBiZ4Plnu3M,6605
5
+ contentstack/contenttype.py,sha256=mEj94nZMY5pGsAMUPt4Xs5gagrFU1vKSfOq7u_Aho4Y,5422
6
+ contentstack/controller.py,sha256=kcFnVdvFJk6_HYgK60-cUgyEK3C1UlD98zv108JtcVI,1095
7
+ contentstack/deep_merge_lp.py,sha256=PIRGo5Dv60g4hzBY__nOrIAKgIx1Pd36gGzxnM5gZK4,1575
8
+ contentstack/endpoint.py,sha256=8ZTPDlpQ0C1oa3EgU_nbcHjFeQ5Chgen8viUFCVGk3w,6579
9
+ contentstack/entry.py,sha256=EVJ89VHF40P5Kv_GSKvQaL3IoNFvxrEur12ucrTMC2k,12320
10
+ contentstack/entryqueryable.py,sha256=4YBX4N6tNSPMavrPxzM26RFBH8Qi6pIalIu-KEdVOtE,9828
11
+ contentstack/error_messages.py,sha256=Qep3wvN2Rl0lb1UIRGCjzpHBGnpXaortaescCdNuMHY,3334
12
+ contentstack/globalfields.py,sha256=APhIpiAVJ2v7Illh6yS4-S6W8yEzXBtYpAaPUKD-XuQ,2865
13
+ contentstack/https_connection.py,sha256=jipKdr0ouyQ7-uY11VfJILaY6E7c9gB24bZNKiGXD7o,1693
14
+ contentstack/image_transform.py,sha256=jL8y1bpF8RIDrwQIPhzzKR-WFjbNZEFWcWXYQFxh4C0,2203
15
+ contentstack/query.py,sha256=UA7W8ESjdgvWyG8QQWzA2Uo1XJM_ZgwJXwmaHgLtOgY,15674
16
+ contentstack/region_refresh.py,sha256=zXwsMwVMSMb7duhqhV_Zx5aOHqsQE_6pnSppPLVteWs,2553
17
+ contentstack/stack.py,sha256=Xu7iS117AL3q1vhlYNEC97lPho91yrGxBiwk0htAZU8,16948
18
+ contentstack/taxonomy.py,sha256=g6zey4MkoeQqxRlHLSuzbA2NfbphgogGBXAwk28P5KI,2339
19
+ contentstack/utility.py,sha256=qZWckUMZZh4F80A7gV9qHn9QKOhr099M8FiJKxtxdao,3169
20
+ contentstack/variants.py,sha256=9qFGU6VsUcYEDTNjSUPJxnevXw2S8xflnDDIyk2Cmak,3757
21
+ contentstack-2.6.0.dist-info/licenses/LICENSE,sha256=BF_N9KC72HmX8HTAJROoPoFrW6xmO3rlbqpfjxmli08,1099
22
+ contentstack-2.6.0.dist-info/METADATA,sha256=vTcPNLDN7YGvuICTH4mNspHmvw2wDFYnK5dFzrgrlrI,9346
23
+ contentstack-2.6.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
24
+ contentstack-2.6.0.dist-info/top_level.txt,sha256=jMUc8tWMXdbMFbvosYZ-vHWHrsLFWeHgrWQytLTVZf4,13
25
+ contentstack-2.6.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2012 - 2025 Contentstack. All rights reserved.
3
+ Copyright (c) 2012 - 2026 Contentstack. All rights reserved.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,23 +0,0 @@
1
- contentstack/__init__.py,sha256=8U5Otw-6VX4ZHcKhf0ykmaTRukarYc2sFcXREnm1ncY,802
2
- contentstack/asset.py,sha256=xG1g1zttMsKk-1A9I__HpQHu5d3m4Qm8Qo_IVHn9w1M,5558
3
- contentstack/assetquery.py,sha256=8W6XsrdxEaAJEhVzzrnyESIlt8kz-IdiIGHHV1pxO1o,6577
4
- contentstack/basequery.py,sha256=c_A7Pi45OHHfCpd8_ZjcIYAy9mhZ7CXlbBiZ4Plnu3M,6605
5
- contentstack/contenttype.py,sha256=7JDYvEei1BRnOiGBaBOH2b1m-V87U56hQXtyf-cCNXQ,5387
6
- contentstack/controller.py,sha256=kcFnVdvFJk6_HYgK60-cUgyEK3C1UlD98zv108JtcVI,1095
7
- contentstack/deep_merge_lp.py,sha256=PIRGo5Dv60g4hzBY__nOrIAKgIx1Pd36gGzxnM5gZK4,1575
8
- contentstack/entry.py,sha256=wLP_0zvZoMQUFF17JNrZkXHAeUaItzuUOEQKqS9pnfo,10378
9
- contentstack/entryqueryable.py,sha256=RC4f4e-XvxALO10QuZn9y1UJQjOEYZip-gD_NYxSMgA,7983
10
- contentstack/error_messages.py,sha256=Qep3wvN2Rl0lb1UIRGCjzpHBGnpXaortaescCdNuMHY,3334
11
- contentstack/globalfields.py,sha256=APhIpiAVJ2v7Illh6yS4-S6W8yEzXBtYpAaPUKD-XuQ,2865
12
- contentstack/https_connection.py,sha256=jipKdr0ouyQ7-uY11VfJILaY6E7c9gB24bZNKiGXD7o,1693
13
- contentstack/image_transform.py,sha256=jL8y1bpF8RIDrwQIPhzzKR-WFjbNZEFWcWXYQFxh4C0,2203
14
- contentstack/query.py,sha256=UA7W8ESjdgvWyG8QQWzA2Uo1XJM_ZgwJXwmaHgLtOgY,15674
15
- contentstack/stack.py,sha256=Ek9jJsBnoWCgbRbynTEP-Lb5YLPfbTNzrj6IFocDGXM,16938
16
- contentstack/taxonomy.py,sha256=g6zey4MkoeQqxRlHLSuzbA2NfbphgogGBXAwk28P5KI,2339
17
- contentstack/utility.py,sha256=qZWckUMZZh4F80A7gV9qHn9QKOhr099M8FiJKxtxdao,3169
18
- contentstack/variants.py,sha256=9qFGU6VsUcYEDTNjSUPJxnevXw2S8xflnDDIyk2Cmak,3757
19
- contentstack-2.4.1.dist-info/licenses/LICENSE,sha256=maHrlORXmX4stBfcMzjCZ9qSaAzxEVeWOYdDJixLn3Q,1099
20
- contentstack-2.4.1.dist-info/METADATA,sha256=sbAgyIpTXLePanbyPRqBMkEqF1v8U74lhQiJBt2fEUE,9346
21
- contentstack-2.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
- contentstack-2.4.1.dist-info/top_level.txt,sha256=jMUc8tWMXdbMFbvosYZ-vHWHrsLFWeHgrWQytLTVZf4,13
23
- contentstack-2.4.1.dist-info/RECORD,,