👷 Add pre-commit (#1336)

* 🔧 Add pre-commit config

Similar to graphene and graphene-sqlalchemy

* ⬆ Bump black

* 👷 Lint on CI

* ⬆ Bump flake8-black

* 🔧 Keep excluding migrations

* ⬆ Bump flake8

* 🔧 Remove black and flake8 from tox config

* ⬆ Update pre-commit versions

* Upgrade syntax to python 3.7+

* Format with pre-commit

dedent docs/schema.py to allow formatting

* Fix tests on python 3.7
This commit is contained in:
Nikolai Røed Kristiansen 2022-10-19 16:10:30 +02:00 committed by GitHub
parent f24cbd5148
commit 4517e32224
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 779 additions and 244 deletions

View File

@ -27,8 +27,8 @@ a github repo, https://repl.it or similar (you can use this template as a starti
* **Please tell us about your environment:** * **Please tell us about your environment:**
- Version: - Version:
- Platform: - Platform:
* **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow) * **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow)

View File

@ -16,7 +16,7 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install tox pip install tox
- name: Run lint 💅 - name: Run pre-commit 💅
run: tox run: tox
env: env:
TOXENV: flake8 TOXENV: pre-commit

30
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,30 @@
default_language_version:
python: python3.9
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-merge-conflict
- id: check-json
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
exclude: ^docs/.*$
- id: pretty-format-json
args:
- --autofix
- id: trailing-whitespace
exclude: README.md
- repo: https://github.com/asottile/pyupgrade
rev: v2.37.3
hooks:
- id: pyupgrade
args: [--py37-plus]
- repo: https://github.com/psf/black
rev: 22.6.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 5.0.4
hooks:
- id: flake8

View File

@ -59,4 +59,4 @@ Then to produce a HTML version of the documentation:
```sh ```sh
make html make html
``` ```

View File

@ -3,4 +3,4 @@ recursive-include graphene_django/templates *
recursive-include graphene_django/static * recursive-include graphene_django/static *
include examples/cookbook/cookbook/ingredients/fixtures/ingredients.json include examples/cookbook/cookbook/ingredients/fixtures/ingredients.json
include examples/cookbook-plain/cookbook/ingredients/fixtures/ingredients.json include examples/cookbook-plain/cookbook/ingredients/fixtures/ingredients.json

View File

@ -13,7 +13,7 @@ tests:
.PHONY: format ## Format code .PHONY: format ## Format code
format: format:
black --exclude "/migrations/" graphene_django examples setup.py black graphene_django examples setup.py
.PHONY: lint ## Lint code .PHONY: lint ## Lint code
lint: lint:

View File

@ -1,60 +1,57 @@
import graphene import graphene
from graphene_django.types import DjangoObjectType from graphene_django.types import DjangoObjectType
from cookbook.ingredients.models import Category, Ingredient from cookbook.ingredients.models import Category, Ingredient
class CategoryType(DjangoObjectType): class CategoryType(DjangoObjectType):
class Meta: class Meta:
model = Category model = Category
fields = '__all__' fields = "__all__"
class IngredientType(DjangoObjectType): class IngredientType(DjangoObjectType):
class Meta: class Meta:
model = Ingredient model = Ingredient
fields = '__all__' fields = "__all__"
class Query(object): class Query:
category = graphene.Field(CategoryType, category = graphene.Field(CategoryType, id=graphene.Int(), name=graphene.String())
id=graphene.Int(), all_categories = graphene.List(CategoryType)
name=graphene.String())
all_categories = graphene.List(CategoryType)
ingredient = graphene.Field(
IngredientType, id=graphene.Int(), name=graphene.String()
)
all_ingredients = graphene.List(IngredientType)
ingredient = graphene.Field(IngredientType, def resolve_all_categories(self, info, **kwargs):
id=graphene.Int(), return Category.objects.all()
name=graphene.String())
all_ingredients = graphene.List(IngredientType)
def resolve_all_categories(self, info, **kwargs): def resolve_all_ingredients(self, info, **kwargs):
return Category.objects.all() return Ingredient.objects.all()
def resolve_all_ingredients(self, info, **kwargs): def resolve_category(self, info, **kwargs):
return Ingredient.objects.all() id = kwargs.get("id")
name = kwargs.get("name")
def resolve_category(self, info, **kwargs): if id is not None:
id = kwargs.get('id') return Category.objects.get(pk=id)
name = kwargs.get('name')
if id is not None: if name is not None:
return Category.objects.get(pk=id) return Category.objects.get(name=name)
if name is not None: return None
return Category.objects.get(name=name)
return None def resolve_ingredient(self, info, **kwargs):
id = kwargs.get("id")
name = kwargs.get("name")
def resolve_ingredient(self, info, **kwargs): if id is not None:
id = kwargs.get('id') return Ingredient.objects.get(pk=id)
name = kwargs.get('name')
if id is not None: if name is not None:
return Ingredient.objects.get(pk=id) return Ingredient.objects.get(name=name)
if name is not None: return None
return Ingredient.objects.get(name=name)
return None

View File

@ -85,8 +85,8 @@ Make sure the app name in ``cookbook.ingredients.apps.IngredientsConfig`` is set
# cookbook/ingredients/apps.py # cookbook/ingredients/apps.py
from django.apps import AppConfig from django.apps import AppConfig
class IngredientsConfig(AppConfig): class IngredientsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = 'django.db.models.BigAutoField'
name = 'cookbook.ingredients' name = 'cookbook.ingredients'

View File

@ -1 +1,52 @@
[{"model": "ingredients.category", "pk": 1, "fields": {"name": "Dairy"}}, {"model": "ingredients.category", "pk": 2, "fields": {"name": "Meat"}}, {"model": "ingredients.ingredient", "pk": 1, "fields": {"name": "Eggs", "notes": "Good old eggs", "category": 1}}, {"model": "ingredients.ingredient", "pk": 2, "fields": {"name": "Milk", "notes": "Comes from a cow", "category": 1}}, {"model": "ingredients.ingredient", "pk": 3, "fields": {"name": "Beef", "notes": "Much like milk, this comes from a cow", "category": 2}}, {"model": "ingredients.ingredient", "pk": 4, "fields": {"name": "Chicken", "notes": "Definitely doesn't come from a cow", "category": 2}}] [
{
"fields": {
"name": "Dairy"
},
"model": "ingredients.category",
"pk": 1
},
{
"fields": {
"name": "Meat"
},
"model": "ingredients.category",
"pk": 2
},
{
"fields": {
"category": 1,
"name": "Eggs",
"notes": "Good old eggs"
},
"model": "ingredients.ingredient",
"pk": 1
},
{
"fields": {
"category": 1,
"name": "Milk",
"notes": "Comes from a cow"
},
"model": "ingredients.ingredient",
"pk": 2
},
{
"fields": {
"category": 2,
"name": "Beef",
"notes": "Much like milk, this comes from a cow"
},
"model": "ingredients.ingredient",
"pk": 3
},
{
"fields": {
"category": 2,
"name": "Chicken",
"notes": "Definitely doesn't come from a cow"
},
"model": "ingredients.ingredient",
"pk": 4
}
]

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2015-12-04 18:15 # Generated by Django 1.9 on 2015-12-04 18:15
from __future__ import unicode_literals
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
@ -10,24 +8,46 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Category', name="Category",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=100)), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Ingredient', name="Ingredient",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=100)), "id",
('notes', models.TextField()), models.AutoField(
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ingredients', to='ingredients.Category')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
("notes", models.TextField()),
(
"category",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="ingredients",
to="ingredients.Category",
),
),
], ],
), ),
] ]

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-11-04 00:50 # Generated by Django 1.9 on 2016-11-04 00:50
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -8,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('ingredients', '0001_initial'), ("ingredients", "0001_initial"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='ingredient', model_name="ingredient",
name='notes', name="notes",
field=models.TextField(blank=True, null=True), field=models.TextField(blank=True, null=True),
), ),
] ]

