Skip to content

expose livehtml autobuild in Makefile + Add API autodoc #971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ __pycache__/
# Distribution / packaging
.Python
env/
venv/
.venv/
build/
develop-eggs/
dist/
Expand Down
18 changes: 13 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@ help:
@echo "Please use \`make <target>' where <target> is one of"
@grep -E '^\.PHONY: [a-zA-Z_-]+ .*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = "(: |##)"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'

.PHONY: install-dev ## Install development dependencies
install-dev:
pip install -e ".[test]"

test:
py.test graphene

.PHONY: docs ## Generate docs
docs:
@cd docs &&\
pip install -r requirements.txt &&\
make html &&\
cd -
docs: install-dev
cd docs && make install && make html

.PHONY: docs-live ## Generate docs with live reloading
docs-live: install-dev
cd docs && make install && make livehtml
10 changes: 7 additions & 3 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ help:
@echo "Please use \`make <target>' where <target> is one of"
@grep -E '^\.PHONY: [a-zA-Z_-]+ .*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = "(: |##)"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'

.PHONY: clean
.PHONY: install ## to install all documentation related requirements
install:
pip install -r requirements.txt

.PHONY: clean ## to remove all built documentation
clean:
rm -rf $(BUILDDIR)/*

Expand Down Expand Up @@ -199,6 +203,6 @@ dummy:
@echo
@echo "Build finished. Dummy builder generates no files."

.PHONY: livehtml
.PHONY: livehtml ## to build and serve live-reloading documentation
livehtml:
sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
sphinx-autobuild -b html --watch ../graphene $(ALLSPHINXOPTS) $(BUILDDIR)/html
Empty file added docs/_static/.gitkeep
Empty file.
106 changes: 106 additions & 0 deletions docs/api/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
API Reference
=============

Schema
------

.. autoclass:: graphene.types.schema.Schema
:members:

.. Uncomment sections / types as API documentation is fleshed out
.. in each class

Object types
------------

.. autoclass:: graphene.ObjectType

.. autoclass:: graphene.InputObjectType

.. autoclass:: graphene.Mutation
:members:

Fields (Mounted Types)
----------------------

.. autoclass:: graphene.Field

.. autoclass:: graphene.Argument

.. autoclass:: graphene.InputField

Fields (Unmounted Types)
------------------------

.. autoclass:: graphene.types.unmountedtype.UnmountedType

GraphQL Scalars
---------------

.. autoclass:: graphene.Int()

.. autoclass:: graphene.Float()

.. autoclass:: graphene.String()

.. autoclass:: graphene.Boolean()

.. autoclass:: graphene.ID()

Graphene Scalars
----------------

.. autoclass:: graphene.Date()

.. autoclass:: graphene.DateTime()

.. autoclass:: graphene.Time()

.. autoclass:: graphene.Decimal()

.. autoclass:: graphene.UUID()

.. autoclass:: graphene.JSONString()

Enum
----

.. autoclass:: graphene.Enum()

Structures
----------

.. autoclass:: graphene.List

.. autoclass:: graphene.NonNull

Type Extension
--------------

.. autoclass:: graphene.Interface()

.. autoclass:: graphene.Union()

Execution Metadata
------------------

.. autoclass:: graphene.ResolveInfo

.. autoclass:: graphene.Context

.. autoclass:: graphql.execution.base.ExecutionResult

.. Relay
.. -----

.. .. autoclass:: graphene.Node

.. .. autoclass:: graphene.GlobalID

.. .. autoclass:: graphene.ClientIDMutation

.. .. autoclass:: graphene.Connection

.. .. autoclass:: graphene.ConnectionField

.. .. autoclass:: graphene.PageInfo
8 changes: 5 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import os
import sys

sys.path.insert(0, os.path.abspath(".."))

# -- General configuration ------------------------------------------------

Expand All @@ -41,6 +42,7 @@
"sphinx.ext.todo",
"sphinx.ext.coverage",
"sphinx.ext.viewcode",
"sphinx.ext.napoleon",
]
if not on_rtd:
extensions += ["sphinx.ext.githubpages"]
Expand Down
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ Contents:
execution/index
relay/index
testing/index
api/index

Integrations
-----
------------

* `Graphene-Django <http://docs.graphene-python.org/projects/django/en/latest/>`_ (`source <https://github.com/graphql-python/graphene-django/>`_)
* `Graphene-SQLAlchemy <http://docs.graphene-python.org/projects/sqlalchemy/en/latest/>`_ (`source <https://github.com/graphql-python/graphene-sqlalchemy/>`_)
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Required library
Sphinx==1.5.3
sphinx-autobuild
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please pin this to a specific version

# Docs template
http://graphene-python.org/sphinx_graphene_theme.zip
29 changes: 29 additions & 0 deletions graphene/types/argument.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,35 @@


class Argument(MountedType):
"""
Makes an Argument available on a Field in the GraphQL schema.

Arguments will be parsed and provided to resolver methods for fields as keyword arguments.

All ``arg`` and ``**extra_args`` for a ``graphene.Field`` are implicitly mounted as Argument
using the below parameters.

.. code:: python

age = graphene.String(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to run black on code snippets in docstrings here.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    age = graphene.String(
        # Boolean implicitly mounted as Argument
        dog_years=graphene.Boolean(description="convert to dog years"),
        # Boolean explicitly mounted as Argument
        decades=graphene.Argument(graphene.Boolean, default_value=False),
    )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I omit graphene.<Whatever> like you did in your PR?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd vote yes on this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes from me too

# Boolean implicitly mounted as Argument
dog_years=graphene.Boolean(description='convert to dog years'),
# Boolean explicitly mounted as Argument
decades=graphene.Argument(graphene.Boolean, default_value=False)
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
)
age = String(
# Boolean implicitly mounted as Argument
dog_years=Boolean(description="convert to dog years"),
# Boolean explicitly mounted as Argument
decades=Argument(Boolean, default_value=False),
)


args:
type (class for a graphene.UnmountedType): must be a class (not an instance) of an
unmounted graphene type (ex. scalar or object) which is used for the type of this
argument in the GraphQL schema.
required (bool): indicates this argument as not null in the graphql scehma. Same behavior
as graphene.NonNull. Default False.
name (str): the name of the GraphQL argument. Defaults to parameter name.
description (str): the description of the GraphQL argument in the schema.
default_value (Any): The value to be provided if the user does not set this argument in
the operation.
"""

def __init__(
self,
type,
Expand Down
19 changes: 19 additions & 0 deletions graphene/types/context.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
class Context(object):
"""
Context can be used to make a convenient container for attributes to provide
for execution for resolvers of a GraphQL operation like a query.

.. code:: python

context = Context(loaders=build_dataloaders(), request=my_web_request)
schema.execute('{ hello(name: "world") }', context=context)

def resolve_hello(parent, info, name):
info.context.request # value set in Context
info.context.loaders # value set in Context
# ...

args:
**params (Dict[str, Any]): values to make available on Context instance as attributes.

"""

def __init__(self, **params):
for key, value in params.items():
setattr(self, key, value)
22 changes: 22 additions & 0 deletions graphene/types/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ def from_enum(cls, enum, description=None, deprecation_reason=None): # noqa: N8


class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)):
"""
Enum type defintion

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Enum type defintion
Enum type definition


Defines a static set of values that can be provided as a Field, Argument or InputField.

.. code:: python

class NameFormat(graphene.Enum):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class NameFormat(graphene.Enum):
class NameFormat(Enum):

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to keep graphene to show exactly which Enum we mean.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be worth a larger conversation. Naming collisions with python modules like enum.Enum, for example. Perhaps a naming protocol going forward?

As @ProjectCheshire pointed out in https://graphenetools.slack.com/archives/CGR4VCHUL/p1559524808014100, core-next has these types available as, for example:

from graphql import (
    GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString)

See https://graphql-core-next.readthedocs.io/en/latest/intro.html#getting-started

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll keep the import close in all examples to avoid confusion.

Agree with @phalt that the clash for name Enum is a little confusing. I do prefer the shorter names in code as these objects are used very often in the schema. GraphQL as a prefix seems like overkill in most cases (especially given the namespace graphql and graphene for the module).

FIRST_LAST = 'first_last'
LAST_FIRST = 'last_first'

Meta:
enum (optional, Enum): Python enum to use as a base for GraphQL Enum.

name (optional, str): the name of the GraphQL type (must be unique in schema). Defaults to class
name.
description (optional, str): the description of the GraphQL type in the schema. Defaults to class
docstring.
deprecation_reason (optional, str): Setting this value indicates that the enum is
depreciated and may provide instruction or reason on how for clients to proceed.
"""

@classmethod
def __init_subclass_with_meta__(cls, enum=None, _meta=None, **options):
if not _meta:
Expand Down
41 changes: 41 additions & 0 deletions graphene/types/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,47 @@ def source_resolver(source, root, info, **args):


class Field(MountedType):
"""
Makes a field available on an ObjectType in the GraphQL schema. Any type can be mounted as a
Field:

- Object Type
- Scalar Type
- Enum
- Interface
- Union

All class attributes of ``graphene.ObjectType`` are implicitly mounted as Field using the below
arguments.

.. code:: python

class Person(ObjectType):
first_name = graphene.String(required=True) # implicitly mounted as Field
last_name = graphene.Field(String, description='Surname') # explicitly mounted as Field

args:
type (class for a graphene.UnmountedType): must be a class (not an instance) of an
unmounted graphene type (ex. scalar or object) which is used for the type of this
field in the GraphQL schema.
args (optional, Dict[str, graphene.Argument]): arguments that can be input to the field.
Prefer to use **extra_args.
resolver (optional, Callable): A function to get the value for a Field from the parent
value object. If not set, the default resolver method for the schema is used.
source (optional, str): attribute name to resolve for this field from the parent value
object. Alternative to resolver (cannot set both source and resolver).
deprecation_reason (optional, str): Setting this value indicates that the field is
depreciated and may provide instruction or reason on how for clients to proceed.
required (optional, bool): indicates this field as not null in the graphql scehma. Same behavior as
graphene.NonNull. Default False.
name (optional, str): the name of the GraphQL field (must be unique in a type). Defaults to attribute
name.
description (optional, str): the description of the GraphQL field in the schema.
default_value (optional, Any): Default value to resolve if none set from schema.
**extra_args (optional, Dict[str, Union[graphene.Argument, graphene.UnmountedType]): any
additional arguments to mount on the field.
"""

def __init__(
self,
type,
Expand Down
36 changes: 36 additions & 0 deletions graphene/types/inputfield.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,42 @@


class InputField(MountedType):
"""
Makes a field available on an ObjectType in the GraphQL schema. Any type can be mounted as a
Input Field except Interface and Union:

- Object Type
- Scalar Type
- Enum

Input object types also can't have arguments on their input fields, unlike regular ``graphene.Field``.

All class attributes of ``graphene.InputObjectType`` are implicitly mounted as InputField
using the below arguments.

.. code:: python

class Person(graphene.InputObjectType):
first_name = graphene.String(required=True) # implicitly mounted as Input Field
last_name = graphene.InputField(String, description='Surname') # explicitly mounted as Input Field

args:
type (class for a graphene.UnmountedType): must be a class (not an instance) of an
unmounted graphene type (ex. scalar or object) which is used for the type of this
field in the GraphQL schema.
name (optional, str): the name of the GraphQL input field (must be unique in a type).
Defaults to attribute name.
default_value (optional, Any): Default value to use as input if none set in user operation (
query, mutation, etc.).
deprecation_reason (optional, str): Setting this value indicates that the field is
depreciated and may provide instruction or reason on how for clients to proceed.
description (optional, str): the description of the GraphQL field in the schema.
required (optional, bool): indicates this input field as not null in the graphql scehma.
Raises a validation error if argument not provided. Same behavior as graphene.NonNull.
Default False.
**extra_args (optional, Dict): Not used.
"""

def __init__(
self,
type,
Expand Down
Loading