Skip to content
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

add psycopg dialect #19

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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 @@ -22,6 +22,8 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
uv.lock
.venv

# Unit test / coverage reports
htmlcov/
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![codecov](https://codecov.io/gh/dorosch/sqlalchemy-timescaledb/branch/develop/graph/badge.svg?token=Gzh7KpADjZ)][3]
[![Downloads](https://pepy.tech/badge/sqlalchemy-timescaledb)][4]

This is the TimescaleDB dialect driver for SQLAlchemy. Drivers `psycopg2` and `asyncpg` are supported.
This is the TimescaleDB dialect driver for SQLAlchemy. Drivers `psycopg2`, `psycopg` and `asyncpg` are supported.

## Install

Expand All @@ -22,6 +22,7 @@ import datetime
from sqlalchemy import create_engine, MetaData
from sqlalchemy import Table, Column, Integer, String, DateTime

# or use timescaledb+psycopg/asyncpg
engine = create_engine('timescaledb://user:password@host:port/database')
metadata = MetaData()
metadata.bind = engine
Expand Down
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ test = [
"pytest-cov==4.0.0",
"pytest-factoryboy==2.5.1",
"sqlalchemy[asyncio]>=1.3",
"psycopg2-binary==2.9.5",
"psycopg2-binary==2.9.9",
"psycopg[binary]==3.2.3",
"alembic==1.9.4",
"asyncpg==0.27.0",
"asyncpg==0.30.0",
"pytest-asyncio==0.20.3"
]

Expand All @@ -28,6 +29,7 @@ test = [
[project.entry-points."sqlalchemy.dialects"]
"timescaledb" = "sqlalchemy_timescaledb.dialect:TimescaledbPsycopg2Dialect"
"timescaledb.psycopg2" = "sqlalchemy_timescaledb.dialect:TimescaledbPsycopg2Dialect"
"timescaledb.psycopg" = "sqlalchemy_timescaledb.dialect:TimescaledbPsycopgDialect"
"timescaledb.asyncpg" = "sqlalchemy_timescaledb.dialect:TimescaledbAsyncpgDialect"

[build-system]
Expand Down
6 changes: 6 additions & 0 deletions sqlalchemy_timescaledb/dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from sqlalchemy.dialects.postgresql.asyncpg import PGDialect_asyncpg
from sqlalchemy.dialects.postgresql.base import PGDDLCompiler
from sqlalchemy.dialects.postgresql.psycopg2 import PGDialect_psycopg2
from sqlalchemy.dialects.postgresql.psycopg import PGDialect_psycopg

try:
import alembic
Expand Down Expand Up @@ -74,3 +75,8 @@ class TimescaledbPsycopg2Dialect(TimescaledbDialect, PGDialect_psycopg2):
class TimescaledbAsyncpgDialect(TimescaledbDialect, PGDialect_asyncpg):
driver = 'asyncpg'
supports_statement_cache = True


class TimescaledbPsycopgDialect(TimescaledbDialect, PGDialect_psycopg):
driver = 'psycopg'
supports_statement_cache = True
Empty file added tests/psycopg/__init__.py
Empty file.
43 changes: 43 additions & 0 deletions tests/psycopg/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import pytest
from sqlalchemy import create_engine, text

from sqlalchemy.orm import Session

from tests.factories import FactorySession
from tests.models import Base, DATABASE_URL


@pytest.fixture
def psycopg_engine():
yield create_engine(
DATABASE_URL.set(drivername='timescaledb+psycopg')
)

@pytest.fixture
def session(psycopg_engine):
with Session(psycopg_engine) as session:
yield session


@pytest.fixture(autouse=True)
def setup(psycopg_engine):
FactorySession.configure(bind=psycopg_engine)
Base.metadata.create_all(bind=psycopg_engine)
yield
Base.metadata.drop_all(bind=psycopg_engine)


@pytest.fixture
def is_hypertable(session):
def check_hypertable(table):
return session.execute(
text(
f"""
SELECT count(*)
FROM _timescaledb_catalog.hypertable
WHERE table_name = '{table.__tablename__}'
"""
)
).scalar_one() == 1

return check_hypertable
9 changes: 9 additions & 0 deletions tests/psycopg/test_hypertable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from tests.models import Metric, User


class TestHypertable:
def test_is_hypertable(self, is_hypertable):
assert is_hypertable(Metric)

def test_is_not_hypertable(self, is_hypertable):
assert not is_hypertable(User)