Skip to content

Commit 0f0a992

Browse files
authored
Prevent rehydrating RichText fields (contentful#42)
1 parent 80ddcce commit 0f0a992

File tree

4 files changed

+201
-1
lines changed

4 files changed

+201
-1
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+
### Fixed
5+
* Entries that had already been processed when coercing RichText fields are now properly omitted. [#41](https://github.com/contentful/contentful.py/issues/41)
46

57
## v1.11.3
68
### Fixed

contentful/content_type_field_types.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import dateutil.parser
77
from collections import namedtuple
88
from .utils import unicode_class, resource_for_link, unresolvable
9-
from .resource import FieldsResource, Link
9+
from .resource import FieldsResource, Link, Resource
1010

1111
"""
1212
contentful.content_type_field_types
@@ -188,6 +188,10 @@ def _coerce_block(self, value, includes=None, errors=None, resources=None, defau
188188
coerced_nodes = {}
189189
for index, node in enumerate(value['content']):
190190
if node.get('data', None) and node['data'].get('target', None):
191+
# Resource has already been hydrated previously
192+
if isinstance(node['data']['target'], Resource):
193+
continue
194+
191195
link = self._coerce_link(
192196
node,
193197
includes=includes,

fixtures/integration/issue-41.yaml

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
interactions:
2+
- request:
3+
body: null
4+
headers:
5+
Accept: ['*/*']
6+
Accept-Encoding: [identity]
7+
Authorization: [Bearer 45ba81cc69423fcd2e3f0a4779de29481bb5c11495bc7e14649a996cf984e98e]
8+
Connection: [keep-alive]
9+
Content-Type: [application/vnd.contentful.delivery.v1+json]
10+
User-Agent: [python-requests/2.20.0]
11+
X-Contentful-User-Agent: [sdk contentful.py/1.11.3; platform python/3.6.3; os
12+
macOS/16.7.0;]
13+
method: GET
14+
uri: https://cdn.contentful.com/spaces/fds721b88p6b/environments/master/content_types
15+
response:
16+
body: {string: "{\n \"sys\": {\n \"type\": \"Array\"\n },\n \"total\": 2,\n
17+
\ \"skip\": 0,\n \"limit\": 100,\n \"items\": [\n {\n \"sys\": {\n
18+
\ \"space\": {\n \"sys\": {\n \"type\": \"Link\",\n
19+
\ \"linkType\": \"Space\",\n \"id\": \"fds721b88p6b\"\n
20+
\ }\n },\n \"id\": \"parent\",\n \"type\": \"ContentType\",\n
21+
\ \"createdAt\": \"2018-11-22T13:46:07.272Z\",\n \"updatedAt\":
22+
\"2018-11-22T13:46:07.272Z\",\n \"environment\": {\n \"sys\":
23+
{\n \"id\": \"master\",\n \"type\": \"Link\",\n \"linkType\":
24+
\"Environment\"\n }\n },\n \"revision\": 1\n },\n
25+
\ \"displayField\": \"title\",\n \"name\": \"Parent\",\n \"description\":
26+
\"\",\n \"fields\": [\n {\n \"id\": \"title\",\n \"name\":
27+
\"Title\",\n \"type\": \"Symbol\",\n \"localized\": false,\n
28+
\ \"required\": false,\n \"disabled\": false,\n \"omitted\":
29+
false\n },\n {\n \"id\": \"children\",\n \"name\":
30+
\"Children\",\n \"type\": \"Array\",\n \"localized\": false,\n
31+
\ \"required\": false,\n \"disabled\": false,\n \"omitted\":
32+
false,\n \"items\": {\n \"type\": \"Link\",\n \"validations\":
33+
[],\n \"linkType\": \"Entry\"\n }\n }\n ]\n
34+
\ },\n {\n \"sys\": {\n \"space\": {\n \"sys\":
35+
{\n \"type\": \"Link\",\n \"linkType\": \"Space\",\n
36+
\ \"id\": \"fds721b88p6b\"\n }\n },\n \"id\":
37+
\"child\",\n \"type\": \"ContentType\",\n \"createdAt\": \"2018-11-22T13:48:47.928Z\",\n
38+
\ \"updatedAt\": \"2018-11-22T13:48:47.928Z\",\n \"environment\":
39+
{\n \"sys\": {\n \"id\": \"master\",\n \"type\":
40+
\"Link\",\n \"linkType\": \"Environment\"\n }\n },\n
41+
\ \"revision\": 1\n },\n \"displayField\": \"title\",\n \"name\":
42+
\"Child\",\n \"description\": \"\",\n \"fields\": [\n {\n
43+
\ \"id\": \"title\",\n \"name\": \"Title\",\n \"type\":
44+
\"Symbol\",\n \"localized\": false,\n \"required\": false,\n
45+
\ \"disabled\": false,\n \"omitted\": false\n },\n
46+
\ {\n \"id\": \"body\",\n \"name\": \"Body\",\n \"type\":
47+
\"RichText\",\n \"localized\": false,\n \"required\": false,\n
48+
\ \"disabled\": false,\n \"omitted\": false\n }\n
49+
\ ]\n }\n ]\n}\n"}
50+
headers:
51+
Accept-Ranges: [bytes]
52+
Access-Control-Allow-Headers: ['Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization,X-Contentful-Skip-Transformation,X-Contentful-User-Agent,X-Contentful-Enable-Alpha-Feature']
53+
Access-Control-Allow-Methods: ['GET,HEAD,OPTIONS']
54+
Access-Control-Allow-Origin: ['*']
55+
Access-Control-Expose-Headers: [Etag]
56+
Access-Control-Max-Age: ['86400']
57+
Age: ['0']
58+
Cache-Control: [max-age=0]
59+
Connection: [keep-alive]
60+
Content-Length: ['2357']
61+
Content-Type: [application/vnd.contentful.delivery.v1+json]
62+
Contentful-Api: [cda_cached]
63+
Date: ['Thu, 22 Nov 2018 13:58:02 GMT']
64+
ETag: [W/"c2b8adf3ad96fc1cb1b7d1d679e17d7c"]
65+
Server: [Contentful]
66+
Vary: [Accept-Encoding]
67+
Via: [1.1 varnish]
68+
X-Cache: [MISS]
69+
X-Cache-Hits: ['0']
70+
X-Content-Type-Options: [nosniff]
71+
X-Contentful-Region: [us-east-1]
72+
X-Contentful-Request-Id: [1ad1c6ab1ba098f56907d007cf499365]
73+
X-Served-By: [cache-fra19144-FRA]
74+
status: {code: 200, message: OK}
75+
- request:
76+
body: null
77+
headers:
78+
Accept: ['*/*']
79+
Accept-Encoding: [identity]
80+
Authorization: [Bearer 45ba81cc69423fcd2e3f0a4779de29481bb5c11495bc7e14649a996cf984e98e]
81+
Connection: [keep-alive]
82+
Content-Type: [application/vnd.contentful.delivery.v1+json]
83+
User-Agent: [python-requests/2.20.0]
84+
X-Contentful-User-Agent: [sdk contentful.py/1.11.3; platform python/3.6.3; os
85+
macOS/16.7.0;]
86+
method: GET
87+
uri: https://cdn.contentful.com/spaces/fds721b88p6b/environments/master/entries?sys.id=1tBAu0wP9qAQEg6qCqMics
88+
response:
89+
body: {string: "{\n \"sys\": {\n \"type\": \"Array\"\n },\n \"total\": 1,\n
90+
\ \"skip\": 0,\n \"limit\": 100,\n \"items\": [\n {\n \"sys\": {\n
91+
\ \"space\": {\n \"sys\": {\n \"type\": \"Link\",\n
92+
\ \"linkType\": \"Space\",\n \"id\": \"fds721b88p6b\"\n
93+
\ }\n },\n \"id\": \"1tBAu0wP9qAQEg6qCqMics\",\n \"type\":
94+
\"Entry\",\n \"createdAt\": \"2018-11-22T13:49:04.334Z\",\n \"updatedAt\":
95+
\"2018-11-22T13:50:01.448Z\",\n \"environment\": {\n \"sys\":
96+
{\n \"id\": \"master\",\n \"type\": \"Link\",\n \"linkType\":
97+
\"Environment\"\n }\n },\n \"revision\": 2,\n \"contentType\":
98+
{\n \"sys\": {\n \"type\": \"Link\",\n \"linkType\":
99+
\"ContentType\",\n \"id\": \"parent\"\n }\n },\n
100+
\ \"locale\": \"en-US\"\n },\n \"fields\": {\n \"title\":
101+
\"Parent\",\n \"children\": [\n {\n \"sys\": {\n
102+
\ \"type\": \"Link\",\n \"linkType\": \"Entry\",\n
103+
\ \"id\": \"2RJFAOGr1KeCQuYiASOY82\"\n }\n },\n
104+
\ {\n \"sys\": {\n \"type\": \"Link\",\n \"linkType\":
105+
\"Entry\",\n \"id\": \"2RJFAOGr1KeCQuYiASOY82\"\n }\n
106+
\ },\n {\n \"sys\": {\n \"type\":
107+
\"Link\",\n \"linkType\": \"Entry\",\n \"id\": \"5YcYYsGv3q4Oq68WQcOiAA\"\n
108+
\ }\n }\n ]\n }\n }\n ],\n \"includes\":
109+
{\n \"Entry\": [\n {\n \"sys\": {\n \"space\": {\n
110+
\ \"sys\": {\n \"type\": \"Link\",\n \"linkType\":
111+
\"Space\",\n \"id\": \"fds721b88p6b\"\n }\n },\n
112+
\ \"id\": \"2RJFAOGr1KeCQuYiASOY82\",\n \"type\": \"Entry\",\n
113+
\ \"createdAt\": \"2018-11-22T13:49:38.406Z\",\n \"updatedAt\":
114+
\"2018-11-22T13:49:38.406Z\",\n \"environment\": {\n \"sys\":
115+
{\n \"id\": \"master\",\n \"type\": \"Link\",\n
116+
\ \"linkType\": \"Environment\"\n }\n },\n
117+
\ \"revision\": 1,\n \"contentType\": {\n \"sys\":
118+
{\n \"type\": \"Link\",\n \"linkType\": \"ContentType\",\n
119+
\ \"id\": \"child\"\n }\n },\n \"locale\":
120+
\"en-US\"\n },\n \"fields\": {\n \"title\": \"Child\",\n
121+
\ \"body\": {\n \"data\": {},\n \"content\":
122+
[\n {\n \"data\": {},\n \"content\":
123+
[\n {\n \"data\": {},\n \"marks\":
124+
[],\n \"value\": \"Some stuff here\",\n \"nodeType\":
125+
\"text\"\n }\n ],\n \"nodeType\":
126+
\"paragraph\"\n },\n {\n \"data\":
127+
{\n \"target\": {\n \"sys\": {\n \"id\":
128+
\"3VDkQdyZ9YYaEceWKgGcAG\",\n \"type\": \"Link\",\n \"linkType\":
129+
\"Entry\"\n }\n }\n },\n
130+
\ \"content\": [],\n \"nodeType\": \"embedded-entry-block\"\n
131+
\ },\n {\n \"data\": {},\n \"content\":
132+
[\n {\n \"data\": {},\n \"marks\":
133+
[],\n \"value\": \"\",\n \"nodeType\":
134+
\"text\"\n }\n ],\n \"nodeType\":
135+
\"paragraph\"\n }\n ],\n \"nodeType\":
136+
\"document\"\n }\n }\n },\n {\n \"sys\":
137+
{\n \"space\": {\n \"sys\": {\n \"type\":
138+
\"Link\",\n \"linkType\": \"Space\",\n \"id\": \"fds721b88p6b\"\n
139+
\ }\n },\n \"id\": \"5YcYYsGv3q4Oq68WQcOiAA\",\n
140+
\ \"type\": \"Entry\",\n \"createdAt\": \"2018-11-22T13:49:58.353Z\",\n
141+
\ \"updatedAt\": \"2018-11-22T13:49:58.353Z\",\n \"environment\":
142+
{\n \"sys\": {\n \"id\": \"master\",\n \"type\":
143+
\"Link\",\n \"linkType\": \"Environment\"\n }\n },\n
144+
\ \"revision\": 1,\n \"contentType\": {\n \"sys\":
145+
{\n \"type\": \"Link\",\n \"linkType\": \"ContentType\",\n
146+
\ \"id\": \"child\"\n }\n },\n \"locale\":
147+
\"en-US\"\n },\n \"fields\": {\n \"title\": \"Other
148+
Child\",\n \"body\": {\n \"data\": {},\n \"content\":
149+
[\n {\n \"data\": {},\n \"content\":
150+
[\n {\n \"data\": {},\n \"marks\":
151+
[],\n \"value\": \"Some other stuff here\",\n \"nodeType\":
152+
\"text\"\n }\n ],\n \"nodeType\":
153+
\"paragraph\"\n }\n ],\n \"nodeType\":
154+
\"document\"\n }\n }\n }\n ]\n }\n}\n"}
155+
headers:
156+
Accept-Ranges: [bytes]
157+
Access-Control-Allow-Headers: ['Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization,X-Contentful-Skip-Transformation,X-Contentful-User-Agent,X-Contentful-Enable-Alpha-Feature']
158+
Access-Control-Allow-Methods: ['GET,HEAD,OPTIONS']
159+
Access-Control-Allow-Origin: ['*']
160+
Access-Control-Expose-Headers: [Etag]
161+
Access-Control-Max-Age: ['86400']
162+
Age: ['0']
163+
Cache-Control: [max-age=0]
164+
Connection: [keep-alive]
165+
Content-Length: ['4825']
166+
Content-Type: [application/vnd.contentful.delivery.v1+json]
167+
Contentful-Api: [cda_cached]
168+
Date: ['Thu, 22 Nov 2018 13:58:02 GMT']
169+
ETag: [W/"c5d3dbad3fcadc2086a73db56968fd73"]
170+
Server: [Contentful]
171+
Vary: [Accept-Encoding]
172+
Via: [1.1 varnish]
173+
X-Cache: [MISS]
174+
X-Cache-Hits: ['0']
175+
X-Content-Type-Options: [nosniff]
176+
X-Contentful-Region: [us-east-1]
177+
X-Contentful-Request-Id: [1321ee31210755c76387cdeb0ecc23ba]
178+
X-Served-By: [cache-fra19147-FRA]
179+
status: {code: 200, message: OK}
180+
version: 1

tests/client_test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,17 @@ def test_rich_text_field_with_embeds_in_lists(self):
444444

445445
self.assertEqual(entry.body['content'][4]['nodeType'], 'ordered-list')
446446
self.assertEqual(str(entry.body['content'][4]['content'][2]['content'][0]['data']['target']), "<Entry[embedded] id='5ZF9Q4K6iWSYIU2OUs0UaQ'>")
447+
448+
@vcr.use_cassette('fixtures/integration/issue-41.yaml')
449+
def test_rich_text_fields_should_not_get_hydrated_twice(self):
450+
client = Client(
451+
'fds721b88p6b',
452+
'45ba81cc69423fcd2e3f0a4779de29481bb5c11495bc7e14649a996cf984e98e',
453+
gzip_encoded=False
454+
)
455+
456+
entry = client.entry('1tBAu0wP9qAQEg6qCqMics')
457+
458+
# Not failing is already a success
459+
self.assertEqual(str(entry.children[0]), str(entry.children[1]))
460+
self.assertEqual(str(entry.children[0].body), str(entry.children[1].body))

0 commit comments

Comments
 (0)