Skip to content

Commit fc84f92

Browse files
author
Rami Chowdhury
committed
Set up automated testing on CircleCI
1 parent 0d1612b commit fc84f92

File tree

8 files changed

+79
-35
lines changed

8 files changed

+79
-35
lines changed

.circleci/config.yml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
version: 2
1+
version: 2.1
22
jobs:
33
build:
44
docker:
5-
- image: circleci/python:3.7
5+
- image: themattrix/tox
66
steps:
77
- checkout
8-
- run:
9-
name: Install Tox
10-
command: pip install tox
11-
- run:
12-
name: Tests with Tox
13-
command: tox
14-
8+
- run: tox

.pre-commit-config.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,3 @@ repos:
2828
hooks:
2929
- id: black
3030
language_version: python3.7
31-

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# ![Graphene Logo](http://graphene-python.org/favicon.png) Graphene-Pydantic [![Build Status](https://travis-ci.org/graphql-python/graphene-pydantic.svg?branch=master)](https://circle-ci.org/graphql-python/graphene-sqlalchemy) [![PyPI version](https://badge.fury.io/py/graphene-pydantic.svg)](https://badge.fury.io/py/graphene-pydantic) [![Coverage Status](https://coveralls.io/repos/graphql-python/graphene-sqlalchemy/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-python/graphene-sqlalchemy?branch=master)
1+
# ![Graphene Logo](http://graphene-python.org/favicon.png) graphene-pydantic [![Build status](https://circleci.com/gh/upsidetravel/graphene-pydantic-2.svg?style=svg)](https://circleci.com/gh/upsidetravel/graphene-pydantic-2) [![PyPI version](https://badge.fury.io/py/graphene-pydantic.svg)](https://badge.fury.io/py/graphene-pydantic) [![Coverage Status](https://coveralls.io/repos/upsidetravel/graphene-pydantic/badge.svg?branch=master&service=github)](https://coveralls.io/github/upsidetravel/graphene-pydantic?branch=master)
2+
23

34

