Skip to content

Commit

Permalink
Merge pull request #78 from glyph/non-twisted
Browse files Browse the repository at this point in the history
database adapters for native asyncio bindings
  • Loading branch information
glyph authored Mar 20, 2024
2 parents cf8abd5 + 41f1080 commit 2152e7b
Show file tree
Hide file tree
Showing 29 changed files with 1,244 additions and 343 deletions.
3 changes: 3 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ extend-ignore =

######## WARNINGS ABOVE SHOULD BE FIXED ########

# module level import not at top of file
E402,

# Invalid first argument used for instance method
B902,

Expand Down
67 changes: 65 additions & 2 deletions .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,18 +183,54 @@ jobs:


unit:
name: "Py:${{ matrix.python-version }} - Tw:${{ matrix.twisted-version }} - ${{ matrix.os }}"
name: "${{ matrix.tox-suffix }}Py:${{ matrix.python-version }} - Tw:${{ matrix.twisted-version }} - ${{ matrix.os }}"

runs-on: ${{ matrix.os }}
timeout-minutes: 30
continue-on-error: ${{ matrix.optional }}

services:
mysql:
image: "${{ matrix.mysql-image }}"
env:
MYSQL_ROOT_PASSWORD: "ghamysqlpassword"
MYSQL_DATABASE: "ghamysqldb"
ports:
- "3306:3306"
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
postgres16:

# https://github.com/actions/runner/issues/822
image: "${{ matrix.pg-image }}"

env:
POSTGRES_DB: "ghapgdb"
POSTGRES_USER: "ghapguser"
POSTGRES_PASSWORD: "ghapgpass"
POSTGRES_PORT: "5432"
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
strategy:
matrix:
os: ["ubuntu-latest"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
twisted-version: ["21.2", "22.1", "23.10"]
tox-prefix: ["coverage"]
tox-suffix: [""]
optional: [false]
pg-image: [""]
include:
- os: "ubuntu-latest"
python-version: "pypy-3.8"
Expand All @@ -208,6 +244,20 @@ jobs:
twisted-version: "current"
tox-prefix: "coverage"
optional: false
- os: "ubuntu-latest"
python-version: "3.12"
twisted-version: "23.10"
tox-prefix: "coverage"
tox-suffix: "-postgres"
pg-image: "postgres:16"
optional: false
- os: "ubuntu-latest"
python-version: "3.12"
twisted-version: "23.10"
tox-prefix: "coverage"
tox-suffix: "-mysql"
mysql-image: "mysql:8.0.29"
optional: false

steps:

Expand Down Expand Up @@ -239,7 +289,7 @@ jobs:
tw = "${{ matrix.twisted-version }}"
tw = tw.replace(".", "")
env = f"${{ matrix.tox-prefix }}-py{py}-tw{tw}"
env = f"${{ matrix.tox-prefix }}-py{py}-tw{tw}${{ matrix.tox-suffix }}"
print(f"TOX_ENV={env}")
Expand All @@ -259,6 +309,19 @@ jobs:

- name: Run unit tests
run: tox run -e ${TOX_ENV}
env:
PGHOST: "localhost"
PGPORT: "5432"

PGUSER: "ghapguser"
PGDATABASE: "ghapgdb"
PGPASSWORD: "ghapgpass"

MYSQL_USER: "root"
MYSQL_PWD: "ghamysqlpassword"
MYSQL_DATABASE: "ghamysqldb"
MYSQL_HOST: "localhost"
MYSQL_PORT: "3306"

- name: Combine coverage
run: tox run -e coverage_combine,coverage_report
Expand Down
4 changes: 4 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ profile = black
# Put two blank lines after imports
lines_after_imports = 2

# not sure why this is a non-default, let's not make 'as' imports randomly way
# more verbose
combine_as_imports = true

# Match max-line-length in Flake8 config
line_length = 80

Expand Down
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ repos:
- id: python-check-blanket-noqa
- id: python-check-blanket-type-ignore
- id: python-no-eval
- id: python-use-type-annotations
- id: rst-backticks
- id: rst-directive-colons
- id: rst-inline-touching-normal
Expand Down
41 changes: 23 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,40 +80,45 @@ drivers and pytest is definitely on the roadmap.)
Using it looks like this:

```python
@dataclass
class Quote:
db: QuoteDB
id: int
contents: str

from dbxs import query, one, many
from dbxs.dbapi_async import adaptSynchronousDriver
from dbxs import accessor, many, one, query, statement

class QuoteDB(Protocol):
@query(
sql="select id, contents from quote where id = {id}",
load=one(Quote),
)
async def quoteByID(self, id: int) -> Quote:
...
@query(sql="SELECT id, contents FROM quote WHERE id={id}", load=one(Quote))
async def quoteByID(self, id: int) -> Quote: ...

@query(sql="SELECT id, contents FROM quote", load=many(Quote))
def allQuotes(self) -> AsyncIterable[Quote]: ...

@statement(sql="INSERT INTO quote (contents) VALUES ({text})")
async def addQuote(self, text: str) -> None: ...

@query(
sql="select id, contents from quote",
load=many(Quote),
from dbxs.dbapi import DBAPIConnection
def sqliteWithSchema() -> DBAPIConnection:
c = connect(":memory:")
c.execute(
"CREATE TABLE quote (contents, id INTEGER PRIMARY KEY AUTOINCREMENT)"
)
def allQuotes(self) -> AsyncIterable[Quote]:
...
c.commit()
return c

from dbxs.adapters.dbapi_twisted import adaptSynchronousDriver
driver = adaptSynchronousDriver(sqliteWithSchema, paramstyle)
quotes = accessor(QuoteDB)

driver = adaptSynchronousDriver(lambda: sqlite3.connect(...))

async def main() -> None:
from dbxs.async_dbapi import transaction
async with transaction(driver) as t:
quotedb: QuoteDB = quotes(t)
print("quote 1", (await quotedb.quoteByID(1)).contents)
await quotedb.addQuote("hello, world")
async for quote in quotedb.allQuotes():
print("quote", quote.id, quote.contents)

matched = (await quotedb.quoteByID(quote.id)) == quote
print(f"quote ({quote.id}) {quote.contents!r} {matched}")
```

### Previous SQL Interface Solutions
Expand Down
63 changes: 63 additions & 0 deletions check_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from __future__ import annotations

from dataclasses import dataclass
from sqlite3 import connect, paramstyle
from typing import AsyncIterable, Protocol


@dataclass
class Quote:
db: QuoteDB
id: int
contents: str


from dbxs import accessor, many, one, query, statement
from dbxs.adapters.dbapi_twisted import adaptSynchronousDriver
from dbxs.async_dbapi import transaction
from dbxs.dbapi import DBAPIConnection


class QuoteDB(Protocol):
@query(sql="SELECT id, contents FROM quote WHERE id={id}", load=one(Quote))
async def quoteByID(self, id: int) -> Quote:
...

@query(sql="SELECT id, contents FROM quote", load=many(Quote))
def allQuotes(self) -> AsyncIterable[Quote]:
...

@statement(sql="INSERT INTO quote (contents) VALUES ({text})")
async def addQuote(self, text: str) -> None:
...


def sqliteWithSchema() -> DBAPIConnection:
c = connect(":memory:")
c.execute(
"CREATE TABLE quote (contents, id INTEGER PRIMARY KEY AUTOINCREMENT)"
)
c.commit()
return c


driver = adaptSynchronousDriver(sqliteWithSchema, paramstyle)
quotes = accessor(QuoteDB)


async def main() -> None:
async with transaction(driver) as t:
quotedb: QuoteDB = quotes(t)
await quotedb.addQuote("hello, world")
async for quote in quotedb.allQuotes():
matched = (await quotedb.quoteByID(quote.id)) == quote
print(f"quote ({quote.id}) {quote.contents!r} {matched}")


if __name__ == "__main__":
from twisted.internet.defer import Deferred
from twisted.internet.task import react

@react
def run(reactor: object) -> Deferred[None]:
return Deferred.fromCoroutine(main())
2 changes: 2 additions & 0 deletions requirements/mypy.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
-r postgres.txt
mypy==1.8.0
mypy-zope==1.0.3
mysql-connector-python==8.3.0
types-click==7.1.8
1 change: 1 addition & 0 deletions requirements/mysql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mysql-connector-python==8.3.0
2 changes: 2 additions & 0 deletions requirements/postgres.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
psycopg==3.1.18
psycopg-binary==3.1.18 ; implementation_name == "cpython"
2 changes: 1 addition & 1 deletion requirements/tox-pin-base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ hyperlink==21.0.0
idna==3.4
incremental==22.10.0
six==1.16.0
typing_extensions==4.9.0
typing-extensions==4.10.0
zope.interface==6.1
Loading

0 comments on commit 2152e7b

Please sign in to comment.