diff --git a/.gitignore b/.gitignore index 52d024f..5915b7e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ docs/_build env env2 *.egg-info +htmlcov/ .python-version +.tox/ diff --git a/.travis.yml b/.travis.yml index f677311..5e537a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,10 @@ language: python python: - - 2.7 - - 3.5 - 3.6 - 3.7 - 3.8 + - 3.9 - "nightly" matrix: diff --git a/docs/index.rst b/docs/index.rst index d63848a..e872ce8 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -35,6 +35,10 @@ An Object-Relational Mapper (ORM) Changelog --------- +**4.0 (???)** + +- dropped support for Python 2.7 and 3.5 (:pr:`96`) + **3.0.0 (Oct 19, 2019)** - the :class:`ReadOnly` exception has been renamed to :class:`ReadOnlyAttribute`, and the :attr:`_read_only_attributes` attribute of the :class:`~postgres.orm.Model` class has been renamed to :attr:`attnames` (:pr:`91`) diff --git a/postgres/__init__.py b/postgres/__init__.py index 74e674a..99b8df4 100644 --- a/postgres/__init__.py +++ b/postgres/__init__.py @@ -8,11 +8,11 @@ $ pip install postgres -:mod:`postgres` requires `psycopg2`_ version 2.7.5 or higher. +:mod:`postgres` requires `psycopg2`_ version 2.8 or higher. -We `test `_ against Python 2.7, 3.5, -3.6, and 3.7. We don't yet have a testing matrix for different versions of -:mod:`psycopg2` or PostgreSQL. +We currently `test `_ against +Python 3.6, 3.7, 3.8 and 3.9. We don't have a testing matrix for different +versions of :mod:`psycopg2` or PostgreSQL. :mod:`postgres` is released under the `MIT license`_. @@ -163,11 +163,9 @@ .. _SQL injection: http://en.wikipedia.org/wiki/SQL_injection """ -from __future__ import absolute_import, division, print_function, unicode_literals from collections import OrderedDict, namedtuple from inspect import isclass -import sys import psycopg2 from psycopg2 import DataError, InterfaceError, ProgrammingError @@ -186,15 +184,6 @@ from postgres.orm import Model -if sys.version_info[0] == 2: # Python 2 - # "Note: In Python 2, if you want to uniformly receive all your database - # input in Unicode, you can register the related typecasters globally as - # soon as Psycopg is imported." - # -- http://initd.org/psycopg/docs/usage.html#unicode-handling - psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) - psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY) - - __version__ = '3.0.0' @@ -249,7 +238,7 @@ def __str__(self): } -class Postgres(object): +class Postgres: """Interact with a `PostgreSQL `_ database. :param str url: A ``postgres://`` URL or a `PostgreSQL connection string @@ -652,11 +641,8 @@ class ModelCaster(CompositeCaster): def _from_db(cls, db, typname, ModelSubclass): # Override to set custom attributes. with db.get_cursor(autocommit=True, readonly=True) as cursor: - name = typname - if sys.version_info[0] < 3: - name = name.encode('UTF-8') try: - caster = super(ModelCaster, cls)._from_db(name, cursor) + caster = super(ModelCaster, cls)._from_db(typname, cursor) except ProgrammingError: raise NoSuchType(typname) caster.db = ModelSubclass.db = db diff --git a/postgres/context_managers.py b/postgres/context_managers.py index 5f96c9c..42732a9 100644 --- a/postgres/context_managers.py +++ b/postgres/context_managers.py @@ -1,9 +1,7 @@ -from __future__ import absolute_import, division, print_function, unicode_literals - from psycopg2 import InterfaceError -class CursorContextManager(object): +class CursorContextManager: """Instantiated once per :func:`~postgres.Postgres.get_cursor` call. :param pool: see :mod:`psycopg2_pool` @@ -49,7 +47,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.pool.putconn(self.conn) -class ConnectionCursorContextManager(object): +class ConnectionCursorContextManager: """Creates a cursor from the given connection, then wraps it in a context manager that automatically commits or rolls back the changes on exit. @@ -91,7 +89,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.conn.__exit__(exc_type, exc_val, exc_tb) -class CursorSubcontextManager(object): +class CursorSubcontextManager: """Wraps a cursor so that it can be used for a subtransaction. See :meth:`~postgres.Postgres.get_cursor` for an explanation of subtransactions. @@ -121,7 +119,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.cursor.back_as = self.outer_back_as -class ConnectionContextManager(object): +class ConnectionContextManager: """Instantiated once per :func:`~postgres.Postgres.get_connection` call. :param pool: see :mod:`psycopg2_pool` diff --git a/postgres/cursors.py b/postgres/cursors.py index 140e475..82742cd 100644 --- a/postgres/cursors.py +++ b/postgres/cursors.py @@ -5,7 +5,6 @@ and :meth:`all`. """ -from __future__ import absolute_import, division, print_function, unicode_literals from inspect import isclass from operator import itemgetter @@ -62,7 +61,7 @@ class TooMany(OutOfBounds): # Cursors # ======= -class SimpleCursorBase(object): +class SimpleCursorBase: """ This is a mixin to provide a simpler API atop the usual DB-API 2.0 API @@ -390,7 +389,7 @@ def return_tuple_as_is(cols, vals): return vals -class Row(object): +class Row: """A versatile row type. """ diff --git a/postgres/orm.py b/postgres/orm.py index 38bed3c..70f66b8 100644 --- a/postgres/orm.py +++ b/postgres/orm.py @@ -171,7 +171,6 @@ -------------------- """ -from __future__ import absolute_import, division, print_function, unicode_literals # Exceptions @@ -193,7 +192,7 @@ def __str__(self): # Stuff # ===== -class Model(object): +class Model: """This is the base class for models in :mod:`postgres.orm`. Instances of subclasses of :class:`~postgres.orm.Model` will have an diff --git a/setup.cfg b/setup.cfg index 3ed1922..5370471 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,8 +18,10 @@ classifiers = Intended Audience :: Developers License :: OSI Approved :: MIT License Operating System :: OS Independent - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 Programming Language :: SQL Topic :: Database :: Front-Ends Topic :: Software Development :: Libraries :: Python Modules diff --git a/tests.py b/tests.py index d905e6c..53dbd0d 100644 --- a/tests.py +++ b/tests.py @@ -1,7 +1,4 @@ -from __future__ import absolute_import, division, print_function, unicode_literals - from collections import namedtuple -import sys from unittest import TestCase from postgres import ( @@ -658,8 +655,7 @@ def test_one(self): assert r[1] == 43 assert r.value == 43 assert r['value'] == 43 - if sys.version_info >= (3, 0): - assert repr(r) == "Row(key='biz', value=43)" + assert repr(r) == "Row(key='biz', value=43)" def test_all(self): rows = self.db.all("SELECT * FROM foo ORDER BY key") @@ -712,8 +708,6 @@ def test_special_col_names(self): assert r['?column?'] == 2 assert r['3'] == 3 - @mark.xfail(sys.version_info < (3, 0), - reason="Unicode attribute names require Python >= 3.0") def test_nonascii_names(self): r = self.db.one('SELECT 1 as \xe5h\xe9, 2 as \u2323') assert getattr(r, '\xe5h\xe9') == 1 diff --git a/tox.ini b/tox.ini index ea4e606..4b870e8 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py{27,35,36,37},docs +envlist = py{36,37,38,39},docs [testenv] deps = @@ -9,15 +9,15 @@ deps = commands = python -m pytest tests.py -v --cov postgres --cov-report html flake8 - py37: python postgres/__init__.py - py37: python postgres/cursors.py - py37: python postgres/orm.py + py39: python postgres/__init__.py + py39: python postgres/cursors.py + py39: python postgres/orm.py passenv = PG* setenv = PGDATABASE={env:PGDATABASE:test} usedevelop = true [testenv:docs] -basepython = python3.7 +basepython = python3.9 deps = sphinx commands = sphinx-build -b html docs/ docs/_build/html usedevelop = true