From a3eefeda342cc9d88c6648f9f4f7f453d647dfd5 Mon Sep 17 00:00:00 2001 From: OMpawar-21 Date: Thu, 18 Jun 2026 02:52:50 +0530 Subject: [PATCH 1/4] fix: add refresh_regions utility and auto-refresh regions.json at build time. - Add `contentstack_management/region_refresh.py` exposing a `refresh_regions()` function that downloads the latest regions manifest from the Contentstack CDN and overwrites the bundled `data/regions.json`. - Export `refresh_regions` at the package level so CI pipelines and tooling can call it programmatically (`from contentstack_management import refresh_regions`). - Hook `setup.py` with a custom `BuildPyWithRegions` command so `regions.json` is refreshed automatically on every `python setup.py build` / `pip install`, keeping the bundled region data current without a manual step. --- contentstack_management/__init__.py | 4 +- contentstack_management/region_refresh.py | 81 +++++++++++++++++++++++ setup.py | 16 +++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 contentstack_management/region_refresh.py diff --git a/contentstack_management/__init__.py b/contentstack_management/__init__.py index ba7b064..deaaa16 100644 --- a/contentstack_management/__init__.py +++ b/contentstack_management/__init__.py @@ -37,6 +37,7 @@ from .variants.variants import Variants from .oauth.oauth_handler import OAuthHandler from .oauth.oauth_interceptor import OAuthInterceptor +from .region_refresh import refresh_regions __all__ = ( @@ -77,7 +78,8 @@ "VariantGroup", "Variants", "OAuthHandler", -"OAuthInterceptor" +"OAuthInterceptor", +"refresh_regions", ) def get_contentstack_endpoint(region='us', service='', omit_https=False): diff --git a/contentstack_management/region_refresh.py b/contentstack_management/region_refresh.py new file mode 100644 index 0000000..889af34 --- /dev/null +++ b/contentstack_management/region_refresh.py @@ -0,0 +1,81 @@ +""" +Utility to pull the latest regions.json from the Contentstack CDN and +overwrite the bundled copy at contentstack_management/data/regions.json. + +Exposed as a package-level function so tooling and CI pipelines can call it +programmatically instead of invoking the script directly: + + from contentstack_management import refresh_regions + refresh_regions() +""" + +import json +import os +import sys +import urllib.request + +_REGIONS_URL = "https://artifacts.contentstack.com/regions.json" +_ASSET_PATH = os.path.join(os.path.dirname(__file__), "data", "regions.json") + + +def refresh_regions( + url: str = _REGIONS_URL, + dest: str = _ASSET_PATH, + *, + timeout: int = 30, + silent: bool = False, +) -> dict: + """ + Download the latest regions manifest from the Contentstack CDN and write + it to the bundled data file so all consumers get the update. + + @param url - URL to fetch regions.json from (defaults to Contentstack CDN) + @param dest - Destination file path (defaults to contentstack_management/data/regions.json) + @param timeout - HTTP request timeout in seconds + @param silent - Suppress progress output when True + @returns The parsed regions dict on success + @raises RuntimeError on download failure, invalid JSON, or unexpected schema + """ + dest = os.path.normpath(dest) + + if not silent: + print(f"Fetching {url} ...") + + try: + with urllib.request.urlopen(url, timeout=timeout) as resp: + data = resp.read().decode("utf-8") + except Exception as exc: + raise RuntimeError(f"Could not download regions.json: {exc}") from exc + + try: + decoded = json.loads(data) + except json.JSONDecodeError as exc: + raise RuntimeError(f"Downloaded content is not valid JSON: {exc}") from exc + + if not isinstance(decoded, dict) or "regions" not in decoded: + raise RuntimeError("Downloaded JSON does not contain a 'regions' key.") + + os.makedirs(os.path.dirname(dest), exist_ok=True) + with open(dest, "w", encoding="utf-8") as fh: + json.dump(decoded, fh, indent=2, ensure_ascii=False) + fh.write("\n") + + region_count = len(decoded["regions"]) + if not silent: + print(f"OK: Wrote {region_count} regions to {dest}") + + return decoded + + +def _cli_main() -> int: + """Entry point kept for backward compatibility with the scripts/ invocation.""" + try: + refresh_regions() + return 0 + except RuntimeError as exc: + print(f"ERROR: {exc}", file=sys.stderr) + return 1 + + +if __name__ == "__main__": + sys.exit(_cli_main()) diff --git a/setup.py b/setup.py index 684be4c..1061207 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,21 @@ import os import re +import sys from setuptools import setup, find_packages +from setuptools.command.build_py import build_py + + +class BuildPyWithRegions(build_py): + """Fetch latest regions.json from Contentstack CDN before packaging.""" + + def run(self): + sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + try: + from contentstack_management.region_refresh import refresh_regions + refresh_regions() + except Exception as exc: + print(f"WARNING: Could not refresh regions.json: {exc}", file=sys.stderr) + super().run() with open("README.md", "r") as f: long_description = f.read() @@ -33,6 +48,7 @@ def get_author_email(package): init_py, re.MULTILINE).group(1) setup( + cmdclass={"build_py": BuildPyWithRegions}, name="contentstack-management", version=get_version(package), packages=find_packages(exclude=['tests']), From 18c2eeb316a48ff1db3b8a6b206ce18c3209fc54 Mon Sep 17 00:00:00 2001 From: OMpawar-21 Date: Thu, 18 Jun 2026 03:01:05 +0530 Subject: [PATCH 2/4] fix: updated change log with the fix --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c56438a..2658c77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ - `Client` now resolves the `contentManagement` endpoint from the registry instead of a hardcoded host pattern. - Added `scripts/download_regions.py` to refresh the bundled registry file. - New regions and services require no SDK code changes — registry update is sufficient. +- Added `refresh_regions()` utility to programmatically download the latest regions manifest from the Contentstack CDN and overwrite the bundled `data/regions.json`. +- Exposed `refresh_regions` at the package level (`from contentstack_management import refresh_regions`) for use in CI pipelines and tooling. +- `setup.py` now auto-refreshes `regions.json` at build time via a custom `BuildPyWithRegions` command, keeping bundled region data current on every `pip install`. --- ## v1.9.0 From 50a5bb9cdba87ab63e60f4cccc4a4b56117e071f Mon Sep 17 00:00:00 2001 From: OMpawar-21 Date: Thu, 18 Jun 2026 03:06:22 +0530 Subject: [PATCH 3/4] fix: change log date update --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2658c77..af15fd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ --- ## v1.10.0 -#### Date: 08 June 2026 +#### Date: 22 June 2026 - Dynamic region endpoint resolution via the Contentstack Regions Registry (`regions.json`). - Added `Endpoint` class with 3-tier resolution: in-memory cache → bundled `data/regions.json` → live CDN download. From 2f4776189a6ee10787093e5affd4ba77398d5ce3 Mon Sep 17 00:00:00 2001 From: OMpawar-21 Date: Thu, 18 Jun 2026 10:40:26 +0530 Subject: [PATCH 4/4] Update CHANGELOG.md --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af15fd7..d12d9ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,11 +10,12 @@ - Added `Endpoint` class with 3-tier resolution: in-memory cache → bundled `data/regions.json` → live CDN download. - Exposed `contentstack_management.get_contentstack_endpoint(region, service, omit_https)` module-level proxy. - `Client` now resolves the `contentManagement` endpoint from the registry instead of a hardcoded host pattern. -- Added `scripts/download_regions.py` to refresh the bundled registry file. +- Bundled `contentstack_management/data/regions.json` included in `package_data` — always present after `pip install`. +- `setup.py` auto-refreshes `regions.json` at build time via a custom `BuildPyWithRegions` command; network failures warn but never block the build. +- Runtime fallback: if `regions.json` is absent, the SDK downloads it live on the first `Endpoint` call. - New regions and services require no SDK code changes — registry update is sufficient. -- Added `refresh_regions()` utility to programmatically download the latest regions manifest from the Contentstack CDN and overwrite the bundled `data/regions.json`. -- Exposed `refresh_regions` at the package level (`from contentstack_management import refresh_regions`) for use in CI pipelines and tooling. -- `setup.py` now auto-refreshes `regions.json` at build time via a custom `BuildPyWithRegions` command, keeping bundled region data current on every `pip install`. +- Added `refresh_regions()` utility to programmatically download the latest regions manifest from the Contentstack CDN and overwrite the bundled `data/regions.json` (`from contentstack_management import refresh_regions`). +- Added `python3 -m contentstack_management.region_refresh` CLI command for refreshing the registry after `pip install` (source-tree script `scripts/download_regions.py` is for contributors only). --- ## v1.9.0