Skip to main content

A simplified GraphQL-esque library

Project description

NewQL

CI codecov pypi license

A simplified GraphQL-esque library

Notable features:

  • Schema defined using pythonic classes
  • Introspection for support with the GraphiQL interface
    • Field / type / argument docstrings
    • Nested types
  • Aliases
  • Query variables
  • Enums (can simply use pure python enums)
  • Flexible type system (unlike GraphQL which coerces and validates more strictly)

What NewQL does not support:

  • Fragments
  • Directives
  • Subscriptions
  • Per-field or per-type introspection (the introspection returns all or nothing)

Installation

Requires python 3.7+

pip install newql

Usage

from newql import ExecutionContext, Schema, field

class Product:
    """Represents a product in stock"""

    product_id = field(type=int)
    product_name = field(type=str)
    price = field(type=float)

class ProductQuery:
    # pass 'type' here since the function returns a dictionary,
    # but we want to actually resolve to a Product
    @field(type=Product)
    def product(_, context: ExecutionContext, product_id: int) -> dict:
        # The "Args" section of the docstring is parsed out to add
        # docs to the arguments (can be seen in GraphiQL)
        """Find a specific product by id

        Args:
            product_id: The ID of the product to find
        """

        products = {1: ("Product1", 49.99), 2: ("Product2", 94.49)}
        if product_id in products:
            name, price = products[product_id]
            return {"product_id": product_id, "product_name": name, "price": price}
        else:
            raise ValueError(f"Product not found: {product_id}")

schema = Schema(ProductQuery)

Explore the above example using python -m newql.dev_server --schema newql.example.product_schema:

{
  product(product_id: 1) {
    price
    product_name
  }
}

Or execute a query through code:

QUERY = """
{
  product(product_id: 1) {
    price
    product_name
  }
}
"""

from newql.example import product_schema
product_schema.execute(QUERY)
# => {"data": {"product": {"price": 49.99, "product_name": "Product1"}}}

A mutation class can be defined in exactly the same way as a query class, and can be passed to Schema as a second positional argument or by the mutation keyword argument.

class Mutation:
    ...

schema = Schema(mutation=Mutation)

To start a dev server serving a GraphiQL interface:

python -m newql.dev_server  # uses the schema in newql.example

# can specify a custom schema
python -m newql.dev_server --schema <full import name of your schema>
# for example:
python -m newql.dev_server --schema my_module.nested_module.my_schema

Note that when defining a field inline and not specifying the field name, the field name will be determined by the name of the variable to which it is assigned. For example:

class MyClass:
    my_field = field(type=str)

The field will be named my_field. This is achieved by the library varname, however since it needs to parse AST to determine the name, it can take time.

If there are more than a couple hundred fields, it is recommended to explicitly set the name of the field to avoid this performance hit:

class MyClass:
    my_field = field("my_field", type=str)

Development

Clone the repo, then from the project directory:

python3 -m venv .venv
. .venv/bin/activate

make install-dev

To run tests (and show coverage):

make test

Before making changes, fix formatting and check changes (isort, black, flake8, mypy):

make format check

Changelog

0.5.0 2021-07-26

  • Allow variable types to be a list, e.g. [String!]

0.4.0 2021-07-23

  • Allow '!' after variable type definitions (currently just ignored)

0.3.1 2021-07-22

  • Allow unused variables to be sent in query

0.3.0 2021-07-21

  • Support commas as whitespace

0.2.0 2021-07-21

  • Improve Enum support (was not working properly when wrapped in an Optional or List)

0.1.1 2021-06-30

  • Fix changelog release date + header
  • Cosmetic improvements to query parsing

0.1.0 2021-06-30

  • Initial release

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

newql-0.5.0.tar.gz (15.3 kB view details)

Uploaded Source

Built Distribution

newql-0.5.0-py3-none-any.whl (16.4 kB view details)

Uploaded Python 3

File details

Details for the file newql-0.5.0.tar.gz.

File metadata

  • Download URL: newql-0.5.0.tar.gz
  • Upload date:
  • Size: 15.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.7.11

File hashes

Hashes for newql-0.5.0.tar.gz
Algorithm Hash digest
SHA256 2114c67ef3537d0c5481f3da64bd4687c8c223247b1a91d9a2c0c70d9c6a9891
MD5 22744a62ffdb90fceb5cbeb2f47b85ff
BLAKE2b-256 3ab732c879a8444b7f74a42bd4c5c1a34d3e30612b46c49c6a8aacde7b99d308

See more details on using hashes here.

File details

Details for the file newql-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: newql-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 16.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.7.11

File hashes

Hashes for newql-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 816d2aab3e52ee37389607fc91aa4d666ece6a2ca75ddc5ad78abb8c4d278cc4
MD5 f64ac02c95707bc9f7fccff5841c2993
BLAKE2b-256 0b8a731087b8c037d706bdd647d3e542e07b0ac2bc15b78ea6ccc66b7d633f46

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page