View File

@ -6,12 +6,12 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('ingredients', '0002_auto_20161104_0050'), ("ingredients", "0002_auto_20161104_0050"),
] ]
operations = [ operations = [
migrations.AlterModelOptions( migrations.AlterModelOptions(
name='category', name="category",
options={'verbose_name_plural': 'Categories'}, options={"verbose_name_plural": "Categories"},
), ),
] ]

View File

@ -16,7 +16,7 @@ class IngredientType(DjangoObjectType):
fields = "__all__" fields = "__all__"
class Query(object): class Query:
category = graphene.Field(CategoryType, id=graphene.Int(), name=graphene.String()) category = graphene.Field(CategoryType, id=graphene.Int(), name=graphene.String())
all_categories = graphene.List(CategoryType) all_categories = graphene.List(CategoryType)

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2015-12-04 18:20 # Generated by Django 1.9 on 2015-12-04 18:20
from __future__ import unicode_literals
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
@ -11,26 +9,62 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('ingredients', '0001_initial'), ("ingredients", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Recipe', name="Recipe",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('title', models.CharField(max_length=100)), "id",
('instructions', models.TextField()), models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=100)),
("instructions", models.TextField()),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='RecipeIngredient', name="RecipeIngredient",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('amount', models.FloatField()), "id",
('unit', models.CharField(choices=[('kg', 'Kilograms'), ('l', 'Litres'), ('', 'Units')], max_length=20)), models.AutoField(
('ingredient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='used_by', to='ingredients.Ingredient')), auto_created=True,
('recipes', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='amounts', to='recipes.Recipe')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("amount", models.FloatField()),
(
"unit",
models.CharField(
choices=[("kg", "Kilograms"), ("l", "Litres"), ("", "Units")],
max_length=20,
),
),
(
"ingredient",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="used_by",
to="ingredients.Ingredient",
),
),
(
"recipes",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="amounts",
to="recipes.Recipe",
),
),
], ],
), ),
] ]

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-11-04 01:06 # Generated by Django 1.9 on 2016-11-04 01:06
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -8,18 +6,26 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('recipes', '0001_initial'), ("recipes", "0001_initial"),
] ]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(
model_name='recipeingredient', model_name="recipeingredient",
old_name='recipes', old_name="recipes",
new_name='recipe', new_name="recipe",
), ),
migrations.AlterField( migrations.AlterField(
model_name='recipeingredient', model_name="recipeingredient",
name='unit', name="unit",
field=models.CharField(choices=[(b'unit', b'Units'), (b'kg', b'Kilograms'), (b'l', b'Litres'), (b'st', b'Shots')], max_length=20), field=models.CharField(
choices=[
(b"unit", b"Units"),
(b"kg", b"Kilograms"),
(b"l", b"Litres"),
(b"st", b"Shots"),
],
max_length=20,
),
), ),
] ]

View File

@ -6,13 +6,21 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('recipes', '0002_auto_20161104_0106'), ("recipes", "0002_auto_20161104_0106"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='recipeingredient', model_name="recipeingredient",
name='unit', name="unit",
field=models.CharField(choices=[('unit', 'Units'), ('kg', 'Kilograms'), ('l', 'Litres'), ('st', 'Shots')], max_length=20), field=models.CharField(
choices=[
("unit", "Units"),
("kg", "Kilograms"),
("l", "Litres"),
("st", "Shots"),
],
max_length=20,
),
), ),
] ]

View File

@ -16,7 +16,7 @@ class RecipeIngredientType(DjangoObjectType):
fields = "__all__" fields = "__all__"
class Query(object): class Query:
recipe = graphene.Field(RecipeType, id=graphene.Int(), title=graphene.String()) recipe = graphene.Field(RecipeType, id=graphene.Int(), title=graphene.String())
all_recipes = graphene.List(RecipeType) all_recipes = graphene.List(RecipeType)

View File

@ -1 +1,52 @@
[{"model": "ingredients.category", "pk": 1, "fields": {"name": "Dairy"}}, {"model": "ingredients.category", "pk": 2, "fields": {"name": "Meat"}}, {"model": "ingredients.ingredient", "pk": 1, "fields": {"name": "Eggs", "notes": "Good old eggs", "category": 1}}, {"model": "ingredients.ingredient", "pk": 2, "fields": {"name": "Milk", "notes": "Comes from a cow", "category": 1}}, {"model": "ingredients.ingredient", "pk": 3, "fields": {"name": "Beef", "notes": "Much like milk, this comes from a cow", "category": 2}}, {"model": "ingredients.ingredient", "pk": 4, "fields": {"name": "Chicken", "notes": "Definitely doesn't come from a cow", "category": 2}}] [
{
"fields": {
"name": "Dairy"
},
"model": "ingredients.category",
"pk": 1
},
{
"fields": {
"name": "Meat"
},
"model": "ingredients.category",
"pk": 2
},
{
"fields": {
"category": 1,
"name": "Eggs",
"notes": "Good old eggs"
},
"model": "ingredients.ingredient",
"pk": 1
},
{
"fields": {
"category": 1,
"name": "Milk",
"notes": "Comes from a cow"
},
"model": "ingredients.ingredient",
"pk": 2
},
{
"fields": {
"category": 2,
"name": "Beef",
"notes": "Much like milk, this comes from a cow"
},
"model": "ingredients.ingredient",
"pk": 3
},
{
"fields": {
"category": 2,
"name": "Chicken",
"notes": "Definitely doesn't come from a cow"
},
"model": "ingredients.ingredient",
"pk": 4
}
]

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2015-12-04 18:15 # Generated by Django 1.9 on 2015-12-04 18:15
from __future__ import unicode_literals
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
@ -10,24 +8,46 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Category', name="Category",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=100)), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Ingredient', name="Ingredient",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=100)), "id",
('notes', models.TextField()), models.AutoField(
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ingredients', to='ingredients.Category')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100)),
("notes", models.TextField()),
(
"category",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="ingredients",
to="ingredients.Category",
),
),
], ],
), ),
] ]

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-11-04 00:50 # Generated by Django 1.9 on 2016-11-04 00:50
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -8,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('ingredients', '0001_initial'), ("ingredients", "0001_initial"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='ingredient', model_name="ingredient",
name='notes', name="notes",
field=models.TextField(blank=True, null=True), field=models.TextField(blank=True, null=True),
), ),
] ]

