mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-11 04:07:16 +03:00
Added scalars
This commit is contained in:
parent
55a1450dd3
commit
453d6d6ab7
148
graphene/new_types/scalars.py
Normal file
148
graphene/new_types/scalars.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
import six
|
||||
|
||||
from graphql.language.ast import BooleanValue, FloatValue, IntValue, StringValue
|
||||
|
||||
from ..utils.is_base_type import is_base_type
|
||||
from .options import Options
|
||||
from .unmountedtype import UnmountedType
|
||||
|
||||
|
||||
class ScalarTypeMeta(type):
|
||||
|
||||
def __new__(cls, name, bases, attrs):
|
||||
super_new = super(ScalarTypeMeta, cls).__new__
|
||||
|
||||
# Also ensure initialization is only performed for subclasses of Model
|
||||
# (excluding Model class itself).
|
||||
if not is_base_type(bases, ScalarTypeMeta):
|
||||
return super_new(cls, name, bases, attrs)
|
||||
|
||||
options = Options(
|
||||
attrs.pop('Meta', None),
|
||||
name=None,
|
||||
description=None,
|
||||
)
|
||||
|
||||
return super_new(cls, name, bases, dict(attrs, _meta=options))
|
||||
|
||||
|
||||
class Scalar(six.with_metaclass(ScalarTypeMeta, UnmountedType)):
|
||||
serialize = None
|
||||
parse_value = None
|
||||
parse_literal = None
|
||||
|
||||
# As per the GraphQL Spec, Integers are only treated as valid when a valid
|
||||
# 32-bit signed integer, providing the broadest support across platforms.
|
||||
#
|
||||
# n.b. JavaScript's integers are safe between -(2^53 - 1) and 2^53 - 1 because
|
||||
# they are internally represented as IEEE 754 doubles.
|
||||
MAX_INT = 2147483647
|
||||
MIN_INT = -2147483648
|
||||
|
||||
|
||||
class Int(Scalar):
|
||||
'''
|
||||
The `Int` scalar type represents non-fractional signed whole numeric
|
||||
values. Int can represent values between -(2^53 - 1) and 2^53 - 1 since
|
||||
represented in JSON as double-precision floating point numbers specified
|
||||
by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
|
||||
'''
|
||||
|
||||
@staticmethod
|
||||
def coerce_int(value):
|
||||
try:
|
||||
num = int(value)
|
||||
except ValueError:
|
||||
try:
|
||||
num = int(float(value))
|
||||
except ValueError:
|
||||
return None
|
||||
if MIN_INT <= num <= MAX_INT:
|
||||
return num
|
||||
|
||||
serialize = coerce_int
|
||||
parse_value = coerce_int
|
||||
|
||||
@staticmethod
|
||||
def parse_literal(ast):
|
||||
if isinstance(ast, IntValue):
|
||||
num = int(ast.value)
|
||||
if MIN_INT <= num <= MAX_INT:
|
||||
return num
|
||||
|
||||
|
||||
class Float(Scalar):
|
||||
'''
|
||||
The `Float` scalar type represents signed double-precision fractional
|
||||
values as specified by
|
||||
[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
|
||||
'''
|
||||
|
||||
@staticmethod
|
||||
def coerce_float(value):
|
||||
try:
|
||||
return float(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
serialize = coerce_float
|
||||
parse_value = coerce_float
|
||||
|
||||
@staticmethod
|
||||
def parse_literal(ast):
|
||||
if isinstance(ast, (FloatValue, IntValue)):
|
||||
return float(ast.value)
|
||||
|
||||
|
||||
class String(Scalar):
|
||||
'''
|
||||
The `String` scalar type represents textual data, represented as UTF-8
|
||||
character sequences. The String type is most often used by GraphQL to
|
||||
represent free-form human-readable text.
|
||||
'''
|
||||
|
||||
@staticmethod
|
||||
def coerce_string(value):
|
||||
if isinstance(value, bool):
|
||||
return u'true' if value else u'false'
|
||||
return six.text_type(value)
|
||||
|
||||
serialize = coerce_string
|
||||
parse_value = coerce_string
|
||||
|
||||
@staticmethod
|
||||
def parse_literal(ast):
|
||||
if isinstance(ast, StringValue):
|
||||
return ast.value
|
||||
|
||||
|
||||
class Boolean(Scalar):
|
||||
'''
|
||||
The `Boolean` scalar type represents `true` or `false`.
|
||||
'''
|
||||
|
||||
serialize = bool
|
||||
parse_value = bool
|
||||
|
||||
@staticmethod
|
||||
def parse_literal(ast):
|
||||
if isinstance(ast, BooleanValue):
|
||||
return ast.value
|
||||
|
||||
|
||||
class ID(Scalar):
|
||||
'''
|
||||
The `ID` scalar type represents a unique identifier, often used to
|
||||
refetch an object or as key for a cache. The ID type appears in a JSON
|
||||
response as a String; however, it is not intended to be human-readable.
|
||||
When expected as an input type, any string (such as `"4"`) or integer
|
||||
(such as `4`) input value will be accepted as an ID.
|
||||
'''
|
||||
|
||||
serialize = str
|
||||
parse_value = str
|
||||
|
||||
@staticmethod
|
||||
def parse_literal(ast):
|
||||
if isinstance(ast, (StringValue, IntValue)):
|
||||
return ast.value
|
|
@ -70,6 +70,7 @@ def test_generate_objecttype_inherit_abstracttype():
|
|||
assert MyObjectType._meta.fields.keys() == ['field1', 'field2']
|
||||
assert [type(x) for x in MyObjectType._meta.fields.values()] == [Field, Field]
|
||||
|
||||
|
||||
def test_generate_objecttype_inherit_abstracttype_reversed():
|
||||
class MyAbstractType(AbstractType):
|
||||
field1 = MyScalar(MyType)
|
||||
|
|
50
graphene/new_types/tests/test_scalars_serialization.py
Normal file
50
graphene/new_types/tests/test_scalars_serialization.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
from ..scalars import (Boolean, Float, Int, String)
|
||||
|
||||
|
||||
def test_serializes_output_int():
|
||||
assert Int.serialize(1) == 1
|
||||
assert Int.serialize(0) == 0
|
||||
assert Int.serialize(-1) == -1
|
||||
assert Int.serialize(0.1) == 0
|
||||
assert Int.serialize(1.1) == 1
|
||||
assert Int.serialize(-1.1) == -1
|
||||
assert Int.serialize(1e5) == 100000
|
||||
assert Int.serialize(9876504321) is None
|
||||
assert Int.serialize(-9876504321) is None
|
||||
assert Int.serialize(1e100) is None
|
||||
assert Int.serialize(-1e100) is None
|
||||
assert Int.serialize('-1.1') == -1
|
||||
assert Int.serialize('one') is None
|
||||
assert Int.serialize(False) == 0
|
||||
assert Int.serialize(True) == 1
|
||||
|
||||
|
||||
def test_serializes_output_float():
|
||||
assert Float.serialize(1) == 1.0
|
||||
assert Float.serialize(0) == 0.0
|
||||
assert Float.serialize(-1) == -1.0
|
||||
assert Float.serialize(0.1) == 0.1
|
||||
assert Float.serialize(1.1) == 1.1
|
||||
assert Float.serialize(-1.1) == -1.1
|
||||
assert Float.serialize('-1.1') == -1.1
|
||||
assert Float.serialize('one') is None
|
||||
assert Float.serialize(False) == 0
|
||||
assert Float.serialize(True) == 1
|
||||
|
||||
|
||||
def test_serializes_output_string():
|
||||
assert String.serialize('string') == 'string'
|
||||
assert String.serialize(1) == '1'
|
||||
assert String.serialize(-1.1) == '-1.1'
|
||||
assert String.serialize(True) == 'true'
|
||||
assert String.serialize(False) == 'false'
|
||||
assert String.serialize(u'\U0001F601') == u'\U0001F601'
|
||||
|
||||
|
||||
def test_serializes_output_boolean():
|
||||
assert Boolean.serialize('string') is True
|
||||
assert Boolean.serialize('') is False
|
||||
assert Boolean.serialize(1) is True
|
||||
assert Boolean.serialize(0) is False
|
||||
assert Boolean.serialize(True) is True
|
||||
assert Boolean.serialize(False) is False
|
Loading…
Reference in New Issue
Block a user