Skip to content

Commit ee74c86

Browse files
authored
Add support of environments and fix style (contentful#28)
Add support of environments
1 parent de17488 commit ee74c86

38 files changed

+191
-69
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# CHANGELOG
22

33
## Unreleased
4+
### Added
5+
* Added support of `environments` functionality.
46

57
## v1.6.0
68
### Added

README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ Client Configuration Options
158158

159159
``default_locale``: (optional) Default Locale for your Space, defaults to 'en-US'.
160160

161+
``environment``: (optional) Default Environment for client, defaults to 'master'.
162+
161163
``https``: (optional) Boolean determining wether to use https or http, defaults to True.
162164

163165
``authorization_as_header``: (optional) Boolean determining wether to send access_token through a header or via GET params, defaults to True.

contentful/asset.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,9 @@ def incoming_references(self, client=None, query={}):
5555
if client is None:
5656
return False
5757

58-
query.update({ 'links_to_asset': self.id })
58+
query.update({'links_to_asset': self.id})
5959
return client.entries(query)
6060

61-
6261
def __repr__(self):
6362
return "<Asset id='{0}' url='{1}'>".format(
6463
self.sys.get('id', ''),

contentful/client.py

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import requests
22
import platform
33
from re import sub
4-
from .utils import ConfigurationException, retry_request, string_class
4+
from .utils import ConfigurationException, NotSupportedException
5+
from .utils import retry_request, string_class
56
from .errors import get_error, RateLimitExceededError, EntryNotFoundError
67
from .resource_builder import ResourceBuilder
78
from .content_type_cache import ContentTypeCache
@@ -32,6 +33,8 @@ class Client(object):
3233
:param api_version: (optional) Target version of the Contentful API.
3334
:param default_locale: (optional) Default Locale for your Space,
3435
defaults to 'en-US'.
36+
:param environment: (optional) Default Environment for client, defaults
37+
to 'master'.
3538
:param https: (optional) Boolean determining wether to use https
3639
or http, defaults to True.
3740
:param authorization_as_header: (optional) Boolean determining wether
@@ -79,6 +82,7 @@ def __init__(
7982
api_url='cdn.contentful.com',
8083
api_version=1,
8184
default_locale='en-US',
85+
environment='master',
8286
https=True,
8387
authorization_as_header=True,
8488
raw_mode=False,
@@ -101,6 +105,7 @@ def __init__(
101105
self.api_url = api_url
102106
self.api_version = api_version
103107
self.default_locale = default_locale
108+
self.environment = environment
104109
self.https = https
105110
self.authorization_as_header = authorization_as_header
106111
self.raw_mode = raw_mode
@@ -156,7 +161,9 @@ def content_type(self, content_type_id, query=None):
156161
"""
157162

158163
return self._get(
159-
'/content_types/{0}'.format(content_type_id),
164+
self.environment_url(
165+
'/content_types/{0}'.format(content_type_id)
166+
),
160167
query
161168
)
162169

@@ -178,7 +185,7 @@ def content_types(self, query=None):
178185
"""
179186

180187
return self._get(
181-
'/content_types',
188+
self.environment_url('/content_types'),
182189
query
183190
)
184191

@@ -204,7 +211,7 @@ def entry(self, entry_id, query=None):
204211
try:
205212
query.update({'sys.id': entry_id})
206213
return self._get(
207-
'/entries',
214+
self.environment_url('/entries'),
208215
query
209216
)[0]
210217
except IndexError:
@@ -240,7 +247,7 @@ def entries(self, query=None):
240247
self._normalize_select(query)
241248

242249
return self._get(
243-
'/entries',
250+
self.environment_url('/entries'),
244251
query
245252
)
246253

@@ -260,7 +267,9 @@ def asset(self, asset_id, query=None):
260267
"""
261268

262269
return self._get(
263-
'/assets/{0}'.format(asset_id),
270+
self.environment_url(
271+
'/assets/{0}'.format(asset_id)
272+
),
264273
query
265274
)
266275

@@ -286,7 +295,30 @@ def assets(self, query=None):
286295
self._normalize_select(query)
287296

288297
return self._get(
289-
'/assets',
298+
self.environment_url('/assets'),
299+
query
300+
)
301+
302+
def locales(self, query=None):
303+
"""Fetches all Locales from the Environment (up to the set limit, can be modified in `query`).
304+
305+
# TODO: fix url
306+
API Reference: https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/assets/assets-collection/get-all-assets-of-a-space
307+
308+
:param query: (optional) Dict with API options.
309+
:return: List of :class:`Locale <contentful.locale.Locale>` objects.
310+
:rtype: List of contentful.locale.Locale
311+
312+
Usage:
313+
>>> locales = client.locales()
314+
[<Locale[English (United States)] code='en-US' default=True fallback_code=None optional=False>]
315+
"""
316+
317+
if query is None:
318+
query = {}
319+
320+
return self._get(
321+
self.environment_url('/locales'),
290322
query
291323
)
292324

@@ -304,6 +336,9 @@ def sync(self, query=None):
304336
<SyncPage next_sync_token='w5ZGw6JFwqZmVcKsE8Kow4grw45QdybC...'>
305337
"""
306338

339+
if self.environment != 'master':
340+
raise NotSupportedException('The sync endpoint is only available for the master environment.')
341+
307342
if query is None:
308343
query = {}
309344
self._normalize_sync(query)
@@ -313,6 +348,14 @@ def sync(self, query=None):
313348
query
314349
)
315350

351+
def environment_url(self, url):
352+
"""Formats the URL with the environment."""
353+
354+
return "/environments/{0}{1}".format(
355+
self.environment,
356+
url
357+
)
358+
316359
def _normalize_select(self, query):
317360
"""
318361
If the query contains the :select operator, we enforce :sys properties.

contentful/content_type_field.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .utils import snake_case
2-
from .content_type_field_types import * # noqa: F401
2+
from .content_type_field_types import * # noqa: F401, F403
33

44
"""
55
contentful.content_type_field

contentful/entry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def incoming_references(self, client=None, query={}):
105105
if client is None:
106106
return False
107107

108-
query.update({ 'links_to_entry': self.id })
108+
query.update({'links_to_entry': self.id})
109109
return client.entries(query)
110110

111111
def __repr__(self):

contentful/errors.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import json
2-
3-
41
"""
52
contentful.errors
63
~~~~~~~~~~~~~~~~~
@@ -88,7 +85,7 @@ def _handle_detail(detail):
8885
return detail.get('details', None)
8986

9087
inner_details = [_handle_detail(detail) for detail in details['errors']]
91-
inner_details = [detail for detail in inner_details if detail is not None] # This works in both Py2 and Py3
88+
inner_details = [detail for detail in inner_details if detail is not None] # This works in both Py2 and Py3
9289
return "\n\t".join(inner_details)
9390

9491

@@ -109,7 +106,6 @@ class AccessDeniedError(HTTPError):
109106
def _default_error_message(self):
110107
return "The specified token does not have access to the requested resource."
111108

112-
113109
def _handle_details(self, details):
114110
return "\n\tReasons:\n\t\t{0}".format("\n\t\t".join(details['reasons']))
115111

contentful/locale.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from .resource import Resource
12
"""
23
contentful.locale
34
~~~~~~~~~~~~~~~~~
@@ -11,20 +12,26 @@
1112
"""
1213

1314

14-
class Locale(object):
15+
class Locale(Resource):
1516
"""
1617
API Reference: https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/localization
1718
"""
1819

19-
def __init__(self, locale_data):
20-
self.code = locale_data.get('code', '')
21-
self.name = locale_data.get('name', '')
22-
self.fallback_code = locale_data.get('fallbackCode', '')
23-
self.default = locale_data.get('default', False)
20+
def __init__(self, item, **kwargs):
21+
super(Locale, self).__init__(item, **kwargs)
22+
self.code = item.get('code', '')
23+
self.name = item.get('name', '')
24+
self.fallback_code = item.get('fallbackCode', '')
25+
self.default = item.get('default', False)
26+
self.optional = item.get('optional', False)
2427

2528
def __repr__(self):
26-
return "<Locale[{0}] code='{1}' default={2}>".format(
29+
return "<Locale[{0}] code='{1}' default={2} fallback_code={3} optional={4}>".format(
2730
self.name,
2831
self.code,
29-
self.default
32+
self.default,
33+
"'{0}'".format(
34+
self.fallback_code
35+
) if self.fallback_code is not None else 'None',
36+
self.optional
3037
)

contentful/resource.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def __init__(
4242

4343
def _hydrate_sys(self, item):
4444
sys = {}
45-
for k, v in item['sys'].items():
45+
for k, v in item.get('sys', {}).items():
4646
if k in ['space', 'contentType']:
4747
v = self._build_link(v)
4848
if k in ['createdAt', 'updatedAt', 'deletedAt']:

contentful/resource_builder.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from .content_type import ContentType # noqa: F401
77
from .deleted_asset import DeletedAsset # noqa: F401
88
from .deleted_entry import DeletedEntry # noqa: F401
9+
from .locale import Locale # noqa: F401
910
from .sync_page import SyncPage
1011
from .utils import unresolvable
1112

@@ -63,11 +64,11 @@ def _build_array(self):
6364
errors = self._errors()
6465

6566
items = [self._build_item(
66-
item,
67-
includes=includes,
68-
errors=errors
69-
) for item in self.json['items']
70-
if not unresolvable(item, self._errors())]
67+
item,
68+
includes=includes,
69+
errors=errors
70+
) for item in self.json['items']
71+
if not unresolvable(item, self._errors())]
7172

7273
return Array(self.json, items)
7374

@@ -83,7 +84,8 @@ def _build_item(self, item, includes=None, errors=None):
8384
'ContentType',
8485
'Space',
8586
'DeletedEntry',
86-
'DeletedAsset'
87+
'DeletedAsset',
88+
'Locale'
8789
]
8890
if item['sys']['type'] in buildables:
8991
return globals()[item['sys']['type']](
@@ -101,7 +103,7 @@ def _includes(self):
101103
for e in ['Entry', 'Asset']:
102104
if e in self.json.get('includes', {}):
103105
includes += [item for item in self.json['includes'].get(e, [])
104-
if not unresolvable(item, self._errors())]
106+
if not unresolvable(item, self._errors())]
105107
return includes
106108

107109
def _errors(self):

0 commit comments

Comments
 (0)