45
A [Pydantic](https://pydantic-docs.helpmanual.io/) integration for [Graphene](http://graphene-python.org/).

graphene_pydantic/converters.py

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,23 @@
55
import enum
66
import inspect
77

8-
from graphene import Field, Boolean, Dynamic, Enum, Float, Int, List, String, UUID, Union
8+
from graphene import (
9+
Field,
10+
Boolean,
11+
Dynamic,
12+
Enum,
13+
Float,
14+
Int,
15+
List,
16+
String,
17+
UUID,
18+
Union,
19+
)
920
from graphene.types.base import BaseType
21+
1022
try:
1123
from graphene.types.decimal import Decimal as GrapheneDecimal
24+
1225
DECIMAL_SUPPORTED = True
1326
except ImportError:
1427
# graphene 2.1.5+ is required for Decimals
@@ -24,21 +37,21 @@ class ConversionError(TypeError):
2437
pass
2538

2639

27-
# Placeholder for NoneType, so that we can easily reference it later
28-
TYPE_NONE = type(None)
29-
30-
3140
def get_attr_resolver(attr_name: str) -> T.Callable:
3241
"""
3342
Return a helper function that resolves a field with the given name by
3443
looking it up as an attribute of the type we're trying to resolve it on.
3544
"""
45+
3646
def _get_field(root, _info):
3747
return getattr(root, attr_name, None)
48+
3849
return _get_field
3950

4051

41-
def convert_pydantic_field(field: fields.Field, registry: Registry, **field_kwargs) -> Field:
52+
def convert_pydantic_field(
53+
field: fields.Field, registry: Registry, **field_kwargs
54+
) -> Field:
4255
"""
4356
Convert a Pydantic model field into a Graphene type field that we can add
4457
to the generated Graphene data model type.
@@ -58,7 +71,9 @@ def convert_pydantic_field(field: fields.Field, registry: Registry, **field_kwar
5871
return Field(resolver=get_attr_resolver(field.name), **field_kwargs)
5972

6073

61-
def to_graphene_type(type_: T.Type, field: fields.Field, registry: Registry = None) -> BaseType: # noqa: C901
74+
def to_graphene_type(
75+
type_: T.Type, field: fields.Field, registry: Registry = None
76+
) -> BaseType: # noqa: C901
6277
"""
6378
Map a native Python type to a Graphene-supported Field type, where possible.
6479
"""
@@ -83,7 +98,7 @@ def to_graphene_type(type_: T.Type, field: fields.Field, registry: Registry = No
8398
elif type_ in (tuple, list, set):
8499
# TODO: do Sets really belong here?
85100
return List
86-
elif hasattr(type_, '__origin__'):
101+
elif hasattr(type_, "__origin__"):
87102
return convert_generic_type(type_, field, registry)
88103
elif issubclass(type_, enum.Enum):
89104
return Enum.from_enum(type_)
@@ -98,7 +113,9 @@ def to_graphene_type(type_: T.Type, field: fields.Field, registry: Registry = No
98113
)
99114

100115

101-
def convert_pydantic_type(type_: T.Type, field: fields.Field, registry: Registry = None) -> BaseType: # noqa: C901
116+
def convert_pydantic_type(
117+
type_: T.Type, field: fields.Field, registry: Registry = None
118+
) -> BaseType: # noqa: C901
102119
"""
103120
Convert a Pydantic type to a Graphene Field type, including not just the
104121
native Python type but any additional metadata (e.g. shape) that Pydantic
@@ -107,7 +124,12 @@ def convert_pydantic_type(type_: T.Type, field: fields.Field, registry: Registry
107124
graphene_type = to_graphene_type(type_, field, registry)
108125
if field.shape == fields.Shape.SINGLETON:
109126
return graphene_type
110-
elif field.shape in (fields.Shape.LIST, fields.Shape.TUPLE, fields.Shape.SEQUENCE, fields.Shape.SET):
127+
elif field.shape in (
128+
fields.Shape.LIST,
129+
fields.Shape.TUPLE,
130+
fields.Shape.SEQUENCE,
131+
fields.Shape.SET,
132+
):
111133
# TODO: _should_ Sets remain here?
112134
return List(graphene_type)
113135
elif field.shape == fields.Shape.MAPPING:
@@ -142,16 +164,20 @@ def convert_union_type(type_, field, registry=None):
142164
wrapped_types = type_.__args__
143165
# NOTE: a typing.Optional decomposes to a Union[None, T], so we can return
144166
# the Graphene type for T; Pydantic will have already parsed it as optional
145-
if len(wrapped_types) == 2 and TYPE_NONE in wrapped_types:
146-
native_type = next(x for x in wrapped_types if x != TYPE_NONE)
167+
if len(wrapped_types) == 2 and type(None) in wrapped_types:
168+
native_type = next(x for x in wrapped_types if x != type(None)) # noqa: E721
147169
graphene_type = to_graphene_type(native_type, field, registry)
148170
return graphene_type
149171
else:
150172
# Otherwise, we use a little metaprogramming -- create our own unique
151173
# subclass of graphene.Union that knows its constituent Graphene types
152-
graphene_types = tuple(to_graphene_type(x, field, registry) for x in wrapped_types)
153-
internal_meta = type("Meta", (), {'types': graphene_types})
174+
graphene_types = tuple(
175+
to_graphene_type(x, field, registry) for x in wrapped_types
176+
)
177+
internal_meta = type("Meta", (), {"types": graphene_types})
154178

155179
union_class_name = "".join(x.__name__ for x in wrapped_types)
156-
union_class = type(f"Union_{union_class_name}", (Union,), {'Meta': internal_meta})
180+
union_class = type(
181+
f"Union_{union_class_name}", (Union,), {"Meta": internal_meta}
182+
)
157183
return union_class

graphene_pydantic/registry.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ def __init__(self):
2323
def register(self, obj_type):
2424
assert_is_pydantic_object_type(obj_type)
2525

26-
assert obj_type._meta.registry == self, "Can't register models linked to another Registry"
26+
assert (
27+
obj_type._meta.registry == self
28+
), "Can't register models linked to another Registry"
2729
self._registry[obj_type._meta.model] = obj_type
2830

2931
def get_type_for_model(self, model):
@@ -49,9 +51,7 @@ def register_enum(self, py_enum, graphene_enum):
4951
if not isinstance(py_enum, PyEnum):
5052
raise TypeError(f"Expected Python Enum, but got: {py_enum!r}")
5153
if not isinstance(graphene_enum, type(Enum)):
52-
raise TypeError(
53-
f"Expected Graphene Enum, but got: {graphene_enum!r}"
54-
)
54+
raise TypeError(f"Expected Graphene Enum, but got: {graphene_enum!r}")
5555

5656
self._registry_enums[py_enum] = graphene_enum
5757

graphene_pydantic/types.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ def construct_fields(
3333
"""
3434
fields = {}
3535
for name, field in model.__fields__.items():
36-
converted = convert_pydantic_field(
37-
field,
38-
registry,
39-
)
36+
converted = convert_pydantic_field(field, registry)
4037
registry.register_orm_field(obj_type, name, field)
4138
fields[name] = converted
4239
return fields

tests/test_converters.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import graphene
2+
from pydantic import BaseModel, create_model
3+
4+
5+
from graphene_pydantic.types import PydanticObjectType
6+
from graphene_pydantic.converters import convert_pydantic_field
7+
from graphene_pydantic.registry import get_global_registry
8+
9+
10+
def _get_field_from_spec(name, type_spec_or_default):
11+
kwargs = {name: type_spec_or_default}
12+
m = create_model('model', **kwargs)
13+
return m.__fields__[name]
14+
15+
16+
def test_convert_string():
17+
field = convert_pydantic_field(
18+
_get_field_from_spec('prop', (str, ...)),
19+
get_global_registry())
20+
assert field is not None
21+
assert isinstance(field, graphene.Field)
22+
assert isinstance(field.type, graphene.NonNull) # ... means required
23+
assert field.type.of_type == graphene.String

tox.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ skipsdist = true
55
[testenv]
66
deps =
77
.[test]
8+
mypy
9+
black
810
commands =
9-
pytest graphene_pydantic --cov-report=term-missing --cov=graphene_pydantic {posargs}
11+
pytest tests/ --cov-report=term-missing --cov=graphene_pydantic {posargs}
12+
mypy --ignore-missing-imports --no-strict-optional -m graphene_pydantic
13+
black --check graphene_pydantic
1014

1115
[testenv:pre-commit]
1216
basepython=python3.7

0 commit comments

Comments
 (0)