Skip to content

Commit

Permalink
Support psycopg 3.x (#268)
Browse files Browse the repository at this point in the history
* Replace setup.cfg/.py with pyproject.toml

* Support linting with flake8 or ruff and fix some linting issues

* Fix test issues

* Update workflows

* Use uv in workflow for faster install

* Change default postgres username in workflow

* Delete STYLE.rst

* Update changelog

* Support psycopg 3.x

* Add documentation for the new connection flags

* Update changelog

* Make sdssdb.use_psycopg3 a boolean
  • Loading branch information
albireox authored Sep 3, 2024
1 parent b0fd161 commit aa1113a
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This document records the main changes to the ``sdssdb`` code.

* :feature:`264` Add metadata for the ``sdss_id_to_catalog`` table.
* :feature:`266` Support PEP 621.
* :feature:`268` Allows to use `psycopy3 <https://www.psycopg.org/psycopg3/docs/>`__ as a driver for the Peewee database connection.
* Add missing columns to the ``SDSS_ID_To_Catalog`` models (the columns were being completed via reflection).
* Change ``reflection=False`` to ``use_reflection=False`` in many ``catalogdb`` models. The previous setting was incorrect and was causing the models to be reflected.
* Add ``gortdb`` schema and models to ``lvmdb``. Moved ``lvmopsdb.overhead`` to ``gortdb``.
Expand Down
18 changes: 17 additions & 1 deletion docs/sphinx/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ There are two database connections, ``SQLADatabaseConnection`` and ``PeeWeeDatab


A note about passwords
----------------------
^^^^^^^^^^^^^^^^^^^^^^

``sdssdb`` does not allow you to pass plaintext passwords when creating a connection, or to store them in the profiles. Instead, you should use `pgpass <https://www.postgresql.org/docs/9.3/libpq-pgpass.html>`__ to set your passwords. A typical ``~/.pgpass`` file looks something like ::

Expand All @@ -256,6 +256,22 @@ A note about passwords
where ``XXXX``, ``YYYY``, etc are the associated passwords for each set of parameters.


Connection flags
^^^^^^^^^^^^^^^^

``sdssdb`` supports two flags that change the behaviour of the database connection.

* **autoconnect**: if set to `False` the connection will not attempt to connect to the database when created. This is useful when you want to create a connection object but connect to the database later. ``autoconnect`` defaults to `True` and can be changed either by setting the environment variable ``SDSSDB_AUTOCONNECT=0`` before importing the model classes, or by doing ::

>>> import sdssdb
>>> sdssdb.autoconnect = False
... import your model classes ...

When instantiating a `.DatabaseConnection` object manually, you can also pass the ``autoconnect=False`` keyword argument.

* **use_psycopg3**: prefers to use `psycopg3 <https://www.psycopg.org/psycopg3/docs/>`__ instead of the default ``psycopg2``. If ``psycopg3`` is not installed, ``psycopg2`` will be used instead. This flag can be set via the environment variable ``SDSSDB_PSYCOPG3=1`` or by importing ``sdssdb`` and setting ``sdssdb.use_psycopg3 = True`` before importing the model classes.


.. _profile:

Supported Profiles
Expand Down
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ content-type = "text/markdown"

[project.optional-dependencies]
all = [
"psycopg[binary]",
"progressbar2>=3.46.1",
"pydot>=1.4.1",
"astropy>=4.0.0",
"pandas>=1.0.0",
"inflect>=4.1.0",
"h5py>=3.8.0",
"sdssdb[dev]",
"sdssdb[docs]",
"sdssdb[docs]"
]
dev = [
"pytest>=5.2",
Expand Down Expand Up @@ -145,5 +146,8 @@ sdss = ["sdsstools"]
sqla = ["sqlalchemy"]
peewee = ["peewee", "playhouse"]

[tool.ruff.format]
preview = true

[tool.coverage.run]
branch = true
3 changes: 3 additions & 0 deletions python/sdssdb/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# encoding: utf-8

import os
import warnings

from sqlalchemy.exc import MovedIn20Warning
Expand Down Expand Up @@ -32,6 +33,8 @@
config = get_config(NAME)

autoconnect = True
use_psycopg3 = os.environ.get("SDSSDB_PSYCOPG3", "false").lower() in ["true", "1"]


from .connection import PeeweeDatabaseConnection # noqa
from .connection import SQLADatabaseConnection # noqa
24 changes: 20 additions & 4 deletions python/sdssdb/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import os
import re
import socket
import warnings

import pgpasslib
import six
Expand All @@ -23,18 +24,30 @@
from sqlalchemy.orm import scoped_session, sessionmaker

import peewee
from peewee import OperationalError, PostgresqlDatabase
from peewee import OperationalError
from playhouse.postgres_ext import ArrayField
from playhouse.reflection import Introspector, UnknownField

import sdssdb
from sdssdb import config, log
from sdssdb import config, log, use_psycopg3
from sdssdb.utils.internals import get_database_columns


__all__ = ["DatabaseConnection", "PeeweeDatabaseConnection", "SQLADatabaseConnection"]


if use_psycopg3 is True:
try:
import psycopg # noqa
from playhouse.psycopg3_ext import Psycopg3Database as PostgresqlDatabase
except ImportError:
warnings.warn("psycopg3 is not installed. Using psycopg2.")
from peewee import PostgresqlDatabase

else:
from peewee import PostgresqlDatabase


def _should_autoconnect():
"""Determines whether we should autoconnect."""

Expand Down Expand Up @@ -62,7 +75,7 @@ def get_database_uri(
else:
auth: str = f"{user}:{password}@"

host_port: str = f"{host or ''}" if port is None else f"{host or ''}:{port}"
host_port: str = f"{host or ""}" if port is None else f"{host or ""}:{port}"

if auth == "" and host_port == "":
return f"postgresql://{dbname}"
Expand Down Expand Up @@ -132,7 +145,10 @@ def __init__(self, dbname=None, profile=None, autoconnect=None, dbversion=None):

def __repr__(self):
return "<{} (dbname={!r}, profile={!r}, connected={})>".format(
self.__class__.__name__, self.dbname, self.profile, self.connected
self.__class__.__name__,
self.dbname,
self.profile,
self.connected,
)

def set_profile(self, profile=None, connect=True, **params):
Expand Down

0 comments on commit aa1113a

Please sign in to comment.