View File

@ -28,7 +28,7 @@ class IngredientNode(DjangoObjectType):
} }
class Query(object): class Query:
category = Node.Field(CategoryNode) category = Node.Field(CategoryNode)
all_categories = DjangoFilterConnectionField(CategoryNode) all_categories = DjangoFilterConnectionField(CategoryNode)

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2015-12-04 18:20 # Generated by Django 1.9 on 2015-12-04 18:20
from __future__ import unicode_literals
import django.db.models.deletion import django.db.models.deletion
from django.db import migrations, models from django.db import migrations, models
@ -11,26 +9,62 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('ingredients', '0001_initial'), ("ingredients", "0001_initial"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Recipe', name="Recipe",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('title', models.CharField(max_length=100)), "id",
('instructions', models.TextField()), models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=100)),
("instructions", models.TextField()),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='RecipeIngredient', name="RecipeIngredient",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('amount', models.FloatField()), "id",
('unit', models.CharField(choices=[('kg', 'Kilograms'), ('l', 'Litres'), ('', 'Units')], max_length=20)), models.AutoField(
('ingredient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='used_by', to='ingredients.Ingredient')), auto_created=True,
('recipes', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='amounts', to='recipes.Recipe')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("amount", models.FloatField()),
(
"unit",
models.CharField(
choices=[("kg", "Kilograms"), ("l", "Litres"), ("", "Units")],
max_length=20,
),
),
(
"ingredient",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="used_by",
to="ingredients.Ingredient",
),
),
(
"recipes",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="amounts",
to="recipes.Recipe",
),
),
], ],
), ),
] ]

View File

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-11-04 01:06 # Generated by Django 1.9 on 2016-11-04 01:06
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -8,18 +6,26 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('recipes', '0001_initial'), ("recipes", "0001_initial"),
] ]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(
model_name='recipeingredient', model_name="recipeingredient",
old_name='recipes', old_name="recipes",
new_name='recipe', new_name="recipe",
), ),
migrations.AlterField( migrations.AlterField(
model_name='recipeingredient', model_name="recipeingredient",
name='unit', name="unit",
field=models.CharField(choices=[(b'unit', b'Units'), (b'kg', b'Kilograms'), (b'l', b'Litres'), (b'st', b'Shots')], max_length=20), field=models.CharField(
choices=[
(b"unit", b"Units"),
(b"kg", b"Kilograms"),
(b"l", b"Litres"),
(b"st", b"Shots"),
],
max_length=20,
),
), ),
] ]

View File

@ -25,7 +25,7 @@ class RecipeIngredientNode(DjangoObjectType):
} }
class Query(object): class Query:
recipe = Node.Field(RecipeNode) recipe = Node.Field(RecipeNode)
all_recipes = DjangoFilterConnectionField(RecipeNode) all_recipes = DjangoFilterConnectionField(RecipeNode)

View File

