Skip to content

Commit 209d9ce

Browse files
committed
perf: Minor improvements
1 parent 6e27011 commit 209d9ce

3 files changed

Lines changed: 32 additions & 23 deletions

File tree

docs/changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Changelog
44
`Unreleased`_ - TBD
55
-------------------
66

7+
**Performance**
8+
9+
- Improve performance on recent Hypothesis versions.
10+
711
`0.6.0`_ - 2022-04-25
812
---------------------
913

src/hypothesis_graphql/_strategies/primitives.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,42 @@
99
MIN_INT = -(2**31)
1010
MAX_INT = 2**31 - 1
1111

12+
TEXT_STRATEGY = st.text(alphabet=st.characters(blacklist_categories=("Cs",), max_codepoint=0xFFFF))
13+
1214

1315
def scalar(type_: graphql.GraphQLScalarType, nullable: bool = True) -> st.SearchStrategy[ScalarValueNode]:
14-
if type_.name == "Int":
16+
type_name = type_.name
17+
if type_name == "Int":
1518
return int_(nullable)
16-
if type_.name == "Float":
19+
if type_name == "Float":
1720
return float_(nullable)
18-
if type_.name == "String":
21+
if type_name == "String":
1922
return string(nullable)
20-
if type_.name == "ID":
23+
if type_name == "ID":
2124
return id_(nullable)
22-
if type_.name == "Boolean":
25+
if type_name == "Boolean":
2326
return boolean(nullable)
2427
raise TypeError("Custom scalar types are not supported")
2528

2629

2730
def enum(type_: graphql.GraphQLEnumType, nullable: bool = True) -> st.SearchStrategy[graphql.EnumValueNode]:
28-
value = st.sampled_from(list(type_.values))
29-
return maybe_null(value.map(make_enum_node), nullable)
31+
values = st.sampled_from(list(type_.values))
32+
return maybe_null(values.map(make_enum_node), nullable)
3033

3134

3235
def int_(nullable: bool = True) -> st.SearchStrategy[graphql.IntValueNode]:
33-
value = st.integers(min_value=MIN_INT, max_value=MAX_INT)
34-
return maybe_null(value.map(make_int_node), nullable)
36+
values = st.integers(min_value=MIN_INT, max_value=MAX_INT)
37+
return maybe_null(values.map(make_int_node), nullable)
3538

3639

3740
def float_(nullable: bool = True) -> st.SearchStrategy[graphql.FloatValueNode]:
38-
value = st.floats(allow_infinity=False, allow_nan=False)
39-
return maybe_null(value.map(make_float_node), nullable)
41+
values = st.floats(allow_infinity=False, allow_nan=False)
42+
return maybe_null(values.map(make_float_node), nullable)
4043

4144

4245
def string(nullable: bool = True) -> st.SearchStrategy[graphql.StringValueNode]:
43-
value = st.text(alphabet=st.characters(blacklist_categories=("Cs",), max_codepoint=0xFFFF))
44-
return maybe_null(value.map(make_string_node), nullable)
46+
values = st.text(alphabet=st.characters(blacklist_categories=("Cs",), max_codepoint=0xFFFF))
47+
return maybe_null(values.map(make_string_node), nullable)
4548

4649

4750
def id_(nullable: bool = True) -> st.SearchStrategy[Union[graphql.StringValueNode, graphql.IntValueNode]]:

src/hypothesis_graphql/_strategies/selections.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple, TypeVar, Union
1+
import operator
2+
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, TypeVar
23

34
import graphql
45
from graphql import is_equal_type
@@ -114,14 +115,17 @@ def selections_for_type(
114115
if not implementations:
115116
# Shortcut when there are no implementations - take fields from the interface itself
116117
return selections(context, field_type)
117-
return unique_by(implementations, lambda v: v.name).flatmap(lambda t: interfaces(context, field_type, t))
118+
return unique_by(implementations, BY_NAME).flatmap(lambda t: interfaces(context, field_type, t))
118119
if isinstance(field_type, graphql.GraphQLUnionType):
119120
# A union is a set of object types - take a subset of them and generate inline fragments
120-
return unique_by(field_type.types, lambda m: m.name).flatmap(lambda m: inline_fragments(context, m))
121+
return unique_by(field_type.types, BY_NAME).flatmap(lambda m: inline_fragments(context, m))
121122
# Other types don't have fields
122123
return st.none()
123124

124125

126+
BY_NAME = operator.attrgetter("name")
127+
128+
125129
def interfaces(
126130
context: Context, interface: graphql.GraphQLInterfaceType, implementations: List[InterfaceOrObject]
127131
) -> st.SearchStrategy[SelectionNodes]:
@@ -132,18 +136,16 @@ def interfaces(
132136
if overlapping_fields:
133137
return compose_interfaces_with_filter(selections(context, interface), strategies, implementations)
134138
# No overlapping - safe to choose any subset of fields within the interface itself and any fragment
135-
return st.tuples(selections(context, interface), *strategies).map(flatten).map(list) # type: ignore
139+
return st.tuples(selections(context, interface), *strategies).map(flatten) # type: ignore
136140

137141

138142
T = TypeVar("T")
139143

140144

141-
def flatten(items: Tuple[Union[T, List[T]], ...]) -> Generator[T, None, None]:
142-
for item in items:
143-
if isinstance(item, list):
144-
yield from item
145-
else:
146-
yield item
145+
def flatten(items: Tuple[List[T], T]) -> List[T]:
146+
output = items[0]
147+
output.extend(items[1:])
148+
return output
147149

148150

149151
def inline_fragments(context: Context, items: List[graphql.GraphQLObjectType]) -> st.SearchStrategy[SelectionNodes]:

0 commit comments

Comments
 (0)