Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion contentstack_management/taxonomies/taxonomy.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,73 @@ def delete(self, taxonomy_uid: str = None):
return self.client.delete(url, headers = self.client.headers, params = self.params)


def publish(self, data: dict):
"""
Publish one or more taxonomies to the specified environments and locales.
Call on a collection-level instance (no taxonomy_uid set).

:param data: ``{"locales": [...], "environments": [...], "items": [{"uid": "..."}]}``
:return: requests.Response

[Example:]
>>> data = {"locales": ["en-us"], "environments": ["production"], "items": [{"uid": "taxonomy_1"}]}
>>> client.stack('api_key').taxonomy().publish(data).json()
"""
url = f"{self.path}/publish"
return self.client.post(url, headers=self.client.headers, data=json.dumps(data), params=self.params)

def unpublish(self, data: dict):
"""
Unpublish one or more taxonomies from the specified environments and locales.
Call on a collection-level instance (no taxonomy_uid set).

:param data: ``{"locales": [...], "environments": [...], "items": [{"uid": "..."}]}``
:return: requests.Response

[Example:]
>>> data = {"locales": ["en-us"], "environments": ["production"], "items": [{"uid": "taxonomy_1"}]}
>>> client.stack('api_key').taxonomy().unpublish(data).json()
"""
url = f"{self.path}/unpublish"
return self.client.post(url, headers=self.client.headers, data=json.dumps(data), params=self.params)

def localize(self, data: dict, locale: str):
"""
Localize a taxonomy into the specified locale.
Requires a taxonomy_uid (instance-level).

:param data: ``{"taxonomy": {"name": "..."}}``
:param locale: Target locale code, e.g. ``"hi-in"``
:return: requests.Response

[Example:]
>>> client.stack('api_key').taxonomy('uid').localize({"taxonomy": {"name": "Hindi"}}, 'hi-in').json()
"""
self.validate_taxonomy_uid()
self.add_param('locale', locale)
url = f"{self.path}/{self.taxonomy_uid}"
return self.client.post(url, headers=self.client.headers, data=json.dumps(data), params=self.params)

def unlocalize(self, locale: str):
"""
Remove a locale variant of a taxonomy.
Requires a taxonomy_uid (instance-level).

:param locale: Locale code to remove, e.g. ``"hi-in"``
:return: requests.Response

[Example:]
>>> client.stack('api_key').taxonomy('uid').unlocalize('hi-in').json()
"""
self.validate_taxonomy_uid()
self.add_param('locale', locale)
url = f"{self.path}/{self.taxonomy_uid}"
return self.client.delete(url, headers=self.client.headers, params=self.params)

def validate_taxonomy_uid(self):
if self.taxonomy_uid is None or '':
raise ArgumentException(TAXONOMY_UID_REQUIRED)

def terms(self, terms_uid: str = None):
self.validate_taxonomy_uid()
return Terms(self.client, self.taxonomy_uid, terms_uid)
Expand Down
39 changes: 37 additions & 2 deletions contentstack_management/terms/terms.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,14 +282,49 @@ def descendants(self, terms_uid: str = None):
url = f"{self.path}/{self.terms_uid}/descendants"
return self.client.get(url, headers = self.client.headers, params = self.params)

def localize(self, data: dict, locale: str):
"""
Localize a term into the specified locale.
Requires both taxonomy_uid and terms_uid (instance-level).

:param data: ``{"term": {"name": "..."}}``
:param locale: Target locale code, e.g. ``"hi-in"``
:return: requests.Response

[Example:]
>>> client.stack('api_key').taxonomy('t_uid').terms('term_uid').localize({"term": {"name": "Hindi"}}, 'hi-in').json()
"""
self.validate_taxonomy_uid()
self.validate_terms_uid()
self.add_param('locale', locale)
url = f"{self.path}/{self.terms_uid}"
return self.client.post(url, headers=self.client.headers, data=json.dumps(data), params=self.params)

def unlocalize(self, locale: str):
"""
Remove a locale variant of a term.
Requires both taxonomy_uid and terms_uid (instance-level).

:param locale: Locale code to remove, e.g. ``"hi-in"``
:return: requests.Response

[Example:]
>>> client.stack('api_key').taxonomy('t_uid').terms('term_uid').unlocalize('hi-in').json()
"""
self.validate_taxonomy_uid()
self.validate_terms_uid()
self.add_param('locale', locale)
url = f"{self.path}/{self.terms_uid}"
return self.client.delete(url, headers=self.client.headers, params=self.params)

def validate_taxonomy_uid(self):
if self.taxonomy_uid is None or '':
raise ArgumentException(TAXONOMY_UID_REQUIRED)

def validate_terms_uid(self):
if self.terms_uid is None or '':
raise ArgumentException(TERMS_UID_REQUIRED)

def validate_term_string(self, term_string):
if term_string is None or '':
raise ArgumentException(TERM_STRING_REQUIRED)
Expand Down
48 changes: 48 additions & 0 deletions tests/integration/api/test_07_taxonomy.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,54 @@ def test_fetch_nonexistent(self, stack):
h.assert_status(resp, 404, 422)


class TestTaxonomyLocalize:
def test_localize(self, stack, store):
"""Localize a taxonomy into a non-master locale."""
uid = store["taxonomies"]["main"]
locale = store["locales"].get("custom", "fr-fr")
data = {"taxonomy": {"name": f"Taxonomy {locale}"}}
resp = stack.taxonomy(uid).localize(data, locale)
h.assert_status(resp, 200, 201)
h.wait(h.SHORT_DELAY)

