Skip to content

Commit 22b2a70

Browse files
authored
Merge pull request #7 from Globegitter/to-global-id-unicode-error
Fix utf-8 error on py 2.7
2 parents c4c6533 + 148575e commit 22b2a70

File tree

10 files changed

+97
-56
lines changed

10 files changed

+97
-56
lines changed

graphql_relay/mutation/tests/test_mutation.py

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
from collections import OrderedDict
2+
13
from promise import Promise
2-
from collections import namedtuple
3-
from pytest import raises
44
from graphql import graphql
55
from graphql.type import (
66
GraphQLSchema,
@@ -83,22 +83,6 @@ def test_requires_an_argument():
8383
}
8484
}
8585
'''
86-
expected = {
87-
'allObjects': [
88-
{
89-
'id': 'VXNlcjox'
90-
},
91-
{
92-
'id': 'VXNlcjoy'
93-
},
94-
{
95-
'id': 'UGhvdG86MQ=='
96-
},
97-
{
98-
'id': 'UGhvdG86Mg=='
99-
},
100-
]
101-
}
10286
result = graphql(schema, query)
10387
assert len(result.errors) == 1
10488

@@ -333,96 +317,103 @@ def test_contains_correct_field():
333317
}
334318
}
335319
'''
336-
337320
expected = {
338321
'__schema': {
339322
'mutationType': {
340323
'fields': [
341324
{
342-
'name': 'simpleMutation',
325+
'name': 'simplePromiseMutation',
343326
'args': [
344327
{
345328
'name': 'input',
346329
'type': {
347330
'name': None,
348331
'kind': 'NON_NULL',
349332
'ofType': {
350-
'name': 'SimpleMutationInput',
333+
'name': 'SimplePromiseMutationInput',
351334
'kind': 'INPUT_OBJECT'
352335
}
353336
},
354337
}
355338
],
356339
'type': {
357-
'name': 'SimpleMutationPayload',
340+
'name': 'SimplePromiseMutationPayload',
358341
'kind': 'OBJECT',
359342
}
360343
},
361344
{
362-
'name': 'simpleMutationWithThunkFields',
345+
'name': 'simpleRootValueMutation',
363346
'args': [
364347
{
365348
'name': 'input',
366349
'type': {
367350
'name': None,
368351
'kind': 'NON_NULL',
369352
'ofType': {
370-
'name': 'SimpleMutationWithThunkFieldsInput',
353+
'name': 'SimpleRootValueMutationInput',
371354
'kind': 'INPUT_OBJECT'
372355
}
373356
},
374357
}
375358
],
376359
'type': {
377-
'name': 'SimpleMutationWithThunkFieldsPayload',
360+
'name': 'SimpleRootValueMutationPayload',
378361
'kind': 'OBJECT',
379362
}
380363
},
381364
{
382-
'name': 'simplePromiseMutation',
365+
'name': 'simpleMutation',
383366
'args': [
384367
{
385368
'name': 'input',
386369
'type': {
387370
'name': None,
388371
'kind': 'NON_NULL',
389372
'ofType': {
390-
'name': 'SimplePromiseMutationInput',
373+
'name': 'SimpleMutationInput',
391374
'kind': 'INPUT_OBJECT'
392375
}
393376
},
394377
}
395378
],
396379
'type': {
397-
'name': 'SimplePromiseMutationPayload',
380+
'name': 'SimpleMutationPayload',
398381
'kind': 'OBJECT',
399382
}
400383
},
401384
{
402-
'name': 'simpleRootValueMutation',
385+
'name': 'simpleMutationWithThunkFields',
403386
'args': [
404387
{
405388
'name': 'input',
406389
'type': {
407390
'name': None,
408391
'kind': 'NON_NULL',
409392
'ofType': {
410-
'name': 'SimpleRootValueMutationInput',
393+
'name': 'SimpleMutationWithThunkFieldsInput',
411394
'kind': 'INPUT_OBJECT'
412395
}
413396
},
414397
}
415398
],
416399
'type': {
417-
'name': 'SimpleRootValueMutationPayload',
400+
'name': 'SimpleMutationWithThunkFieldsPayload',
418401
'kind': 'OBJECT',
419402
}
420403
},
421404
]
422405
}
423406
}
424-
425407
}
426408
result = graphql(schema, query)
427409
assert not result.errors
410+
# ensure the ordering is correct for the assertion
411+
expected['__schema']['mutationType']['fields'] = sorted(
412+
expected['__schema']['mutationType']['fields'],
413+
key=lambda k: k['name']
414+
)
415+
result.data['__schema']['mutationType']['fields'] = sorted(
416+
result.data['__schema']['mutationType']['fields'],
417+
key=lambda k: k['name']
418+
)
428419
assert result.data == expected

graphql_relay/node/node.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from collections import OrderedDict
22
from graphql_relay.utils import base64, unbase64
33

