diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e4c8ddf8..fb1aba8a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -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 `__ 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``. diff --git a/docs/sphinx/intro.rst b/docs/sphinx/intro.rst index e5322cea..33541337 100644 --- a/docs/sphinx/intro.rst +++ b/docs/sphinx/intro.rst @@ -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 `__ to set your passwords. A typical ``~/.pgpass`` file looks something like :: @@ -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 `__ 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 diff --git a/pyproject.toml b/pyproject.toml index e94d5dd3..cf35eb79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ content-type = "text/markdown" [project.optional-dependencies] all = [ + "psycopg[binary]", "progressbar2>=3.46.1", "pydot>=1.4.1", "astropy>=4.0.0", @@ -37,7 +38,7 @@ all = [ "inflect>=4.1.0", "h5py>=3.8.0", "sdssdb[dev]", - "sdssdb[docs]", + "sdssdb[docs]" ] dev = [ "pytest>=5.2", @@ -145,5 +146,8 @@ sdss = ["sdsstools"] sqla = ["sqlalchemy"] peewee = ["peewee", "playhouse"] +[tool.ruff.format] +preview = true + [tool.coverage.run] branch = true diff --git a/python/sdssdb/__init__.py b/python/sdssdb/__init__.py index 8c841df5..224014a2 100644 --- a/python/sdssdb/__init__.py +++ b/python/sdssdb/__init__.py @@ -1,5 +1,6 @@ # encoding: utf-8 +import os import warnings from sqlalchemy.exc import MovedIn20Warning @@ -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 diff --git a/python/sdssdb/connection.py b/python/sdssdb/connection.py index fa971a4c..925088dc 100644 --- a/python/sdssdb/connection.py +++ b/python/sdssdb/connection.py @@ -13,6 +13,7 @@ import os import re import socket +import warnings import pgpasslib import six @@ -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.""" @@ -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}" @@ -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):