def test_unlocalize(self, stack, store):
"""Remove the non-master locale variant."""
uid = store["taxonomies"]["main"]
locale = store["locales"].get("custom", "fr-fr")
stack.client.headers.pop("Content-Type", None)
resp = stack.taxonomy(uid).unlocalize(locale)
h.assert_status(resp, 200, 204)


class TestTaxonomyPublish:
def test_publish(self, stack, store):
"""Publish a taxonomy (requires taxonomy_publish feature flag on the stack)."""
uid = store["taxonomies"]["main"]
env = store["environments"].get("main")
locale = store["locales"].get("custom", "fr-fr")
if not env:
pytest.skip("No environment in store — skipping publish test")
data = {"locales": [locale], "environments": [env], "items": [{"uid": uid}]}
resp = stack.taxonomy().publish(data)
if resp.status_code == 403:
pytest.skip("taxonomy_publish feature not enabled on this stack")
h.assert_status(resp, 200, 201, 202)
h.wait(h.SHORT_DELAY)

def test_unpublish(self, stack, store):
"""Unpublish a taxonomy (requires taxonomy_publish feature flag on the stack)."""
uid = store["taxonomies"]["main"]
env = store["environments"].get("main")
locale = store["locales"].get("custom", "fr-fr")
if not env:
pytest.skip("No environment in store — skipping unpublish test")
data = {"locales": [locale], "environments": [env], "items": [{"uid": uid}]}
resp = stack.taxonomy().unpublish(data)
if resp.status_code == 403:
pytest.skip("taxonomy_publish feature not enabled on this stack")
h.assert_status(resp, 200, 201, 202)


class TestTaxonomyDelete:
def test_delete(self, stack):
uid = h.generate_valid_uid("tax_del")
Expand Down
19 changes: 19 additions & 0 deletions tests/integration/api/test_08_terms.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,25 @@ def test_fetch_nonexistent(self, stack, taxonomy_uid):
h.assert_status(resp, 404, 422)


class TestTermsLocalize:
def test_localize(self, stack, store, taxonomy_uid):
"""Localize a term into a non-master locale."""
uid = store["terms"]["main"]
locale = store["locales"].get("custom", "fr-fr")
data = {"term": {"name": f"Term {locale}"}}
resp = stack.taxonomy(taxonomy_uid).terms(uid).localize(data, locale)
h.assert_status(resp, 200, 201)
h.wait(h.SHORT_DELAY)

def test_unlocalize(self, stack, store, taxonomy_uid):
"""Remove the non-master locale variant of a term."""
uid = store["terms"]["main"]
locale = store["locales"].get("custom", "fr-fr")
stack.client.headers.pop("Content-Type", None)
resp = stack.taxonomy(taxonomy_uid).terms(uid).unlocalize(locale)
h.assert_status(resp, 200, 204)


class TestTermsDelete:
def test_delete(self, stack, taxonomy_uid):
uid = h.generate_valid_uid("term_del")
Expand Down
25 changes: 25 additions & 0 deletions tests/unit/taxonomies/test_taxonomy_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,28 @@ def test_delete_taxonomy(self):
response = self.client.stack(api_key).taxonomy(taxonomy_uid).delete()
self.assertEqual(response.request.url, f"{self.client.endpoint}taxonomies/{taxonomy_uid}")
self.assertEqual(response.request.method, "DELETE")

def test_publish(self):
data = {"locales": ["en-us"], "environments": ["production"], "items": [{"uid": taxonomy_uid}]}
response = self.client.stack(api_key).taxonomy().publish(data)
self.assertEqual(response.request.url, f"{self.client.endpoint}taxonomies/publish")
self.assertEqual(response.request.method, "POST")

def test_unpublish(self):
data = {"locales": ["en-us"], "environments": ["production"], "items": [{"uid": taxonomy_uid}]}
response = self.client.stack(api_key).taxonomy().unpublish(data)
self.assertEqual(response.request.url, f"{self.client.endpoint}taxonomies/unpublish")
self.assertEqual(response.request.method, "POST")

def test_localize(self):
data = {"taxonomy": {"name": "Taxonomy Hindi"}}
response = self.client.stack(api_key).taxonomy(taxonomy_uid).localize(data, "hi-in")
self.assertIn(f"taxonomies/{taxonomy_uid}", response.request.url)
self.assertIn("locale=hi-in", response.request.url)
self.assertEqual(response.request.method, "POST")

def test_unlocalize(self):
response = self.client.stack(api_key).taxonomy(taxonomy_uid).unlocalize("hi-in")
self.assertIn(f"taxonomies/{taxonomy_uid}", response.request.url)
self.assertIn("locale=hi-in", response.request.url)
self.assertEqual(response.request.method, "DELETE")
13 changes: 13 additions & 0 deletions tests/unit/terms/test_terms_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,18 @@ def test_descendants(self):
self.assertEqual(response.request.method, "GET")
self.assertEqual(response.request.headers["Content-Type"], "application/json")

def test_localize(self):
data = {"term": {"name": "Term Hindi"}}
response = self.client.stack(api_key).taxonomy(taxonomy_uid).terms(terms_uid).localize(data, "hi-in")
self.assertIn(f"taxonomies/{taxonomy_uid}/terms/{terms_uid}", response.request.url)
self.assertIn("locale=hi-in", response.request.url)
self.assertEqual(response.request.method, "POST")

def test_unlocalize(self):
response = self.client.stack(api_key).taxonomy(taxonomy_uid).terms(terms_uid).unlocalize("hi-in")
self.assertIn(f"taxonomies/{taxonomy_uid}/terms/{terms_uid}", response.request.url)
self.assertIn("locale=hi-in", response.request.url)
self.assertEqual(response.request.method, "DELETE")

if __name__ == '__main__':
unittest.main()
Loading