PyGraphile
A Python library inspired by PostGraphile — automatically generates GraphQL APIs from your database schema.
Point PyGraphile at a SQLite file or a MariaDB/MySQL database, and get a fully working GraphQL API — as an ASGI app (FastAPI, Starlette, Uvicorn) or a WSGI app (Gunicorn, Flask, Django). No schema writing, no manual resolvers.
🚧 Project Status
v0.7.0 — Early access. Core query API is working for SQLite, MariaDB, and MySQL. WSGI support added. Mutations, filtering, and PostgreSQL are on the roadmap.
✨ Features
- 🔍 Schema introspection — Automatically reads tables, columns, and types from your database
- ⚡ Instant GraphQL — Generates a complete, executable GraphQL schema with resolvers on the fly
- 🗄️ Multi-database support — SQLite, MariaDB, and MySQL supported today
- 🔤 Identifier sanitization — Table and column names with spaces or special characters are automatically converted to valid GraphQL names (e.g.
"full name"→full_name,"tabapi request log"→TabapiRequestLog) - 🔌 ASGI & WSGI — Returns a standard ASGI or WSGI app; mount into FastAPI, Starlette, Gunicorn, or any compatible framework
- 🐍 Pure Python — Supports Python 3.9 through 3.13+
🚀 Installation
SQLite (no extra dependencies)
pip install pygraphile
MariaDB / MySQL
pip install "pygraphile[mariadb]"
# or for mysql alias:
pip install "pygraphile[mysql]"
Using uv
uv add pygraphile # SQLite only
uv add "pygraphile[mariadb]" # with MariaDB/MySQL support
From source
git clone https://github.com/dshaw0004/pygraphile.git
cd pygraphile
uv pip install -e .
📖 Quick Start
ASGI — SQLite (FastAPI / Uvicorn)
from pygraphile import PyGraphile
from fastapi import FastAPI
import uvicorn
app = FastAPI()
pg = PyGraphile('mydb.sqlite', db_type='sqlite', debug=True)
app.mount('/graphql', pg.get_asgi_app())
if __name__ == '__main__':
uvicorn.run(app, port=8000)
ASGI — MariaDB / MySQL (FastAPI / Uvicorn)
from pygraphile import PyGraphile
from fastapi import FastAPI
import uvicorn
app = FastAPI()
md = PyGraphile(
'mariadb://user:password@127.0.0.1:3306/mydb',
db_type='mariadb', # or 'mysql'
debug=True,
)
app.mount('/graphql', md.get_asgi_app())
if __name__ == '__main__':
uvicorn.run(app, port=8000)
WSGI — MariaDB / MySQL (Gunicorn)
# app.py
# pip install "pygraphile[mariadb]" gunicorn
from pygraphile import PyGraphile
pg = PyGraphile(
'mariadb://user:password@127.0.0.1:3306/mydb',
db_type='mariadb',
debug=True,
)
application = pg.get_wsgi_app()
gunicorn app:application
WSGI — SQLite (Gunicorn)
# app.py
# pip install pygraphile gunicorn
from pygraphile import PyGraphile
pg = PyGraphile('mydb.sqlite', db_type='sqlite', debug=True)
application = pg.get_wsgi_app()
gunicorn app:application
What gets generated
Given a table named "tabapi request log" with columns id INT and full name VARCHAR:
# Table and column names with spaces are sanitized automatically
type TabapiRequestLog {
id: Int
full_name: String
}
type Query {
tabapi_request_log: [TabapiRequestLog]
}
Query it:
curl -X POST http://localhost:8000/graphql/ \
-H "Content-Type: application/json" \
-d '{"query":"{ tabapi_request_log { id full_name } }"}'
With debug=True, an Apollo GraphQL Explorer is also available at /graphql.
⚙️ API Reference
PyGraphile(db_name, db_type, migration_folder, debug)
| Parameter | Type | Default | Description |
|---|---|---|---|
db_name |
str |
'pygraphile.sqlite' |
SQLite file path, or MariaDB/MySQL connection URI |
db_type |
str |
'sqlite' |
'sqlite', 'sqlite3', 'mariadb', or 'mysql' |
migration_folder |
str |
'nomigration' |
Reserved for future migration support |
debug |
bool |
False |
Enables Apollo Explorer and verbose logging |
pg.get_asgi_app()
Returns an ASGI-compatible Ariadne GraphQL app ready to be mounted into FastAPI, Starlette, or any ASGI server (Uvicorn, Hypercorn, etc.).
app.mount('/graphql', pg.get_asgi_app())
pg.get_wsgi_app()
Returns a WSGI-compatible Ariadne GraphQL app ready to be served by Gunicorn or any WSGI server.
# app.py
application = pg.get_wsgi_app()
# gunicorn app:application
pg.get_query_app(app_type='asgi')
Convenience method that delegates to get_asgi_app() or get_wsgi_app() based on the app_type argument.
| Parameter | Type | Default | Description |
|---|---|---|---|
app_type |
str |
'asgi' |
'asgi' returns an ASGI app; 'wsgi' returns a WSGI app |
pg.get_query_app() # ASGI (default)
pg.get_query_app('wsgi') # WSGI
Utility functions
from pygraphile import sanitize_field_name, sanitize_type_name
sanitize_field_name("full name") # → "full_name"
sanitize_field_name("tabapi request log") # → "tabapi_request_log"
sanitize_type_name("tabapi request log") # → "TabapiRequestLog"
sanitize_type_name("order-items") # → "OrderItems"
🗺️ Roadmap
- Project setup and structure
- SQLite schema introspection and query resolvers
- GraphQL schema generation
- MariaDB & MySQL support
- Identifier sanitization (spaces & special characters in table/column names)
- WSGI support (
get_wsgi_app()) - Mutation support (INSERT / UPDATE / DELETE)
- PostgreSQL support
- Filtering & pagination
- Authentication & authorization
- Plugin system
🤝 Contributing
Contributions are welcome! This project is in early stages, so there's plenty of opportunity to shape its direction.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License — see the LICENSE file for details.
🙏 Acknowledgments
- Inspired by PostGraphile — An amazing tool for PostgreSQL
- Built with Ariadne for GraphQL execution
- Tooling powered by uv
📬 Contact
- GitHub: @dshaw0004
- Project: https://github.com/dshaw0004/pygraphile
Note: This project is under active development. APIs and features are subject to change.
Metadata
Release files for pygraphile 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pygraphile-0.7.0.tar.gz | 145.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pygraphile-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 156.8 kB
Release files / pygraphile-0.7.0.tar.gz
| Download URL | pygraphile-0.7.0.tar.gz |
|---|---|
| Size | 145.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ec1964098e0f76198acd029a04d7f5cbe1282352a22994d7336a2ecb559db939
|
|
BLAKE2b-256 checksum How to use checksums |
5e09aa8cbdfbbb1c530a4eca87a8a1da5191030d65f0cfcee835b5ceff587e4c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / pygraphile-0.7.0-py3-none-any.whl
| Download URL | pygraphile-0.7.0-py3-none-any.whl |
|---|---|
| Size | 11.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0aa3179b2d8856cdb9a89651bd3146cc5e71074a2310c3ed7dac174d41b30d84
|
|
BLAKE2b-256 checksum How to use checksums |
9160da66ebb10292319d2a778508ea76c213b5ddeb893db9eb37d386e2b7d727
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency log