Skip to content

Commit

Permalink
Merge pull request #1414 from loft-orbital/issue-#1413_fix-invalid-in…
Browse files Browse the repository at this point in the history
…put-type

Providing an invalid value to an input type will now provoke an exception.
For example if the input as the type `UUID` and that you provide the value `2` it will now fail.
  • Loading branch information
erikwrede committed Aug 14, 2022
2 parents 97abb9d + 3bdc67c commit 23ca978
Show file tree
Hide file tree
Showing 11 changed files with 428 additions and 25 deletions.
2 changes: 1 addition & 1 deletion docs/types/scalars.rst
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ The following is an example for creating a DateTime scalar:
return dt.isoformat()
@staticmethod
def parse_literal(node):
def parse_literal(node, _variables=None):
if isinstance(node, ast.StringValue):
return datetime.datetime.strptime(
node.value, "%Y-%m-%dT%H:%M:%S.%f")
Expand Down
4 changes: 2 additions & 2 deletions graphene/tests/issues/test_1419.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
(ID, "1"),
(DateTime, '"2022-02-02T11:11:11"'),
(UUID, '"cbebbc62-758e-4f75-a890-bc73b5017d81"'),
(Decimal, "1.1"),
(JSONString, '{key:"foo",value:"bar"}'),
(Decimal, '"1.1"'),
(JSONString, '"{\\"key\\":\\"foo\\",\\"value\\":\\"bar\\"}"'),
(Base64, '"Q2hlbG8gd29ycmxkCg=="'),
],
)
Expand Down
6 changes: 4 additions & 2 deletions graphene/types/decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from decimal import Decimal as _Decimal

from graphql import Undefined
from graphql.language.ast import StringValueNode, IntValueNode

from .scalars import Scalar
Expand All @@ -25,10 +26,11 @@ def serialize(dec):
def parse_literal(cls, node, _variables=None):
if isinstance(node, (StringValueNode, IntValueNode)):
return cls.parse_value(node.value)
return Undefined

@staticmethod
def parse_value(value):
try:
return _Decimal(value)
except ValueError:
return None
except Exception:
return Undefined
7 changes: 6 additions & 1 deletion graphene/types/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import json

from graphql import Undefined
from graphql.language.ast import StringValueNode

from .scalars import Scalar
Expand All @@ -22,7 +23,11 @@ def serialize(dt):
@staticmethod
def parse_literal(node, _variables=None):
if isinstance(node, StringValueNode):
return json.loads(node.value)
try:
return json.loads(node.value)
except Exception as error:
raise ValueError(f"Badly formed JSONString: {str(error)}")
return Undefined

@staticmethod
def parse_value(value):
Expand Down
14 changes: 11 additions & 3 deletions graphene/types/scalars.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Any