@ -1 +1,302 @@
[{"model": "auth.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$24000$0SgBlSlnbv5c$ijVQipm2aNDlcrTL8Qi3SVNHphTm4HIsDfUi4kn9tog=", "last_login": "2016-11-04T00:46:58Z", "is_superuser": true, "username": "admin", "first_name": "", "last_name": "", "email": "asdf@example.com", "is_staff": true, "is_active": true, "date_joined": "2016-11-03T18:24:40Z", "groups": [], "user_permissions": []}}, {"model": "recipes.recipe", "pk": 1, "fields": {"title": "Cheerios With a Shot of Vermouth", "instructions": "https://xkcd.com/720/"}}, {"model": "recipes.recipe", "pk": 2, "fields": {"title": "Quail Eggs in Whipped Cream and MSG", "instructions": "https://xkcd.com/720/"}}, {"model": "recipes.recipe", "pk": 3, "fields": {"title": "Deep Fried Skittles", "instructions": "https://xkcd.com/720/"}}, {"model": "recipes.recipe", "pk": 4, "fields": {"title": "Newt ala Doritos", "instructions": "https://xkcd.com/720/"}}, {"model": "recipes.recipe", "pk": 5, "fields": {"title": "Fruit Salad", "instructions": "Chop up and add together"}}, {"model": "recipes.recipeingredient", "pk": 1, "fields": {"recipes": 5, "ingredient": 9, "amount": 1.0, "unit": "unit"}}, {"model": "recipes.recipeingredient", "pk": 2, "fields": {"recipes": 5, "ingredient": 10, "amount": 2.0, "unit": "unit"}}, {"model": "recipes.recipeingredient", "pk": 3, "fields": {"recipes": 5, "ingredient": 7, "amount": 3.0, "unit": "unit"}}, {"model": "recipes.recipeingredient", "pk": 4, "fields": {"recipes": 5, "ingredient": 8, "amount": 4.0, "unit": "unit"}}, {"model": "recipes.recipeingredient", "pk": 5, "fields": {"recipes": 4, "ingredient": 5, "amount": 1.0, "unit": "kg"}}, {"model": "recipes.recipeingredient", "pk": 6, "fields": {"recipes": 4, "ingredient": 6, "amount": 2.0, "unit": "l"}}, {"model": "recipes.recipeingredient", "pk": 7, "fields": {"recipes": 3, "ingredient": 4, "amount": 1.0, "unit": "unit"}}, {"model": "recipes.recipeingredient", "pk": 8, "fields": {"recipes": 2, "ingredient": 2, "amount": 1.0, "unit": "kg"}}, {"model": "recipes.recipeingredient", "pk": 9, "fields": {"recipes": 2, "ingredient": 11, "amount": 2.0, "unit": "l"}}, {"model": "recipes.recipeingredient", "pk": 10, "fields": {"recipes": 2, "ingredient": 12, "amount": 3.0, "unit": "st"}}, {"model": "recipes.recipeingredient", "pk": 11, "fields": {"recipes": 1, "ingredient": 1, "amount": 1.0, "unit": "kg"}}, {"model": "recipes.recipeingredient", "pk": 12, "fields": {"recipes": 1, "ingredient": 3, "amount": 1.0, "unit": "st"}}, {"model": "ingredients.category", "pk": 1, "fields": {"name": "fruit"}}, {"model": "ingredients.category", "pk": 3, "fields": {"name": "xkcd"}}, {"model": "ingredients.ingredient", "pk": 1, "fields": {"name": "Cheerios", "notes": "this is a note", "category": 3}}, {"model": "ingredients.ingredient", "pk": 2, "fields": {"name": "Quail Eggs", "notes": "has more notes", "category": 3}}, {"model": "ingredients.ingredient", "pk": 3, "fields": {"name": "Vermouth", "notes": "", "category": 3}}, {"model": "ingredients.ingredient", "pk": 4, "fields": {"name": "Skittles", "notes": "", "category": 3}}, {"model": "ingredients.ingredient", "pk": 5, "fields": {"name": "Newt", "notes": "Braised and Confuesd", "category": 3}}, {"model": "ingredients.ingredient", "pk": 6, "fields": {"name": "Doritos", "notes": "Crushed", "category": 3}}, {"model": "ingredients.ingredient", "pk": 7, "fields": {"name": "Apple", "notes": "", "category": 1}}, {"model": "ingredients.ingredient", "pk": 8, "fields": {"name": "Orange", "notes": "", "category": 1}}, {"model": "ingredients.ingredient", "pk": 9, "fields": {"name": "Banana", "notes": "", "category": 1}}, {"model": "ingredients.ingredient", "pk": 10, "fields": {"name": "Grapes", "notes": "", "category": 1}}, {"model": "ingredients.ingredient", "pk": 11, "fields": {"name": "Whipped Cream", "notes": "", "category": 3}}, {"model": "ingredients.ingredient", "pk": 12, "fields": {"name": "MSG", "notes": "", "category": 3}}] [
{
"fields": {
"date_joined": "2016-11-03T18:24:40Z",
"email": "asdf@example.com",
"first_name": "",
"groups": [],
"is_active": true,
"is_staff": true,
"is_superuser": true,
"last_login": "2016-11-04T00:46:58Z",
"last_name": "",
"password": "pbkdf2_sha256$24000$0SgBlSlnbv5c$ijVQipm2aNDlcrTL8Qi3SVNHphTm4HIsDfUi4kn9tog=",
"user_permissions": [],
"username": "admin"
},
"model": "auth.user",
"pk": 1
},
{
"fields": {
"instructions": "https://xkcd.com/720/",
"title": "Cheerios With a Shot of Vermouth"
},
"model": "recipes.recipe",
"pk": 1
},
{
"fields": {
"instructions": "https://xkcd.com/720/",
"title": "Quail Eggs in Whipped Cream and MSG"
},
"model": "recipes.recipe",
"pk": 2
},
{
"fields": {
"instructions": "https://xkcd.com/720/",
"title": "Deep Fried Skittles"
},
"model": "recipes.recipe",
"pk": 3
},
{
"fields": {
"instructions": "https://xkcd.com/720/",
"title": "Newt ala Doritos"
},
"model": "recipes.recipe",
"pk": 4
},
{
"fields": {
"instructions": "Chop up and add together",
"title": "Fruit Salad"
},
"model": "recipes.recipe",
"pk": 5
},
{
"fields": {
"amount": 1.0,
"ingredient": 9,
"recipes": 5,
"unit": "unit"
},
"model": "recipes.recipeingredient",
"pk": 1
},
{
"fields": {
"amount": 2.0,
"ingredient": 10,
"recipes": 5,
"unit": "unit"
},
"model": "recipes.recipeingredient",
"pk": 2
},
{
"fields": {
"amount": 3.0,
"ingredient": 7,
"recipes": 5,
"unit": "unit"
},
"model": "recipes.recipeingredient",
"pk": 3
},
{
"fields": {
"amount": 4.0,
"ingredient": 8,
"recipes": 5,
"unit": "unit"
},
"model": "recipes.recipeingredient",
"pk": 4
},
{
"fields": {
"amount": 1.0,
"ingredient": 5,
"recipes": 4,
"unit": "kg"
},
"model": "recipes.recipeingredient",
"pk": 5
},
{
"fields": {
"amount": 2.0,
"ingredient": 6,
"recipes": 4,
"unit": "l"
},
"model": "recipes.recipeingredient",
"pk": 6
},
{
"fields": {
"amount": 1.0,
"ingredient": 4,
"recipes": 3,
"unit": "unit"
},
"model": "recipes.recipeingredient",
"pk": 7
},
{
"fields": {
"amount": 1.0,
"ingredient": 2,
"recipes": 2,
"unit": "kg"
},
"model": "recipes.recipeingredient",
"pk": 8
},
{
"fields": {
"amount": 2.0,
"ingredient": 11,
"recipes": 2,
"unit": "l"
},
"model": "recipes.recipeingredient",
"pk": 9
},
{
"fields": {
"amount": 3.0,
"ingredient": 12,
"recipes": 2,
"unit": "st"
},
"model": "recipes.recipeingredient",
"pk": 10
},
{
"fields": {
"amount": 1.0,
"ingredient": 1,
"recipes": 1,
"unit": "kg"
},
"model": "recipes.recipeingredient",
"pk": 11
},
{
"fields": {
"amount": 1.0,
"ingredient": 3,
"recipes": 1,
"unit": "st"
},
"model": "recipes.recipeingredient",
"pk": 12
},
{
"fields": {
"name": "fruit"
},
"model": "ingredients.category",
"pk": 1
},
{
"fields": {
"name": "xkcd"
},
"model": "ingredients.category",
"pk": 3
},
{
"fields": {
"category": 3,
"name": "Cheerios",
"notes": "this is a note"
},
"model": "ingredients.ingredient",
"pk": 1
},
{
"fields": {
"category": 3,
"name": "Quail Eggs",
"notes": "has more notes"
},
"model": "ingredients.ingredient",
"pk": 2
},
{
"fields": {
"category": 3,
"name": "Vermouth",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 3
},
{
"fields": {
"category": 3,
"name": "Skittles",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 4
},
{
"fields": {
"category": 3,
"name": "Newt",
"notes": "Braised and Confuesd"
},
"model": "ingredients.ingredient",
"pk": 5
},
{
"fields": {
"category": 3,
"name": "Doritos",
"notes": "Crushed"
},
"model": "ingredients.ingredient",
"pk": 6
},
{
"fields": {
"category": 1,
"name": "Apple",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 7
},
{
"fields": {
"category": 1,
"name": "Orange",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 8
},
{
"fields": {
"category": 1,
"name": "Banana",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 9
},
{
"fields": {
"category": 1,
"name": "Grapes",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 10
},
{
"fields": {
"category": 3,
"name": "Whipped Cream",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 11
},
{
"fields": {
"category": 3,
"name": "MSG",
"notes": ""
},
"model": "ingredients.ingredient",
"pk": 12
}
]

View File

@ -1,5 +1,3 @@
from __future__ import absolute_import
from django.db import models from django.db import models

View File

@ -1,4 +1,4 @@
class MissingType(object): class MissingType:
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
pass pass

View File

@ -74,8 +74,7 @@ def get_choices(choices):
choices = choices.items() choices = choices.items()
for value, help_text in choices: for value, help_text in choices:
if isinstance(help_text, (tuple, list)): if isinstance(help_text, (tuple, list)):
for choice in get_choices(help_text): yield from get_choices(help_text)
yield choice
else: else:
name = convert_choice_name(value) name = convert_choice_name(value)
while name in converted_names: while name in converted_names:
@ -92,7 +91,7 @@ def convert_choices_to_named_enum_with_descriptions(name, choices):
named_choices = [(c[0], c[1]) for c in choices] named_choices = [(c[0], c[1]) for c in choices]
named_choices_descriptions = {c[0]: c[2] for c in choices} named_choices_descriptions = {c[0]: c[2] for c in choices}
class EnumWithDescriptionsType(object): class EnumWithDescriptionsType:
@property @property
def description(self): def description(self):
return str(named_choices_descriptions[self.name]) return str(named_choices_descriptions[self.name])
@ -109,7 +108,7 @@ def generate_enum_name(django_model_meta, field):
) )
name = custom_func(field) name = custom_func(field)
elif graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V2_NAMING is True: elif graphene_settings.DJANGO_CHOICE_FIELD_ENUM_V2_NAMING is True:
name = to_camel_case("{}_{}".format(django_model_meta.object_name, field.name)) name = to_camel_case(f"{django_model_meta.object_name}_{field.name}")
else: else:
name = "{app_label}{object_name}{field_name}Choices".format( name = "{app_label}{object_name}{field_name}Choices".format(
app_label=to_camel_case(django_model_meta.app_label.title()), app_label=to_camel_case(django_model_meta.app_label.title()),
@ -155,7 +154,9 @@ def get_django_field_description(field):
@singledispatch @singledispatch
def convert_django_field(field, registry=None): def convert_django_field(field, registry=None):
raise Exception( raise Exception(
"Don't know how to convert the Django field %s (%s)" % (field, field.__class__) "Don't know how to convert the Django field {} ({})".format(
field, field.__class__
)
) )

View File

@ -7,7 +7,7 @@ from .exception.formating import wrap_exception
from .types import DjangoDebug from .types import DjangoDebug
class DjangoDebugContext(object): class DjangoDebugContext:
def __init__(self): def __init__(self):
self.debug_promise = None self.debug_promise = None
self.promises = [] self.promises = []
@ -46,7 +46,7 @@ class DjangoDebugContext(object):
unwrap_cursor(connection) unwrap_cursor(connection)
class DjangoDebugMiddleware(object): class DjangoDebugMiddleware:
def resolve(self, next, root, info, **args): def resolve(self, next, root, info, **args):
context = info.context context = info.context
django_debug = getattr(context, "django_debug", None) django_debug = getattr(context, "django_debug", None)

View File

@ -1,5 +1,4 @@
# Code obtained from django-debug-toolbar sql panel tracking # Code obtained from django-debug-toolbar sql panel tracking
from __future__ import absolute_import, unicode_literals
import json import json
from threading import local from threading import local
@ -50,7 +49,7 @@ def unwrap_cursor(connection):
del connection._graphene_cursor del connection._graphene_cursor
class ExceptionCursorWrapper(object): class ExceptionCursorWrapper:
""" """
Wraps a cursor and raises an exception on any operation. Wraps a cursor and raises an exception on any operation.
Used in Templates panel. Used in Templates panel.
@ -63,7 +62,7 @@ class ExceptionCursorWrapper(object):
raise SQLQueryTriggered() raise SQLQueryTriggered()
class NormalCursorWrapper(object): class NormalCursorWrapper:
""" """
Wraps a cursor and logs queries. Wraps a cursor and logs queries.
""" """
@ -85,7 +84,7 @@ class NormalCursorWrapper(object):
if not params: if not params:
return params return params
if isinstance(params, dict): if isinstance(params, dict):
return dict((key, self._quote_expr(value)) for key, value in params.items()) return {key: self._quote_expr(value) for key, value in params.items()}
return list(map(self._quote_expr, params)) return list(map(self._quote_expr, params))
def _decode(self, param): def _decode(self, param):

View File

@ -8,7 +8,7 @@ from ..middleware import DjangoDebugMiddleware
from ..types import DjangoDebug from ..types import DjangoDebug
class context(object): class context:
pass pass

View File

@ -28,7 +28,7 @@ class DjangoListField(Field):
_type = _type.of_type _type = _type.of_type
# Django would never return a Set of None vvvvvvv # Django would never return a Set of None vvvvvvv
super(DjangoListField, self).__init__(List(NonNull(_type)), *args, **kwargs) super().__init__(List(NonNull(_type)), *args, **kwargs)
assert issubclass( assert issubclass(
self._underlying_type, DjangoObjectType self._underlying_type, DjangoObjectType
@ -63,7 +63,7 @@ class DjangoListField(Field):
return queryset return queryset
def wrap_resolve(self, parent_resolver): def wrap_resolve(self, parent_resolver):
resolver = super(DjangoListField, self).wrap_resolve(parent_resolver) resolver = super().wrap_resolve(parent_resolver)
_type = self.type _type = self.type
if isinstance(_type, NonNull): if isinstance(_type, NonNull):
_type = _type.of_type _type = _type.of_type
@ -87,7 +87,7 @@ class DjangoConnectionField(ConnectionField):
graphene_settings.RELAY_CONNECTION_ENFORCE_FIRST_OR_LAST, graphene_settings.RELAY_CONNECTION_ENFORCE_FIRST_OR_LAST,
) )
kwargs.setdefault("offset", Int()) kwargs.setdefault("offset", Int())
super(DjangoConnectionField, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@property @property
def type(self): def type(self):

View File

@ -44,7 +44,7 @@ class DjangoFilterConnectionField(DjangoConnectionField):
self._filtering_args = None self._filtering_args = None
self._extra_filter_meta = extra_filter_meta self._extra_filter_meta = extra_filter_meta
self._base_args = None self._base_args = None
super(DjangoFilterConnectionField, self).__init__(type_, *args, **kwargs) super().__init__(type_, *args, **kwargs)
@property @property
def args(self): def args(self):
@ -90,9 +90,7 @@ class DjangoFilterConnectionField(DjangoConnectionField):
kwargs[k] = convert_enum(v) kwargs[k] = convert_enum(v)
return kwargs return kwargs
qs = super(DjangoFilterConnectionField, cls).resolve_queryset( qs = super().resolve_queryset(connection, iterable, info, args)
connection, iterable, info, args
)
filterset = filterset_class( filterset = filterset_class(
data=filter_kwargs(), queryset=qs, request=info.context data=filter_kwargs(), queryset=qs, request=info.context

View File

@ -22,6 +22,6 @@ class ArrayFilter(TypedFilter):
return qs return qs
if self.distinct: if self.distinct:
qs = qs.distinct() qs = qs.distinct()
lookup = "%s__%s" % (self.field_name, self.lookup_expr) lookup = f"{self.field_name}__{self.lookup_expr}"
qs = self.get_method(qs)(**{lookup: value}) qs = self.get_method(qs)(**{lookup: value})
return qs return qs

View File

@ -17,7 +17,7 @@ class GlobalIDFilter(Filter):
_id = None _id = None
if value is not None: if value is not None:
_, _id = from_global_id(value) _, _id = from_global_id(value)
return super(GlobalIDFilter, self).filter(qs, _id) return super().filter(qs, _id)
class GlobalIDMultipleChoiceFilter(MultipleChoiceFilter): class GlobalIDMultipleChoiceFilter(MultipleChoiceFilter):
@ -25,4 +25,4 @@ class GlobalIDMultipleChoiceFilter(MultipleChoiceFilter):
def filter(self, qs, value): def filter(self, qs, value):
gids = [from_global_id(v)[1] for v in value] gids = [from_global_id(v)[1] for v in value]
return super(GlobalIDMultipleChoiceFilter, self).filter(qs, gids) return super().filter(qs, gids)

View File

@ -23,4 +23,4 @@ class ListFilter(TypedFilter):
else: else:
return qs.none() return qs.none()
else: else:
return super(ListFilter, self).filter(qs, value) return super().filter(qs, value)

View File

@ -12,7 +12,7 @@ class TypedFilter(Filter):
def __init__(self, input_type=None, *args, **kwargs): def __init__(self, input_type=None, *args, **kwargs):
self._input_type = input_type self._input_type = input_type
super(TypedFilter, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@property @property
def input_type(self): def input_type(self):

View File

@ -31,7 +31,7 @@ class GrapheneFilterSetMixin(BaseFilterSet):
def setup_filterset(filterset_class): def setup_filterset(filterset_class):
"""Wrap a provided filterset in Graphene-specific functionality""" """Wrap a provided filterset in Graphene-specific functionality"""
return type( return type(
"Graphene{}".format(filterset_class.__name__), f"Graphene{filterset_class.__name__}",
(filterset_class, GrapheneFilterSetMixin), (filterset_class, GrapheneFilterSetMixin),
{}, {},
) )
@ -40,7 +40,7 @@ def setup_filterset(filterset_class):
def custom_filterset_factory(model, filterset_base_class=FilterSet, **meta): def custom_filterset_factory(model, filterset_base_class=FilterSet, **meta):
"""Create a filterset for the given model using the provided meta data""" """Create a filterset for the given model using the provided meta data"""
meta.update({"model": model}) meta.update({"model": model})
meta_class = type(str("Meta"), (object,), meta) meta_class = type("Meta", (object,), meta)
filterset = type( filterset = type(
str("%sFilterSet" % model._meta.object_name), str("%sFilterSet" % model._meta.object_name),
(filterset_base_class, GrapheneFilterSetMixin), (filterset_base_class, GrapheneFilterSetMixin),

View File

@ -1,4 +1,4 @@
from mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
from django.db import models from django.db import models

View File

@ -67,7 +67,7 @@ def assert_arguments(field, *arguments):
actual = [name for name in args if name not in ignore and not name.startswith("_")] actual = [name for name in args if name not in ignore and not name.startswith("_")]
assert set(arguments) == set( assert set(arguments) == set(
actual actual
), "Expected arguments ({}) did not match actual ({})".format(arguments, actual) ), f"Expected arguments ({arguments}) did not match actual ({actual})"
def assert_orderable(field): def assert_orderable(field):
@ -141,7 +141,7 @@ def test_filter_shortcut_filterset_context():
@property @property
def qs(self): def qs(self):
qs = super(ArticleContextFilter, self).qs qs = super().qs
return qs.filter(reporter=self.request.reporter) return qs.filter(reporter=self.request.reporter)
class Query(ObjectType): class Query(ObjectType):
@ -166,7 +166,7 @@ def test_filter_shortcut_filterset_context():
editor=r2, editor=r2,
) )
class context(object): class context:
reporter = r2 reporter = r2
query = """ query = """

View File

@ -349,19 +349,19 @@ def test_fk_id_in_filter(query):
schema = Schema(query=query) schema = Schema(query=query)
query = """ query = """
query { query {{
articles (reporter_In: [%s, %s]) { articles (reporter_In: [{}, {}]) {{
edges { edges {{
node { node {{
headline headline
reporter { reporter {{
lastName lastName
} }}
} }}
} }}
} }}
} }}
""" % ( """.format(
john_doe.id, john_doe.id,
jean_bon.id, jean_bon.id,
) )

View File

@ -98,7 +98,7 @@ def test_typed_filter_schema(schema):
) )
for filter_field, gql_type in filters.items(): for filter_field, gql_type in filters.items():
assert "{}: {}".format(filter_field, gql_type) in all_articles_filters assert f"{filter_field}: {gql_type}" in all_articles_filters
def test_typed_filters_work(schema): def test_typed_filters_work(schema):

View File

@ -95,7 +95,7 @@ class DjangoFormMutation(BaseDjangoFormMutation):
_meta.fields = yank_fields_from_attrs(output_fields, _as=Field) _meta.fields = yank_fields_from_attrs(output_fields, _as=Field)
input_fields = yank_fields_from_attrs(input_fields, _as=InputField) input_fields = yank_fields_from_attrs(input_fields, _as=InputField)
super(DjangoFormMutation, cls).__init_subclass_with_meta__( super().__init_subclass_with_meta__(
_meta=_meta, input_fields=input_fields, **options _meta=_meta, input_fields=input_fields, **options
) )
@ -127,7 +127,7 @@ class DjangoModelFormMutation(BaseDjangoFormMutation):
return_field_name=None, return_field_name=None,
only_fields=(), only_fields=(),
exclude_fields=(), exclude_fields=(),
**options **options,
): ):
if not form_class: if not form_class:
@ -147,7 +147,7 @@ class DjangoModelFormMutation(BaseDjangoFormMutation):
registry = get_global_registry() registry = get_global_registry()
model_type = registry.get_type_for_model(model) model_type = registry.get_type_for_model(model)
if not model_type: if not model_type:
raise Exception("No type registered for model: {}".format(model.__name__)) raise Exception(f"No type registered for model: {model.__name__}")
if not return_field_name: if not return_field_name:
model_name = model.__name__ model_name = model.__name__
@ -163,7 +163,7 @@ class DjangoModelFormMutation(BaseDjangoFormMutation):
_meta.fields = yank_fields_from_attrs(output_fields, _as=Field) _meta.fields = yank_fields_from_attrs(output_fields, _as=Field)
input_fields = yank_fields_from_attrs(input_fields, _as=InputField) input_fields = yank_fields_from_attrs(input_fields, _as=InputField)
super(DjangoModelFormMutation, cls).__init_subclass_with_meta__( super().__init_subclass_with_meta__(
_meta=_meta, input_fields=input_fields, **options _meta=_meta, input_fields=input_fields, **options
) )

View File

@ -73,16 +73,12 @@ class Command(CommandArguments):
elif file_extension == ".json": elif file_extension == ".json":
self.save_json_file(out, schema_dict, indent) self.save_json_file(out, schema_dict, indent)
else: else:
raise CommandError( raise CommandError(f'Unrecognised file format "{file_extension}"')
'Unrecognised file format "{}"'.format(file_extension)
)
style = getattr(self, "style", None) style = getattr(self, "style", None)
success = getattr(style, "SUCCESS", lambda x: x) success = getattr(style, "SUCCESS", lambda x: x)
self.stdout.write( self.stdout.write(success(f"Successfully dumped GraphQL schema to {out}"))
success("Successfully dumped GraphQL schema to {}".format(out))
)
def handle(self, *args, **options): def handle(self, *args, **options):
options_schema = options.get("schema") options_schema = options.get("schema")

View File

@ -1,4 +1,4 @@
class Registry(object): class Registry:
def __init__(self): def __init__(self):
self._registry = {} self._registry = {}
self._field_registry = {} self._field_registry = {}

View File

@ -114,7 +114,7 @@ class SerializerMutation(ClientIDMutation):
_meta.fields = yank_fields_from_attrs(output_fields, _as=Field) _meta.fields = yank_fields_from_attrs(output_fields, _as=Field)
input_fields = yank_fields_from_attrs(input_fields, _as=InputField) input_fields = yank_fields_from_attrs(input_fields, _as=InputField)
super(SerializerMutation, cls).__init_subclass_with_meta__( super().__init_subclass_with_meta__(
_meta=_meta, input_fields=input_fields, **options _meta=_meta, input_fields=input_fields, **options
) )

View File

@ -72,7 +72,7 @@ def convert_serializer_to_input_type(serializer_class):
for name, field in serializer.fields.items() for name, field in serializer.fields.items()
} }
ret_type = type( ret_type = type(
"{}Input".format(serializer.__class__.__name__), f"{serializer.__class__.__name__}Input",
(graphene.InputObjectType,), (graphene.InputObjectType,),
items, items,
) )

View File

@ -11,7 +11,6 @@ This module provides the `graphene_settings` object, that is used to access
Graphene settings, checking for user settings first, then falling Graphene settings, checking for user settings first, then falling
back to the defaults. back to the defaults.
""" """
from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
from django.test.signals import setting_changed from django.test.signals import setting_changed
@ -78,7 +77,7 @@ def import_from_string(val, setting_name):
module = importlib.import_module(module_path) module = importlib.import_module(module_path)
return getattr(module, class_name) return getattr(module, class_name)
except (ImportError, AttributeError) as e: except (ImportError, AttributeError) as e:
msg = "Could not import '%s' for Graphene setting '%s'. %s: %s." % ( msg = "Could not import '{}' for Graphene setting '{}'. {}: {}.".format(
val, val,
setting_name, setting_name,
e.__class__.__name__, e.__class__.__name__,
@ -87,7 +86,7 @@ def import_from_string(val, setting_name):
raise ImportError(msg) raise ImportError(msg)
class GrapheneSettings(object): class GrapheneSettings:
""" """
A settings object, that allows API settings to be accessed as properties. A settings object, that allows API settings to be accessed as properties.
For example: For example:

View File

@ -1,5 +1,3 @@
from __future__ import absolute_import
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -37,7 +35,7 @@ class Film(models.Model):
class DoeReporterManager(models.Manager): class DoeReporterManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super(DoeReporterManager, self).get_queryset().filter(last_name="Doe") return super().get_queryset().filter(last_name="Doe")
class Reporter(models.Model): class Reporter(models.Model):
@ -57,7 +55,7 @@ class Reporter(models.Model):
) )
def __str__(self): # __unicode__ on Python 2 def __str__(self): # __unicode__ on Python 2
return "%s %s" % (self.first_name, self.last_name) return f"{self.first_name} {self.last_name}"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """
@ -67,7 +65,7 @@ class Reporter(models.Model):
when a CNNReporter is pulled from the database, it is still when a CNNReporter is pulled from the database, it is still
of type Reporter. This was added to test proxy model support. of type Reporter. This was added to test proxy model support.
""" """
super(Reporter, self).__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if self.reporter_type == 2: # quick and dirty way without enums if self.reporter_type == 2: # quick and dirty way without enums
self.__class__ = CNNReporter self.__class__ = CNNReporter
@ -77,7 +75,7 @@ class Reporter(models.Model):
class CNNReporterManager(models.Manager): class CNNReporterManager(models.Manager):
def get_queryset(self): def get_queryset(self):
return super(CNNReporterManager, self).get_queryset().filter(reporter_type=2) return super().get_queryset().filter(reporter_type=2)
class CNNReporter(Reporter): class CNNReporter(Reporter):

View File

@ -2,7 +2,7 @@ from textwrap import dedent
from django.core import management from django.core import management
from io import StringIO from io import StringIO
from mock import mock_open, patch from unittest.mock import mock_open, patch
from graphene import ObjectType, Schema, String from graphene import ObjectType, Schema, String

View File

@ -1151,9 +1151,9 @@ def test_connection_should_limit_after_to_list_length():
REPORTERS = [ REPORTERS = [
dict( dict(
first_name="First {}".format(i), first_name=f"First {i}",
last_name="Last {}".format(i), last_name=f"Last {i}",
email="johndoe+{}@example.com".format(i), email=f"johndoe+{i}@example.com",
a_choice=1, a_choice=1,
) )
for i in range(6) for i in range(6)

View File

@ -3,7 +3,7 @@ from textwrap import dedent
import pytest import pytest
from django.db import models from django.db import models
from mock import patch from unittest.mock import patch
from graphene import Connection, Field, Interface, ObjectType, Schema, String from graphene import Connection, Field, Interface, ObjectType, Schema, String
from graphene.relay import Node from graphene.relay import Node
@ -104,7 +104,7 @@ def test_django_objecttype_with_custom_meta():
@classmethod @classmethod
def __init_subclass_with_meta__(cls, **options): def __init_subclass_with_meta__(cls, **options):
options.setdefault("_meta", ArticleTypeOptions(cls)) options.setdefault("_meta", ArticleTypeOptions(cls))
super(ArticleType, cls).__init_subclass_with_meta__(**options) super().__init_subclass_with_meta__(**options)
class Article(ArticleType): class Article(ArticleType):
class Meta: class Meta:
@ -484,7 +484,7 @@ def test_django_objecttype_neither_fields_nor_exclude():
def custom_enum_name(field): def custom_enum_name(field):
return "CustomEnum{}".format(field.name.title()) return f"CustomEnum{field.name.title()}"
class TestDjangoObjectType: class TestDjangoObjectType:

View File

@ -2,7 +2,7 @@ import json
import pytest import pytest
from django.utils.translation import gettext_lazy from django.utils.translation import gettext_lazy
from mock import patch from unittest.mock import patch
from ..utils import camelize, get_model_fields, GraphQLTestCase from ..utils import camelize, get_model_fields, GraphQLTestCase
from .models import Film, Reporter from .models import Film, Reporter
@ -11,11 +11,11 @@ from ..utils.testing import graphql_query
def test_get_model_fields_no_duplication(): def test_get_model_fields_no_duplication():
reporter_fields = get_model_fields(Reporter) reporter_fields = get_model_fields(Reporter)
reporter_name_set = set([field[0] for field in reporter_fields]) reporter_name_set = {field[0] for field in reporter_fields}
assert len(reporter_fields) == len(reporter_name_set) assert len(reporter_fields) == len(reporter_name_set)
film_fields = get_model_fields(Film) film_fields = get_model_fields(Film)
film_name_set = set([field[0] for field in film_fields]) film_name_set = {field[0] for field in film_fields}
assert len(film_fields) == len(film_name_set) assert len(film_fields) == len(film_name_set)
@ -54,7 +54,7 @@ def test_graphql_test_case_operation_name(post_mock):
tc._pre_setup() tc._pre_setup()
tc.setUpClass() tc.setUpClass()
tc.query("query { }", operation_name="QueryName") tc.query("query { }", operation_name="QueryName")
body = json.loads(post_mock.call_args.args[1]) body = json.loads(post_mock.call_args[0][1])
# `operationName` field from https://graphql.org/learn/serving-over-http/#post-request # `operationName` field from https://graphql.org/learn/serving-over-http/#post-request
assert ( assert (
"operationName", "operationName",
@ -66,7 +66,7 @@ def test_graphql_test_case_operation_name(post_mock):
@patch("graphene_django.utils.testing.Client.post") @patch("graphene_django.utils.testing.Client.post")
def test_graphql_query_case_operation_name(post_mock): def test_graphql_query_case_operation_name(post_mock):
graphql_query("query { }", operation_name="QueryName") graphql_query("query { }", operation_name="QueryName")
body = json.loads(post_mock.call_args.args[1]) body = json.loads(post_mock.call_args[0][1])
# `operationName` field from https://graphql.org/learn/serving-over-http/#post-request # `operationName` field from https://graphql.org/learn/serving-over-http/#post-request
assert ( assert (
"operationName", "operationName",

View File

@ -2,7 +2,7 @@ import json
import pytest import pytest
from mock import patch from unittest.mock import patch
from django.db import connection from django.db import connection
@ -507,7 +507,7 @@ def test_handles_invalid_json_bodies(client):
def test_handles_django_request_error(client, monkeypatch): def test_handles_django_request_error(client, monkeypatch):
def mocked_read(*args): def mocked_read(*args):
raise IOError("foo-bar") raise OSError("foo-bar")
monkeypatch.setattr("django.http.request.HttpRequest.read", mocked_read) monkeypatch.setattr("django.http.request.HttpRequest.read", mocked_read)

View File

@ -168,10 +168,8 @@ class DjangoObjectType(ObjectType):
if not DJANGO_FILTER_INSTALLED and (filter_fields or filterset_class): if not DJANGO_FILTER_INSTALLED and (filter_fields or filterset_class):
raise Exception( raise Exception(
( "Can only set filter_fields or filterset_class if "
"Can only set filter_fields or filterset_class if " "Django-Filter is installed"
"Django-Filter is installed"
)
) )
assert not (fields and exclude), ( assert not (fields and exclude), (
@ -228,7 +226,7 @@ class DjangoObjectType(ObjectType):
if use_connection is None and interfaces: if use_connection is None and interfaces:
use_connection = any( use_connection = any(
(issubclass(interface, Node) for interface in interfaces) issubclass(interface, Node) for interface in interfaces
) )
if use_connection and not connection: if use_connection and not connection:
@ -255,7 +253,7 @@ class DjangoObjectType(ObjectType):
_meta.fields = django_fields _meta.fields = django_fields
_meta.connection = connection _meta.connection = connection
super(DjangoObjectType, cls).__init_subclass_with_meta__( super().__init_subclass_with_meta__(
_meta=_meta, interfaces=interfaces, **options _meta=_meta, interfaces=interfaces, **options
) )

View File

@ -65,7 +65,7 @@ def graphql_query(
return resp return resp
class GraphQLTestMixin(object): class GraphQLTestMixin:
""" """
Based on: https://www.sam.today/blog/testing-graphql-with-graphene-django/ Based on: https://www.sam.today/blog/testing-graphql-with-graphene-django/
""" """

View File

@ -26,7 +26,7 @@ class HttpError(Exception):
def __init__(self, response, message=None, *args, **kwargs): def __init__(self, response, message=None, *args, **kwargs):
self.response = response self.response = response
self.message = message = message or response.content.decode() self.message = message = message or response.content.decode()
super(HttpError, self).__init__(message, *args, **kwargs) super().__init__(message, *args, **kwargs)
def get_accepted_content_types(request): def get_accepted_content_types(request):

View File

@ -5,7 +5,7 @@ test=pytest
universal=1 universal=1
[flake8] [flake8]
exclude = docs,graphene_django/debug/sql/*,migrations exclude = docs,graphene_django/debug/sql/*
max-line-length = 120 max-line-length = 120
select = select =
# Dictionary key repeated # Dictionary key repeated

16
tox.ini
View File

@ -2,7 +2,7 @@
envlist = envlist =
py{37,38,39,310}-django32, py{37,38,39,310}-django32,
py{38,39,310}-django{40,41,main}, py{38,39,310}-django{40,41,main},
black,flake8 pre-commit
[gh-actions] [gh-actions]
python = python =
@ -32,14 +32,8 @@ deps =
djangomain: https://github.com/django/django/archive/main.zip djangomain: https://github.com/django/django/archive/main.zip
commands = {posargs:py.test --cov=graphene_django graphene_django examples} commands = {posargs:py.test --cov=graphene_django graphene_django examples}
[testenv:black] [testenv:pre-commit]
basepython = python3.9 skip_install = true
deps = -e.[dev] deps = pre-commit
commands =
black --exclude "/migrations/" graphene_django examples setup.py --check
[testenv:flake8]
basepython = python3.9
deps = -e.[dev]
commands = commands =
flake8 graphene_django examples setup.py pre-commit run --all-files --show-diff-on-failure