4+
from six import text_type
5+
46
from graphql.type import (
57
GraphQLArgument,
68
GraphQLNonNull,
@@ -52,7 +54,7 @@ def to_global_id(type, id):
5254
Takes a type name and an ID specific to that type name, and returns a
5355
"global ID" that is unique among all types.
5456
'''
55-
return base64(':'.join([type, str(id)]))
57+
return base64(':'.join([type, text_type(id)]))
5658

5759

5860
def from_global_id(global_id):

graphql_relay/node/tests/__init__.py

Whitespace-only changes.

graphql_relay/node/tests/test_global.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
from collections import namedtuple
2-
from pytest import raises
32
from graphql import graphql
43
from graphql.type import (
54
GraphQLSchema,
65
GraphQLObjectType,
76
GraphQLField,
8-
GraphQLArgument,
97
GraphQLList,
10-
GraphQLNonNull,
118
GraphQLInt,
129
GraphQLString,
13-
GraphQLBoolean,
14-
GraphQLID,
1510
)
1611

1712
from graphql_relay.node.node import (

graphql_relay/node/tests/test_node.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
14
from collections import namedtuple
2-
from pytest import raises
35
from graphql import graphql
46
from graphql.type import (
57
GraphQLSchema,
68
GraphQLObjectType,
79
GraphQLField,
8-
GraphQLArgument,
9-
GraphQLList,
1010
GraphQLNonNull,
1111
GraphQLInt,
1212
GraphQLString,
13-
GraphQLBoolean,
1413
GraphQLID,
1514
)
1615

17-
from graphql_relay.node.node import node_definitions
16+
from ..node import node_definitions, to_global_id, from_global_id
1817

1918
User = namedtuple('User', ['id', 'name'])
2019
Photo = namedtuple('Photo', ['id', 'width'])
@@ -332,3 +331,25 @@ def test_has_correct_node_root_field():
332331
result = graphql(schema, query)
333332
assert not result.errors
334333
assert result.data == expected
334+
335+
336+
def test_to_global_id_converts_unicode_strings_correctly():
337+
my_unicode_id = u'ûñö'
338+
g_id = to_global_id('MyType', my_unicode_id)
339+
assert g_id == 'TXlUeXBlOsO7w7HDtg=='
340+
341+
my_unicode_id = u'\u06ED'
342+
g_id = to_global_id('MyType', my_unicode_id)
343+
assert g_id == 'TXlUeXBlOtut'
344+
345+
346+
def test_from_global_id_converts_unicode_strings_correctly():
347+
my_unicode_id = u'ûñö'
348+
my_type, my_id = from_global_id('TXlUeXBlOsO7w7HDtg==')
349+
assert my_type == 'MyType'
350+
assert my_id == my_unicode_id
351+
352+
my_unicode_id = u'\u06ED'
353+
my_type, my_id = from_global_id('TXlUeXBlOtut')
354+
assert my_type == 'MyType'
355+
assert my_id == my_unicode_id

graphql_relay/tests/__init__.py

Whitespace-only changes.

graphql_relay/tests/test_utils.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import base64
5+
6+
from .. import utils
7+
8+
9+
def test_base64_encode_unicode_strings_correctly():
10+
my_unicode = u'ûñö'
11+
my_base64 = utils.base64(my_unicode)
12+
assert my_base64 == base64.b64encode(my_unicode.encode('utf-8')).decode('utf-8')
13+
14+
my_unicode = u'\u06ED'
15+
my_base64 = utils.base64(my_unicode)
16+
assert my_base64 == base64.b64encode(my_unicode.encode('utf-8')).decode('utf-8')
17+
18+
19+
def test_base64_encode_strings_correctly():
20+
my_string = 'abc'
21+
my_base64 = utils.base64(my_string)
22+
assert my_base64 == base64.b64encode(my_string.encode('utf-8')).decode('utf-8')
23+
24+
25+
def test_unbase64_decodes_unicode_strings_correctly():
26+
my_unicode = u'ûñö'
27+
my_converted_unicode = utils.unbase64(utils.base64(my_unicode))
28+
assert my_unicode == my_converted_unicode
29+
30+
31+
def test_unbase64_decodes_strings_correctly():
32+
my_string = 'abc'
33+
my_converted_string = utils.unbase64(utils.base64(my_string))
34+
assert my_string == my_converted_string

graphql_relay/utils.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
from base64 import b64encode as _base64, b64decode as _unbase64
22

3-
try:
4-
str_type = basestring
5-
base64 = _base64
6-
unbase64 = _unbase64
3+
from six import string_types
74

8-
def is_str(s):
9-
return isinstance(s, basestring)
105

11-
except NameError:
12-
def base64(s):
13-
return _base64(bytes(s, 'utf-8')).decode('utf-8')
6+
def base64(s):
7+
return _base64(s.encode('utf-8')).decode('utf-8')
148

15-
def unbase64(s):
16-
return _unbase64(s).decode('utf-8')
179

18-
def is_str(s):
19-
return isinstance(s, str)
10+
def unbase64(s):
11+
return _unbase64(s).decode('utf-8')
12+
13+
14+
def is_str(s):
15+
return isinstance(s, string_types)
2016

2117

2218
def resolve_maybe_thunk(f):

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def run_tests(self):
5454
packages=find_packages(exclude=['tests']),
5555

5656
install_requires=[
57+
'six>=1.10.0',
5758
'graphql-core>=0.5.0',
5859
'promise>=0.4.0'
5960
],

tox.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ envlist = py27,py33,py34,py35,pypy
55
deps=
66
pytest>=2.7.2
77
django>=1.8.0,<1.9
8+
six
89
flake8
910
singledispatch
1011
commands=

0 commit comments

Comments
 (0)