from graphql import Undefined
from graphql.language.ast import (
BooleanValueNode,
FloatValueNode,
Expand Down Expand Up @@ -67,9 +68,10 @@ def coerce_int(value):
try:
num = int(float(value))
except ValueError:
return None
return Undefined
if MIN_INT <= num <= MAX_INT:
return num
return Undefined

serialize = coerce_int
parse_value = coerce_int
Expand All @@ -80,6 +82,7 @@ def parse_literal(ast, _variables=None):
num = int(ast.value)
if MIN_INT <= num <= MAX_INT:
return num
return Undefined


class BigInt(Scalar):
Expand All @@ -97,7 +100,7 @@ def coerce_int(value):
try:
num = int(float(value))
except ValueError:
return None
return Undefined
return num

serialize = coerce_int
Expand All @@ -107,6 +110,7 @@ def coerce_int(value):
def parse_literal(ast, _variables=None):
if isinstance(ast, IntValueNode):
return int(ast.value)
return Undefined


class Float(Scalar):
Expand All @@ -122,7 +126,7 @@ def coerce_float(value):
try:
return float(value)
except ValueError:
return None
return Undefined

serialize = coerce_float
parse_value = coerce_float
Expand All @@ -131,6 +135,7 @@ def coerce_float(value):
def parse_literal(ast, _variables=None):
if isinstance(ast, (FloatValueNode, IntValueNode)):
return float(ast.value)
return Undefined


class String(Scalar):
Expand All @@ -153,6 +158,7 @@ def coerce_string(value):
def parse_literal(ast, _variables=None):
if isinstance(ast, StringValueNode):
return ast.value
return Undefined


class Boolean(Scalar):
Expand All @@ -167,6 +173,7 @@ class Boolean(Scalar):
def parse_literal(ast, _variables=None):
if isinstance(ast, BooleanValueNode):
return ast.value
return Undefined


class ID(Scalar):
Expand All @@ -185,3 +192,4 @@ class ID(Scalar):
def parse_literal(ast, _variables=None):
if isinstance(ast, (StringValueNode, IntValueNode)):
return ast.value
return Undefined
17 changes: 17 additions & 0 deletions graphene/types/tests/test_decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,25 @@ def test_bad_decimal_query():
not_a_decimal = "Nobody expects the Spanish Inquisition!"

result = schema.execute("""{ decimal(input: "%s") }""" % not_a_decimal)
assert result.errors
assert len(result.errors) == 1
assert result.data is None
assert (
result.errors[0].message
== "Expected value of type 'Decimal', found \"Nobody expects the Spanish Inquisition!\"."
)

result = schema.execute("{ decimal(input: true) }")
assert result.errors
assert len(result.errors) == 1
assert result.data is None
assert result.errors[0].message == "Expected value of type 'Decimal', found true."

result = schema.execute("{ decimal(input: 1.2) }")
assert result.errors
assert len(result.errors) == 1
assert result.data is None
assert result.errors[0].message == "Expected value of type 'Decimal', found 1.2."


def test_decimal_string_query_integer():
Expand Down
52 changes: 52 additions & 0 deletions graphene/types/tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def test_jsonstring_query():
assert not result.errors
assert result.data == {"json": json_value}

result = schema.execute("""{ json(input: "{}") }""")
assert not result.errors
assert result.data == {"json": "{}"}


def test_jsonstring_query_variable():
json_value = '{"key": "value"}'
Expand All @@ -31,3 +35,51 @@ def test_jsonstring_query_variable():
)
assert not result.errors
assert result.data == {"json": json_value}


def test_jsonstring_optional_uuid_input():
"""
Test that we can provide a null value to an optional input
"""
result = schema.execute("{ json(input: null) }")
assert not result.errors
assert result.data == {"json": None}


def test_jsonstring_invalid_query():
"""
Test that if an invalid type is provided we get an error
"""
result = schema.execute("{ json(input: 1) }")
assert result.errors
assert len(result.errors) == 1
assert result.errors[0].message == "Expected value of type 'JSONString', found 1."

result = schema.execute("{ json(input: {}) }")
assert result.errors
assert len(result.errors) == 1
assert result.errors[0].message == "Expected value of type 'JSONString', found {}."

result = schema.execute('{ json(input: "a") }')
assert result.errors
assert len(result.errors) == 1
assert result.errors[0].message == (
"Expected value of type 'JSONString', found \"a\"; "
"Badly formed JSONString: Expecting value: line 1 column 1 (char 0)"
)

result = schema.execute("""{ json(input: "{\\'key\\': 0}") }""")
assert result.errors
assert len(result.errors) == 1
assert (
result.errors[0].message
== "Syntax Error: Invalid character escape sequence: '\\''."
)

result = schema.execute("""{ json(input: "{\\"key\\": 0,}") }""")
assert result.errors
assert len(result.errors) == 1
assert result.errors[0].message == (
'Expected value of type \'JSONString\', found "{\\"key\\": 0,}"; '
"Badly formed JSONString: Expecting property name enclosed in double quotes: line 1 column 11 (char 10)"
)

0 comments on commit 23ca978

Please sign in to comment.