From 4325abbc7b9362f9edbf23fa08cafcf208c06bf9 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 21 Apr 2019 20:12:40 +0200 Subject: [PATCH 001/295] Usage of augmented assignment statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source code like “var = var + …” was specified at some places so far. Use augmented assignment statements instead because they are succinct and can be more efficient. https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements Signed-off-by: Markus Elfring --- sqlobject/col.py | 9 ++++----- sqlobject/dbconnection.py | 8 ++++---- sqlobject/joins.py | 4 ++-- sqlobject/tests/test_select.py | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index 81195393..a22fb666 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -733,9 +733,9 @@ def addSQLAttrs(self, str): if self.length and self.length >= 1: _ret = "%s(%d)" % (_ret, self.length) if self.unsigned: - _ret = _ret + " UNSIGNED" + _ret += " UNSIGNED" if self.zerofill: - _ret = _ret + " ZEROFILL" + _ret += " ZEROFILL" return _ret def _sqlType(self): @@ -1092,9 +1092,8 @@ def maxdbCreateSQL(self): sql = ' '.join([fidName, self._maxdbType()]) tName = other.sqlmeta.table idName = self.refColumn or other.sqlmeta.idName - sql = sql + ',' + '\n' - sql = sql + 'FOREIGN KEY (%s) REFERENCES %s(%s)' % (fidName, tName, - idName) + sql += ',\nFOREIGN KEY (%s) REFERENCES %s(%s)' % (fidName, tName, + idName) return sql def maxdbCreateReferenceConstraint(self): diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index fbff4576..8e096391 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -108,8 +108,8 @@ def oldUri(self): auth = getattr(self, 'user', '') or '' if auth: if self.password: - auth = auth + ':' + self.password - auth = auth + '@' + auth += ':' + self.password + auth += '@' else: assert not getattr(self, 'password', None), ( 'URIs cannot express passwords without usernames') @@ -129,8 +129,8 @@ def uri(self): if auth: auth = quote(auth) if self.password: - auth = auth + ':' + quote(self.password) - auth = auth + '@' + auth += ':' + quote(self.password) + auth += '@' else: assert not getattr(self, 'password', None), ( 'URIs cannot express passwords without usernames') diff --git a/sqlobject/joins.py b/sqlobject/joins.py index afb0f881..e2c835a6 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -170,9 +170,9 @@ def __init__(self, addRemoveName=None, **kw): if not self.joinMethodName: name = self.otherClassName[0].lower() + self.otherClassName[1:] if name.endswith('s'): - name = name + "es" + name += "es" else: - name = name + "s" + name += "s" self.joinMethodName = name if addRemoveName: self.addRemoveName = addRemoveName diff --git a/sqlobject/tests/test_select.py b/sqlobject/tests/test_select.py index 3a0055ea..12677063 100644 --- a/sqlobject/tests/test_select.py +++ b/sqlobject/tests/test_select.py @@ -66,7 +66,7 @@ def test_04_indexed_ended_by_exception(): try: while 1: all[count] - count = count + 1 + count += 1 # Stop the test if it's gone on too long if count > len(names): break From 85bae29d1727980a682e9d59cd5254ded573add3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Apr 2019 19:35:38 +0300 Subject: [PATCH 002/295] Fix(pgconnection): Adapt Postgres exception handling to `psycopg2` 2.8 In the recent `psycopg2` errors are in `psycopg2.errors` module. --- docs/News.rst | 10 ++++++++-- sqlobject/postgres/pgconnection.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 1b968833..dade2cbf 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,14 @@ News .. contents:: Contents: :backlinks: none -SQLObject 3.8.0 (master) -======================== +SQLObject (master) +================== + +Minor features +-------------- + +* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: + in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. SQLObject 3.7.1 =============== diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 8dd1db58..afe81333 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -11,7 +11,7 @@ class ErrorMessage(str): def __new__(cls, e, append_msg=''): obj = str.__new__(cls, e.args[0] + append_msg) - if e.__module__ == 'psycopg2': + if hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors obj.code = getattr(e, 'pgcode', None) obj.error = getattr(e, 'pgerror', None) else: From bebfdf9512ca6cdf94a3724dc2625a2288246945 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Apr 2019 19:45:45 +0300 Subject: [PATCH 003/295] Build(devscripts): Remove docs/_build/html on branch change [skip ci] --- devscripts/git-hooks/post-checkout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index 2bd5be00..40f7bd71 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -13,7 +13,7 @@ if [ "$new_branch" = 1 ]; then for d in sqlobject/include/pydispatch sqlobject/include/tests; do if [ "`echo $d/*`" = "$d/*" ]; then rm -rf $d; fi done && - rm -rf docs/html + rm -rf docs/_build/html docs/html fi && python -m compileall -q -x '\.tox/.+' . && From 113a4505fa59ef69672fc8c250fa7821151b41cc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Apr 2019 20:51:30 +0300 Subject: [PATCH 004/295] Docs(Authors): Add Markus Elfring [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 92f936ea..65834b4c 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -37,6 +37,7 @@ Contributions have been made by: * Shailesh Mungikar * Michael S. Root * Scott Stahl +* Markus Elfring * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From c3f99e59301513e39f53b4e1b2b3c8c30e18ad78 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 Apr 2019 19:08:05 +0300 Subject: [PATCH 005/295] Feat: Remove RdbhostConnection David Keeney and rdbhost seem to be unavailable since 2017. [skip ci] --- README.rst | 2 +- docs/Authors.rst | 1 - docs/News.rst | 3 + .../sqlobject.rdbhost.rdbhostconnection.rst | 7 --- docs/api/sqlobject.rdbhost.rst | 15 ----- setup.py | 4 +- sqlobject/.coveragerc | 1 - sqlobject/conftest.py | 1 - sqlobject/converters.py | 8 +-- sqlobject/dbconnection.py | 1 - sqlobject/rdbhost/__init__.py | 8 --- sqlobject/rdbhost/rdbhostconnection.py | 61 ------------------- sqlobject/sqlbuilder.py | 3 +- sqlobject/tests/dbtest.py | 4 +- sqlobject/tests/test_auto.py | 15 +---- 15 files changed, 14 insertions(+), 120 deletions(-) delete mode 100644 docs/api/sqlobject.rdbhost.rdbhostconnection.rst delete mode 100644 docs/api/sqlobject.rdbhost.rst delete mode 100644 sqlobject/rdbhost/__init__.py delete mode 100644 sqlobject/rdbhost/rdbhostconnection.py diff --git a/README.rst b/README.rst index 3e96729c..92962cf6 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ classes, and your rows in Python instances. It currently supports MySQL through the `MySQLdb` package, PostgreSQL through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL, -Sybase and Rdbhost. Python 2.7 or 3.4+ is required. +and Sybase. Python 2.7 or 3.4+ is required. For more information please see the documentation in ``_, or online at http://sqlobject.org/ diff --git a/docs/Authors.rst b/docs/Authors.rst index 65834b4c..9f1c6fe5 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -22,7 +22,6 @@ Contributions have been made by: * Dan Pascu * Diez B. Roggisch * Christopher Singley -* David Keeney * Daniel Fetchinson * Neil Muller * Petr Jakes diff --git a/docs/News.rst b/docs/News.rst index dade2cbf..af4ce644 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,9 @@ Minor features * Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. +* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable + since 2017. + SQLObject 3.7.1 =============== diff --git a/docs/api/sqlobject.rdbhost.rdbhostconnection.rst b/docs/api/sqlobject.rdbhost.rdbhostconnection.rst deleted file mode 100644 index 016d0e66..00000000 --- a/docs/api/sqlobject.rdbhost.rdbhostconnection.rst +++ /dev/null @@ -1,7 +0,0 @@ -sqlobject\.rdbhost\.rdbhostconnection module -============================================ - -.. automodule:: sqlobject.rdbhost.rdbhostconnection - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/api/sqlobject.rdbhost.rst b/docs/api/sqlobject.rdbhost.rst deleted file mode 100644 index c4f57c87..00000000 --- a/docs/api/sqlobject.rdbhost.rst +++ /dev/null @@ -1,15 +0,0 @@ -sqlobject\.rdbhost package -========================== - -.. automodule:: sqlobject.rdbhost - :members: - :undoc-members: - :show-inheritance: - -Submodules ----------- - -.. toctree:: - - sqlobject.rdbhost.rdbhostconnection - diff --git a/setup.py b/setup.py index 9e5a9543..ca58f2eb 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ subpackages = ['firebird', 'include', 'include.tests', 'inheritance', 'inheritance.tests', - 'manager', 'maxdb', 'mysql', 'mssql', 'postgres', 'rdbhost', + 'manager', 'maxdb', 'mysql', 'mssql', 'postgres', 'sqlite', 'sybase', 'tests', 'util', 'versioning', 'versioning.test'] @@ -164,7 +164,7 @@ It currently supports MySQL through the `MySQLdb` package, PostgreSQL through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL -Sybase and Rdbhost. Python 2.7 or 3.4+ is required. +and Sybase. Python 2.7 or 3.4+ is required. Where is SQLObject diff --git a/sqlobject/.coveragerc b/sqlobject/.coveragerc index c49e277b..b4c9dee6 100644 --- a/sqlobject/.coveragerc +++ b/sqlobject/.coveragerc @@ -3,7 +3,6 @@ omit = firebird/*.py maxdb/*.py mssql/*.py - rdbhost/*.py sybase/*.py tests/test_boundattributes.py tests/test_paste.py diff --git a/sqlobject/conftest.py b/sqlobject/conftest.py index af39c6ff..3673168c 100644 --- a/sqlobject/conftest.py +++ b/sqlobject/conftest.py @@ -16,7 +16,6 @@ 'dbm': 'dbm:///data', 'postgres': 'postgres:///test', 'postgresql': 'postgres:///test', - 'rdbhost': 'rdhbost://role:authcode@www.rdbhost.com/', 'pygresql': 'pygresql://localhost/test', 'sqlite': 'sqlite:/:memory:', 'sybase': 'sybase://test:test123@sybase/test?autoCommit=0', diff --git a/sqlobject/converters.py b/sqlobject/converters.py index 5f4a7c93..19b90d07 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -84,14 +84,14 @@ def StringLikeConverter(value, db): elif isinstance(value, buffer_type): value = str(value) - if db in ('mysql', 'postgres', 'rdbhost'): + if db in ('mysql', 'postgres'): for orig, repl in sqlStringReplace: value = value.replace(orig, repl) elif db in ('sqlite', 'firebird', 'sybase', 'maxdb', 'mssql'): value = value.replace("'", "''") else: assert 0, "Database %s unknown" % db - if db in ('postgres', 'rdbhost') and ('\\' in value): + if (db == 'postgres') and ('\\' in value): return "E'%s'" % value return "'%s'" % value @@ -125,7 +125,7 @@ def LongConverter(value, db): def BoolConverter(value, db): - if db in ('postgres', 'rdbhost'): + if db == 'postgres': if value: return "'t'" else: @@ -237,7 +237,7 @@ def sqlrepr(obj, db=None): def quote_str(s, db): - if db in ('postgres', 'rdbhost') and ('\\' in s): + if (db == 'postgres') and ('\\' in s): return "E'%s'" % s return "'%s'" % s diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 8e096391..0b9fd02d 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -1124,6 +1124,5 @@ def dbConnectionForScheme(self, scheme): from . import mssql # noqa from . import mysql # noqa from . import postgres # noqa -from . import rdbhost # noqa from . import sqlite # noqa from . import sybase # noqa diff --git a/sqlobject/rdbhost/__init__.py b/sqlobject/rdbhost/__init__.py deleted file mode 100644 index 588c6a84..00000000 --- a/sqlobject/rdbhost/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from sqlobject.dbconnection import registerConnection - - -def builder(): - from . import rdbhostconnection - return rdbhostconnection.RdbhostConnection - -registerConnection(['rdbhost'], builder) diff --git a/sqlobject/rdbhost/rdbhostconnection.py b/sqlobject/rdbhost/rdbhostconnection.py deleted file mode 100644 index 25200e90..00000000 --- a/sqlobject/rdbhost/rdbhostconnection.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -This module written by David Keeney, 2009, 2010 - -Released under the LGPL for use with the SQLObject ORM library. -""" - -from sqlobject.dbconnection import DBAPI -from sqlobject.postgres.pgconnection import PostgresConnection - - -class RdbhostConnection(PostgresConnection): - - supportTransactions = False - dbName = 'rdbhost' - schemes = [dbName] - - def __init__(self, dsn=None, host=None, port=None, db=None, - user=None, password=None, unicodeCols=False, **kw): - from rdbhdb import rdbhdb as rdb - # monkey patch % escaping into Cursor._execute - old_execute = getattr(rdb.Cursor, '_execute') - setattr(rdb.Cursor, '_old_execute', old_execute) - - def _execute(self, query, *args): - assert not any([a for a in args]) - query = query.replace('%', '%%') - self._old_execute(query, (), (), ()) - setattr(rdb.Cursor, '_execute', _execute) - - self.module = rdb - self.user = user - self.host = host - self.port = port - self.db = db - self.password = password - self.dsn_dict = dsn_dict = {} - self.use_dsn = dsn is not None - if host: - dsn_dict["host"] = host - if user: - dsn_dict["role"] = user - if password: - dsn_dict["authcode"] = password - if dsn is None: - dsn = [] - if db: - dsn.append('dbname=%s' % db) - if user: - dsn.append('user=%s' % user) - if password: - dsn.append('password=%s' % password) - if host: - dsn.append('host=%s' % host) - if port: - dsn.append('port=%d' % port) - dsn = ' '.join(dsn) - self.dsn = dsn - self.unicodeCols = unicodeCols - self.schema = kw.pop('schema', None) - self.dbEncoding = 'utf-8' - DBAPI.__init__(self, **kw) diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 5178c73d..cc6696b5 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -1092,7 +1092,7 @@ def __sqlrepr__(self, db): def _quote_like_special(s, db): - if db in ('postgres', 'rdbhost'): + if db == 'postgres': escape = r'\\' else: escape = '\\' @@ -1433,7 +1433,6 @@ class RLIKE(LIKE): 'maxdb': 'RLIKE', 'mysql': 'RLIKE', 'postgres': '~', - 'rdbhost': '~', 'sqlite': 'REGEXP' } diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index b1cf6e4b..6c0c8463 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -33,7 +33,7 @@ def test_featureX(): pytest.skip("Doesn't support featureX") """ supportsMatrix = { - '-blobData': 'mssql rdbhost', + '-blobData': 'mssql', '-decimalColumn': 'mssql', '-dropTableCascade': 'sybase mssql mysql', '-emptyTable': 'mssql', @@ -43,7 +43,7 @@ def test_featureX(): '+memorydb': 'sqlite', '+rlike': 'mysql postgres sqlite', '+schema': 'postgres', - '-transactions': 'mysql rdbhost', + '-transactions': 'mysql', } diff --git a/sqlobject/tests/test_auto.py b/sqlobject/tests/test_auto.py index 1b66821e..ee4967ab 100644 --- a/sqlobject/tests/test_auto.py +++ b/sqlobject/tests/test_auto.py @@ -117,19 +117,6 @@ class TestAuto: ) """ - rdbhostCreate = """ - CREATE TABLE auto_test ( - auto_id SERIAL PRIMARY KEY, - first_name VARCHAR(100), - last_name VARCHAR(200) NOT NULL, - age INT DEFAULT 0, - created VARCHAR(40) NOT NULL, - happy char(1) DEFAULT 'Y' NOT NULL, - long_field TEXT, - wannahavefun BOOL DEFAULT FALSE NOT NULL - ) - """ - sqliteCreate = """ CREATE TABLE auto_test ( auto_id INTEGER PRIMARY KEY AUTOINCREMENT , @@ -177,7 +164,7 @@ class TestAuto: DROP TABLE auto_test """ - sqliteDrop = sybaseDrop = mssqlDrop = rdbhostDrop = postgresDrop + sqliteDrop = sybaseDrop = mssqlDrop = postgresDrop def setup_method(self, meth): conn = getConnection() From b2b8dcffb2123e1cdffd87602e8a533321db23e2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 29 Apr 2019 19:11:38 +0300 Subject: [PATCH 006/295] Docs(API): Regenerate API docs [skip ci] --- docs/api/sqlobject.boundattributes.rst | 4 ++-- docs/api/sqlobject.cache.rst | 4 ++-- docs/api/sqlobject.classregistry.rst | 4 ++-- docs/api/sqlobject.col.rst | 4 ++-- docs/api/sqlobject.compat.rst | 4 ++-- docs/api/sqlobject.conftest.rst | 4 ++-- docs/api/sqlobject.constraints.rst | 4 ++-- docs/api/sqlobject.converters.rst | 4 ++-- docs/api/sqlobject.dbconnection.rst | 4 ++-- docs/api/sqlobject.dberrors.rst | 4 ++-- docs/api/sqlobject.declarative.rst | 4 ++-- docs/api/sqlobject.events.rst | 4 ++-- docs/api/sqlobject.firebird.firebirdconnection.rst | 4 ++-- docs/api/sqlobject.firebird.rst | 4 ++-- docs/api/sqlobject.include.hashcol.rst | 4 ++-- docs/api/sqlobject.include.rst | 4 ++-- docs/api/sqlobject.include.tests.rst | 4 ++-- docs/api/sqlobject.include.tests.test_hashcol.rst | 5 ++--- docs/api/sqlobject.index.rst | 4 ++-- docs/api/sqlobject.inheritance.iteration.rst | 4 ++-- docs/api/sqlobject.inheritance.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.rst | 4 ++-- docs/api/sqlobject.inheritance.tests.test_aggregates.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_asdict.rst | 5 ++--- .../sqlobject.inheritance.tests.test_deep_inheritance.rst | 5 ++--- .../sqlobject.inheritance.tests.test_destroy_cascade.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_foreignKey.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_indexes.rst | 5 ++--- docs/api/sqlobject.inheritance.tests.test_inheritance.rst | 5 ++--- .../sqlobject.inheritance.tests.test_inheritance_tree.rst | 5 ++--- docs/api/sqlobject.joins.rst | 4 ++-- docs/api/sqlobject.main.rst | 4 ++-- docs/api/sqlobject.manager.command.rst | 5 ++--- docs/api/sqlobject.manager.rst | 4 ++-- docs/api/sqlobject.maxdb.maxdbconnection.rst | 4 ++-- docs/api/sqlobject.maxdb.rst | 4 ++-- docs/api/sqlobject.mssql.mssqlconnection.rst | 4 ++-- docs/api/sqlobject.mssql.rst | 4 ++-- docs/api/sqlobject.mysql.mysqlconnection.rst | 4 ++-- docs/api/sqlobject.mysql.rst | 4 ++-- docs/api/sqlobject.postgres.pgconnection.rst | 4 ++-- docs/api/sqlobject.postgres.rst | 4 ++-- docs/api/sqlobject.rst | 1 - docs/api/sqlobject.sqlbuilder.rst | 4 ++-- docs/api/sqlobject.sqlite.rst | 4 ++-- docs/api/sqlobject.sqlite.sqliteconnection.rst | 4 ++-- docs/api/sqlobject.sresults.rst | 4 ++-- docs/api/sqlobject.styles.rst | 4 ++-- docs/api/sqlobject.sybase.rst | 4 ++-- docs/api/sqlobject.sybase.sybaseconnection.rst | 4 ++-- docs/api/sqlobject.tests.dbtest.rst | 4 ++-- docs/api/sqlobject.tests.rst | 5 +++-- docs/api/sqlobject.tests.test_ForeignKey.rst | 5 ++--- docs/api/sqlobject.tests.test_NoneValuedResultItem.rst | 5 ++--- docs/api/sqlobject.tests.test_SQLMultipleJoin.rst | 5 ++--- docs/api/sqlobject.tests.test_SQLRelatedJoin.rst | 5 ++--- docs/api/sqlobject.tests.test_SingleJoin.rst | 5 ++--- docs/api/sqlobject.tests.test_aggregates.rst | 5 ++--- docs/api/sqlobject.tests.test_aliases.rst | 5 ++--- docs/api/sqlobject.tests.test_asdict.rst | 5 ++--- docs/api/sqlobject.tests.test_auto.rst | 5 ++--- docs/api/sqlobject.tests.test_basic.rst | 5 ++--- docs/api/sqlobject.tests.test_blob.rst | 5 ++--- docs/api/sqlobject.tests.test_boundattributes.rst | 4 ++-- docs/api/sqlobject.tests.test_cache.rst | 5 ++--- docs/api/sqlobject.tests.test_class_hash.rst | 5 ++--- docs/api/sqlobject.tests.test_columns_order.rst | 5 ++--- docs/api/sqlobject.tests.test_combining_joins.rst | 5 ++--- docs/api/sqlobject.tests.test_comparison.rst | 4 ++-- docs/api/sqlobject.tests.test_compat.rst | 7 +++++++ docs/api/sqlobject.tests.test_complex_sorting.rst | 5 ++--- docs/api/sqlobject.tests.test_constraints.rst | 4 ++-- docs/api/sqlobject.tests.test_converters.rst | 4 ++-- docs/api/sqlobject.tests.test_create_drop.rst | 5 ++--- docs/api/sqlobject.tests.test_csvexport.rst | 5 ++--- docs/api/sqlobject.tests.test_csvimport.rst | 4 ++-- docs/api/sqlobject.tests.test_cyclic_reference.rst | 5 ++--- docs/api/sqlobject.tests.test_datetime.rst | 5 ++--- docs/api/sqlobject.tests.test_decimal.rst | 5 ++--- docs/api/sqlobject.tests.test_declarative.rst | 4 ++-- docs/api/sqlobject.tests.test_default_style.rst | 4 ++-- docs/api/sqlobject.tests.test_delete.rst | 5 ++--- docs/api/sqlobject.tests.test_distinct.rst | 5 ++--- docs/api/sqlobject.tests.test_empty.rst | 4 ++-- docs/api/sqlobject.tests.test_enum.rst | 5 ++--- docs/api/sqlobject.tests.test_events.rst | 5 ++--- docs/api/sqlobject.tests.test_exceptions.rst | 5 ++--- docs/api/sqlobject.tests.test_expire.rst | 5 ++--- docs/api/sqlobject.tests.test_groupBy.rst | 5 ++--- docs/api/sqlobject.tests.test_identity.rst | 5 ++--- docs/api/sqlobject.tests.test_indexes.rst | 5 ++--- docs/api/sqlobject.tests.test_inheritance.rst | 5 ++--- docs/api/sqlobject.tests.test_joins.rst | 5 ++--- docs/api/sqlobject.tests.test_joins_conditional.rst | 5 ++--- docs/api/sqlobject.tests.test_jsonbcol.rst | 5 ++--- docs/api/sqlobject.tests.test_jsoncol.rst | 5 ++--- docs/api/sqlobject.tests.test_lazy.rst | 5 ++--- docs/api/sqlobject.tests.test_md5.rst | 4 ++-- docs/api/sqlobject.tests.test_mysql.rst | 4 ++-- docs/api/sqlobject.tests.test_new_joins.rst | 5 ++--- docs/api/sqlobject.tests.test_parse_uri.rst | 4 ++-- docs/api/sqlobject.tests.test_paste.rst | 5 ++--- docs/api/sqlobject.tests.test_perConnection.rst | 5 ++--- docs/api/sqlobject.tests.test_pickle.rst | 5 ++--- docs/api/sqlobject.tests.test_picklecol.rst | 5 ++--- docs/api/sqlobject.tests.test_postgres.rst | 5 ++--- docs/api/sqlobject.tests.test_reparent_sqlmeta.rst | 5 ++--- docs/api/sqlobject.tests.test_schema.rst | 5 ++--- docs/api/sqlobject.tests.test_select.rst | 5 ++--- docs/api/sqlobject.tests.test_select_through.rst | 5 ++--- docs/api/sqlobject.tests.test_setters.rst | 5 ++--- docs/api/sqlobject.tests.test_slice.rst | 5 ++--- docs/api/sqlobject.tests.test_sorting.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlbuilder.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst | 4 ++-- .../sqlobject.tests.test_sqlbuilder_joins_instances.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlite.rst | 5 ++--- docs/api/sqlobject.tests.test_sqlmeta_idName.rst | 4 ++-- docs/api/sqlobject.tests.test_sqlobject_admin.rst | 5 ++--- docs/api/sqlobject.tests.test_string_id.rst | 5 ++--- docs/api/sqlobject.tests.test_style.rst | 5 ++--- docs/api/sqlobject.tests.test_subqueries.rst | 5 ++--- docs/api/sqlobject.tests.test_transactions.rst | 5 ++--- docs/api/sqlobject.tests.test_unicode.rst | 5 ++--- docs/api/sqlobject.tests.test_uuidcol.rst | 5 ++--- docs/api/sqlobject.tests.test_validation.rst | 5 ++--- docs/api/sqlobject.tests.test_views.rst | 5 ++--- docs/api/sqlobject.util.csvexport.rst | 4 ++-- docs/api/sqlobject.util.csvimport.rst | 4 ++-- docs/api/sqlobject.util.moduleloader.rst | 4 ++-- docs/api/sqlobject.util.rst | 4 ++-- docs/api/sqlobject.util.threadinglocal.rst | 4 ++-- docs/api/sqlobject.versioning.rst | 4 ++-- docs/api/sqlobject.versioning.test.rst | 4 ++-- docs/api/sqlobject.versioning.test.test_version.rst | 5 ++--- docs/api/sqlobject.views.rst | 4 ++-- docs/api/sqlobject.wsgi_middleware.rst | 4 ++-- 138 files changed, 280 insertions(+), 346 deletions(-) create mode 100644 docs/api/sqlobject.tests.test_compat.rst diff --git a/docs/api/sqlobject.boundattributes.rst b/docs/api/sqlobject.boundattributes.rst index ebc0ab5a..1518f8da 100644 --- a/docs/api/sqlobject.boundattributes.rst +++ b/docs/api/sqlobject.boundattributes.rst @@ -1,5 +1,5 @@ -sqlobject\.boundattributes module -================================= +sqlobject.boundattributes module +================================ .. automodule:: sqlobject.boundattributes :members: diff --git a/docs/api/sqlobject.cache.rst b/docs/api/sqlobject.cache.rst index 657e1e86..6c74d5be 100644 --- a/docs/api/sqlobject.cache.rst +++ b/docs/api/sqlobject.cache.rst @@ -1,5 +1,5 @@ -sqlobject\.cache module -======================= +sqlobject.cache module +====================== .. automodule:: sqlobject.cache :members: diff --git a/docs/api/sqlobject.classregistry.rst b/docs/api/sqlobject.classregistry.rst index 80ed01a7..08824917 100644 --- a/docs/api/sqlobject.classregistry.rst +++ b/docs/api/sqlobject.classregistry.rst @@ -1,5 +1,5 @@ -sqlobject\.classregistry module -=============================== +sqlobject.classregistry module +============================== .. automodule:: sqlobject.classregistry :members: diff --git a/docs/api/sqlobject.col.rst b/docs/api/sqlobject.col.rst index 4c649dc9..5282fc2f 100644 --- a/docs/api/sqlobject.col.rst +++ b/docs/api/sqlobject.col.rst @@ -1,5 +1,5 @@ -sqlobject\.col module -===================== +sqlobject.col module +==================== .. automodule:: sqlobject.col :members: diff --git a/docs/api/sqlobject.compat.rst b/docs/api/sqlobject.compat.rst index 4191c0cf..cdb4f6dd 100644 --- a/docs/api/sqlobject.compat.rst +++ b/docs/api/sqlobject.compat.rst @@ -1,5 +1,5 @@ -sqlobject\.compat module -======================== +sqlobject.compat module +======================= .. automodule:: sqlobject.compat :members: diff --git a/docs/api/sqlobject.conftest.rst b/docs/api/sqlobject.conftest.rst index e29d059d..8e564281 100644 --- a/docs/api/sqlobject.conftest.rst +++ b/docs/api/sqlobject.conftest.rst @@ -1,5 +1,5 @@ -sqlobject\.conftest module -========================== +sqlobject.conftest module +========================= .. automodule:: sqlobject.conftest :members: diff --git a/docs/api/sqlobject.constraints.rst b/docs/api/sqlobject.constraints.rst index 88a736b3..ad39272b 100644 --- a/docs/api/sqlobject.constraints.rst +++ b/docs/api/sqlobject.constraints.rst @@ -1,5 +1,5 @@ -sqlobject\.constraints module -============================= +sqlobject.constraints module +============================ .. automodule:: sqlobject.constraints :members: diff --git a/docs/api/sqlobject.converters.rst b/docs/api/sqlobject.converters.rst index 38f7777f..82b5cff7 100644 --- a/docs/api/sqlobject.converters.rst +++ b/docs/api/sqlobject.converters.rst @@ -1,5 +1,5 @@ -sqlobject\.converters module -============================ +sqlobject.converters module +=========================== .. automodule:: sqlobject.converters :members: diff --git a/docs/api/sqlobject.dbconnection.rst b/docs/api/sqlobject.dbconnection.rst index 6ab39d10..6a6adc35 100644 --- a/docs/api/sqlobject.dbconnection.rst +++ b/docs/api/sqlobject.dbconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.dbconnection module -============================== +sqlobject.dbconnection module +============================= .. automodule:: sqlobject.dbconnection :members: diff --git a/docs/api/sqlobject.dberrors.rst b/docs/api/sqlobject.dberrors.rst index e8be2dbf..3035746a 100644 --- a/docs/api/sqlobject.dberrors.rst +++ b/docs/api/sqlobject.dberrors.rst @@ -1,5 +1,5 @@ -sqlobject\.dberrors module -========================== +sqlobject.dberrors module +========================= .. automodule:: sqlobject.dberrors :members: diff --git a/docs/api/sqlobject.declarative.rst b/docs/api/sqlobject.declarative.rst index f89a88b4..9cc7e9bd 100644 --- a/docs/api/sqlobject.declarative.rst +++ b/docs/api/sqlobject.declarative.rst @@ -1,5 +1,5 @@ -sqlobject\.declarative module -============================= +sqlobject.declarative module +============================ .. automodule:: sqlobject.declarative :members: diff --git a/docs/api/sqlobject.events.rst b/docs/api/sqlobject.events.rst index 18ddcc78..8c33239d 100644 --- a/docs/api/sqlobject.events.rst +++ b/docs/api/sqlobject.events.rst @@ -1,5 +1,5 @@ -sqlobject\.events module -======================== +sqlobject.events module +======================= .. automodule:: sqlobject.events :members: diff --git a/docs/api/sqlobject.firebird.firebirdconnection.rst b/docs/api/sqlobject.firebird.firebirdconnection.rst index e517e981..6fdf26e9 100644 --- a/docs/api/sqlobject.firebird.firebirdconnection.rst +++ b/docs/api/sqlobject.firebird.firebirdconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.firebird\.firebirdconnection module -============================================== +sqlobject.firebird.firebirdconnection module +============================================ .. automodule:: sqlobject.firebird.firebirdconnection :members: diff --git a/docs/api/sqlobject.firebird.rst b/docs/api/sqlobject.firebird.rst index a1f5b0ae..78cec9ae 100644 --- a/docs/api/sqlobject.firebird.rst +++ b/docs/api/sqlobject.firebird.rst @@ -1,5 +1,5 @@ -sqlobject\.firebird package -=========================== +sqlobject.firebird package +========================== .. automodule:: sqlobject.firebird :members: diff --git a/docs/api/sqlobject.include.hashcol.rst b/docs/api/sqlobject.include.hashcol.rst index 7abe8d54..76396aa4 100644 --- a/docs/api/sqlobject.include.hashcol.rst +++ b/docs/api/sqlobject.include.hashcol.rst @@ -1,5 +1,5 @@ -sqlobject\.include\.hashcol module -================================== +sqlobject.include.hashcol module +================================ .. automodule:: sqlobject.include.hashcol :members: diff --git a/docs/api/sqlobject.include.rst b/docs/api/sqlobject.include.rst index aebc9e47..62086bfc 100644 --- a/docs/api/sqlobject.include.rst +++ b/docs/api/sqlobject.include.rst @@ -1,5 +1,5 @@ -sqlobject\.include package -========================== +sqlobject.include package +========================= .. automodule:: sqlobject.include :members: diff --git a/docs/api/sqlobject.include.tests.rst b/docs/api/sqlobject.include.tests.rst index 0bf1f136..e17b4def 100644 --- a/docs/api/sqlobject.include.tests.rst +++ b/docs/api/sqlobject.include.tests.rst @@ -1,5 +1,5 @@ -sqlobject\.include\.tests package -================================= +sqlobject.include.tests package +=============================== .. automodule:: sqlobject.include.tests :members: diff --git a/docs/api/sqlobject.include.tests.test_hashcol.rst b/docs/api/sqlobject.include.tests.test_hashcol.rst index 2ec99027..5289acd7 100644 --- a/docs/api/sqlobject.include.tests.test_hashcol.rst +++ b/docs/api/sqlobject.include.tests.test_hashcol.rst @@ -1,8 +1,7 @@ -sqlobject\.include\.tests\.test\_hashcol module -=============================================== +sqlobject.include.tests.test\_hashcol module +============================================ .. automodule:: sqlobject.include.tests.test_hashcol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.index.rst b/docs/api/sqlobject.index.rst index c2facd02..bc96433c 100644 --- a/docs/api/sqlobject.index.rst +++ b/docs/api/sqlobject.index.rst @@ -1,5 +1,5 @@ -sqlobject\.index module -======================= +sqlobject.index module +====================== .. automodule:: sqlobject.index :members: diff --git a/docs/api/sqlobject.inheritance.iteration.rst b/docs/api/sqlobject.inheritance.iteration.rst index b6318065..0e9538f8 100644 --- a/docs/api/sqlobject.inheritance.iteration.rst +++ b/docs/api/sqlobject.inheritance.iteration.rst @@ -1,5 +1,5 @@ -sqlobject\.inheritance\.iteration module -======================================== +sqlobject.inheritance.iteration module +====================================== .. automodule:: sqlobject.inheritance.iteration :members: diff --git a/docs/api/sqlobject.inheritance.rst b/docs/api/sqlobject.inheritance.rst index 5d9dae4c..7ab19a77 100644 --- a/docs/api/sqlobject.inheritance.rst +++ b/docs/api/sqlobject.inheritance.rst @@ -1,5 +1,5 @@ -sqlobject\.inheritance package -============================== +sqlobject.inheritance package +============================= .. automodule:: sqlobject.inheritance :members: diff --git a/docs/api/sqlobject.inheritance.tests.rst b/docs/api/sqlobject.inheritance.tests.rst index c29cbc40..994c85ab 100644 --- a/docs/api/sqlobject.inheritance.tests.rst +++ b/docs/api/sqlobject.inheritance.tests.rst @@ -1,5 +1,5 @@ -sqlobject\.inheritance\.tests package -===================================== +sqlobject.inheritance.tests package +=================================== .. automodule:: sqlobject.inheritance.tests :members: diff --git a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst index 15fa5afd..58a2944d 100644 --- a/docs/api/sqlobject.inheritance.tests.test_aggregates.rst +++ b/docs/api/sqlobject.inheritance.tests.test_aggregates.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_aggregates module -====================================================== +sqlobject.inheritance.tests.test\_aggregates module +=================================================== .. automodule:: sqlobject.inheritance.tests.test_aggregates :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_asdict.rst b/docs/api/sqlobject.inheritance.tests.test_asdict.rst index c24c5114..6a33dce2 100644 --- a/docs/api/sqlobject.inheritance.tests.test_asdict.rst +++ b/docs/api/sqlobject.inheritance.tests.test_asdict.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_asdict module -================================================== +sqlobject.inheritance.tests.test\_asdict module +=============================================== .. automodule:: sqlobject.inheritance.tests.test_asdict :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst index eb1661dd..5447d0bd 100644 --- a/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_deep_inheritance.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_deep\_inheritance module -============================================================= +sqlobject.inheritance.tests.test\_deep\_inheritance module +========================================================== .. automodule:: sqlobject.inheritance.tests.test_deep_inheritance :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst index 3504fe65..8b9b7069 100644 --- a/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst +++ b/docs/api/sqlobject.inheritance.tests.test_destroy_cascade.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_destroy\_cascade module -============================================================ +sqlobject.inheritance.tests.test\_destroy\_cascade module +========================================================= .. automodule:: sqlobject.inheritance.tests.test_destroy_cascade :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst index b6e28aa5..68059887 100644 --- a/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst +++ b/docs/api/sqlobject.inheritance.tests.test_foreignKey.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_foreignKey module -====================================================== +sqlobject.inheritance.tests.test\_foreignKey module +=================================================== .. automodule:: sqlobject.inheritance.tests.test_foreignKey :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_indexes.rst b/docs/api/sqlobject.inheritance.tests.test_indexes.rst index bb2e3f7b..cda20165 100644 --- a/docs/api/sqlobject.inheritance.tests.test_indexes.rst +++ b/docs/api/sqlobject.inheritance.tests.test_indexes.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_indexes module -=================================================== +sqlobject.inheritance.tests.test\_indexes module +================================================ .. automodule:: sqlobject.inheritance.tests.test_indexes :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,indexDefinitions diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst index 0c186b0a..7af4fc40 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_inheritance module -======================================================= +sqlobject.inheritance.tests.test\_inheritance module +==================================================== .. automodule:: sqlobject.inheritance.tests.test_inheritance :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst index b56d0474..31cea2e6 100644 --- a/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst +++ b/docs/api/sqlobject.inheritance.tests.test_inheritance_tree.rst @@ -1,8 +1,7 @@ -sqlobject\.inheritance\.tests\.test\_inheritance\_tree module -============================================================= +sqlobject.inheritance.tests.test\_inheritance\_tree module +========================================================== .. automodule:: sqlobject.inheritance.tests.test_inheritance_tree :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.joins.rst b/docs/api/sqlobject.joins.rst index c864c429..70e43b04 100644 --- a/docs/api/sqlobject.joins.rst +++ b/docs/api/sqlobject.joins.rst @@ -1,5 +1,5 @@ -sqlobject\.joins module -======================= +sqlobject.joins module +====================== .. automodule:: sqlobject.joins :members: diff --git a/docs/api/sqlobject.main.rst b/docs/api/sqlobject.main.rst index 5f8c4b8e..b4de5566 100644 --- a/docs/api/sqlobject.main.rst +++ b/docs/api/sqlobject.main.rst @@ -1,5 +1,5 @@ -sqlobject\.main module -====================== +sqlobject.main module +===================== .. automodule:: sqlobject.main :members: diff --git a/docs/api/sqlobject.manager.command.rst b/docs/api/sqlobject.manager.command.rst index be4a0073..bae2b682 100644 --- a/docs/api/sqlobject.manager.command.rst +++ b/docs/api/sqlobject.manager.command.rst @@ -1,8 +1,7 @@ -sqlobject\.manager\.command module -================================== +sqlobject.manager.command module +================================ .. automodule:: sqlobject.manager.command :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.manager.rst b/docs/api/sqlobject.manager.rst index 2b3387c6..3a8c8a81 100644 --- a/docs/api/sqlobject.manager.rst +++ b/docs/api/sqlobject.manager.rst @@ -1,5 +1,5 @@ -sqlobject\.manager package -========================== +sqlobject.manager package +========================= .. automodule:: sqlobject.manager :members: diff --git a/docs/api/sqlobject.maxdb.maxdbconnection.rst b/docs/api/sqlobject.maxdb.maxdbconnection.rst index c2cae465..1a6490ea 100644 --- a/docs/api/sqlobject.maxdb.maxdbconnection.rst +++ b/docs/api/sqlobject.maxdb.maxdbconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.maxdb\.maxdbconnection module -======================================== +sqlobject.maxdb.maxdbconnection module +====================================== .. automodule:: sqlobject.maxdb.maxdbconnection :members: diff --git a/docs/api/sqlobject.maxdb.rst b/docs/api/sqlobject.maxdb.rst index 1ca83a35..d591970e 100644 --- a/docs/api/sqlobject.maxdb.rst +++ b/docs/api/sqlobject.maxdb.rst @@ -1,5 +1,5 @@ -sqlobject\.maxdb package -======================== +sqlobject.maxdb package +======================= .. automodule:: sqlobject.maxdb :members: diff --git a/docs/api/sqlobject.mssql.mssqlconnection.rst b/docs/api/sqlobject.mssql.mssqlconnection.rst index d3121122..ffcc0023 100644 --- a/docs/api/sqlobject.mssql.mssqlconnection.rst +++ b/docs/api/sqlobject.mssql.mssqlconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.mssql\.mssqlconnection module -======================================== +sqlobject.mssql.mssqlconnection module +====================================== .. automodule:: sqlobject.mssql.mssqlconnection :members: diff --git a/docs/api/sqlobject.mssql.rst b/docs/api/sqlobject.mssql.rst index 84c45418..7e622693 100644 --- a/docs/api/sqlobject.mssql.rst +++ b/docs/api/sqlobject.mssql.rst @@ -1,5 +1,5 @@ -sqlobject\.mssql package -======================== +sqlobject.mssql package +======================= .. automodule:: sqlobject.mssql :members: diff --git a/docs/api/sqlobject.mysql.mysqlconnection.rst b/docs/api/sqlobject.mysql.mysqlconnection.rst index 224601ef..3e5a9ef8 100644 --- a/docs/api/sqlobject.mysql.mysqlconnection.rst +++ b/docs/api/sqlobject.mysql.mysqlconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.mysql\.mysqlconnection module -======================================== +sqlobject.mysql.mysqlconnection module +====================================== .. automodule:: sqlobject.mysql.mysqlconnection :members: diff --git a/docs/api/sqlobject.mysql.rst b/docs/api/sqlobject.mysql.rst index e244266d..7e69a9e2 100644 --- a/docs/api/sqlobject.mysql.rst +++ b/docs/api/sqlobject.mysql.rst @@ -1,5 +1,5 @@ -sqlobject\.mysql package -======================== +sqlobject.mysql package +======================= .. automodule:: sqlobject.mysql :members: diff --git a/docs/api/sqlobject.postgres.pgconnection.rst b/docs/api/sqlobject.postgres.pgconnection.rst index 3880e511..854104d5 100644 --- a/docs/api/sqlobject.postgres.pgconnection.rst +++ b/docs/api/sqlobject.postgres.pgconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.postgres\.pgconnection module -======================================== +sqlobject.postgres.pgconnection module +====================================== .. automodule:: sqlobject.postgres.pgconnection :members: diff --git a/docs/api/sqlobject.postgres.rst b/docs/api/sqlobject.postgres.rst index 5decb52a..ad93e75d 100644 --- a/docs/api/sqlobject.postgres.rst +++ b/docs/api/sqlobject.postgres.rst @@ -1,5 +1,5 @@ -sqlobject\.postgres package -=========================== +sqlobject.postgres package +========================== .. automodule:: sqlobject.postgres :members: diff --git a/docs/api/sqlobject.rst b/docs/api/sqlobject.rst index 1695715e..2711347b 100644 --- a/docs/api/sqlobject.rst +++ b/docs/api/sqlobject.rst @@ -19,7 +19,6 @@ Subpackages sqlobject.mssql sqlobject.mysql sqlobject.postgres - sqlobject.rdbhost sqlobject.sqlite sqlobject.sybase sqlobject.tests diff --git a/docs/api/sqlobject.sqlbuilder.rst b/docs/api/sqlobject.sqlbuilder.rst index 4c49ca06..bd21c086 100644 --- a/docs/api/sqlobject.sqlbuilder.rst +++ b/docs/api/sqlobject.sqlbuilder.rst @@ -1,5 +1,5 @@ -sqlobject\.sqlbuilder module -============================ +sqlobject.sqlbuilder module +=========================== .. automodule:: sqlobject.sqlbuilder :members: diff --git a/docs/api/sqlobject.sqlite.rst b/docs/api/sqlobject.sqlite.rst index 8afe099e..f62364ef 100644 --- a/docs/api/sqlobject.sqlite.rst +++ b/docs/api/sqlobject.sqlite.rst @@ -1,5 +1,5 @@ -sqlobject\.sqlite package -========================= +sqlobject.sqlite package +======================== .. automodule:: sqlobject.sqlite :members: diff --git a/docs/api/sqlobject.sqlite.sqliteconnection.rst b/docs/api/sqlobject.sqlite.sqliteconnection.rst index 37e64745..0ce1763a 100644 --- a/docs/api/sqlobject.sqlite.sqliteconnection.rst +++ b/docs/api/sqlobject.sqlite.sqliteconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.sqlite\.sqliteconnection module -========================================== +sqlobject.sqlite.sqliteconnection module +======================================== .. automodule:: sqlobject.sqlite.sqliteconnection :members: diff --git a/docs/api/sqlobject.sresults.rst b/docs/api/sqlobject.sresults.rst index 7b18b85f..690de42e 100644 --- a/docs/api/sqlobject.sresults.rst +++ b/docs/api/sqlobject.sresults.rst @@ -1,5 +1,5 @@ -sqlobject\.sresults module -========================== +sqlobject.sresults module +========================= .. automodule:: sqlobject.sresults :members: diff --git a/docs/api/sqlobject.styles.rst b/docs/api/sqlobject.styles.rst index f5238168..04aeb8c8 100644 --- a/docs/api/sqlobject.styles.rst +++ b/docs/api/sqlobject.styles.rst @@ -1,5 +1,5 @@ -sqlobject\.styles module -======================== +sqlobject.styles module +======================= .. automodule:: sqlobject.styles :members: diff --git a/docs/api/sqlobject.sybase.rst b/docs/api/sqlobject.sybase.rst index 84e1fc2a..b5d5aef8 100644 --- a/docs/api/sqlobject.sybase.rst +++ b/docs/api/sqlobject.sybase.rst @@ -1,5 +1,5 @@ -sqlobject\.sybase package -========================= +sqlobject.sybase package +======================== .. automodule:: sqlobject.sybase :members: diff --git a/docs/api/sqlobject.sybase.sybaseconnection.rst b/docs/api/sqlobject.sybase.sybaseconnection.rst index b684c94a..3cdf4c02 100644 --- a/docs/api/sqlobject.sybase.sybaseconnection.rst +++ b/docs/api/sqlobject.sybase.sybaseconnection.rst @@ -1,5 +1,5 @@ -sqlobject\.sybase\.sybaseconnection module -========================================== +sqlobject.sybase.sybaseconnection module +======================================== .. automodule:: sqlobject.sybase.sybaseconnection :members: diff --git a/docs/api/sqlobject.tests.dbtest.rst b/docs/api/sqlobject.tests.dbtest.rst index 617ef7f7..b6fb5132 100644 --- a/docs/api/sqlobject.tests.dbtest.rst +++ b/docs/api/sqlobject.tests.dbtest.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.dbtest module -=============================== +sqlobject.tests.dbtest module +============================= .. automodule:: sqlobject.tests.dbtest :members: diff --git a/docs/api/sqlobject.tests.rst b/docs/api/sqlobject.tests.rst index e7a409ce..6cf2f130 100644 --- a/docs/api/sqlobject.tests.rst +++ b/docs/api/sqlobject.tests.rst @@ -1,5 +1,5 @@ -sqlobject\.tests package -======================== +sqlobject.tests package +======================= .. automodule:: sqlobject.tests :members: @@ -29,6 +29,7 @@ Submodules sqlobject.tests.test_columns_order sqlobject.tests.test_combining_joins sqlobject.tests.test_comparison + sqlobject.tests.test_compat sqlobject.tests.test_complex_sorting sqlobject.tests.test_constraints sqlobject.tests.test_converters diff --git a/docs/api/sqlobject.tests.test_ForeignKey.rst b/docs/api/sqlobject.tests.test_ForeignKey.rst index 1ca6c9d7..c495f8b9 100644 --- a/docs/api/sqlobject.tests.test_ForeignKey.rst +++ b/docs/api/sqlobject.tests.test_ForeignKey.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_ForeignKey module -========================================= +sqlobject.tests.test\_ForeignKey module +======================================= .. automodule:: sqlobject.tests.test_ForeignKey :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst index bac55967..35ee6435 100644 --- a/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst +++ b/docs/api/sqlobject.tests.test_NoneValuedResultItem.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_NoneValuedResultItem module -=================================================== +sqlobject.tests.test\_NoneValuedResultItem module +================================================= .. automodule:: sqlobject.tests.test_NoneValuedResultItem :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst index a7473fbd..7ae46d52 100644 --- a/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLMultipleJoin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_SQLMultipleJoin module -============================================== +sqlobject.tests.test\_SQLMultipleJoin module +============================================ .. automodule:: sqlobject.tests.test_SQLMultipleJoin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst index e1813011..e12f1f55 100644 --- a/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst +++ b/docs/api/sqlobject.tests.test_SQLRelatedJoin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_SQLRelatedJoin module -============================================= +sqlobject.tests.test\_SQLRelatedJoin module +=========================================== .. automodule:: sqlobject.tests.test_SQLRelatedJoin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_SingleJoin.rst b/docs/api/sqlobject.tests.test_SingleJoin.rst index 7f4179da..80f8907c 100644 --- a/docs/api/sqlobject.tests.test_SingleJoin.rst +++ b/docs/api/sqlobject.tests.test_SingleJoin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_SingleJoin module -========================================= +sqlobject.tests.test\_SingleJoin module +======================================= .. automodule:: sqlobject.tests.test_SingleJoin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_aggregates.rst b/docs/api/sqlobject.tests.test_aggregates.rst index 117aadde..283cea6f 100644 --- a/docs/api/sqlobject.tests.test_aggregates.rst +++ b/docs/api/sqlobject.tests.test_aggregates.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_aggregates module -========================================= +sqlobject.tests.test\_aggregates module +======================================= .. automodule:: sqlobject.tests.test_aggregates :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_aliases.rst b/docs/api/sqlobject.tests.test_aliases.rst index d96edd13..fa46a461 100644 --- a/docs/api/sqlobject.tests.test_aliases.rst +++ b/docs/api/sqlobject.tests.test_aliases.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_aliases module -====================================== +sqlobject.tests.test\_aliases module +==================================== .. automodule:: sqlobject.tests.test_aliases :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_asdict.rst b/docs/api/sqlobject.tests.test_asdict.rst index b316c7ef..e1550441 100644 --- a/docs/api/sqlobject.tests.test_asdict.rst +++ b/docs/api/sqlobject.tests.test_asdict.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_asdict module -===================================== +sqlobject.tests.test\_asdict module +=================================== .. automodule:: sqlobject.tests.test_asdict :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_auto.rst b/docs/api/sqlobject.tests.test_auto.rst index 9c23284c..6d578d5e 100644 --- a/docs/api/sqlobject.tests.test_auto.rst +++ b/docs/api/sqlobject.tests.test_auto.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_auto module -=================================== +sqlobject.tests.test\_auto module +================================= .. automodule:: sqlobject.tests.test_auto :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_basic.rst b/docs/api/sqlobject.tests.test_basic.rst index 549436dd..40235ecf 100644 --- a/docs/api/sqlobject.tests.test_basic.rst +++ b/docs/api/sqlobject.tests.test_basic.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_basic module -==================================== +sqlobject.tests.test\_basic module +================================== .. automodule:: sqlobject.tests.test_basic :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_blob.rst b/docs/api/sqlobject.tests.test_blob.rst index 798a66c0..1d01d512 100644 --- a/docs/api/sqlobject.tests.test_blob.rst +++ b/docs/api/sqlobject.tests.test_blob.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_blob module -=================================== +sqlobject.tests.test\_blob module +================================= .. automodule:: sqlobject.tests.test_blob :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_boundattributes.rst b/docs/api/sqlobject.tests.test_boundattributes.rst index ec672dfb..47d9e2b1 100644 --- a/docs/api/sqlobject.tests.test_boundattributes.rst +++ b/docs/api/sqlobject.tests.test_boundattributes.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_boundattributes module -============================================== +sqlobject.tests.test\_boundattributes module +============================================ .. automodule:: sqlobject.tests.test_boundattributes :members: diff --git a/docs/api/sqlobject.tests.test_cache.rst b/docs/api/sqlobject.tests.test_cache.rst index 3e01991e..69f05823 100644 --- a/docs/api/sqlobject.tests.test_cache.rst +++ b/docs/api/sqlobject.tests.test_cache.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_cache module -==================================== +sqlobject.tests.test\_cache module +================================== .. automodule:: sqlobject.tests.test_cache :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_class_hash.rst b/docs/api/sqlobject.tests.test_class_hash.rst index 076937ab..f25b66b6 100644 --- a/docs/api/sqlobject.tests.test_class_hash.rst +++ b/docs/api/sqlobject.tests.test_class_hash.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_class\_hash module -========================================== +sqlobject.tests.test\_class\_hash module +======================================== .. automodule:: sqlobject.tests.test_class_hash :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_columns_order.rst b/docs/api/sqlobject.tests.test_columns_order.rst index 6187c32d..c48cf7c0 100644 --- a/docs/api/sqlobject.tests.test_columns_order.rst +++ b/docs/api/sqlobject.tests.test_columns_order.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_columns\_order module -============================================= +sqlobject.tests.test\_columns\_order module +=========================================== .. automodule:: sqlobject.tests.test_columns_order :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_combining_joins.rst b/docs/api/sqlobject.tests.test_combining_joins.rst index 7b30db09..e1961a80 100644 --- a/docs/api/sqlobject.tests.test_combining_joins.rst +++ b/docs/api/sqlobject.tests.test_combining_joins.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_combining\_joins module -=============================================== +sqlobject.tests.test\_combining\_joins module +============================================= .. automodule:: sqlobject.tests.test_combining_joins :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_comparison.rst b/docs/api/sqlobject.tests.test_comparison.rst index e54aacc3..02127b7b 100644 --- a/docs/api/sqlobject.tests.test_comparison.rst +++ b/docs/api/sqlobject.tests.test_comparison.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_comparison module -========================================= +sqlobject.tests.test\_comparison module +======================================= .. automodule:: sqlobject.tests.test_comparison :members: diff --git a/docs/api/sqlobject.tests.test_compat.rst b/docs/api/sqlobject.tests.test_compat.rst new file mode 100644 index 00000000..e37cb543 --- /dev/null +++ b/docs/api/sqlobject.tests.test_compat.rst @@ -0,0 +1,7 @@ +sqlobject.tests.test\_compat module +=================================== + +.. automodule:: sqlobject.tests.test_compat + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/api/sqlobject.tests.test_complex_sorting.rst b/docs/api/sqlobject.tests.test_complex_sorting.rst index 570fe23c..2321e963 100644 --- a/docs/api/sqlobject.tests.test_complex_sorting.rst +++ b/docs/api/sqlobject.tests.test_complex_sorting.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_complex\_sorting module -=============================================== +sqlobject.tests.test\_complex\_sorting module +============================================= .. automodule:: sqlobject.tests.test_complex_sorting :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_constraints.rst b/docs/api/sqlobject.tests.test_constraints.rst index d3521779..c967979b 100644 --- a/docs/api/sqlobject.tests.test_constraints.rst +++ b/docs/api/sqlobject.tests.test_constraints.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_constraints module -========================================== +sqlobject.tests.test\_constraints module +======================================== .. automodule:: sqlobject.tests.test_constraints :members: diff --git a/docs/api/sqlobject.tests.test_converters.rst b/docs/api/sqlobject.tests.test_converters.rst index 4548363b..a6893bda 100644 --- a/docs/api/sqlobject.tests.test_converters.rst +++ b/docs/api/sqlobject.tests.test_converters.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_converters module -========================================= +sqlobject.tests.test\_converters module +======================================= .. automodule:: sqlobject.tests.test_converters :members: diff --git a/docs/api/sqlobject.tests.test_create_drop.rst b/docs/api/sqlobject.tests.test_create_drop.rst index d7845b9b..fcd3eea5 100644 --- a/docs/api/sqlobject.tests.test_create_drop.rst +++ b/docs/api/sqlobject.tests.test_create_drop.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_create\_drop module -=========================================== +sqlobject.tests.test\_create\_drop module +========================================= .. automodule:: sqlobject.tests.test_create_drop :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_csvexport.rst b/docs/api/sqlobject.tests.test_csvexport.rst index 2935f61d..0927f4f0 100644 --- a/docs/api/sqlobject.tests.test_csvexport.rst +++ b/docs/api/sqlobject.tests.test_csvexport.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_csvexport module -======================================== +sqlobject.tests.test\_csvexport module +====================================== .. automodule:: sqlobject.tests.test_csvexport :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_csvimport.rst b/docs/api/sqlobject.tests.test_csvimport.rst index 56981a8d..f7db4138 100644 --- a/docs/api/sqlobject.tests.test_csvimport.rst +++ b/docs/api/sqlobject.tests.test_csvimport.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_csvimport module -======================================== +sqlobject.tests.test\_csvimport module +====================================== .. automodule:: sqlobject.tests.test_csvimport :members: diff --git a/docs/api/sqlobject.tests.test_cyclic_reference.rst b/docs/api/sqlobject.tests.test_cyclic_reference.rst index 1cb34572..910421ab 100644 --- a/docs/api/sqlobject.tests.test_cyclic_reference.rst +++ b/docs/api/sqlobject.tests.test_cyclic_reference.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_cyclic\_reference module -================================================ +sqlobject.tests.test\_cyclic\_reference module +============================================== .. automodule:: sqlobject.tests.test_cyclic_reference :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_datetime.rst b/docs/api/sqlobject.tests.test_datetime.rst index b6b42358..87a1b043 100644 --- a/docs/api/sqlobject.tests.test_datetime.rst +++ b/docs/api/sqlobject.tests.test_datetime.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_datetime module -======================================= +sqlobject.tests.test\_datetime module +===================================== .. automodule:: sqlobject.tests.test_datetime :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_decimal.rst b/docs/api/sqlobject.tests.test_decimal.rst index 9e680e3a..86868120 100644 --- a/docs/api/sqlobject.tests.test_decimal.rst +++ b/docs/api/sqlobject.tests.test_decimal.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_decimal module -====================================== +sqlobject.tests.test\_decimal module +==================================== .. automodule:: sqlobject.tests.test_decimal :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_declarative.rst b/docs/api/sqlobject.tests.test_declarative.rst index 097a81fc..a022b0cc 100644 --- a/docs/api/sqlobject.tests.test_declarative.rst +++ b/docs/api/sqlobject.tests.test_declarative.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_declarative module -========================================== +sqlobject.tests.test\_declarative module +======================================== .. automodule:: sqlobject.tests.test_declarative :members: diff --git a/docs/api/sqlobject.tests.test_default_style.rst b/docs/api/sqlobject.tests.test_default_style.rst index 50868333..5cd86ffe 100644 --- a/docs/api/sqlobject.tests.test_default_style.rst +++ b/docs/api/sqlobject.tests.test_default_style.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_default\_style module -============================================= +sqlobject.tests.test\_default\_style module +=========================================== .. automodule:: sqlobject.tests.test_default_style :members: diff --git a/docs/api/sqlobject.tests.test_delete.rst b/docs/api/sqlobject.tests.test_delete.rst index 8ee8eb76..508cc86a 100644 --- a/docs/api/sqlobject.tests.test_delete.rst +++ b/docs/api/sqlobject.tests.test_delete.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_delete module -===================================== +sqlobject.tests.test\_delete module +=================================== .. automodule:: sqlobject.tests.test_delete :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_distinct.rst b/docs/api/sqlobject.tests.test_distinct.rst index 5b2b72c6..68080aa3 100644 --- a/docs/api/sqlobject.tests.test_distinct.rst +++ b/docs/api/sqlobject.tests.test_distinct.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_distinct module -======================================= +sqlobject.tests.test\_distinct module +===================================== .. automodule:: sqlobject.tests.test_distinct :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_empty.rst b/docs/api/sqlobject.tests.test_empty.rst index 111994c7..69964d49 100644 --- a/docs/api/sqlobject.tests.test_empty.rst +++ b/docs/api/sqlobject.tests.test_empty.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_empty module -==================================== +sqlobject.tests.test\_empty module +================================== .. automodule:: sqlobject.tests.test_empty :members: diff --git a/docs/api/sqlobject.tests.test_enum.rst b/docs/api/sqlobject.tests.test_enum.rst index c5c5a0f1..0ae9e483 100644 --- a/docs/api/sqlobject.tests.test_enum.rst +++ b/docs/api/sqlobject.tests.test_enum.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_enum module -=================================== +sqlobject.tests.test\_enum module +================================= .. automodule:: sqlobject.tests.test_enum :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_events.rst b/docs/api/sqlobject.tests.test_events.rst index 78c7b839..7c1b9ef8 100644 --- a/docs/api/sqlobject.tests.test_events.rst +++ b/docs/api/sqlobject.tests.test_events.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_events module -===================================== +sqlobject.tests.test\_events module +=================================== .. automodule:: sqlobject.tests.test_events :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_exceptions.rst b/docs/api/sqlobject.tests.test_exceptions.rst index 45d09fd2..5e440e43 100644 --- a/docs/api/sqlobject.tests.test_exceptions.rst +++ b/docs/api/sqlobject.tests.test_exceptions.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_exceptions module -========================================= +sqlobject.tests.test\_exceptions module +======================================= .. automodule:: sqlobject.tests.test_exceptions :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_expire.rst b/docs/api/sqlobject.tests.test_expire.rst index 26b81f54..614f06ce 100644 --- a/docs/api/sqlobject.tests.test_expire.rst +++ b/docs/api/sqlobject.tests.test_expire.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_expire module -===================================== +sqlobject.tests.test\_expire module +=================================== .. automodule:: sqlobject.tests.test_expire :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_groupBy.rst b/docs/api/sqlobject.tests.test_groupBy.rst index f823fd07..c8f6cc92 100644 --- a/docs/api/sqlobject.tests.test_groupBy.rst +++ b/docs/api/sqlobject.tests.test_groupBy.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_groupBy module -====================================== +sqlobject.tests.test\_groupBy module +==================================== .. automodule:: sqlobject.tests.test_groupBy :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_identity.rst b/docs/api/sqlobject.tests.test_identity.rst index e154f2dc..63716dfb 100644 --- a/docs/api/sqlobject.tests.test_identity.rst +++ b/docs/api/sqlobject.tests.test_identity.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_identity module -======================================= +sqlobject.tests.test\_identity module +===================================== .. automodule:: sqlobject.tests.test_identity :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_indexes.rst b/docs/api/sqlobject.tests.test_indexes.rst index cfe8e4bc..023d8fdb 100644 --- a/docs/api/sqlobject.tests.test_indexes.rst +++ b/docs/api/sqlobject.tests.test_indexes.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_indexes module -====================================== +sqlobject.tests.test\_indexes module +==================================== .. automodule:: sqlobject.tests.test_indexes :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns,indexDefinitions diff --git a/docs/api/sqlobject.tests.test_inheritance.rst b/docs/api/sqlobject.tests.test_inheritance.rst index 369aa4df..a381ee17 100644 --- a/docs/api/sqlobject.tests.test_inheritance.rst +++ b/docs/api/sqlobject.tests.test_inheritance.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_inheritance module -========================================== +sqlobject.tests.test\_inheritance module +======================================== .. automodule:: sqlobject.tests.test_inheritance :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_joins.rst b/docs/api/sqlobject.tests.test_joins.rst index 67ef3475..a0679733 100644 --- a/docs/api/sqlobject.tests.test_joins.rst +++ b/docs/api/sqlobject.tests.test_joins.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_joins module -==================================== +sqlobject.tests.test\_joins module +================================== .. automodule:: sqlobject.tests.test_joins :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_joins_conditional.rst b/docs/api/sqlobject.tests.test_joins_conditional.rst index 8bc28896..ca6fd0b5 100644 --- a/docs/api/sqlobject.tests.test_joins_conditional.rst +++ b/docs/api/sqlobject.tests.test_joins_conditional.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_joins\_conditional module -================================================= +sqlobject.tests.test\_joins\_conditional module +=============================================== .. automodule:: sqlobject.tests.test_joins_conditional :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_jsonbcol.rst b/docs/api/sqlobject.tests.test_jsonbcol.rst index 48eba47e..30f0d54a 100644 --- a/docs/api/sqlobject.tests.test_jsonbcol.rst +++ b/docs/api/sqlobject.tests.test_jsonbcol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_jsonbcol module -======================================= +sqlobject.tests.test\_jsonbcol module +===================================== .. automodule:: sqlobject.tests.test_jsonbcol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_jsoncol.rst b/docs/api/sqlobject.tests.test_jsoncol.rst index 18334b2a..bc78a692 100644 --- a/docs/api/sqlobject.tests.test_jsoncol.rst +++ b/docs/api/sqlobject.tests.test_jsoncol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_jsoncol module -====================================== +sqlobject.tests.test\_jsoncol module +==================================== .. automodule:: sqlobject.tests.test_jsoncol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_lazy.rst b/docs/api/sqlobject.tests.test_lazy.rst index 34df4cbb..98994362 100644 --- a/docs/api/sqlobject.tests.test_lazy.rst +++ b/docs/api/sqlobject.tests.test_lazy.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_lazy module -=================================== +sqlobject.tests.test\_lazy module +================================= .. automodule:: sqlobject.tests.test_lazy :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_md5.rst b/docs/api/sqlobject.tests.test_md5.rst index 8ea42178..922a8b88 100644 --- a/docs/api/sqlobject.tests.test_md5.rst +++ b/docs/api/sqlobject.tests.test_md5.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_md5 module -================================== +sqlobject.tests.test\_md5 module +================================ .. automodule:: sqlobject.tests.test_md5 :members: diff --git a/docs/api/sqlobject.tests.test_mysql.rst b/docs/api/sqlobject.tests.test_mysql.rst index 1ac3d767..adb997f9 100644 --- a/docs/api/sqlobject.tests.test_mysql.rst +++ b/docs/api/sqlobject.tests.test_mysql.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_mysql module -==================================== +sqlobject.tests.test\_mysql module +================================== .. automodule:: sqlobject.tests.test_mysql :members: diff --git a/docs/api/sqlobject.tests.test_new_joins.rst b/docs/api/sqlobject.tests.test_new_joins.rst index 5f751be7..7edf06aa 100644 --- a/docs/api/sqlobject.tests.test_new_joins.rst +++ b/docs/api/sqlobject.tests.test_new_joins.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_new\_joins module -========================================= +sqlobject.tests.test\_new\_joins module +======================================= .. automodule:: sqlobject.tests.test_new_joins :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_parse_uri.rst b/docs/api/sqlobject.tests.test_parse_uri.rst index d5adf4e9..8a7cf626 100644 --- a/docs/api/sqlobject.tests.test_parse_uri.rst +++ b/docs/api/sqlobject.tests.test_parse_uri.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_parse\_uri module -========================================= +sqlobject.tests.test\_parse\_uri module +======================================= .. automodule:: sqlobject.tests.test_parse_uri :members: diff --git a/docs/api/sqlobject.tests.test_paste.rst b/docs/api/sqlobject.tests.test_paste.rst index 2a284741..dc0fb590 100644 --- a/docs/api/sqlobject.tests.test_paste.rst +++ b/docs/api/sqlobject.tests.test_paste.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_paste module -==================================== +sqlobject.tests.test\_paste module +================================== .. automodule:: sqlobject.tests.test_paste :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_perConnection.rst b/docs/api/sqlobject.tests.test_perConnection.rst index e4d43710..7d4b1781 100644 --- a/docs/api/sqlobject.tests.test_perConnection.rst +++ b/docs/api/sqlobject.tests.test_perConnection.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_perConnection module -============================================ +sqlobject.tests.test\_perConnection module +========================================== .. automodule:: sqlobject.tests.test_perConnection :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_pickle.rst b/docs/api/sqlobject.tests.test_pickle.rst index 6e7cfe33..c44fa27d 100644 --- a/docs/api/sqlobject.tests.test_pickle.rst +++ b/docs/api/sqlobject.tests.test_pickle.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_pickle module -===================================== +sqlobject.tests.test\_pickle module +=================================== .. automodule:: sqlobject.tests.test_pickle :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_picklecol.rst b/docs/api/sqlobject.tests.test_picklecol.rst index 56db3212..7edd7c08 100644 --- a/docs/api/sqlobject.tests.test_picklecol.rst +++ b/docs/api/sqlobject.tests.test_picklecol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_picklecol module -======================================== +sqlobject.tests.test\_picklecol module +====================================== .. automodule:: sqlobject.tests.test_picklecol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_postgres.rst b/docs/api/sqlobject.tests.test_postgres.rst index 374a7869..d8082b5c 100644 --- a/docs/api/sqlobject.tests.test_postgres.rst +++ b/docs/api/sqlobject.tests.test_postgres.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_postgres module -======================================= +sqlobject.tests.test\_postgres module +===================================== .. automodule:: sqlobject.tests.test_postgres :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst index 2af5978d..8c044b55 100644 --- a/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst +++ b/docs/api/sqlobject.tests.test_reparent_sqlmeta.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_reparent\_sqlmeta module -================================================ +sqlobject.tests.test\_reparent\_sqlmeta module +============================================== .. automodule:: sqlobject.tests.test_reparent_sqlmeta :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_schema.rst b/docs/api/sqlobject.tests.test_schema.rst index 42f80883..9cf3457f 100644 --- a/docs/api/sqlobject.tests.test_schema.rst +++ b/docs/api/sqlobject.tests.test_schema.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_schema module -===================================== +sqlobject.tests.test\_schema module +=================================== .. automodule:: sqlobject.tests.test_schema :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_select.rst b/docs/api/sqlobject.tests.test_select.rst index 0ba89a83..9e63811b 100644 --- a/docs/api/sqlobject.tests.test_select.rst +++ b/docs/api/sqlobject.tests.test_select.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_select module -===================================== +sqlobject.tests.test\_select module +=================================== .. automodule:: sqlobject.tests.test_select :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_select_through.rst b/docs/api/sqlobject.tests.test_select_through.rst index 8c5cdaa1..f0833e2f 100644 --- a/docs/api/sqlobject.tests.test_select_through.rst +++ b/docs/api/sqlobject.tests.test_select_through.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_select\_through module -============================================== +sqlobject.tests.test\_select\_through module +============================================ .. automodule:: sqlobject.tests.test_select_through :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_setters.rst b/docs/api/sqlobject.tests.test_setters.rst index 0bb4d136..f35cfb0e 100644 --- a/docs/api/sqlobject.tests.test_setters.rst +++ b/docs/api/sqlobject.tests.test_setters.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_setters module -====================================== +sqlobject.tests.test\_setters module +==================================== .. automodule:: sqlobject.tests.test_setters :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_slice.rst b/docs/api/sqlobject.tests.test_slice.rst index f0559438..f2819a1b 100644 --- a/docs/api/sqlobject.tests.test_slice.rst +++ b/docs/api/sqlobject.tests.test_slice.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_slice module -==================================== +sqlobject.tests.test\_slice module +================================== .. automodule:: sqlobject.tests.test_slice :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sorting.rst b/docs/api/sqlobject.tests.test_sorting.rst index 04e1510a..a461b701 100644 --- a/docs/api/sqlobject.tests.test_sorting.rst +++ b/docs/api/sqlobject.tests.test_sorting.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sorting module -====================================== +sqlobject.tests.test\_sorting module +==================================== .. automodule:: sqlobject.tests.test_sorting :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder.rst b/docs/api/sqlobject.tests.test_sqlbuilder.rst index e70be201..f71230de 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlbuilder module -========================================= +sqlobject.tests.test\_sqlbuilder module +======================================= .. automodule:: sqlobject.tests.test_sqlbuilder :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst index b3291a43..47c965c9 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_dbspecific.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlbuilder\_dbspecific module -===================================================== +sqlobject.tests.test\_sqlbuilder\_dbspecific module +=================================================== .. automodule:: sqlobject.tests.test_sqlbuilder_dbspecific :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst b/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst index d6c874d1..56eb89fa 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_importproxy.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_sqlbuilder\_importproxy module -====================================================== +sqlobject.tests.test\_sqlbuilder\_importproxy module +==================================================== .. automodule:: sqlobject.tests.test_sqlbuilder_importproxy :members: diff --git a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst index d92359b0..ac24093e 100644 --- a/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst +++ b/docs/api/sqlobject.tests.test_sqlbuilder_joins_instances.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlbuilder\_joins\_instances module -=========================================================== +sqlobject.tests.test\_sqlbuilder\_joins\_instances module +========================================================= .. automodule:: sqlobject.tests.test_sqlbuilder_joins_instances :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlite.rst b/docs/api/sqlobject.tests.test_sqlite.rst index 1da10c03..7ef87923 100644 --- a/docs/api/sqlobject.tests.test_sqlite.rst +++ b/docs/api/sqlobject.tests.test_sqlite.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlite module -===================================== +sqlobject.tests.test\_sqlite module +=================================== .. automodule:: sqlobject.tests.test_sqlite :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_sqlmeta_idName.rst b/docs/api/sqlobject.tests.test_sqlmeta_idName.rst index e01eb945..b2954f4c 100644 --- a/docs/api/sqlobject.tests.test_sqlmeta_idName.rst +++ b/docs/api/sqlobject.tests.test_sqlmeta_idName.rst @@ -1,5 +1,5 @@ -sqlobject\.tests\.test\_sqlmeta\_idName module -============================================== +sqlobject.tests.test\_sqlmeta\_idName module +============================================ .. automodule:: sqlobject.tests.test_sqlmeta_idName :members: diff --git a/docs/api/sqlobject.tests.test_sqlobject_admin.rst b/docs/api/sqlobject.tests.test_sqlobject_admin.rst index d76ebc52..517d03ed 100644 --- a/docs/api/sqlobject.tests.test_sqlobject_admin.rst +++ b/docs/api/sqlobject.tests.test_sqlobject_admin.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_sqlobject\_admin module -=============================================== +sqlobject.tests.test\_sqlobject\_admin module +============================================= .. automodule:: sqlobject.tests.test_sqlobject_admin :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_string_id.rst b/docs/api/sqlobject.tests.test_string_id.rst index fbadd05c..28be7463 100644 --- a/docs/api/sqlobject.tests.test_string_id.rst +++ b/docs/api/sqlobject.tests.test_string_id.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_string\_id module -========================================= +sqlobject.tests.test\_string\_id module +======================================= .. automodule:: sqlobject.tests.test_string_id :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_style.rst b/docs/api/sqlobject.tests.test_style.rst index 04722741..df0981a2 100644 --- a/docs/api/sqlobject.tests.test_style.rst +++ b/docs/api/sqlobject.tests.test_style.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_style module -==================================== +sqlobject.tests.test\_style module +================================== .. automodule:: sqlobject.tests.test_style :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_subqueries.rst b/docs/api/sqlobject.tests.test_subqueries.rst index 59b034be..c4ef5395 100644 --- a/docs/api/sqlobject.tests.test_subqueries.rst +++ b/docs/api/sqlobject.tests.test_subqueries.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_subqueries module -========================================= +sqlobject.tests.test\_subqueries module +======================================= .. automodule:: sqlobject.tests.test_subqueries :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_transactions.rst b/docs/api/sqlobject.tests.test_transactions.rst index 940636ca..1c218945 100644 --- a/docs/api/sqlobject.tests.test_transactions.rst +++ b/docs/api/sqlobject.tests.test_transactions.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_transactions module -=========================================== +sqlobject.tests.test\_transactions module +========================================= .. automodule:: sqlobject.tests.test_transactions :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_unicode.rst b/docs/api/sqlobject.tests.test_unicode.rst index cb48d1ad..c90397f9 100644 --- a/docs/api/sqlobject.tests.test_unicode.rst +++ b/docs/api/sqlobject.tests.test_unicode.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_unicode module -====================================== +sqlobject.tests.test\_unicode module +==================================== .. automodule:: sqlobject.tests.test_unicode :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_uuidcol.rst b/docs/api/sqlobject.tests.test_uuidcol.rst index 4ca71612..6ea9226e 100644 --- a/docs/api/sqlobject.tests.test_uuidcol.rst +++ b/docs/api/sqlobject.tests.test_uuidcol.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_uuidcol module -====================================== +sqlobject.tests.test\_uuidcol module +==================================== .. automodule:: sqlobject.tests.test_uuidcol :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_validation.rst b/docs/api/sqlobject.tests.test_validation.rst index 98ccedec..30e3fe04 100644 --- a/docs/api/sqlobject.tests.test_validation.rst +++ b/docs/api/sqlobject.tests.test_validation.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_validation module -========================================= +sqlobject.tests.test\_validation module +======================================= .. automodule:: sqlobject.tests.test_validation :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.tests.test_views.rst b/docs/api/sqlobject.tests.test_views.rst index 291d57c7..ed828c36 100644 --- a/docs/api/sqlobject.tests.test_views.rst +++ b/docs/api/sqlobject.tests.test_views.rst @@ -1,8 +1,7 @@ -sqlobject\.tests\.test\_views module -==================================== +sqlobject.tests.test\_views module +================================== .. automodule:: sqlobject.tests.test_views :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.util.csvexport.rst b/docs/api/sqlobject.util.csvexport.rst index 465bed93..25a3cb86 100644 --- a/docs/api/sqlobject.util.csvexport.rst +++ b/docs/api/sqlobject.util.csvexport.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.csvexport module -================================= +sqlobject.util.csvexport module +=============================== .. automodule:: sqlobject.util.csvexport :members: diff --git a/docs/api/sqlobject.util.csvimport.rst b/docs/api/sqlobject.util.csvimport.rst index 6b19ee8d..415b518c 100644 --- a/docs/api/sqlobject.util.csvimport.rst +++ b/docs/api/sqlobject.util.csvimport.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.csvimport module -================================= +sqlobject.util.csvimport module +=============================== .. automodule:: sqlobject.util.csvimport :members: diff --git a/docs/api/sqlobject.util.moduleloader.rst b/docs/api/sqlobject.util.moduleloader.rst index 9bfeb892..f262edad 100644 --- a/docs/api/sqlobject.util.moduleloader.rst +++ b/docs/api/sqlobject.util.moduleloader.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.moduleloader module -==================================== +sqlobject.util.moduleloader module +================================== .. automodule:: sqlobject.util.moduleloader :members: diff --git a/docs/api/sqlobject.util.rst b/docs/api/sqlobject.util.rst index 2e194f23..9f5c1b38 100644 --- a/docs/api/sqlobject.util.rst +++ b/docs/api/sqlobject.util.rst @@ -1,5 +1,5 @@ -sqlobject\.util package -======================= +sqlobject.util package +====================== .. automodule:: sqlobject.util :members: diff --git a/docs/api/sqlobject.util.threadinglocal.rst b/docs/api/sqlobject.util.threadinglocal.rst index 3511fe17..dddba4d2 100644 --- a/docs/api/sqlobject.util.threadinglocal.rst +++ b/docs/api/sqlobject.util.threadinglocal.rst @@ -1,5 +1,5 @@ -sqlobject\.util\.threadinglocal module -====================================== +sqlobject.util.threadinglocal module +==================================== .. automodule:: sqlobject.util.threadinglocal :members: diff --git a/docs/api/sqlobject.versioning.rst b/docs/api/sqlobject.versioning.rst index 5f8c4d28..852d3e95 100644 --- a/docs/api/sqlobject.versioning.rst +++ b/docs/api/sqlobject.versioning.rst @@ -1,5 +1,5 @@ -sqlobject\.versioning package -============================= +sqlobject.versioning package +============================ .. automodule:: sqlobject.versioning :members: diff --git a/docs/api/sqlobject.versioning.test.rst b/docs/api/sqlobject.versioning.test.rst index f87edc23..6f9ea366 100644 --- a/docs/api/sqlobject.versioning.test.rst +++ b/docs/api/sqlobject.versioning.test.rst @@ -1,5 +1,5 @@ -sqlobject\.versioning\.test package -=================================== +sqlobject.versioning.test package +================================= .. automodule:: sqlobject.versioning.test :members: diff --git a/docs/api/sqlobject.versioning.test.test_version.rst b/docs/api/sqlobject.versioning.test.test_version.rst index 6ddf7722..2f03e9e4 100644 --- a/docs/api/sqlobject.versioning.test.test_version.rst +++ b/docs/api/sqlobject.versioning.test.test_version.rst @@ -1,8 +1,7 @@ -sqlobject\.versioning\.test\.test\_version module -================================================= +sqlobject.versioning.test.test\_version module +============================================== .. automodule:: sqlobject.versioning.test.test_version :members: :undoc-members: :show-inheritance: - :exclude-members: columnDefinitions,columnList,columns diff --git a/docs/api/sqlobject.views.rst b/docs/api/sqlobject.views.rst index ce4b406e..d0a30c58 100644 --- a/docs/api/sqlobject.views.rst +++ b/docs/api/sqlobject.views.rst @@ -1,5 +1,5 @@ -sqlobject\.views module -======================= +sqlobject.views module +====================== .. automodule:: sqlobject.views :members: diff --git a/docs/api/sqlobject.wsgi_middleware.rst b/docs/api/sqlobject.wsgi_middleware.rst index 79bc8727..b0aa884c 100644 --- a/docs/api/sqlobject.wsgi_middleware.rst +++ b/docs/api/sqlobject.wsgi_middleware.rst @@ -1,5 +1,5 @@ -sqlobject\.wsgi\_middleware module -================================== +sqlobject.wsgi\_middleware module +================================= .. automodule:: sqlobject.wsgi_middleware :members: From dffe5e97678ecf0e5f9d71aa141026f34ce151cc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 1 May 2019 18:50:47 +0300 Subject: [PATCH 007/295] Release 3.7.2 --- ANNOUNCE.rst | 30 +++++++++++------------------- README.rst | 2 +- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 4 ++-- 5 files changed, 19 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 84b0dcbe..6ab1d9ad 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,20 @@ Hello! -I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. - -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. - -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +I'm pleased to announce version 3.7.2, the second bugfix release of branch +3.7 of SQLObject. What's new in SQLObject ======================= -Contributors for this release are +Minor features +-------------- + +* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: + in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. + +* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable + since 2017. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +46,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0a0.dev20190202/ +https://pypi.org/project/SQLObject/3.7.2 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 92962cf6..52213389 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.8.0 +SQLObject 3.7.2 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 746018a3..bcb5c7c7 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.7.1 && +build_docs 3.7.2 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index af4ce644..dce568ef 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.7.2 +=============== + +Released 1 May 2019. Minor features -------------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 6e6740f7..52a80488 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.7.1' +version = '3.7.2' major = 3 minor = 7 -micro = 1 +micro = 2 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From ee26d9787b276686f5be9a19229134f3256e24a3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 1 May 2019 19:01:59 +0300 Subject: [PATCH 008/295] Prepare for the next release --- ANNOUNCE.rst | 30 +++++++++++++++++++----------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 6ab1d9ad..5cb28861 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,20 +1,28 @@ Hello! -I'm pleased to announce version 3.7.2, the second bugfix release of branch -3.7 of SQLObject. +I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -What's new in SQLObject -======================= +I'm pleased to announce version 3.8.0b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. + +I'm pleased to announce version 3.8.0rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. + +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -Minor features --------------- +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: - in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. -* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable - since 2017. +What's new in SQLObject +======================= + +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -46,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.7.2 +https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 52213389..404d1650 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.7.2 -=============== +SQLObject 3.7.3a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index dce568ef..b2da732e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.7.2 =============== From 16925142461dd707162cc23ba57add3794aa4647 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Jun 2019 21:33:23 +0300 Subject: [PATCH 009/295] Build(devscripts): Add `tox-select-envs.cmd` for w32 [skip ci] --- devscripts/tox-select-envs.cmd | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 devscripts/tox-select-envs.cmd diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd new file mode 100644 index 00000000..2f6fbae4 --- /dev/null +++ b/devscripts/tox-select-envs.cmd @@ -0,0 +1,18 @@ +@echo off +SetLocal EnableDelayedExpansion + +set "pattern=%1" +shift + +set "envs=" +for /f "usebackq" %%e in ( + `tox --listenvs-all ^| find "%pattern%" ^| find "-w32"` +) do ( + if not defined envs (set "envs=%%e") else (set "envs=!envs!,%%e") +) + +if not "%envs%"=="" ( + tox -e "%envs%" %* +) else ( + echo "No environments match %pattern%" >&2 +) From 37ec639c362949356a01a7fb1a8c700178b80237 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 17:10:45 +0300 Subject: [PATCH 010/295] Tests(tox): Refactor `tox-select-envs.cmd` --- devscripts/tox-select-envs.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd index 2f6fbae4..4ea6114e 100644 --- a/devscripts/tox-select-envs.cmd +++ b/devscripts/tox-select-envs.cmd @@ -8,7 +8,7 @@ set "envs=" for /f "usebackq" %%e in ( `tox --listenvs-all ^| find "%pattern%" ^| find "-w32"` ) do ( - if not defined envs (set "envs=%%e") else (set "envs=!envs!,%%e") + if defined envs (set "envs=!envs!,%%e") else (set "envs=%%e") ) if not "%envs%"=="" ( From ed65656d57475b9cdcac7fe45a47581b95c4f375 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 17:21:13 +0300 Subject: [PATCH 011/295] Tests(tox): Add dummy tests and unify test names Add dummy tests for `MySQL-python` on Python 3 and for `mysqlclient`/`pypostgresql` on Python 2.7. Unified test names must be structured "python-version" - "database name" - "driver" [-w32]. These tests will be used in refactored `.travis.yml`/`appveyor.yml`. --- tox.ini | 65 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/tox.ini b/tox.ini index dc17448c..f3f2bfc0 100644 --- a/tox.ini +++ b/tox.ini @@ -58,6 +58,22 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} +[testenv:py34-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[testenv:py35-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[testenv:py36-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[testenv:py37-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + [mysqlclient] commands = {[testenv]commands} @@ -66,6 +82,10 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' +[testenv:py27-mysqlclient] +commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" +deps = + [testenv:py34-mysqlclient] commands = {[mysqlclient]commands} @@ -136,21 +156,21 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-pymysql] +[testenv:py27-mysql-pymysql] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py34-pymysql] +[testenv:py34-mysql-pymysql] commands = {[pymysql]commands} -[testenv:py35-pymysql] +[testenv:py35-mysql-pymysql] commands = {[pymysql]commands} -[testenv:py36-pymysql] +[testenv:py36-mysql-pymysql] commands = {[pymysql]commands} -[testenv:py37-pymysql] +[testenv:py37-mysql-pymysql] commands = {[pymysql]commands} [mysql-pyodbc] @@ -263,16 +283,20 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py34-pypostgresql] +[testenv:py27-postgres-pypostgresql] +commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" +deps = + +[testenv:py34-postgres-pypostgresql] commands = {[pypostgresql]commands} -[testenv:py35-pypostgresql] +[testenv:py35-postgres-pypostgresql] commands = {[pypostgresql]commands} -[testenv:py36-pypostgresql] +[testenv:py36-postgres-pypostgresql] commands = {[pypostgresql]commands} -[testenv:py37-pypostgresql] +[testenv:py37-postgres-pypostgresql] commands = {[pypostgresql]commands} [pg8000] @@ -543,25 +567,25 @@ commands = pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-pymysql-w32] +[testenv:py27-mysql-pymysql-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py34-pymysql-w32] +[testenv:py34-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} -[testenv:py35-pymysql-w32] +[testenv:py35-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} -[testenv:py36-pymysql-w32] +[testenv:py36-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} -[testenv:py37-pymysql-w32] +[testenv:py37-mysql-pymysql-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -710,19 +734,24 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py34-pypostgresql-w32] +[testenv:py27-postgres-pypostgresql-w32] +platform = win32 +commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" +deps = + +[testenv:py34-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} -[testenv:py35-pypostgresql-w32] +[testenv:py35-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} -[testenv:py36-pypostgresql-w32] +[testenv:py36-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} -[testenv:py37-pypostgresql-w32] +[testenv:py37-postgres-pypostgresql-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" From 9084e6f3a27fcf24e5fd02010319cfacf5a015dc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 17:52:29 +0300 Subject: [PATCH 012/295] CI: Reduce the number of virtual machines/containers One OS, one DB, one python version, many drivers per VM. --- .travis.yml | 129 +++++++++++--------------------------------------- appveyor.yml | 97 ++++--------------------------------- docs/News.rst | 6 +++ 3 files changed, 43 insertions(+), 189 deletions(-) diff --git a/.travis.yml b/.travis.yml index acd3e873..8fe81bad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,132 +22,57 @@ addons: matrix: include: - python: "2.7" - env: TOXENV=py27-mysqldb + env: TESTS=py27-mysql - python: "3.4" - env: TOXENV=py34-mysqlclient + env: TESTS=py34-mysql - python: "3.5" - env: TOXENV=py35-mysqlclient + env: TESTS=py35-mysql - python: "3.6" - env: TOXENV=py36-mysqlclient + env: TESTS=py36-mysql - python: "3.7" dist: xenial - env: TOXENV=py37-mysqlclient + env: TESTS=py37-mysql - python: "2.7" - env: TOXENV=py27-mysql-connector + env: TESTS=py27-postgres - python: "3.4" - env: TOXENV=py34-mysql-connector + env: TESTS=py34-postgres - python: "3.5" - env: TOXENV=py35-mysql-connector + env: TESTS=py35-postgres - python: "3.6" - env: TOXENV=py36-mysql-connector + env: TESTS=py36-postgres - python: "3.7" dist: xenial - env: TOXENV=py37-mysql-connector + env: TESTS=py37-postgres - python: "2.7" - env: TOXENV=py27-mysql-oursql + env: TESTS=py27-sqlite - python: "3.4" - env: TOXENV=py34-mysql-oursql3 + env: TESTS=py34-sqlite - python: "3.5" - env: TOXENV=py35-mysql-oursql3 + env: TESTS=py35-sqlite - python: "3.6" - env: TOXENV=py36-mysql-oursql3 + env: TESTS=py36-sqlite - python: "3.7" dist: xenial - env: TOXENV=py37-mysql-oursql3 + env: TESTS=py37-sqlite - python: "2.7" - env: TOXENV=py27-pymysql - - python: "3.4" - env: TOXENV=py34-pymysql - - python: "3.5" - env: TOXENV=py35-pymysql - - python: "3.6" - env: TOXENV=py36-pymysql - - python: "3.7" - dist: xenial - env: TOXENV=py37-pymysql - - python: "2.7" - env: TOXENV=py27-postgres-psycopg - - python: "3.4" - env: TOXENV=py34-postgres-psycopg - - python: "3.5" - env: TOXENV=py35-postgres-psycopg - - python: "3.6" - env: TOXENV=py36-postgres-psycopg - - python: "3.7" - dist: xenial - env: TOXENV=py37-postgres-psycopg - - python: "2.7" - env: TOXENV=py27-postgres-pygresql - - python: "3.4" - env: TOXENV=py34-postgres-pygresql - - python: "3.5" - env: TOXENV=py35-postgres-pygresql - - python: "3.6" - env: TOXENV=py36-postgres-pygresql - - python: "3.7" - dist: xenial - env: TOXENV=py37-postgres-pygresql - - python: "3.4" - env: TOXENV=py34-pypostgresql - - python: "3.5" - env: TOXENV=py35-pypostgresql - - python: "3.6" - env: TOXENV=py36-pypostgresql - - python: "3.7" - dist: xenial - env: TOXENV=py37-pypostgresql - - python: "2.7" - env: TOXENV=py27-postgres-pg8000 - - python: "3.4" - env: TOXENV=py34-postgres-pg8000 - - python: "3.5" - env: TOXENV=py35-postgres-pg8000 - - python: "3.6" - env: TOXENV=py36-postgres-pg8000 - - python: "3.7" - dist: xenial - env: TOXENV=py37-postgres-pg8000 - - python: "2.7" - env: TOXENV=py27-sqlite - - python: "3.4" - env: TOXENV=py34-sqlite - - python: "3.5" - env: TOXENV=py35-sqlite - - python: "3.6" - env: TOXENV=py36-sqlite - - python: "3.7" - dist: xenial - env: TOXENV=py37-sqlite - - python: "2.7" - env: TOXENV=py27-sqlite-memory - - python: "3.4" - env: TOXENV=py34-sqlite-memory - - python: "3.5" - env: TOXENV=py35-sqlite-memory - - python: "3.6" - env: TOXENV=py36-sqlite-memory - - python: "3.7" - dist: xenial - env: TOXENV=py37-sqlite-memory - - python: "2.7" - env: TOXENV=py27-flake8 + env: TESTS=py27-flake8 - python: "3.7" dist: xenial - env: TOXENV=py37-flake8 + env: TESTS=py37-flake8 - python: "2.7" - env: TOXENV=py27-firebird-fdb + env: TESTS=py27-firebird - python: "3.6" - env: TOXENV=py36-firebird-fdb + env: TESTS=py36-firebird - python: "2.7" - env: TOXENV=py27-firebirdsql + env: TESTS=py27-firebird - python: "3.6" - env: TOXENV=py36-firebirdsql + env: TESTS=py36-firebird allow_failures: - - env: TOXENV=py27-firebird-fdb - - env: TOXENV=py36-firebird-fdb - - env: TOXENV=py27-firebirdsql - - env: TOXENV=py36-firebirdsql + - env: TESTS=py27-firebird + - env: TESTS=py36-firebird + - env: TESTS=py27-firebird + - env: TESTS=py36-firebird fast_finish: true @@ -160,7 +85,7 @@ before_install: # to create the test database. # Copied password initializtion from # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - - if [[ $TOXENV = *firebird* ]]; then + - if [[ $TESTS = *firebird* ]]; then sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && sudo /etc/init.d/firebird2.5-super start && sleep 5 && sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' && @@ -171,7 +96,7 @@ before_install: install: travis_retry pip install --upgrade "pip < 19.1" setuptools tox coveralls codecov ppu -script: tox +script: devscripts/tox-select-envs $TESTS after_success: - cd sqlobject diff --git a/appveyor.yml b/appveyor.yml index 953cc8ac..0bd35764 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,122 +25,45 @@ environment: CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" matrix: - - TOXENV: "py27-mysql-connector-w32" + - TESTS: "py27-mysql" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" db: mysql - - TOXENV: "py36-mysql-connector-w32" + - TESTS: "py36-mysql" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: mysql - - TOXENV: "py37-mysql-connector-w32" + - TESTS: "py37-mysql" PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: mysql - - TOXENV: "py27-pymysql-w32" + - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - db: mysql - - TOXENV: "py36-pymysql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: mysql - - TOXENV: "py37-pymysql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: mysql - - TOXENV: "py27-postgres-psycopg-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: postgresql - - TOXENV: "py36-postgres-psycopg-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TOXENV: "py37-postgres-psycopg-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TOXENV: "py27-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27-x64" - db: postgresql - - TOXENV: "py36-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TOXENV: "py37-postgres-pygresql-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TOXENV: "py36-pypostgresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36" - db: postgresql - - TOXENV: "py37-pypostgresql-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37" db: postgresql - - TOXENV: "py36-pypostgresql-w32" + - TESTS: "py36-postgres" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" db: postgresql - - TOXENV: "py37-pypostgresql-w32" + - TESTS: "py37-postgres" PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: postgresql - - TOXENV: "py27-postgres-pg8000-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: postgresql - - TOXENV: "py36-postgres-pg8000-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TOXENV: "py37-postgres-pg8000-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TOXENV: "py27-sqlite-w32" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - - TOXENV: "py36-sqlite-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - - TOXENV: "py37-sqlite-w32" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - - TOXENV: "py27-sqlite-memory-w32" + - TESTS: "py27-sqlite" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" PYTHON_HOME: "C:\\Python27" - - TOXENV: "py36-sqlite-memory-w32" + - TESTS: "py36-sqlite" PYTHON_ARCH: "64" PYTHON_VERSION: "3.6" PYTHON_HOME: "C:\\Python36-x64" - - TOXENV: "py37-sqlite-memory-w32" + - TESTS: "py37-sqlite" PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" @@ -165,7 +88,7 @@ install: build: false test_script: - - "%CMD_IN_ENV% tox" + - "%CMD_IN_ENV% devscripts\\tox-select-envs %TESTS%" after_test: - "remove-old-files.py -o 180 %LOCALAPPDATA%\\pip\\Cache" diff --git a/docs/News.rst b/docs/News.rst index b2da732e..e57e68c0 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +CI +-- + +* Reduce the number of virtual machines/containers: + one OS, one DB, one python version, many drivers per VM. + SQLObject 3.7.2 =============== From 9d4af66987f77054c307c417dbdd786d6bfb5012 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 30 Jun 2019 18:27:22 +0300 Subject: [PATCH 013/295] Tests(tox): Exclude tests from the list of auto tests Exclude ODBC tests and py27-pygresql. --- devscripts/tox-select-envs | 2 +- devscripts/tox-select-envs.cmd | 2 +- tox.ini | 92 +++++++++++++++++----------------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/devscripts/tox-select-envs b/devscripts/tox-select-envs index 34ff4b2c..f1e9a817 100755 --- a/devscripts/tox-select-envs +++ b/devscripts/tox-select-envs @@ -2,7 +2,7 @@ pattern="$1" shift -envs="`tox --listenvs-all | grep -F $pattern | sed 's/$/,/'`" +envs="`tox --listenvs-all | grep -F $pattern | grep -v 'noauto\|w32' | sed 's/$/,/'`" if [ -n "$envs" ]; then exec tox -e "$envs" "$@" diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd index 4ea6114e..03d8b4e1 100644 --- a/devscripts/tox-select-envs.cmd +++ b/devscripts/tox-select-envs.cmd @@ -6,7 +6,7 @@ shift set "envs=" for /f "usebackq" %%e in ( - `tox --listenvs-all ^| find "%pattern%" ^| find "-w32"` + `tox --listenvs-all ^| find "%pattern%" ^| find "-w32" ^| find /v "noauto"` ) do ( if defined envs (set "envs=!envs!,%%e") else (set "envs=%%e") ) diff --git a/tox.ini b/tox.ini index f3f2bfc0..7dac706b 100644 --- a/tox.ini +++ b/tox.ini @@ -182,21 +182,21 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pyodbc] +[testenv:py27-mysql-pyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py34-mysql-pyodbc] +[testenv:py34-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} -[testenv:py35-mysql-pyodbc] +[testenv:py35-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} -[testenv:py36-mysql-pyodbc] +[testenv:py36-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} -[testenv:py37-mysql-pyodbc] +[testenv:py37-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -207,21 +207,21 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pypyodbc] +[testenv:py27-mysql-pypyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py34-mysql-pypyodbc] +[testenv:py34-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} -[testenv:py35-mysql-pypyodbc] +[testenv:py35-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} -[testenv:py36-mysql-pypyodbc] +[testenv:py36-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} -[testenv:py37-mysql-pypyodbc] +[testenv:py37-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -333,21 +333,21 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pyodbc] +[testenv:py27-postgres-pyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py34-postgres-pyodbc] +[testenv:py34-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} -[testenv:py35-postgres-pyodbc] +[testenv:py35-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} -[testenv:py36-postgres-pyodbc] +[testenv:py36-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} -[testenv:py37-postgres-pyodbc] +[testenv:py37-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -358,21 +358,21 @@ commands = pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pypyodbc] +[testenv:py27-postgres-pypyodbc-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py34-postgres-pypyodbc] +[testenv:py34-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} -[testenv:py35-postgres-pypyodbc] +[testenv:py35-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} -[testenv:py36-postgres-pypyodbc] +[testenv:py36-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} -[testenv:py37-postgres-pypyodbc] +[testenv:py37-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -501,25 +501,25 @@ commands = pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&timeout=30&debug=1" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" -[testenv:py27-mssql-pyodbc-w32] +[testenv:py27-mssql-pyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py34-mssql-pyodbc-w32] +[testenv:py34-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} -[testenv:py35-mssql-pyodbc-w32] +[testenv:py35-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} -[testenv:py36-mssql-pyodbc-w32] +[testenv:py36-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} -[testenv:py37-mssql-pyodbc-w32] +[testenv:py37-mssql-pyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -601,25 +601,25 @@ commands = pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pyodbc-w32] +[testenv:py27-mysql-pyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py34-mysql-pyodbc-w32] +[testenv:py34-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} -[testenv:py35-mysql-pyodbc-w32] +[testenv:py35-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} -[testenv:py36-mysql-pyodbc-w32] +[testenv:py36-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} -[testenv:py37-mysql-pyodbc-w32] +[testenv:py37-mysql-pyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -635,25 +635,25 @@ commands = pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-mysql-pypyodbc-w32] +[testenv:py27-mysql-pypyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py34-mysql-pypyodbc-w32] +[testenv:py34-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} -[testenv:py35-mysql-pypyodbc-w32] +[testenv:py35-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} -[testenv:py36-mysql-pypyodbc-w32] +[testenv:py36-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} -[testenv:py37-mysql-pypyodbc-w32] +[testenv:py37-mysql-pypyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -701,7 +701,7 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pygresql-w32] +[testenv:py27-postgres-pygresql-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base @@ -800,25 +800,25 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pyodbc-w32] +[testenv:py27-postgres-pyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py34-postgres-pyodbc-w32] +[testenv:py34-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} -[testenv:py35-postgres-pyodbc-w32] +[testenv:py35-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} -[testenv:py36-postgres-pyodbc-w32] +[testenv:py36-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} -[testenv:py37-postgres-pyodbc-w32] +[testenv:py37-postgres-pyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" @@ -834,25 +834,25 @@ commands = pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test -[testenv:py27-postgres-pypyodbc-w32] +[testenv:py27-postgres-pypyodbc-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py34-postgres-pypyodbc-w32] +[testenv:py34-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} -[testenv:py35-postgres-pypyodbc-w32] +[testenv:py35-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} -[testenv:py36-postgres-pypyodbc-w32] +[testenv:py36-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} -[testenv:py37-postgres-pypyodbc-w32] +[testenv:py37-postgres-pypyodbc-noauto-w32] platform = win32 commands = cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" From bae4bad96fbff1fdb476ca11e200d4d1a0907083 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 20:02:03 +0300 Subject: [PATCH 014/295] Build: Remove outdated `git-svn` --- .../git-svn/SQLObject-gitignore/.gitignore | 10 ---- .../SQLObject-gitignore/docs/.gitignore | 3 - devscripts/git-svn/svn2git | 55 ------------------- devscripts/git-svn/svn2git-fullhistory | 33 ----------- 4 files changed, 101 deletions(-) delete mode 100644 devscripts/git-svn/SQLObject-gitignore/.gitignore delete mode 100644 devscripts/git-svn/SQLObject-gitignore/docs/.gitignore delete mode 100755 devscripts/git-svn/svn2git delete mode 100755 devscripts/git-svn/svn2git-fullhistory diff --git a/devscripts/git-svn/SQLObject-gitignore/.gitignore b/devscripts/git-svn/SQLObject-gitignore/.gitignore deleted file mode 100644 index 52d4a58a..00000000 --- a/devscripts/git-svn/SQLObject-gitignore/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -*~ -*.tmp -*.pyc -*.pyo -/MANIFEST -/SQLObject.egg-info -/build -/data -/dist -/temp diff --git a/devscripts/git-svn/SQLObject-gitignore/docs/.gitignore b/devscripts/git-svn/SQLObject-gitignore/docs/.gitignore deleted file mode 100644 index 59370209..00000000 --- a/devscripts/git-svn/SQLObject-gitignore/docs/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/*.html -/data.db -/html diff --git a/devscripts/git-svn/svn2git b/devscripts/git-svn/svn2git deleted file mode 100755 index e93e4f6f..00000000 --- a/devscripts/git-svn/svn2git +++ /dev/null @@ -1,55 +0,0 @@ -#! /bin/sh - -if [ -z "$1" ]; then - echo "Usage: $0 svn_url [dir]" >&2 - exit 1 -fi - -url="$1" - -if [ ! -f authors.txt ]; then - echo "Run \"get-authors $1\" first" >&2 - exit 2 -fi - -if [ -z "$2" ]; then - dir="`basename $url`" -else - dir="$2" -fi - -if [ -z "$dir" ]; then - echo "Usage: $0 $url dir" >&2 - exit 1 -fi - -# init + fetch -git svn clone "$url" --authors-file=authors.txt --prefix=svn/ --stdlayout "$dir" && -cd "$dir" && - -# Convert tags and branches - -# See http://blog.jessitron.com/2013/08/converting-from-svn-to-git.html - -git for-each-ref --format="%(refname:short)" refs/remotes/svn | - sed 's#svn/##' | grep -v '^tags' | - while read aBranch; do git branch $aBranch svn/$aBranch || exit 1; done - -# See http://thomasrast.ch/git/git-svn-conversion.html - -git for-each-ref --format="%(refname:short)" refs/remotes/svn/tags/ | -while read tag; do - GIT_COMMITTER_DATE="`git log -1 --pretty=format:\"%ad\" \"$tag\"`" \ - GIT_COMMITTER_EMAIL="`git log -1 --pretty=format:\"%ce\" \"$tag\"`" \ - GIT_COMMITTER_NAME="`git log -1 --pretty=format:\"%cn\" \"$tag\"`" \ - git tag -a -m "`git for-each-ref --format=\"%(contents)\" \"$tag\"`" \ - "`echo \"$tag\" | sed 's#svn/tags/##'`" "$tag" || exit 1 -done - -# preserve authors.txt -cp -p ../authors.txt .git/info && -git config --local --path svn.authorsfile .git/info/authors.txt - -git svn gc && -git gc --aggressive && -echo "Cloned from $url using git-svn" >.git/description diff --git a/devscripts/git-svn/svn2git-fullhistory b/devscripts/git-svn/svn2git-fullhistory deleted file mode 100755 index bc74b897..00000000 --- a/devscripts/git-svn/svn2git-fullhistory +++ /dev/null @@ -1,33 +0,0 @@ -#! /bin/sh - -"`dirname \"$0\"`"/svn2git \ - http://svn.colorstudy.com/SQLObject SQLObject-fullhistory && - -git init --bare SQLObject.git && -cd SQLObject.git && -echo "Bare SQLObject repository" >description && -git fetch ../SQLObject-fullhistory master:master 1.5:1.5 1.6:1.6 1.7:1.7 tag 1.5.0b1 tag 1.5.0rc1 tag 1.5.0 tag 1.5.1 tag 1.5.2 tag 1.6.0a1 tag 1.6.0b1 tag 1.6.0 tag 1.7.0b1 && - -cd .. && -git clone SQLObject.git SQLObject && rm -rf SQLObject.git && -cd SQLObject && git remote rm origin && rmdir .git/refs/remotes/origin && - -echo "Development SQLObject repository" >.git/description && -git branch --track 1.5 origin/1.5 && -git branch --track 1.6 origin/1.6 && -git branch --track 1.7 origin/1.7 && - -# Null merges -git checkout 1.6 && git merge --no-commit -s ours 1.5 && -git checkout HEAD sqlobject/main.py && git commit && - -git checkout 1.7 && git merge --no-commit -s ours 1.6 && -git checkout HEAD sqlobject/col.py && git commit && - -git checkout master && git merge --no-commit -s ours 1.7 && -git checkout HEAD setup.cfg setup.py \ - sqlobject/__version__.py sqlobject/converters.py \ - sqlobject/tests/test_converters.py sqlobject/tests/test_datetime.py && -git commit && - -exec vim .git/config From 26d83fb89b914940892dbecd033707fbfcc8b71e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 20:54:30 +0300 Subject: [PATCH 015/295] CI(AppVeyor): Move `validators.py` -> `devscripts/CI/` --- validators.py => devscripts/CI/validators.py | 0 tox.ini | 26 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) rename validators.py => devscripts/CI/validators.py (100%) diff --git a/validators.py b/devscripts/CI/validators.py similarity index 100% rename from validators.py rename to devscripts/CI/validators.py diff --git a/tox.ini b/tox.ini index 7dac706b..899295c8 100644 --- a/tox.ini +++ b/tox.ini @@ -522,7 +522,7 @@ commands = {[mssql-pyodbc-w32]commands} [testenv:py37-mssql-pyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mssql-pyodbc-w32]commands} [mysql-connector-w32] @@ -555,7 +555,7 @@ commands = {[mysql-connector-w32]commands} [testenv:py37-mysql-connector-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-connector-w32]commands} [pymysql-w32] @@ -588,7 +588,7 @@ commands = {[pymysql-w32]commands} [testenv:py37-mysql-pymysql-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pymysql-w32]commands} [mysql-pyodbc-w32] @@ -622,7 +622,7 @@ commands = {[mysql-pyodbc-w32]commands} [testenv:py37-mysql-pyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pyodbc-w32]commands} [mysql-pypyodbc-w32] @@ -656,7 +656,7 @@ commands = {[mysql-pypyodbc-w32]commands} [testenv:py37-mysql-pypyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pypyodbc-w32]commands} [psycopg-w32] @@ -689,7 +689,7 @@ commands = {[psycopg-w32]commands} [testenv:py37-postgres-psycopg-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[psycopg-w32]commands} [pygresql-w32] @@ -722,7 +722,7 @@ commands = {[pygresql-w32]commands} [testenv:py37-postgres-pygresql-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pygresql-w32]commands} [pypostgresql-w32] @@ -754,7 +754,7 @@ commands = {[pypostgresql-w32]commands} [testenv:py37-postgres-pypostgresql-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pypostgresql-w32]commands} [pg8000-w32] @@ -787,7 +787,7 @@ commands = {[pg8000-w32]commands} [testenv:py37-postgres-pg8000-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pg8000-w32]commands} [postgres-pyodbc-w32] @@ -821,7 +821,7 @@ commands = {[postgres-pyodbc-w32]commands} [testenv:py37-postgres-pyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pyodbc-w32]commands} [postgres-pypyodbc-w32] @@ -855,7 +855,7 @@ commands = {[postgres-pypyodbc-w32]commands} [testenv:py37-postgres-pypyodbc-noauto-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pypyodbc-w32]commands} [sqlite-w32] @@ -885,7 +885,7 @@ commands = {[sqlite-w32]commands} [testenv:py37-sqlite-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-w32]commands} [sqlite-memory-w32] @@ -915,5 +915,5 @@ commands = {[sqlite-memory-w32]commands} [testenv:py37-sqlite-memory-w32] platform = win32 commands = - cmd /c "copy ..\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-memory-w32]commands} From e24b9ed78e3de8016e6f9aafdfa153aa08faa732 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 18:32:17 +0300 Subject: [PATCH 016/295] Refactor: Remove excessive assignment --- sqlobject/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sqlobject/main.py b/sqlobject/main.py index 5d9b537a..488b9924 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -1621,7 +1621,6 @@ def destroySelf(self): join.joinColumn, self.id) self._connection.query(q) - depends = [] depends = self._SO_depends() for k in depends: # Free related joins From 14d47233fb0d8e0eb4f39c17f0ffce3b907e2910 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Sep 2019 19:14:27 +0300 Subject: [PATCH 017/295] Tests(ForeignKey_cascade): Add tests for cascade deletion --- docs/News.rst | 5 + sqlobject/tests/test_ForeignKey_cascade.py | 125 +++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 sqlobject/tests/test_ForeignKey_cascade.py diff --git a/docs/News.rst b/docs/News.rst index e57e68c0..a8f949df 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests +----- + +* Add tests for cascade deletion. + CI -- diff --git a/sqlobject/tests/test_ForeignKey_cascade.py b/sqlobject/tests/test_ForeignKey_cascade.py new file mode 100644 index 00000000..d4a10612 --- /dev/null +++ b/sqlobject/tests/test_ForeignKey_cascade.py @@ -0,0 +1,125 @@ +from sqlobject import ForeignKey, SQLObject, StringCol, \ + SQLObjectIntegrityError, SQLObjectNotFound +from sqlobject.tests.dbtest import raises, setupClass + + +class SOTestPerson1(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeTrue(SQLObject): + sender = ForeignKey('SOTestPerson1', cascade=True) + recipient = ForeignKey('SOTestPerson1', cascade=True) + body = StringCol() + + +def test1(): + setupClass([SOTestPerson1, SOTestMessageCascadeTrue]) + + john = SOTestPerson1(name='john') + emily = SOTestPerson1(name='emily') + message = SOTestMessageCascadeTrue( + sender=emily, recipient=john, body='test1' + ) + + SOTestPerson1.delete(emily.id) + john.expire() + message.expire() + + john.sync() + raises(SQLObjectNotFound, emily.sync) + raises(SQLObjectNotFound, message.sync) + + +class SOTestPerson2(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeFalse(SQLObject): + sender = ForeignKey('SOTestPerson2', cascade=False) + recipient = ForeignKey('SOTestPerson2', cascade=False) + body = StringCol() + + +def test2(): + setupClass([SOTestPerson2, SOTestMessageCascadeFalse]) + + john = SOTestPerson2(name='john') + emily = SOTestPerson2(name='emily') + message = SOTestMessageCascadeFalse( + sender=emily, recipient=john, body='test2' + ) + + raises(SQLObjectIntegrityError, SOTestPerson2.delete, emily.id) + john.expire() + emily.expire() + message.expire() + + john.sync() + emily.sync() + message.sync() + + assert message.sender == emily + assert message.recipient == john + + +class SOTestPerson3(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeNull(SQLObject): + sender = ForeignKey('SOTestPerson3', cascade='null') + recipient = ForeignKey('SOTestPerson3', cascade='null') + body = StringCol() + + +def test3(): + setupClass([SOTestPerson3, SOTestMessageCascadeNull]) + + john = SOTestPerson3(name='john') + emily = SOTestPerson3(name='emily') + message = SOTestMessageCascadeNull( + sender=emily, recipient=john, body='test3' + ) + + SOTestPerson3.delete(emily.id) + john.expire() + message.expire() + + john.sync() + message.sync() + raises(SQLObjectNotFound, emily.sync) + + assert message.recipient is None + + # This looks like a bug; `message.sender` here should be None + # assert message.sender is None + + +class SOTestPerson4(SQLObject): + name = StringCol() + + +class SOTestMessageCascadeMixed(SQLObject): + sender = ForeignKey('SOTestPerson4', cascade=True) + recipient = ForeignKey('SOTestPerson4', cascade='null') + body = StringCol() + + +def test4(): + setupClass([SOTestPerson4, SOTestMessageCascadeMixed]) + + john = SOTestPerson4(name='john') + emily = SOTestPerson4(name='emily') + message = SOTestMessageCascadeMixed( + sender=emily, recipient=john, body='test4' + ) + + SOTestPerson4.delete(emily.id) + john.expire() + message.expire() + + john.sync() + + # This is even a nastier bug; `message` was deleted from the DB + # message.sync() From b3d72cd4c4516bddf8bd39550ed8582cf7101eae Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 15 Sep 2019 17:47:31 +0300 Subject: [PATCH 018/295] Tests: Fix calls to `pytest.mark.skipif` Make conditions bool instead of str. --- docs/News.rst | 2 ++ sqlobject/tests/test_boundattributes.py | 4 +++- sqlobject/tests/test_paste.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a8f949df..f1fcf89a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,8 @@ Tests * Add tests for cascade deletion. +* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. + CI -- diff --git a/sqlobject/tests/test_boundattributes.py b/sqlobject/tests/test_boundattributes.py index 5ae20152..1453658d 100644 --- a/sqlobject/tests/test_boundattributes.py +++ b/sqlobject/tests/test_boundattributes.py @@ -3,7 +3,9 @@ from sqlobject import boundattributes from sqlobject import declarative -pytestmark = pytest.mark.skipif('True') +pytestmark = pytest.mark.skipif( + True, + reason='The module "boundattributes" and its tests were not finished yet') class SOTestMe(object): diff --git a/sqlobject/tests/test_paste.py b/sqlobject/tests/test_paste.py index 36623093..5cd90298 100644 --- a/sqlobject/tests/test_paste.py +++ b/sqlobject/tests/test_paste.py @@ -5,7 +5,7 @@ try: from sqlobject.wsgi_middleware import make_middleware except ImportError: - pytestmark = pytest.mark.skipif('True') + pytestmark = pytest.mark.skipif(True, reason='These tests require Paste') from .dbtest import getConnection, getConnectionURI, setupClass From 477cff64f80a545db9346770e7cc4378c3413780 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 15 Sep 2019 17:54:31 +0300 Subject: [PATCH 019/295] Tests: Fix module-level calls to `pytest.mark.skip` Add reasons. --- docs/News.rst | 2 ++ sqlobject/tests/test_decimal.py | 2 +- sqlobject/tests/test_mysql.py | 2 +- sqlobject/tests/test_postgres.py | 2 +- sqlobject/tests/test_sqlite.py | 2 +- sqlobject/tests/test_transactions.py | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index f1fcf89a..a216624b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -15,6 +15,8 @@ Tests * Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. +* Fix module-level calls to ``pytest.mark.skip`` - add reasons. + CI -- diff --git a/sqlobject/tests/test_decimal.py b/sqlobject/tests/test_decimal.py index c7388e0d..06cd2fbe 100644 --- a/sqlobject/tests/test_decimal.py +++ b/sqlobject/tests/test_decimal.py @@ -16,7 +16,7 @@ pass else: if not support_decimal_column: - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require Decimal support") class DecimalTable(SQLObject): diff --git a/sqlobject/tests/test_mysql.py b/sqlobject/tests/test_mysql.py index de4b040b..3d7b9a68 100644 --- a/sqlobject/tests/test_mysql.py +++ b/sqlobject/tests/test_mysql.py @@ -10,7 +10,7 @@ pass else: if connection.dbName != "mysql": - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require MySQL") class SOTestSOListMySQL(SQLObject): diff --git a/sqlobject/tests/test_postgres.py b/sqlobject/tests/test_postgres.py index e656ce78..ab1f9692 100644 --- a/sqlobject/tests/test_postgres.py +++ b/sqlobject/tests/test_postgres.py @@ -16,7 +16,7 @@ pass else: if connection.dbName != "postgres": - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require PostgreSQL") class SOTestSSLMode(SQLObject): diff --git a/sqlobject/tests/test_sqlite.py b/sqlobject/tests/test_sqlite.py index 4e9611a8..5fb070b2 100644 --- a/sqlobject/tests/test_sqlite.py +++ b/sqlobject/tests/test_sqlite.py @@ -16,7 +16,7 @@ pass else: if connection.dbName != "sqlite": - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require SQLite") class SQLiteFactoryTest(SQLObject): diff --git a/sqlobject/tests/test_transactions.py b/sqlobject/tests/test_transactions.py index 56ce7f8e..ee66620b 100644 --- a/sqlobject/tests/test_transactions.py +++ b/sqlobject/tests/test_transactions.py @@ -16,7 +16,7 @@ pass else: if not support_transactions: - pytestmark = pytest.mark.skip('') + pytestmark = pytest.mark.skip("These tests require transactions") class SOTestSOTrans(SQLObject): From a26acf96a3322dedfaf2a2b36b5eaf3d313e0901 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 13 Sep 2019 04:16:10 +0300 Subject: [PATCH 020/295] Fix: Avoid excessive parentheses around `ALL/ANY/SOME()` --- docs/News.rst | 7 +++++++ sqlobject/sqlbuilder.py | 3 ++- sqlobject/tests/test_mysql.py | 16 +++++++++++++++- sqlobject/tests/test_postgres.py | 16 +++++++++++++++- sqlobject/tests/test_sqlbuilder.py | 17 +++++++++++++++-- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a216624b..3ca56b08 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,11 +8,18 @@ News SQLObject (master) ================== +Bug fixes +--------- + +* Avoid excessive parentheses around ``ALL/ANY/SOME()``. + Tests ----- * Add tests for cascade deletion. +* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. + * Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. * Fix module-level calls to ``pytest.mark.skip`` - add reasons. diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index cc6696b5..d6c2e619 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -308,7 +308,8 @@ def __sqlrepr__(self, db): s2 = sqlrepr(self.expr2, db) if s1[0] != '(' and s1 != 'NULL': s1 = '(' + s1 + ')' - if s2[0] != '(' and s2 != 'NULL': + if s2[0] != '(' and s2 != 'NULL' and \ + not isinstance(self.expr2, Subquery): s2 = '(' + s2 + ')' return "(%s %s %s)" % (s1, self.op, s2) diff --git a/sqlobject/tests/test_mysql.py b/sqlobject/tests/test_mysql.py index 3d7b9a68..5f41bd96 100644 --- a/sqlobject/tests/test_mysql.py +++ b/sqlobject/tests/test_mysql.py @@ -1,5 +1,6 @@ import pytest -from sqlobject import SQLObject +from sqlobject import SQLObject, IntCol +from sqlobject.sqlbuilder import Select, ANY from sqlobject.tests.dbtest import getConnection, setupClass @@ -24,3 +25,16 @@ def test_list_databases(): def test_list_tables(): setupClass(SOTestSOListMySQL) assert SOTestSOListMySQL.sqlmeta.table in connection.listTables() + + +class SOTestANY(SQLObject): + value = IntCol() + + +def test_ANY(): + setupClass(SOTestANY) + SOTestANY(value=10) + SOTestANY(value=20) + SOTestANY(value=30) + assert len(list(SOTestANY.select( + SOTestANY.q.value > ANY(Select([SOTestANY.q.value]))))) == 2 diff --git a/sqlobject/tests/test_postgres.py b/sqlobject/tests/test_postgres.py index ab1f9692..dbe62c04 100644 --- a/sqlobject/tests/test_postgres.py +++ b/sqlobject/tests/test_postgres.py @@ -1,6 +1,7 @@ import os import pytest -from sqlobject import SQLObject, StringCol +from sqlobject import SQLObject, StringCol, IntCol +from sqlobject.sqlbuilder import Select, SOME from sqlobject.tests.dbtest import getConnection, setupClass @@ -56,3 +57,16 @@ def test_list_databases(): def test_list_tables(): setupClass(SOTestSOList) assert SOTestSOList.sqlmeta.table in connection.listTables() + + +class SOTestSOME(SQLObject): + value = IntCol() + + +def test_SOME(): + setupClass(SOTestSOME) + SOTestSOME(value=10) + SOTestSOME(value=20) + SOTestSOME(value=30) + assert len(list(SOTestSOME.select( + SOTestSOME.q.value > SOME(Select([SOTestSOME.q.value]))))) == 2 diff --git a/sqlobject/tests/test_sqlbuilder.py b/sqlobject/tests/test_sqlbuilder.py index 1d2c8501..5b9d3b41 100644 --- a/sqlobject/tests/test_sqlbuilder.py +++ b/sqlobject/tests/test_sqlbuilder.py @@ -1,7 +1,7 @@ from sqlobject import IntCol, SQLObject, StringCol from sqlobject.compat import PY2 -from sqlobject.sqlbuilder import AND, CONCAT, Delete, Insert, SQLOp, Select, \ - Union, Update, const, func, sqlrepr +from sqlobject.sqlbuilder import AND, ANY, CONCAT, Delete, Insert, \ + SQLConstant, SQLOp, Select, Union, Update, const, func, sqlrepr from sqlobject.tests.dbtest import getConnection, raises, setupClass @@ -119,3 +119,16 @@ def test_CONCAT(): if not PY2 and not isinstance(result, str): result = result.decode('ascii') assert result == "test-suffix" + + +def test_ANY(): + setupClass(SOTestSQLBuilder) + + select = Select( + [SOTestSQLBuilder.q.name], + SQLConstant("'value'") == ANY(SOTestSQLBuilder.q.so_value), + ) + + assert sqlrepr(select, 'mysql') == \ + "SELECT so_test_sql_builder.name FROM so_test_sql_builder " \ + "WHERE (('value') = ANY (so_test_sql_builder.so_value))" From ff5a94f43b4e221e9ae5986eea824fb642d309c0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 03:47:42 +0300 Subject: [PATCH 021/295] Fix escape sequences `'\%'` -> `'\\%'` --- docs/News.rst | 2 ++ sqlobject/tests/test_converters.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 3ca56b08..23c6f888 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -24,6 +24,8 @@ Tests * Fix module-level calls to ``pytest.mark.skip`` - add reasons. +* Fix escape sequences ``'\%'`` -> ``'\\%'``. + CI -- diff --git a/sqlobject/tests/test_converters.py b/sqlobject/tests/test_converters.py index 0468a75c..a064c69f 100644 --- a/sqlobject/tests/test_converters.py +++ b/sqlobject/tests/test_converters.py @@ -262,8 +262,8 @@ def test_timedelta(): def test_quote_unquote_str(): assert quote_str('test%', 'postgres') == "'test%'" assert quote_str('test%', 'sqlite') == "'test%'" - assert quote_str('test\%', 'postgres') == "E'test\\%'" - assert quote_str('test\\%', 'sqlite') == "'test\%'" + assert quote_str('test\\%', 'postgres') == "E'test\\%'" + assert quote_str('test\\%', 'sqlite') == "'test\\%'" assert unquote_str("'test%'") == 'test%' assert unquote_str("'test\\%'") == 'test\\%' assert unquote_str("E'test\\%'") == 'test\\%' From aa0af590862607300b0e4a695fcc6516d903a926 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 03:50:35 +0300 Subject: [PATCH 022/295] Fix sqlite test under Python 3.7+ at AppVeyor --- docs/News.rst | 2 ++ sqlobject/tests/test_sqlite.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 23c6f888..e8d7d991 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -32,6 +32,8 @@ CI * Reduce the number of virtual machines/containers: one OS, one DB, one python version, many drivers per VM. +* Fix sqlite test under Python 3.7+ at AppVeyor. + SQLObject 3.7.2 =============== diff --git a/sqlobject/tests/test_sqlite.py b/sqlobject/tests/test_sqlite.py index 5fb070b2..2ec1d422 100644 --- a/sqlobject/tests/test_sqlite.py +++ b/sqlobject/tests/test_sqlite.py @@ -140,7 +140,7 @@ def test_memorydb(): def test_list_databases(): - assert connection.listDatabases() == ['main'] + assert 'main' in connection.listDatabases() def test_list_tables(): From 6c54d9a0009d50a9859d2fa0b76103e2992a17de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 15:51:56 +0300 Subject: [PATCH 023/295] Docs(News): SQLObject 3.7.3 released 22 Sep 2019 --- docs/News.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index e8d7d991..d24ad0ac 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +SQLObject 3.7.3 +=============== + +Released 22 Sep 2019. + Bug fixes --------- From f31a1bc9c70cb0b1504b70d1dacd4ef18dc8cfb7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 15:59:34 +0300 Subject: [PATCH 024/295] Release 3.7.3 --- ANNOUNCE.rst | 41 +++++++++++++++++++++++++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- sqlobject/__version__.py | 4 ++-- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5cb28861..67323a9d 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,37 @@ Hello! -I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.7.3, a bugfix release of branch +3.7 of SQLObject. -I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.0b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.0rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +Bug fixes +--------- -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. +* Avoid excessive parentheses around ``ALL/ANY/SOME()``. -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +Tests +----- +* Add tests for cascade deletion. -What's new in SQLObject -======================= +* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. + +* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. + +* Fix module-level calls to ``pytest.mark.skip`` - add reasons. + +* Fix escape sequences ``'\%'`` -> ``'\\%'``. + +CI +-- + +* Reduce the number of virtual machines/containers: + one OS, one DB, one python version, many drivers per VM. + +* Fix sqlite test under Python 3.7+ at AppVeyor. Contributors for this release are @@ -54,7 +65,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ +https://pypi.org/project/SQLObject/3.7.3 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 404d1650..4348085e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.7.3a0 -================= +SQLObject 3.7.3 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index bcb5c7c7..65231745 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.7.2 && +build_docs 3.7.3 && build_docs master devel && rm -rf docs/html && diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 52a80488..0d929919 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.7.2' +version = '3.7.3' major = 3 minor = 7 -micro = 2 +micro = 3 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From d53e4f7d2110daa53c86c8c78e401f590da95a5a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 22 Sep 2019 16:08:24 +0300 Subject: [PATCH 025/295] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 41 +++++++++++++++-------------------------- README.rst | 4 ++-- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 67323a9d..5cb28861 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,37 +1,26 @@ Hello! -I'm pleased to announce version 3.7.3, a bugfix release of branch -3.7 of SQLObject. +I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -What's new in SQLObject -======================= - -Bug fixes ---------- - -* Avoid excessive parentheses around ``ALL/ANY/SOME()``. - -Tests ------ +I'm pleased to announce version 3.8.0b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Add tests for cascade deletion. +I'm pleased to announce version 3.8.0rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -* Fix module-level calls to ``pytest.mark.skip`` - add reasons. -* Fix escape sequences ``'\%'`` -> ``'\\%'``. - -CI --- - -* Reduce the number of virtual machines/containers: - one OS, one DB, one python version, many drivers per VM. - -* Fix sqlite test under Python 3.7+ at AppVeyor. +What's new in SQLObject +======================= Contributors for this release are @@ -65,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.7.3 +https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 4348085e..9f09e511 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.7.3 -=============== +SQLObject 3.8.0a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python From 351ac9230a1cb13ebeeddae9ab6b7b8c1dda1191 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Sep 2019 20:24:53 +0300 Subject: [PATCH 026/295] Fix a bug working with microseconds in `Time` columns --- docs/News.rst | 5 +++++ sqlobject/col.py | 6 +++++- sqlobject/mysql/mysqlconnection.py | 5 ----- sqlobject/tests/dbtest.py | 6 +----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index d24ad0ac..abb141b2 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Bug fixes +--------- + +* Fixed a bug working with microseconds in Time columns. + SQLObject 3.7.3 =============== diff --git a/sqlobject/col.py b/sqlobject/col.py index a22fb666..56752f40 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1505,7 +1505,11 @@ def to_python(self, value, state): raise validators.Invalid( "the value for the TimeCol '%s' must has days=0, " "it has days=%d" % (self.name, value.days), value, state) - return datetime.time(*time.gmtime(value.seconds)[3:6]) + print("[DEBUG1]:", value.microseconds) + return datetime.time( + *time.gmtime(value.seconds)[3:6], + microsecond=value.microseconds + ) value = super(TimeValidator, self).to_python(value, state) if isinstance(value, datetime.datetime): value = value.time() diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 2d7afa58..00cc3d65 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,5 +1,3 @@ -import os - from sqlobject import col, dberrors from sqlobject.compat import PY2 from sqlobject.dbconnection import DBAPI @@ -482,9 +480,6 @@ def server_version(self): def can_use_microseconds(self): if self._can_use_microseconds is not None: return self._can_use_microseconds - if os.environ.get('APPVEYOR') or os.environ.get('TRAVIS'): - self._can_use_microseconds = False - return False server_version = self.server_version() if server_version is None: return None diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index 6c0c8463..c7c8b0ea 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -120,11 +120,7 @@ def getConnectionURI(): if 'sphinx' not in sys.modules: print("Could not open database: %s" % e, file=sys.stderr) else: - if (connection.dbName == 'firebird') \ - or ( - (connection.dbName == 'mysql') - and ((os.environ.get('APPVEYOR')) or (os.environ.get('TRAVIS'))) - ): + if (connection.dbName == 'firebird'): use_microseconds(False) From 701fb3c7268fc96ab54c243feed58a4f7614403c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Sep 2019 20:25:23 +0300 Subject: [PATCH 027/295] Tests: Allow to run `flake8` under any Python version --- tox.ini | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tox.ini b/tox.ini index 899295c8..fb7ab87f 100644 --- a/tox.ini +++ b/tox.ini @@ -483,6 +483,30 @@ commands = {[testenv]commands} flake8 . +[testenv:py34-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + +[testenv:py35-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + +[testenv:py36-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + [testenv:py37-flake8] changedir = ./ deps = From f9822e7a2ad3558402dec8a552107b7328da938a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Sep 2019 20:31:39 +0300 Subject: [PATCH 028/295] Feat(sqlite): Add driver `supersqlite` --- docs/News.rst | 6 ++++++ docs/SQLObject.rst | 21 +++++++++++---------- docs/download.rst | 7 ++++++- setup.py | 1 + sqlobject/sqlite/sqliteconnection.py | 11 ++++++++--- tox.ini | 26 ++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 14 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index abb141b2..d795a697 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Features +-------- + +* Add driver ``supersqlite``. Not all tests are passing + so the driver isn't added to the list of default drivers. + Bug fixes --------- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 46d820ee..9504c1a2 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,14 +48,14 @@ Requirements Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, PyODBC_ -and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; -PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a -built-in driver or PySQLite_. Firebird_ is supported via fdb_ or -kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ -(also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL -Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and -PyPyODBC_ are supported for MySQL, PostgreSQL and MSSQL but have -problems (not all tests passed). +and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, +py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver, +PySQLite_ or supersqlite_. Firebird_ is supported via fdb_ or kinterbasdb_; +pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP +DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via +pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are +supported for MySQL, PostgreSQL and MSSQL but have problems (not all tests +passed). .. _MySQL: https://www.mysql.com/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ @@ -70,6 +70,7 @@ problems (not all tests passed). .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite +.. _supersqlite: https://github.com/plasticityai/supersqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ .. _fdb: http://www.firebirdsql.org/en/devel-python-driver/ .. _kinterbasdb: http://kinterbasdb.sourceforge.net/ @@ -1857,8 +1858,8 @@ multi-threaded environment. The user can choose a DB API driver for SQLite by using a ``driver`` parameter in DB URI or SQLiteConnection that can be a comma-separated list of driver names. Possible drivers are: ``pysqlite2`` (alias ``sqlite2``), -``sqlite3``, ``sqlite`` (alias ``sqlite1``). Default is to test pysqlite2, -sqlite3 and sqlite in that order. +``sqlite3``, ``sqlite`` (alias ``sqlite1``), ``supersqlite``. Default is to +test supersqlite, pysqlite2, sqlite3 and sqlite in that order. Connection-specific parameters are: ``encoding``, ``mode``, ``timeout``, ``check_same_thread``, ``use_table_info``. diff --git a/docs/download.rst b/docs/download.rst index 1d9e5467..0126343b 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -76,10 +76,15 @@ PostgreSQL psycopg2 psycopg postgres postgresql (synonyms for psycopg2) pygresql pypostgresql py-postgresql pg8000 +SQLite +^^^^^^ + +sqlite pysqlite supersqlite + The rest ^^^^^^^^ -sapdb sqlite (pysqlite) sybase +sapdb sybase Repositories ------------ diff --git a/setup.py b/setup.py index ca58f2eb..0af8a294 100755 --- a/setup.py +++ b/setup.py @@ -131,6 +131,7 @@ # 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], + 'supersqlite': ['supersqlite'], 'sybase': ['Sybase'], }, ) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 024b01c6..06cf3c43 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -32,13 +32,17 @@ class SQLiteConnection(DBAPI): schemes = [dbName] def __init__(self, filename, autoCommit=1, **kw): - drivers = kw.pop('driver', None) or 'pysqlite2,sqlite3,sqlite' + drivers = kw.pop('driver', None) or \ + 'supersqlite,pysqlite2,sqlite3,sqlite' for driver in drivers.split(','): driver = driver.strip() if not driver: continue try: - if driver in ('sqlite2', 'pysqlite2'): + if driver == 'supersqlite': + from supersqlite import sqlite3 as sqlite + self.using_sqlite2 = True + elif driver in ('sqlite2', 'pysqlite2'): from pysqlite2 import dbapi2 as sqlite self.using_sqlite2 = True elif driver == 'sqlite3': @@ -50,7 +54,8 @@ def __init__(self, filename, autoCommit=1, **kw): else: raise ValueError( 'Unknown SQLite driver "%s", ' - 'expected pysqlite2, sqlite3 or sqlite' % driver) + 'expected supersqlite, pysqlite2, sqlite3 ' + 'or sqlite' % driver) except ImportError: pass else: diff --git a/tox.ini b/tox.ini index fb7ab87f..65b21476 100644 --- a/tox.ini +++ b/tox.ini @@ -29,6 +29,7 @@ deps = postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 pyodbc: pyodbc pypyodbc: pypyodbc + supersqlite: supersqlite firebird-fdb: fdb firebirdsql: firebirdsql passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR @@ -423,6 +424,31 @@ commands = {[sqlite-memory]commands} [testenv:py37-sqlite-memory] commands = {[sqlite-memory]commands} +[sqlite-supersqlite] +commands = + {[testenv]commands} + -rm -f /tmp/sqlobject_test.sqdb + -pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1 + rm -f /tmp/sqlobject_test.sqdb + +[testenv:py27-sqlite-supersqlite] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[sqlite-supersqlite]commands} + +[testenv:py34-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + +[testenv:py35-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + +[testenv:py36-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + +[testenv:py37-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + + # Firebird database test environments [fdb] commands = From 852bded59e5c7da4e118d6b54c1097f8a32fcf67 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Sep 2019 19:00:52 +0300 Subject: [PATCH 029/295] Fix a bug in cascade deletion/nullification --- docs/News.rst | 2 + sqlobject/col.py | 9 ++++- sqlobject/main.py | 47 +++++++++++++--------- sqlobject/tests/test_ForeignKey_cascade.py | 35 +++++++++++++--- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index d795a697..5b63bba6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,8 @@ Features Bug fixes --------- +* Fixed a bug in cascade deletion/nullification. + * Fixed a bug working with microseconds in Time columns. SQLObject 3.7.3 diff --git a/sqlobject/col.py b/sqlobject/col.py index 56752f40..be8571cd 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -170,8 +170,13 @@ def __init__(self, # True: a CASCADE constraint is generated # False: a RESTRICT constraint is generated # 'null': a SET NULL trigger is generated - if isinstance(cascade, str): - assert cascade == 'null', ( + if not isinstance(cascade, (bool, string_type, type(None))): + raise TypeError( + 'Expected cascade to be True, False, None or "null", ' + "(you gave: %r %r)" % (type(cascade), cascade) + ) + if isinstance(cascade, str) and (cascade != 'null'): + raise ValueError( "The only string value allowed for cascade is 'null' " "(you gave: %r)" % cascade) self.cascade = cascade diff --git a/sqlobject/main.py b/sqlobject/main.py index 488b9924..827db2cd 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -1639,36 +1639,45 @@ def destroySelf(self): continue query = [] - delete = setnull = restrict = False + restrict = False for _col in cols: + query.append(getattr(k.q, _col.name) == self.id) if _col.cascade is False: # Found a restriction restrict = True - query.append(getattr(k.q, _col.name) == self.id) + query = sqlbuilder.OR(*query) + results = k.select(query, connection=self._connection) + if restrict and results.count(): + # Restrictions only apply if there are + # matching records on the related table + raise SQLObjectIntegrityError( + "Tried to delete %s::%s but " + "table %s has a restriction against it" % + (klass.__name__, self.id, k.__name__)) + + setnull = {} + for _col in cols: if _col.cascade == 'null': - setnull = _col.name - elif _col.cascade: + setnull[_col.name] = None + if setnull: + for row in results: + clear = {} + for name in setnull: + if getattr(row, name) == self.id: + clear[name] = None + row.set(**clear) + + delete = False + for _col in cols: + if _col.cascade is True: delete = True assert delete or setnull or restrict, ( "Class %s depends on %s accoriding to " "findDependantColumns, but this seems inaccurate" % (k, klass)) - query = sqlbuilder.OR(*query) - results = k.select(query, connection=self._connection) - if restrict: - if results.count(): - # Restrictions only apply if there are - # matching records on the related table - raise SQLObjectIntegrityError( - "Tried to delete %s::%s but " - "table %s has a restriction against it" % - (klass.__name__, self.id, k.__name__)) - else: + if delete: for row in results: - if delete: - row.destroySelf() - else: - row.set(**{setnull: None}) + row.destroySelf() self.sqlmeta._obsolete = True self._connection._SO_delete(self) diff --git a/sqlobject/tests/test_ForeignKey_cascade.py b/sqlobject/tests/test_ForeignKey_cascade.py index d4a10612..e8942b58 100644 --- a/sqlobject/tests/test_ForeignKey_cascade.py +++ b/sqlobject/tests/test_ForeignKey_cascade.py @@ -90,10 +90,17 @@ def test3(): message.sync() raises(SQLObjectNotFound, emily.sync) - assert message.recipient is None + assert message.sender is None + assert message.recipient == john - # This looks like a bug; `message.sender` here should be None - # assert message.sender is None + SOTestPerson3.delete(john.id) + john.expire() + message.expire() + + message.sync() + raises(SQLObjectNotFound, john.sync) + + assert message.recipient is None class SOTestPerson4(SQLObject): @@ -120,6 +127,24 @@ def test4(): message.expire() john.sync() + raises(SQLObjectNotFound, message.sync) + - # This is even a nastier bug; `message` was deleted from the DB - # message.sync() +def test5(): + setupClass([SOTestPerson4, SOTestMessageCascadeMixed]) + + john = SOTestPerson4(name='john') + emily = SOTestPerson4(name='emily') + message = SOTestMessageCascadeMixed( + sender=emily, recipient=john, body='test5' + ) + + john.destroySelf() + emily.expire() + message.expire() + + emily.sync() + message.sync() + + assert message.recipient is None + assert message.sender == emily From 596704cd6be8970c26b200df32cfa335c0d2bf50 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 30 Sep 2019 23:00:22 +0300 Subject: [PATCH 030/295] Feat(sqlbuilder): Improve sqlrepr'ing `ALL/ANY/SOME()` --- docs/News.rst | 6 ++++++ sqlobject/sqlbuilder.py | 2 ++ sqlobject/tests/test_sqlbuilder.py | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 5b63bba6..425aa1af 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,12 @@ Features * Add driver ``supersqlite``. Not all tests are passing so the driver isn't added to the list of default drivers. +Minor features +-------------- + +* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression + at the right side of the comparison operation. + Bug fixes --------- diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index d6c2e619..844ab9ea 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -300,6 +300,8 @@ def tablesUsedSet(obj, db): class SQLOp(SQLExpression): def __init__(self, op, expr1, expr2): self.op = op.upper() + if isinstance(expr1, Subquery): + expr1, expr2 = expr2, expr1 self.expr1 = expr1 self.expr2 = expr2 diff --git a/sqlobject/tests/test_sqlbuilder.py b/sqlobject/tests/test_sqlbuilder.py index 5b9d3b41..1b198fc2 100644 --- a/sqlobject/tests/test_sqlbuilder.py +++ b/sqlobject/tests/test_sqlbuilder.py @@ -1,7 +1,7 @@ from sqlobject import IntCol, SQLObject, StringCol from sqlobject.compat import PY2 from sqlobject.sqlbuilder import AND, ANY, CONCAT, Delete, Insert, \ - SQLConstant, SQLOp, Select, Union, Update, const, func, sqlrepr + SQLOp, Select, Union, Update, const, func, sqlrepr from sqlobject.tests.dbtest import getConnection, raises, setupClass @@ -126,7 +126,7 @@ def test_ANY(): select = Select( [SOTestSQLBuilder.q.name], - SQLConstant("'value'") == ANY(SOTestSQLBuilder.q.so_value), + 'value' == ANY(SOTestSQLBuilder.q.so_value), ) assert sqlrepr(select, 'mysql') == \ From cdf61fad45dc594f28ebb2b56ae0adc931f615f1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 1 Nov 2019 17:51:52 +0300 Subject: [PATCH 031/295] CI: Run tests with Python 3.8 at Travis CI Add Python 3.8 to `setup.py` and `devscripts/setup`. --- .travis.yml | 13 +++++- devscripts/setup | 2 +- docs/News.rst | 5 ++ setup.py | 1 + tox.ini | 118 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 135 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8fe81bad..a674f2d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,9 @@ matrix: - python: "3.7" dist: xenial env: TESTS=py37-mysql + - python: "3.8" + dist: xenial + env: TESTS=py38-mysql - python: "2.7" env: TESTS=py27-postgres - python: "3.4" @@ -43,6 +46,9 @@ matrix: - python: "3.7" dist: xenial env: TESTS=py37-postgres + - python: "3.8" + dist: xenial + env: TESTS=py38-postgres - python: "2.7" env: TESTS=py27-sqlite - python: "3.4" @@ -54,11 +60,14 @@ matrix: - python: "3.7" dist: xenial env: TESTS=py37-sqlite + - python: "3.8" + dist: xenial + env: TESTS=py38-sqlite - python: "2.7" env: TESTS=py27-flake8 - - python: "3.7" + - python: "3.8" dist: xenial - env: TESTS=py37-flake8 + env: TESTS=py38-flake8 - python: "2.7" env: TESTS=py27-firebird - python: "3.6" diff --git a/devscripts/setup b/devscripts/setup index 04ed1b78..3c12824d 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -3,7 +3,7 @@ umask 022 # -rwxr-xr-x cd "`dirname \"$0\"`"/.. && -for py_ver in 2.7 3.4 3.5 3.6 3.7; do +for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8; do python$py_ver -m pip install --install-option=-O2 --upgrade . done && diff --git a/docs/News.rst b/docs/News.rst index 425aa1af..24ad6612 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -27,6 +27,11 @@ Bug fixes * Fixed a bug working with microseconds in Time columns. +CI +-- + +* Run tests with Python 3.8 at Travis CI. + SQLObject 3.7.3 =============== diff --git a/setup.py b/setup.py index 0af8a294..d85791d3 100755 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 65b21476..9be1d8bc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py{27,34,35,36,37}-sqlite{,-memory},py{27,37}-flake8 +envlist = py{27,34,35,36,37,38}-sqlite{,-memory},py{27,38}-flake8 # Base test environment settings [testenv] @@ -12,6 +12,7 @@ basepython = py35: {env:TOXPYTHON:python3.5} py36: {env:TOXPYTHON:python3.6} py37: {env:TOXPYTHON:python3.7} + py38: {env:TOXPYTHON:python3.8} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" @@ -75,6 +76,10 @@ deps = commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = +[testenv:py38-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + [mysqlclient] commands = {[testenv]commands} @@ -99,6 +104,9 @@ commands = {[mysqlclient]commands} [testenv:py37-mysqlclient] commands = {[mysqlclient]commands} +[testenv:py38-mysqlclient] +commands = {[mysqlclient]commands} + [mysql-connector] commands = {[testenv]commands} @@ -124,6 +132,9 @@ commands = {[mysql-connector]commands} [testenv:py37-mysql-connector] commands = {[mysql-connector]commands} +[testenv:py38-mysql-connector] +commands = {[mysql-connector]commands} + [oursql] commands = {[testenv]commands} @@ -149,6 +160,9 @@ commands = {[oursql]commands} [testenv:py37-mysql-oursql3] commands = {[oursql]commands} +[testenv:py38-mysql-oursql3] +commands = {[oursql]commands} + [pymysql] commands = {[testenv]commands} @@ -174,6 +188,9 @@ commands = {[pymysql]commands} [testenv:py37-mysql-pymysql] commands = {[pymysql]commands} +[testenv:py38-mysql-pymysql] +commands = {[pymysql]commands} + [mysql-pyodbc] commands = {[testenv]commands} @@ -200,6 +217,9 @@ commands = {[mysql-pyodbc]commands} [testenv:py37-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} +[testenv:py38-mysql-pyodbc-noauto] +commands = {[mysql-pyodbc]commands} + [mysql-pypyodbc] commands = {[testenv]commands} @@ -225,6 +245,9 @@ commands = {[mysql-pypyodbc]commands} [testenv:py37-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} +[testenv:py38-mysql-pypyodbc-noauto] +commands = {[mysql-pypyodbc]commands} + # PostgreSQL test environments [psycopg] commands = @@ -251,6 +274,9 @@ commands = {[psycopg]commands} [testenv:py37-postgres-psycopg] commands = {[psycopg]commands} +[testenv:py38-postgres-psycopg] +commands = {[psycopg]commands} + [pygresql] commands = {[testenv]commands} @@ -276,6 +302,9 @@ commands = {[pygresql]commands} [testenv:py37-postgres-pygresql] commands = {[pygresql]commands} +[testenv:py38-postgres-pygresql] +commands = {[pygresql]commands} + [pypostgresql] commands = {[testenv]commands} @@ -300,6 +329,9 @@ commands = {[pypostgresql]commands} [testenv:py37-postgres-pypostgresql] commands = {[pypostgresql]commands} +[testenv:py38-postgres-pypostgresql] +commands = {[pypostgresql]commands} + [pg8000] commands = {[testenv]commands} @@ -325,6 +357,9 @@ commands = {[pg8000]commands} [testenv:py37-postgres-pg8000] commands = {[pg8000]commands} +[testenv:py38-postgres-pg8000] +commands = {[pg8000]commands} + [postgres-pyodbc] commands = {[testenv]commands} @@ -351,6 +386,9 @@ commands = {[postgres-pyodbc]commands} [testenv:py37-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} +[testenv:py38-postgres-pyodbc-noauto] +commands = {[postgres-pyodbc]commands} + [postgres-pypyodbc] commands = {[testenv]commands} @@ -376,6 +414,9 @@ commands = {[postgres-pypyodbc]commands} [testenv:py37-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} +[testenv:py38-postgres-pypyodbc-noauto] +commands = {[postgres-pypyodbc]commands} + # SQLite test environments [sqlite] @@ -402,6 +443,9 @@ commands = {[sqlite]commands} [testenv:py37-sqlite] commands = {[sqlite]commands} +[testenv:py38-sqlite] +commands = {[sqlite]commands} + [sqlite-memory] commands = {[testenv]commands} @@ -424,6 +468,9 @@ commands = {[sqlite-memory]commands} [testenv:py37-sqlite-memory] commands = {[sqlite-memory]commands} +[testenv:py38-sqlite-memory] +commands = {[sqlite-memory]commands} + [sqlite-supersqlite] commands = {[testenv]commands} @@ -448,6 +495,9 @@ commands = {[sqlite-supersqlite]commands} [testenv:py37-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} +[testenv:py38-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + # Firebird database test environments [fdb] @@ -475,6 +525,9 @@ commands = {[fdb]commands} [testenv:py37-firebird-fdb] commands = {[fdb]commands} +[testenv:py38-firebird-fdb] +commands = {[fdb]commands} + [firebirdsql] commands = {[testenv]commands} @@ -500,6 +553,9 @@ commands = {[firebirdsql]commands} [testenv:py37-firebirdsql] commands = {[firebirdsql]commands} +[testenv:py38-firebirdsql] +commands = {[firebirdsql]commands} + # Special test environments [testenv:py27-flake8] changedir = ./ @@ -541,6 +597,14 @@ commands = {[testenv]commands} flake8 . +[testenv:py38-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + # Windows testing [mssql-pyodbc-w32] platform = win32 @@ -575,6 +639,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mssql-pyodbc-w32]commands} +[testenv:py38-mssql-pyodbc-noauto-w32] +platform = win32 +commands = {[mssql-pyodbc-w32]commands} + [mysql-connector-w32] platform = win32 commands = @@ -608,6 +676,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-connector-w32]commands} +[testenv:py38-mysql-connector-w32] +platform = win32 +commands = {[mysql-connector-w32]commands} + [pymysql-w32] platform = win32 commands = @@ -641,6 +713,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pymysql-w32]commands} +[testenv:py38-mysql-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = @@ -675,6 +751,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pyodbc-w32]commands} +[testenv:py38-mysql-pyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pyodbc-w32]commands} + [mysql-pypyodbc-w32] platform = win32 commands = @@ -709,6 +789,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[mysql-pypyodbc-w32]commands} +[testenv:py38-mysql-pypyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pypyodbc-w32]commands} + [psycopg-w32] platform = win32 commands = @@ -742,6 +826,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[psycopg-w32]commands} +[testenv:py38-postgres-psycopg-w32] +platform = win32 +commands = {[psycopg-w32]commands} + [pygresql-w32] platform = win32 commands = @@ -775,6 +863,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pygresql-w32]commands} +[testenv:py38-postgres-pygresql-w32] +platform = win32 +commands = {[pygresql-w32]commands} + [pypostgresql-w32] platform = win32 commands = @@ -807,6 +899,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pypostgresql-w32]commands} +[testenv:py38-postgres-pypostgresql-w32] +platform = win32 +commands = {[pypostgresql-w32]commands} + [pg8000-w32] platform = win32 commands = @@ -840,6 +936,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[pg8000-w32]commands} +[testenv:py38-postgres-pg8000-w32] +platform = win32 +commands = {[pg8000-w32]commands} + [postgres-pyodbc-w32] platform = win32 commands = @@ -874,6 +974,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pyodbc-w32]commands} +[testenv:py38-postgres-pyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pyodbc-w32]commands} + [postgres-pypyodbc-w32] platform = win32 commands = @@ -908,6 +1012,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[postgres-pypyodbc-w32]commands} +[testenv:py38-postgres-pypyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pypyodbc-w32]commands} + [sqlite-w32] platform = win32 commands = @@ -938,6 +1046,10 @@ commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-w32]commands} +[testenv:py38-sqlite-w32] +platform = win32 +commands = {[sqlite-w32]commands} + [sqlite-memory-w32] platform = win32 commands = @@ -967,3 +1079,7 @@ platform = win32 commands = cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" {[sqlite-memory-w32]commands} + +[testenv:py38-sqlite-memory-w32] +platform = win32 +commands = {[sqlite-memory-w32]commands} From 83fd61d2d8ef1231291fee1aa650af6f58098342 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 14 Nov 2019 20:23:05 +0300 Subject: [PATCH 032/295] Fix(postgres): Fix a bug in `PostgresConnection.columnsFromSchema` PostgreSQL 12 removed outdated catalog attribute `pg_catalog.pg_attrdef.adsrc`. --- docs/News.rst | 4 ++++ sqlobject/postgres/pgconnection.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 24ad6612..a68b7395 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -25,6 +25,10 @@ Bug fixes * Fixed a bug in cascade deletion/nullification. +* Fixed a bug in ``PostgresConnection.columnsFromSchema``: + PostgreSQL 12 removed outdated catalog attribute + ``pg_catalog.pg_attrdef.adsrc``. + * Fixed a bug working with microseconds in Time columns. CI diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index afe81333..85a50945 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -353,7 +353,8 @@ def columnsFromSchema(self, tableName, soClass): colQuery = """ SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), a.attnotnull, - (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d + (SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128) + FROM pg_catalog.pg_attrdef d WHERE d.adrelid=a.attrelid AND d.adnum = a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid =%s::regclass From 0e6ca33cc343ac7910bee9c34a0a33d0d9d3a192 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 21 Nov 2019 15:43:25 +0300 Subject: [PATCH 033/295] Tests(tox-select-envs.cmd): Exit the batch with an error [skip ci] --- devscripts/tox-select-envs.cmd | 1 + 1 file changed, 1 insertion(+) diff --git a/devscripts/tox-select-envs.cmd b/devscripts/tox-select-envs.cmd index 03d8b4e1..1aa15195 100644 --- a/devscripts/tox-select-envs.cmd +++ b/devscripts/tox-select-envs.cmd @@ -15,4 +15,5 @@ if not "%envs%"=="" ( tox -e "%envs%" %* ) else ( echo "No environments match %pattern%" >&2 + exit /b 1 ) From b0b1c9c3610f9b52ea80c815a93cf49241081497 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 7 Dec 2019 20:27:56 +0300 Subject: [PATCH 034/295] Release 3.8.0 --- ANNOUNCE.rst | 45 +++++++++++++++++++++++++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 6 +++--- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5cb28861..fe822ef1 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,41 @@ Hello! -I'm pleased to announce version 3.8.0a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -I'm pleased to announce version 3.8.0a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.0b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.0rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +Features +-------- -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. +* Add driver ``supersqlite``. Not all tests are passing + so the driver isn't added to the list of default drivers. -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +Minor features +-------------- +* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression + at the right side of the comparison operation. -What's new in SQLObject -======================= +Bug fixes +--------- + +* Fixed a bug in cascade deletion/nullification. + +* Fixed a bug in ``PostgresConnection.columnsFromSchema``: + PostgreSQL 12 removed outdated catalog attribute + ``pg_catalog.pg_attrdef.adsrc``. + +* Fixed a bug working with microseconds in Time columns. + +CI +-- + +* Run tests with Python 3.8 at Travis CI. -Contributors for this release are +Contributors for this release are Andrew Trusty, Marco Sirabella and darix. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +67,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0a0.dev20190501/ +https://pypi.org/project/SQLObject/3.8.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 9f09e511..92962cf6 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.8.0a0 -================= +SQLObject 3.8.0 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 65231745..349c6ed8 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.7.3 && +build_docs 3.8.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index a68b7395..9012621b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.8.0 +=============== + +Released 7 Dec 2019. Features -------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 0d929919..763a4a41 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.7.3' +version = '3.8.0' major = 3 -minor = 7 -micro = 3 +minor = 8 +micro = 0 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 0783e77bcfe6511483f864ebb152d306d858758f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 7 Dec 2019 20:41:37 +0300 Subject: [PATCH 035/295] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 45 ++++++++++++++++----------------------------- README.rst | 2 +- docs/News.rst | 3 +++ 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index fe822ef1..38444044 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,41 +1,28 @@ Hello! -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. - - -What's new in SQLObject -======================= - -Features --------- +I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. -* Add driver ``supersqlite``. Not all tests are passing - so the driver isn't added to the list of default drivers. +I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -Minor features --------------- +I'm pleased to announce version 3.8.1b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression - at the right side of the comparison operation. +I'm pleased to announce version 3.8.1rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -Bug fixes ---------- - -* Fixed a bug in cascade deletion/nullification. - -* Fixed a bug in ``PostgresConnection.columnsFromSchema``: - PostgreSQL 12 removed outdated catalog attribute - ``pg_catalog.pg_attrdef.adsrc``. +I'm pleased to announce version 3.8.0, the first stable release of branch +3.8 of SQLObject. -* Fixed a bug working with microseconds in Time columns. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -CI --- -* Run tests with Python 3.8 at Travis CI. +What's new in SQLObject +======================= -Contributors for this release are Andrew Trusty, Marco Sirabella and darix. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -67,7 +54,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.0 +https://pypi.org/project/SQLObject/3.8.1a0.dev20191208/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 92962cf6..88ecfac9 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.8.0 +SQLObject 3.8.1 =============== Thanks for looking at SQLObject. SQLObject is an object-relational diff --git a/docs/News.rst b/docs/News.rst index 9012621b..089f671e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.8.0 =============== From a92401156915a9b82553c7202566cc11d647cb0f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 25 Feb 2020 23:20:18 +0300 Subject: [PATCH 036/295] CI(Travis): Set default OS to `linux`, dist to `xenial` Default dist is `xenial` anyway. --- .travis.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index a674f2d7..7a6a950e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ +os: linux + +dist: xenial + language: python python: @@ -30,10 +34,8 @@ matrix: - python: "3.6" env: TESTS=py36-mysql - python: "3.7" - dist: xenial env: TESTS=py37-mysql - python: "3.8" - dist: xenial env: TESTS=py38-mysql - python: "2.7" env: TESTS=py27-postgres @@ -44,10 +46,8 @@ matrix: - python: "3.6" env: TESTS=py36-postgres - python: "3.7" - dist: xenial env: TESTS=py37-postgres - python: "3.8" - dist: xenial env: TESTS=py38-postgres - python: "2.7" env: TESTS=py27-sqlite @@ -58,15 +58,12 @@ matrix: - python: "3.6" env: TESTS=py36-sqlite - python: "3.7" - dist: xenial env: TESTS=py37-sqlite - python: "3.8" - dist: xenial env: TESTS=py38-sqlite - python: "2.7" env: TESTS=py27-flake8 - python: "3.8" - dist: xenial env: TESTS=py38-flake8 - python: "2.7" env: TESTS=py27-firebird From df601fd23785c2be0d36492d6b8710f66c24cc58 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Feb 2020 00:36:46 +0300 Subject: [PATCH 037/295] CI(Travis): Remove duplicate Firebird tests --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a6a950e..1d54f6b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -69,16 +69,10 @@ matrix: env: TESTS=py27-firebird - python: "3.6" env: TESTS=py36-firebird - - python: "2.7" - env: TESTS=py27-firebird - - python: "3.6" - env: TESTS=py36-firebird allow_failures: - env: TESTS=py27-firebird - env: TESTS=py36-firebird - - env: TESTS=py27-firebird - - env: TESTS=py36-firebird fast_finish: true From 0252ba226b81eedbaba6d1d169d1c692632f17fe Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Feb 2020 00:37:29 +0300 Subject: [PATCH 038/295] CI(AppVeyor): Run tests with Python 3.8 --- appveyor.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 0bd35764..4d2f86b4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,6 +40,11 @@ environment: PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: mysql + - TESTS: "py38-mysql" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" + db: mysql - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -55,6 +60,11 @@ environment: PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" db: postgresql + - TESTS: "py38-postgres" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" + db: postgresql - TESTS: "py27-sqlite" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -67,6 +77,10 @@ environment: PYTHON_ARCH: "64" PYTHON_VERSION: "3.7" PYTHON_HOME: "C:\\Python37-x64" + - TESTS: "py38-sqlite" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" matrix: fast_finish: true From ab6bfb9b2246bff936a2ec6e3efa746c499f0824 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Feb 2020 00:37:49 +0300 Subject: [PATCH 039/295] Tests(tox): Refactor the list of environments --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9be1d8bc..41619f20 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py{27,34,35,36,37,38}-sqlite{,-memory},py{27,38}-flake8 +envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,38}-flake8 # Base test environment settings [testenv] From 04f9060c15c0ca1fcf0d82ce03d10e458958ed11 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2020 15:10:33 +0300 Subject: [PATCH 040/295] Limit `setuptools<44` for Python 2.7 --- .travis.yml | 2 +- appveyor.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d54f6b8..1e4feb51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,7 +94,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db; fi -install: travis_retry pip install --upgrade "pip < 19.1" setuptools tox coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<19.1" "setuptools<44" tox coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 4d2f86b4..778e9f51 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -91,8 +91,8 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip < 19.1\" setuptools" - - "pip install --upgrade \"tox < 3.1\" ppu" + - "python -m pip install --upgrade \"pip<19.1\" \"setuptools<44\"" + - "pip install --upgrade \"tox<3.1\" ppu" - "pip --version" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name From 7b0bab102f7c80333ade797341846c177020adb7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 4 May 2020 21:36:48 +0300 Subject: [PATCH 041/295] Tests(tox): Delete SQLite database under w32 --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 41619f20..7de2551d 100644 --- a/tox.ini +++ b/tox.ini @@ -1021,6 +1021,7 @@ platform = win32 commands = {[testenv]commands} pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 + cmd /c "del C:\projects\sqlobject\sqlobject_test.sqdb" [testenv:py27-sqlite-w32] platform = win32 From 0266ac96332b82b768afd8344f8a6a2ea8fe1ef2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 4 May 2020 21:38:06 +0300 Subject: [PATCH 042/295] Tests: Add `test-sqlobject.cmd` --- devscripts/test-sqlobject.cmd | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 devscripts/test-sqlobject.cmd diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd new file mode 100644 index 00000000..53b7cab5 --- /dev/null +++ b/devscripts/test-sqlobject.cmd @@ -0,0 +1,16 @@ +@echo off + +SetLocal EnableDelayedExpansion +set SavePATH=%PATH% + +for %%V in (27 34 35 36 37 38) do ( + for %%s in (32 64) do ( + set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! + set TOXPYTHON=C:\Python%%V-%%s\python.exe + !TOXPYTHON! -m tox -e "py%%V-sqlite{-memory,}-w32" + if !ERRORLEVEL! EQU 0 (echo Ok) else (echo Error && goto Quit) + ) +) + +:Quit +set PATH=%SavePATH% From eb00dff007fb8e16d4ebebae6860f305ae4cf54b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 6 May 2020 23:22:39 +0300 Subject: [PATCH 043/295] CI: pip<21 for Python 2.7 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e4feb51..e1760350 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,7 +94,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db; fi -install: travis_retry pip install --upgrade "pip<19.1" "setuptools<44" tox coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<21" "setuptools<44" tox coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 778e9f51..e5f00a6e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -91,7 +91,7 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip<19.1\" \"setuptools<44\"" + - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" - "pip install --upgrade \"tox<3.1\" ppu" - "pip --version" # List ODBC drivers From 51d38936203e9f1881d60efe63cee694216ff0f7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 03:31:51 +0300 Subject: [PATCH 044/295] Fix(col.TimeValidator): Remove debug print --- sqlobject/col.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index be8571cd..9bbde2a6 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1510,7 +1510,6 @@ def to_python(self, value, state): raise validators.Invalid( "the value for the TimeCol '%s' must has days=0, " "it has days=%d" % (self.name, value.days), value, state) - print("[DEBUG1]:", value.microseconds) return datetime.time( *time.gmtime(value.seconds)[3:6], microsecond=value.microseconds From 7b2279dec80985a485976f6a0a264bd0d021e06e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 18:48:59 +0300 Subject: [PATCH 045/295] Fix `PyGreSQL` version for Python 3.4 --- devscripts/requirements/requirements_pygresql.txt | 2 ++ docs/News.rst | 5 +++++ tox.ini | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 devscripts/requirements/requirements_pygresql.txt diff --git a/devscripts/requirements/requirements_pygresql.txt b/devscripts/requirements/requirements_pygresql.txt new file mode 100644 index 00000000..ea4052ca --- /dev/null +++ b/devscripts/requirements/requirements_pygresql.txt @@ -0,0 +1,2 @@ +pygresql<5.2; python_version == '3.4' +pygresql; python_version != '3.4' diff --git a/docs/News.rst b/docs/News.rst index 089f671e..374899ce 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests +----- + +* Fix ``PyGreSQL`` version for Python 3.4. + SQLObject 3.8.0 =============== diff --git a/tox.ini b/tox.ini index 7de2551d..1a21ebb5 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,7 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: pymysql postgres-psycopg: psycopg2-binary - postgres-pygresql: pygresql + pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 pyodbc: pyodbc From f25602178eab6e148be25cdf87ba4bd5744d0838 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 18:51:22 +0300 Subject: [PATCH 046/295] Style: Fix `flake8` E741 ambiguous variable name 'l' --- sqlobject/constraints.py | 4 ++-- sqlobject/manager/command.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sqlobject/constraints.py b/sqlobject/constraints.py index 9241579f..1b8bd0fe 100644 --- a/sqlobject/constraints.py +++ b/sqlobject/constraints.py @@ -51,8 +51,8 @@ def isBool(obj, col, value): class InList: - def __init__(self, l): - self.list = l + def __init__(self, _l): + self.list = _l def __call__(self, obj, col, value): if value not in self.list: diff --git a/sqlobject/manager/command.py b/sqlobject/manager/command.py index e9891d91..fc8db834 100755 --- a/sqlobject/manager/command.py +++ b/sqlobject/manager/command.py @@ -1095,8 +1095,8 @@ def update_db(self, version, conn): connection=conn) def strip_comments(self, sql): - lines = [l for l in sql.splitlines() - if not l.strip().startswith('--')] + lines = [_l for _l in sql.splitlines() + if not _l.strip().startswith('--')] return '\n'.join(lines) def base_dir(self): From dfedb4e3f88f71b17b96559cb89080e4c1c967bb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 18:53:06 +0300 Subject: [PATCH 047/295] Style: Fix `flake8` warnings E124 closing bracket does not match visual indentation E128 continuation line under-indented for visual indent --- sqlobject/dbconnection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 0b9fd02d..e3de62e8 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -1071,9 +1071,9 @@ def registerConnection(self, schemes, builder): def registerConnectionInstance(self, inst): if inst.name: assert (inst.name not in self.instanceNames - or self.instanceNames[inst.name] is cls # noqa - ), ("A instance has already been registered " - "with the name %s" % inst.name) + or self.instanceNames[inst.name] is cls # noqa + ), ("A instance has already been registered " + "with the name %s" % inst.name) assert inst.name.find(':') == -1, \ "You cannot include ':' " \ "in your class names (%r)" % cls.name # noqa From 551063155c71b177345fc5cfb8bcbd238aa17eac Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Jun 2020 23:08:26 +0300 Subject: [PATCH 048/295] CI(AppVeyor): Ignore errors with `PyGreSQL` --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1a21ebb5..51855a57 100644 --- a/tox.ini +++ b/tox.ini @@ -836,7 +836,7 @@ commands = {[testenv]commands} -dropdb -U postgres -w sqlobject_test createdb -U postgres -w sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + -pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb -U postgres -w sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] From 7b85a599c0989780aed68feed24c2ebef8d5c9f9 Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 21 Aug 2020 13:42:15 +0200 Subject: [PATCH 049/295] Use conf.py options to exclude sqlmeta options This aims to fix the same issue as in #147, but fixing the problem that genapi docs will override the rst files and lose the exclusions. --- docs/conf.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index f8272ab1..b6e460e3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,6 +35,11 @@ 'sphinx.ext.viewcode', ] +# Exclude uninformative members from the api docs +autodoc_default_options = { + 'exclude-members': 'columnDefinitions,columnList,columns,indexDefinitions' +} + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From a2d90177d185c9c1f6ed6b2425e35262fa70ad18 Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 22 Aug 2020 08:41:31 +0200 Subject: [PATCH 050/295] Rerun genapidocs and new & updated files --- docs/api/sqlobject.tests.rst | 1 + docs/api/sqlobject.tests.test_ForeignKey_cascade.rst | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 docs/api/sqlobject.tests.test_ForeignKey_cascade.rst diff --git a/docs/api/sqlobject.tests.rst b/docs/api/sqlobject.tests.rst index 6cf2f130..fcab4e81 100644 --- a/docs/api/sqlobject.tests.rst +++ b/docs/api/sqlobject.tests.rst @@ -13,6 +13,7 @@ Submodules sqlobject.tests.dbtest sqlobject.tests.test_ForeignKey + sqlobject.tests.test_ForeignKey_cascade sqlobject.tests.test_NoneValuedResultItem sqlobject.tests.test_SQLMultipleJoin sqlobject.tests.test_SQLRelatedJoin diff --git a/docs/api/sqlobject.tests.test_ForeignKey_cascade.rst b/docs/api/sqlobject.tests.test_ForeignKey_cascade.rst new file mode 100644 index 00000000..cbe1c448 --- /dev/null +++ b/docs/api/sqlobject.tests.test_ForeignKey_cascade.rst @@ -0,0 +1,7 @@ +sqlobject.tests.test\_ForeignKey\_cascade module +================================================ + +.. automodule:: sqlobject.tests.test_ForeignKey_cascade + :members: + :undoc-members: + :show-inheritance: From cb7575ab2050260311e6ace0226917dfdeb3dfbc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 1 Oct 2020 18:00:14 +0300 Subject: [PATCH 051/295] Release 3.8.1 --- ANNOUNCE.rst | 33 +++++++++++++++++---------------- devscripts/build-all-docs | 2 +- docs/News.rst | 16 ++++++++++++++-- sqlobject/__version__.py | 4 ++-- 4 files changed, 34 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 38444044..5cfb5180 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,29 @@ Hello! -I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.8.1, the first bugfix release of branch +3.8 of SQLObject. -I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.1b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.1rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +The contributor for this release is Neil Muller. -I'm pleased to announce version 3.8.0, the first stable release of branch -3.8 of SQLObject. +Documentation +------------- -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. +* Use conf.py options to exclude sqlmeta options. +Tests +----- -What's new in SQLObject -======================= +* Fix ``PyGreSQL`` version for Python 3.4. + +CI +-- + +* Run tests with Python 3.8 at AppVeyor. -Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +55,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.1a0.dev20191208/ +https://pypi.org/project/SQLObject/3.8.1 News and changes: http://sqlobject.org/News.html diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 349c6ed8..4eab6205 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.8.0 && +build_docs 3.8.1 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 374899ce..291954fe 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,14 +5,26 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.8.1 +=============== + +Released 2020 Oct 01. + +Documentation +------------- + +* Use conf.py options to exclude sqlmeta options. Tests ----- * Fix ``PyGreSQL`` version for Python 3.4. +CI +-- + +* Run tests with Python 3.8 at AppVeyor. + SQLObject 3.8.0 =============== diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 763a4a41..579bdd6a 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.8.0' +version = '3.8.1' major = 3 minor = 8 -micro = 0 +micro = 1 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 270dd73d1d0a6db0abc453bf74743189151d8a08 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 1 Oct 2020 18:19:49 +0300 Subject: [PATCH 052/295] Prepare for the next release --- ANNOUNCE.rst | 32 ++++++++++++++------------------ README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5cfb5180..9beb8c90 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,29 +1,25 @@ Hello! -I'm pleased to announce version 3.8.1, the first bugfix release of branch -3.8 of SQLObject. - - -What's new in SQLObject -======================= +I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming +release of branch 3.8 of SQLObject. -The contributor for this release is Neil Muller. +I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming +release of branch 3.8 of SQLObject. -Documentation -------------- +I'm pleased to announce version 3.8.1b1, the first beta of the upcoming +release of branch 3.8 of SQLObject. -* Use conf.py options to exclude sqlmeta options. +I'm pleased to announce version 3.8.1rc1, the first release candidate +of the upcoming release of branch 3.8 of SQLObject. -Tests ------ - -* Fix ``PyGreSQL`` version for Python 3.4. +I'm pleased to announce version 3.8.2, the first bugfix release of branch +3.8 of SQLObject. -CI --- -* Run tests with Python 3.8 at AppVeyor. +What's new in SQLObject +======================= +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -55,7 +51,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.1 +https://pypi.org/project/SQLObject/3.8.2a0.dev20201001/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 88ecfac9..a0f632de 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.8.1 -=============== +SQLObject 3.8.2a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index 291954fe..dc57777a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.8.1 =============== From 5a9174719f50e03caec767209b239fd0e2caf5c6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Nov 2020 17:30:41 +0300 Subject: [PATCH 053/295] Tests,CI: Run tests with Python 3.9 at Travis and AppVeyor --- .travis.yml | 6 +++ appveyor.yml | 16 +++++++ docs/News.rst | 5 +++ tox.ini | 118 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e1760350..9f03a84f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,8 @@ matrix: env: TESTS=py37-mysql - python: "3.8" env: TESTS=py38-mysql + - python: "3.9" + env: TESTS=py39-mysql - python: "2.7" env: TESTS=py27-postgres - python: "3.4" @@ -49,6 +51,8 @@ matrix: env: TESTS=py37-postgres - python: "3.8" env: TESTS=py38-postgres + - python: "3.9" + env: TESTS=py39-postgres - python: "2.7" env: TESTS=py27-sqlite - python: "3.4" @@ -61,6 +65,8 @@ matrix: env: TESTS=py37-sqlite - python: "3.8" env: TESTS=py38-sqlite + - python: "3.9" + env: TESTS=py39-sqlite - python: "2.7" env: TESTS=py27-flake8 - python: "3.8" diff --git a/appveyor.yml b/appveyor.yml index e5f00a6e..be97e213 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,6 +3,8 @@ # and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) version: '{branch}-{build}' +image: Visual Studio 2019 + cache: - '%LOCALAPPDATA%\pip\Cache' @@ -45,6 +47,11 @@ environment: PYTHON_VERSION: "3.8" PYTHON_HOME: "C:\\Python38-x64" db: mysql + - TESTS: "py39-mysql" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" + db: mysql - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -65,6 +72,11 @@ environment: PYTHON_VERSION: "3.8" PYTHON_HOME: "C:\\Python38-x64" db: postgresql + - TESTS: "py39-postgres" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" + db: postgresql - TESTS: "py27-sqlite" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" @@ -81,6 +93,10 @@ environment: PYTHON_ARCH: "64" PYTHON_VERSION: "3.8" PYTHON_HOME: "C:\\Python38-x64" + - TESTS: "py39-sqlite" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" matrix: fast_finish: true diff --git a/docs/News.rst b/docs/News.rst index dc57777a..fcab0d42 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +CI +-- + +* Run tests with Python 3.9 at Travis and AppVeyor. + SQLObject 3.8.1 =============== diff --git a/tox.ini b/tox.ini index 51855a57..c84ffcf6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,38}-flake8 +envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,39}-flake8 # Base test environment settings [testenv] @@ -13,6 +13,7 @@ basepython = py36: {env:TOXPYTHON:python3.6} py37: {env:TOXPYTHON:python3.7} py38: {env:TOXPYTHON:python3.8} + py39: {env:TOXPYTHON:python3.9} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" @@ -80,6 +81,10 @@ deps = commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = +[testenv:py39-mysqldb] +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + [mysqlclient] commands = {[testenv]commands} @@ -107,6 +112,9 @@ commands = {[mysqlclient]commands} [testenv:py38-mysqlclient] commands = {[mysqlclient]commands} +[testenv:py39-mysqlclient] +commands = {[mysqlclient]commands} + [mysql-connector] commands = {[testenv]commands} @@ -135,6 +143,9 @@ commands = {[mysql-connector]commands} [testenv:py38-mysql-connector] commands = {[mysql-connector]commands} +[testenv:py39-mysql-connector] +commands = {[mysql-connector]commands} + [oursql] commands = {[testenv]commands} @@ -163,6 +174,9 @@ commands = {[oursql]commands} [testenv:py38-mysql-oursql3] commands = {[oursql]commands} +[testenv:py39-mysql-oursql3] +commands = {[oursql]commands} + [pymysql] commands = {[testenv]commands} @@ -191,6 +205,9 @@ commands = {[pymysql]commands} [testenv:py38-mysql-pymysql] commands = {[pymysql]commands} +[testenv:py39-mysql-pymysql] +commands = {[pymysql]commands} + [mysql-pyodbc] commands = {[testenv]commands} @@ -220,6 +237,9 @@ commands = {[mysql-pyodbc]commands} [testenv:py38-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} +[testenv:py39-mysql-pyodbc-noauto] +commands = {[mysql-pyodbc]commands} + [mysql-pypyodbc] commands = {[testenv]commands} @@ -248,6 +268,9 @@ commands = {[mysql-pypyodbc]commands} [testenv:py38-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} +[testenv:py39-mysql-pypyodbc-noauto] +commands = {[mysql-pypyodbc]commands} + # PostgreSQL test environments [psycopg] commands = @@ -277,6 +300,9 @@ commands = {[psycopg]commands} [testenv:py38-postgres-psycopg] commands = {[psycopg]commands} +[testenv:py39-postgres-psycopg] +commands = {[psycopg]commands} + [pygresql] commands = {[testenv]commands} @@ -305,6 +331,9 @@ commands = {[pygresql]commands} [testenv:py38-postgres-pygresql] commands = {[pygresql]commands} +[testenv:py39-postgres-pygresql] +commands = {[pygresql]commands} + [pypostgresql] commands = {[testenv]commands} @@ -332,6 +361,9 @@ commands = {[pypostgresql]commands} [testenv:py38-postgres-pypostgresql] commands = {[pypostgresql]commands} +[testenv:py39-postgres-pypostgresql] +commands = {[pypostgresql]commands} + [pg8000] commands = {[testenv]commands} @@ -360,6 +392,9 @@ commands = {[pg8000]commands} [testenv:py38-postgres-pg8000] commands = {[pg8000]commands} +[testenv:py39-postgres-pg8000] +commands = {[pg8000]commands} + [postgres-pyodbc] commands = {[testenv]commands} @@ -389,6 +424,9 @@ commands = {[postgres-pyodbc]commands} [testenv:py38-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} +[testenv:py39-postgres-pyodbc-noauto] +commands = {[postgres-pyodbc]commands} + [postgres-pypyodbc] commands = {[testenv]commands} @@ -417,6 +455,9 @@ commands = {[postgres-pypyodbc]commands} [testenv:py38-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} +[testenv:py39-postgres-pypyodbc-noauto] +commands = {[postgres-pypyodbc]commands} + # SQLite test environments [sqlite] @@ -446,6 +487,9 @@ commands = {[sqlite]commands} [testenv:py38-sqlite] commands = {[sqlite]commands} +[testenv:py39-sqlite] +commands = {[sqlite]commands} + [sqlite-memory] commands = {[testenv]commands} @@ -471,6 +515,9 @@ commands = {[sqlite-memory]commands} [testenv:py38-sqlite-memory] commands = {[sqlite-memory]commands} +[testenv:py39-sqlite-memory] +commands = {[sqlite-memory]commands} + [sqlite-supersqlite] commands = {[testenv]commands} @@ -498,6 +545,9 @@ commands = {[sqlite-supersqlite]commands} [testenv:py38-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} +[testenv:py39-sqlite-supersqlite] +commands = {[sqlite-supersqlite]commands} + # Firebird database test environments [fdb] @@ -528,6 +578,9 @@ commands = {[fdb]commands} [testenv:py38-firebird-fdb] commands = {[fdb]commands} +[testenv:py39-firebird-fdb] +commands = {[fdb]commands} + [firebirdsql] commands = {[testenv]commands} @@ -556,6 +609,9 @@ commands = {[firebirdsql]commands} [testenv:py38-firebirdsql] commands = {[firebirdsql]commands} +[testenv:py39-firebirdsql] +commands = {[firebirdsql]commands} + # Special test environments [testenv:py27-flake8] changedir = ./ @@ -605,6 +661,14 @@ commands = {[testenv]commands} flake8 . +[testenv:py39-flake8] +changedir = ./ +deps = + flake8 +commands = + {[testenv]commands} + flake8 . + # Windows testing [mssql-pyodbc-w32] platform = win32 @@ -643,6 +707,10 @@ commands = platform = win32 commands = {[mssql-pyodbc-w32]commands} +[testenv:py39-mssql-pyodbc-noauto-w32] +platform = win32 +commands = {[mssql-pyodbc-w32]commands} + [mysql-connector-w32] platform = win32 commands = @@ -680,6 +748,10 @@ commands = platform = win32 commands = {[mysql-connector-w32]commands} +[testenv:py39-mysql-connector-w32] +platform = win32 +commands = {[mysql-connector-w32]commands} + [pymysql-w32] platform = win32 commands = @@ -717,6 +789,10 @@ commands = platform = win32 commands = {[pymysql-w32]commands} +[testenv:py39-mysql-pymysql-w32] +platform = win32 +commands = {[pymysql-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = @@ -755,6 +831,10 @@ commands = platform = win32 commands = {[mysql-pyodbc-w32]commands} +[testenv:py39-mysql-pyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pyodbc-w32]commands} + [mysql-pypyodbc-w32] platform = win32 commands = @@ -793,6 +873,10 @@ commands = platform = win32 commands = {[mysql-pypyodbc-w32]commands} +[testenv:py39-mysql-pypyodbc-noauto-w32] +platform = win32 +commands = {[mysql-pypyodbc-w32]commands} + [psycopg-w32] platform = win32 commands = @@ -830,6 +914,10 @@ commands = platform = win32 commands = {[psycopg-w32]commands} +[testenv:py39-postgres-psycopg-w32] +platform = win32 +commands = {[psycopg-w32]commands} + [pygresql-w32] platform = win32 commands = @@ -867,6 +955,10 @@ commands = platform = win32 commands = {[pygresql-w32]commands} +[testenv:py39-postgres-pygresql-w32] +platform = win32 +commands = {[pygresql-w32]commands} + [pypostgresql-w32] platform = win32 commands = @@ -903,6 +995,10 @@ commands = platform = win32 commands = {[pypostgresql-w32]commands} +[testenv:py39-postgres-pypostgresql-w32] +platform = win32 +commands = {[pypostgresql-w32]commands} + [pg8000-w32] platform = win32 commands = @@ -940,6 +1036,10 @@ commands = platform = win32 commands = {[pg8000-w32]commands} +[testenv:py39-postgres-pg8000-w32] +platform = win32 +commands = {[pg8000-w32]commands} + [postgres-pyodbc-w32] platform = win32 commands = @@ -978,6 +1078,10 @@ commands = platform = win32 commands = {[postgres-pyodbc-w32]commands} +[testenv:py39-postgres-pyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pyodbc-w32]commands} + [postgres-pypyodbc-w32] platform = win32 commands = @@ -1016,6 +1120,10 @@ commands = platform = win32 commands = {[postgres-pypyodbc-w32]commands} +[testenv:py39-postgres-pypyodbc-noauto-w32] +platform = win32 +commands = {[postgres-pypyodbc-w32]commands} + [sqlite-w32] platform = win32 commands = @@ -1051,6 +1159,10 @@ commands = platform = win32 commands = {[sqlite-w32]commands} +[testenv:py39-sqlite-w32] +platform = win32 +commands = {[sqlite-w32]commands} + [sqlite-memory-w32] platform = win32 commands = @@ -1084,3 +1196,7 @@ commands = [testenv:py38-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} + +[testenv:py39-sqlite-memory-w32] +platform = win32 +commands = {[sqlite-memory-w32]commands} From f2e34acc8dd32ef00f28275c4bca044e9ca03d05 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 21 Nov 2020 15:53:13 +0300 Subject: [PATCH 054/295] CI: Turn off `fast_finish` --- .travis.yml | 2 -- appveyor.yml | 3 --- 2 files changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f03a84f..71cc4c2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,8 +80,6 @@ matrix: - env: TESTS=py27-firebird - env: TESTS=py36-firebird - fast_finish: true - before_install: # Start the firebird database server. # We use firebird-super, so there's none of the inetd configuration diff --git a/appveyor.yml b/appveyor.yml index be97e213..cdb6cfe4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -98,9 +98,6 @@ environment: PYTHON_VERSION: "3.9" PYTHON_HOME: "C:\\Python39-x64" -matrix: - fast_finish: true - install: # Ensure we use the right python version - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" From a80792d2a52980ddc644c728f4c968f2015dd2d7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 21 Nov 2020 18:38:40 +0300 Subject: [PATCH 055/295] CI(AppVeyor): Use `PostgreSQL` 9.6 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index cdb6cfe4..537ec564 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -100,7 +100,7 @@ environment: install: # Ensure we use the right python version - - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.5\\bin;%PATH%" + - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.6\\bin;%PATH%" - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" From 7ccfeb89506ef301ec11253d3fed550e39ab6278 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 21 Nov 2020 19:07:12 +0300 Subject: [PATCH 056/295] Tests: Clear microseconds It seems MySQL at AppVeyor rounds seconds if microseconds > 0.5 sec. --- sqlobject/tests/test_datetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index 58c43f99..df9bbc3a 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -24,7 +24,7 @@ class DateTime1(SQLObject): def test_dateTime(): setupClass(DateTime1) - _now = datetime.now() + _now = datetime.now().replace(microsecond=0) dt1 = DateTime1(col1=_now, col2=_now, col3=_now.time()) assert isinstance(dt1.col1, datetime) From 470c8f43e956d34a500e18d9fe428c16927cabd2 Mon Sep 17 00:00:00 2001 From: "Michael S. Root" Date: Thu, 3 Sep 2020 14:14:00 +0300 Subject: [PATCH 057/295] Update for JSON column and functions Refs: #159. --- sqlobject/col.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sqlobject/col.py b/sqlobject/col.py index 9bbde2a6..6fda37f6 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -2008,11 +2008,68 @@ def createValidators(self): return [JSONValidator(name=self.name)] + \ super(SOJSONCol, self).createValidators() + def _sqlType(self): + return 'JSON' + class JSONCol(StringCol): baseClass = SOJSONCol +############################################# +# +# Added by Tippett +# + +# +# Convenience stuff Monkey-Patched onto sqlbuilder.SQLObjectField, +# so you can do: +# +# Table.q.column.json_extract("key") == value +# Table.q.column.json_contains("item") +# Table.q.column.json_length("key") +# +# instead of +# +# func.JSON_EXTRACT(Table.q.column, '$.key') == value +# func.JSON_CONTAINS(Table.q.column, json.dumps("item")) +# func.JSON_LENGTH(Table.q.column, '$.key') +# + +def _json_extract(col, key, path=None): + """ + """ + assert isinstance(col.column, SOJSONCol), \ + "{!r} is not a JSONCol".format(col) + if path is None: + return sqlbuilder.func.JSON_EXTRACT(col, '$.%s' % key) + else: + return sqlbuilder.func.JSON_EXTRACT(col, '$.%s' % key, path) + + +def _json_contains(col, value, path=None): + assert isinstance(col.column, SOJSONCol), \ + "{!r} is not a JSONCol".format(col) + if path is None: + return sqlbuilder.func.JSON_CONTAINS(col, json.dumps(value)) + else: + return sqlbuilder.func.JSON_CONTAINS(col, json.dumps(value), path) + + +def _json_length(col, path=None): + assert isinstance(col.column, SOJSONCol), \ + "{!r} is not a JSONCol".format(col) + if path is None: + return sqlbuilder.func.JSON_LENGTH(col) + else: + return sqlbuilder.func.JSON_LENGTH(col, path) + + +sqlbuilder.SQLObjectField.json_extract = _json_extract +sqlbuilder.SQLObjectField.json_contains = _json_contains +sqlbuilder.SQLObjectField.json_length = _json_length + + def pushKey(kw, name, value): if name not in kw: kw[name] = value From ac96456b98cbb0e95a3bdafab263d3f59e7d8e77 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Sep 2020 16:15:32 +0300 Subject: [PATCH 058/295] Feat(mysql): Check if the server allows to use JSON functions Refs: #159. --- sqlobject/mysql/mysqlconnection.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 00cc3d65..16bd4b0f 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -148,6 +148,8 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self._server_version = None self._can_use_microseconds = None + self._can_use_json_funcs = None + DBAPI.__init__(self, **kw) @classmethod @@ -490,3 +492,17 @@ def can_use_microseconds(self): can_use_microseconds = (server_version >= (5, 6, 4)) self._can_use_microseconds = can_use_microseconds return can_use_microseconds + + def can_use_json_funcs(self): + if self._can_use_json_funcs is not None: + return self._can_use_json_funcs + server_version = self.server_version() + if server_version is None: + return None + server_version, db_tag = server_version + if db_tag == "MariaDB": + can_use_json_funcs = (server_version >= (10, 2, 7)) + else: # MySQL + can_use_json_funcs = (server_version >= (5, 7, 0)) + self._can_use_json_funcs = can_use_json_funcs + return can_use_json_funcs From 6d5d0c200b8428b009a35d8f4c5912413e5db7c6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Sep 2020 16:17:01 +0300 Subject: [PATCH 059/295] Test(mysql/json): Test JSON functions Refs: #159. --- sqlobject/tests/test_jsoncol.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/sqlobject/tests/test_jsoncol.py b/sqlobject/tests/test_jsoncol.py index 1a120cda..52bb354e 100644 --- a/sqlobject/tests/test_jsoncol.py +++ b/sqlobject/tests/test_jsoncol.py @@ -1,3 +1,4 @@ +import pytest from sqlobject import SQLObject, JSONCol from sqlobject.tests.dbtest import setupClass @@ -18,17 +19,38 @@ class JSONTest(SQLObject): u"unicode", u"unicode'with'apostrophes", u"unicode\"with\"quotes", ], u"unicode", u"unicode'with'apostrophes", u"unicode\"with\"quotes", + {'test': 'Test'}, ) -def test_JSONCol(): +def _setup(): setupClass(JSONTest) for _id, test_data in enumerate(_json_test_data): - json = JSONTest(id=_id + 1, json=test_data) + JSONTest(id=_id + 1, json=test_data) + +def test_JSONCol(): + _setup() JSONTest._connection.cache.clear() for _id, test_data in enumerate(_json_test_data): json = JSONTest.get(_id + 1) assert json.json == test_data + + +def test_JSONCol_funcs(): + connection = JSONTest._connection + if not hasattr(connection, 'can_use_json_funcs') \ + or not connection.can_use_json_funcs(): + pytest.skip( + "The database doesn't support JSON functions; " + "JSON functions are supported by MariaDB since version 10.2.7 " + "and by MySQL since version 5.7.") + _setup() + + rows = list( + JSONTest.select(JSONTest.q.json.json_extract('test') == 'Test') + ) + assert len(rows) == 1 + assert rows[0].json == {'test': 'Test'} From 3a4e35f61d6779c555032b8fd70dddef1dcec7f0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Nov 2020 17:13:17 +0300 Subject: [PATCH 060/295] Fix(col): Fix `JSONValidator` Refs: #159. --- sqlobject/col.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sqlobject/col.py b/sqlobject/col.py index 6fda37f6..8c4118ed 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -1978,11 +1978,13 @@ class JsonbCol(Col): baseClass = SOJsonbCol -class JSONValidator(StringValidator): +class JSONValidator(SOValidator): def to_python(self, value, state): if value is None: return None + if isinstance(value, (bool, int, float, long, dict, list)): + return value if isinstance(value, string_type): return json.loads(value) raise validators.Invalid( @@ -2005,8 +2007,7 @@ def from_python(self, value, state): class SOJSONCol(SOStringCol): def createValidators(self): - return [JSONValidator(name=self.name)] + \ - super(SOJSONCol, self).createValidators() + return [JSONValidator(name=self.name)] def _sqlType(self): return 'JSON' From 48b1521d3fd55fb1bd968d6fdd34656e471004b1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 24 Nov 2020 18:43:16 +0300 Subject: [PATCH 061/295] Python 3.9 is supported --- devscripts/setup | 2 +- setup.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/devscripts/setup b/devscripts/setup index 3c12824d..e28d6765 100755 --- a/devscripts/setup +++ b/devscripts/setup @@ -3,7 +3,7 @@ umask 022 # -rwxr-xr-x cd "`dirname \"$0\"`"/.. && -for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8; do +for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8 3.9; do python$py_ver -m pip install --install-option=-O2 --upgrade . done && diff --git a/setup.py b/setup.py index d85791d3..58cd1d0f 100755 --- a/setup.py +++ b/setup.py @@ -60,6 +60,7 @@ "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", From 1b9aff1e6983b4e3f708933884333d8cc93512ec Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Nov 2020 16:30:37 +0300 Subject: [PATCH 062/295] Fix(col): Comment out `SOJSONCol._sqlType()` Doesn't work, especially with Postgres. Refs: #159. --- docs/SQLObject.rst | 3 ++- sqlobject/col.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 9504c1a2..c3f19576 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1244,7 +1244,8 @@ different types of columns, when SQLObject creates your tables. `JSONCol`: A universal json column that converts simple Python objects (None, bool, int, float, long, dict, list, str/unicode to/from JSON using - json.dumps/loads. A subclass of StringCol. + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. `PickleCol`: An extension of BLOBCol; this column can store/retrieve any Python object; diff --git a/sqlobject/col.py b/sqlobject/col.py index 8c4118ed..c5bd2968 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -2009,8 +2009,9 @@ class SOJSONCol(SOStringCol): def createValidators(self): return [JSONValidator(name=self.name)] - def _sqlType(self): - return 'JSON' + # Doesn't work, especially with Postgres + # def _sqlType(self): + # return 'JSON' class JSONCol(StringCol): From ed106ef2c461ea31387f9597d6f17d934c3eebd0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Nov 2020 16:43:13 +0300 Subject: [PATCH 063/295] Docs(News): Add `JSONCol` [skip ci] --- docs/News.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index fcab0d42..aee1f6e3 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +Features +-------- + +* Add ``JSONCol``: a universal json column that converts simple Python objects + (None, bool, int, float, long, dict, list, str/unicode to/from JSON using + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. + CI -- From 3635f444399c34e256dba87687e6ab657e85447a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Nov 2020 04:11:11 +0300 Subject: [PATCH 064/295] Tests(tox): Add `py39-sqlite` to the default list of environments --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index c84ffcf6..f0fc2b23 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.0 -envlist = py27,py3{4,5,6,7,8}-sqlite{,-memory},py{27,39}-flake8 +envlist = py27,py3{4,5,6,7,8,9}-sqlite{,-memory},py{27,39}-flake8 # Base test environment settings [testenv] From b6d0201febccc7895e398b548d8c2f60e8ead1d1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Dec 2020 16:47:03 +0300 Subject: [PATCH 065/295] Feat(DateTime): Drop support for very old version of `mxDateTime` Drop support for very old version of `mxDateTime` without `mx.` namespace. Refs: #161. --- docs/News.rst | 3 +++ sqlobject/col.py | 31 ++++++++++++++++--------------- sqlobject/converters.py | 33 ++++++++++++++++----------------- 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index aee1f6e3..1842d1a0 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,9 @@ Features json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` columns at backends, doesn't work with ``JSON`` columns. +* Drop support for very old version of ``mxDateTime`` + without ``mx.`` namespace. + CI -- diff --git a/sqlobject/col.py b/sqlobject/col.py index c5bd2968..80745a24 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -46,27 +46,28 @@ try: from mx import DateTime except ImportError: - try: - # old version of mxDateTime, - # or Zope's Version if we're running with Zope - import DateTime - except ImportError: - mxdatetime_available = False - else: - mxdatetime_available = True + mxdatetime_available = False else: mxdatetime_available = True +try: + # DateTime from Zope + import DateTime +except ImportError: + zope_datetime_available = False +else: + zope_datetime_available = True + DATETIME_IMPLEMENTATION = "datetime" MXDATETIME_IMPLEMENTATION = "mxDateTime" -if mxdatetime_available: - if hasattr(DateTime, "Time"): - DateTimeType = type(DateTime.now()) - TimeType = type(DateTime.Time()) - else: # Zope - DateTimeType = type(DateTime.DateTime()) - TimeType = type(DateTime.DateTime.Time(DateTime.DateTime())) +if mxdatetime_available and hasattr(DateTime, "Time"): + DateTimeType = type(DateTime.now()) + TimeType = type(DateTime.Time()) + +elif zope_datetime_available: + DateTimeType = type(DateTime.DateTime()) + TimeType = type(DateTime.DateTime.Time(DateTime.DateTime())) __all__ = ["datetime_available", "mxdatetime_available", "default_datetime_implementation", "DATETIME_IMPLEMENTATION"] diff --git a/sqlobject/converters.py b/sqlobject/converters.py index 19b90d07..b79695fa 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -16,13 +16,11 @@ try: - from mx.DateTime import DateTimeType, DateTimeDeltaType + from mx.DateTime import DateTimeType as mxDateTimeType, \ + DateTimeDeltaType as mxDateTimeDeltaType except ImportError: - try: - from DateTime import DateTimeType, DateTimeDeltaType - except ImportError: - DateTimeType = None - DateTimeDeltaType = None + mxDateTimeType = None + mxDateTimeDeltaType = None try: import Sybase @@ -144,17 +142,6 @@ def FloatConverter(value, db): registerConverter(float, FloatConverter) -if DateTimeType: - def mxDateTimeConverter(value, db): - return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") - - registerConverter(DateTimeType, mxDateTimeConverter) - - def mxTimeConverter(value, db): - return "'%s'" % value.strftime("%H:%M:%S") - - registerConverter(DateTimeDeltaType, mxTimeConverter) - def NoneConverter(value, db): return "NULL" @@ -209,6 +196,18 @@ def TimeConverterMS(value, db): registerConverter(datetime.time, TimeConverterMS) +if mxDateTimeType: + def mxDateTimeConverter(value, db): + return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") + + registerConverter(mxDateTimeType, mxDateTimeConverter) + + def mxTimeConverter(value, db): + return "'%s'" % value.strftime("%H:%M:%S") + + registerConverter(mxDateTimeDeltaType, mxTimeConverter) + + def DecimalConverter(value, db): return value.to_eng_string() From e7b379f442a5aa8071076fd3438e9a56c0fb8eed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Dec 2020 17:08:07 +0300 Subject: [PATCH 066/295] Feat(DateTime): Extend/fix support for `DateTime` from `Zope` Refs: #161. --- devscripts/requirements/requirements.txt | 3 + docs/News.rst | 2 + sqlobject/col.py | 143 +++++++++++++++++++---- sqlobject/converters.py | 14 +++ sqlobject/tests/test_datetime.py | 37 ++++-- 5 files changed, 169 insertions(+), 30 deletions(-) diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index b8113c5c..f77d60a2 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -1,5 +1,8 @@ --install-option=-O2 +# DateTime from Zope +DateTime + FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0' FormEncode >= 1.3.1; python_version >= '3.4' PyDispatcher >= 2.0.4 diff --git a/docs/News.rst b/docs/News.rst index 1842d1a0..e9d02920 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,8 @@ Features json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` columns at backends, doesn't work with ``JSON`` columns. +* Extend/fix support for ``DateTime`` from ``Zope``. + * Drop support for very old version of ``mxDateTime`` without ``mx.`` namespace. diff --git a/sqlobject/col.py b/sqlobject/col.py index 80745a24..cf9705de 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -44,7 +44,7 @@ datetime_available = True try: - from mx import DateTime + from mx import DateTime as mxDateTime except ImportError: mxdatetime_available = False else: @@ -52,7 +52,7 @@ try: # DateTime from Zope - import DateTime + import DateTime as zopeDateTime except ImportError: zope_datetime_available = False else: @@ -60,14 +60,14 @@ DATETIME_IMPLEMENTATION = "datetime" MXDATETIME_IMPLEMENTATION = "mxDateTime" +ZOPE_DATETIME_IMPLEMENTATION = "zopeDateTime" -if mxdatetime_available and hasattr(DateTime, "Time"): - DateTimeType = type(DateTime.now()) - TimeType = type(DateTime.Time()) +if mxdatetime_available and hasattr(mxDateTime, "Time"): + mxDateTimeType = type(mxDateTime.now()) + mxTimeType = type(mxDateTime.Time()) -elif zope_datetime_available: - DateTimeType = type(DateTime.DateTime()) - TimeType = type(DateTime.DateTime.Time(DateTime.DateTime())) +if zope_datetime_available: + zopeDateTimeType = type(zopeDateTime.DateTime()) __all__ = ["datetime_available", "mxdatetime_available", "default_datetime_implementation", "DATETIME_IMPLEMENTATION"] @@ -75,6 +75,9 @@ if mxdatetime_available: __all__.append("MXDATETIME_IMPLEMENTATION") +if zope_datetime_available: + __all__.append("ZOPE_DATETIME_IMPLEMENTATION") + default_datetime_implementation = DATETIME_IMPLEMENTATION if not PY2: @@ -1257,7 +1260,7 @@ def to_python(self, value, state): datetime.time, sqlbuilder.SQLExpression)): return value if mxdatetime_available: - if isinstance(value, DateTimeType): + if isinstance(value, mxDateTimeType): # convert mxDateTime instance to datetime if (self.format.find("%H") >= 0) or \ (self.format.find("%T")) >= 0: @@ -1267,13 +1270,23 @@ def to_python(self, value, state): int(value.second)) else: return datetime.date(value.year, value.month, value.day) - elif isinstance(value, TimeType): + elif isinstance(value, mxTimeType): # convert mxTime instance to time if self.format.find("%d") >= 0: return datetime.timedelta(seconds=value.seconds) else: return datetime.time(value.hour, value.minute, int(value.second)) + if zope_datetime_available: + if isinstance(value, zopeDateTimeType): + # convert zopeDateTime instance to datetime + if (self.format.find("%H") >= 0) or \ + (self.format.find("%T")) >= 0: + return datetime.datetime( + value.year(), value.month(), value.day(), + value.hour(), value.minute(), int(value.second())) + else: + return datetime.date(value.year, value.month, value.day) try: if self.format.find(".%f") >= 0: if '.' in value: @@ -1315,23 +1328,30 @@ def to_python(self, value, state): if value is None: return None if isinstance(value, - (DateTimeType, TimeType, sqlbuilder.SQLExpression)): + (mxDateTimeType, mxTimeType, + sqlbuilder.SQLExpression)): return value if isinstance(value, datetime.datetime): - return DateTime.DateTime(value.year, value.month, value.day, - value.hour, value.minute, - value.second) + return mxDateTime.DateTime(value.year, value.month, value.day, + value.hour, value.minute, + value.second) elif isinstance(value, datetime.date): - return DateTime.Date(value.year, value.month, value.day) + return mxDateTime.Date(value.year, value.month, value.day) elif isinstance(value, datetime.time): - return DateTime.Time(value.hour, value.minute, value.second) + return mxDateTime.Time(value.hour, value.minute, value.second) elif isinstance(value, datetime.timedelta): if value.days: raise validators.Invalid( "the value for the TimeCol '%s' must has days=0, " "it has days=%d" % (self.name, value.days), value, state) - return DateTime.Time(seconds=value.seconds) + return mxDateTime.Time(seconds=value.seconds) + if zope_datetime_available: + if isinstance(value, zopeDateTimeType): + # convert zopeDateTime instance to mxdatetime + return mxDateTime.DateTime( + value.year(), value.month(), value.day(), + value.hour(), value.minute(), int(value.second())) try: if self.format.find(".%f") >= 0: if '.' in value: @@ -1347,9 +1367,9 @@ def to_python(self, value, state): else: value += '.0' value = datetime.datetime.strptime(value, self.format) - return DateTime.DateTime(value.year, value.month, value.day, - value.hour, value.minute, - value.second) + return mxDateTime.DateTime(value.year, value.month, value.day, + value.hour, value.minute, + value.second) except Exception: raise validators.Invalid( "expected a date/time string of the '%s' format " @@ -1361,7 +1381,8 @@ def from_python(self, value, state): if value is None: return None if isinstance(value, - (DateTimeType, TimeType, sqlbuilder.SQLExpression)): + (mxDateTimeType, mxTimeType, + sqlbuilder.SQLExpression)): return value if hasattr(value, "strftime"): return value.strftime(self.format) @@ -1371,6 +1392,76 @@ def from_python(self, value, state): self.name, type(value), value), value, state) +if zope_datetime_available: + class ZopeDateTimeValidator(validators.DateValidator): + def to_python(self, value, state): + if value is None: + return None + if isinstance(value, + (zopeDateTimeType, sqlbuilder.SQLExpression)): + return value + if isinstance(value, datetime.datetime): + return zopeDateTime.DateTime( + value.year, value.month, value.day, + value.hour, value.minute, value.second) + elif isinstance(value, datetime.date): + return zopeDateTime.DateTime( + value.year, value.month, value.day) + elif isinstance(value, datetime.time): + return zopeDateTime.DateTime( + value.hour, value.minute, value.second) + elif isinstance(value, datetime.timedelta): + if value.days: + raise validators.Invalid( + "the value for the TimeCol '%s' must has days=0, " + "it has days=%d" % (self.name, value.days), + value, state) + return zopeDateTime.DateTime(seconds=value.seconds) + if mxdatetime_available: + if isinstance(value, mxDateTimeType): + # convert mxDateTime instance to zopeDateTime + return zopeDateTime.DateTime( + value.year, value.month, value.day, + value.hour, value.minute, value.second) + try: + if self.format.find(".%f") >= 0: + if '.' in value: + _value = value.split('.') + microseconds = _value[-1] + _l = len(microseconds) + if _l < 6: + _value[-1] = microseconds + '0' * (6 - _l) + elif _l > 6: + _value[-1] = microseconds[:6] + if _l != 6: + value = '.'.join(_value) + else: + value += '.0' + value = datetime.datetime.strptime(value, self.format) + return zopeDateTime.DateTime( + value.year, value.month, value.day, + value.hour, value.minute, value.second) + except Exception: + raise validators.Invalid( + "expected a date/time string of the '%s' format " + "in the DateTimeCol '%s', got %s %r instead" % ( + self.format, self.name, type(value), value), + value, state) + + def from_python(self, value, state): + if value is None: + return None + if isinstance(value, + (zopeDateTimeType, sqlbuilder.SQLExpression)): + return value + if hasattr(value, "strftime"): + return value.strftime(self.format) + raise validators.Invalid( + "expected a zopeDateTime in the DateTimeCol '%s', " + "got %s %r instead" % ( + self.name, type(value), value), value, state) + + class SODateTimeCol(SOCol): datetimeFormat = '%Y-%m-%d %H:%M:%S.%f' @@ -1386,6 +1477,8 @@ def createValidators(self): validatorClass = DateTimeValidator elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: validatorClass = MXDateTimeValidator + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + validatorClass = ZopeDateTimeValidator if default_datetime_implementation: _validators.insert(0, validatorClass(name=self.name, format=self.datetimeFormat)) @@ -1427,7 +1520,9 @@ def now(): if default_datetime_implementation == DATETIME_IMPLEMENTATION: return datetime.datetime.now() elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: - return DateTime.now() + return mxDateTime.now() + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + return zopeDateTime.DateTimr() else: assert 0, ("No datetime implementation available " "(DATETIME_IMPLEMENTATION=%r)" @@ -1468,6 +1563,8 @@ def createValidators(self): validatorClass = DateValidator elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: validatorClass = MXDateTimeValidator + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + validatorClass = ZopeDateTimeValidator if default_datetime_implementation: _validators.insert(0, validatorClass(name=self.name, format=self.dateFormat)) @@ -1538,6 +1635,8 @@ def createValidators(self): validatorClass = TimeValidator elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION: validatorClass = MXDateTimeValidator + elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION: + validatorClass = ZopeDateTimeValidator if default_datetime_implementation: _validators.insert(0, validatorClass(name=self.name, format=self.timeFormat)) diff --git a/sqlobject/converters.py b/sqlobject/converters.py index b79695fa..fa6ea1c0 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -22,6 +22,13 @@ mxDateTimeType = None mxDateTimeDeltaType = None +try: + from DateTime import DateTime as zopeDateTime +except ImportError: + zopeDateTimeType = None +else: + zopeDateTimeType = type(zopeDateTime()) + try: import Sybase NumericType = Sybase.NumericType @@ -208,6 +215,13 @@ def mxTimeConverter(value, db): registerConverter(mxDateTimeDeltaType, mxTimeConverter) +if zopeDateTimeType: + def zopeDateTimeConverter(value, db): + return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") + + registerConverter(zopeDateTimeType, zopeDateTimeConverter) + + def DecimalConverter(value, db): return value.to_eng_string() diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index df9bbc3a..06ce1ae6 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -3,8 +3,9 @@ from sqlobject import SQLObject from sqlobject import col -from sqlobject.col import DATETIME_IMPLEMENTATION, DateCol, DateTimeCol, \ - MXDATETIME_IMPLEMENTATION, TimeCol, mxdatetime_available, use_microseconds +from sqlobject.col import DateCol, DateTimeCol, TimeCol, use_microseconds, \ + DATETIME_IMPLEMENTATION, MXDATETIME_IMPLEMENTATION, mxdatetime_available, \ + ZOPE_DATETIME_IMPLEMENTATION, zope_datetime_available from sqlobject.tests.dbtest import getConnection, setupClass @@ -82,7 +83,7 @@ def test_microseconds(): if mxdatetime_available: col.default_datetime_implementation = MXDATETIME_IMPLEMENTATION - from mx.DateTime import now, Time + from mx.DateTime import now as mx_now, Time as mxTime dateFormat = None # use default try: @@ -104,11 +105,11 @@ class DateTime2(SQLObject): def test_mxDateTime(): setupClass(DateTime2) - _now = now() + _now = mx_now() dt2 = DateTime2(col1=_now, col2=_now.pydate(), - col3=Time(_now.hour, _now.minute, _now.second)) + col3=mxTime(_now.hour, _now.minute, _now.second)) - assert isinstance(dt2.col1, col.DateTimeType) + assert isinstance(dt2.col1, col.mxDateTimeType) assert dt2.col1.year == _now.year assert dt2.col1.month == _now.month assert dt2.col1.day == _now.day @@ -116,7 +117,7 @@ def test_mxDateTime(): assert dt2.col1.minute == _now.minute assert dt2.col1.second == int(_now.second) - assert isinstance(dt2.col2, col.DateTimeType) + assert isinstance(dt2.col2, col.mxDateTimeType) assert dt2.col2.year == _now.year assert dt2.col2.month == _now.month assert dt2.col2.day == _now.day @@ -124,7 +125,27 @@ def test_mxDateTime(): assert dt2.col2.minute == 0 assert dt2.col2.second == 0 - assert isinstance(dt2.col3, (col.DateTimeType, col.TimeType)) + assert isinstance(dt2.col3, (col.mxDateTimeType, col.mxTimeType)) assert dt2.col3.hour == _now.hour assert dt2.col3.minute == _now.minute assert dt2.col3.second == int(_now.second) + +if zope_datetime_available: + col.default_datetime_implementation = ZOPE_DATETIME_IMPLEMENTATION + from DateTime import DateTime as zopeDateTime + + class DateTime3(SQLObject): + col1 = DateTimeCol() + + def test_ZopeDateTime(): + setupClass(DateTime3) + _now = zopeDateTime() + dt3 = DateTime3(col1=_now) + + assert isinstance(dt3.col1, col.zopeDateTimeType) + assert dt3.col1.year() == _now.year() + assert dt3.col1.month() == _now.month() + assert dt3.col1.day() == _now.day() + assert dt3.col1.hour() == _now.hour() + assert dt3.col1.minute() == _now.minute() + assert int(dt3.col1.second()) == int(_now.second()) From 11247f12ca31106288caf51fdf2cb1b2de92dd6b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Dec 2020 02:31:05 +0300 Subject: [PATCH 067/295] Test(devscripts/test-sqlobject.cmd): Run tests with Python 3.9 [skip ci] --- devscripts/test-sqlobject.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd index 53b7cab5..97846d80 100644 --- a/devscripts/test-sqlobject.cmd +++ b/devscripts/test-sqlobject.cmd @@ -3,7 +3,7 @@ SetLocal EnableDelayedExpansion set SavePATH=%PATH% -for %%V in (27 34 35 36 37 38) do ( +for %%V in (27 34 35 36 37 38 39) do ( for %%s in (32 64) do ( set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! set TOXPYTHON=C:\Python%%V-%%s\python.exe From 805632876ff07142ed0f71b4b557a878e805d370 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 12 Dec 2020 19:16:02 +0300 Subject: [PATCH 068/295] Feat(mysql): Support `mariadb` --- .travis.yml | 8 ++++ appveyor.yml | 20 ++++++++ docs/News.rst | 5 ++ docs/SQLObject.rst | 26 ++++++----- sqlobject/mysql/mysqlconnection.py | 38 +++++++++++---- tox.ini | 75 ++++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 71cc4c2b..c5e810fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,14 @@ matrix: env: TESTS=py38-mysql - python: "3.9" env: TESTS=py39-mysql + - python: "3.6" + env: TESTS=py36-mariadb + - python: "3.7" + env: TESTS=py37-mariadb + - python: "3.8" + env: TESTS=py38-mariadb + - python: "3.9" + env: TESTS=py39-mariadb - python: "2.7" env: TESTS=py27-postgres - python: "3.4" diff --git a/appveyor.yml b/appveyor.yml index 537ec564..84c56d4d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -52,6 +52,26 @@ environment: PYTHON_VERSION: "3.9" PYTHON_HOME: "C:\\Python39-x64" db: mysql + - TESTS: "py36-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.6" + PYTHON_HOME: "C:\\Python36-x64" + db: mysql + - TESTS: "py37-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.7" + PYTHON_HOME: "C:\\Python37-x64" + db: mysql + - TESTS: "py38-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.8" + PYTHON_HOME: "C:\\Python38-x64" + db: mysql + - TESTS: "py39-mariadb" + PYTHON_ARCH: "64" + PYTHON_VERSION: "3.9" + PYTHON_HOME: "C:\\Python39-x64" + db: mysql - TESTS: "py27-postgres" PYTHON_ARCH: "32" PYTHON_VERSION: "2.7" diff --git a/docs/News.rst b/docs/News.rst index e9d02920..253ef84b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,11 @@ Features * Drop support for very old version of ``mxDateTime`` without ``mx.`` namespace. +Drivers +------- + +* Support ``mariadb``. + CI -- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index c3f19576..ddbe2c5d 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -46,23 +46,25 @@ used with the same query syntax. Requirements ============ -Currently SQLObject supports MySQL_ via MySQLdb_ aka MySQL-python (called -mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, PyODBC_ -and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, -py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver, -PySQLite_ or supersqlite_. Firebird_ is supported via fdb_ or kinterbasdb_; -pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP -DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via -pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are -supported for MySQL, PostgreSQL and MSSQL but have problems (not all tests -passed). +Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka +MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, +oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, py-postgresql_ and pg8000_ +are supported; SQLite_ has a built-in driver, PySQLite_ or supersqlite_. +Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is +supported but has problems. `MAX DB`_ (also known as SAP DB) is supported +via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) +or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for MySQL, +PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQL: https://www.mysql.com/ +.. _MariaDB: https://mariadb.org/ .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ .. _oursql: https://github.com/python-oursql/oursql .. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ +.. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg2: http://initd.org/psycopg/ .. _PyGreSQL: http://www.pygresql.org/ @@ -1788,8 +1790,8 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``oursql`` and -``pymysql``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +Supported drivers are ``mysqldb``, ``connector``, ``oursql``, ``pymysql`` +and ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); defualt is ``mysqldb``. diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 16bd4b0f..95d6b58e 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -5,7 +5,10 @@ class ErrorMessage(str): def __new__(cls, e, append_msg=''): - obj = str.__new__(cls, e.args[1] + append_msg) + if len(e.args) > 1: + obj = str.__new__(cls, e.args[1] + append_msg) + else: + obj = str.__new__(cls, append_msg) try: obj.code = int(e.args[0]) except ValueError: @@ -70,6 +73,9 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): oursql.errnos['CR_SERVER_GONE_ERROR'] self.CR_SERVER_LOST = oursql.errnos['CR_SERVER_LOST'] self.ER_DUP_ENTRY = oursql.errnos['ER_DUP_ENTRY'] + elif driver == 'mariadb': + import mariadb + self.module = mariadb elif driver == 'pyodbc': import pyodbc self.module = pyodbc @@ -86,7 +92,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, ' - 'oursql, pymysql, ' + 'oursql, pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -125,21 +131,26 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.dbEncoding = None self.driver = driver + if driver in ('mariadb', 'odbc', 'pyodbc', 'pypyodbc'): + self.CR_SERVER_GONE_ERROR = 2006 + self.CR_SERVER_LOST = 2013 + self.ER_DUP_ENTRY = '23000' + if driver in ('odbc', 'pyodbc', 'pypyodbc'): self.make_odbc_conn_str(kw.pop('odbcdrv', 'MySQL ODBC 5.3 ANSI Driver'), db, host, port, user, password ) - self.CR_SERVER_GONE_ERROR = 2006 - self.CR_SERVER_LOST = 2013 - self.ER_DUP_ENTRY = '23000' - elif self.driver == 'oursql': + elif driver == 'oursql': if "use_unicode" not in self.kw: self.kw["use_unicode"] = not PY2 # oursql doesn't implement ping(True) yet self.kw["autoreconnect"] = True + elif driver == 'mariadb': + self.kw.pop("charset", None) + global mysql_Bin if not PY2 and mysql_Bin is None: mysql_Bin = self.module.Binary @@ -179,7 +190,13 @@ def character_set_name(self): conn = self.module.connect( host=self.host, port=self.port, db=self.db, user=self.user, passwd=self.password, **self.kw) - if self.driver != 'oursql': + if self.driver == 'mariadb': + # Attempt to reconnect. + # This setting is persistent due to ``auto_reconnect``. + # mariadb doesn't implement ping(True) + conn.auto_reconnect = True + conn.ping() + elif self.driver != 'oursql': # Attempt to reconnect. This setting is persistent. conn.ping(True) except self.module.OperationalError as e: @@ -229,7 +246,7 @@ def _executeRetry(self, conn, cursor, query): self.printDebug(conn, query, 'QueryR') dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( - self.driver in ('mysqldb', 'connector', 'oursql')): + self.driver in ('mysqldb', 'connector', 'oursql', 'mariadb')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the @@ -263,6 +280,9 @@ def _executeRetry(self, conn, cursor, query): msg = ErrorMessage(e) if e.args[0] == self.ER_DUP_ENTRY: raise dberrors.DuplicateEntryError(msg) + elif isinstance(e.args[0], str) \ + and e.args[0].startswith('Duplicate'): + raise dberrors.DuplicateEntryError(msg) else: raise dberrors.IntegrityError(msg) except self.module.InternalError as e: @@ -345,6 +365,8 @@ def tableExists(self, tableName): except dberrors.ProgrammingError as e: if e.args[0].code in (1146, '42S02'): # ER_NO_SUCH_TABLE return False + if self.driver == 'mariadb': + return False raise def addColumn(self, tableName, column): diff --git a/tox.ini b/tox.ini index f0fc2b23..e8893f32 100644 --- a/tox.ini +++ b/tox.ini @@ -25,6 +25,7 @@ deps = mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: pymysql + mariadb: mariadb postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql @@ -208,6 +209,38 @@ commands = {[pymysql]commands} [testenv:py39-mysql-pymysql] commands = {[pymysql]commands} +[mariadb] +commands = + {[testenv]commands} + -mysql -uroot -e 'drop database sqlobject_test;' + mysql -uroot -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 + mysql -uroot -e 'drop database sqlobject_test;' + +[testenv:py27-mariadb] +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py34-mariadb] +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py35-mariadb] +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py36-mariadb] +commands = {[mariadb]commands} + +[testenv:py37-mariadb] +commands = {[mariadb]commands} + +[testenv:py38-mariadb] +commands = {[mariadb]commands} + +[testenv:py39-mariadb] +commands = {[mariadb]commands} + [mysql-pyodbc] commands = {[testenv]commands} @@ -793,6 +826,48 @@ commands = {[pymysql-w32]commands} platform = win32 commands = {[pymysql-w32]commands} +[mariadb-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + +[testenv:py27-mariadb-w32] +platform = win32 +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py34-mariadb-w32] +platform = win32 +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py35-mariadb-w32] +platform = win32 +commands = {envpython} -c "print('mariadb requires Python 3.6+')" +deps = + +[testenv:py36-mariadb-w32] +platform = win32 +commands = {[mariadb-w32]commands} + +[testenv:py37-mariadb-w32] +platform = win32 +commands = + cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" + {[mariadb-w32]commands} + +[testenv:py38-mariadb-w32] +platform = win32 +commands = {[mariadb-w32]commands} + +[testenv:py39-mariadb-w32] +platform = win32 +commands = {[mariadb-w32]commands} + [mysql-pyodbc-w32] platform = win32 commands = From fb39c1809498fbb93e5e6dbf23391b8aaaa7efc0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 13 Dec 2020 15:38:49 +0300 Subject: [PATCH 069/295] CI(Travis): Install mysql-compatible development files Install MariaDB mysql-compatible development files to compile mysql drivers. --- .travis.yml | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index c5e810fa..9fddebe6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,13 +14,6 @@ services: - postgres addons: - apt: - packages: - - python-egenix-mxdatetime - - python-mysqldb - - python-psycopg2 - - python3-psycopg2 - - firebird2.5-super postgresql: "9.4" matrix: @@ -41,12 +34,16 @@ matrix: env: TESTS=py39-mysql - python: "3.6" env: TESTS=py36-mariadb + dist: focal - python: "3.7" env: TESTS=py37-mariadb + dist: focal - python: "3.8" env: TESTS=py38-mariadb + dist: focal - python: "3.9" env: TESTS=py39-mariadb + dist: focal - python: "2.7" env: TESTS=py27-postgres - python: "3.4" @@ -89,7 +86,20 @@ matrix: - env: TESTS=py36-firebird before_install: - # Start the firebird database server. + # Install version-specific dependencies + - if [[ $TESTS = py27-* ]]; then + sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2; + fi + - if [[ $TESTS = py3*-* ]]; then + sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2; + fi + # Install MariaDB mysql-compatible development files to compile mysql drivers + - if [[ $TESTS = py3[6789]-mysql ]]; then + sudo apt-get --quiet --yes install libmysqlclient-dev; + elif [[ $TESTS = py3[6789]-mariadb ]]; then + sudo apt-get --quiet --yes install libmariadb-dev-compat; + fi + # Install and start the firebird database server. # We use firebird-super, so there's none of the inetd configuration # required by firebird-classic. # We also create a test user for the firebird test and @@ -98,6 +108,7 @@ before_install: # Copied password initializtion from # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - if [[ $TESTS = *firebird* ]]; then + sudo apt-get --quiet --yes install firebird2.5-super && sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && sudo /etc/init.d/firebird2.5-super start && sleep 5 && sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' && From ed8dd808114faace25c01ead78ae83f2ca09ceb9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 14 Dec 2020 00:55:57 +0300 Subject: [PATCH 070/295] Test(tox): Skip tests with `mysql-connector` and `oursql` On newer Ubuntu (`focal`) they exhibit problems. Need investigation. --- tox.ini | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tox.ini b/tox.ini index e8893f32..5fd8c596 100644 --- a/tox.ini +++ b/tox.ini @@ -124,27 +124,27 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-connector] +[testenv:py27-mysql-connector-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py34-mysql-connector] +[testenv:py34-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py35-mysql-connector] +[testenv:py35-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py36-mysql-connector] +[testenv:py36-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py37-mysql-connector] +[testenv:py37-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py38-mysql-connector] +[testenv:py38-mysql-connector-noauto] commands = {[mysql-connector]commands} -[testenv:py39-mysql-connector] +[testenv:py39-mysql-connector-noauto] commands = {[mysql-connector]commands} [oursql] @@ -155,27 +155,27 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mysql-oursql] +[testenv:py27-mysql-oursql-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py34-mysql-oursql3] +[testenv:py34-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py35-mysql-oursql3] +[testenv:py35-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py36-mysql-oursql3] +[testenv:py36-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py37-mysql-oursql3] +[testenv:py37-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py38-mysql-oursql3] +[testenv:py38-mysql-oursql3-noauto] commands = {[oursql]commands} -[testenv:py39-mysql-oursql3] +[testenv:py39-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] From 27239030fc3098b9653b036f8f95cb17460bcd71 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 14 Dec 2020 01:14:16 +0300 Subject: [PATCH 071/295] Test(tox): Do not restore `validators.py` It seems we no longer need the hack at AppVeyor. --- devscripts/CI/validators.py | 3089 ----------------------------------- tox.ini | 56 +- 2 files changed, 14 insertions(+), 3131 deletions(-) delete mode 100644 devscripts/CI/validators.py diff --git a/devscripts/CI/validators.py b/devscripts/CI/validators.py deleted file mode 100644 index 233d5dd5..00000000 --- a/devscripts/CI/validators.py +++ /dev/null @@ -1,3089 +0,0 @@ -## FormEncode, a Form processor -## Copyright (C) 2003, Ian Bicking - -""" -Validator/Converters for use with FormEncode. -""" - -import cgi -import locale -import re -import warnings -from encodings import idna - -try: # import dnspython - import dns.resolver - import dns.exception -except (IOError, ImportError): - have_dns = False -else: - have_dns = True - - -# These are only imported when needed -httplib = None -random = None -sha1 = None -socket = None -urlparse = None - -from .api import (FancyValidator, Identity, Invalid, NoDefault, Validator, - deprecation_warning, is_empty) - -assert Identity and Invalid and NoDefault # silence unused import warnings - -# Dummy i18n translation function, nothing is translated here. -# Instead this is actually done in api.message. -# The surrounding _('string') of the strings is only for extracting -# the strings automatically. -# If you run pygettext with this source comment this function out temporarily. -_ = lambda s: s - - -############################################################ -## Utility methods -############################################################ - -# These all deal with accepting both datetime and mxDateTime modules and types -datetime_module = None -mxDateTime_module = None - - -def import_datetime(module_type): - global datetime_module, mxDateTime_module - module_type = module_type.lower() if module_type else 'datetime' - if module_type == 'datetime': - if datetime_module is None: - import datetime as datetime_module - return datetime_module - elif module_type == 'mxdatetime': - if mxDateTime_module is None: - from mx import DateTime as mxDateTime_module - return mxDateTime_module - else: - raise ImportError('Invalid datetime module %r' % module_type) - - -def datetime_now(module): - if module.__name__ == 'datetime': - return module.datetime.now() - else: - return module.now() - - -def datetime_makedate(module, year, month, day): - if module.__name__ == 'datetime': - return module.date(year, month, day) - else: - try: - return module.DateTime(year, month, day) - except module.RangeError as e: - raise ValueError(str(e)) - - -def datetime_time(module): - if module.__name__ == 'datetime': - return module.time - else: - return module.Time - - -def datetime_isotime(module): - if module.__name__ == 'datetime': - return module.time.isoformat - else: - return module.ISO.Time - - -############################################################ -## Wrapper Validators -############################################################ - -class ConfirmType(FancyValidator): - """ - Confirms that the input/output is of the proper type. - - Uses the parameters: - - subclass: - The class or a tuple of classes; the item must be an instance - of the class or a subclass. - type: - A type or tuple of types (or classes); the item must be of - the exact class or type. Subclasses are not allowed. - - Examples:: - - >>> cint = ConfirmType(subclass=int) - >>> cint.to_python(True) - True - >>> cint.to_python('1') - Traceback (most recent call last): - ... - Invalid: '1' is not a subclass of - >>> cintfloat = ConfirmType(subclass=(float, int)) - >>> cintfloat.to_python(1.0), cintfloat.from_python(1.0) - (1.0, 1.0) - >>> cintfloat.to_python(1), cintfloat.from_python(1) - (1, 1) - >>> cintfloat.to_python(None) - Traceback (most recent call last): - ... - Invalid: None is not a subclass of one of the types , - >>> cint2 = ConfirmType(type=int) - >>> cint2(accept_python=False).from_python(True) - Traceback (most recent call last): - ... - Invalid: True must be of the type - """ - - accept_iterator = True - - subclass = None - type = None - - messages = dict( - subclass=_('%(object)r is not a subclass of %(subclass)s'), - inSubclass=_('%(object)r is not a subclass of one of the types %(subclassList)s'), - inType=_('%(object)r must be one of the types %(typeList)s'), - type=_('%(object)r must be of the type %(type)s')) - - def __init__(self, *args, **kw): - FancyValidator.__init__(self, *args, **kw) - if self.subclass: - if isinstance(self.subclass, list): - self.subclass = tuple(self.subclass) - elif not isinstance(self.subclass, tuple): - self.subclass = (self.subclass,) - self._validate_python = self.confirm_subclass - if self.type: - if isinstance(self.type, list): - self.type = tuple(self.type) - elif not isinstance(self.type, tuple): - self.type = (self.type,) - self._validate_python = self.confirm_type - - def confirm_subclass(self, value, state): - if not isinstance(value, self.subclass): - if len(self.subclass) == 1: - msg = self.message('subclass', state, object=value, - subclass=self.subclass[0]) - else: - subclass_list = ', '.join(map(str, self.subclass)) - msg = self.message('inSubclass', state, object=value, - subclassList=subclass_list) - raise Invalid(msg, value, state) - - def confirm_type(self, value, state): - for t in self.type: - if type(value) is t: - break - else: - if len(self.type) == 1: - msg = self.message('type', state, object=value, - type=self.type[0]) - else: - msg = self.message('inType', state, object=value, - typeList=', '.join(map(str, self.type))) - raise Invalid(msg, value, state) - return value - - def is_empty(self, value): - return False - - -class Wrapper(FancyValidator): - """ - Used to convert functions to validator/converters. - - You can give a simple function for `_convert_to_python`, - `_convert_from_python`, `_validate_python` or `_validate_other`. - If that function raises an exception, the value is considered invalid. - Whatever value the function returns is considered the converted value. - - Unlike validators, the `state` argument is not used. Functions - like `int` can be used here, that take a single argument. - - Note that as Wrapper will generate a FancyValidator, empty - values (those who pass ``FancyValidator.is_empty)`` will return ``None``. - To override this behavior you can use ``Wrapper(empty_value=callable)``. - For example passing ``Wrapper(empty_value=lambda val: val)`` will return - the value itself when is considered empty. - - Examples:: - - >>> def downcase(v): - ... return v.lower() - >>> wrap = Wrapper(convert_to_python=downcase) - >>> wrap.to_python('This') - 'this' - >>> wrap.from_python('This') - 'This' - >>> wrap.to_python('') is None - True - >>> wrap2 = Wrapper( - ... convert_from_python=downcase, empty_value=lambda value: value) - >>> wrap2.from_python('This') - 'this' - >>> wrap2.to_python('') - '' - >>> wrap2.from_python(1) - Traceback (most recent call last): - ... - Invalid: 'int' object has no attribute 'lower' - >>> wrap3 = Wrapper(validate_python=int) - >>> wrap3.to_python('1') - '1' - >>> wrap3.to_python('a') # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - Invalid: invalid literal for int()... - """ - - func_convert_to_python = None - func_convert_from_python = None - func_validate_python = None - func_validate_other = None - - _deprecated_methods = ( - ('func_to_python', 'func_convert_to_python'), - ('func_from_python', 'func_convert_from_python')) - - def __init__(self, *args, **kw): - # allow old method names as parameters - if 'to_python' in kw and 'convert_to_python' not in kw: - kw['convert_to_python'] = kw.pop('to_python') - if 'from_python' in kw and 'convert_from_python' not in kw: - kw['convert_from_python'] = kw.pop('from_python') - for n in ('convert_to_python', 'convert_from_python', - 'validate_python', 'validate_other'): - if n in kw: - kw['func_%s' % n] = kw.pop(n) - FancyValidator.__init__(self, *args, **kw) - self._convert_to_python = self.wrap(self.func_convert_to_python) - self._convert_from_python = self.wrap(self.func_convert_from_python) - self._validate_python = self.wrap(self.func_validate_python) - self._validate_other = self.wrap(self.func_validate_other) - - def wrap(self, func): - if not func: - return None - - def result(value, state, func=func): - try: - return func(value) - except Exception as e: - raise Invalid(str(e), value, state) - - return result - - -class Constant(FancyValidator): - """ - This converter converts everything to the same thing. - - I.e., you pass in the constant value when initializing, then all - values get converted to that constant value. - - This is only really useful for funny situations, like:: - - # Any evaluates sub validators in reverse order for to_python - fromEmailValidator = Any( - Constant('unknown@localhost'), - Email()) - - In this case, the if the email is not valid - ``'unknown@localhost'`` will be used instead. Of course, you - could use ``if_invalid`` instead. - - Examples:: - - >>> Constant('X').to_python('y') - 'X' - """ - - __unpackargs__ = ('value',) - - def _convert_to_python(self, value, state): - return self.value - - _convert_from_python = _convert_to_python - - -############################################################ -## Normal validators -############################################################ - -class MaxLength(FancyValidator): - """ - Invalid if the value is longer than `maxLength`. Uses len(), - so it can work for strings, lists, or anything with length. - - Examples:: - - >>> max5 = MaxLength(5) - >>> max5.to_python('12345') - '12345' - >>> max5.from_python('12345') - '12345' - >>> max5.to_python('123456') - Traceback (most recent call last): - ... - Invalid: Enter a value less than 5 characters long - >>> max5(accept_python=False).from_python('123456') - Traceback (most recent call last): - ... - Invalid: Enter a value less than 5 characters long - >>> max5.to_python([1, 2, 3]) - [1, 2, 3] - >>> max5.to_python([1, 2, 3, 4, 5, 6]) - Traceback (most recent call last): - ... - Invalid: Enter a value less than 5 characters long - >>> max5.to_python(5) - Traceback (most recent call last): - ... - Invalid: Invalid value (value with length expected) - """ - - __unpackargs__ = ('maxLength',) - - messages = dict( - tooLong=_('Enter a value less than %(maxLength)i characters long'), - invalid=_('Invalid value (value with length expected)')) - - def _validate_python(self, value, state): - try: - if value and len(value) > self.maxLength: - raise Invalid( - self.message('tooLong', state, - maxLength=self.maxLength), value, state) - else: - return None - except TypeError: - raise Invalid( - self.message('invalid', state), value, state) - - -class MinLength(FancyValidator): - """ - Invalid if the value is shorter than `minlength`. Uses len(), so - it can work for strings, lists, or anything with length. Note - that you **must** use ``not_empty=True`` if you don't want to - accept empty values -- empty values are not tested for length. - - Examples:: - - >>> min5 = MinLength(5) - >>> min5.to_python('12345') - '12345' - >>> min5.from_python('12345') - '12345' - >>> min5.to_python('1234') - Traceback (most recent call last): - ... - Invalid: Enter a value at least 5 characters long - >>> min5(accept_python=False).from_python('1234') - Traceback (most recent call last): - ... - Invalid: Enter a value at least 5 characters long - >>> min5.to_python([1, 2, 3, 4, 5]) - [1, 2, 3, 4, 5] - >>> min5.to_python([1, 2, 3]) - Traceback (most recent call last): - ... - Invalid: Enter a value at least 5 characters long - >>> min5.to_python(5) - Traceback (most recent call last): - ... - Invalid: Invalid value (value with length expected) - - """ - - __unpackargs__ = ('minLength',) - - messages = dict( - tooShort=_('Enter a value at least %(minLength)i characters long'), - invalid=_('Invalid value (value with length expected)')) - - def _validate_python(self, value, state): - try: - if len(value) < self.minLength: - raise Invalid( - self.message('tooShort', state, - minLength=self.minLength), value, state) - except TypeError: - raise Invalid( - self.message('invalid', state), value, state) - - -class NotEmpty(FancyValidator): - """ - Invalid if value is empty (empty string, empty list, etc). - - Generally for objects that Python considers false, except zero - which is not considered invalid. - - Examples:: - - >>> ne = NotEmpty(messages=dict(empty='enter something')) - >>> ne.to_python('') - Traceback (most recent call last): - ... - Invalid: enter something - >>> ne.to_python(0) - 0 - """ - not_empty = True - - messages = dict( - empty=_('Please enter a value')) - - def _validate_python(self, value, state): - if value == 0: - # This isn't "empty" for this definition. - return value - if not value: - raise Invalid(self.message('empty', state), value, state) - - -class Empty(FancyValidator): - """ - Invalid unless the value is empty. Use cleverly, if at all. - - Examples:: - - >>> Empty.to_python(0) - Traceback (most recent call last): - ... - Invalid: You cannot enter a value here - """ - - messages = dict( - notEmpty=_('You cannot enter a value here')) - - def _validate_python(self, value, state): - if value or value == 0: - raise Invalid(self.message('notEmpty', state), value, state) - - -class Regex(FancyValidator): - """ - Invalid if the value doesn't match the regular expression `regex`. - - The regular expression can be a compiled re object, or a string - which will be compiled for you. - - Use strip=True if you want to strip the value before validation, - and as a form of conversion (often useful). - - Examples:: - - >>> cap = Regex(r'^[A-Z]+$') - >>> cap.to_python('ABC') - 'ABC' - - Note that ``.from_python()`` calls (in general) do not validate - the input:: - - >>> cap.from_python('abc') - 'abc' - >>> cap(accept_python=False).from_python('abc') - Traceback (most recent call last): - ... - Invalid: The input is not valid - >>> cap.to_python(1) - Traceback (most recent call last): - ... - Invalid: The input must be a string (not a : 1) - >>> Regex(r'^[A-Z]+$', strip=True).to_python(' ABC ') - 'ABC' - >>> Regex(r'this', regexOps=('I',)).to_python('THIS') - 'THIS' - """ - - regexOps = () - strip = False - regex = None - - __unpackargs__ = ('regex',) - - messages = dict( - invalid=_('The input is not valid')) - - def __init__(self, *args, **kw): - FancyValidator.__init__(self, *args, **kw) - if isinstance(self.regex, str): - ops = 0 - assert not isinstance(self.regexOps, str), ( - "regexOps should be a list of options from the re module " - "(names, or actual values)") - for op in self.regexOps: - if isinstance(op, str): - ops |= getattr(re, op) - else: - ops |= op - self.regex = re.compile(self.regex, ops) - - def _validate_python(self, value, state): - self.assert_string(value, state) - if self.strip and isinstance(value, str): - value = value.strip() - if not self.regex.search(value): - raise Invalid(self.message('invalid', state), value, state) - - def _convert_to_python(self, value, state): - if self.strip and isinstance(value, str): - return value.strip() - return value - - -class PlainText(Regex): - """ - Test that the field contains only letters, numbers, underscore, - and the hyphen. Subclasses Regex. - - Examples:: - - >>> PlainText.to_python('_this9_') - '_this9_' - >>> PlainText.from_python(' this ') - ' this ' - >>> PlainText(accept_python=False).from_python(' this ') - Traceback (most recent call last): - ... - Invalid: Enter only letters, numbers, or _ (underscore) - >>> PlainText(strip=True).to_python(' this ') - 'this' - >>> PlainText(strip=True).from_python(' this ') - 'this' - """ - - regex = r"^[a-zA-Z_\-0-9]*$" - - messages = dict( - invalid=_('Enter only letters, numbers, or _ (underscore)')) - - -class OneOf(FancyValidator): - """ - Tests that the value is one of the members of a given list. - - If ``testValueList=True``, then if the input value is a list or - tuple, all the members of the sequence will be checked (i.e., the - input must be a subset of the allowed values). - - Use ``hideList=True`` to keep the list of valid values out of the - error message in exceptions. - - Examples:: - - >>> oneof = OneOf([1, 2, 3]) - >>> oneof.to_python(1) - 1 - >>> oneof.to_python(4) - Traceback (most recent call last): - ... - Invalid: Value must be one of: 1; 2; 3 (not 4) - >>> oneof(testValueList=True).to_python([2, 3, [1, 2, 3]]) - [2, 3, [1, 2, 3]] - >>> oneof.to_python([2, 3, [1, 2, 3]]) - Traceback (most recent call last): - ... - Invalid: Value must be one of: 1; 2; 3 (not [2, 3, [1, 2, 3]]) - """ - - list = None - testValueList = False - hideList = False - - __unpackargs__ = ('list',) - - messages = dict( - invalid=_('Invalid value'), - notIn=_('Value must be one of: %(items)s (not %(value)r)')) - - def _validate_python(self, value, state): - if self.testValueList and isinstance(value, (list, tuple)): - for v in value: - self._validate_python(v, state) - else: - if not value in self.list: - if self.hideList: - raise Invalid(self.message('invalid', state), value, state) - else: - try: - items = '; '.join(map(str, self.list)) - except UnicodeError: - items = '; '.join(map(str, self.list)) - raise Invalid( - self.message('notIn', state, - items=items, value=value), value, state) - - @property - def accept_iterator(self): - return self.testValueList - - -class DictConverter(FancyValidator): - """ - Converts values based on a dictionary which has values as keys for - the resultant values. - - If ``allowNull`` is passed, it will not balk if a false value - (e.g., '' or None) is given (it will return None in these cases). - - to_python takes keys and gives values, from_python takes values and - gives keys. - - If you give hideDict=True, then the contents of the dictionary - will not show up in error messages. - - Examples:: - - >>> dc = DictConverter({1: 'one', 2: 'two'}) - >>> dc.to_python(1) - 'one' - >>> dc.from_python('one') - 1 - >>> dc.to_python(3) - Traceback (most recent call last): - .... - Invalid: Enter a value from: 1; 2 - >>> dc2 = dc(hideDict=True) - >>> dc2.hideDict - True - >>> dc2.dict - {1: 'one', 2: 'two'} - >>> dc2.to_python(3) - Traceback (most recent call last): - .... - Invalid: Choose something - >>> dc.from_python('three') - Traceback (most recent call last): - .... - Invalid: Nothing in my dictionary goes by the value 'three'. Choose one of: 'one'; 'two' - """ - - messages = dict( - keyNotFound=_('Choose something'), - chooseKey=_('Enter a value from: %(items)s'), - valueNotFound=_('That value is not known'), - chooseValue=_('Nothing in my dictionary goes by the value %(value)s.' - ' Choose one of: %(items)s')) - - dict = None - hideDict = False - - __unpackargs__ = ('dict',) - - def _convert_to_python(self, value, state): - try: - return self.dict[value] - except KeyError: - if self.hideDict: - raise Invalid(self.message('keyNotFound', state), value, state) - else: - items = sorted(self.dict) - items = '; '.join(map(repr, items)) - raise Invalid(self.message('chooseKey', - state, items=items), value, state) - - def _convert_from_python(self, value, state): - for k, v in self.dict.items(): - if value == v: - return k - if self.hideDict: - raise Invalid(self.message('valueNotFound', state), value, state) - else: - items = '; '.join(map(repr, iter(self.dict.values()))) - raise Invalid( - self.message('chooseValue', state, - value=repr(value), items=items), value, state) - - -class IndexListConverter(FancyValidator): - """ - Converts a index (which may be a string like '2') to the value in - the given list. - - Examples:: - - >>> index = IndexListConverter(['zero', 'one', 'two']) - >>> index.to_python(0) - 'zero' - >>> index.from_python('zero') - 0 - >>> index.to_python('1') - 'one' - >>> index.to_python(5) - Traceback (most recent call last): - Invalid: Index out of range - >>> index(not_empty=True).to_python(None) - Traceback (most recent call last): - Invalid: Please enter a value - >>> index.from_python('five') - Traceback (most recent call last): - Invalid: Item 'five' was not found in the list - """ - - list = None - - __unpackargs__ = ('list',) - - messages = dict( - integer=_('Must be an integer index'), - outOfRange=_('Index out of range'), - notFound=_('Item %(value)s was not found in the list')) - - def _convert_to_python(self, value, state): - try: - value = int(value) - except (ValueError, TypeError): - raise Invalid(self.message('integer', state), value, state) - try: - return self.list[value] - except IndexError: - raise Invalid(self.message('outOfRange', state), value, state) - - def _convert_from_python(self, value, state): - for i, v in enumerate(self.list): - if v == value: - return i - raise Invalid( - self.message('notFound', state, value=repr(value)), value, state) - - -class DateValidator(FancyValidator): - """ - Validates that a date is within the given range. Be sure to call - DateConverter first if you aren't expecting mxDateTime input. - - ``earliest_date`` and ``latest_date`` may be functions; if so, - they will be called each time before validating. - - ``after_now`` means a time after the current timestamp; note that - just a few milliseconds before now is invalid! ``today_or_after`` - is more permissive, and ignores hours and minutes. - - Examples:: - - >>> from datetime import datetime, timedelta - >>> d = DateValidator(earliest_date=datetime(2003, 1, 1)) - >>> d.to_python(datetime(2004, 1, 1)) - datetime.datetime(2004, 1, 1, 0, 0) - >>> d.to_python(datetime(2002, 1, 1)) - Traceback (most recent call last): - ... - Invalid: Date must be after Wednesday, 01 January 2003 - >>> d.to_python(datetime(2003, 1, 1)) - datetime.datetime(2003, 1, 1, 0, 0) - >>> d = DateValidator(after_now=True) - >>> now = datetime.now() - >>> d.to_python(now+timedelta(seconds=5)) == now+timedelta(seconds=5) - True - >>> d.to_python(now-timedelta(days=1)) - Traceback (most recent call last): - ... - Invalid: The date must be sometime in the future - >>> d.to_python(now+timedelta(days=1)) > now - True - >>> d = DateValidator(today_or_after=True) - >>> d.to_python(now) == now - True - - """ - - earliest_date = None - latest_date = None - after_now = False - # Like after_now, but just after this morning: - today_or_after = False - # Use None or 'datetime' for the datetime module in the standard lib, - # or 'mxDateTime' to force the mxDateTime module - datetime_module = None - - messages = dict( - after=_('Date must be after %(date)s'), - before=_('Date must be before %(date)s'), - # Double %'s, because this will be substituted twice: - date_format=_('%%A, %%d %%B %%Y'), - future=_('The date must be sometime in the future')) - - def _validate_python(self, value, state): - date_format = self.message('date_format', state) - if (str is not str # Python 2 - and isinstance(date_format, str)): - # strftime uses the locale encoding, not Unicode - encoding = locale.getlocale(locale.LC_TIME)[1] or 'utf-8' - date_format = date_format.encode(encoding) - else: - encoding = None - if self.earliest_date: - if callable(self.earliest_date): - earliest_date = self.earliest_date() - else: - earliest_date = self.earliest_date - if value < earliest_date: - date_formatted = earliest_date.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('after', state, date=date_formatted), - value, state) - if self.latest_date: - if callable(self.latest_date): - latest_date = self.latest_date() - else: - latest_date = self.latest_date - if value > latest_date: - date_formatted = latest_date.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('before', state, date=date_formatted), - value, state) - if self.after_now: - dt_mod = import_datetime(self.datetime_module) - now = datetime_now(dt_mod) - if value < now: - date_formatted = now.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('future', state, date=date_formatted), - value, state) - if self.today_or_after: - dt_mod = import_datetime(self.datetime_module) - now = datetime_now(dt_mod) - today = datetime_makedate(dt_mod, - now.year, now.month, now.day) - value_as_date = datetime_makedate( - dt_mod, value.year, value.month, value.day) - if value_as_date < today: - date_formatted = now.strftime(date_format) - if encoding: - date_formatted = date_formatted.decode(encoding) - raise Invalid( - self.message('future', state, date=date_formatted), - value, state) - - -class Bool(FancyValidator): - """ - Always Valid, returns True or False based on the value and the - existance of the value. - - If you want to convert strings like ``'true'`` to booleans, then - use ``StringBool``. - - Examples:: - - >>> Bool.to_python(0) - False - >>> Bool.to_python(1) - True - >>> Bool.to_python('') - False - >>> Bool.to_python(None) - False - """ - - if_missing = False - - def _convert_to_python(self, value, state): - return bool(value) - - _convert_from_python = _convert_to_python - - def empty_value(self, value): - return False - - -class RangeValidator(FancyValidator): - """This is an abstract base class for Int and Number. - - It verifies that a value is within range. It accepts min and max - values in the constructor. - - (Since this is an abstract base class, the tests are in Int and Number.) - - """ - - messages = dict( - tooLow=_('Please enter a number that is %(min)s or greater'), - tooHigh=_('Please enter a number that is %(max)s or smaller')) - - min = None - max = None - - def _validate_python(self, value, state): - if self.min is not None: - if value < self.min: - msg = self.message('tooLow', state, min=self.min) - raise Invalid(msg, value, state) - if self.max is not None: - if value > self.max: - msg = self.message('tooHigh', state, max=self.max) - raise Invalid(msg, value, state) - - -class Int(RangeValidator): - """Convert a value to an integer. - - Example:: - - >>> Int.to_python('10') - 10 - >>> Int.to_python('ten') - Traceback (most recent call last): - ... - Invalid: Please enter an integer value - >>> Int(min=5).to_python('6') - 6 - >>> Int(max=10).to_python('11') - Traceback (most recent call last): - ... - Invalid: Please enter a number that is 10 or smaller - - """ - - messages = dict( - integer=_('Please enter an integer value')) - - def _convert_to_python(self, value, state): - try: - return int(value) - except (ValueError, TypeError): - raise Invalid(self.message('integer', state), value, state) - - _convert_from_python = _convert_to_python - - -class Number(RangeValidator): - """Convert a value to a float or integer. - - Tries to convert it to an integer if no information is lost. - - Example:: - - >>> Number.to_python('10') - 10 - >>> Number.to_python('10.5') - 10.5 - >>> Number.to_python('ten') - Traceback (most recent call last): - ... - Invalid: Please enter a number - >>> Number.to_python([1.2]) - Traceback (most recent call last): - ... - Invalid: Please enter a number - >>> Number(min=5).to_python('6.5') - 6.5 - >>> Number(max=10.5).to_python('11.5') - Traceback (most recent call last): - ... - Invalid: Please enter a number that is 10.5 or smaller - - """ - - messages = dict( - number=_('Please enter a number')) - - def _convert_to_python(self, value, state): - try: - value = float(value) - try: - int_value = int(value) - except OverflowError: - int_value = None - if value == int_value: - return int_value - return value - except (ValueError, TypeError): - raise Invalid(self.message('number', state), value, state) - - -class ByteString(FancyValidator): - """Convert to byte string, treating empty things as the empty string. - - Under Python 2.x you can also use the alias `String` for this validator. - - Also takes a `max` and `min` argument, and the string length must fall - in that range. - - Also you may give an `encoding` argument, which will encode any unicode - that is found. Lists and tuples are joined with `list_joiner` - (default ``', '``) in ``from_python``. - - :: - - >>> ByteString(min=2).to_python('a') - Traceback (most recent call last): - ... - Invalid: Enter a value 2 characters long or more - >>> ByteString(max=10).to_python('xxxxxxxxxxx') - Traceback (most recent call last): - ... - Invalid: Enter a value not more than 10 characters long - >>> ByteString().from_python(None) - '' - >>> ByteString().from_python([]) - '' - >>> ByteString().to_python(None) - '' - >>> ByteString(min=3).to_python(None) - Traceback (most recent call last): - ... - Invalid: Please enter a value - >>> ByteString(min=1).to_python('') - Traceback (most recent call last): - ... - Invalid: Please enter a value - - """ - - min = None - max = None - not_empty = None - encoding = None - list_joiner = ', ' - - messages = dict( - tooLong=_('Enter a value not more than %(max)i characters long'), - tooShort=_('Enter a value %(min)i characters long or more')) - - def __initargs__(self, new_attrs): - if self.not_empty is None and self.min: - self.not_empty = True - - def _convert_to_python(self, value, state): - if value is None: - value = '' - elif not isinstance(value, str): - try: - value = bytes(value) - except UnicodeEncodeError: - value = str(value) - if self.encoding is not None and isinstance(value, str): - value = value.encode(self.encoding) - return value - - def _convert_from_python(self, value, state): - if value is None: - value = '' - elif not isinstance(value, str): - if isinstance(value, (list, tuple)): - value = self.list_joiner.join( - self._convert_from_python(v, state) for v in value) - try: - value = str(value) - except UnicodeEncodeError: - value = str(value) - if self.encoding is not None and isinstance(value, str): - value = value.encode(self.encoding) - if self.strip: - value = value.strip() - return value - - def _validate_other(self, value, state): - if self.max is None and self.min is None: - return - if value is None: - value = '' - elif not isinstance(value, str): - try: - value = str(value) - except UnicodeEncodeError: - value = str(value) - if self.max is not None and len(value) > self.max: - raise Invalid( - self.message('tooLong', state, max=self.max), value, state) - if self.min is not None and len(value) < self.min: - raise Invalid( - self.message('tooShort', state, min=self.min), value, state) - - def empty_value(self, value): - return '' - - -class UnicodeString(ByteString): - """Convert things to unicode string. - - This is implemented as a specialization of the ByteString class. - - Under Python 3.x you can also use the alias `String` for this validator. - - In addition to the String arguments, an encoding argument is also - accepted. By default the encoding will be utf-8. You can overwrite - this using the encoding parameter. You can also set inputEncoding - and outputEncoding differently. An inputEncoding of None means - "do not decode", an outputEncoding of None means "do not encode". - - All converted strings are returned as Unicode strings. - - :: - - >>> UnicodeString().to_python(None) - u'' - >>> UnicodeString().to_python([]) - u'' - >>> UnicodeString(encoding='utf-7').to_python('Ni Ni Ni') - u'Ni Ni Ni' - - """ - encoding = 'utf-8' - inputEncoding = NoDefault - outputEncoding = NoDefault - messages = dict( - badEncoding=_('Invalid data or incorrect encoding')) - - def __init__(self, **kw): - ByteString.__init__(self, **kw) - if self.inputEncoding is NoDefault: - self.inputEncoding = self.encoding - if self.outputEncoding is NoDefault: - self.outputEncoding = self.encoding - - def _convert_to_python(self, value, state): - if not value: - return '' - if isinstance(value, str): - return value - if not isinstance(value, str): - if hasattr(value, '__unicode__'): - value = str(value) - return value - if not (str is str # Python 3 - and isinstance(value, bytes) and self.inputEncoding): - value = str(value) - if self.inputEncoding and not isinstance(value, str): - try: - value = str(value, self.inputEncoding) - except UnicodeDecodeError: - raise Invalid(self.message('badEncoding', state), value, state) - except TypeError: - raise Invalid( - self.message('badType', state, - type=type(value), value=value), value, state) - return value - - def _convert_from_python(self, value, state): - if not isinstance(value, str): - if hasattr(value, '__unicode__'): - value = str(value) - else: - value = str(value) - if self.outputEncoding and isinstance(value, str): - value = value.encode(self.outputEncoding) - return value - - def empty_value(self, value): - return '' - - -# Provide proper alias for native strings - -String = UnicodeString if str is str else ByteString - - -class Set(FancyValidator): - """ - This is for when you think you may return multiple values for a - certain field. - - This way the result will always be a list, even if there's only - one result. It's equivalent to ForEach(convert_to_list=True). - - If you give ``use_set=True``, then it will return an actual - ``set`` object. - - :: - - >>> Set.to_python(None) - [] - >>> Set.to_python('this') - ['this'] - >>> Set.to_python(('this', 'that')) - ['this', 'that'] - >>> s = Set(use_set=True) - >>> s.to_python(None) - set([]) - >>> s.to_python('this') - set(['this']) - >>> s.to_python(('this',)) - set(['this']) - """ - - use_set = False - - if_missing = () - accept_iterator = True - - def _convert_to_python(self, value, state): - if self.use_set: - if isinstance(value, set): - return value - elif isinstance(value, (list, tuple)): - return set(value) - elif value is None: - return set() - else: - return set([value]) - else: - if isinstance(value, list): - return value - elif isinstance(value, set): - return list(value) - elif isinstance(value, tuple): - return list(value) - elif value is None: - return [] - else: - return [value] - - def empty_value(self, value): - if self.use_set: - return set() - else: - return [] - - -class Email(FancyValidator): - r""" - Validate an email address. - - If you pass ``resolve_domain=True``, then it will try to resolve - the domain name to make sure it's valid. This takes longer, of - course. You must have the `dnspython `__ modules - installed to look up DNS (MX and A) records. - - :: - - >>> e = Email() - >>> e.to_python(' test@foo.com ') - 'test@foo.com' - >>> e.to_python('test') - Traceback (most recent call last): - ... - Invalid: An email address must contain a single @ - >>> e.to_python('test@foobar') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: foobar) - >>> e.to_python('test@foobar.com.5') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: foobar.com.5) - >>> e.to_python('test@foo..bar.com') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: foo..bar.com) - >>> e.to_python('test@.foo.bar.com') - Traceback (most recent call last): - ... - Invalid: The domain portion of the email address is invalid (the portion after the @: .foo.bar.com) - >>> e.to_python('nobody@xn--m7r7ml7t24h.com') - 'nobody@xn--m7r7ml7t24h.com' - >>> e.to_python('o*reilly@test.com') - 'o*reilly@test.com' - >>> e = Email(resolve_domain=True) - >>> e.resolve_domain - True - >>> e.to_python('doesnotexist@colorstudy.com') - 'doesnotexist@colorstudy.com' - >>> e.to_python('test@nyu.edu') - 'test@nyu.edu' - >>> # NOTE: If you do not have dnspython installed this example won't work: - >>> e.to_python('test@thisdomaindoesnotexistithinkforsure.com') - Traceback (most recent call last): - ... - Invalid: The domain of the email address does not exist (the portion after the @: thisdomaindoesnotexistithinkforsure.com) - >>> e.to_python('test@google.com') - u'test@google.com' - >>> e = Email(not_empty=False) - >>> e.to_python('') - - """ - - resolve_domain = False - resolve_timeout = 10 # timeout in seconds when resolving domains - - usernameRE = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") - domainRE = re.compile(r''' - ^(?:[a-z0-9][a-z0-9\-]{,62}\.)+ # subdomain - (?:[a-z]{2,63}|xn--[a-z0-9\-]{2,59})$ # top level domain - ''', re.I | re.VERBOSE) - - messages = dict( - empty=_('Please enter an email address'), - noAt=_('An email address must contain a single @'), - badUsername=_('The username portion of the email address is invalid' - ' (the portion before the @: %(username)s)'), - socketError=_('An error occured when trying to connect to the server:' - ' %(error)s'), - badDomain=_('The domain portion of the email address is invalid' - ' (the portion after the @: %(domain)s)'), - domainDoesNotExist=_('The domain of the email address does not exist' - ' (the portion after the @: %(domain)s)')) - - def __init__(self, *args, **kw): - FancyValidator.__init__(self, *args, **kw) - if self.resolve_domain: - if not have_dns: - warnings.warn( - "dnspython is not installed on" - " your system (or the dns.resolver package cannot be found)." - " I cannot resolve domain names in addresses") - raise ImportError("no module named dns.resolver") - - def _validate_python(self, value, state): - if not value: - raise Invalid(self.message('empty', state), value, state) - value = value.strip() - splitted = value.split('@', 1) - try: - username, domain = splitted - except ValueError: - raise Invalid(self.message('noAt', state), value, state) - if not self.usernameRE.search(username): - raise Invalid( - self.message('badUsername', state, username=username), - value, state) - try: - idna_domain = [idna.ToASCII(p) for p in domain.split('.')] - if str is str: # Python 3 - idna_domain = [p.decode('ascii') for p in idna_domain] - idna_domain = '.'.join(idna_domain) - except UnicodeError: - # UnicodeError: label empty or too long - # This exception might happen if we have an invalid domain name part - # (for example test@.foo.bar.com) - raise Invalid( - self.message('badDomain', state, domain=domain), - value, state) - if not self.domainRE.search(idna_domain): - raise Invalid( - self.message('badDomain', state, domain=domain), - value, state) - if self.resolve_domain: - assert have_dns, "dnspython should be available" - global socket - if socket is None: - import socket - try: - try: - dns.resolver.query(domain, 'MX') - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: - try: - dns.resolver.query(domain, 'A') - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: - raise Invalid( - self.message('domainDoesNotExist', - state, domain=domain), value, state) - except (socket.error, dns.exception.DNSException) as e: - raise Invalid( - self.message('socketError', state, error=e), value, state) - - def _convert_to_python(self, value, state): - return value.strip() - - -class URL(FancyValidator): - """ - Validate a URL, either http://... or https://. If check_exists - is true, then we'll actually make a request for the page. - - If add_http is true, then if no scheme is present we'll add - http:// - - :: - - >>> u = URL(add_http=True) - >>> u.to_python('foo.com') - 'http://foo.com' - >>> u.to_python('http://hahaha.ha/bar.html') - 'http://hahaha.ha/bar.html' - >>> u.to_python('http://xn--m7r7ml7t24h.com') - 'http://xn--m7r7ml7t24h.com' - >>> u.to_python('http://xn--c1aay4a.xn--p1ai') - 'http://xn--c1aay4a.xn--p1ai' - >>> u.to_python('http://foo.com/test?bar=baz&fleem=morx') - 'http://foo.com/test?bar=baz&fleem=morx' - >>> u.to_python('http://foo.com/login?came_from=http%3A%2F%2Ffoo.com%2Ftest') - 'http://foo.com/login?came_from=http%3A%2F%2Ffoo.com%2Ftest' - >>> u.to_python('http://foo.com:8000/test.html') - 'http://foo.com:8000/test.html' - >>> u.to_python('http://foo.com/something\\nelse') - Traceback (most recent call last): - ... - Invalid: That is not a valid URL - >>> u.to_python('https://test.com') - 'https://test.com' - >>> u.to_python('http://test') - Traceback (most recent call last): - ... - Invalid: You must provide a full domain name (like test.com) - >>> u.to_python('http://test..com') - Traceback (most recent call last): - ... - Invalid: That is not a valid URL - >>> u = URL(add_http=False, check_exists=True) - >>> u.to_python('http://google.com') - 'http://google.com' - >>> u.to_python('google.com') - Traceback (most recent call last): - ... - Invalid: You must start your URL with http://, https://, etc - >>> u.to_python('http://www.formencode.org/does/not/exist/page.html') - Traceback (most recent call last): - ... - Invalid: The server responded that the page could not be found - >>> u.to_python('http://this.domain.does.not.exist.example.org/test.html') - ... # doctest: +ELLIPSIS - Traceback (most recent call last): - ... - Invalid: An error occured when trying to connect to the server: ... - - If you want to allow addresses without a TLD (e.g., ``localhost``) you can do:: - - >>> URL(require_tld=False).to_python('http://localhost') - 'http://localhost' - - By default, internationalized domain names (IDNA) in Unicode will be - accepted and encoded to ASCII using Punycode (as described in RFC 3490). - You may set allow_idna to False to change this behavior:: - - >>> URL(allow_idna=True).to_python( - ... 'http://\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') - 'http://xn--c1aay4a.xn--p1ai' - >>> URL(allow_idna=True, add_http=True).to_python( - ... '\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') - 'http://xn--c1aay4a.xn--p1ai' - >>> URL(allow_idna=False).to_python( - ... 'http://\\u0433\\u0443\\u0433\\u043b.\\u0440\\u0444') - Traceback (most recent call last): - ... - Invalid: That is not a valid URL - - """ - - add_http = True - allow_idna = True - check_exists = False - require_tld = True - - url_re = re.compile(r''' - ^(http|https):// - (?:[%:\w]*@)? # authenticator - (?: # ip or domain - (?P(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))| - (?P[a-z0-9][a-z0-9\-]{,62}\.)* # subdomain - (?P[a-z]{2,63}|xn--[a-z0-9\-]{2,59}) # top level domain - ) - (?::[0-9]{1,5})? # port - # files/delims/etc - (?P/[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]*)? - $ - ''', re.I | re.VERBOSE) - - scheme_re = re.compile(r'^[a-zA-Z]+:') - - messages = dict( - noScheme=_('You must start your URL with http://, https://, etc'), - badURL=_('That is not a valid URL'), - httpError=_('An error occurred when trying to access the URL:' - ' %(error)s'), - socketError=_('An error occured when trying to connect to the server:' - ' %(error)s'), - notFound=_('The server responded that the page could not be found'), - status=_('The server responded with a bad status code (%(status)s)'), - noTLD=_('You must provide a full domain name (like %(domain)s.com)')) - - def _convert_to_python(self, value, state): - value = value.strip() - if self.add_http: - if not self.scheme_re.search(value): - value = 'http://' + value - if self.allow_idna: - value = self._encode_idna(value) - match = self.scheme_re.search(value) - if not match: - raise Invalid(self.message('noScheme', state), value, state) - value = match.group(0).lower() + value[len(match.group(0)):] - match = self.url_re.search(value) - if not match: - raise Invalid(self.message('badURL', state), value, state) - if self.require_tld and not match.group('domain'): - raise Invalid( - self.message('noTLD', state, domain=match.group('tld')), - value, state) - if self.check_exists and value.startswith(('http://', 'https://')): - self._check_url_exists(value, state) - return value - - def _encode_idna(self, url): - global urlparse - if urlparse is None: - import urllib.parse - try: - scheme, netloc, path, params, query, fragment = urllib.parse.urlparse( - url) - except ValueError: - return url - try: - netloc = netloc.encode('idna') - if str is str: # Python 3 - netloc = netloc.decode('ascii') - return str(urllib.parse.urlunparse((scheme, netloc, - path, params, query, fragment))) - except UnicodeError: - return url - - def _check_url_exists(self, url, state): - global httplib, urlparse, socket - if httplib is None: - import http.client - if urlparse is None: - import urllib.parse - if socket is None: - import socket - scheme, netloc, path, params, query, fragment = urllib.parse.urlparse( - url, 'http') - if scheme == 'https': - ConnClass = http.client.HTTPSConnection - else: - ConnClass = http.client.HTTPConnection - try: - conn = ConnClass(netloc) - if params: - path += ';' + params - if query: - path += '?' + query - conn.request('HEAD', path) - res = conn.getresponse() - except http.client.HTTPException as e: - raise Invalid( - self.message('httpError', state, error=e), state, url) - except socket.error as e: - raise Invalid( - self.message('socketError', state, error=e), state, url) - else: - if res.status == 404: - raise Invalid( - self.message('notFound', state), state, url) - if not 200 <= res.status < 500: - raise Invalid( - self.message('status', state, status=res.status), - state, url) - - -class XRI(FancyValidator): - r""" - Validator for XRIs. - - It supports both i-names and i-numbers, of the first version of the XRI - standard. - - :: - - >>> inames = XRI(xri_type="i-name") - >>> inames.to_python(" =John.Smith ") - '=John.Smith' - >>> inames.to_python("@Free.Software.Foundation") - '@Free.Software.Foundation' - >>> inames.to_python("Python.Software.Foundation") - Traceback (most recent call last): - ... - Invalid: The type of i-name is not defined; it may be either individual or organizational - >>> inames.to_python("http://example.org") - Traceback (most recent call last): - ... - Invalid: The type of i-name is not defined; it may be either individual or organizational - >>> inames.to_python("=!2C43.1A9F.B6F6.E8E6") - Traceback (most recent call last): - ... - Invalid: "!2C43.1A9F.B6F6.E8E6" is an invalid i-name - >>> iname_with_schema = XRI(True, xri_type="i-name") - >>> iname_with_schema.to_python("=Richard.Stallman") - 'xri://=Richard.Stallman' - >>> inames.to_python("=John Smith") - Traceback (most recent call last): - ... - Invalid: "John Smith" is an invalid i-name - >>> inumbers = XRI(xri_type="i-number") - >>> inumbers.to_python("!!1000!de21.4536.2cb2.8074") - '!!1000!de21.4536.2cb2.8074' - >>> inumbers.to_python("@!1000.9554.fabd.129c!2847.df3c") - '@!1000.9554.fabd.129c!2847.df3c' - - """ - - iname_valid_pattern = re.compile(r""" - ^ - [\w]+ # A global alphanumeric i-name - (\.[\w]+)* # An i-name with dots - (\*[\w]+(\.[\w]+)*)* # A community i-name - $ - """, re.VERBOSE | re.UNICODE) - - iname_invalid_start = re.compile(r"^[\d\.-]", re.UNICODE) - """@cvar: These characters must not be at the beggining of the i-name""" - - inumber_pattern = re.compile(r""" - ^ - ( - [=@]! # It's a personal or organization i-number - | - !! # It's a network i-number - ) - [\dA-F]{1,4}(\.[\dA-F]{1,4}){0,3} # A global i-number - (![\dA-F]{1,4}(\.[\dA-F]{1,4}){0,3})* # Zero or more sub i-numbers - $ - """, re.VERBOSE | re.IGNORECASE) - - messages = dict( - noType=_('The type of i-name is not defined;' - ' it may be either individual or organizational'), - repeatedChar=_('Dots and dashes may not be repeated consecutively'), - badIname=_('"%(iname)s" is an invalid i-name'), - badInameStart=_('i-names may not start with numbers' - ' nor punctuation marks'), - badInumber=_('"%(inumber)s" is an invalid i-number'), - badType=_('The XRI must be a string (not a %(type)s: %(value)r)'), - badXri=_('"%(xri_type)s" is not a valid type of XRI')) - - def __init__(self, add_xri=False, xri_type="i-name", **kwargs): - """Create an XRI validator. - - @param add_xri: Should the schema be added if not present? - Officially it's optional. - @type add_xri: C{bool} - @param xri_type: What type of XRI should be validated? - Possible values: C{i-name} or C{i-number}. - @type xri_type: C{str} - - """ - self.add_xri = add_xri - assert xri_type in ('i-name', 'i-number'), ( - 'xri_type must be "i-name" or "i-number"') - self.xri_type = xri_type - super(XRI, self).__init__(**kwargs) - - def _convert_to_python(self, value, state): - """Prepend the 'xri://' schema if needed and remove trailing spaces""" - value = value.strip() - if self.add_xri and not value.startswith('xri://'): - value = 'xri://' + value - return value - - def _validate_python(self, value, state=None): - """Validate an XRI - - @raise Invalid: If at least one of the following conditions in met: - - C{value} is not a string. - - The XRI is not a personal, organizational or network one. - - The relevant validator (i-name or i-number) considers the XRI - is not valid. - - """ - if not isinstance(value, str): - raise Invalid( - self.message('badType', state, - type=str(type(value)), value=value), value, state) - - # Let's remove the schema, if any - if value.startswith('xri://'): - value = value[6:] - - if not value[0] in ('@', '=') and not ( - self.xri_type == 'i-number' and value[0] == '!'): - raise Invalid(self.message('noType', state), value, state) - - if self.xri_type == 'i-name': - self._validate_iname(value, state) - else: - self._validate_inumber(value, state) - - def _validate_iname(self, iname, state): - """Validate an i-name""" - # The type is not required here: - iname = iname[1:] - if '..' in iname or '--' in iname: - raise Invalid(self.message('repeatedChar', state), iname, state) - if self.iname_invalid_start.match(iname): - raise Invalid(self.message('badInameStart', state), iname, state) - if not self.iname_valid_pattern.match(iname) or '_' in iname: - raise Invalid( - self.message('badIname', state, iname=iname), iname, state) - - def _validate_inumber(self, inumber, state): - """Validate an i-number""" - if not self.__class__.inumber_pattern.match(inumber): - raise Invalid( - self.message('badInumber', state, - inumber=inumber, value=inumber), inumber, state) - - -class OpenId(FancyValidator): - r""" - OpenId validator. - - :: - >>> v = OpenId(add_schema=True) - >>> v.to_python(' example.net ') - 'http://example.net' - >>> v.to_python('@TurboGears') - 'xri://@TurboGears' - >>> w = OpenId(add_schema=False) - >>> w.to_python(' example.net ') - Traceback (most recent call last): - ... - Invalid: "example.net" is not a valid OpenId (it is neither an URL nor an XRI) - >>> w.to_python('!!1000') - '!!1000' - >>> w.to_python('look@me.com') - Traceback (most recent call last): - ... - Invalid: "look@me.com" is not a valid OpenId (it is neither an URL nor an XRI) - - """ - - messages = dict( - badId=_('"%(id)s" is not a valid OpenId' - ' (it is neither an URL nor an XRI)')) - - def __init__(self, add_schema=False, **kwargs): - """Create an OpenId validator. - - @param add_schema: Should the schema be added if not present? - @type add_schema: C{bool} - - """ - self.url_validator = URL(add_http=add_schema) - self.iname_validator = XRI(add_schema, xri_type="i-name") - self.inumber_validator = XRI(add_schema, xri_type="i-number") - - def _convert_to_python(self, value, state): - value = value.strip() - try: - return self.url_validator.to_python(value, state) - except Invalid: - try: - return self.iname_validator.to_python(value, state) - except Invalid: - try: - return self.inumber_validator.to_python(value, state) - except Invalid: - pass - # It's not an OpenId! - raise Invalid(self.message('badId', state, id=value), value, state) - - def _validate_python(self, value, state): - self._convert_to_python(value, state) - - -def StateProvince(*kw, **kwargs): - deprecation_warning("please use formencode.national.USStateProvince") - from formencode.national import USStateProvince - return USStateProvince(*kw, **kwargs) - - -def PhoneNumber(*kw, **kwargs): - deprecation_warning("please use formencode.national.USPhoneNumber") - from formencode.national import USPhoneNumber - return USPhoneNumber(*kw, **kwargs) - - -def IPhoneNumberValidator(*kw, **kwargs): - deprecation_warning( - "please use formencode.national.InternationalPhoneNumber") - from formencode.national import InternationalPhoneNumber - return InternationalPhoneNumber(*kw, **kwargs) - - -class FieldStorageUploadConverter(FancyValidator): - """ - Handles cgi.FieldStorage instances that are file uploads. - - This doesn't do any conversion, but it can detect empty upload - fields (which appear like normal fields, but have no filename when - no upload was given). - """ - def _convert_to_python(self, value, state=None): - if isinstance(value, cgi.FieldStorage): - if getattr(value, 'filename', None): - return value - raise Invalid('invalid', value, state) - else: - return value - - def is_empty(self, value): - if isinstance(value, cgi.FieldStorage): - return not bool(getattr(value, 'filename', None)) - return FancyValidator.is_empty(self, value) - - -class FileUploadKeeper(FancyValidator): - """ - Takes two inputs (a dictionary with keys ``static`` and - ``upload``) and converts them into one value on the Python side (a - dictionary with ``filename`` and ``content`` keys). The upload - takes priority over the static value. The filename may be None if - it can't be discovered. - - Handles uploads of both text and ``cgi.FieldStorage`` upload - values. - - This is basically for use when you have an upload field, and you - want to keep the upload around even if the rest of the form - submission fails. When converting *back* to the form submission, - there may be extra values ``'original_filename'`` and - ``'original_content'``, which may want to use in your form to show - the user you still have their content around. - - To use this, make sure you are using variabledecode, then use - something like:: - - - - - Then in your scheme:: - - class MyScheme(Scheme): - myfield = FileUploadKeeper() - - Note that big file uploads mean big hidden fields, and lots of - bytes passed back and forth in the case of an error. - """ - - upload_key = 'upload' - static_key = 'static' - - def _convert_to_python(self, value, state): - upload = value.get(self.upload_key) - static = value.get(self.static_key, '').strip() - filename = content = None - if isinstance(upload, cgi.FieldStorage): - filename = upload.filename - content = upload.value - elif isinstance(upload, str) and upload: - filename = None - # @@: Should this encode upload if it is unicode? - content = upload - if not content and static: - filename, content = static.split(None, 1) - filename = '' if filename == '-' else filename.decode('base64') - content = content.decode('base64') - return {'filename': filename, 'content': content} - - def _convert_from_python(self, value, state): - filename = value.get('filename', '') - content = value.get('content', '') - if filename or content: - result = self.pack_content(filename, content) - return {self.upload_key: '', - self.static_key: result, - 'original_filename': filename, - 'original_content': content} - else: - return {self.upload_key: '', - self.static_key: ''} - - def pack_content(self, filename, content): - enc_filename = self.base64encode(filename) or '-' - enc_content = (content or '').encode('base64') - result = '%s %s' % (enc_filename, enc_content) - return result - - -class DateConverter(FancyValidator): - """ - Validates and converts a string date, like mm/yy, dd/mm/yy, - dd-mm-yy, etc. Using ``month_style`` you can support - the three general styles ``mdy`` = ``us`` = ``mm/dd/yyyy``, - ``dmy`` = ``euro`` = ``dd/mm/yyyy`` and - ``ymd`` = ``iso`` = ``yyyy/mm/dd``. - - Accepts English month names, also abbreviated. Returns value as a - datetime object (you can get mx.DateTime objects if you use - ``datetime_module='mxDateTime'``). Two year dates are assumed to - be within 1950-2020, with dates from 21-49 being ambiguous and - signaling an error. - - Use accept_day=False if you just want a month/year (like for a - credit card expiration date). - - :: - - >>> d = DateConverter() - >>> d.to_python('12/3/09') - datetime.date(2009, 12, 3) - >>> d.to_python('12/3/2009') - datetime.date(2009, 12, 3) - >>> d.to_python('2/30/04') - Traceback (most recent call last): - ... - Invalid: That month only has 29 days - >>> d.to_python('13/2/05') - Traceback (most recent call last): - ... - Invalid: Please enter a month from 1 to 12 - >>> d.to_python('1/1/200') - Traceback (most recent call last): - ... - Invalid: Please enter a four-digit year after 1899 - - If you change ``month_style`` you can get European-style dates:: - - >>> d = DateConverter(month_style='dd/mm/yyyy') - >>> date = d.to_python('12/3/09') - >>> date - datetime.date(2009, 3, 12) - >>> d.from_python(date) - '12/03/2009' - """ - - # set to False if you want only month and year - accept_day = True - # allowed month styles: 'mdy' = 'us', 'dmy' = 'euro', 'ymd' = 'iso' - # also allowed: 'mm/dd/yyyy', 'dd/mm/yyyy', 'yyyy/mm/dd' - month_style = 'mdy' - # preferred separator for reverse conversion: '/', '.' or '-' - separator = '/' - - # Use 'datetime' to force the Python datetime module, or - # 'mxDateTime' to force the mxDateTime module (None means use - # datetime, or if not present mxDateTime) - datetime_module = None - - _month_names = { - 'jan': 1, 'january': 1, - 'feb': 2, 'febuary': 2, - 'mar': 3, 'march': 3, - 'apr': 4, 'april': 4, - 'may': 5, - 'jun': 6, 'june': 6, - 'jul': 7, 'july': 7, - 'aug': 8, 'august': 8, - 'sep': 9, 'sept': 9, 'september': 9, - 'oct': 10, 'october': 10, - 'nov': 11, 'november': 11, - 'dec': 12, 'december': 12, - } - - _date_re = dict( - dmy=re.compile( - r'^\s*(\d\d?)[\-\./\\](\d\d?|%s)[\-\./\\](\d\d\d?\d?)\s*$' - % '|'.join(_month_names), re.I), - mdy=re.compile( - r'^\s*(\d\d?|%s)[\-\./\\](\d\d?)[\-\./\\](\d\d\d?\d?)\s*$' - % '|'.join(_month_names), re.I), - ymd=re.compile( - r'^\s*(\d\d\d?\d?)[\-\./\\](\d\d?|%s)[\-\./\\](\d\d?)\s*$' - % '|'.join(_month_names), re.I), - my=re.compile( - r'^\s*(\d\d?|%s)[\-\./\\](\d\d\d?\d?)\s*$' - % '|'.join(_month_names), re.I), - ym=re.compile( - r'^\s*(\d\d\d?\d?)[\-\./\\](\d\d?|%s)\s*$' - % '|'.join(_month_names), re.I)) - - _formats = dict(d='%d', m='%m', y='%Y') - - _human_formats = dict(d=_('DD'), m=_('MM'), y=_('YYYY')) - - # Feb. should be leap-year aware (but mxDateTime does catch that) - _monthDays = { - 1: 31, 2: 29, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 31, - 9: 30, 10: 31, 11: 30, 12: 31} - - messages = dict( - badFormat=_('Please enter the date in the form %(format)s'), - monthRange=_('Please enter a month from 1 to 12'), - invalidDay=_('Please enter a valid day'), - dayRange=_('That month only has %(days)i days'), - invalidDate=_('That is not a valid day (%(exception)s)'), - unknownMonthName=_('Unknown month name: %(month)s'), - invalidYear=_('Please enter a number for the year'), - fourDigitYear=_('Please enter a four-digit year after 1899'), - wrongFormat=_('Please enter the date in the form %(format)s')) - - def __init__(self, *args, **kw): - super(DateConverter, self).__init__(*args, **kw) - month_style = (self.month_style or DateConverter.month_style).lower() - accept_day = bool(self.accept_day) - self.accept_day = self.accept_day - if month_style in ('mdy', - 'md', 'mm/dd/yyyy', 'mm/dd', 'us', 'american'): - month_style = 'mdy' - elif month_style in ('dmy', - 'dm', 'dd/mm/yyyy', 'dd/mm', 'euro', 'european'): - month_style = 'dmy' - elif month_style in ('ymd', - 'ym', 'yyyy/mm/dd', 'yyyy/mm', 'iso', 'china', 'chinese'): - month_style = 'ymd' - else: - raise TypeError('Bad month_style: %r' % month_style) - self.month_style = month_style - separator = self.separator - if not separator or separator == 'auto': - separator = dict(mdy='/', dmy='.', ymd='-')[month_style] - elif separator not in ('-', '.', '/', '\\'): - raise TypeError('Bad separator: %r' % separator) - self.separator = separator - self.format = separator.join(self._formats[part] - for part in month_style if part != 'd' or accept_day) - self.human_format = separator.join(self._human_formats[part] - for part in month_style if part != 'd' or accept_day) - - def _convert_to_python(self, value, state): - self.assert_string(value, state) - month_style = self.month_style - if not self.accept_day: - month_style = 'ym' if month_style == 'ymd' else 'my' - match = self._date_re[month_style].search(value) - if not match: - raise Invalid( - self.message('badFormat', state, - format=self.human_format), value, state) - groups = match.groups() - if self.accept_day: - if month_style == 'mdy': - month, day, year = groups - elif month_style == 'dmy': - day, month, year = groups - else: - year, month, day = groups - day = int(day) - if not 1 <= day <= 31: - raise Invalid(self.message('invalidDay', state), value, state) - else: - day = 1 - if month_style == 'my': - month, year = groups - else: - year, month = groups - month = self.make_month(month, state) - if not 1 <= month <= 12: - raise Invalid(self.message('monthRange', state), value, state) - if self._monthDays[month] < day: - raise Invalid( - self.message('dayRange', state, - days=self._monthDays[month]), value, state) - year = self.make_year(year, state) - dt_mod = import_datetime(self.datetime_module) - try: - return datetime_makedate(dt_mod, year, month, day) - except ValueError as v: - raise Invalid( - self.message('invalidDate', state, - exception=str(v)), value, state) - - def make_month(self, value, state): - try: - return int(value) - except ValueError: - try: - return self._month_names[value.lower().strip()] - except KeyError: - raise Invalid( - self.message('unknownMonthName', state, - month=value), value, state) - - def make_year(self, year, state): - try: - year = int(year) - except ValueError: - raise Invalid(self.message('invalidYear', state), year, state) - if year <= 20: - year += 2000 - elif 50 <= year < 100: - year += 1900 - if 20 < year < 50 or 99 < year < 1900: - raise Invalid(self.message('fourDigitYear', state), year, state) - return year - - def _convert_from_python(self, value, state): - if self.if_empty is not NoDefault and not value: - return '' - return value.strftime(self.format) - - -class TimeConverter(FancyValidator): - """ - Converts times in the format HH:MM:SSampm to (h, m, s). - Seconds are optional. - - For ampm, set use_ampm = True. For seconds, use_seconds = True. - Use 'optional' for either of these to make them optional. - - Examples:: - - >>> tim = TimeConverter() - >>> tim.to_python('8:30') - (8, 30) - >>> tim.to_python('20:30') - (20, 30) - >>> tim.to_python('30:00') - Traceback (most recent call last): - ... - Invalid: You must enter an hour in the range 0-23 - >>> tim.to_python('13:00pm') - Traceback (most recent call last): - ... - Invalid: You must enter an hour in the range 1-12 - >>> tim.to_python('12:-1') - Traceback (most recent call last): - ... - Invalid: You must enter a minute in the range 0-59 - >>> tim.to_python('12:02pm') - (12, 2) - >>> tim.to_python('12:02am') - (0, 2) - >>> tim.to_python('1:00PM') - (13, 0) - >>> tim.from_python((13, 0)) - '13:00:00' - >>> tim2 = tim(use_ampm=True, use_seconds=False) - >>> tim2.from_python((13, 0)) - '1:00pm' - >>> tim2.from_python((0, 0)) - '12:00am' - >>> tim2.from_python((12, 0)) - '12:00pm' - - Examples with ``datetime.time``:: - - >>> v = TimeConverter(use_datetime=True) - >>> a = v.to_python('18:00') - >>> a - datetime.time(18, 0) - >>> b = v.to_python('30:00') - Traceback (most recent call last): - ... - Invalid: You must enter an hour in the range 0-23 - >>> v2 = TimeConverter(prefer_ampm=True, use_datetime=True) - >>> v2.from_python(a) - '6:00:00pm' - >>> v3 = TimeConverter(prefer_ampm=True, - ... use_seconds=False, use_datetime=True) - >>> a = v3.to_python('18:00') - >>> a - datetime.time(18, 0) - >>> v3.from_python(a) - '6:00pm' - >>> a = v3.to_python('18:00:00') - Traceback (most recent call last): - ... - Invalid: You may not enter seconds - """ - - use_ampm = 'optional' - prefer_ampm = False - use_seconds = 'optional' - use_datetime = False - # This can be set to make it prefer mxDateTime: - datetime_module = None - - messages = dict( - noAMPM=_('You must indicate AM or PM'), - tooManyColon=_('There are too many :\'s'), - noSeconds=_('You may not enter seconds'), - secondsRequired=_('You must enter seconds'), - minutesRequired=_('You must enter minutes (after a :)'), - badNumber=_('The %(part)s value you gave is not a number: %(number)r'), - badHour=_('You must enter an hour in the range %(range)s'), - badMinute=_('You must enter a minute in the range 0-59'), - badSecond=_('You must enter a second in the range 0-59')) - - def _convert_to_python(self, value, state): - result = self._to_python_tuple(value, state) - if self.use_datetime: - dt_mod = import_datetime(self.datetime_module) - time_class = datetime_time(dt_mod) - return time_class(*result) - else: - return result - - def _to_python_tuple(self, value, state): - time = value.strip() - explicit_ampm = False - if self.use_ampm: - last_two = time[-2:].lower() - if last_two not in ('am', 'pm'): - if self.use_ampm != 'optional': - raise Invalid(self.message('noAMPM', state), value, state) - offset = 0 - else: - explicit_ampm = True - offset = 12 if last_two == 'pm' else 0 - time = time[:-2] - else: - offset = 0 - parts = time.split(':', 3) - if len(parts) > 3: - raise Invalid(self.message('tooManyColon', state), value, state) - if len(parts) == 3 and not self.use_seconds: - raise Invalid(self.message('noSeconds', state), value, state) - if (len(parts) == 2 - and self.use_seconds and self.use_seconds != 'optional'): - raise Invalid(self.message('secondsRequired', state), value, state) - if len(parts) == 1: - raise Invalid(self.message('minutesRequired', state), value, state) - try: - hour = int(parts[0]) - except ValueError: - raise Invalid( - self.message('badNumber', state, - number=parts[0], part='hour'), value, state) - if explicit_ampm: - if not 1 <= hour <= 12: - raise Invalid( - self.message('badHour', state, - number=hour, range='1-12'), value, state) - if hour == 12 and offset == 12: - # 12pm == 12 - pass - elif hour == 12 and offset == 0: - # 12am == 0 - hour = 0 - else: - hour += offset - else: - if not 0 <= hour < 24: - raise Invalid( - self.message('badHour', state, - number=hour, range='0-23'), value, state) - try: - minute = int(parts[1]) - except ValueError: - raise Invalid( - self.message('badNumber', state, - number=parts[1], part='minute'), value, state) - if not 0 <= minute < 60: - raise Invalid( - self.message('badMinute', state, number=minute), - value, state) - if len(parts) == 3: - try: - second = int(parts[2]) - except ValueError: - raise Invalid( - self.message('badNumber', state, - number=parts[2], part='second'), value, state) - if not 0 <= second < 60: - raise Invalid( - self.message('badSecond', state, number=second), - value, state) - else: - second = None - if second is None: - return (hour, minute) - else: - return (hour, minute, second) - - def _convert_from_python(self, value, state): - if isinstance(value, str): - return value - if hasattr(value, 'hour'): - hour, minute = value.hour, value.minute - second = value.second - elif len(value) == 3: - hour, minute, second = value - elif len(value) == 2: - hour, minute = value - second = 0 - ampm = '' - if (self.use_ampm == 'optional' and self.prefer_ampm) or ( - self.use_ampm and self.use_ampm != 'optional'): - ampm = 'am' - if hour > 12: - hour -= 12 - ampm = 'pm' - elif hour == 12: - ampm = 'pm' - elif hour == 0: - hour = 12 - if self.use_seconds: - return '%i:%02i:%02i%s' % (hour, minute, second, ampm) - else: - return '%i:%02i%s' % (hour, minute, ampm) - - -def PostalCode(*kw, **kwargs): - deprecation_warning("please use formencode.national.USPostalCode") - from formencode.national import USPostalCode - return USPostalCode(*kw, **kwargs) - - -class StripField(FancyValidator): - """ - Take a field from a dictionary, removing the key from the dictionary. - - ``name`` is the key. The field value and a new copy of the dictionary - with that field removed are returned. - - >>> StripField('test').to_python({'a': 1, 'test': 2}) - (2, {'a': 1}) - >>> StripField('test').to_python({}) - Traceback (most recent call last): - ... - Invalid: The name 'test' is missing - - """ - - __unpackargs__ = ('name',) - - messages = dict( - missing=_('The name %(name)s is missing')) - - def _convert_to_python(self, valueDict, state): - v = valueDict.copy() - try: - field = v.pop(self.name) - except KeyError: - raise Invalid( - self.message('missing', state, name=repr(self.name)), - valueDict, state) - return field, v - - def is_empty(self, value): - # empty dictionaries don't really apply here - return False - - -class StringBool(FancyValidator): # originally from TurboGears 1 - """ - Converts a string to a boolean. - - Values like 'true' and 'false' are considered True and False, - respectively; anything in ``true_values`` is true, anything in - ``false_values`` is false, case-insensitive). The first item of - those lists is considered the preferred form. - - :: - - >>> s = StringBool() - >>> s.to_python('yes'), s.to_python('no') - (True, False) - >>> s.to_python(1), s.to_python('N') - (True, False) - >>> s.to_python('ye') - Traceback (most recent call last): - ... - Invalid: Value should be 'true' or 'false' - """ - - true_values = ['true', 't', 'yes', 'y', 'on', '1'] - false_values = ['false', 'f', 'no', 'n', 'off', '0'] - - messages = dict( - string=_('Value should be %(true)r or %(false)r')) - - def _convert_to_python(self, value, state): - if isinstance(value, str): - value = value.strip().lower() - if value in self.true_values: - return True - if not value or value in self.false_values: - return False - raise Invalid( - self.message('string', state, - true=self.true_values[0], false=self.false_values[0]), - value, state) - return bool(value) - - def _convert_from_python(self, value, state): - return (self.true_values if value else self.false_values)[0] - -# Should deprecate: -StringBoolean = StringBool - - -class SignedString(FancyValidator): - """ - Encodes a string into a signed string, and base64 encodes both the - signature string and a random nonce. - - It is up to you to provide a secret, and to keep the secret handy - and consistent. - """ - - messages = dict( - malformed=_('Value does not contain a signature'), - badsig=_('Signature is not correct')) - - secret = None - nonce_length = 4 - - def _convert_to_python(self, value, state): - global sha1 - if not sha1: - from hashlib import sha1 - assert self.secret is not None, "You must give a secret" - parts = value.split(None, 1) - if not parts or len(parts) == 1: - raise Invalid(self.message('malformed', state), value, state) - sig, rest = parts - sig = sig.decode('base64') - rest = rest.decode('base64') - nonce = rest[:self.nonce_length] - rest = rest[self.nonce_length:] - expected = sha1(str(self.secret) + nonce + rest).digest() - if expected != sig: - raise Invalid(self.message('badsig', state), value, state) - return rest - - def _convert_from_python(self, value, state): - global sha1 - if not sha1: - from hashlib import sha1 - nonce = self.make_nonce() - value = str(value) - digest = sha1(self.secret + nonce + value).digest() - return self.encode(digest) + ' ' + self.encode(nonce + value) - - def encode(self, value): - return value.encode('base64').strip().replace('\n', '') - - def make_nonce(self): - global random - if not random: - import random - return ''.join(chr(random.randrange(256)) - for _i in range(self.nonce_length)) - - -class IPAddress(FancyValidator): - """ - Formencode validator to check whether a string is a correct IP address. - - Examples:: - - >>> ip = IPAddress() - >>> ip.to_python('127.0.0.1') - '127.0.0.1' - >>> ip.to_python('299.0.0.1') - Traceback (most recent call last): - ... - Invalid: The octets must be within the range of 0-255 (not '299') - >>> ip.to_python('192.168.0.1/1') - Traceback (most recent call last): - ... - Invalid: Please enter a valid IP address (a.b.c.d) - >>> ip.to_python('asdf') - Traceback (most recent call last): - ... - Invalid: Please enter a valid IP address (a.b.c.d) - """ - - messages = dict( - badFormat=_('Please enter a valid IP address (a.b.c.d)'), - leadingZeros=_('The octets must not have leading zeros'), - illegalOctets=_('The octets must be within the range of 0-255' - ' (not %(octet)r)')) - - leading_zeros = False - - def _validate_python(self, value, state=None): - try: - if not value: - raise ValueError - octets = value.split('.', 5) - # Only 4 octets? - if len(octets) != 4: - raise ValueError - # Correct octets? - for octet in octets: - if octet.startswith('0') and octet != '0': - if not self.leading_zeros: - raise Invalid( - self.message('leadingZeros', state), value, state) - # strip zeros so this won't be an octal number - octet = octet.lstrip('0') - if not 0 <= int(octet) < 256: - raise Invalid( - self.message('illegalOctets', state, octet=octet), - value, state) - # Splitting faild: wrong syntax - except ValueError: - raise Invalid(self.message('badFormat', state), value, state) - - -class CIDR(IPAddress): - """ - Formencode validator to check whether a string is in correct CIDR - notation (IP address, or IP address plus /mask). - - Examples:: - - >>> cidr = CIDR() - >>> cidr.to_python('127.0.0.1') - '127.0.0.1' - >>> cidr.to_python('299.0.0.1') - Traceback (most recent call last): - ... - Invalid: The octets must be within the range of 0-255 (not '299') - >>> cidr.to_python('192.168.0.1/1') - Traceback (most recent call last): - ... - Invalid: The network size (bits) must be within the range of 8-32 (not '1') - >>> cidr.to_python('asdf') - Traceback (most recent call last): - ... - Invalid: Please enter a valid IP address (a.b.c.d) or IP network (a.b.c.d/e) - """ - - messages = dict(IPAddress._messages, - badFormat=_('Please enter a valid IP address (a.b.c.d)' - ' or IP network (a.b.c.d/e)'), - illegalBits=_('The network size (bits) must be within the range' - ' of 8-32 (not %(bits)r)')) - - def _validate_python(self, value, state): - try: - # Split into octets and bits - if '/' in value: # a.b.c.d/e - addr, bits = value.split('/') - else: # a.b.c.d - addr, bits = value, 32 - # Use IPAddress validator to validate the IP part - IPAddress._validate_python(self, addr, state) - # Bits (netmask) correct? - if not 8 <= int(bits) <= 32: - raise Invalid( - self.message('illegalBits', state, bits=bits), - value, state) - # Splitting faild: wrong syntax - except ValueError: - raise Invalid(self.message('badFormat', state), value, state) - - -class MACAddress(FancyValidator): - """ - Formencode validator to check whether a string is a correct hardware - (MAC) address. - - Examples:: - - >>> mac = MACAddress() - >>> mac.to_python('aa:bb:cc:dd:ee:ff') - 'aabbccddeeff' - >>> mac.to_python('aa:bb:cc:dd:ee:ff:e') - Traceback (most recent call last): - ... - Invalid: A MAC address must contain 12 digits and A-F; the value you gave has 13 characters - >>> mac.to_python('aa:bb:cc:dd:ee:fx') - Traceback (most recent call last): - ... - Invalid: MAC addresses may only contain 0-9 and A-F (and optionally :), not 'x' - >>> MACAddress(add_colons=True).to_python('aabbccddeeff') - 'aa:bb:cc:dd:ee:ff' - """ - - strip = True - valid_characters = '0123456789abcdefABCDEF' - add_colons = False - - messages = dict( - badLength=_('A MAC address must contain 12 digits and A-F;' - ' the value you gave has %(length)s characters'), - badCharacter=_('MAC addresses may only contain 0-9 and A-F' - ' (and optionally :), not %(char)r')) - - def _convert_to_python(self, value, state): - address = value.replace(':', '').lower() # remove colons - if len(address) != 12: - raise Invalid( - self.message('badLength', state, - length=len(address)), address, state) - for char in address: - if char not in self.valid_characters: - raise Invalid( - self.message('badCharacter', state, - char=char), address, state) - if self.add_colons: - address = '%s:%s:%s:%s:%s:%s' % ( - address[0:2], address[2:4], address[4:6], - address[6:8], address[8:10], address[10:12]) - return address - - _convert_from_python = _convert_to_python - - -class FormValidator(FancyValidator): - """ - A FormValidator is something that can be chained with a Schema. - - Unlike normal chaining the FormValidator can validate forms that - aren't entirely valid. - - The important method is .validate(), of course. It gets passed a - dictionary of the (processed) values from the form. If you have - .validate_partial_form set to True, then it will get the incomplete - values as well -- check with the "in" operator if the form was able - to process any particular field. - - Anyway, .validate() should return a string or a dictionary. If a - string, it's an error message that applies to the whole form. If - not, then it should be a dictionary of fieldName: errorMessage. - The special key "form" is the error message for the form as a whole - (i.e., a string is equivalent to {"form": string}). - - Returns None on no errors. - """ - - validate_partial_form = False - - validate_partial_python = None - validate_partial_other = None - - def is_empty(self, value): - return False - - def field_is_empty(self, value): - return is_empty(value) - - -class RequireIfMissing(FormValidator): - """ - Require one field based on another field being present or missing. - - This validator is applied to a form, not an individual field (usually - using a Schema's ``pre_validators`` or ``chained_validators``) and is - available under both names ``RequireIfMissing`` and ``RequireIfPresent``. - - If you provide a ``missing`` value (a string key name) then - if that field is missing the field must be entered. - This gives you an either/or situation. - - If you provide a ``present`` value (another string key name) then - if that field is present, the required field must also be present. - - :: - - >>> from formencode import validators - >>> v = validators.RequireIfPresent('phone_type', present='phone') - >>> v.to_python(dict(phone_type='', phone='510 420 4577')) - Traceback (most recent call last): - ... - Invalid: You must give a value for phone_type - >>> v.to_python(dict(phone='')) - {'phone': ''} - - Note that if you have a validator on the optionally-required - field, you should probably use ``if_missing=None``. This way you - won't get an error from the Schema about a missing value. For example:: - - class PhoneInput(Schema): - phone = PhoneNumber() - phone_type = String(if_missing=None) - chained_validators = [RequireIfPresent('phone_type', present='phone')] - """ - - # Field that potentially is required: - required = None - # If this field is missing, then it is required: - missing = None - # If this field is present, then it is required: - present = None - - __unpackargs__ = ('required',) - - def _convert_to_python(self, value_dict, state): - is_empty = self.field_is_empty - if is_empty(value_dict.get(self.required)) and ( - (self.missing and is_empty(value_dict.get(self.missing))) or - (self.present and not is_empty(value_dict.get(self.present)))): - raise Invalid( - _('You must give a value for %s') % self.required, - value_dict, state, - error_dict={self.required: - Invalid(self.message('empty', state), - value_dict.get(self.required), state)}) - return value_dict - -RequireIfPresent = RequireIfMissing - -class RequireIfMatching(FormValidator): - """ - Require a list of fields based on the value of another field. - - This validator is applied to a form, not an individual field (usually - using a Schema's ``pre_validators`` or ``chained_validators``). - - You provide a field name, an expected value and a list of required fields - (a list of string key names). If the value of the field, if present, - matches the value of ``expected_value``, then the validator will raise an - ``Invalid`` exception for every field in ``required_fields`` that is - missing. - - :: - - >>> from formencode import validators - >>> v = validators.RequireIfMatching('phone_type', expected_value='mobile', required_fields=['mobile']) - >>> v.to_python(dict(phone_type='mobile')) - Traceback (most recent call last): - ... - formencode.api.Invalid: You must give a value for mobile - >>> v.to_python(dict(phone_type='someothervalue')) - {'phone_type': 'someothervalue'} - """ - - # Field that we will check for its value: - field = None - # Value that the field shall have - expected_value = None - # If this field is present, then these fields are required: - required_fields = [] - - __unpackargs__ = ('field', 'expected_value') - - def _convert_to_python(self, value_dict, state): - is_empty = self.field_is_empty - - if self.field in value_dict and value_dict.get(self.field) == self.expected_value: - for required_field in self.required_fields: - if required_field not in value_dict or is_empty(value_dict.get(required_field)): - raise Invalid( - _('You must give a value for %s') % required_field, - value_dict, state, - error_dict={required_field: - Invalid(self.message('empty', state), - value_dict.get(required_field), state)}) - return value_dict - -class FieldsMatch(FormValidator): - """ - Tests that the given fields match, i.e., are identical. Useful - for password+confirmation fields. Pass the list of field names in - as `field_names`. - - :: - - >>> f = FieldsMatch('pass', 'conf') - >>> sorted(f.to_python({'pass': 'xx', 'conf': 'xx'}).items()) - [('conf', 'xx'), ('pass', 'xx')] - >>> f.to_python({'pass': 'xx', 'conf': 'yy'}) - Traceback (most recent call last): - ... - Invalid: conf: Fields do not match - """ - - show_match = False - field_names = None - validate_partial_form = True - - __unpackargs__ = ('*', 'field_names') - - messages = dict( - invalid=_('Fields do not match (should be %(match)s)'), - invalidNoMatch=_('Fields do not match'), - notDict=_('Fields should be a dictionary')) - - def __init__(self, *args, **kw): - super(FieldsMatch, self).__init__(*args, **kw) - if len(self.field_names) < 2: - raise TypeError('FieldsMatch() requires at least two field names') - - def validate_partial(self, field_dict, state): - for name in self.field_names: - if name not in field_dict: - return - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - try: - ref = field_dict[self.field_names[0]] - except TypeError: - # Generally because field_dict isn't a dict - raise Invalid(self.message('notDict', state), field_dict, state) - except KeyError: - ref = '' - errors = {} - for name in self.field_names[1:]: - if field_dict.get(name, '') != ref: - if self.show_match: - errors[name] = self.message('invalid', state, - match=ref) - else: - errors[name] = self.message('invalidNoMatch', state) - if errors: - error_list = sorted(errors.items()) - error_message = '
\n'.join( - '%s: %s' % (name, value) for name, value in error_list) - raise Invalid(error_message, field_dict, state, error_dict=errors) - - -class CreditCardValidator(FormValidator): - """ - Checks that credit card numbers are valid (if not real). - - You pass in the name of the field that has the credit card - type and the field with the credit card number. The credit - card type should be one of "visa", "mastercard", "amex", - "dinersclub", "discover", "jcb". - - You must check the expiration date yourself (there is no - relation between CC number/types and expiration dates). - - :: - - >>> cc = CreditCardValidator() - >>> sorted(cc.to_python({'ccType': 'visa', 'ccNumber': '4111111111111111'}).items()) - [('ccNumber', '4111111111111111'), ('ccType', 'visa')] - >>> cc.to_python({'ccType': 'visa', 'ccNumber': '411111111111111'}) - Traceback (most recent call last): - ... - Invalid: ccNumber: You did not enter a valid number of digits - >>> cc.to_python({'ccType': 'visa', 'ccNumber': '411111111111112'}) - Traceback (most recent call last): - ... - Invalid: ccNumber: You did not enter a valid number of digits - >>> cc().to_python({}) - Traceback (most recent call last): - ... - Invalid: The field ccType is missing - """ - - validate_partial_form = True - - cc_type_field = 'ccType' - cc_number_field = 'ccNumber' - - __unpackargs__ = ('cc_type_field', 'cc_number_field') - - messages = dict( - notANumber=_('Please enter only the number, no other characters'), - badLength=_('You did not enter a valid number of digits'), - invalidNumber=_('That number is not valid'), - missing_key=_('The field %(key)s is missing')) - - def validate_partial(self, field_dict, state): - if not field_dict.get(self.cc_type_field, None) \ - or not field_dict.get(self.cc_number_field, None): - return None - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - errors = self._validateReturn(field_dict, state) - if errors: - error_list = sorted(errors.items()) - raise Invalid( - '
\n'.join('%s: %s' % (name, value) - for name, value in error_list), - field_dict, state, error_dict=errors) - - def _validateReturn(self, field_dict, state): - for field in self.cc_type_field, self.cc_number_field: - if field not in field_dict: - raise Invalid( - self.message('missing_key', state, key=field), - field_dict, state) - ccType = field_dict[self.cc_type_field].lower().strip() - number = field_dict[self.cc_number_field].strip() - number = number.replace(' ', '') - number = number.replace('-', '') - try: - int(number) - except ValueError: - return {self.cc_number_field: self.message('notANumber', state)} - assert ccType in self._cardInfo, ( - "I can't validate that type of credit card") - foundValid = False - validLength = False - for prefix, length in self._cardInfo[ccType]: - if len(number) == length: - validLength = True - if number.startswith(prefix): - foundValid = True - break - if not validLength: - return {self.cc_number_field: self.message('badLength', state)} - if not foundValid: - return {self.cc_number_field: self.message('invalidNumber', state)} - if not self._validateMod10(number): - return {self.cc_number_field: self.message('invalidNumber', state)} - return None - - def _validateMod10(self, s): - """Check string with the mod 10 algorithm (aka "Luhn formula").""" - checksum, factor = 0, 1 - for c in reversed(s): - for c in str(factor * int(c)): - checksum += int(c) - factor = 3 - factor - return checksum % 10 == 0 - - _cardInfo = { - "visa": [('4', 16), - ('4', 13)], - "mastercard": [('51', 16), - ('52', 16), - ('53', 16), - ('54', 16), - ('55', 16)], - "discover": [('6011', 16)], - "amex": [('34', 15), - ('37', 15)], - "dinersclub": [('300', 14), - ('301', 14), - ('302', 14), - ('303', 14), - ('304', 14), - ('305', 14), - ('36', 14), - ('38', 14)], - "jcb": [('3', 16), - ('2131', 15), - ('1800', 15)], - } - - -class CreditCardExpires(FormValidator): - """ - Checks that credit card expiration date is valid relative to - the current date. - - You pass in the name of the field that has the credit card - expiration month and the field with the credit card expiration - year. - - :: - - >>> ed = CreditCardExpires() - >>> sorted(ed.to_python({'ccExpiresMonth': '11', 'ccExpiresYear': '2250'}).items()) - [('ccExpiresMonth', '11'), ('ccExpiresYear', '2250')] - >>> ed.to_python({'ccExpiresMonth': '10', 'ccExpiresYear': '2005'}) - Traceback (most recent call last): - ... - Invalid: ccExpiresMonth: Invalid Expiration Date
- ccExpiresYear: Invalid Expiration Date - """ - - validate_partial_form = True - - cc_expires_month_field = 'ccExpiresMonth' - cc_expires_year_field = 'ccExpiresYear' - - __unpackargs__ = ('cc_expires_month_field', 'cc_expires_year_field') - - datetime_module = None - - messages = dict( - notANumber=_('Please enter numbers only for month and year'), - invalidNumber=_('Invalid Expiration Date')) - - def validate_partial(self, field_dict, state): - if not field_dict.get(self.cc_expires_month_field, None) \ - or not field_dict.get(self.cc_expires_year_field, None): - return None - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - errors = self._validateReturn(field_dict, state) - if errors: - error_list = sorted(errors.items()) - raise Invalid( - '
\n'.join('%s: %s' % (name, value) - for name, value in error_list), - field_dict, state, error_dict=errors) - - def _validateReturn(self, field_dict, state): - ccExpiresMonth = str(field_dict[self.cc_expires_month_field]).strip() - ccExpiresYear = str(field_dict[self.cc_expires_year_field]).strip() - - try: - ccExpiresMonth = int(ccExpiresMonth) - ccExpiresYear = int(ccExpiresYear) - dt_mod = import_datetime(self.datetime_module) - now = datetime_now(dt_mod) - today = datetime_makedate(dt_mod, now.year, now.month, now.day) - next_month = ccExpiresMonth % 12 + 1 - next_month_year = ccExpiresYear - if next_month == 1: - next_month_year += 1 - expires_date = datetime_makedate( - dt_mod, next_month_year, next_month, 1) - assert expires_date > today - except ValueError: - return {self.cc_expires_month_field: - self.message('notANumber', state), - self.cc_expires_year_field: - self.message('notANumber', state)} - except AssertionError: - return {self.cc_expires_month_field: - self.message('invalidNumber', state), - self.cc_expires_year_field: - self.message('invalidNumber', state)} - - -class CreditCardSecurityCode(FormValidator): - """ - Checks that credit card security code has the correct number - of digits for the given credit card type. - - You pass in the name of the field that has the credit card - type and the field with the credit card security code. - - :: - - >>> code = CreditCardSecurityCode() - >>> sorted(code.to_python({'ccType': 'visa', 'ccCode': '111'}).items()) - [('ccCode', '111'), ('ccType', 'visa')] - >>> code.to_python({'ccType': 'visa', 'ccCode': '1111'}) - Traceback (most recent call last): - ... - Invalid: ccCode: Invalid credit card security code length - """ - - validate_partial_form = True - - cc_type_field = 'ccType' - cc_code_field = 'ccCode' - - __unpackargs__ = ('cc_type_field', 'cc_code_field') - - messages = dict( - notANumber=_('Please enter numbers only for credit card security code'), - badLength=_('Invalid credit card security code length')) - - def validate_partial(self, field_dict, state): - if (not field_dict.get(self.cc_type_field, None) - or not field_dict.get(self.cc_code_field, None)): - return None - self._validate_python(field_dict, state) - - def _validate_python(self, field_dict, state): - errors = self._validateReturn(field_dict, state) - if errors: - error_list = sorted(errors.items()) - raise Invalid( - '
\n'.join('%s: %s' % (name, value) - for name, value in error_list), - field_dict, state, error_dict=errors) - - def _validateReturn(self, field_dict, state): - ccType = str(field_dict[self.cc_type_field]).strip() - ccCode = str(field_dict[self.cc_code_field]).strip() - try: - int(ccCode) - except ValueError: - return {self.cc_code_field: self.message('notANumber', state)} - length = self._cardInfo[ccType] - if len(ccCode) != length: - return {self.cc_code_field: self.message('badLength', state)} - - # key = credit card type, value = length of security code - _cardInfo = dict(visa=3, mastercard=3, discover=3, amex=4) - - -def validators(): - """Return the names of all validators in this module.""" - return [name for name, value in globals().items() - if isinstance(value, type) and issubclass(value, Validator)] - -__all__ = ['Invalid'] + validators() - diff --git a/tox.ini b/tox.ini index 5fd8c596..57e8b8b3 100644 --- a/tox.ini +++ b/tox.ini @@ -732,9 +732,7 @@ commands = {[mssql-pyodbc-w32]commands} [testenv:py37-mssql-pyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mssql-pyodbc-w32]commands} +commands = {[mssql-pyodbc-w32]commands} [testenv:py38-mssql-pyodbc-noauto-w32] platform = win32 @@ -773,9 +771,7 @@ commands = {[mysql-connector-w32]commands} [testenv:py37-mysql-connector-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mysql-connector-w32]commands} +commands = {[mysql-connector-w32]commands} [testenv:py38-mysql-connector-w32] platform = win32 @@ -814,9 +810,7 @@ commands = {[pymysql-w32]commands} [testenv:py37-mysql-pymysql-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pymysql-w32]commands} +commands = {[pymysql-w32]commands} [testenv:py38-mysql-pymysql-w32] platform = win32 @@ -856,9 +850,7 @@ commands = {[mariadb-w32]commands} [testenv:py37-mariadb-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mariadb-w32]commands} +commands = {[mariadb-w32]commands} [testenv:py38-mariadb-w32] platform = win32 @@ -898,9 +890,7 @@ commands = {[mysql-pyodbc-w32]commands} [testenv:py37-mysql-pyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mysql-pyodbc-w32]commands} +commands = {[mysql-pyodbc-w32]commands} [testenv:py38-mysql-pyodbc-noauto-w32] platform = win32 @@ -940,9 +930,7 @@ commands = {[mysql-pypyodbc-w32]commands} [testenv:py37-mysql-pypyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[mysql-pypyodbc-w32]commands} +commands = {[mysql-pypyodbc-w32]commands} [testenv:py38-mysql-pypyodbc-noauto-w32] platform = win32 @@ -981,9 +969,7 @@ commands = {[psycopg-w32]commands} [testenv:py37-postgres-psycopg-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[psycopg-w32]commands} +commands = {[psycopg-w32]commands} [testenv:py38-postgres-psycopg-w32] platform = win32 @@ -1022,9 +1008,7 @@ commands = {[pygresql-w32]commands} [testenv:py37-postgres-pygresql-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pygresql-w32]commands} +commands = {[pygresql-w32]commands} [testenv:py38-postgres-pygresql-w32] platform = win32 @@ -1062,9 +1046,7 @@ commands = {[pypostgresql-w32]commands} [testenv:py37-postgres-pypostgresql-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pypostgresql-w32]commands} +commands = {[pypostgresql-w32]commands} [testenv:py38-postgres-pypostgresql-w32] platform = win32 @@ -1103,9 +1085,7 @@ commands = {[pg8000-w32]commands} [testenv:py37-postgres-pg8000-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[pg8000-w32]commands} +commands = {[pg8000-w32]commands} [testenv:py38-postgres-pg8000-w32] platform = win32 @@ -1145,9 +1125,7 @@ commands = {[postgres-pyodbc-w32]commands} [testenv:py37-postgres-pyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[postgres-pyodbc-w32]commands} +commands = {[postgres-pyodbc-w32]commands} [testenv:py38-postgres-pyodbc-noauto-w32] platform = win32 @@ -1187,9 +1165,7 @@ commands = {[postgres-pypyodbc-w32]commands} [testenv:py37-postgres-pypyodbc-noauto-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[postgres-pypyodbc-w32]commands} +commands = {[postgres-pypyodbc-w32]commands} [testenv:py38-postgres-pypyodbc-noauto-w32] platform = win32 @@ -1226,9 +1202,7 @@ commands = {[sqlite-w32]commands} [testenv:py37-sqlite-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[sqlite-w32]commands} +commands = {[sqlite-w32]commands} [testenv:py38-sqlite-w32] platform = win32 @@ -1264,9 +1238,7 @@ commands = {[sqlite-memory-w32]commands} [testenv:py37-sqlite-memory-w32] platform = win32 -commands = - cmd /c "copy ..\\devscripts\\CI\\validators.py {envsitepackagesdir}\\formencode\\validators.py" - {[sqlite-memory-w32]commands} +commands = {[sqlite-memory-w32]commands} [testenv:py38-sqlite-memory-w32] platform = win32 From 73ffdca9970cde63e66636335e6161e73a48ad84 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 15 Dec 2020 16:56:18 +0300 Subject: [PATCH 072/295] Release 3.9.0 --- ANNOUNCE.rst | 48 ++++++++++++++++++++++++++------------- README.rst | 12 ++++++---- devscripts/build-all-docs | 2 +- docs/News.rst | 8 ++++--- sqlobject/__version__.py | 6 ++--- 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9beb8c90..36371d0e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,40 @@ Hello! -I'm pleased to announce version 3.8.1a1, the first alpha of the upcoming -release of branch 3.8 of SQLObject. +I'm pleased to announce version 3.9.0, the first release +of branch 3.9 of SQLObject. -I'm pleased to announce version 3.8.1a2, the second alpha of the upcoming -release of branch 3.8 of SQLObject. -I'm pleased to announce version 3.8.1b1, the first beta of the upcoming -release of branch 3.8 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.8.1rc1, the first release candidate -of the upcoming release of branch 3.8 of SQLObject. +Contributors for this release are: -I'm pleased to announce version 3.8.2, the first bugfix release of branch -3.8 of SQLObject. ++ Michael S. Root, Ameya Bapat - ``JSONCol``; ++ Jerry Nance - reported a bug with ``DateTime`` from ``Zope``. -What's new in SQLObject -======================= +Features +-------- + +* Add ``JSONCol``: a universal json column that converts simple Python objects + (None, bool, int, float, long, dict, list, str/unicode to/from JSON using + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. + +* Extend/fix support for ``DateTime`` from ``Zope``. + +* Drop support for very old version of ``mxDateTime`` + without ``mx.`` namespace. + +Drivers +------- + +* Support `mariadb `_. + +CI +-- -Contributors for this release are +* Run tests with Python 3.9 at Travis and AppVeyor. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -32,8 +47,9 @@ SQLObject is an object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. -SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite, -Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB). +It currently supports MySQL, PostgreSQL and SQLite; connections to other +backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are +lesser debugged). Python 2.7 or 3.4+ is required. @@ -51,7 +67,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.8.2a0.dev20201001/ +https://pypi.org/project/SQLObject/3.9.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index a0f632de..cd66ddfa 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,15 @@ -SQLObject 3.8.2a0 -================= +SQLObject 3.9.0 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python classes, and your rows in Python instances. -It currently supports MySQL through the `MySQLdb` package, PostgreSQL -through the `psycopg` package, SQLite, Firebird, MaxDB (SAP DB), MS SQL, -and Sybase. Python 2.7 or 3.4+ is required. +It currently supports MySQL, PostgreSQL and SQLite; connections to other +backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are +lesser debugged). + +Python 2.7 or 3.4+ is required. For more information please see the documentation in ``_, or online at http://sqlobject.org/ diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 4eab6205..1f21c9a8 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.8.1 && +build_docs 3.9.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 253ef84b..e1e59161 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.9.0 +=============== + +Released 2020 Dec 15. Features -------- @@ -24,7 +26,7 @@ Features Drivers ------- -* Support ``mariadb``. +* Support `mariadb `_. CI -- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 579bdd6a..f133a875 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.8.1' +version = '3.9.0' major = 3 -minor = 8 -micro = 1 +minor = 9 +micro = 0 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 78cf7a8465a224ee11dac455c6b8affe92fa016f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 15 Dec 2020 17:10:24 +0300 Subject: [PATCH 073/295] Prepare for the next release [skip ci] --- ANNOUNCE.rst | 49 +++++++++++++++++-------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 36371d0e..72872502 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,40 +1,25 @@ Hello! -I'm pleased to announce version 3.9.0, the first release -of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.1a1, the first alpha of the upcoming +release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.1a2, the second alpha of the upcoming +release of branch 3.9 of SQLObject. -What's new in SQLObject -======================= - -Contributors for this release are: - -+ Michael S. Root, Ameya Bapat - ``JSONCol``; - -+ Jerry Nance - reported a bug with ``DateTime`` from ``Zope``. +I'm pleased to announce version 3.9.1b1, the first beta of the upcoming +release of branch 3.9 of SQLObject. -Features --------- +I'm pleased to announce version 3.9.1rc1, the first release candidate +of the upcoming release of branch 3.9 of SQLObject. -* Add ``JSONCol``: a universal json column that converts simple Python objects - (None, bool, int, float, long, dict, list, str/unicode to/from JSON using - json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` - columns at backends, doesn't work with ``JSON`` columns. +I'm pleased to announce version 3.9.1, the first bugfix release of branch +3.9 of SQLObject. -* Extend/fix support for ``DateTime`` from ``Zope``. -* Drop support for very old version of ``mxDateTime`` - without ``mx.`` namespace. - -Drivers -------- - -* Support `mariadb `_. - -CI --- +What's new in SQLObject +======================= -* Run tests with Python 3.9 at Travis and AppVeyor. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -47,9 +32,9 @@ SQLObject is an object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. -It currently supports MySQL, PostgreSQL and SQLite; connections to other -backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are -lesser debugged). +SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite; +connections to other backends - Firebird, Sybase, MSSQL +and MaxDB (also known as SAPDB) - are lesser debugged). Python 2.7 or 3.4+ is required. @@ -67,7 +52,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.0 +https://pypi.org/project/SQLObject/3.9.1a0.dev20201215/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index cd66ddfa..2442b674 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.0 -=============== +SQLObject 3.9.1a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index e1e59161..5d5b0665 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.9.0 =============== From a2b0c6297dafc14a37503fb8c089e0cbc4d9e925 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Dec 2020 03:29:44 +0300 Subject: [PATCH 074/295] Build(setup.py): Change URLs for ``oursql`` in ``extras_require`` Provide separate URLs for Python 2.7 and 3.4+. [skip ci] --- docs/News.rst | 6 ++++++ setup.py | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 5d5b0665..df973871 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Build +----- + +* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. + Provide separate URLs for Python 2.7 and 3.4+. + SQLObject 3.9.0 =============== diff --git a/setup.py b/setup.py index 58cd1d0f..674aaec9 100755 --- a/setup.py +++ b/setup.py @@ -115,7 +115,10 @@ 'mysql:python_version=="2.7"': ['MySQL-python'], 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], - 'oursql': ['oursql'], + 'oursql:python_version=="2.7"': [ + 'oursql @ git+https://github.com/sqlobject/oursql.git@master'], + 'oursql:python_version>="3.4"': [ + 'oursql3 @ git+https://github.com/sqlobject/oursql.git@py3k'], 'pymysql': ['pymysql'], # ODBC 'odbc': ['pyodbc'], From 6f6f974c00bf095cb8120ca2df3ca6ef18d52a94 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Dec 2020 03:31:41 +0300 Subject: [PATCH 075/295] Build(setup.py): Add ``mariadb`` in ``extras_require`` [skip ci] --- docs/News.rst | 2 ++ docs/download.rst | 2 +- setup.py | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index df973871..59558ab6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,8 @@ Build * Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. Provide separate URLs for Python 2.7 and 3.4+. +* Add ``mariadb`` in ``extras_require`` in ``setup.py``. + SQLObject 3.9.0 =============== diff --git a/docs/download.rst b/docs/download.rst index 0126343b..69069dd9 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector oursql pymysql +mysql-connector oursql pymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index 674aaec9..11a6cbaa 100755 --- a/setup.py +++ b/setup.py @@ -120,6 +120,7 @@ 'oursql:python_version>="3.4"': [ 'oursql3 @ git+https://github.com/sqlobject/oursql.git@py3k'], 'pymysql': ['pymysql'], + 'mariadb': ['mariadb'], # ODBC 'odbc': ['pyodbc'], 'pyodbc': ['pyodbc'], From a784248acfa8d1ba01b69553100fe20c4f0859ba Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Jan 2021 01:03:40 +0300 Subject: [PATCH 076/295] CI(AppVeyor): Upgrade `tox` It seems we no longer need to limit version at AppVeyor. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 84c56d4d..68dd3ce2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -125,7 +125,7 @@ install: - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" - - "pip install --upgrade \"tox<3.1\" ppu" + - "pip install --upgrade tox ppu" - "pip --version" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name From da5e27ffd5bd80acdba7459c276f5cd80c0e6162 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Jan 2021 16:30:30 +0300 Subject: [PATCH 077/295] Test(tox): Fix `py-postgresql` package name --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 57e8b8b3..77d44c5e 100644 --- a/tox.ini +++ b/tox.ini @@ -28,7 +28,7 @@ deps = mariadb: mariadb postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt - pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=pypostgresql + pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 pyodbc: pyodbc pypyodbc: pypyodbc From d724e34b67a89e3dfddf2b2d7914673170312e71 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 20 Feb 2021 18:01:04 +0300 Subject: [PATCH 078/295] CI(.travis.yml): Use `- |` for multiline shell blocks --- .travis.yml | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9fddebe6..56623427 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,17 +87,20 @@ matrix: before_install: # Install version-specific dependencies - - if [[ $TESTS = py27-* ]]; then - sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2; + - | + if [[ $TESTS = py27-* ]]; then + sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2 fi - - if [[ $TESTS = py3*-* ]]; then - sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2; + - | + if [[ $TESTS = py3*-* ]]; then + sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2 fi # Install MariaDB mysql-compatible development files to compile mysql drivers - - if [[ $TESTS = py3[6789]-mysql ]]; then - sudo apt-get --quiet --yes install libmysqlclient-dev; + - | + if [[ $TESTS = py3[6789]-mysql ]]; then + sudo apt-get --quiet --yes install libmysqlclient-dev elif [[ $TESTS = py3[6789]-mariadb ]]; then - sudo apt-get --quiet --yes install libmariadb-dev-compat; + sudo apt-get --quiet --yes install libmariadb-dev-compat fi # Install and start the firebird database server. # We use firebird-super, so there's none of the inetd configuration @@ -107,14 +110,15 @@ before_install: # to create the test database. # Copied password initializtion from # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - - if [[ $TESTS = *firebird* ]]; then - sudo apt-get --quiet --yes install firebird2.5-super && - sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' && - sudo /etc/init.d/firebird2.5-super start && sleep 5 && - sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' && - sudo gsec -user sysdba -pass masterkey -add test -pw test && - sudo /bin/bash -c "echo \"CREATE DATABASE 'localhost:/tmp/test.fdb';\" > /var/lib/firebird/create_test_db" && - sudo chmod 644 /var/lib/firebird/create_test_db; + - | + if [[ $TESTS = *firebird* ]]; then + sudo apt-get --quiet --yes install firebird2.5-super + sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' + sudo /etc/init.d/firebird2.5-super start && sleep 5 + sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' + sudo gsec -user sysdba -pass masterkey -add test -pw test + sudo /bin/bash -c "echo \"CREATE DATABASE 'localhost:/tmp/test.fdb';\" > /var/lib/firebird/create_test_db" + sudo chmod 644 /var/lib/firebird/create_test_db fi install: travis_retry pip install --upgrade "pip<21" "setuptools<44" tox coveralls codecov ppu From 52740edf09bb92b5d57d1364411db4c6bdc8d4fc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 20 Feb 2021 18:47:48 +0300 Subject: [PATCH 079/295] Tests: Refactor `tox.ini` Requires `tox` >= 3.15. For tests with Python 3.4 run `tox` under Python 3.5. --- .travis.yml | 20 +- appveyor.yml | 2 +- devscripts/requirements/requirements_tox.txt | 2 +- tox.ini | 694 +------------------ 4 files changed, 52 insertions(+), 666 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56623427..638d6484 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,8 @@ matrix: include: - python: "2.7" env: TESTS=py27-mysql - - python: "3.4" - env: TESTS=py34-mysql + - python: "3.5" + env: TESTS=py34-mysql TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - python: "3.5" env: TESTS=py35-mysql - python: "3.6" @@ -46,8 +46,8 @@ matrix: dist: focal - python: "2.7" env: TESTS=py27-postgres - - python: "3.4" - env: TESTS=py34-postgres + - python: "3.5" + env: TESTS=py34-postgres TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - python: "3.5" env: TESTS=py35-postgres - python: "3.6" @@ -60,8 +60,8 @@ matrix: env: TESTS=py39-postgres - python: "2.7" env: TESTS=py27-sqlite - - python: "3.4" - env: TESTS=py34-sqlite + - python: "3.5" + env: TESTS=py34-sqlite TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - python: "3.5" env: TESTS=py35-sqlite - python: "3.6" @@ -95,6 +95,12 @@ before_install: if [[ $TESTS = py3*-* ]]; then sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2 fi + - | + if [[ $TESTS = py34-* ]]; then + # Manually install Python 3.4 to run tox under Python 3.5 and tests with Python 3.4 + curl -sSf --retry 5 -o python-3.4.tar.bz2 https://storage.googleapis.com/travis-ci-language-archives/python/binaries/ubuntu/16.04/x86_64/python-3.4.tar.bz2 + sudo tar xjf python-3.4.tar.bz2 --directory / + fi # Install MariaDB mysql-compatible development files to compile mysql drivers - | if [[ $TESTS = py3[6789]-mysql ]]; then @@ -121,7 +127,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db fi -install: travis_retry pip install --upgrade "pip<21" "setuptools<44" tox coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<21" "setuptools<44" "tox>=3.15" coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 68dd3ce2..38a7a1ec 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -125,7 +125,7 @@ install: - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" - - "pip install --upgrade tox ppu" + - "pip install --upgrade \"tox>=3.15\" ppu" - "pip --version" # List ODBC drivers - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name diff --git a/devscripts/requirements/requirements_tox.txt b/devscripts/requirements/requirements_tox.txt index 8c9b6ed3..8b5960b9 100644 --- a/devscripts/requirements/requirements_tox.txt +++ b/devscripts/requirements/requirements_tox.txt @@ -1 +1 @@ -tox >= 2.0, < 3.1 +tox >= 3.15 diff --git a/tox.ini b/tox.ini index 77d44c5e..8eddc056 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -minversion = 2.0 +minversion = 3.15 envlist = py27,py3{4,5,6,7,8,9}-sqlite{,-memory},py{27,39}-flake8 # Base test environment settings @@ -62,27 +62,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py34-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py35-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py36-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py37-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py38-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - -[testenv:py39-mysqldb] +[testenv:py3{4,5,6,7,8,9}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -98,22 +78,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py34-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py35-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py36-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py37-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py38-mysqlclient] -commands = {[mysqlclient]commands} - -[testenv:py39-mysqlclient] +[testenv:py3{4,5,6,7,8,9}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -129,22 +94,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py34-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py35-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py36-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py37-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py38-mysql-connector-noauto] -commands = {[mysql-connector]commands} - -[testenv:py39-mysql-connector-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-connector-noauto] commands = {[mysql-connector]commands} [oursql] @@ -160,22 +110,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py34-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py35-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py36-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py37-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py38-mysql-oursql3-noauto] -commands = {[oursql]commands} - -[testenv:py39-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -191,22 +126,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py34-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py35-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py36-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py37-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py38-mysql-pymysql] -commands = {[pymysql]commands} - -[testenv:py39-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -217,28 +137,11 @@ commands = pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 mysql -uroot -e 'drop database sqlobject_test;' -[testenv:py27-mariadb] +[testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py34-mariadb] -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py35-mariadb] -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py36-mariadb] -commands = {[mariadb]commands} - -[testenv:py37-mariadb] -commands = {[mariadb]commands} - -[testenv:py38-mariadb] -commands = {[mariadb]commands} - -[testenv:py39-mariadb] +[testenv:py3{6,7,8,9}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -255,22 +158,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py34-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py35-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py36-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py37-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py38-mysql-pyodbc-noauto] -commands = {[mysql-pyodbc]commands} - -[testenv:py39-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -286,22 +174,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py34-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py35-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py36-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py37-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py38-mysql-pypyodbc-noauto] -commands = {[mysql-pypyodbc]commands} - -[testenv:py39-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -318,22 +191,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py34-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py35-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py36-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py37-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py38-postgres-psycopg] -commands = {[psycopg]commands} - -[testenv:py39-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -349,22 +207,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py34-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py35-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py36-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py37-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py38-postgres-pygresql] -commands = {[pygresql]commands} - -[testenv:py39-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -379,22 +222,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py34-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py35-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py36-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py37-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py38-postgres-pypostgresql] -commands = {[pypostgresql]commands} - -[testenv:py39-postgres-pypostgresql] +[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql] commands = {[pypostgresql]commands} [pg8000] @@ -410,22 +238,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py34-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py35-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py36-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py37-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py38-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py39-postgres-pg8000] +[testenv:py3{4,5,6,7,8,9}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -442,22 +255,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py34-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py35-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py36-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py37-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py38-postgres-pyodbc-noauto] -commands = {[postgres-pyodbc]commands} - -[testenv:py39-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -473,22 +271,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py34-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py35-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py36-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py37-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py38-postgres-pypyodbc-noauto] -commands = {[postgres-pypyodbc]commands} - -[testenv:py39-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -505,22 +288,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py34-sqlite] -commands = {[sqlite]commands} - -[testenv:py35-sqlite] -commands = {[sqlite]commands} - -[testenv:py36-sqlite] -commands = {[sqlite]commands} - -[testenv:py37-sqlite] -commands = {[sqlite]commands} - -[testenv:py38-sqlite] -commands = {[sqlite]commands} - -[testenv:py39-sqlite] +[testenv:py3{4,5,6,7,8,9}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -533,22 +301,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py34-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py35-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py36-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py37-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py38-sqlite-memory] -commands = {[sqlite-memory]commands} - -[testenv:py39-sqlite-memory] +[testenv:py3{4,5,6,7,8,9}-sqlite-memory] commands = {[sqlite-memory]commands} [sqlite-supersqlite] @@ -563,22 +316,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-supersqlite]commands} -[testenv:py34-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py35-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py36-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py37-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py38-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - -[testenv:py39-sqlite-supersqlite] +[testenv:py3{4,5,6,7,8,9}-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} @@ -596,22 +334,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py34-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py35-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py36-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py37-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py38-firebird-fdb] -commands = {[fdb]commands} - -[testenv:py39-firebird-fdb] +[testenv:py3{4,5,6,7,8,9}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -627,50 +350,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py34-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py35-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py36-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py37-firebirdsql] +[testenv:py3{4,5,6,7,8,9}-firebirdsql] commands = {[firebirdsql]commands} -[testenv:py38-firebirdsql] -commands = {[firebirdsql]commands} - -[testenv:py39-firebirdsql] -commands = {[firebirdsql]commands} # Special test environments -[testenv:py27-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py34-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py35-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py36-flake8] +[testenv:py{27,34,35,36,37,38,39}-flake8] changedir = ./ deps = flake8 @@ -678,29 +363,6 @@ commands = {[testenv]commands} flake8 . -[testenv:py37-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py38-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . - -[testenv:py39-flake8] -changedir = ./ -deps = - flake8 -commands = - {[testenv]commands} - flake8 . # Windows testing [mssql-pyodbc-w32] @@ -718,27 +380,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py34-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py35-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py36-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py37-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py38-mssql-pyodbc-noauto-w32] -platform = win32 -commands = {[mssql-pyodbc-w32]commands} - -[testenv:py39-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -757,27 +399,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py34-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py35-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py36-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py37-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py38-mysql-connector-w32] -platform = win32 -commands = {[mysql-connector-w32]commands} - -[testenv:py39-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -796,27 +418,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py34-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py35-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py36-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py37-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py38-mysql-pymysql-w32] -platform = win32 -commands = {[pymysql-w32]commands} - -[testenv:py39-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -829,34 +431,12 @@ commands = pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' -[testenv:py27-mariadb-w32] -platform = win32 -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py34-mariadb-w32] -platform = win32 -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - -[testenv:py35-mariadb-w32] +[testenv:py{27,34,35}-mariadb-w32] platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py36-mariadb-w32] -platform = win32 -commands = {[mariadb-w32]commands} - -[testenv:py37-mariadb-w32] -platform = win32 -commands = {[mariadb-w32]commands} - -[testenv:py38-mariadb-w32] -platform = win32 -commands = {[mariadb-w32]commands} - -[testenv:py39-mariadb-w32] +[testenv:py3{6,7,8,9}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -876,27 +456,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py34-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py35-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py36-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py37-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py38-mysql-pyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pyodbc-w32]commands} - -[testenv:py39-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -916,27 +476,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py34-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py35-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py36-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py37-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py38-mysql-pypyodbc-noauto-w32] -platform = win32 -commands = {[mysql-pypyodbc-w32]commands} - -[testenv:py39-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -955,27 +495,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py34-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py35-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py36-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py37-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py38-postgres-psycopg-w32] -platform = win32 -commands = {[psycopg-w32]commands} - -[testenv:py39-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -994,27 +514,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py34-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py35-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py36-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py37-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py38-postgres-pygresql-w32] -platform = win32 -commands = {[pygresql-w32]commands} - -[testenv:py39-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -1032,27 +532,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py34-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py35-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py36-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py37-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py38-postgres-pypostgresql-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - -[testenv:py39-postgres-pypostgresql-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -1071,27 +551,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py34-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py35-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py36-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py37-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py38-postgres-pg8000-w32] -platform = win32 -commands = {[pg8000-w32]commands} - -[testenv:py39-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -1111,27 +571,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py34-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py35-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py36-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py37-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py38-postgres-pyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pyodbc-w32]commands} - -[testenv:py39-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -1151,27 +591,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py34-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py35-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py36-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py37-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py38-postgres-pypyodbc-noauto-w32] -platform = win32 -commands = {[postgres-pypyodbc-w32]commands} - -[testenv:py39-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -1188,27 +608,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py34-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py35-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py36-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py37-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py38-sqlite-w32] -platform = win32 -commands = {[sqlite-w32]commands} - -[testenv:py39-sqlite-w32] +[testenv:py3{4,5,6,7,8,9}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -1224,26 +624,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py34-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py35-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py36-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py37-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py38-sqlite-memory-w32] -platform = win32 -commands = {[sqlite-memory-w32]commands} - -[testenv:py39-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From 70355ffdaab154c93494c5ed2e32395a5bbd4737 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 21 Feb 2021 02:24:46 +0300 Subject: [PATCH 080/295] Tests(tox.ini): Limit `PyMySQL` version for Python 2.7 and 3.4 --- devscripts/requirements/requirements_pymysql.txt | 3 +++ tox.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 devscripts/requirements/requirements_pymysql.txt diff --git a/devscripts/requirements/requirements_pymysql.txt b/devscripts/requirements/requirements_pymysql.txt new file mode 100644 index 00000000..47ca8d09 --- /dev/null +++ b/devscripts/requirements/requirements_pymysql.txt @@ -0,0 +1,3 @@ +pymysql < 1.0; python_version == '2.7' +pymysql < 0.10.0; python_version == '3.4' +pymysql; python_version >= '3.5' diff --git a/tox.ini b/tox.ini index 8eddc056..95bfdbd7 100644 --- a/tox.ini +++ b/tox.ini @@ -24,7 +24,7 @@ deps = mysql-connector: mysql-connector <= 2.2.2 mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql - pymysql: pymysql + pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt From 9e9724b152a4bbc359708906cf327af2d7fe2e51 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 12:50:18 +0300 Subject: [PATCH 081/295] Docs(News): Update News [skip ci] --- docs/News.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index 59558ab6..43d381cb 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,16 @@ Build * Add ``mariadb`` in ``extras_require`` in ``setup.py``. +CI +-- + +* For tests with Python 3.4 run ``tox`` under Python 3.5. + +Tests +----- + +* Refactor ``tox.ini``. + SQLObject 3.9.0 =============== From 28974d303f13f085113018651ad7f074d510937c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 12:51:50 +0300 Subject: [PATCH 082/295] Build(devscripts): Rename `split.sh` -> `split_tag.sh` [skip ci] --- devscripts/branch | 2 +- devscripts/prerelease | 2 +- devscripts/prerelease-tag | 2 +- devscripts/release | 2 +- devscripts/{split.sh => split_tag.sh} | 0 devscripts/{test-split.sh => test-split_tag.sh} | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename devscripts/{split.sh => split_tag.sh} (100%) rename devscripts/{test-split.sh => test-split_tag.sh} (93%) diff --git a/devscripts/branch b/devscripts/branch index 908e5fb3..7c7ef731 100755 --- a/devscripts/branch +++ b/devscripts/branch @@ -8,7 +8,7 @@ fi branch="$1" treeish="$2" -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && branch="$1" if [ -z "$treeish" ]; then diff --git a/devscripts/prerelease b/devscripts/prerelease index edd7358e..dd788c6f 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -10,7 +10,7 @@ else branch="$2" fi -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && split_tag $tag $branch git checkout "$branch" && diff --git a/devscripts/prerelease-tag b/devscripts/prerelease-tag index b7f10175..46ac39e7 100755 --- a/devscripts/prerelease-tag +++ b/devscripts/prerelease-tag @@ -10,7 +10,7 @@ else branch="$2" fi -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && split_tag $tag $branch git checkout "$branch" && diff --git a/devscripts/release b/devscripts/release index 35154c95..33bb23ff 100755 --- a/devscripts/release +++ b/devscripts/release @@ -15,7 +15,7 @@ find build -name '*.py[co]' -delete && python setup.py bdist_wheel --universal && version=`python setup.py --version` -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && split_tag $version if [ "$state" = final ]; then diff --git a/devscripts/split.sh b/devscripts/split_tag.sh similarity index 100% rename from devscripts/split.sh rename to devscripts/split_tag.sh diff --git a/devscripts/test-split.sh b/devscripts/test-split_tag.sh similarity index 93% rename from devscripts/test-split.sh rename to devscripts/test-split_tag.sh index a5f17495..0dc48c30 100755 --- a/devscripts/test-split.sh +++ b/devscripts/test-split_tag.sh @@ -1,6 +1,6 @@ #! /bin/sh -. `dirname $0`/split.sh && +. `dirname $0`/split_tag.sh && test_eq() { if [ "$1" != "$2" ]; then From 00c4a089d8185576f4ebcf5eba94d96044f3b092 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 13:02:18 +0300 Subject: [PATCH 083/295] Build(devscripts): Split post-release tag and counter [skip ci] --- devscripts/split_tag.sh | 2 +- devscripts/test-split_tag.sh | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/devscripts/split_tag.sh b/devscripts/split_tag.sh index ce5c3c5e..d0024f04 100644 --- a/devscripts/split_tag.sh +++ b/devscripts/split_tag.sh @@ -1,6 +1,6 @@ split_tag() { branch=$2 - set -- `echo $1 | sed -e 's/\./ /g' -e 's/a/ alpha /' -e 's/b/ beta /' -e 's/rc/ rc /' -e 's/\([0-9]\)c/\1 rc /'` + set -- `echo $1 | sed -e 's/\./ /g' -e 's/a/ alpha /' -e 's/b/ beta /' -e 's/rc/ rc /' -e 's/\([0-9]\)c/\1 rc /' -e 's/post\([0-9]\+\)/ post \1/'` major=$1 minor=$2 micro=$3 diff --git a/devscripts/test-split_tag.sh b/devscripts/test-split_tag.sh index 0dc48c30..40b9d3d4 100755 --- a/devscripts/test-split_tag.sh +++ b/devscripts/test-split_tag.sh @@ -23,3 +23,11 @@ test_eq "$minor" 12 test_eq "$micro" 42 test_eq "$state" "release candidate" test_eq "$serial" 4 + +split_tag 21.12.42.post1 +test_eq "$branch" 21.12 +test_eq "$major" 21 +test_eq "$minor" 12 +test_eq "$micro" 42 +test_eq "$state" "post" +test_eq "$serial" 1 From 99861557ab30dd842c4b0d22f0c995d7f29d1778 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 22 Feb 2021 15:00:46 +0300 Subject: [PATCH 084/295] Build(devscripts/postrelease): Improve commit message [skip ci] --- devscripts/postrelease | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/postrelease b/devscripts/postrelease index 55dfe674..0a9c73a5 100755 --- a/devscripts/postrelease +++ b/devscripts/postrelease @@ -3,4 +3,4 @@ git checkout HEAD~ ANNOUNCE.rst setup.cfg && `git var GIT_EDITOR` ANNOUNCE.rst setup.cfg README.rst docs/News.rst && -exec git commit --message="Prepare for the next release" ANNOUNCE.rst setup.cfg README.rst docs/News.rst +exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst From 47307e617424d8a4bdcad350ca235a72396fd23f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Feb 2021 21:12:58 +0300 Subject: [PATCH 085/295] Feat(PostgreSQL): Adapt to the latest `pg8000` --- docs/News.rst | 5 +++++ sqlobject/postgres/pgconnection.py | 28 +++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 43d381cb..234fca55 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Drivers +------- + +* Adapt to the latest ``pg8000``. + Build ----- diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 85a50945..749ca575 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -10,13 +10,26 @@ class ErrorMessage(str): def __new__(cls, e, append_msg=''): - obj = str.__new__(cls, e.args[0] + append_msg) - if hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors - obj.code = getattr(e, 'pgcode', None) - obj.error = getattr(e, 'pgerror', None) + eargs0 = emessage = e.args[0] + if e.__module__.startswith('pg8000') \ + and isinstance(e.args, tuple) and len(e.args) > 1: + # pg8000 =~ 1.12 for Python 3.4 + ecode = e.args[2] + eerror = emessage = e.args[3] + elif e.__module__.startswith('pg8000') and isinstance(eargs0, dict): + # pg8000 =~ 1.13 for Python 2.7 + # pg8000 for Python 3.5+ + ecode = eargs0['C'] + eerror = emessage = eargs0['M'] + elif hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors + ecode = getattr(e, 'pgcode', None) + eerror = getattr(e, 'pgerror', None) else: - obj.code = getattr(e, 'code', None) - obj.error = getattr(e, 'error', None) + ecode = getattr(e, 'code', None) + eerror = getattr(e, 'error', None) + obj = str.__new__(cls, emessage + append_msg) + obj.code = ecode + obj.error = eerror obj.module = e.__module__ obj.exception = e.__class__.__name__ return obj @@ -237,7 +250,8 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) except self.module.IntegrityError as e: msg = ErrorMessage(e) - if getattr(e, 'code', -1) == '23505' or \ + if getattr(msg, 'code', -1) == '23505' or \ + getattr(e, 'code', -1) == '23505' or \ getattr(e, 'pgcode', -1) == '23505' or \ getattr(e, 'sqlstate', -1) == '23505' or \ e.args[0] == '23505': From aa8815be7576ca097233993d6387a34196570c1d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Feb 2021 21:20:21 +0300 Subject: [PATCH 086/295] Tests(tox.ini): Limit `pg8000` version for Python 2.7 and 3.4 Revert back to stock `pg8000`. --- devscripts/requirements/requirements_pg8000.txt | 3 +++ devscripts/requirements/requirements_pygresql.txt | 2 +- setup.py | 4 +++- tox.ini | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 devscripts/requirements/requirements_pg8000.txt diff --git a/devscripts/requirements/requirements_pg8000.txt b/devscripts/requirements/requirements_pg8000.txt new file mode 100644 index 00000000..06cd178f --- /dev/null +++ b/devscripts/requirements/requirements_pg8000.txt @@ -0,0 +1,3 @@ +pg8000 < 1.13; python_version == '2.7' +pg8000 < 1.12.4; python_version == '3.4' +pg8000; python_version >= '3.5' diff --git a/devscripts/requirements/requirements_pygresql.txt b/devscripts/requirements/requirements_pygresql.txt index ea4052ca..5fbb3514 100644 --- a/devscripts/requirements/requirements_pygresql.txt +++ b/devscripts/requirements/requirements_pygresql.txt @@ -1,2 +1,2 @@ -pygresql<5.2; python_version == '3.4' +pygresql < 5.2; python_version == '3.4' pygresql; python_version != '3.4' diff --git a/setup.py b/setup.py index 11a6cbaa..3dfd2caa 100755 --- a/setup.py +++ b/setup.py @@ -133,7 +133,9 @@ 'pygresql': ['pygresql'], 'pypostgresql': ['py-postgresql'], 'py-postgresql': ['py-postgresql'], - 'pg8000': ['pg8000'], + 'pg8000:python_version=="2.7"': ['pg8000<1.13'], + 'pg8000:python_version=="3.4"': ['pg8000<1.12.4'], + 'pg8000:python_version>="3.5"': ['pg8000'], # 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], diff --git a/tox.ini b/tox.ini index 95bfdbd7..67765a34 100644 --- a/tox.ini +++ b/tox.ini @@ -29,7 +29,7 @@ deps = postgres-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql - postgres-pg8000: git+https://github.com/sqlobject/pg8000.git@getuser#egg=pg8000 + pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc supersqlite: supersqlite From 3173e08bcd55284c5b914d7d59088c94ad83f7c7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Feb 2021 22:00:41 +0300 Subject: [PATCH 087/295] Feat(PostgreSQL): Protect `getuser()` It can raise `ImportError` on w32 due to absent of `pwd` module. --- docs/News.rst | 3 +++ sqlobject/postgres/pgconnection.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 234fca55..f190d966 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,9 @@ Drivers * Adapt to the latest ``pg8000``. +* Protect ``getuser()`` - it can raise ``ImportError`` on w32 + due to absent of ``pwd`` module. + Build ----- diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 749ca575..722f3d4e 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -35,6 +35,15 @@ def __new__(cls, e, append_msg=''): return obj +def _getuser(): + # ``getuser()`` on w32 can raise ``ImportError`` + # due to absent of ``pwd`` module. + try: + return getuser() + except ImportError: + return None + + class PostgresConnection(DBAPI): supportTransactions = True @@ -174,7 +183,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, dsn_dict["host"] = None dsn_dict["unix_sock"] = host if user is None: - dsn_dict["user"] = getuser() + dsn_dict["user"] = _getuser() self.dsn = dsn self.driver = driver self.unicodeCols = kw.pop('unicodeCols', False) From 8bcaa3cc57c96d915549b8666548b4e0d5fabaa9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 16:40:16 +0300 Subject: [PATCH 088/295] Release 3.9.1 --- ANNOUNCE.rst | 40 ++++++++++++++++++++++++++-------------- README.rst | 4 ++-- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 4 ++-- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 72872502..fdee54bc 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,37 @@ Hello! -I'm pleased to announce version 3.9.1a1, the first alpha of the upcoming -release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.1, the first minor feature release +of branch 3.9 of SQLObject. -I'm pleased to announce version 3.9.1a2, the second alpha of the upcoming -release of branch 3.9 of SQLObject. -I'm pleased to announce version 3.9.1b1, the first beta of the upcoming -release of branch 3.9 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.9.1rc1, the first release candidate -of the upcoming release of branch 3.9 of SQLObject. +Drivers +------- -I'm pleased to announce version 3.9.1, the first bugfix release of branch -3.9 of SQLObject. +* Adapt to the latest ``pg8000``. +* Protect ``getuser()`` - it can raise ``ImportError`` on w32 + due to absent of ``pwd`` module. -What's new in SQLObject -======================= +Build +----- + +* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. + Provide separate URLs for Python 2.7 and 3.4+. + +* Add ``mariadb`` in ``extras_require`` in ``setup.py``. + +CI +-- + +* For tests with Python 3.4 run ``tox`` under Python 3.5. + +Tests +----- -Contributors for this release are +* Refactor ``tox.ini``. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +64,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.1a0.dev20201215/ +https://pypi.org/project/SQLObject/3.9.1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 2442b674..80d69665 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.1a0 -================= +SQLObject 3.9.1 +=============== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index f190d966..06c9c8fd 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.9.1 +=============== + +Released 2021 Feb 27. Drivers ------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index f133a875..cb43f08a 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.9.0' +version = '3.9.1' major = 3 minor = 9 -micro = 0 +micro = 1 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 1551a039c36ae52b03076a7826b3fded29950245 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 16:49:36 +0300 Subject: [PATCH 089/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 40 ++++++++++++++-------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index fdee54bc..5f6c2aa6 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,37 +1,25 @@ Hello! -I'm pleased to announce version 3.9.1, the first minor feature release -of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.2a1, the first alpha of the upcoming +release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.9.2a2, the second alpha of the upcoming +release of branch 3.9 of SQLObject. -What's new in SQLObject -======================= - -Drivers -------- - -* Adapt to the latest ``pg8000``. - -* Protect ``getuser()`` - it can raise ``ImportError`` on w32 - due to absent of ``pwd`` module. +I'm pleased to announce version 3.9.2b1, the first beta of the upcoming +release of branch 3.9 of SQLObject. -Build ------ +I'm pleased to announce version 3.9.2rc1, the first release candidate +of the upcoming release of branch 3.9 of SQLObject. -* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. - Provide separate URLs for Python 2.7 and 3.4+. +I'm pleased to announce version 3.9.2, the first bugfix release of branch +3.9 of SQLObject. -* Add ``mariadb`` in ``extras_require`` in ``setup.py``. -CI --- - -* For tests with Python 3.4 run ``tox`` under Python 3.5. - -Tests ------ +What's new in SQLObject +======================= -* Refactor ``tox.ini``. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -64,7 +52,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.1 +https://pypi.org/project/SQLObject/3.9.2a0.dev20210227/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 80d69665..2152854e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.1 -=============== +SQLObject 3.9.2a0 +================= Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index 06c9c8fd..37935f3a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.9.1 =============== From cf99cde3cb2a828ee165e2b32dc886a0b881f17e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 16:58:29 +0300 Subject: [PATCH 090/295] Build(devscripts): Update `RELEASE-CHECKLIST` Remove duplicate "commit and merge" instructions. [skip ci] --- devscripts/RELEASE-CHECKLIST | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index e85de5e2..42f6b10b 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -17,8 +17,7 @@ 'dev' and date stamp). If it's the first stable release of the branch - edit build-all-docs, - advance stable branch. Commit. If it's not master - merge to all higher - branches and master. + advance stable branch. Commit. Verify. From a95ac237f6c8289afa872c879622cb14cb7af995 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 17:00:20 +0300 Subject: [PATCH 091/295] Build(devscripts): Update `RELEASE-CHECKLIST` Reorder instructions: run `push-all` after `postrelease`. [skip ci] --- devscripts/RELEASE-CHECKLIST | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 42f6b10b..f47ec418 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -34,15 +34,15 @@ 6. Move old releases at SourceForge to subdirectory OldFiles. -7. Run devscripts/push-all in the development repository to push all - branches and tags to the public repositories. - -8. Run devscripts/postrelease. The script restores ANNOUNCE.rst and +7. Run devscripts/postrelease. The script restores ANNOUNCE.rst and setup.cfg from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new version. +8. Run devscripts/push-all in the development repository to push all + branches and tags to the public repositories. + 9. Generate new docs using devscripts/build-all-docs. Upload docs using devscripts/publish-docs. From df7ad69dca4d25021b0f07f90aac075b38d20227 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 27 Feb 2021 17:04:44 +0300 Subject: [PATCH 092/295] Build(devscripts): Fix `build-all-docs`: Set the current version [skip ci] --- devscripts/build-all-docs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 1f21c9a8..34aacd3c 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.9.0 && +build_docs 3.9.1 && build_docs master devel && rm -rf docs/html && From 1f50e64d9fa6cd96843cdbf3901c0517a075cfe6 Mon Sep 17 00:00:00 2001 From: James Hudson Date: Thu, 3 Jun 2021 16:23:41 +0100 Subject: [PATCH 093/295] Add new converter for pendulum.DateTime --- sqlobject/converters.py | 14 ++++++++++++++ sqlobject/tests/test_datetime.py | 22 +++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/sqlobject/converters.py b/sqlobject/converters.py index fa6ea1c0..667fdded 100644 --- a/sqlobject/converters.py +++ b/sqlobject/converters.py @@ -22,6 +22,13 @@ mxDateTimeType = None mxDateTimeDeltaType = None +try: + import pendulum +except ImportError: + pendulumDateTimeType = None +else: + pendulumDateTimeType = pendulum.DateTime + try: from DateTime import DateTime as zopeDateTime except ImportError: @@ -215,6 +222,13 @@ def mxTimeConverter(value, db): registerConverter(mxDateTimeDeltaType, mxTimeConverter) +if pendulumDateTimeType: + def pendulumConverter(value, db): + return "'%s'" % value.to_datetime_string() + + registerConverter(pendulum.DateTime, pendulumConverter) + + if zopeDateTimeType: def zopeDateTimeConverter(value, db): return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S") diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index 06ce1ae6..21ed5a62 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -7,7 +7,7 @@ DATETIME_IMPLEMENTATION, MXDATETIME_IMPLEMENTATION, mxdatetime_available, \ ZOPE_DATETIME_IMPLEMENTATION, zope_datetime_available from sqlobject.tests.dbtest import getConnection, setupClass - +from sqlobject.converters import pendulumDateTimeType ######################################## # Date/time columns @@ -130,6 +130,26 @@ def test_mxDateTime(): assert dt2.col3.minute == _now.minute assert dt2.col3.second == int(_now.second) +if pendulumDateTimeType: + import pendulum + + class DateTimePendulum(SQLObject): + col1 = DateTimeCol() + + def test_PendulumDateTime(): + setupClass(DateTimePendulum) + _now = pendulum.now() + dtp = DateTimePendulum(col1=_now) + + assert isinstance(dtp.col1, datetime) + assert dtp.col1.year == _now.year + assert dtp.col1.month == _now.month + assert dtp.col1.day == _now.day + assert dtp.col1.hour == _now.hour + assert dtp.col1.minute == _now.minute + assert int(dtp.col1.second) == int(_now.second) + + if zope_datetime_available: col.default_datetime_implementation = ZOPE_DATETIME_IMPLEMENTATION from DateTime import DateTime as zopeDateTime From 48e7eac934099caec2d7f3a0b86ff2badb000ec4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:13:02 +0300 Subject: [PATCH 094/295] CI: Downgrade `pip` to `<19.2` for Python 3.4 compatibility --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 638d6484..adcd77ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -127,7 +127,7 @@ before_install: sudo chmod 644 /var/lib/firebird/create_test_db fi -install: travis_retry pip install --upgrade "pip<21" "setuptools<44" "tox>=3.15" coveralls codecov ppu +install: travis_retry pip install --upgrade "pip<19.2" "setuptools<44" "tox>=3.15" coveralls codecov ppu script: devscripts/tox-select-envs $TESTS diff --git a/appveyor.yml b/appveyor.yml index 38a7a1ec..808f4404 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -124,7 +124,7 @@ install: - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - "python --version" - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip<21\" \"setuptools<44\"" + - "python -m pip install --upgrade \"pip<19.2\" \"setuptools<44\"" - "pip install --upgrade \"tox>=3.15\" ppu" - "pip --version" # List ODBC drivers From 51387761fa25f7d41916a3876753ef86ad4f4d7f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:16:26 +0300 Subject: [PATCH 095/295] Tests(tox): Install `zope.datetime` --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 67765a34..28717e6d 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,8 @@ commands = {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = -rdevscripts/requirements/requirements_tests.txt + py34: zope.datetime < 4.3 + !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 From 84a4595b6a3f881979fb2d1a8ee39196fca08243 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:25:48 +0300 Subject: [PATCH 096/295] Docs: Add compatibility with `Pendulum` Authors: Add James Hudson. [skip ci] --- docs/Authors.rst | 1 + docs/News.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 9f1c6fe5..5ac91443 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -37,6 +37,7 @@ Contributions have been made by: * Michael S. Root * Scott Stahl * Markus Elfring +* James Hudson * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 diff --git a/docs/News.rst b/docs/News.rst index 37935f3a..96cc7f7c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Features +-------- + +* Add compatibility with ``Pendulum``. + SQLObject 3.9.1 =============== From 6624e0a319fb81e11a586cb5ac2f8fd5c4b95b27 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:27:58 +0300 Subject: [PATCH 097/295] Tests(tox): Install `pendulum` for new test in `test_datetime` --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 67765a34..158c18cf 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,8 @@ commands = {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = -rdevscripts/requirements/requirements_tests.txt + py34: pendulum < 2.1 + !py34: pendulum mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 From 661f41c795e020ffea9d16df0e340d54c73974c1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 4 Jun 2021 19:32:04 +0300 Subject: [PATCH 098/295] Tests(test_datetime): Fix `test_PendulumDateTime` Reset `default_datetime_implementation` back to `datetime`. --- sqlobject/tests/test_datetime.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index 21ed5a62..b40e4dd4 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -131,6 +131,7 @@ def test_mxDateTime(): assert dt2.col3.second == int(_now.second) if pendulumDateTimeType: + col.default_datetime_implementation = DATETIME_IMPLEMENTATION import pendulum class DateTimePendulum(SQLObject): From 924c868a16fde2c2d31609c3c26d4d49052ef0a0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 19 Jul 2021 00:32:56 +0300 Subject: [PATCH 099/295] Docs: Change Travis CI URLs CI relocated from travis-ci.org to travis-ci.com. [skip ci] --- docs/DeveloperGuide.rst | 4 ++-- docs/News.rst | 6 ++++++ setup.py | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 966c379d..4ac95566 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -272,8 +272,8 @@ exercised, even if the tests are absolutely complete. We now use Travis CI and AppVeyor to run tests. See the statuses: -.. image:: https://travis-ci.org/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.org/sqlobject/sqlobject +.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master + :target: https://travis-ci.com/github/sqlobject/sqlobject .. image:: https://ci.appveyor.com/api/projects/status/github/sqlobject/sqlobject?branch=master :target: https://ci.appveyor.com/project/phdru/sqlobject diff --git a/docs/News.rst b/docs/News.rst index 96cc7f7c..af6b8a7d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,12 @@ Features * Add compatibility with ``Pendulum``. +Documentation +------------- + +* Change Travis CI URLs: + CI relocated from travis-ci.org to travis-ci.com. + SQLObject 3.9.1 =============== diff --git a/setup.py b/setup.py index 3dfd2caa..c7f59f24 100755 --- a/setup.py +++ b/setup.py @@ -42,8 +42,8 @@ `SourceForge `_ and `GitHub `_. -.. image:: https://travis-ci.org/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.org/sqlobject/sqlobject +.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master + :target: https://travis-ci.com/github/sqlobject/sqlobject """, long_description_content_type="text/x-rst", classifiers=[ From 87757d537df98bb7fb9b40e6f402266ef39b2c7e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Jul 2021 14:49:55 +0300 Subject: [PATCH 100/295] Tests(tox): Limit `VIRTUALENV_PIP` version for Python 3.4 --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index c03d56cd..64e08bd6 100644 --- a/tox.ini +++ b/tox.ini @@ -40,6 +40,8 @@ deps = firebird-fdb: fdb firebirdsql: firebirdsql passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR +setenv = + VIRTUALENV_PIP = 19.1.1 # Don't fail or warn on uninstalled commands platform = linux whitelist_externals = From f4741f8e03171883554319c6d7d59a26dedd1762 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Jul 2021 19:54:28 +0300 Subject: [PATCH 101/295] Tests(tox): Limit `pip` and `setuptools` versions for Python 3.4 --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 64e08bd6..88febe67 100644 --- a/tox.ini +++ b/tox.ini @@ -18,6 +18,8 @@ commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = + pip < 19.2 + setuptools < 44 -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 py34: zope.datetime < 4.3 From 6a4df62a61757f64c452359a57ff956bac6f452d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 3 Oct 2021 17:52:17 +0300 Subject: [PATCH 102/295] Build(devscripts): `rsync -a` -> `rsync -ahPv` Especially remove option `-4`. [skip ci] --- devscripts/build-all-docs | 2 +- devscripts/release | 4 ++-- docs/rebuild | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 34aacd3c..8cb4ba16 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -3,7 +3,7 @@ build_docs() { git checkout "$1" && devscripts/build-docs && - rsync -ahP --del --exclude=/robots.txt docs/html/ ../SQLObject-docs/"$2"/ + rsync -ahPv --del --exclude=/robots.txt docs/html/ ../SQLObject-docs/"$2"/ } cd "`dirname \"$0\"`" && diff --git a/devscripts/release b/devscripts/release index 33bb23ff..3873ec25 100755 --- a/devscripts/release +++ b/devscripts/release @@ -19,8 +19,8 @@ version=`python setup.py --version` split_tag $version if [ "$state" = final ]; then - rsync -ahP4 dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && - rsync -ahP4 ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 + rsync -ahPv dist/* frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/ && + rsync -ahPv ANNOUNCE.rst frs.sourceforge.net:/home/frs/project/sqlobject/sqlobject/"$version"/README.rst || exit 1 devscripts/sftp-frs fi && diff --git a/docs/rebuild b/docs/rebuild index 12703849..4798a23d 100755 --- a/docs/rebuild +++ b/docs/rebuild @@ -2,4 +2,4 @@ PYTHONPATH=.. make html && find . -name \*.tmp -type f -delete && -exec rsync -ahP --del --exclude=.buildinfo --exclude=objects.inv _build/html . +exec rsync -ahPv --del --exclude=.buildinfo --exclude=objects.inv _build/html . From 0d612ecb5e3f367a7734636d31cd2e80d1edd27e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 5 Oct 2021 10:47:59 +0300 Subject: [PATCH 103/295] Build: Remove personal script `setup` [skip ci] --- devscripts/setup | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100755 devscripts/setup diff --git a/devscripts/setup b/devscripts/setup deleted file mode 100755 index e28d6765..00000000 --- a/devscripts/setup +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/sh - -umask 022 # -rwxr-xr-x -cd "`dirname \"$0\"`"/.. && - -for py_ver in 2.7 3.4 3.5 3.6 3.7 3.8 3.9; do - python$py_ver -m pip install --install-option=-O2 --upgrade . -done && - -exec rm -rf build dist SQLObject.egg-info MANIFEST *.egg From d7c7996ed212ee18b416f527a7dfc4e746434465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 15:42:10 +0200 Subject: [PATCH 104/295] fix typo --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..a4adc741 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -584,7 +584,7 @@ in-place:: the class definition is equivalent to calling certain class methods (like ``addColumn()``). -Now we can get the backreference with ``aPerson.addresses``, which +Now we can get the backreference with ``Person.addresses``, which returns a list. An example:: >>> p.addresses From caa8261b0b21bca42dc10825359ab7114470dc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:38:14 +0200 Subject: [PATCH 105/295] fix typo --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..079da8d4 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -264,7 +264,7 @@ To create a new object (and row), use class instantiation, like:: .. note:: In SQLObject NULL/None does *not* mean default. NULL is a funny - thing; it mean very different things in different contexts and to + thing; it means very different things in different contexts and to different people. Sometimes it means "default", sometimes "not applicable", sometimes "unknown". If you want a default, NULL or otherwise, you always have to be explicit in your class From 8878c12bb3e1508ea34b277e30b5e542be3139cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:40:15 +0200 Subject: [PATCH 106/295] remove redundant dot --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..4e1962f4 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -304,7 +304,7 @@ Here's a longer example of using the class:: >>> p is p2 True -Columns are accessed like attributes. (This uses the ``property`` +Columns are accessed like attributes (This uses the ``property`` feature of Python, so that retrieving and setting these attributes executes code). Also note that objects are unique -- there is generally only one ``Person`` instance of a particular id in memory at From bc88b43dc6b34c42c25e3fd751df214bf83b2e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:48:57 +0200 Subject: [PATCH 107/295] fix hint about indexes Using an index properly improves performance, not importance. --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..96780597 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -461,7 +461,7 @@ slicing, this makes batched queries easy to write: the entire result set to sort the items (so it knows which the first ten are), and depending on your query may need to scan through the entire table (depending on your use of indexes). - Indexes are probably the most important way to improve importance + Indexes are probably the most important way to improve performance in a case like this, and you may find caching to be more effective than slicing. From f73d5f8df8d3fac02e110d2138976cba750924d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Mon, 18 Oct 2021 17:55:24 +0200 Subject: [PATCH 108/295] fix address example --- docs/SQLObject.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..3fe858a8 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -546,8 +546,8 @@ addresses, of course:: Note the column ``person = ForeignKey("Person")``. This is a reference to a `Person` object. We refer to other classes by name -(with a string). In the database there will be a ``person_id`` -column, type ``INT``, which points to the ``person`` column. +(with a string). In the address table there will be a ``person_id`` +column, type ``INT``, which points to the ``person`` table. .. note:: From fa13293d11eb11c1fb1400234fdc7c7c27c31b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Gmach?= Date: Tue, 19 Oct 2021 15:56:45 +0200 Subject: [PATCH 109/295] fix description for `joinColumn` --- docs/SQLObject.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index ddbe2c5d..33beaf34 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1357,7 +1357,7 @@ Several keyword arguments are allowed to the `MultipleJoin` constructor: have a table ``Product``, and another table has a column ``ProductNo`` that points to this table, then you'd use ``joinColumn="ProductNo"``. WARNING: the argument you pass must - conform to the column name in the database, not to the column in the + conform to the column name in the database, not to the attribute in the class. So, if you have a SQLObject containing the ``ProductNo`` column, this will probably be translated into ``product_no_id`` in the DB (``product_no`` is the normal uppercase- to-lowercase + From 6b1514aa4d881b947e799595d6d92cffdb342922 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 31 Oct 2021 12:51:59 +0300 Subject: [PATCH 110/295] Docs(Authors): Add Juergen Gmach [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 5ac91443..70115048 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -38,6 +38,7 @@ Contributions have been made by: * Scott Stahl * Markus Elfring * James Hudson +* Juergen Gmach * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From b74820a65dbbaa48064bc0f3d98091b1a3820a41 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 7 Nov 2021 00:33:20 +0300 Subject: [PATCH 111/295] Tests: Python 3.10 --- docs/News.rst | 5 ++++ setup.py | 1 + tox.ini | 73 ++++++++++++++++++++++++++------------------------- 3 files changed, 43 insertions(+), 36 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index af6b8a7d..4c45d135 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,11 @@ Features * Add compatibility with ``Pendulum``. +Tests +----- + +* Run tests with Python 3.10. + Documentation ------------- diff --git a/setup.py b/setup.py index c7f59f24..d98fb37d 100755 --- a/setup.py +++ b/setup.py @@ -61,6 +61,7 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 88febe67..5f65b49d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9}-sqlite{,-memory},py{27,39}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10}-sqlite{,-memory},py{27,310}-flake8 # Base test environment settings [testenv] @@ -14,12 +14,13 @@ basepython = py37: {env:TOXPYTHON:python3.7} py38: {env:TOXPYTHON:python3.8} py39: {env:TOXPYTHON:python3.9} + py310: {env:TOXPYTHON:python3.10} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = - pip < 19.2 - setuptools < 44 + py27,py34: pip < 19.2 + py27,py34: setuptools < 44 -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 py34: zope.datetime < 4.3 @@ -70,7 +71,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -86,7 +87,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -102,7 +103,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-connector-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-noauto] commands = {[mysql-connector]commands} [oursql] @@ -118,7 +119,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -134,7 +135,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -149,7 +150,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9}-mariadb] +[testenv:py3{6,7,8,9,10}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -166,7 +167,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -182,7 +183,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -199,7 +200,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -215,7 +216,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -230,7 +231,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql] commands = {[pypostgresql]commands} [pg8000] @@ -246,7 +247,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pg8000] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -263,7 +264,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -279,7 +280,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -296,7 +297,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite] +[testenv:py3{4,5,6,7,8,9,10}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -309,7 +310,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory] commands = {[sqlite-memory]commands} [sqlite-supersqlite] @@ -324,7 +325,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-supersqlite]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-supersqlite] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} @@ -342,7 +343,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -358,7 +359,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10}-firebirdsql] commands = {[firebirdsql]commands} @@ -388,7 +389,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -407,7 +408,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -426,7 +427,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -444,7 +445,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9}-mariadb-w32] +[testenv:py3{6,7,8,9,10}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -464,7 +465,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -484,7 +485,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -503,7 +504,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -522,7 +523,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -540,7 +541,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9}-postgres-pypostgresql-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -559,7 +560,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -579,7 +580,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -599,7 +600,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -616,7 +617,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -632,6 +633,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From c3933b813383cc1b269b6c2564e89e3c7aa523e9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 8 Nov 2021 00:34:15 +0300 Subject: [PATCH 112/295] Docs(DevGuide): Document more requirements Document more requirements and recommendations for the source code and commit messages. [skip ci] --- docs/DeveloperGuide.rst | 23 ++++++++++++++++++++++- docs/News.rst | 14 ++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 4ac95566..955dc03d 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -125,6 +125,9 @@ Python Style Guide. Some things to take particular note of: .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ +* With some exceptions sources must be pure ASCII. Including string + literals and comments. + * With a few exceptions sources must be `flake8`_-clean (and hence pep8-clean). Please consider using pre-commit hook installed by running ``flake8 --install-hook``. @@ -196,6 +199,9 @@ Python Style Guide. Some things to take particular note of: Don't use single quotes ('''). Don't bother trying make the string less vertically compact. + Not strictly required but ``reStructuredText`` format for docstrings is + very much recommended. + * Comments go right before the thing they are commenting on. * Methods never, ever, ever start with capital letters. Generally @@ -298,9 +304,24 @@ Documentation ============= Please write documentation. Documentation should live in the docs/ -directory in reStructuredText format. We use Sphinx to convert docs to +directory in ``reStructuredText`` format. We use Sphinx to convert docs to HTML. +Contributing +============ + +* Now de-facto `stadard for good commit messages + `_ is required. + +* `Conventional commit subject liness + `_ are recommended. + +* ``Markdown`` format for commit message bodies is recommended. + `Github-flavored Markdown `_ is allowed. + +* Commit messages must be pure ASCII. No fancy Unicode emojies, + quotes, etc. + .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 :target: https://sourceforge.net/projects/sqlobject :class: noborder diff --git a/docs/News.rst b/docs/News.rst index 4c45d135..c1a52547 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,20 @@ Tests Documentation ------------- +* DevGuide: source code must be pure ASCII. + +* DevGuide: ``reStructuredText`` format for docstrings is recommended. + +* DevGuide: de-facto good commit message format is required: + subject/body/trailers. + +* DevGuide: ``conventional commit`` format for commit message subject lines + is recommended. + +* DevGuide: ``Markdown`` format for commit message bodies is recommended. + +* DevGuide: commit messages must be pure ASCII. + * Change Travis CI URLs: CI relocated from travis-ci.org to travis-ci.com. From 2a7d26086f73028fdb651f9e22e99c812b81b883 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 11 Jan 2022 16:56:41 +0200 Subject: [PATCH 113/295] Remove "U" option in open for Python 3.11 compatibility --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d98fb37d..cdfcb9aa 100755 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ execfile(versionpath, sqlobject_version) # noqa: F821 'execfile' Py3 elif sys.version_info >= (3, 4): - exec(open(versionpath, 'rU').read(), sqlobject_version) + exec(open(versionpath, 'r').read(), sqlobject_version) else: raise ImportError("SQLObject requires Python 2.7 or 3.4+") From 18f55ff5894eeb33dc77d6318cf32f0d4341f661 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Jan 2022 21:41:33 +0300 Subject: [PATCH 114/295] Docs(Authors): Add Hugo van Kemenade [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 70115048..6c5b23c9 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -39,6 +39,7 @@ Contributions have been made by: * Markus Elfring * James Hudson * Juergen Gmach +* Hugo van Kemenade * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From 9f3ca7e00da3d820b7181a9988f82424b2439254 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 21 Feb 2022 18:29:29 +0300 Subject: [PATCH 115/295] Feat(dbconnection): Allow connections in `ConnectionHub` to be strings This allows to open a new connection in every thread. --- docs/News.rst | 3 +++ sqlobject/dbconnection.py | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index c1a52547..afce29f1 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,9 @@ SQLObject (master) Features -------- +* Allow connections in ``ConnectionHub`` to be strings. + This allows to open a new connection in every thread. + * Add compatibility with ``Pendulum``. Tests diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index e3de62e8..6a383e79 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -989,14 +989,21 @@ def __set__(self, obj, value): def getConnection(self): try: - return self.threadingLocal.connection + connection = self.threadingLocal.connection + if isinstance(connection, string_type): + connection = connectionForURI(connection) + self.threadingLocal.connection = connection except AttributeError: try: - return self.processConnection + connection = self.processConnection + if isinstance(connection, string_type): + connection = connectionForURI(connection) + self.processConnection = connection except AttributeError: raise AttributeError( "No connection has been defined for this thread " "or process") + return connection def doInTransaction(self, func, *args, **kw): """ @@ -1019,6 +1026,8 @@ def doInTransaction(self, func, *args, **kw): except AttributeError: old_conn = self.processConnection old_conn_is_threading = False + if isinstance(old_conn, string_type): + old_conn = connectionForURI(old_conn) conn = old_conn.transaction() if old_conn_is_threading: self.threadConnection = conn From 91057747751df3793898898903fb371709ccc1f8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 21 Feb 2022 23:17:59 +0300 Subject: [PATCH 116/295] Build(devscripts): Run Python 3.10 in `test-sqlobject.cmd` --- devscripts/test-sqlobject.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd index 97846d80..8c7e38d0 100644 --- a/devscripts/test-sqlobject.cmd +++ b/devscripts/test-sqlobject.cmd @@ -3,7 +3,7 @@ SetLocal EnableDelayedExpansion set SavePATH=%PATH% -for %%V in (27 34 35 36 37 38 39) do ( +for %%V in (27 34 35 36 37 38 39 310) do ( for %%s in (32 64) do ( set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! set TOXPYTHON=C:\Python%%V-%%s\python.exe From 71da8511dd6ab1b45c2d2057849602b7d66a8435 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 22 Feb 2022 00:12:02 +0300 Subject: [PATCH 117/295] Test(tox): `postgres-psycopg` -> `psycopg` --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5f65b49d..e29e1d77 100644 --- a/tox.ini +++ b/tox.ini @@ -33,7 +33,7 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - postgres-psycopg: psycopg2-binary + psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt From 576f82f00163ef041ff994f9ed9cca168300c835 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 22 Feb 2022 00:13:04 +0300 Subject: [PATCH 118/295] Test(tox): Use our branch `combined-fixes` for `py-postgresql` The branch combines fixes from `fix_w32` and `pr/114` (parse PostgreSQL version screwed by Debian). --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index e29e1d77..8fadaffc 100644 --- a/tox.ini +++ b/tox.ini @@ -35,7 +35,7 @@ deps = mariadb: mariadb psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt - pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@fix_w32#egg=py-postgresql + pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc From 42a1f53a2368e4a53d0bef0227295d3fec9f4731 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 23 Feb 2022 05:28:19 +0300 Subject: [PATCH 119/295] Tests(tox): Limit version of `psycopg2-binary` for Python 3.4 --- tox.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 8fadaffc..73adcfee 100644 --- a/tox.ini +++ b/tox.ini @@ -33,7 +33,8 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - psycopg: psycopg2-binary + py34-psycopg: psycopg2-binary==2.8.4 + !py34-psycopg: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt From 836763622ef5b93f933cbd712ef7b65cdb742183 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 23 Feb 2022 19:02:45 +0300 Subject: [PATCH 120/295] Tests(tox): Use long options for MySQL/PostgreSQL tools --- tox.ini | 120 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/tox.ini b/tox.ini index 73adcfee..9c2ae387 100644 --- a/tox.ini +++ b/tox.ini @@ -62,10 +62,10 @@ whitelist_externals = [mysqldb] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysqldb] commands = @@ -79,10 +79,10 @@ deps = [mysqlclient] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysqlclient] commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" @@ -94,10 +94,10 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-connector-noauto] commands = @@ -110,10 +110,10 @@ commands = {[mysql-connector]commands} [oursql] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-oursql-noauto] commands = @@ -126,10 +126,10 @@ commands = {[oursql]commands} [pymysql] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-pymysql] commands = @@ -142,10 +142,10 @@ commands = {[pymysql]commands} [mariadb] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" @@ -158,10 +158,10 @@ commands = {[mariadb]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-pyodbc-noauto] commands = @@ -174,10 +174,10 @@ commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] commands = {[testenv]commands} - -mysql -uroot -e 'drop database sqlobject_test;' - mysql -uroot -e 'create database sqlobject_test;' + -mysql --user=root --execute='drop database sqlobject_test;' + mysql --user=root --execute='create database sqlobject_test;' pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql -uroot -e 'drop database sqlobject_test;' + mysql --user=root --execute='drop database sqlobject_test;' [testenv:py27-mysql-pypyodbc-noauto] commands = @@ -191,10 +191,10 @@ commands = {[mysql-pypyodbc]commands} [psycopg] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg] commands = @@ -207,10 +207,10 @@ commands = {[psycopg]commands} [pygresql] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql] commands = @@ -223,10 +223,10 @@ commands = {[pygresql]commands} [pypostgresql] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" @@ -238,10 +238,10 @@ commands = {[pypostgresql]commands} [pg8000] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000] commands = @@ -255,10 +255,10 @@ commands = {[pg8000]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] commands = @@ -271,10 +271,10 @@ commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] commands = @@ -494,10 +494,10 @@ commands = {[mysql-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] platform = win32 @@ -513,10 +513,10 @@ commands = {[psycopg-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test -pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] platform = win32 @@ -532,10 +532,10 @@ commands = {[pygresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] platform = win32 @@ -550,10 +550,10 @@ commands = {[pypostgresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] platform = win32 @@ -570,10 +570,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] platform = win32 @@ -590,10 +590,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -dropdb -U postgres -w sqlobject_test - createdb -U postgres -w sqlobject_test + -dropdb --username=postgres --no-password sqlobject_test + createdb --username=postgres --no-password sqlobject_test pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb -U postgres -w sqlobject_test + dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] platform = win32 From 1aed26838d1616b3686b74697e01bb4da5e47b79 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:37:31 +0300 Subject: [PATCH 121/295] Style: Fix `flake8` E275 missing whitespace after keyword --- sqlobject/tests/test_identity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlobject/tests/test_identity.py b/sqlobject/tests/test_identity.py index b3111f25..2c862efe 100644 --- a/sqlobject/tests/test_identity.py +++ b/sqlobject/tests/test_identity.py @@ -20,10 +20,10 @@ def test_identity(): SOTestIdentity(n=100) # i1 # verify result i1get = SOTestIdentity.get(1) - assert(i1get.n == 100) + assert (i1get.n == 100) # insert while giving identity SOTestIdentity(id=2, n=200) # i2 # verify result i2get = SOTestIdentity.get(2) - assert(i2get.n == 200) + assert (i2get.n == 200) From 71ba79e666a738d37cf1d57eb82e2be1b61a2c90 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:40:49 +0300 Subject: [PATCH 122/295] Style: Fix `flake8` E501 line too long --- sqlobject/include/hashcol.py | 12 ++++++++---- sqlobject/sqlbuilder.py | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sqlobject/include/hashcol.py b/sqlobject/include/hashcol.py index e36b980e..83f8fec4 100644 --- a/sqlobject/include/hashcol.py +++ b/sqlobject/include/hashcol.py @@ -6,8 +6,10 @@ class DbHash: - """ Presents a comparison object for hashes, allowing plain text to be - automagically compared with the base content. """ + """ + Presents a comparison object for hashes, allowing plain text to be + automagically compared with the base content + """ def __init__(self, hash, hashMethod): self.hash = hash @@ -99,7 +101,9 @@ def createValidators(self): class HashCol(sqlobject.col.StringCol): - """ End-user HashCol class. May be instantiated with 'hashMethod', a function - which returns the string hash of any other string (i.e. basestring). """ + """ + End-user HashCol class. May be instantiated with 'hashMethod', a function + which returns the string hash of any other string (i.e. basestring) + """ baseClass = SOHashCol diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 844ab9ea..9eabcf52 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -1509,8 +1509,9 @@ def tablesUsedImmediate(self): class ImportProxy(SQLExpression): - '''Class to be used in column definitions that rely on other tables that might - not yet be in a classregistry. + ''' + Class to be used in column definitions that rely on other tables that might + not yet be in a classregistry ''' FieldClass = ImportProxyField From 50e50dc0c972ab80c6dc8f3ca64fe7c762cb73ed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:42:13 +0300 Subject: [PATCH 123/295] Style(hashcol): Improve docstring formatting --- sqlobject/include/hashcol.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlobject/include/hashcol.py b/sqlobject/include/hashcol.py index 83f8fec4..7a8bbf4d 100644 --- a/sqlobject/include/hashcol.py +++ b/sqlobject/include/hashcol.py @@ -63,7 +63,7 @@ def __repr__(self): class HashValidator(sqlobject.col.StringValidator): - """ Provides formal SQLObject validation services for the HashCol. """ + """Provides formal SQLObject validation services for the HashCol""" def to_python(self, value, state): """ Passes out a hash object. """ @@ -72,14 +72,14 @@ def to_python(self, value, state): return DbHash(hash=value, hashMethod=self.hashMethod) def from_python(self, value, state): - """ Store the given value as a MD5 hash, or None if specified. """ + """Store the given value as a MD5 hash, or None if specified""" if value is None: return None return self.hashMethod(value) class SOHashCol(sqlobject.col.SOStringCol): - """ The internal HashCol definition. By default, enforces a md5 digest. """ + """The internal HashCol definition. By default, enforces a md5 digest""" def __init__(self, **kw): if 'hashMethod' not in kw: From 8cde480dfa2940ae1ea4626873627d7ed2d4f325 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 17 Sep 2022 14:54:18 +0300 Subject: [PATCH 124/295] Fix(test): Use `"`-quotes for command line w32 doesn't like apostrophes. Use apostrophes for inner strings. --- tox.ini | 118 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/tox.ini b/tox.ini index 9c2ae387..6a93ed98 100644 --- a/tox.ini +++ b/tox.ini @@ -62,10 +62,10 @@ whitelist_externals = [mysqldb] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqldb] commands = @@ -79,10 +79,10 @@ deps = [mysqlclient] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqlclient] commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" @@ -94,10 +94,10 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector-noauto] commands = @@ -110,10 +110,10 @@ commands = {[mysql-connector]commands} [oursql] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-oursql-noauto] commands = @@ -126,10 +126,10 @@ commands = {[oursql]commands} [pymysql] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pymysql] commands = @@ -142,10 +142,10 @@ commands = {[pymysql]commands} [mariadb] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" @@ -158,10 +158,10 @@ commands = {[mariadb]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto] commands = @@ -174,10 +174,10 @@ commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] commands = {[testenv]commands} - -mysql --user=root --execute='drop database sqlobject_test;' - mysql --user=root --execute='create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1 - mysql --user=root --execute='drop database sqlobject_test;' + -mysql --user=root --execute="drop database sqlobject_test;" + mysql --user=root --execute="create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto] commands = @@ -193,7 +193,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg] @@ -209,7 +209,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql] @@ -225,7 +225,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] @@ -240,7 +240,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000] @@ -257,7 +257,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] @@ -273,7 +273,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1 tests include/tests inheritance/tests versioning/test + pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] @@ -290,7 +290,7 @@ commands = {[postgres-pypyodbc]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?debug=1 + pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite] @@ -318,7 +318,7 @@ commands = {[sqlite-memory]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - -pytest --cov=sqlobject -D sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1 + -pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite-supersqlite] @@ -336,7 +336,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D 'firebird://test:test@localhost/tmp/test.fdb?debug=1' + pytest --cov=sqlobject -D "firebird://test:test@localhost/tmp/test.fdb?debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebird-fdb] @@ -352,7 +352,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D 'firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1' + pytest --cov=sqlobject -D "firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebirdsql] @@ -398,10 +398,10 @@ commands = {[mssql-pyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-connector-w32] platform = win32 @@ -417,10 +417,10 @@ commands = {[mysql-connector-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pymysql-w32] platform = win32 @@ -436,10 +436,10 @@ commands = {[pymysql-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb-w32] platform = win32 @@ -455,10 +455,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto-w32] platform = win32 @@ -475,10 +475,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' - mysql -u root "-pPassword12!" -e 'create database sqlobject_test;' - pytest --cov=sqlobject -D mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1 - mysql -u root "-pPassword12!" -e 'drop database sqlobject_test;' + -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + mysql -u root "-pPassword12!" -e "create database sqlobject_test;" + pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto-w32] platform = win32 From ec1b75d8e4dde24154ee972ce117c01cc247b372 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 19:21:54 +0300 Subject: [PATCH 125/295] CI: Stop testing at Travis CI and AppVeyor --- .travis.yml | 140 ----------------------------------- MANIFEST.in | 2 +- appveyor.yml | 141 ------------------------------------ devscripts/BRANCH-CHECKLIST | 2 +- devscripts/branch | 2 +- docs/DeveloperGuide.rst | 13 ---- docs/News.rst | 7 ++ docs/TODO.rst | 2 +- run_with_env.cmd | 88 ---------------------- setup.py | 3 - tox.ini | 2 +- 11 files changed, 12 insertions(+), 390 deletions(-) delete mode 100644 .travis.yml delete mode 100644 appveyor.yml delete mode 100644 run_with_env.cmd diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index adcd77ac..00000000 --- a/.travis.yml +++ /dev/null @@ -1,140 +0,0 @@ -os: linux - -dist: xenial - -language: python - -python: - - "2.7" - -cache: pip - -services: - - mysql - - postgres - -addons: - postgresql: "9.4" - -matrix: - include: - - python: "2.7" - env: TESTS=py27-mysql - - python: "3.5" - env: TESTS=py34-mysql TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - - python: "3.5" - env: TESTS=py35-mysql - - python: "3.6" - env: TESTS=py36-mysql - - python: "3.7" - env: TESTS=py37-mysql - - python: "3.8" - env: TESTS=py38-mysql - - python: "3.9" - env: TESTS=py39-mysql - - python: "3.6" - env: TESTS=py36-mariadb - dist: focal - - python: "3.7" - env: TESTS=py37-mariadb - dist: focal - - python: "3.8" - env: TESTS=py38-mariadb - dist: focal - - python: "3.9" - env: TESTS=py39-mariadb - dist: focal - - python: "2.7" - env: TESTS=py27-postgres - - python: "3.5" - env: TESTS=py34-postgres TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - - python: "3.5" - env: TESTS=py35-postgres - - python: "3.6" - env: TESTS=py36-postgres - - python: "3.7" - env: TESTS=py37-postgres - - python: "3.8" - env: TESTS=py38-postgres - - python: "3.9" - env: TESTS=py39-postgres - - python: "2.7" - env: TESTS=py27-sqlite - - python: "3.5" - env: TESTS=py34-sqlite TOXPYTHON=/home/travis/virtualenv/python3.4.8/bin/python3.4 - - python: "3.5" - env: TESTS=py35-sqlite - - python: "3.6" - env: TESTS=py36-sqlite - - python: "3.7" - env: TESTS=py37-sqlite - - python: "3.8" - env: TESTS=py38-sqlite - - python: "3.9" - env: TESTS=py39-sqlite - - python: "2.7" - env: TESTS=py27-flake8 - - python: "3.8" - env: TESTS=py38-flake8 - - python: "2.7" - env: TESTS=py27-firebird - - python: "3.6" - env: TESTS=py36-firebird - - allow_failures: - - env: TESTS=py27-firebird - - env: TESTS=py36-firebird - -before_install: - # Install version-specific dependencies - - | - if [[ $TESTS = py27-* ]]; then - sudo apt-get --quiet --yes install python-egenix-mxdatetime python-mysqldb python-psycopg2 - fi - - | - if [[ $TESTS = py3*-* ]]; then - sudo apt-get --quiet --yes install python3-mysqldb python3-psycopg2 - fi - - | - if [[ $TESTS = py34-* ]]; then - # Manually install Python 3.4 to run tox under Python 3.5 and tests with Python 3.4 - curl -sSf --retry 5 -o python-3.4.tar.bz2 https://storage.googleapis.com/travis-ci-language-archives/python/binaries/ubuntu/16.04/x86_64/python-3.4.tar.bz2 - sudo tar xjf python-3.4.tar.bz2 --directory / - fi - # Install MariaDB mysql-compatible development files to compile mysql drivers - - | - if [[ $TESTS = py3[6789]-mysql ]]; then - sudo apt-get --quiet --yes install libmysqlclient-dev - elif [[ $TESTS = py3[6789]-mariadb ]]; then - sudo apt-get --quiet --yes install libmariadb-dev-compat - fi - # Install and start the firebird database server. - # We use firebird-super, so there's none of the inetd configuration - # required by firebird-classic. - # We also create a test user for the firebird test and - # create a script that can be fed into isql-fb - # to create the test database. - # Copied password initializtion from - # https://github.com/xdenser/node-firebird-libfbclient/blob/master/.travis.yml - - | - if [[ $TESTS = *firebird* ]]; then - sudo apt-get --quiet --yes install firebird2.5-super - sudo sed -i /etc/default/firebird2.5 -e 's/=no/=yes/' - sudo /etc/init.d/firebird2.5-super start && sleep 5 - sudo /bin/bash -c '(export FB_VER="2.5"; export FB_FLAVOUR="super";source /usr/share/firebird2.5-common/functions.sh; writeNewPassword masterkey)' - sudo gsec -user sysdba -pass masterkey -add test -pw test - sudo /bin/bash -c "echo \"CREATE DATABASE 'localhost:/tmp/test.fdb';\" > /var/lib/firebird/create_test_db" - sudo chmod 644 /var/lib/firebird/create_test_db - fi - -install: travis_retry pip install --upgrade "pip<19.2" "setuptools<44" "tox>=3.15" coveralls codecov ppu - -script: devscripts/tox-select-envs $TESTS - -after_success: - - cd sqlobject - - coveralls - - codecov - -before_cache: - - remove-old-files.py -o 180 ~/.cache/pip diff --git a/MANIFEST.in b/MANIFEST.in index cb6c6a70..adf1c2bd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,6 @@ global-include *.py *.rst *.txt recursive-include docs *.css *.html *.js *.gif *.png -include LICENSE MANIFEST.in .travis.yml tox.ini +include LICENSE MANIFEST.in .tox.ini include debian/* sqlobject/.coveragerc include docs/Makefile docs/genapidocs docs/rebuild recursive-exclude devscripts * diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 808f4404..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,141 +0,0 @@ -# Install SQLObject on windows and test against MS SQL server and postgres -# Heavily inspired by Oliver Grisel's appveyor-demo (https://github.com/ogrisel/python-appveyor-demo) -# and Michael Sverdlik's appveyor-utils (https://github.com/cloudify-cosmo/appveyor-utils) -version: '{branch}-{build}' - -image: Visual Studio 2019 - -cache: - - '%LOCALAPPDATA%\pip\Cache' - -# Match travis -clone_depth: 50 - -services: - - mysql - - postgresql - -environment: - MYSQL_PWD: "Password12!" - PGUSER: "postgres" - PGPASSWORD: "Password12!" - - global: - # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the - # /E:ON and /V:ON options are not enabled in the batch script intepreter - # See: http://stackoverflow.com/a/13751649/163740 - CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\run_with_env.cmd" - - matrix: - - TESTS: "py27-mysql" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: mysql - - TESTS: "py36-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: mysql - - TESTS: "py37-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: mysql - - TESTS: "py38-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - db: mysql - - TESTS: "py39-mysql" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - db: mysql - - TESTS: "py36-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: mysql - - TESTS: "py37-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: mysql - - TESTS: "py38-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - db: mysql - - TESTS: "py39-mariadb" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - db: mysql - - TESTS: "py27-postgres" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - db: postgresql - - TESTS: "py36-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - db: postgresql - - TESTS: "py37-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - db: postgresql - - TESTS: "py38-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - db: postgresql - - TESTS: "py39-postgres" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - db: postgresql - - TESTS: "py27-sqlite" - PYTHON_ARCH: "32" - PYTHON_VERSION: "2.7" - PYTHON_HOME: "C:\\Python27" - - TESTS: "py36-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.6" - PYTHON_HOME: "C:\\Python36-x64" - - TESTS: "py37-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.7" - PYTHON_HOME: "C:\\Python37-x64" - - TESTS: "py38-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.8" - PYTHON_HOME: "C:\\Python38-x64" - - TESTS: "py39-sqlite" - PYTHON_ARCH: "64" - PYTHON_VERSION: "3.9" - PYTHON_HOME: "C:\\Python39-x64" - -install: - # Ensure we use the right python version - - "SET PATH=%PYTHON_HOME%;%PYTHON_HOME%\\Scripts;C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin;C:\\Program Files\\PostgreSQL\\9.6\\bin;%PATH%" - - "SET TOXPYTHON=%PYTHON_HOME%\\python.exe" - - "python --version" - - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" - - "python -m pip install --upgrade \"pip<19.2\" \"setuptools<44\"" - - "pip install --upgrade \"tox>=3.15\" ppu" - - "pip --version" - # List ODBC drivers - - ps: Get-OdbcDriver -Platform 32-bit | Select-Object -ExpandProperty Name - - ps: Get-OdbcDriver -Platform 64-bit | Select-Object -ExpandProperty Name - -# Not a C project, so no build step -build: false - -test_script: - - "%CMD_IN_ENV% devscripts\\tox-select-envs %TESTS%" - -after_test: - - "remove-old-files.py -o 180 %LOCALAPPDATA%\\pip\\Cache" diff --git a/devscripts/BRANCH-CHECKLIST b/devscripts/BRANCH-CHECKLIST index da9c16ac..29899043 100644 --- a/devscripts/BRANCH-CHECKLIST +++ b/devscripts/BRANCH-CHECKLIST @@ -9,7 +9,7 @@ setup.cfg in the branch edit section [publish] - uncomment doc-dest for stable branch. In setup.py in the branch edit URL (remove '/devel') and download URLs. In setup.py and DeveloperGuide.rst edit - Travis CI build status image URL (change branch). Commit. + CI build status image URL (change branch). Commit. 1b. If the branching point was master the script checks out master and calls editor again; edit README.rst, __version__.py and News.rst in diff --git a/devscripts/branch b/devscripts/branch index 7c7ef731..dfcd6df1 100755 --- a/devscripts/branch +++ b/devscripts/branch @@ -42,7 +42,7 @@ micro = 0 release_level = 'trunk' serial = 0 version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && - `git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst appveyor.yml setup.py && + `git var GIT_EDITOR` README.rst sqlobject/__version__.py docs/News.rst setup.py && git commit --message="Next branch will be $major.$next_minor" README.rst sqlobject/__version__.py docs/News.rst setup.py && exec sed -i /"$major\.$minor"/"$major.$next_minor"/ ANNOUNCE.rst diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 955dc03d..262ffa2a 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -276,19 +276,6 @@ forced to write the test. That's no fun for us, to just be writing tests. So please, write tests; everything at least needs to be exercised, even if the tests are absolutely complete. -We now use Travis CI and AppVeyor to run tests. See the statuses: - -.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.com/github/sqlobject/sqlobject - -.. image:: https://ci.appveyor.com/api/projects/status/github/sqlobject/sqlobject?branch=master - :target: https://ci.appveyor.com/project/phdru/sqlobject - -To avoid triggering unnecessary test run at CI services add text `[skip ci] -`_ or -``[ci skip]`` anywhere in your commit messages for commits that don't change -code (documentation updates and such). - We use `coverage.py `_ to measures code coverage by tests and upload the result for analyzis to `Coveralls `_ and diff --git a/docs/News.rst b/docs/News.rst index afce29f1..1f5d666b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,6 +21,13 @@ Tests * Run tests with Python 3.10. +CI +-- + +* Stop testing at Travis CI. + +* Stop testing at AppVeyor. + Documentation ------------- diff --git a/docs/TODO.rst b/docs/TODO.rst index 106a5996..39dff951 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -3,7 +3,7 @@ TODO * Fix test ordering problem with Postgres. -* Fix unicode problems with pyodbc at AppVeyor. +* Fix unicode problems with pyodbc. * Resolve timeout problems with MSSQL. diff --git a/run_with_env.cmd b/run_with_env.cmd deleted file mode 100644 index 5da547c4..00000000 --- a/run_with_env.cmd +++ /dev/null @@ -1,88 +0,0 @@ -:: To build extensions for 64 bit Python 3, we need to configure environment -:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) -:: -:: To build extensions for 64 bit Python 2, we need to configure environment -:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: -:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) -:: -:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific -:: environment configurations. -:: -:: Note: this script needs to be run with the /E:ON and /V:ON flags for the -:: cmd interpreter, at least for (SDK v7.0) -:: -:: More details at: -:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows -:: http://stackoverflow.com/a/13751649/163740 -:: -:: Author: Olivier Grisel -:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ -:: -:: Notes about batch files for Python people: -:: -:: Quotes in values are literally part of the values: -:: SET FOO="bar" -:: FOO is now five characters long: " b a r " -:: If you don't want quotes, don't include them on the right-hand side. -:: -:: The CALL lines at the end of this file look redundant, but if you move them -:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y -:: case, I don't know why. -@ECHO OFF - -SET COMMAND_TO_RUN=%* -SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows -SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf - -:: Extract the major and minor versions, and allow for the minor version to be -:: more than 9. This requires the version number to have two dots in it. -SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1% -IF "%PYTHON_VERSION:~3,1%" == "." ( - SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1% -) ELSE ( - SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,2% -) - -:: Based on the Python version, determine what SDK version to use, and whether -:: to set the SDK for 64-bit. -IF %MAJOR_PYTHON_VERSION% == 2 ( - SET WINDOWS_SDK_VERSION="v7.0" - SET SET_SDK_64=Y -) ELSE ( - IF %MAJOR_PYTHON_VERSION% == 3 ( - SET WINDOWS_SDK_VERSION="v7.1" - IF %MINOR_PYTHON_VERSION% LEQ 4 ( - SET SET_SDK_64=Y - ) ELSE ( - SET SET_SDK_64=N - IF EXIST "%WIN_WDK%" ( - :: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/ - REN "%WIN_WDK%" 0wdf - ) - ) - ) ELSE ( - ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" - EXIT 1 - ) -) - -IF %PYTHON_ARCH% == 64 ( - IF %SET_SDK_64% == Y ( - ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture - SET DISTUTILS_USE_SDK=1 - SET MSSdk=1 - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% - "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 - ) ELSE ( - ECHO Using default MSVC build environment for 64 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 - ) -) ELSE ( - ECHO Using default MSVC build environment for 32 bit architecture - ECHO Executing: %COMMAND_TO_RUN% - call %COMMAND_TO_RUN% || EXIT 1 -) diff --git a/setup.py b/setup.py index cdfcb9aa..c65eb313 100755 --- a/setup.py +++ b/setup.py @@ -41,9 +41,6 @@ For development see the projects at `SourceForge `_ and `GitHub `_. - -.. image:: https://api.travis-ci.com/sqlobject/sqlobject.svg?branch=master - :target: https://travis-ci.com/github/sqlobject/sqlobject """, long_description_content_type="text/x-rst", classifiers=[ diff --git a/tox.ini b/tox.ini index 6a93ed98..250b03c6 100644 --- a/tox.ini +++ b/tox.ini @@ -43,7 +43,7 @@ deps = supersqlite: supersqlite firebird-fdb: fdb firebirdsql: firebirdsql -passenv = CI TRAVIS TRAVIS_* APPVEYOR DISTUTILS_USE_SDK MSSdk INCLUDE LIB PGPASSWORD WINDIR +passenv = CI setenv = VIRTUALENV_PIP = 19.1.1 # Don't fail or warn on uninstalled commands From d2921ea11e634169b3cbeba3707fc6bd5f048d07 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 20:33:36 +0300 Subject: [PATCH 126/295] Tests(tox): Stop collecting test coverage --- MANIFEST.in | 2 +- .../requirements/requirements_tests.txt | 1 - docs/DeveloperGuide.rst | 11 ---- sqlobject/.coveragerc | 10 --- sqlobject/.gitignore | 2 - tox.ini | 66 +++++++++---------- 6 files changed, 34 insertions(+), 58 deletions(-) delete mode 100644 sqlobject/.coveragerc delete mode 100644 sqlobject/.gitignore diff --git a/MANIFEST.in b/MANIFEST.in index adf1c2bd..c3330428 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,7 @@ global-include *.py *.rst *.txt recursive-include docs *.css *.html *.js *.gif *.png include LICENSE MANIFEST.in .tox.ini -include debian/* sqlobject/.coveragerc +include debian/* include docs/Makefile docs/genapidocs docs/rebuild recursive-exclude devscripts * recursive-exclude docs/_build * diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index 9d647535..73674957 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -2,4 +2,3 @@ pytest < 5.0; python_version == '2.7' or python_version == '3.4' pytest; python_version >= '3.5' -pytest-cov diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 262ffa2a..3b9a0bb2 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -276,17 +276,6 @@ forced to write the test. That's no fun for us, to just be writing tests. So please, write tests; everything at least needs to be exercised, even if the tests are absolutely complete. -We use `coverage.py `_ -to measures code coverage by tests and upload the result for analyzis to -`Coveralls `_ and -`Codecov `_: - -.. image:: https://coveralls.io/repos/github/sqlobject/sqlobject/badge.svg?branch=master - :target: https://coveralls.io/github/sqlobject/sqlobject?branch=master - -.. image:: https://codecov.io/gh/sqlobject/sqlobject/branch/master/graph/badge.svg - :target: https://codecov.io/gh/sqlobject/sqlobject - Documentation ============= diff --git a/sqlobject/.coveragerc b/sqlobject/.coveragerc deleted file mode 100644 index b4c9dee6..00000000 --- a/sqlobject/.coveragerc +++ /dev/null @@ -1,10 +0,0 @@ -[run] -omit = - firebird/*.py - maxdb/*.py - mssql/*.py - sybase/*.py - tests/test_boundattributes.py - tests/test_paste.py - util/threadinglocal.py - wsgi_middleware.py diff --git a/sqlobject/.gitignore b/sqlobject/.gitignore deleted file mode 100644 index b53725ca..00000000 --- a/sqlobject/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/.coverage -/coverage.xml diff --git a/tox.ini b/tox.ini index 250b03c6..5acb951c 100644 --- a/tox.ini +++ b/tox.ini @@ -64,7 +64,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqldb] @@ -81,7 +81,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysqlclient] @@ -96,7 +96,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector-noauto] @@ -112,7 +112,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-oursql-noauto] @@ -128,7 +128,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pymysql] @@ -144,7 +144,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb] @@ -160,7 +160,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto] @@ -176,7 +176,7 @@ commands = {[testenv]commands} -mysql --user=root --execute="drop database sqlobject_test;" mysql --user=root --execute="create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + pytest -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto] @@ -193,7 +193,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg] @@ -209,7 +209,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql] @@ -225,7 +225,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] @@ -240,7 +240,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000] @@ -257,7 +257,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] @@ -273,7 +273,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] @@ -290,7 +290,7 @@ commands = {[postgres-pypyodbc]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?debug=1" + pytest -D "sqlite:///tmp/sqlobject_test.sqdb?debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite] @@ -304,7 +304,7 @@ commands = {[sqlite]commands} [sqlite-memory] commands = {[testenv]commands} - pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 + pytest -D sqlite:/:memory:?debug=1 [testenv:py27-sqlite-memory] commands = @@ -318,7 +318,7 @@ commands = {[sqlite-memory]commands} commands = {[testenv]commands} -rm -f /tmp/sqlobject_test.sqdb - -pytest --cov=sqlobject -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" + -pytest -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" rm -f /tmp/sqlobject_test.sqdb [testenv:py27-sqlite-supersqlite] @@ -336,7 +336,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D "firebird://test:test@localhost/tmp/test.fdb?debug=1" + pytest -D "firebird://test:test@localhost/tmp/test.fdb?debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebird-fdb] @@ -352,7 +352,7 @@ commands = {[testenv]commands} sudo rm -f /tmp/test.fdb isql-fb -u test -p test -i /var/lib/firebird/create_test_db - pytest --cov=sqlobject -D "firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1" + pytest -D "firebird://test:test@localhost:3050/tmp/test.fdb?driver=firebirdsql&charset=utf8&debug=1" sudo rm -f /tmp/test.fdb [testenv:py27-firebirdsql] @@ -381,7 +381,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "CREATE DATABASE sqlobject_test" - pytest --cov=sqlobject -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&timeout=30&debug=1" + pytest -D "mssql://sa:Password12!@localhost\SQL2014/sqlobject_test?driver=pyodbc&odbcdrv=SQL%20Server&timeout=30&debug=1" sqlcmd -U sa -P "Password12!" -S .\SQL2014 -Q "DROP DATABASE sqlobject_test" [testenv:py27-mssql-pyodbc-noauto-w32] @@ -400,7 +400,7 @@ commands = {[testenv]commands} -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-connector-w32] @@ -419,7 +419,7 @@ commands = {[testenv]commands} -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pymysql-w32] @@ -438,7 +438,7 @@ commands = {[testenv]commands} -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb-w32] @@ -457,7 +457,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto-w32] @@ -477,7 +477,7 @@ commands = {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest --cov=sqlobject -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto-w32] @@ -496,7 +496,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] @@ -515,7 +515,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - -pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + -pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] @@ -534,7 +534,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] @@ -552,7 +552,7 @@ commands = {[testenv]commands} -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] @@ -572,7 +572,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] @@ -592,7 +592,7 @@ commands = {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -dropdb --username=postgres --no-password sqlobject_test createdb --username=postgres --no-password sqlobject_test - pytest --cov=sqlobject -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test dropdb --username=postgres --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] @@ -609,7 +609,7 @@ commands = {[postgres-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - pytest --cov=sqlobject -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 + pytest -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 cmd /c "del C:\projects\sqlobject\sqlobject_test.sqdb" [testenv:py27-sqlite-w32] @@ -626,7 +626,7 @@ commands = {[sqlite-w32]commands} platform = win32 commands = {[testenv]commands} - pytest --cov=sqlobject -D sqlite:/:memory:?debug=1 + pytest -D sqlite:/:memory:?debug=1 [testenv:py27-sqlite-memory-w32] platform = win32 From 4cb3e4e694dff3d582bce785a2e62489055479fa Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 19:29:02 +0300 Subject: [PATCH 127/295] CI: GitHub Actions --- .github/workflows/run-tests.yaml | 55 ++++++++++++++++++++++++++++++++ docs/DeveloperGuide.rst | 6 ++++ docs/News.rst | 2 ++ setup.py | 5 ++- 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/run-tests.yaml diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml new file mode 100644 index 00000000..d55cb334 --- /dev/null +++ b/.github/workflows/run-tests.yaml @@ -0,0 +1,55 @@ +name: Run tests + +on: [push, pull_request] + +jobs: + run-tests: + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + python-version: ["2.7"] + include: + - os: ubuntu-latest + os-name: Linux + pip-cache-path: ~/.cache/pip + + name: Python ${{ matrix.python-version }} @ ${{ matrix.os-name }} + runs-on: ${{ matrix.os }} + + steps: + + # Setup Python/pip + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Cache pip + uses: actions/cache@v2 + with: + path: ${{ matrix.pip-cache-path }} + key: ${{ runner.os }}-pip + + # Setup tox + - name: Install dependencies + run: | + python --version + python -m pip install --upgrade "pip<21.0" "setuptools<45" wheel + pip --version + pip install --upgrade virtualenv tox + - name: Set TOXENV + run: | + import os, sys + pyver = '%d%d' % tuple(sys.version_info[:2]) + toxenv = 'py%s-sqlite' % pyver + if os.name == 'posix': + toxenv += ',py%s-flake8' % pyver + with open(os.environ['GITHUB_ENV'], 'a') as f: + f.write('TOXENV=' + toxenv + '\n') + shell: python + + - name: Run tox + run: | + python -c "import os; print(os.environ['TOXENV'])" + tox diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 3b9a0bb2..2cd0f8f6 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -276,6 +276,12 @@ forced to write the test. That's no fun for us, to just be writing tests. So please, write tests; everything at least needs to be exercised, even if the tests are absolutely complete. +We now use `Github Actions `_ +to run tests. + +.. image:: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml/badge.svg?branch=github-actions + :target: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml + Documentation ============= diff --git a/docs/News.rst b/docs/News.rst index 1f5d666b..67090893 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -24,6 +24,8 @@ Tests CI -- +* GitHub Actions. + * Stop testing at Travis CI. * Stop testing at AppVeyor. diff --git a/setup.py b/setup.py index c65eb313..57ea5394 100755 --- a/setup.py +++ b/setup.py @@ -41,7 +41,10 @@ For development see the projects at `SourceForge `_ and `GitHub `_. -""", + +.. image:: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml/badge.svg?branch=github-actions + :target: https://github.com/sqlobject/sqlobject/actions/workflows/run-tests.yaml +""", # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ "Development Status :: 5 - Production/Stable", From 1c5ed87d699191c13a5754637f138c9db5656981 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 20:23:26 +0300 Subject: [PATCH 128/295] CI(GHActions): Use `devscripts/tox-select-envs` --- .github/workflows/run-tests.yaml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index d55cb334..df7de5ca 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -38,18 +38,15 @@ jobs: python -m pip install --upgrade "pip<21.0" "setuptools<45" wheel pip --version pip install --upgrade virtualenv tox - - name: Set TOXENV + - name: Set PYVER run: | import os, sys pyver = '%d%d' % tuple(sys.version_info[:2]) - toxenv = 'py%s-sqlite' % pyver - if os.name == 'posix': - toxenv += ',py%s-flake8' % pyver with open(os.environ['GITHUB_ENV'], 'a') as f: - f.write('TOXENV=' + toxenv + '\n') + f.write('PYVER=' + pyver + '\n') shell: python - name: Run tox run: | - python -c "import os; print(os.environ['TOXENV'])" - tox + python -c "import os; print(os.environ['PYVER'])" + devscripts/tox-select-envs $PYVER-sqlite From 6843aa173302384aebd69f7187b0b23551762927 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 27 Sep 2021 20:40:12 +0300 Subject: [PATCH 129/295] CI(GHActions): Run tests on w64 --- .github/workflows/run-tests.yaml | 13 ++++++++++--- tox.ini | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index df7de5ca..ff384fd5 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -8,12 +8,15 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest] + os: [ubuntu-latest, windows-latest] python-version: ["2.7"] include: - os: ubuntu-latest os-name: Linux pip-cache-path: ~/.cache/pip + - os: windows-latest + os-name: w32 + pip-cache-path: ~\AppData\Local\pip\Cache name: Python ${{ matrix.python-version }} @ ${{ matrix.os-name }} runs-on: ${{ matrix.os }} @@ -46,7 +49,11 @@ jobs: f.write('PYVER=' + pyver + '\n') shell: python - - name: Run tox + - name: Run tox @ Linux run: | - python -c "import os; print(os.environ['PYVER'])" devscripts/tox-select-envs $PYVER-sqlite + if: ${{ runner.os == 'Linux' }} + - name: Run tox @ w64 + run: | + devscripts\tox-select-envs.cmd %PYVER%-sqlite + if: ${{ runner.os == 'Windows' }} diff --git a/tox.ini b/tox.ini index 5acb951c..37ddb217 100644 --- a/tox.ini +++ b/tox.ini @@ -609,8 +609,8 @@ commands = {[postgres-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - pytest -D sqlite:/C:/projects/sqlobject/sqlobject_test.sqdb?debug=1 - cmd /c "del C:\projects\sqlobject\sqlobject_test.sqdb" + pytest -D sqlite:/{env:TEMP}/sqlobject_test.sqdb?debug=1 + cmd /c "del {env:TEMP}\sqlobject_test.sqdb" [testenv:py27-sqlite-w32] platform = win32 From 804dcee1a00dd168ff7fe7bb559b1c8b6f68e915 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:00:52 +0300 Subject: [PATCH 130/295] CI(GHActions): Run `flake8` tests --- .github/workflows/run-tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index ff384fd5..307794b6 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -52,6 +52,7 @@ jobs: - name: Run tox @ Linux run: | devscripts/tox-select-envs $PYVER-sqlite + devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - name: Run tox @ w64 run: | From 0d8ba319dd141f617b3663ca353d77f83d834da5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:10:44 +0300 Subject: [PATCH 131/295] CI(GHActions): Run tests with PostgreSQL --- .github/workflows/run-tests.yaml | 14 +++++ tox.ini | 97 ++++++++++++++++---------------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 307794b6..0e5d7651 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -23,6 +23,17 @@ jobs: steps: + # Setup PostgreSQL + - uses: ankane/setup-postgres@v1 + - name: Setup Postgres user + run: | + sudo -u postgres psql --command="ALTER USER runner CREATEDB ENCRYPTED PASSWORD 'test'" + if: ${{ runner.os == 'Linux' }} + - name: Setup Postgres user + run: | + psql --command="CREATE USER runner CREATEDB ENCRYPTED PASSWORD 'test'" + if: ${{ runner.os == 'Windows' }} + # Setup Python/pip - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -47,14 +58,17 @@ jobs: pyver = '%d%d' % tuple(sys.version_info[:2]) with open(os.environ['GITHUB_ENV'], 'a') as f: f.write('PYVER=' + pyver + '\n') + f.write('PGPASSWORD=test\n') shell: python - name: Run tox @ Linux run: | + devscripts/tox-select-envs $PYVER-postgres devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - name: Run tox @ w64 run: | + devscripts\tox-select-envs.cmd %PYVER%-postgres devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} diff --git a/tox.ini b/tox.ini index 37ddb217..a5a8ca28 100644 --- a/tox.ini +++ b/tox.ini @@ -46,6 +46,7 @@ deps = passenv = CI setenv = VIRTUALENV_PIP = 19.1.1 + PGPASSWORD = test # Don't fail or warn on uninstalled commands platform = linux whitelist_externals = @@ -191,10 +192,10 @@ commands = {[mysql-pypyodbc]commands} [psycopg] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg] commands = @@ -207,10 +208,10 @@ commands = {[psycopg]commands} [pygresql] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql] commands = @@ -223,10 +224,10 @@ commands = {[pygresql]commands} [pypostgresql] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" @@ -238,10 +239,10 @@ commands = {[pypostgresql]commands} [pg8000] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000] commands = @@ -255,10 +256,10 @@ commands = {[pg8000]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] commands = @@ -271,10 +272,10 @@ commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] commands = @@ -494,10 +495,10 @@ commands = {[mysql-pypyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] platform = win32 @@ -513,10 +514,10 @@ commands = {[psycopg-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - -pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] platform = win32 @@ -532,10 +533,10 @@ commands = {[pygresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] platform = win32 @@ -550,10 +551,10 @@ commands = {[pypostgresql-w32]commands} platform = win32 commands = {[testenv]commands} - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] platform = win32 @@ -570,10 +571,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] platform = win32 @@ -590,10 +591,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -dropdb --username=postgres --no-password sqlobject_test - createdb --username=postgres --no-password sqlobject_test - pytest -D "postgres://postgres:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test - dropdb --username=postgres --no-password sqlobject_test + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] platform = win32 From 17bf01d0e15fb6bbb95a5777cac7c2f6236b4031 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:24:26 +0300 Subject: [PATCH 132/295] Tests(tox): Run Postgres tests in default order --- docs/TODO.rst | 2 -- tox.ini | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/docs/TODO.rst b/docs/TODO.rst index 39dff951..0d2c9423 100644 --- a/docs/TODO.rst +++ b/docs/TODO.rst @@ -1,8 +1,6 @@ TODO ---- -* Fix test ordering problem with Postgres. - * Fix unicode problems with pyodbc. * Resolve timeout problems with MSSQL. diff --git a/tox.ini b/tox.ini index a5a8ca28..89b67537 100644 --- a/tox.ini +++ b/tox.ini @@ -194,7 +194,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg] @@ -210,7 +210,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql] @@ -226,7 +226,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql] @@ -241,7 +241,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000] @@ -258,7 +258,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto] @@ -274,7 +274,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto] @@ -497,7 +497,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-psycopg-w32] @@ -516,7 +516,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pygresql-noauto-w32] @@ -535,7 +535,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-w32] @@ -553,7 +553,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pg8000-w32] @@ -573,7 +573,7 @@ commands = {envpython} -c "import pyodbc; print(pyodbc.drivers())" -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pyodbc-noauto-w32] @@ -593,7 +593,7 @@ commands = {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" tests include/tests inheritance/tests versioning/test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=PostgreSQL%20ANSI%28x64%29&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypyodbc-noauto-w32] From f1a3d33bba66bb888e9138df23b49264ea1f1268 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 28 Sep 2021 20:26:21 +0300 Subject: [PATCH 133/295] Tests(tox): Skip some tests py27-pg8000-w32 reports authentication error `InterfaceError: Authentication method 10 not recognized by pg8000.` pg8000 py37+ under Linux reports errors with closed sockets. pypostgresql fails on some tests. --- tox.ini | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tox.ini b/tox.ini index 89b67537..f9992e6b 100644 --- a/tox.ini +++ b/tox.ini @@ -229,11 +229,11 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql] +[testenv:py27-postgres-pypostgresql-noauto] commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -249,7 +249,10 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000] +[testenv:py3{4,5,6}-postgres-pg8000] +commands = {[pg8000]commands} + +[testenv:py3{7,8,9,10}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -538,12 +541,12 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql-w32] +[testenv:py27-postgres-pypostgresql-noauto-w32] platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-w32] +[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -556,7 +559,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pg8000-w32] +[testenv:py27-postgres-pg8000-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base From 988e73e6aa311920dda0bb583b4778ba49991540 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 26 Feb 2022 03:54:38 +0300 Subject: [PATCH 134/295] CI(GHActions): Run tests under Python 3.5 --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 0e5d7651..a2eacd03 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7"] + python-version: ["2.7", "3.5"] include: - os: ubuntu-latest os-name: Linux From 1e4019e1c117b359d6d39823468c48da14df096d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Apr 2022 17:09:56 +0300 Subject: [PATCH 135/295] Tests(tox): Fix `pymysql` versions Python 3.5 requires `pymysql` < 1.0. --- devscripts/requirements/requirements_pymysql.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devscripts/requirements/requirements_pymysql.txt b/devscripts/requirements/requirements_pymysql.txt index 47ca8d09..b8c7bc6a 100644 --- a/devscripts/requirements/requirements_pymysql.txt +++ b/devscripts/requirements/requirements_pymysql.txt @@ -1,3 +1,3 @@ -pymysql < 1.0; python_version == '2.7' +pymysql < 1.0; python_version == '2.7' or python_version == '3.5' pymysql < 0.10.0; python_version == '3.4' -pymysql; python_version >= '3.5' +pymysql; python_version >= '3.6' From b0299a54f5cd611e1f8a9d1ddc214508f79504e9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Apr 2022 18:07:25 +0300 Subject: [PATCH 136/295] Fix(MySQL): Fix encoding --- sqlobject/mysql/mysqlconnection.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 95d6b58e..ebc5686f 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -397,6 +397,9 @@ def columnsFromSchema(self, tableName, soClass): # (SQLObject expected '') kw['notNone'] = (nullAllowed.upper() != 'YES' and True or False) + if not PY2 and isinstance(t, bytes): + t = t.decode('ascii') + if default and t.startswith('int'): kw['default'] = int(default) elif default and t.startswith('float'): @@ -413,6 +416,8 @@ def columnsFromSchema(self, tableName, soClass): return results def guessClass(self, t): + if not PY2 and isinstance(t, bytes): + t = t.decode('ascii') if t.startswith('int'): return col.IntCol, {} elif t.startswith('enum'): From 6259596b1095a24daf5ba6eaeb36253e17661597 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Apr 2022 21:21:21 +0300 Subject: [PATCH 137/295] Tests(tox): Enable tests for `mysql-connector` --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index f9992e6b..2dca2f16 100644 --- a/tox.ini +++ b/tox.ini @@ -100,12 +100,12 @@ commands = pytest -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=root --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector-noauto] +[testenv:py27-mysql-connector] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-noauto] +[testenv:py3{4,5,6,7,8,9,10}-mysql-connector] commands = {[mysql-connector]commands} [oursql] From c38bed3e3ef61b7d30a250146db6515a51fc7f01 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 19 Apr 2022 17:42:40 +0300 Subject: [PATCH 138/295] Fix(MySQL): Convert bytes to unicode Convert bytes to unicode for `mysql.connector` under Python 3. --- sqlobject/mysql/mysqlconnection.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index ebc5686f..e1d74c84 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,5 +1,6 @@ from sqlobject import col, dberrors from sqlobject.compat import PY2 +from sqlobject.converters import registerConverter, StringLikeConverter from sqlobject.dbconnection import DBAPI @@ -101,12 +102,14 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): else: raise ImportError( 'Cannot find a MySQL driver, tried %s' % drivers) + self.host = host self.port = port or 3306 self.db = db self.user = user self.password = password self.kw = {} + for key in ("unix_socket", "init_command", "read_default_file", "read_default_group", "conv"): if key in kw: @@ -151,6 +154,9 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): elif driver == 'mariadb': self.kw.pop("charset", None) + elif driver == 'connector': + registerConverter(bytes, ConnectorBytesConverter) + global mysql_Bin if not PY2 and mysql_Bin is None: mysql_Bin = self.module.Binary @@ -533,3 +539,10 @@ def can_use_json_funcs(self): can_use_json_funcs = (server_version >= (5, 7, 0)) self._can_use_json_funcs = can_use_json_funcs return can_use_json_funcs + + +def ConnectorBytesConverter(value, db): + assert db == 'mysql' + if not PY2: + value = value.decode('latin1') + return StringLikeConverter(value, db) From b815441e42211f13586088c502831cabb2fd44b7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 19 Apr 2022 18:12:59 +0300 Subject: [PATCH 139/295] CI(GHActions): MySQL --- .github/workflows/run-tests.yaml | 5 ++ tox.ini | 104 +++++++++++++++---------------- 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a2eacd03..a00242e3 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -23,6 +23,9 @@ jobs: steps: + # Setup MySQL + - uses: ankane/setup-mysql@v1 + # Setup PostgreSQL - uses: ankane/setup-postgres@v1 - name: Setup Postgres user @@ -63,12 +66,14 @@ jobs: - name: Run tox @ Linux run: | + devscripts/tox-select-envs $PYVER-mysql devscripts/tox-select-envs $PYVER-postgres devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - name: Run tox @ w64 run: | + devscripts\tox-select-envs.cmd %PYVER%-mysql devscripts\tox-select-envs.cmd %PYVER%-postgres devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} diff --git a/tox.ini b/tox.ini index 2dca2f16..eecaa8fb 100644 --- a/tox.ini +++ b/tox.ini @@ -63,10 +63,10 @@ whitelist_externals = [mysqldb] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysqldb] commands = @@ -80,10 +80,10 @@ deps = [mysqlclient] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysqlclient] commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" @@ -95,10 +95,10 @@ commands = {[mysqlclient]commands} [mysql-connector] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector] commands = @@ -111,10 +111,10 @@ commands = {[mysql-connector]commands} [oursql] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-oursql-noauto] commands = @@ -127,10 +127,10 @@ commands = {[oursql]commands} [pymysql] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-pymysql] commands = @@ -143,10 +143,10 @@ commands = {[pymysql]commands} [mariadb] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb] commands = {envpython} -c "print('mariadb requires Python 3.6+')" @@ -159,10 +159,10 @@ commands = {[mariadb]commands} commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto] commands = @@ -175,10 +175,10 @@ commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] commands = {[testenv]commands} - -mysql --user=root --execute="drop database sqlobject_test;" - mysql --user=root --execute="create database sqlobject_test;" - pytest -D "mysql://root:@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" - mysql --user=root --execute="drop database sqlobject_test;" + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto] commands = @@ -402,10 +402,10 @@ commands = {[mssql-pyodbc-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-connector-w32] platform = win32 @@ -421,10 +421,10 @@ commands = {[mysql-connector-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=pymysql&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-pymysql-w32] platform = win32 @@ -440,10 +440,10 @@ commands = {[pymysql-w32]commands} platform = win32 commands = {[testenv]commands} - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py{27,34,35}-mariadb-w32] platform = win32 @@ -459,10 +459,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pyodbc; print(pyodbc.drivers())" - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=pyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-pyodbc-noauto-w32] platform = win32 @@ -479,10 +479,10 @@ platform = win32 commands = {[testenv]commands} {envpython} -c "import pypyodbc; print(pypyodbc.drivers())" - -mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" - mysql -u root "-pPassword12!" -e "create database sqlobject_test;" - pytest -D "mysql://root:Password12!@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" - mysql -u root "-pPassword12!" -e "drop database sqlobject_test;" + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=pypyodbc&odbcdrv=MySQL%20ODBC%205.3%20ANSI%20Driver&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" [testenv:py27-mysql-pypyodbc-noauto-w32] platform = win32 From 18dbbc65877e2adb451db69aec207d542f90733f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Sep 2022 20:08:23 +0300 Subject: [PATCH 140/295] Fix(mysql-connector): Fix dbName under Python 2 --- sqlobject/mysql/mysqlconnection.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index e1d74c84..0a670f78 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -542,7 +542,8 @@ def can_use_json_funcs(self): def ConnectorBytesConverter(value, db): - assert db == 'mysql' if not PY2: + # For PY2 this converter is called also for SQLite + assert db == 'mysql' value = value.decode('latin1') return StringLikeConverter(value, db) From 04da46e0d3773b80fa2db2021956b53c95574da8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Sep 2022 20:29:20 +0300 Subject: [PATCH 141/295] Fix(tox): Skip `py27-mysqldb` Old `MySQLdb` for Python 2.7 requires old MySQL, it cannot be compiled with MySQL 8+. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index eecaa8fb..37c39a6a 100644 --- a/tox.ini +++ b/tox.ini @@ -68,7 +68,7 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysqldb] +[testenv:py27-mysqldb-noauto] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} From 4261d5a101b91697e5fea93c88223bc48f24ad40 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Sep 2022 22:29:50 +0300 Subject: [PATCH 142/295] Fix(tox): Make `mysql-connector` connect as the local user --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 37c39a6a..7b3ee574 100644 --- a/tox.ini +++ b/tox.ini @@ -97,7 +97,7 @@ commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" mysql --execute="create database sqlobject_test;" - pytest -D "mysql://localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" + pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" [testenv:py27-mysql-connector] From 30ba31d4d49c212124d4994abc4b237cc2e57100 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 16:33:04 +0300 Subject: [PATCH 143/295] Fix(mysql-connector): Convert bytearrays --- sqlobject/mysql/mysqlconnection.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 0a670f78..c4a72a6e 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -480,10 +480,10 @@ def guessClass(self, t): return col.Col, {} def listTables(self): - return [v[0] for v in self.queryAll("SHOW TABLES")] + return _decodeBytearrays(self.queryAll("SHOW TABLES")) def listDatabases(self): - return [v[0] for v in self.queryAll("SHOW DATABASES")] + return _decodeBytearrays(self.queryAll("SHOW DATABASES")) def _createOrDropDatabase(self, op="CREATE"): self.query('%s DATABASE %s' % (op, self.db)) @@ -547,3 +547,11 @@ def ConnectorBytesConverter(value, db): assert db == 'mysql' value = value.decode('latin1') return StringLikeConverter(value, db) + + +def _decodeBytearrays(v_list): + if not v_list: + return [] + if not PY2 and isinstance(v_list[0][0], bytearray): + return [v[0].decode('ascii') for v in v_list] + return [v[0] for v in v_list] From b79929b1abfa4ccb96be0838adb5c6b7f7b5c88b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Sep 2022 23:27:28 +0300 Subject: [PATCH 144/295] Feat(GHActions): Python 3.6-3.10 --- .github/workflows/run-tests.yaml | 2 +- devscripts/requirements/requirements_tests.txt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a00242e3..fe4b24d9 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -9,7 +9,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] include: - os: ubuntu-latest os-name: Linux diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index 73674957..d6a51173 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -1,4 +1,8 @@ -r requirements.txt pytest < 5.0; python_version == '2.7' or python_version == '3.4' -pytest; python_version >= '3.5' + +# Pytest 7.0 introduced a major bug; see +# https://github.com/pytest-dev/pytest/issues/9620 + +pytest < 7.0; python_version >= '3.5' From 012da8ffa26f4b8419f19be8d00fdf544297725e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 17 Sep 2022 22:55:44 +0300 Subject: [PATCH 145/295] CI(GHActions): Fix versions for newer Pythons --- .github/workflows/run-tests.yaml | 2 +- tox.ini | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index fe4b24d9..6bc5a27b 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -52,7 +52,7 @@ jobs: - name: Install dependencies run: | python --version - python -m pip install --upgrade "pip<21.0" "setuptools<45" wheel + python -m pip install --upgrade pip setuptools wheel pip --version pip install --upgrade virtualenv tox - name: Set PYVER diff --git a/tox.ini b/tox.ini index 7b3ee574..60e6814c 100644 --- a/tox.ini +++ b/tox.ini @@ -19,8 +19,6 @@ commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" deps = - py27,py34: pip < 19.2 - py27,py34: setuptools < 44 -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 py34: zope.datetime < 4.3 @@ -45,7 +43,6 @@ deps = firebirdsql: firebirdsql passenv = CI setenv = - VIRTUALENV_PIP = 19.1.1 PGPASSWORD = test # Don't fail or warn on uninstalled commands platform = linux From abd02481adbab503e0787c0d32f5c86248cce543 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 18 Sep 2022 20:28:28 +0300 Subject: [PATCH 146/295] CI(GHActions): Show `tox`/`pytest` version --- .github/workflows/run-tests.yaml | 3 +++ tox.ini | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 6bc5a27b..edf0a592 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -64,6 +64,9 @@ jobs: f.write('PGPASSWORD=test\n') shell: python + - name: tox version + run: | + tox --version - name: Run tox @ Linux run: | devscripts/tox-select-envs $PYVER-mysql diff --git a/tox.ini b/tox.ini index 60e6814c..828cc915 100644 --- a/tox.ini +++ b/tox.ini @@ -18,6 +18,7 @@ basepython = commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" + {envpython} -m pytest --version deps = -rdevscripts/requirements/requirements_tests.txt py34: pendulum < 2.1 @@ -370,6 +371,7 @@ commands = {[firebirdsql]commands} changedir = ./ deps = flake8 + pytest < 7.0 commands = {[testenv]commands} flake8 . From 1a0168e0b4c891c51b6255e1295111409bf98fc5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 20 Sep 2022 19:40:58 +0300 Subject: [PATCH 147/295] Release 3.10.0 --- ANNOUNCE.rst | 57 +++++++++++++++++++++++++++++---------- README.rst | 4 +-- devscripts/build-all-docs | 2 +- docs/News.rst | 9 +++---- sqlobject/__version__.py | 6 ++--- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5f6c2aa6..cfec8c15 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,54 @@ Hello! -I'm pleased to announce version 3.9.2a1, the first alpha of the upcoming -release of branch 3.9 of SQLObject. +I'm pleased to announce version 3.10.0, the first release of branch +3.10 of SQLObject. -I'm pleased to announce version 3.9.2a2, the second alpha of the upcoming -release of branch 3.9 of SQLObject. -I'm pleased to announce version 3.9.2b1, the first beta of the upcoming -release of branch 3.9 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.9.2rc1, the first release candidate -of the upcoming release of branch 3.9 of SQLObject. +Contributors for this release are +James Hudson, Juergen Gmach, Hugo van Kemenade. +Many thanks! -I'm pleased to announce version 3.9.2, the first bugfix release of branch -3.9 of SQLObject. +Features +-------- +* Allow connections in ``ConnectionHub`` to be strings. + This allows to open a new connection in every thread. -What's new in SQLObject -======================= +* Add compatibility with ``Pendulum``. + +Tests +----- + +* Run tests with Python 3.10. + +CI +-- + +* GitHub Actions. + +* Stop testing at Travis CI. + +* Stop testing at AppVeyor. + +Documentation +------------- + +* DevGuide: source code must be pure ASCII. + +* DevGuide: ``reStructuredText`` format for docstrings is recommended. + +* DevGuide: de-facto good commit message format is required: + subject/body/trailers. + +* DevGuide: ``conventional commit`` format for commit message subject lines + is recommended. + +* DevGuide: ``Markdown`` format for commit message bodies is recommended. -Contributors for this release are +* DevGuide: commit messages must be pure ASCII. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +81,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.9.2a0.dev20210227/ +https://pypi.org/project/SQLObject/3.10.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 2152854e..92b1dd71 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.9.2a0 -================= +SQLObject 3.10.0 +================ Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8cb4ba16..8942edb7 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.9.1 && +build_docs 3.10.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 67090893..12c0a786 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.0 +================ + +Released 2022 Sep 20. Features -------- @@ -47,9 +49,6 @@ Documentation * DevGuide: commit messages must be pure ASCII. -* Change Travis CI URLs: - CI relocated from travis-ci.org to travis-ci.com. - SQLObject 3.9.1 =============== diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index cb43f08a..e01c255e 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.9.1' +version = '3.10.0' major = 3 -minor = 9 -micro = 1 +minor = 10 +micro = 0 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 66fe5d47cd4277a1aee2e1876c4fe535c3bf11ff Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 20 Sep 2022 20:19:26 +0300 Subject: [PATCH 148/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 57 +++++++++++++-------------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 45 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index cfec8c15..c9b634bd 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,54 +1,25 @@ Hello! -I'm pleased to announce version 3.10.0, the first release of branch -3.10 of SQLObject. - - -What's new in SQLObject -======================= - -Contributors for this release are -James Hudson, Juergen Gmach, Hugo van Kemenade. -Many thanks! - -Features --------- - -* Allow connections in ``ConnectionHub`` to be strings. - This allows to open a new connection in every thread. - -* Add compatibility with ``Pendulum``. +I'm pleased to announce version 3.10.1a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. -Tests ------ +I'm pleased to announce version 3.10.1a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. -* Run tests with Python 3.10. +I'm pleased to announce version 3.10.1b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. -CI --- +I'm pleased to announce version 3.10.1rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. -* GitHub Actions. - -* Stop testing at Travis CI. - -* Stop testing at AppVeyor. - -Documentation -------------- - -* DevGuide: source code must be pure ASCII. - -* DevGuide: ``reStructuredText`` format for docstrings is recommended. - -* DevGuide: de-facto good commit message format is required: - subject/body/trailers. +I'm pleased to announce version 3.10.1, the first bugfix release of branch +3.10 of SQLObject. -* DevGuide: ``conventional commit`` format for commit message subject lines - is recommended. -* DevGuide: ``Markdown`` format for commit message bodies is recommended. +What's new in SQLObject +======================= -* DevGuide: commit messages must be pure ASCII. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -81,7 +52,7 @@ Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/3.10.0 +https://pypi.org/project/SQLObject/3.10.1a0.dev20221020/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 92b1dd71..c9102052 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.0 -================ +SQLObject 3.10.1a0 +================== Thanks for looking at SQLObject. SQLObject is an object-relational mapper, i.e., a library that will wrap your database tables in Python diff --git a/docs/News.rst b/docs/News.rst index 12c0a786..42f56160 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.0 ================ From fb5a71609a3ace1441555cb687539bc1c0f147eb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 21 Sep 2022 02:39:07 +0300 Subject: [PATCH 149/295] CI(GHActions): fail fast, use `setup-python@v4`, `cache@v3` --- .github/workflows/run-tests.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index edf0a592..2c0330d7 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -6,7 +6,6 @@ jobs: run-tests: strategy: - fail-fast: false matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] @@ -39,11 +38,11 @@ jobs: # Setup Python/pip - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Cache pip - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ matrix.pip-cache-path }} key: ${{ runner.os }}-pip From 8d80a738de4e210cdf679a13ad328cae3902bc61 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 21 Sep 2022 11:00:07 +0300 Subject: [PATCH 150/295] Build(devscripts/release): Disable progress bar for `twine` [skip ci] --- devscripts/release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index 3873ec25..8893a52f 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,5 +24,5 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -twine upload --skip-existing dist/* && +twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 3fa162e89cbb1611e03ccbf140cecb7fbddd4f1c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 23 Sep 2022 15:54:40 +0300 Subject: [PATCH 151/295] Docs(ANNOUNCE): Add Developer Guide and brief installation instruction [skip ci] --- ANNOUNCE.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index c9b634bd..7d270b01 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -48,6 +48,9 @@ http://sqlobject.org Development: http://sqlobject.org/devel/ +Developer Guide: +http://sqlobject.org/DeveloperGuide.html + Mailing list: https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss @@ -64,6 +67,10 @@ https://stackoverflow.com/questions/tagged/sqlobject Example ======= +Install:: + + $ pip install sqlobject + Create a simple class that wraps a table:: >>> from sqlobject import * From e3f4e1a00f36a197cc9318ea4fc5911da02ea7ef Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 23 Sep 2022 16:22:22 +0300 Subject: [PATCH 152/295] Docs(ANNOUNCE): Reorder URLs: first users then developers Change the URL for mailing lists. [skip ci] --- ANNOUNCE.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 7d270b01..ae694356 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -45,15 +45,6 @@ Where is SQLObject Site: http://sqlobject.org -Development: -http://sqlobject.org/devel/ - -Developer Guide: -http://sqlobject.org/DeveloperGuide.html - -Mailing list: -https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss - Download: https://pypi.org/project/SQLObject/3.10.1a0.dev20221020/ @@ -63,6 +54,15 @@ http://sqlobject.org/News.html StackOverflow: https://stackoverflow.com/questions/tagged/sqlobject +Mailing lists: +https://sourceforge.net/p/sqlobject/mailman/ + +Development: +http://sqlobject.org/devel/ + +Developer Guide: +http://sqlobject.org/DeveloperGuide.html + Example ======= From 8417bda4771e6281f3851bc18c4c2fed5d48a2c0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Sep 2022 14:48:53 +0300 Subject: [PATCH 153/295] Add lists of supported DB API drivers [skip ci] --- ANNOUNCE.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index ae694356..db59849f 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -32,9 +32,13 @@ SQLObject is an object-relational mapper. Your database tables are described as classes, and rows are instances of those classes. SQLObject is meant to be easy to use and quick to get started with. -SQLObject supports a number of backends: MySQL, PostgreSQL, SQLite; -connections to other backends - Firebird, Sybase, MSSQL -and MaxDB (also known as SAPDB) - are lesser debugged). +SQLObject supports a number of backends: MySQL/MariaDB (with a number of +DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, +``pysqlite``, partially ``supersqlite``); connections to other backends +- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less +debugged). Python 2.7 or 3.4+ is required. From 780cc55642eddbdc1b41557f79fe1d406415f334 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 25 Sep 2022 14:52:49 +0300 Subject: [PATCH 154/295] It's free, open-source (MIT), Python [skip ci] --- ANNOUNCE.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index db59849f..40828217 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -28,9 +28,10 @@ http://sqlobject.org/News.html What is SQLObject ================= -SQLObject is an object-relational mapper. Your database tables are described -as classes, and rows are instances of those classes. SQLObject is meant to be -easy to use and quick to get started with. +SQLObject is a free and open-source (LGPL) Python object-relational +mapper. Your database tables are described as classes, and rows are +instances of those classes. SQLObject is meant to be easy to use and +quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, From e2e7df6412ea84348729eb9450e7107bd5170c74 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 26 Oct 2022 00:05:08 +0300 Subject: [PATCH 155/295] Tests(tox): Remove `basepython` We no longer use `TOXPYTHON`. --- tox.ini | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tox.ini b/tox.ini index 828cc915..cc53f368 100644 --- a/tox.ini +++ b/tox.ini @@ -6,15 +6,6 @@ envlist = py27,py3{4,5,6,7,8,9,10}-sqlite{,-memory},py{27,310}-flake8 [testenv] # Ensure we cd into sqlobject before running the tests changedir = ./sqlobject/ -basepython = - py27: {env:TOXPYTHON:python2.7} - py34: {env:TOXPYTHON:python3.4} - py35: {env:TOXPYTHON:python3.5} - py36: {env:TOXPYTHON:python3.6} - py37: {env:TOXPYTHON:python3.7} - py38: {env:TOXPYTHON:python3.8} - py39: {env:TOXPYTHON:python3.9} - py310: {env:TOXPYTHON:python3.10} commands = {envpython} --version {envpython} -c "import struct; print(struct.calcsize('P') * 8)" From 25ab36002ae4affa9d9337b5b11fdee94aecfa1c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 25 Oct 2022 01:26:30 +0300 Subject: [PATCH 156/295] Tests, CI: Add Python 3.11 --- .github/workflows/run-tests.yaml | 2 +- devscripts/test-sqlobject.cmd | 2 +- docs/News.rst | 5 +++ setup.py | 1 + tox.ini | 68 ++++++++++++++++---------------- 5 files changed, 42 insertions(+), 36 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 2c0330d7..80335a8c 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] include: - os: ubuntu-latest os-name: Linux diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd index 8c7e38d0..f227bf09 100644 --- a/devscripts/test-sqlobject.cmd +++ b/devscripts/test-sqlobject.cmd @@ -3,7 +3,7 @@ SetLocal EnableDelayedExpansion set SavePATH=%PATH% -for %%V in (27 34 35 36 37 38 39 310) do ( +for %%V in (27 34 35 36 37 38 39 310 311) do ( for %%s in (32 64) do ( set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! set TOXPYTHON=C:\Python%%V-%%s\python.exe diff --git a/docs/News.rst b/docs/News.rst index 42f56160..e2d0b97a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests, CI +--------- + +* Run tests with Python 3.11. + SQLObject 3.10.0 ================ diff --git a/setup.py b/setup.py index 57ea5394..b67aa317 100755 --- a/setup.py +++ b/setup.py @@ -62,6 +62,7 @@ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index cc53f368..1f8bbbf6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10}-sqlite{,-memory},py{27,310}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10,11}-sqlite{,-memory},py{27,36,311}-flake8 # Base test environment settings [testenv] @@ -62,7 +62,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10,11}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -78,7 +78,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -94,7 +94,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector] commands = {[mysql-connector]commands} [oursql] @@ -110,7 +110,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -126,7 +126,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -141,7 +141,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10}-mariadb] +[testenv:py3{6,7,8,9,10,11}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -158,7 +158,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -174,7 +174,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -191,7 +191,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -207,7 +207,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -222,7 +222,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -241,7 +241,7 @@ commands = [testenv:py3{4,5,6}-postgres-pg8000] commands = {[pg8000]commands} -[testenv:py3{7,8,9,10}-postgres-pg8000-noauto] +[testenv:py3{7,8,9,10,11}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -258,7 +258,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -274,7 +274,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -291,7 +291,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -304,7 +304,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory] commands = {[sqlite-memory]commands} [sqlite-supersqlite] @@ -319,7 +319,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-supersqlite]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-supersqlite] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-supersqlite] commands = {[sqlite-supersqlite]commands} @@ -337,7 +337,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -353,7 +353,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11}-firebirdsql] commands = {[firebirdsql]commands} @@ -384,7 +384,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -403,7 +403,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -422,7 +422,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -440,7 +440,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -460,7 +460,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -480,7 +480,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -499,7 +499,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -518,7 +518,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -536,7 +536,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypostgresql-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -555,7 +555,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -575,7 +575,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -595,7 +595,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -612,7 +612,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -628,6 +628,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From 302bfb6818745c31b5c863eacfdc315b5784d396 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 27 Oct 2022 19:05:04 +0300 Subject: [PATCH 157/295] Tests(tox): Fix the list of `flake8` environments --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1f8bbbf6..81df7f69 100644 --- a/tox.ini +++ b/tox.ini @@ -358,7 +358,7 @@ commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311}-flake8] changedir = ./ deps = flake8 From 6509ac8c44f0ef98e6d64007a7cc9efd2abf083b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 17 Nov 2022 21:54:35 +0300 Subject: [PATCH 158/295] Fix(compat): Use `.exec_module(.create_module())` instead of `.load_module()` Use `module_loader.exec_module(module_loader.create_module())` instead of `module_loader.load_module()` when available. --- docs/News.rst | 6 ++++++ sqlobject/compat.py | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index e2d0b97a..0eaaa97d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Minor features +-------------- + +* Use ``module_loader.exec_module(module_loader.create_module())`` + instead of ``module_loader.load_module()`` when available. + Tests, CI --------- diff --git a/sqlobject/compat.py b/sqlobject/compat.py index 72d696f4..fc8edf25 100644 --- a/sqlobject/compat.py +++ b/sqlobject/compat.py @@ -47,4 +47,13 @@ def load_module_from_file(base_name, module_name, filename): def load_module_from_file(base_name, module_name, filename): specs = importlib.util.spec_from_file_location(module_name, filename) - return specs.loader.load_module() + loader = specs.loader + if hasattr(loader, 'create_module'): + module = loader.create_module(specs) + else: + module = None + if module is None: + return specs.loader.load_module() + else: + loader.exec_module(module) + return module From 44c441439545d48f9eccf172ff0b0b76bb18ac8d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 18 Nov 2022 18:29:44 +0300 Subject: [PATCH 159/295] Docs(README): Update Copied from https://github.com/sqlobject/.github/tree/master/profile [skip ci] --- README.rst | 87 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index c9102052..8c310399 100644 --- a/README.rst +++ b/README.rst @@ -1,15 +1,86 @@ SQLObject 3.10.1a0 ================== -Thanks for looking at SQLObject. SQLObject is an object-relational -mapper, i.e., a library that will wrap your database tables in Python -classes, and your rows in Python instances. +SQLObject is a free and open-source (LGPL) Python object-relational +mapper. Your database tables are described as classes, and rows are +instances of those classes. SQLObject is meant to be easy to use and +quick to get started with. -It currently supports MySQL, PostgreSQL and SQLite; connections to other -backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are -lesser debugged). +SQLObject supports a number of backends: MySQL/MariaDB (with a number of +DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, +``pysqlite``, partially ``supersqlite``); connections to other backends +- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less +debugged). Python 2.7 or 3.4+ is required. -For more information please see the documentation in -``_, or online at http://sqlobject.org/ + +Where is SQLObject +================== + +Site: +http://sqlobject.org + +Download: +https://pypi.org/project/SQLObject/ + +News and changes: +http://sqlobject.org/News.html + +StackOverflow: +https://stackoverflow.com/questions/tagged/sqlobject + +Mailing lists: +https://sourceforge.net/p/sqlobject/mailman/ + +Development: +http://sqlobject.org/devel/ + +Developer Guide: +http://sqlobject.org/DeveloperGuide.html + + +Example +======= + +Install:: + + $ pip install sqlobject + +Create a simple class that wraps a table:: + + >>> from sqlobject import * + >>> + >>> sqlhub.processConnection = connectionForURI('sqlite:/:memory:') + >>> + >>> class Person(SQLObject): + ... fname = StringCol() + ... mi = StringCol(length=1, default=None) + ... lname = StringCol() + ... + >>> Person.createTable() + +Use the object:: + + >>> p = Person(fname="John", lname="Doe") + >>> p + + >>> p.fname + 'John' + >>> p.mi = 'Q' + >>> p2 = Person.get(1) + >>> p2 + + >>> p is p2 + True + +Queries:: + + >>> p3 = Person.selectBy(lname="Doe")[0] + >>> p3 + + >>> pc = Person.select(Person.q.lname=="Doe").count() + >>> pc + 1 From 295eb1aee711bcbc7c01612a5e4657415fef7f25 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 3 Dec 2022 01:15:34 +0300 Subject: [PATCH 160/295] CI: Unify names I always call it "w32" even if it's really 64-bit. [skip ci] --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 80335a8c..7b5c8b45 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -73,7 +73,7 @@ jobs: devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} - - name: Run tox @ w64 + - name: Run tox @ w32 run: | devscripts\tox-select-envs.cmd %PYVER%-mysql devscripts\tox-select-envs.cmd %PYVER%-postgres From 0745abd1c5a2c0123c18879ed9f1baa08f7bc5ef Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 6 Dec 2022 19:44:17 +0300 Subject: [PATCH 161/295] CI(GHActions): Use `conda` to install older Pythons Ubuntu >= 22 and `setup-python` dropped Pythons < 3.7. Use `s-weigand/setup-conda` instead of `setup-python`. --- .github/workflows/run-tests.yaml | 5 +++++ docs/News.rst | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 7b5c8b45..a0fc3141 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -38,9 +38,14 @@ jobs: # Setup Python/pip - uses: actions/checkout@v2 + - uses: s-weigand/setup-conda@v1 + with: + python-version: ${{ matrix.python-version }} + if: ${{ runner.os == 'Linux' && matrix.python-version != '3.11' }} - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} + if: ${{ runner.os != 'Linux' || matrix.python-version == '3.11' }} - name: Cache pip uses: actions/cache@v3 with: diff --git a/docs/News.rst b/docs/News.rst index 0eaaa97d..02bcdb4a 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,11 +14,18 @@ Minor features * Use ``module_loader.exec_module(module_loader.create_module())`` instead of ``module_loader.load_module()`` when available. -Tests, CI ---------- +Tests +----- * Run tests with Python 3.11. +CI +-- + +* Ubuntu >= 22 and ``setup-python`` dropped Pythons < 3.7. + Use ``conda`` via ``s-weigand/setup-conda`` instead of ``setup-python`` + to install older Pythons on Linux. + SQLObject 3.10.0 ================ From b46a80e04bb2c5f3a873549edd5947527f0088d1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 9 Dec 2022 15:17:15 +0300 Subject: [PATCH 162/295] CI(GHActions): Set `$LD_LIBRARY_PATH` Python 2.7 on Linux requires `$LD_LIBRARY_PATH`. --- .github/workflows/run-tests.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index a0fc3141..5eb73dc9 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -62,8 +62,15 @@ jobs: - name: Set PYVER run: | import os, sys + ld_library_path = None pyver = '%d%d' % tuple(sys.version_info[:2]) + if os.name == 'posix': + if pyver == '27': # Python 2.7 on Linux requires `$LD_LIBRARY_PATH` + ld_library_path = os.path.join( + os.path.dirname(os.path.dirname(sys.executable)), 'lib') with open(os.environ['GITHUB_ENV'], 'a') as f: + if ld_library_path: + f.write('LD_LIBRARY_PATH=' + ld_library_path + '\n') f.write('PYVER=' + pyver + '\n') f.write('PGPASSWORD=test\n') shell: python From 089c9885aebbce49bae7f0388ee57df5b182ffd0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 15 Dec 2022 19:55:37 +0300 Subject: [PATCH 163/295] Tests(tox): Limit "tox < 4" `tox` 4+ has incompatible `tox.ini` syntax. It's impossible to use one `tox.ini` for Pythons < 3.7 and 3.7+. --- .github/workflows/run-tests.yaml | 2 +- devscripts/requirements/requirements_tox.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 5eb73dc9..bc676984 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -58,7 +58,7 @@ jobs: python --version python -m pip install --upgrade pip setuptools wheel pip --version - pip install --upgrade virtualenv tox + pip install --upgrade virtualenv "tox < 4" - name: Set PYVER run: | import os, sys diff --git a/devscripts/requirements/requirements_tox.txt b/devscripts/requirements/requirements_tox.txt index 8b5960b9..b72a322f 100644 --- a/devscripts/requirements/requirements_tox.txt +++ b/devscripts/requirements/requirements_tox.txt @@ -1 +1 @@ -tox >= 3.15 +tox >= 3.15, < 4 From 89a7e24d7de75c745c60481d0da68aa204427f59 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:54:55 +0300 Subject: [PATCH 164/295] Feat(MySQL): Add `mysql-connector-python` --- .../requirements_connector_python.txt | 10 ++++++++++ docs/News.rst | 8 +++++++- setup.py | 1 + sqlobject/mysql/mysqlconnection.py | 15 ++++++++------- tox.ini | 17 +++++++++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 devscripts/requirements/requirements_connector_python.txt diff --git a/devscripts/requirements/requirements_connector_python.txt b/devscripts/requirements/requirements_connector_python.txt new file mode 100644 index 00000000..d06b1911 --- /dev/null +++ b/devscripts/requirements/requirements_connector_python.txt @@ -0,0 +1,10 @@ +mysql-connector-python <= 8.0.23; python_version == '2.7' +protobuf < 3.19; python_version == '3.4' +mysql-connector-python <= 8.0.22, > 2.0; python_version == '3.4' +mysql-connector-python <= 8.0.23, >= 8.0.5; python_version == '3.5' +mysql-connector-python <= 8.0.28, >= 8.0.6; python_version == '3.6' +mysql-connector-python >= 8.0.13; python_version == '3.7' +mysql-connector-python >= 8.0.19; python_version == '3.8' +mysql-connector-python >= 8.0.24; python_version == '3.9' +mysql-connector-python >= 8.0.28; python_version == '3.10' +mysql-connector-python >= 8.0.31; python_version >= '3.11' diff --git a/docs/News.rst b/docs/News.rst index 02bcdb4a..c9d65c90 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,11 @@ Minor features * Use ``module_loader.exec_module(module_loader.create_module())`` instead of ``module_loader.load_module()`` when available. +Drivers +------- + +* Added ``mysql-connector-python``. + Tests ----- @@ -468,7 +473,8 @@ Minor features 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. * Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', - 'connector', 'oursql' and 'pymysql'. Default is to test for mysqldb only. + 'connector', 'connector-python', 'oursql' and 'pymysql'. Default is to + test for mysqldb only. * Add support for `MySQL Connector `_ (pure python; `binary diff --git a/setup.py b/setup.py index b67aa317..db824658 100755 --- a/setup.py +++ b/setup.py @@ -117,6 +117,7 @@ 'mysql:python_version=="2.7"': ['MySQL-python'], 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], + 'mysql-connector-python': ['mysql-connector-python'], 'oursql:python_version=="2.7"': [ 'oursql @ git+https://github.com/sqlobject/oursql.git@master'], 'oursql:python_version>="3.4"': [ diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index c4a72a6e..ac3e0629 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -59,7 +59,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ MySQLdb.constants.CR.CR_SERVER_LOST self.ER_DUP_ENTRY = MySQLdb.constants.ER.DUP_ENTRY - elif driver == 'connector': + elif driver in ('connector', 'connector-python'): import mysql.connector self.module = mysql.connector self.CR_SERVER_GONE_ERROR = \ @@ -92,7 +92,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): else: raise ValueError( 'Unknown MySQL driver "%s", ' - 'expected mysqldb, connector, ' + 'expected mysqldb, connector, connector-python, ' 'oursql, pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: @@ -118,7 +118,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): "client_flag", "local_infile"): if key in kw: self.kw[key] = int(kw.pop(key)) - if driver == 'connector': + if driver in ('connector', 'connector-python'): for key in ("ssl_key", "ssl_cert", "ssl_ca", "ssl_capath"): if key in kw: self.kw[key] = kw.pop(key) @@ -154,7 +154,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): elif driver == 'mariadb': self.kw.pop("charset", None) - elif driver == 'connector': + elif driver in ('connector', 'connector-python'): registerConverter(bytes, ConnectorBytesConverter) global mysql_Bin @@ -185,7 +185,7 @@ def makeConnection(self): def character_set_name(self): return dbEncoding + '_' + dbEncoding Connection.character_set_name = character_set_name - if self.driver == 'connector': + if self.driver in ('connector', 'connector-python'): self.kw['consume_results'] = True try: if self.driver in ('odbc', 'pyodbc', 'pypyodbc'): @@ -237,7 +237,7 @@ def _setAutoCommit(self, conn, auto): try: conn.autocommit(auto) except TypeError: - # mysql-connector has autocommit as a property + # mysql-connector{-python} has autocommit as a property conn.autocommit = auto def _force_reconnect(self, conn): @@ -252,7 +252,8 @@ def _executeRetry(self, conn, cursor, query): self.printDebug(conn, query, 'QueryR') dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( - self.driver in ('mysqldb', 'connector', 'oursql', 'mariadb')): + self.driver in ('mysqldb', 'connector', 'connector-python', + 'oursql', 'mariadb')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the diff --git a/tox.ini b/tox.ini index 81df7f69..9d1bd95f 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,7 @@ deps = mysqldb: mysql-python mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 + mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt @@ -97,6 +98,22 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector] commands = {[mysql-connector]commands} +[mysql-connector-python] +commands = + {[testenv]commands} + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" + +[testenv:py27-mysql-connector-python{,-w32}] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-connector-python]commands} + +[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-python{,-w32}] +commands = {[mysql-connector-python]commands} + [oursql] commands = {[testenv]commands} From 4927a0677762005a794862e940209b7046ea695d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:55:57 +0300 Subject: [PATCH 165/295] Fix(dbconnection): autocommit value must be bool --- sqlobject/dbconnection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index 6a383e79..e691f2d4 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -799,7 +799,7 @@ def __init__(self, dbConnection): self._obsolete = True self._dbConnection = dbConnection self._connection = dbConnection.getConnection() - self._dbConnection._setAutoCommit(self._connection, 0) + self._dbConnection._setAutoCommit(self._connection, False) self.cache = CacheSet(cache=dbConnection.doCache) self._deletedCache = {} self._obsolete = False @@ -924,7 +924,7 @@ def __getattr__(self, attr): def _makeObsolete(self): self._obsolete = True if self._dbConnection.autoCommit: - self._dbConnection._setAutoCommit(self._connection, 1) + self._dbConnection._setAutoCommit(self._connection, True) self._dbConnection.releaseConnection(self._connection, explicit=True) self._connection = None @@ -938,7 +938,7 @@ def begin(self): "without rolling back this one" self._obsolete = False self._connection = self._dbConnection.getConnection() - self._dbConnection._setAutoCommit(self._connection, 0) + self._dbConnection._setAutoCommit(self._connection, False) def __del__(self): if self._obsolete: From 8b1204c5983ded07f95a20db96553de7d9d9f431 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:56:57 +0300 Subject: [PATCH 166/295] Tests: Allow transactions with MySQL MySQL (mostly MariaDB these days) enabled transactions by default long ago. --- sqlobject/tests/dbtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index c7c8b0ea..e934ac51 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -43,7 +43,7 @@ def test_featureX(): '+memorydb': 'sqlite', '+rlike': 'mysql postgres sqlite', '+schema': 'postgres', - '-transactions': 'mysql', + '-transactions': ' ', } From 613839ed6f4948b1504f762d1622a987cdce0407 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 20:58:15 +0300 Subject: [PATCH 167/295] Tests: Skip some inheritance tests under `mysql-connector-python` M-C-P falls into an infinite loop. --- .../inheritance/tests/test_deep_inheritance.py | 6 +++++- sqlobject/inheritance/tests/test_inheritance.py | 16 +++++++++++++++- .../inheritance/tests/test_inheritance_tree.py | 8 +++++++- sqlobject/mysql/mysqlconnection.py | 4 ++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/sqlobject/inheritance/tests/test_deep_inheritance.py b/sqlobject/inheritance/tests/test_deep_inheritance.py index 1ef4d36f..4bdc8e34 100644 --- a/sqlobject/inheritance/tests/test_deep_inheritance.py +++ b/sqlobject/inheritance/tests/test_deep_inheritance.py @@ -72,6 +72,11 @@ def test_creation_fail2(): def test_deep_inheritance(): + conn = getConnection() + if conn.module.__name__ == 'mysql.connector' \ + and conn.connector_type == 'mysql.connector-python': + skip("connector-python falls into an infinite loop here") + setupClass([DIManager, DIEmployee, DIPerson]) manager = DIManager(firstName='Project', lastName='Manager', @@ -81,7 +86,6 @@ def test_deep_inheritance(): so_position='Project leader', manager=manager).id DIPerson(firstName='Oneof', lastName='Authors', manager=manager) - conn = getConnection() cache = conn.cache cache.clear() diff --git a/sqlobject/inheritance/tests/test_inheritance.py b/sqlobject/inheritance/tests/test_inheritance.py index cc26c8f5..2dfd0e3a 100644 --- a/sqlobject/inheritance/tests/test_inheritance.py +++ b/sqlobject/inheritance/tests/test_inheritance.py @@ -1,7 +1,21 @@ +import pytest from pytest import raises from sqlobject import IntCol, StringCol from sqlobject.inheritance import InheritableSQLObject -from sqlobject.tests.dbtest import setupClass +from sqlobject.tests.dbtest import getConnection, setupClass + + +try: + connection = getConnection() +except (AttributeError, NameError): + # The module was imported during documentation building + pass +else: + if connection.module.__name__ == 'mysql.connector' \ + and connection.connector_type == 'mysql.connector-python': + pytestmark = pytest.mark.skip( + "connector-python falls into an infinite loop here") + ######################################## # Inheritance diff --git a/sqlobject/inheritance/tests/test_inheritance_tree.py b/sqlobject/inheritance/tests/test_inheritance_tree.py index 58cdb7ea..34666c38 100644 --- a/sqlobject/inheritance/tests/test_inheritance_tree.py +++ b/sqlobject/inheritance/tests/test_inheritance_tree.py @@ -1,6 +1,7 @@ +from pytest import skip from sqlobject import StringCol from sqlobject.inheritance import InheritableSQLObject -from sqlobject.tests.dbtest import setupClass +from sqlobject.tests.dbtest import getConnection, setupClass ######################################## # Inheritance Tree @@ -28,6 +29,11 @@ class Tree5(Tree2): def test_tree(): + conn = getConnection() + if conn.module.__name__ == 'mysql.connector' \ + and conn.connector_type == 'mysql.connector-python': + skip("connector-python falls into an infinite loop here") + setupClass([Tree1, Tree2, Tree3, Tree4, Tree5]) Tree1(aprop='t1') # t1 diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index ac3e0629..76b11724 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -67,6 +67,10 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ mysql.connector.errorcode.CR_SERVER_LOST self.ER_DUP_ENTRY = mysql.connector.errorcode.ER_DUP_ENTRY + if driver == 'connector-python': + self.connector_type = 'mysql.connector-python' + else: + self.connector_type = 'mysql.connector' elif driver == 'oursql': import oursql self.module = oursql From eeb61ea9059372d005cd5fe3398f0d73b827bd0f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 4 Dec 2022 21:01:09 +0300 Subject: [PATCH 168/295] Tests(mysql-connector-python): Limit versions Versions 8.0.30+ require charset `utf8mb4` on the server which is not available on old MySQL and MariaDB servers. --- .../requirements/requirements_connector_python.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/devscripts/requirements/requirements_connector_python.txt b/devscripts/requirements/requirements_connector_python.txt index d06b1911..e4bffe7a 100644 --- a/devscripts/requirements/requirements_connector_python.txt +++ b/devscripts/requirements/requirements_connector_python.txt @@ -3,8 +3,9 @@ protobuf < 3.19; python_version == '3.4' mysql-connector-python <= 8.0.22, > 2.0; python_version == '3.4' mysql-connector-python <= 8.0.23, >= 8.0.5; python_version == '3.5' mysql-connector-python <= 8.0.28, >= 8.0.6; python_version == '3.6' -mysql-connector-python >= 8.0.13; python_version == '3.7' -mysql-connector-python >= 8.0.19; python_version == '3.8' -mysql-connector-python >= 8.0.24; python_version == '3.9' -mysql-connector-python >= 8.0.28; python_version == '3.10' -mysql-connector-python >= 8.0.31; python_version >= '3.11' +mysql-connector-python <= 8.0.29, >= 8.0.13; python_version == '3.7' +mysql-connector-python <= 8.0.29, >= 8.0.19; python_version == '3.8' +mysql-connector-python <= 8.0.29, >= 8.0.24; python_version == '3.9' +mysql-connector-python <= 8.0.29, >= 8.0.28; python_version == '3.10' +#mysql-connector-python >= 8.0.31; python_version >= '3.11' +mysql-connector-python == 8.0.29; python_version >= '3.11' From d85fd1c45bc700cd1233afb34d124c75be538847 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 16 Dec 2022 00:30:41 +0300 Subject: [PATCH 169/295] CI(GHActions): More descriptive step names Add OS name. --- .github/workflows/run-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index bc676984..31b170bc 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -27,11 +27,11 @@ jobs: # Setup PostgreSQL - uses: ankane/setup-postgres@v1 - - name: Setup Postgres user + - name: Setup Postgres user @ Linux run: | sudo -u postgres psql --command="ALTER USER runner CREATEDB ENCRYPTED PASSWORD 'test'" if: ${{ runner.os == 'Linux' }} - - name: Setup Postgres user + - name: Setup Postgres user @ w32 run: | psql --command="CREATE USER runner CREATEDB ENCRYPTED PASSWORD 'test'" if: ${{ runner.os == 'Windows' }} From bd1459096795e5ce5f4c31c2ce10955aba44fac1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:18:57 +0300 Subject: [PATCH 170/295] Build(RELEASE-CHECKLIST): Minor update [skip ci] --- devscripts/RELEASE-CHECKLIST | 48 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index f47ec418..91d47036 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -1,54 +1,48 @@ 0. Run full test suite in all branches and in master. Continue if all tests passed. -1. Check out the release branch. If it is a stable release - edit - docs/News.rst to set release date. Commit. - -2. If release branch is not master - run devscripts/prerelease $NEW_TAG; if +1. If release branch is not master - run devscripts/prerelease $NEW_TAG; if it's master - run devscripts/prerelease $NEW_TAG master. - The script checks out the release branch and calls editor; update - version, the list of contributors, the list of changes and download - URL in ANNOUNCE.rst; edit __version__.py and README.rst in the release - branch - fix versions. Edit section [egg_info] in setup.cfg - set if - it is a stable or development release. In setup.py edit "Development - Status" in trove classifiers; edit download URLs: if a non-stable - version - append 'dev' and date stamp, for a stable version remove - 'dev' and date stamp). - - If it's the first stable release of the branch - edit build-all-docs, - advance stable branch. - - Commit. Verify. + The script checks out the release branch and calls editor; if it's the + first stable release of the branch - edit build-all-docs, advance stable + branch; if it is a stable release - edit docs/News.rst to set release + date; update version, the list of contributors, the list of changes and + download URL in ANNOUNCE.rst; edit __version__.py and README.rst in the + release branch - fix versions. Edit section [egg_info] in setup.cfg - + set if it is a stable or development release. In setup.py edit + "Development Status" in trove classifiers; edit download URLs: if a + non-stable version - append 'dev' and date stamp, for a stable version + remove 'dev' and date stamp). Commit. Verify. -3. If it's not master - null-merge to the next higher branch. +2. If it's not master - null-merge to the next higher branch. -4. If release branch is not master - run devscripts/prerelease-tag +3. If release branch is not master - run devscripts/prerelease-tag $NEW_TAG; if it's master - run devscripts/prerelease-tag $NEW_TAG master. This checks out the release branch and creates the new tag at the head of the release branch. -5. Run devscripts/release. This generates and uploads new archives to PyPI +4. Run devscripts/release. This generates and uploads new archives to PyPI and if it is a stable release - uploads archives and release announcement (ANNOUNCE.rst) to SourceForge. -6. Move old releases at SourceForge to subdirectory OldFiles. +5. Move old releases at SourceForge to subdirectory OldFiles. -7. Run devscripts/postrelease. The script restores ANNOUNCE.rst and +6. Run devscripts/postrelease. The script restores ANNOUNCE.rst and setup.cfg from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new version. -8. Run devscripts/push-all in the development repository to push all +7. Run devscripts/push-all in the development repository to push all branches and tags to the public repositories. -9. Generate new docs using devscripts/build-all-docs. Upload docs using +8. Generate new docs using devscripts/build-all-docs. Upload docs using devscripts/publish-docs. -10. Send announcement to the SQLObject mailing list. For a stable - release send announcements to python, python-announce and python-db - mailing lists. +9. Send announcement to the SQLObject mailing list. For a stable + release send announcements to python, python-announce and python-db + mailing lists. 10. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable From 5347ce559a2dc11f4ca190e5291b22e0b5beecbb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:22:18 +0300 Subject: [PATCH 171/295] Release 3.10.1 --- ANNOUNCE.rst | 37 +++++++++++++++++++++++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 4 ++-- sqlobject/__version__.py | 4 ++-- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 40828217..8f84a2dc 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,34 @@ Hello! -I'm pleased to announce version 3.10.1a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.1, the first minor feature release of +branch 3.10 of SQLObject. -I'm pleased to announce version 3.10.1a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. -I'm pleased to announce version 3.10.1b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.10.1rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. +Minor features +-------------- -I'm pleased to announce version 3.10.1, the first bugfix release of branch -3.10 of SQLObject. +* Use ``module_loader.exec_module(module_loader.create_module())`` + instead of ``module_loader.load_module()`` when available. +Drivers +------- -What's new in SQLObject -======================= +* Added ``mysql-connector-python``. + +Tests +----- + +* Run tests with Python 3.11. + +CI +-- -Contributors for this release are +* Ubuntu >= 22 and ``setup-python`` dropped Pythons < 3.7. + Use ``conda`` via ``s-weigand/setup-conda`` instead of ``setup-python`` + to install older Pythons on Linux. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -51,7 +60,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.1a0.dev20221020/ +https://pypi.org/project/SQLObject/3.10.1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 8c310399..8fb170f0 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.1a0 -================== +SQLObject 3.10.1 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8942edb7..8da2c52b 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.0 && +build_docs 3.10.1 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index c9d65c90..68b43687 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,8 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.1 +================ Minor features -------------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index e01c255e..7753d960 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.0' +version = '3.10.1' major = 3 minor = 10 -micro = 0 +micro = 1 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 1d0f1bc72a475ce82fac0b1c701b77bcd1e51d3e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:29:48 +0300 Subject: [PATCH 172/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 37 ++++++++++++++----------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 8f84a2dc..0040aed7 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,34 +1,25 @@ Hello! -I'm pleased to announce version 3.10.1, the first minor feature release of -branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.2a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.2a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. -What's new in SQLObject -======================= - -Minor features --------------- - -* Use ``module_loader.exec_module(module_loader.create_module())`` - instead of ``module_loader.load_module()`` when available. +I'm pleased to announce version 3.10.2b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. -Drivers -------- +I'm pleased to announce version 3.10.2rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. -* Added ``mysql-connector-python``. +I'm pleased to announce version 3.10.2, the first bugfix release of branch +3.10 of SQLObject. -Tests ------ -* Run tests with Python 3.11. - -CI --- +What's new in SQLObject +======================= -* Ubuntu >= 22 and ``setup-python`` dropped Pythons < 3.7. - Use ``conda`` via ``s-weigand/setup-conda`` instead of ``setup-python`` - to install older Pythons on Linux. +Contributors for this release are For a more complete list, please see the news: http://sqlobject.org/News.html @@ -60,7 +51,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.1 +https://pypi.org/project/SQLObject/3.10.2a0.dev20221222/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 8fb170f0..3896cef6 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.1 -================ +SQLObject 3.10.2a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index 68b43687..36c0229d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.1 ================ From 8872b7924b98f15456edf9750a64e02b54da67dc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 22 Dec 2022 19:18:57 +0300 Subject: [PATCH 173/295] Build(RELEASE-CHECKLIST): Minor update [skip ci] --- devscripts/RELEASE-CHECKLIST | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/devscripts/RELEASE-CHECKLIST b/devscripts/RELEASE-CHECKLIST index 91d47036..a7909b4f 100644 --- a/devscripts/RELEASE-CHECKLIST +++ b/devscripts/RELEASE-CHECKLIST @@ -24,27 +24,26 @@ 4. Run devscripts/release. This generates and uploads new archives to PyPI and if it is a stable release - uploads archives and release - announcement (ANNOUNCE.rst) to SourceForge. + announcement (ANNOUNCE.rst) to SourceForge. Move old releases at + SourceForge to subdirectory OldFiles. -5. Move old releases at SourceForge to subdirectory OldFiles. - -6. Run devscripts/postrelease. The script restores ANNOUNCE.rst and +5. Run devscripts/postrelease. The script restores ANNOUNCE.rst and setup.cfg from the previous commit (HEAD~). It calls editor; update next version, remove the list of contributors and the list of changes, edit download URL in ANNOUNCE.rst. Edit README.rst and docs/News.rst - add new version. -7. Run devscripts/push-all in the development repository to push all +6. Run devscripts/push-all in the development repository to push all branches and tags to the public repositories. -8. Generate new docs using devscripts/build-all-docs. Upload docs using +7. Generate new docs using devscripts/build-all-docs. Upload docs using devscripts/publish-docs. -9. Send announcement to the SQLObject mailing list. For a stable +8. Send announcement to the SQLObject mailing list. For a stable release send announcements to python, python-announce and python-db mailing lists. -10. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and - Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable - release - announce it at - https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. +9. Announce new release(s) at Twitter (https://twitter.com/SQLObject) and + Wikipedia (https://en.wikipedia.org/wiki/SQLObject). If it is a stable + release - announce it at + https://en.wikipedia.org/wiki/Comparison_of_object-relational_mapping_software. From f089c78127c7631fe8f4258487d377f4b4bcde68 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 26 Dec 2022 20:02:09 +0300 Subject: [PATCH 174/295] Docs(News): Split `News.rst` [skip ci] --- docs/News.rst | 549 +---------------------------------------------- docs/News6.rst | 566 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 567 insertions(+), 548 deletions(-) create mode 100644 docs/News6.rst diff --git a/docs/News.rst b/docs/News.rst index 36c0229d..a0ebdf7f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -78,557 +78,10 @@ Documentation * DevGuide: commit messages must be pure ASCII. -SQLObject 3.9.1 -=============== - -Released 2021 Feb 27. - -Drivers -------- - -* Adapt to the latest ``pg8000``. - -* Protect ``getuser()`` - it can raise ``ImportError`` on w32 - due to absent of ``pwd`` module. - -Build ------ - -* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. - Provide separate URLs for Python 2.7 and 3.4+. - -* Add ``mariadb`` in ``extras_require`` in ``setup.py``. - -CI --- - -* For tests with Python 3.4 run ``tox`` under Python 3.5. - -Tests ------ - -* Refactor ``tox.ini``. - -SQLObject 3.9.0 -=============== - -Released 2020 Dec 15. - -Features --------- - -* Add ``JSONCol``: a universal json column that converts simple Python objects - (None, bool, int, float, long, dict, list, str/unicode to/from JSON using - json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` - columns at backends, doesn't work with ``JSON`` columns. - -* Extend/fix support for ``DateTime`` from ``Zope``. - -* Drop support for very old version of ``mxDateTime`` - without ``mx.`` namespace. - -Drivers -------- - -* Support `mariadb `_. - -CI --- - -* Run tests with Python 3.9 at Travis and AppVeyor. - -SQLObject 3.8.1 -=============== - -Released 2020 Oct 01. - -Documentation -------------- - -* Use conf.py options to exclude sqlmeta options. - -Tests ------ - -* Fix ``PyGreSQL`` version for Python 3.4. - -CI --- - -* Run tests with Python 3.8 at AppVeyor. - -SQLObject 3.8.0 -=============== - -Released 7 Dec 2019. - -Features --------- - -* Add driver ``supersqlite``. Not all tests are passing - so the driver isn't added to the list of default drivers. - -Minor features --------------- - -* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression - at the right side of the comparison operation. - -Bug fixes ---------- - -* Fixed a bug in cascade deletion/nullification. - -* Fixed a bug in ``PostgresConnection.columnsFromSchema``: - PostgreSQL 12 removed outdated catalog attribute - ``pg_catalog.pg_attrdef.adsrc``. - -* Fixed a bug working with microseconds in Time columns. - -CI --- - -* Run tests with Python 3.8 at Travis CI. - -SQLObject 3.7.3 -=============== - -Released 22 Sep 2019. - -Bug fixes ---------- - -* Avoid excessive parentheses around ``ALL/ANY/SOME()``. - -Tests ------ - -* Add tests for cascade deletion. - -* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. - -* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. - -* Fix module-level calls to ``pytest.mark.skip`` - add reasons. - -* Fix escape sequences ``'\%'`` -> ``'\\%'``. - -CI --- - -* Reduce the number of virtual machines/containers: - one OS, one DB, one python version, many drivers per VM. - -* Fix sqlite test under Python 3.7+ at AppVeyor. - -SQLObject 3.7.2 -=============== - -Released 1 May 2019. - -Minor features --------------- - -* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: - in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. - -* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable - since 2017. - -SQLObject 3.7.1 -=============== - -Released 2 Feb 2019. - -Bug fixes ---------- - -* Fixed a unicode problem in the latest mysqlclient. - -Documentation -------------- - -* Exclude sqlmeta members from some of the api docs. - The inclusion of of these sqlmeta members in these files breaks - reproducible builds. - -Development ------------ - -* Source code was made flake8-clean using the latest flake8. - -CI --- - -* Run tests with Python 3.7. - -SQLObject 3.7.0 -=============== - -Released 6 June 2018. - -Features --------- - -* Add signals on commit and rollback; pull request by Scott Stahl. - -Bug fixes ---------- - -* Fix SSL-related parameters for MySQL-connector (connector uses - a different param style). Bug reported by Christophe Popov. - -Drivers -------- - -* Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. - -Tests ------ - -* Install psycopg2 from `psycopg2-binary`_ package. - -.. _`psycopg2-binary`: https://pypi.org/project/psycopg2-binary/ - -SQLObject 3.6.0 -=============== - -Released 24 Feb 2018. - -Minor features --------------- - -* Close cursors after using to free resources immediately - instead of waiting for gc. - -Bug fixes ---------- - -* Fix for TypeError using selectBy on a BLOBCol. PR by Michael S. Root. - -Drivers -------- - -* Extend support for oursql and Python 3 (requires our fork of the driver). - -* Fix cursor.arraysize - pymssql doesn't have arraysize. - -* Set timeout for ODBC with MSSQL. - -* Fix _setAutoCommit for MSSQL. - -Documentation -------------- - -* Document extras that are available for installation. - -Build ------ - -* Use ``python_version`` environment marker in ``setup.py`` to make - ``install_requires`` and ``extras_require`` declarative. This makes - the universal wheel truly universal. - -* Use ``python_requires`` keyword in ``setup.py``. - -SQLObject 3.5.0 -=============== - -Released 15 Nov 2017. - -Minor features --------------- - -* Add Python3 special methods for division to SQLExpression. - Pull request by Michael S. Root. - -Drivers -------- - -* Add support for `pg8000 `_ - PostgreSQL driver. - -* Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. - -Documentation -------------- - -* Remove generated HTML from eggs/wheels (docs are installed into wrong - place). Generated docs are still included in the source distribution. - -Tests ------ - -* Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. - -* Fixed bugs in py-postgresql at AppVeyor. SQLObject requires - the latest version of the driver from our fork. - -SQLObject 3.4.0 -=============== - -Released 5 Aug 2017. - -Features --------- - -* Python 2.6 is no longer supported. The minimal supported version is - Python 2.7. - -Drivers (work in progress) --------------------------- - -* Encode binary values for py-postgresql driver. This fixes the - last remaining problems with the driver. - -* Encode binary values for PyGreSQL driver using the same encoding as for - py-postgresql driver. This fixes the last remaining problems with the driver. - - Our own encoding is needed because unescape_bytea(escape_bytea()) is not - idempotent. See the comment for PQunescapeBytea at - https://www.postgresql.org/docs/9.6/static/libpq-exec.html: - - This conversion is not exactly the inverse of PQescapeBytea, because the - string is not expected to be "escaped" when received from PQgetvalue. In - particular this means there is no need for string quoting considerations. - -* List all drivers in extras_require in setup.py. - -Minor features --------------- - -* Use base64.b64encode/b64decode instead of deprecated - encodestring/decodestring. - -Tests ------ - -* Fix a bug with sqlite-memory: rollback transaction and close connection. - The solution was found by Dr. Neil Muller. - -* Use remove-old-files.py from ppu to cleanup pip cache - at Travis and AppVeyor. - -* Add test_csvimport.py more as an example how to use load_csv - from sqlobject.util.csvimport. - -SQLObject 3.3.0 -=============== - -Released 7 May 2017. - -Features --------- - -* Support for Python 2.6 is declared obsolete and will be removed - in the next release. - -Minor features --------------- - -* Convert scripts repository to devscripts subdirectory. - Some of thses scripts are version-dependent so it's better to have them - in the main repo. - -* Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol. - -Drivers (work in progress) --------------------------- - -* Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for - MySQL, PostgreSQL and MS SQL. Driver names are ``pyodbc``, ``pypyodbc`` - or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems - with pyodbc and many problems with pypyodbc. - -Documentation -------------- - -* Stop updating http://sqlobject.readthedocs.org/ - it's enough to have - http://sqlobject.org/ - -Tests ------ - -* Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. - -* Stop running tests at Travis with Python 2.6. - -* Stop running tests at AppVeyor with pymssql - too many timeouts and - problems. - -SQLObject 3.2.0 -=============== - -Released 11 Mar 2017. - -Minor features --------------- - -* Drop table name from ``VACUUM`` command in SQLiteConnection: SQLite - doesn't vacuum a single table and SQLite 3.15 uses the supplied name as - the name of the attached database to vacuum. - -* Remove ``driver`` keyword from RdbhostConnection as it allows one driver - ``rdbhdb``. - -* Add ``driver`` keyword for FirebirdConnection. Allowed values are 'fdb', - 'kinterbasdb' and 'pyfirebirdsql'. Default is to test 'fdb' and - 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. - -* Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', - 'connector', 'connector-python', 'oursql' and 'pymysql'. Default is to - test for mysqldb only. - -* Add support for `MySQL Connector - `_ (pure python; `binary - packages `_ are not at - PyPI and hence are hard to install and test). - -* Add support for `oursql `_ MySQL - driver (only Python 2.6 and 2.7 until oursql author fixes Python 3 - compatibility). - -* Add support for `PyMySQL `_ - pure - python mysql interface). - -* Add parameter ``timeout`` for MSSQLConnection (usable only with pymssql - driver); timeouts are in seconds. - -* Remove deprecated ez_setup.py. - -Drivers (work in progress) --------------------------- - -* Extend support for PyGreSQL driver. There are still some problems. - -* Add support for `py-postgresql - `_ PostgreSQL driver. There - are still problems with the driver. - -* Add support for `pyfirebirdsql - `_.There are still problems with - the driver. - -Bug fixes ---------- - -* Fix MSSQLConnection.columnsFromSchema: remove `(` and `)` from default - value. - -* Fix MSSQLConnection and SybaseConnection: insert default values into a table - with just one IDENTITY column. - -* Remove excessive NULLs from ``CREATE TABLE`` for MSSQL/Sybase. - -* Fix concatenation operator for MSSQL/Sybase (it's ``+``, not ``||``). - -* Fix MSSQLConnection.server_version() under Py3 (decode version to str). - -Documentation -------------- - -* The docs are now generated with Sphinx. - -* Move ``docs/LICENSE`` to the top-level directory so that Github - recognizes it. - -Tests ------ - -* Rename ``py.test`` -> ``pytest`` in tests and docs. - -* Great Renaming: fix ``pytest`` warnings by renaming ``TestXXX`` classes - to ``SOTestXXX`` to prevent ``pytest`` to recognize them as test classes. - -* Fix ``pytest`` warnings by converting yield tests to plain calls: yield - tests were deprecated in ``pytest``. - -* Tests are now run at CIs with Python 3.5. - -* Drop ``Circle CI``. - -* Run at Travis CI tests with Firebird backend (server version 2.5; - drivers fdb and firebirdsql). There are problems with tests. - -* Run tests at AppVeyor for windows testing. Run tests with MS SQL, - MySQL, Postgres and SQLite backends; use Python 2.7, 3.4 and 3.5, - x86 and x64. There are problems with MS SQL and MySQL. - -SQLObject 3.1.0 -=============== - -Released 16 Aug 2016. - -Features --------- - -* Add UuidCol. - -* Add JsonbCol. Only for PostgreSQL. - Requires psycopg2 >= 2.5.4 and PostgreSQL >= 9.2. - -* Add JSONCol, a universal json column. - -* For Python >= 3.4 minimal FormEncode version is now 1.3.1. - -* If mxDateTime is in use, convert timedelta (returned by MySQL) to - mxDateTime.Time. - -Documentation -------------- - -* Developer's Guide is extended to explain SQLObject architecture - and how to create a new column type. - -* Fix URLs that can be found; remove missing links. - -* Rename reStructuredText files from \*.txt to \*.rst. - -Source code ------------ - -* Fix all `import *` using https://github.com/zestyping/star-destroyer. - -Tests ------ - -* Tests are now run at Circle CI. - -* Use pytest-cov for test coverage. Report test coverage - via coveralls.io and codecov.io. - -* Install mxDateTime to run date/time tests with it. - -SQLObject 3.0.0 -=============== - -Released 1 Jun 2016. - -Features --------- - -* Support for Python 2 and Python 3 with one codebase! - (Python version >= 3.4 currently required.) - -Minor features --------------- - -* PyDispatcher (>=2.0.4) was made an external dependency. - -Development ------------ - -* Source code was made flake8-clean. - -Documentation -------------- - -* Documentation is published at http://sqlobject.readthedocs.org/ in - Sphinx format. `Older news`__ -.. __: News5.html +.. __: News6.html .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 :target: https://sourceforge.net/projects/sqlobject diff --git a/docs/News6.rst b/docs/News6.rst new file mode 100644 index 00000000..313c62b3 --- /dev/null +++ b/docs/News6.rst @@ -0,0 +1,566 @@ +++++ +News +++++ + +.. contents:: Contents: + :backlinks: none + +SQLObject 3.9.1 +=============== + +Released 2021 Feb 27. + +Drivers +------- + +* Adapt to the latest ``pg8000``. + +* Protect ``getuser()`` - it can raise ``ImportError`` on w32 + due to absent of ``pwd`` module. + +Build +----- + +* Change URLs for ``oursql`` in ``extras_require`` in ``setup.py``. + Provide separate URLs for Python 2.7 and 3.4+. + +* Add ``mariadb`` in ``extras_require`` in ``setup.py``. + +CI +-- + +* For tests with Python 3.4 run ``tox`` under Python 3.5. + +Tests +----- + +* Refactor ``tox.ini``. + +SQLObject 3.9.0 +=============== + +Released 2020 Dec 15. + +Features +-------- + +* Add ``JSONCol``: a universal json column that converts simple Python objects + (None, bool, int, float, long, dict, list, str/unicode to/from JSON using + json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT`` + columns at backends, doesn't work with ``JSON`` columns. + +* Extend/fix support for ``DateTime`` from ``Zope``. + +* Drop support for very old version of ``mxDateTime`` + without ``mx.`` namespace. + +Drivers +------- + +* Support `mariadb `_. + +CI +-- + +* Run tests with Python 3.9 at Travis and AppVeyor. + +SQLObject 3.8.1 +=============== + +Released 2020 Oct 01. + +Documentation +------------- + +* Use conf.py options to exclude sqlmeta options. + +Tests +----- + +* Fix ``PyGreSQL`` version for Python 3.4. + +CI +-- + +* Run tests with Python 3.8 at AppVeyor. + +SQLObject 3.8.0 +=============== + +Released 7 Dec 2019. + +Features +-------- + +* Add driver ``supersqlite``. Not all tests are passing + so the driver isn't added to the list of default drivers. + +Minor features +-------------- + +* Improve sqlrepr'ing ``ALL/ANY/SOME()``: always put the expression + at the right side of the comparison operation. + +Bug fixes +--------- + +* Fixed a bug in cascade deletion/nullification. + +* Fixed a bug in ``PostgresConnection.columnsFromSchema``: + PostgreSQL 12 removed outdated catalog attribute + ``pg_catalog.pg_attrdef.adsrc``. + +* Fixed a bug working with microseconds in Time columns. + +CI +-- + +* Run tests with Python 3.8 at Travis CI. + +SQLObject 3.7.3 +=============== + +Released 22 Sep 2019. + +Bug fixes +--------- + +* Avoid excessive parentheses around ``ALL/ANY/SOME()``. + +Tests +----- + +* Add tests for cascade deletion. + +* Add tests for ``sqlbuilder.ALL/ANY/SOME()``. + +* Fix calls to ``pytest.mark.skipif`` - make conditions bool instead of str. + +* Fix module-level calls to ``pytest.mark.skip`` - add reasons. + +* Fix escape sequences ``'\%'`` -> ``'\\%'``. + +CI +-- + +* Reduce the number of virtual machines/containers: + one OS, one DB, one python version, many drivers per VM. + +* Fix sqlite test under Python 3.7+ at AppVeyor. + +SQLObject 3.7.2 +=============== + +Released 1 May 2019. + +Minor features +-------------- + +* Adapt Postgres exception handling to ``psycopg2`` version ``2.8``: + in the recent ``psycopg2`` errors are in ``psycopg2.errors`` module. + +* Removed RdbhostConnection: David Keeney and rdbhost seem to be unavailable + since 2017. + +SQLObject 3.7.1 +=============== + +Released 2 Feb 2019. + +Bug fixes +--------- + +* Fixed a unicode problem in the latest mysqlclient. + +Documentation +------------- + +* Exclude sqlmeta members from some of the api docs. + The inclusion of of these sqlmeta members in these files breaks + reproducible builds. + +Development +----------- + +* Source code was made flake8-clean using the latest flake8. + +CI +-- + +* Run tests with Python 3.7. + +SQLObject 3.7.0 +=============== + +Released 6 June 2018. + +Features +-------- + +* Add signals on commit and rollback; pull request by Scott Stahl. + +Bug fixes +--------- + +* Fix SSL-related parameters for MySQL-connector (connector uses + a different param style). Bug reported by Christophe Popov. + +Drivers +------- + +* Remove psycopg1. Driver ``psycopg`` is now just an alias for ``psycopg2``. + +Tests +----- + +* Install psycopg2 from `psycopg2-binary`_ package. + +.. _`psycopg2-binary`: https://pypi.org/project/psycopg2-binary/ + +SQLObject 3.6.0 +=============== + +Released 24 Feb 2018. + +Minor features +-------------- + +* Close cursors after using to free resources immediately + instead of waiting for gc. + +Bug fixes +--------- + +* Fix for TypeError using selectBy on a BLOBCol. PR by Michael S. Root. + +Drivers +------- + +* Extend support for oursql and Python 3 (requires our fork of the driver). + +* Fix cursor.arraysize - pymssql doesn't have arraysize. + +* Set timeout for ODBC with MSSQL. + +* Fix _setAutoCommit for MSSQL. + +Documentation +------------- + +* Document extras that are available for installation. + +Build +----- + +* Use ``python_version`` environment marker in ``setup.py`` to make + ``install_requires`` and ``extras_require`` declarative. This makes + the universal wheel truly universal. + +* Use ``python_requires`` keyword in ``setup.py``. + +SQLObject 3.5.0 +=============== + +Released 15 Nov 2017. + +Minor features +-------------- + +* Add Python3 special methods for division to SQLExpression. + Pull request by Michael S. Root. + +Drivers +------- + +* Add support for `pg8000 `_ + PostgreSQL driver. + +* Fix autoreconnect with pymysql driver. Contributed by Shailesh Mungikar. + +Documentation +------------- + +* Remove generated HTML from eggs/wheels (docs are installed into wrong + place). Generated docs are still included in the source distribution. + +Tests +----- + +* Add tests for PyGreSQL, py-postgresql and pg8000 at AppVeyor. + +* Fixed bugs in py-postgresql at AppVeyor. SQLObject requires + the latest version of the driver from our fork. + +SQLObject 3.4.0 +=============== + +Released 5 Aug 2017. + +Features +-------- + +* Python 2.6 is no longer supported. The minimal supported version is + Python 2.7. + +Drivers (work in progress) +-------------------------- + +* Encode binary values for py-postgresql driver. This fixes the + last remaining problems with the driver. + +* Encode binary values for PyGreSQL driver using the same encoding as for + py-postgresql driver. This fixes the last remaining problems with the driver. + + Our own encoding is needed because unescape_bytea(escape_bytea()) is not + idempotent. See the comment for PQunescapeBytea at + https://www.postgresql.org/docs/9.6/static/libpq-exec.html: + + This conversion is not exactly the inverse of PQescapeBytea, because the + string is not expected to be "escaped" when received from PQgetvalue. In + particular this means there is no need for string quoting considerations. + +* List all drivers in extras_require in setup.py. + +Minor features +-------------- + +* Use base64.b64encode/b64decode instead of deprecated + encodestring/decodestring. + +Tests +----- + +* Fix a bug with sqlite-memory: rollback transaction and close connection. + The solution was found by Dr. Neil Muller. + +* Use remove-old-files.py from ppu to cleanup pip cache + at Travis and AppVeyor. + +* Add test_csvimport.py more as an example how to use load_csv + from sqlobject.util.csvimport. + +SQLObject 3.3.0 +=============== + +Released 7 May 2017. + +Features +-------- + +* Support for Python 2.6 is declared obsolete and will be removed + in the next release. + +Minor features +-------------- + +* Convert scripts repository to devscripts subdirectory. + Some of thses scripts are version-dependent so it's better to have them + in the main repo. + +* Test for __nonzero__ under Python 2, __bool__ under Python 3 in BoolCol. + +Drivers (work in progress) +-------------------------- + +* Add support for PyODBC and PyPyODBC (pure-python ODBC DB API driver) for + MySQL, PostgreSQL and MS SQL. Driver names are ``pyodbc``, ``pypyodbc`` + or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). There are some problems + with pyodbc and many problems with pypyodbc. + +Documentation +------------- + +* Stop updating http://sqlobject.readthedocs.org/ - it's enough to have + http://sqlobject.org/ + +Tests +----- + +* Run tests at Travis CI and AppVeyor with Python 3.6, x86 and x64. + +* Stop running tests at Travis with Python 2.6. + +* Stop running tests at AppVeyor with pymssql - too many timeouts and + problems. + +SQLObject 3.2.0 +=============== + +Released 11 Mar 2017. + +Minor features +-------------- + +* Drop table name from ``VACUUM`` command in SQLiteConnection: SQLite + doesn't vacuum a single table and SQLite 3.15 uses the supplied name as + the name of the attached database to vacuum. + +* Remove ``driver`` keyword from RdbhostConnection as it allows one driver + ``rdbhdb``. + +* Add ``driver`` keyword for FirebirdConnection. Allowed values are 'fdb', + 'kinterbasdb' and 'pyfirebirdsql'. Default is to test 'fdb' and + 'kinterbasdb' in that order. pyfirebirdsql is supported but has problems. + +* Add ``driver`` keyword for MySQLConnection. Allowed values are 'mysqldb', + 'connector', 'connector-python', 'oursql' and 'pymysql'. Default is to + test for mysqldb only. + +* Add support for `MySQL Connector + `_ (pure python; `binary + packages `_ are not at + PyPI and hence are hard to install and test). + +* Add support for `oursql `_ MySQL + driver (only Python 2.6 and 2.7 until oursql author fixes Python 3 + compatibility). + +* Add support for `PyMySQL `_ - pure + python mysql interface). + +* Add parameter ``timeout`` for MSSQLConnection (usable only with pymssql + driver); timeouts are in seconds. + +* Remove deprecated ez_setup.py. + +Drivers (work in progress) +-------------------------- + +* Extend support for PyGreSQL driver. There are still some problems. + +* Add support for `py-postgresql + `_ PostgreSQL driver. There + are still problems with the driver. + +* Add support for `pyfirebirdsql + `_.There are still problems with + the driver. + +Bug fixes +--------- + +* Fix MSSQLConnection.columnsFromSchema: remove `(` and `)` from default + value. + +* Fix MSSQLConnection and SybaseConnection: insert default values into a table + with just one IDENTITY column. + +* Remove excessive NULLs from ``CREATE TABLE`` for MSSQL/Sybase. + +* Fix concatenation operator for MSSQL/Sybase (it's ``+``, not ``||``). + +* Fix MSSQLConnection.server_version() under Py3 (decode version to str). + +Documentation +------------- + +* The docs are now generated with Sphinx. + +* Move ``docs/LICENSE`` to the top-level directory so that Github + recognizes it. + +Tests +----- + +* Rename ``py.test`` -> ``pytest`` in tests and docs. + +* Great Renaming: fix ``pytest`` warnings by renaming ``TestXXX`` classes + to ``SOTestXXX`` to prevent ``pytest`` to recognize them as test classes. + +* Fix ``pytest`` warnings by converting yield tests to plain calls: yield + tests were deprecated in ``pytest``. + +* Tests are now run at CIs with Python 3.5. + +* Drop ``Circle CI``. + +* Run at Travis CI tests with Firebird backend (server version 2.5; + drivers fdb and firebirdsql). There are problems with tests. + +* Run tests at AppVeyor for windows testing. Run tests with MS SQL, + MySQL, Postgres and SQLite backends; use Python 2.7, 3.4 and 3.5, + x86 and x64. There are problems with MS SQL and MySQL. + +SQLObject 3.1.0 +=============== + +Released 16 Aug 2016. + +Features +-------- + +* Add UuidCol. + +* Add JsonbCol. Only for PostgreSQL. + Requires psycopg2 >= 2.5.4 and PostgreSQL >= 9.2. + +* Add JSONCol, a universal json column. + +* For Python >= 3.4 minimal FormEncode version is now 1.3.1. + +* If mxDateTime is in use, convert timedelta (returned by MySQL) to + mxDateTime.Time. + +Documentation +------------- + +* Developer's Guide is extended to explain SQLObject architecture + and how to create a new column type. + +* Fix URLs that can be found; remove missing links. + +* Rename reStructuredText files from \*.txt to \*.rst. + +Source code +----------- + +* Fix all `import *` using https://github.com/zestyping/star-destroyer. + +Tests +----- + +* Tests are now run at Circle CI. + +* Use pytest-cov for test coverage. Report test coverage + via coveralls.io and codecov.io. + +* Install mxDateTime to run date/time tests with it. + +SQLObject 3.0.0 +=============== + +Released 1 Jun 2016. + +Features +-------- + +* Support for Python 2 and Python 3 with one codebase! + (Python version >= 3.4 currently required.) + +Minor features +-------------- + +* PyDispatcher (>=2.0.4) was made an external dependency. + +Development +----------- + +* Source code was made flake8-clean. + +Documentation +------------- + +* Documentation is published at http://sqlobject.readthedocs.org/ in + Sphinx format. + +`Older news`__ + +.. __: News5.html + +.. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 + :target: https://sourceforge.net/projects/sqlobject + :class: noborder + :align: center + :height: 15 + :width: 80 + :alt: Get SQLObject at SourceForge.net. Fast, secure and Free Open Source software downloads From db162aa7542a1be03d8a3a5f93f17038d7979ead Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 26 Dec 2022 20:07:18 +0300 Subject: [PATCH 175/295] Docs(News): Add forgotten release date SQLObject 3.10.1 was released at 2022 Dec 22. [skip ci] --- docs/News.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index a0ebdf7f..230e7db8 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,8 @@ SQLObject (master) SQLObject 3.10.1 ================ +Released 2022 Dec 22. + Minor features -------------- From 423a0f74a5a995e6b1de1a9c861641ecfd836d7d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 18 Jul 2023 15:50:51 +0300 Subject: [PATCH 176/295] CI(GHActions): Install all Python and PyPy versions from `conda-forge` --- .github/workflows/run-tests.yaml | 10 +++++++--- devscripts/requirements/requirements.txt | 2 -- docs/News.rst | 5 +++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 31b170bc..60b41884 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -4,6 +4,8 @@ on: [push, pull_request] jobs: run-tests: + env: + not_in_conda: "[]" strategy: matrix: @@ -40,12 +42,13 @@ jobs: - uses: actions/checkout@v2 - uses: s-weigand/setup-conda@v1 with: + conda-channels: conda-forge python-version: ${{ matrix.python-version }} - if: ${{ runner.os == 'Linux' && matrix.python-version != '3.11' }} + if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - if: ${{ runner.os != 'Linux' || matrix.python-version == '3.11' }} + if: ${{ contains(fromJSON(env.not_in_conda), matrix.python-version) }} - name: Cache pip uses: actions/cache@v3 with: @@ -56,9 +59,10 @@ jobs: - name: Install dependencies run: | python --version + python -m ensurepip python -m pip install --upgrade pip setuptools wheel pip --version - pip install --upgrade virtualenv "tox < 4" + pip install --upgrade virtualenv "tox >= 3.15, < 4" - name: Set PYVER run: | import os, sys diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index f77d60a2..a419296d 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -1,5 +1,3 @@ ---install-option=-O2 - # DateTime from Zope DateTime diff --git a/docs/News.rst b/docs/News.rst index 230e7db8..507a370c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +CI +-- + +* Install all Python and PyPy versions from ``conda-forge``. + SQLObject 3.10.1 ================ From 79294e3d5d6f2d728093a873265d035496c9349f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Jul 2023 23:38:37 +0300 Subject: [PATCH 177/295] Feat(SQLBuilder): Add method `Alias.select()` --- ANNOUNCE.rst | 5 +++++ docs/News.rst | 5 +++++ sqlobject/sqlbuilder.py | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 0040aed7..3d251d9b 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -21,6 +21,11 @@ What's new in SQLObject Contributors for this release are +Minor features +-------------- + +* Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. + For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 507a370c..9a0a05af 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Minor features +-------------- + +* Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. + CI -- diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 9eabcf52..22118ffc 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -638,16 +638,54 @@ def __sqlrepr__(self, db): self.alias) +class AliasSQLMeta(): + def __init__(self, table, alias): + self.__table = table + self.__alias = alias + + def __getattr__(self, attr): + if attr.startswith('__'): + raise AttributeError + table = self.__table + if (attr == "table"): + return '%s %s' % (table.sqlmeta.table, self.__alias) + return getattr(table.sqlmeta, attr) + + class Alias(SQLExpression): def __init__(self, table, alias=None): self.q = AliasTable(table, alias) + def __getattr__(self, attr): + table = self.q.table + if (attr == "sqlmeta") and hasattr(table, "sqlmeta"): + alias = self.q.alias + return AliasSQLMeta(table, alias) + return getattr(table, attr) + def __sqlrepr__(self, db): return sqlrepr(self.q, db) def components(self): return [self.q] + def select(self, clause=None, clauseTables=None, + orderBy=NoDefault, limit=None, + lazyColumns=False, reversed=False, + distinct=False, connection=None, + join=None, forUpdate=False): + # Import here to avoid circular import + from .sresults import SelectResults + return SelectResults(self, clause, + clauseTables=clauseTables, + orderBy=orderBy, + limit=limit, + lazyColumns=lazyColumns, + reversed=reversed, + distinct=distinct, + connection=connection, + join=join, forUpdate=forUpdate) + class Union(SQLExpression): def __init__(self, *tables): From 0ecd7da093be2152e2da955004bd66003e3dad8f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 29 Jul 2023 00:08:16 +0300 Subject: [PATCH 178/295] Feat(SQLBuilder): Add detailed error message --- sqlobject/sqlbuilder.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sqlobject/sqlbuilder.py b/sqlobject/sqlbuilder.py index 22118ffc..f998c0a9 100644 --- a/sqlobject/sqlbuilder.py +++ b/sqlobject/sqlbuilder.py @@ -480,7 +480,8 @@ def __init__(self, tableName): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) return self.FieldClass(self.tableName, attr) def __sqlrepr__(self, db): @@ -502,7 +503,8 @@ def __init__(self, soClass): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) if attr == 'id': return self._getattrFromID(attr) elif attr in self.soClass.sqlmeta.columns: @@ -565,14 +567,16 @@ class TableSpace: def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) return self.TableClass(attr) class ConstantSpace: def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) return SQLConstant(attr) @@ -628,7 +632,8 @@ def __init__(self, table, alias=None): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) if self.table: attr = getattr(self.table.q, attr).fieldName return self.FieldClass(self.tableName, attr, self.alias, self) @@ -645,7 +650,8 @@ def __init__(self, table, alias): def __getattr__(self, attr): if attr.startswith('__'): - raise AttributeError + raise AttributeError("Attribute '%s' is forbidden in '%s'" % ( + attr, self.__class__.__name__)) table = self.__table if (attr == "table"): return '%s %s' % (table.sqlmeta.table, self.__alias) From a4ee6cdb15c8e253db0d81cd766396d66bfd2e61 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Jul 2023 23:54:08 +0300 Subject: [PATCH 179/295] Fix(SQLRelatedJoin): Fixed a bug when the table joins with itself In the resulting SQL two instances of the table must use different aliases. Fixes: #185. --- ANNOUNCE.rst | 9 ++++++- docs/News.rst | 7 ++++++ sqlobject/joins.py | 35 +++++++++++++++++--------- sqlobject/tests/test_SQLRelatedJoin.py | 29 ++++++++++++++++++++- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 3d251d9b..1b1914ee 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -19,13 +19,20 @@ I'm pleased to announce version 3.10.2, the first bugfix release of branch What's new in SQLObject ======================= -Contributors for this release are +The contributor for this release is Igor Yudytskiy. Minor features -------------- * Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. +Bug fixes +--------- + +* Fixed a bug in ``SQLRelatedJoin`` in the case where the table joins with + itself; in the resulting SQL two instances of the table must use different + aliases. Thanks to Igor Yudytskiy for providing an elaborated bug report. + For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 9a0a05af..3525ea25 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,13 @@ Minor features * Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. +Bug fixes +--------- + +* Fixed a bug in ``SQLRelatedJoin`` in the case where the table joins with + itself; in the resulting SQL two instances of the table must use different + aliases. + CI -- diff --git a/sqlobject/joins.py b/sqlobject/joins.py index e2c835a6..fa2b337c 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -298,11 +298,14 @@ def __init__(self, otherTable, otherIdName, interTable, joinColumn): self.joinColumn = joinColumn def tablesUsedImmediate(self): - return [self.otherTable, self.interTable] + return [ + '%s _SO_SQLRelatedJoin_OtherTable' % self.otherTable, + self.interTable, + ] def __sqlrepr__(self, db): - return '%s.%s = %s.%s' % (self.otherTable, self.otherIdName, - self.interTable, self.joinColumn) + return '_SO_SQLRelatedJoin_OtherTable.%s = %s.%s' % ( + self.otherIdName, self.interTable, self.joinColumn) class JoinToTable(sqlbuilder.SQLExpression): @@ -313,11 +316,14 @@ def __init__(self, table, idName, interTable, joinColumn): self.joinColumn = joinColumn def tablesUsedImmediate(self): - return [self.table, self.interTable] + return [ + '%s _SO_SQLRelatedJoin_ThisTable' % self.table, + self.interTable, + ] def __sqlrepr__(self, db): - return '%s.%s = %s.%s' % (self.interTable, self.joinColumn, self.table, - self.idName) + return '%s.%s = _SO_SQLRelatedJoin_ThisTable.%s' % ( + self.interTable, self.joinColumn, self.idName) class TableToId(sqlbuilder.SQLExpression): @@ -327,10 +333,11 @@ def __init__(self, table, idName, idValue): self.idValue = idValue def tablesUsedImmediate(self): - return [self.table] + return ['%s _SO_SQLRelatedJoin_ThisTable' % self.table] def __sqlrepr__(self, db): - return '%s.%s = %s' % (self.table, self.idName, self.idValue) + return '_SO_SQLRelatedJoin_ThisTable.%s = %s' % ( + self.idName, self.idValue) class SOSQLRelatedJoin(SORelatedJoin): @@ -339,7 +346,9 @@ def performJoin(self, inst): conn = inst._connection else: conn = None - results = self.otherClass.select(sqlbuilder.AND( + results = sqlbuilder.Alias( + self.otherClass, '_SO_SQLRelatedJoin_OtherTable' + ).select(sqlbuilder.AND( OtherTableToJoin( self.otherClass.sqlmeta.table, self.otherClass.sqlmeta.idName, self.intermediateTable, self.otherColumn @@ -350,9 +359,11 @@ def performJoin(self, inst): ), TableToId(self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, inst.id), - ), clauseTables=(self.soClass.sqlmeta.table, - self.otherClass.sqlmeta.table, - self.intermediateTable), + ), clauseTables=( + '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table, + '%s _SO_SQLRelatedJoin_OtherTable' % + self.otherClass.sqlmeta.table, + self.intermediateTable), connection=conn) return results.orderBy(self.orderBy) diff --git a/sqlobject/tests/test_SQLRelatedJoin.py b/sqlobject/tests/test_SQLRelatedJoin.py index 7620258f..5e235dde 100644 --- a/sqlobject/tests/test_SQLRelatedJoin.py +++ b/sqlobject/tests/test_SQLRelatedJoin.py @@ -1,5 +1,6 @@ import pytest -from sqlobject import RelatedJoin, SQLObject, SQLRelatedJoin, StringCol +from sqlobject import RelatedJoin, SQLObject, SQLRelatedJoin, StringCol, \ + ForeignKey from sqlobject.tests.dbtest import setupClass, supports @@ -62,3 +63,29 @@ def test_related_join_transaction(): finally: trans.commit(True) Tourtment._connection.autoCommit = True + + +class RecursiveGroup(SQLObject): + name = StringCol(length=255, unique=True) + subgroups = SQLRelatedJoin( + 'RecursiveGroup', + otherColumn='group_id', + intermediateTable='rec_group_map', + createRelatedTable=False, + ) + + +class RecGroupMap(SQLObject): + recursive_group = ForeignKey('RecursiveGroup') + group = ForeignKey('RecursiveGroup') + + +def test_rec_group(): + setupClass([RecursiveGroup, RecGroupMap]) + a = RecursiveGroup(name='a') + a1 = RecursiveGroup(name='a1') + a.addRecursiveGroup(a1) + a2 = RecursiveGroup(name='a2') + a.addRecursiveGroup(a2) + + assert sorted(a.subgroups, key=lambda x: x.name) == [a1, a2] From e628604d8aa2a796883a020abd3c52a54b477d8f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 9 Aug 2023 14:01:26 +0300 Subject: [PATCH 180/295] Release 3.10.2 --- ANNOUNCE.rst | 16 ++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- sqlobject/__version__.py | 4 ++-- 5 files changed, 11 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 1b1914ee..d5bdebc0 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,19 +1,7 @@ Hello! -I'm pleased to announce version 3.10.2a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.2, the first bugfix release of branch -3.10 of SQLObject. +I'm pleased to announce version 3.10.2, a minor feature release +and the second bugfix release of branch 3.10 of SQLObject. What's new in SQLObject diff --git a/README.rst b/README.rst index 3896cef6..e3ff798e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.2a0 -================== +SQLObject 3.10.2 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8da2c52b..d633b097 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.1 && +build_docs 3.10.2 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 3525ea25..5180fbc7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.2 +================ + +Released 2023 Aug 09. Minor features -------------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 7753d960..8bf191f3 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.1' +version = '3.10.2' major = 3 minor = 10 -micro = 1 +micro = 2 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 00ed0745fd94cf2a030083cc6d09c97a9fc5be22 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 9 Aug 2023 15:11:03 +0300 Subject: [PATCH 181/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 20 ++++++++++++++++---- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d5bdebc0..f6bb586e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,13 +1,25 @@ Hello! -I'm pleased to announce version 3.10.2, a minor feature release -and the second bugfix release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.3a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. + +I'm pleased to announce version 3.10.3, the first bugfix release of branch +3.10 of SQLObject. What's new in SQLObject ======================= -The contributor for this release is Igor Yudytskiy. +The contributors for this release are ... Thanks! Minor features -------------- @@ -51,7 +63,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.2a0.dev20221222/ +https://pypi.org/project/SQLObject/3.10.3a0.dev20230810/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index e3ff798e..3b336e9f 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.2 -================ +SQLObject 3.10.3a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index 5180fbc7..2d052000 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.2 ================ From 0d633b72642bace7da86a51470aca1044b82c808 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Sep 2023 19:32:32 +0300 Subject: [PATCH 182/295] CI(GHActions): Ensure `pip` only if needed This is to work around a problem in conda with Python 3.7 - it brings in wrong version of `setuptools` incompatible with Python 3.7. --- .github/workflows/run-tests.yaml | 2 +- docs/News.rst | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 60b41884..392147f2 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -59,7 +59,7 @@ jobs: - name: Install dependencies run: | python --version - python -m ensurepip + python -m pip || python -m ensurepip --default-pip --upgrade python -m pip install --upgrade pip setuptools wheel pip --version pip install --upgrade virtualenv "tox >= 3.15, < 4" diff --git a/docs/News.rst b/docs/News.rst index 2d052000..f37f366e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +CI +-- + +* GHActions: Ensure ``pip`` only if needed + + This is to work around a problem in conda with Python 3.7 - + it brings in wrong version of ``setuptools`` incompatible with Python 3.7. + SQLObject 3.10.2 ================ From ae1ca49def118ed7a0aa897e6613ef8563ef4d3f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 18 Sep 2023 02:29:36 +0300 Subject: [PATCH 183/295] Fix(SQLiteConnection): Clear `_threadOrigination` --- sqlobject/sqlite/sqliteconnection.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 06cf3c43..89635e36 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -181,6 +181,8 @@ def releaseConnection(self, conn, explicit=False): else: if self._pool and conn in self._pool: self._pool.remove(conn) + if threadid: + del self._threadOrigination[id(conn)] conn.close() def _setAutoCommit(self, conn, auto): @@ -214,6 +216,7 @@ def makeConnection(self): def close(self): DBAPI.close(self) self._threadPool = {} + self._threadOrigination = {} if self._memory: self._memoryConn.close() self.makeMemoryConnection() From a37239b87bfedd8bc72b62431412a9cf5a17e48e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 18 Sep 2023 19:36:16 +0300 Subject: [PATCH 184/295] Fix(SQLiteConnection): Release connections to fix memory leak Release connections from threads that are no longer active. This fixes memory leak in multithreaded programs in Windows. `SQLite` requires different connections per thread so `SQLiteConnection` creates and stores a connection per thread. When a thread finishes its connections should be closed. But if a program doesn't cooperate and doesn't close connections at the end of a thread SQLObject leaks memory as connection objects are stuck in `SQLiteConnection`. On Linux the leak is negligible as Linux reuses thread IDs so new connections replace old ones and old connections are garbage collected. But Windows doesn't reuse thread IDs so old connections pile and never released. To fix the problem `SQLiteConnection` now enumerates threads and releases connections from non-existing threads. Fixes: #186. --- docs/News.rst | 19 +++++++++++++++++++ sqlobject/sqlite/sqliteconnection.py | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index f37f366e..34aabe4f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,25 @@ News SQLObject (master) ================== +Drivers +------- + +* Fix(SQLiteConnection): Release connections from threads that are + no longer active. This fixes memory leak in multithreaded programs + in Windows. + + ``SQLite`` requires different connections per thread so + ``SQLiteConnection`` creates and stores a connection per thread. + When a thread finishes its connections should be closed. + But if a program doesn't cooperate and doesn't close connections at + the end of a thread SQLObject leaks memory as connection objects are + stuck in ``SQLiteConnection``. On Linux the leak is negligible as + Linux reuses thread IDs so new connections replace old ones and old + connections are garbage collected. But Windows doesn't reuse thread + IDs so old connections pile and never released. To fix the problem + ``SQLiteConnection`` now enumerates threads and releases connections + from non-existing threads. + CI -- diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 89635e36..80da75e2 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -4,6 +4,7 @@ from _thread import get_ident except ImportError: from thread import get_ident +from threading import enumerate as enumerate_threads try: from urllib import quote except ImportError: @@ -150,6 +151,7 @@ def getConnection(self): self._connectionNumbers[id(conn)] = self._connectionCount self._connectionCount += 1 return conn + self._releaseUnusedConnections() threadid = get_ident() if (self._pool is not None and threadid in self._threadPool): conn = self._threadPool[threadid] @@ -183,6 +185,7 @@ def releaseConnection(self, conn, explicit=False): self._pool.remove(conn) if threadid: del self._threadOrigination[id(conn)] + del self._threadPool[threadid] conn.close() def _setAutoCommit(self, conn, auto): @@ -213,6 +216,19 @@ def makeConnection(self): conn.text_factory = str # Convert text data to str, not unicode return conn + def _releaseUnusedConnections(self): + """Release connections from threads that're no longer active""" + thread_ids = set(t.ident for t in enumerate_threads()) + tp_set = set(self._threadPool) + unused_connections = [ + self._threadPool[tid] for tid in tp_set - thread_ids + ] + for unused_connection in unused_connections: + try: + self.releaseConnection(unused_connection, explicit=True) + except self.module.ProgrammingError: + pass # Ignore error in `conn.close()` from a different thread + def close(self): DBAPI.close(self) self._threadPool = {} From 8c2a92e206a4352c8cc4332f148a5566eadf3526 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:38:06 +0300 Subject: [PATCH 185/295] Build(devscripts): Delete `test-sqlobject.cmd` --- devscripts/test-sqlobject.cmd | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 devscripts/test-sqlobject.cmd diff --git a/devscripts/test-sqlobject.cmd b/devscripts/test-sqlobject.cmd deleted file mode 100644 index f227bf09..00000000 --- a/devscripts/test-sqlobject.cmd +++ /dev/null @@ -1,16 +0,0 @@ -@echo off - -SetLocal EnableDelayedExpansion -set SavePATH=%PATH% - -for %%V in (27 34 35 36 37 38 39 310 311) do ( - for %%s in (32 64) do ( - set PATH=C:\Python%%V-%%s;C:\Python%%V-%%s\Scripts;!SavePATH! - set TOXPYTHON=C:\Python%%V-%%s\python.exe - !TOXPYTHON! -m tox -e "py%%V-sqlite{-memory,}-w32" - if !ERRORLEVEL! EQU 0 (echo Ok) else (echo Error && goto Quit) - ) -) - -:Quit -set PATH=%SavePATH% From 633532ca1d2fc743cb64d2087359b8659a9bdb4a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:46:05 +0300 Subject: [PATCH 186/295] Style: Fix `flame8` warnings "invalid escape sequence" Make strings raw. --- sqlobject/firebird/firebirdconnection.py | 2 +- sqlobject/mssql/mssqlconnection.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sqlobject/firebird/firebirdconnection.py b/sqlobject/firebird/firebirdconnection.py index 4624b487..9c36f7af 100644 --- a/sqlobject/firebird/firebirdconnection.py +++ b/sqlobject/firebird/firebirdconnection.py @@ -11,7 +11,7 @@ class FirebirdConnection(DBAPI): dbName = 'firebird' schemes = [dbName] - limit_re = re.compile('^\s*(select )(.*)', re.IGNORECASE) + limit_re = re.compile(r'^\s*(select )(.*)', re.IGNORECASE) def __init__(self, host, db, port='3050', user='sysdba', password='masterkey', autoCommit=1, diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index b135fe44..9c179e93 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -10,7 +10,7 @@ class MSSQLConnection(DBAPI): dbName = 'mssql' schemes = [dbName] - limit_re = re.compile('^\s*(select )(.*)', re.IGNORECASE) + limit_re = re.compile(r'^\s*(select )(.*)', re.IGNORECASE) odbc_keywords = ('Server', 'Port', 'User Id', 'Password', 'Database') From 4faa6b208560bedd676e785839c0368b8a511887 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:53:39 +0300 Subject: [PATCH 187/295] Tests: Do not install `pendulum` for Python 3.12+ --- devscripts/requirements/requirements_tests.txt | 3 +++ tox.ini | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index d6a51173..b4390fd0 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -6,3 +6,6 @@ pytest < 5.0; python_version == '2.7' or python_version == '3.4' # https://github.com/pytest-dev/pytest/issues/9620 pytest < 7.0; python_version >= '3.5' + +pendulum < 2.1; python_version == '3.4' +pendulum; python_version == '2.7' or (python_version >= '3.5' and python_version <= '3.11') diff --git a/tox.ini b/tox.ini index 9d1bd95f..0b16290b 100644 --- a/tox.ini +++ b/tox.ini @@ -12,9 +12,7 @@ commands = {envpython} -m pytest --version deps = -rdevscripts/requirements/requirements_tests.txt - py34: pendulum < 2.1 py34: zope.datetime < 4.3 - !py34: pendulum !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient From ab2df13ad1841d8314d1325a1f2963d82041468b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 13:10:23 +0300 Subject: [PATCH 188/295] Drivers: Drop `supersqlite` --- ANNOUNCE.rst | 2 +- README.rst | 2 +- docs/News.rst | 3 +++ docs/SQLObject.rst | 7 +++---- docs/download.rst | 2 +- setup.py | 1 - sqlobject/sqlite/sqliteconnection.py | 9 +++------ tox.ini | 16 ---------------- 8 files changed, 12 insertions(+), 30 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index f6bb586e..216844c3 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -49,7 +49,7 @@ SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``, partially ``supersqlite``); connections to other backends +``pysqlite``); connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/README.rst b/README.rst index 3b336e9f..074d26ae 100644 --- a/README.rst +++ b/README.rst @@ -10,7 +10,7 @@ SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``, partially ``supersqlite``); connections to other backends +``pysqlite``); connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/docs/News.rst b/docs/News.rst index 34aabe4f..fe8c9f75 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -27,6 +27,9 @@ Drivers ``SQLiteConnection`` now enumerates threads and releases connections from non-existing threads. +* Dropped ``supersqlite``. It seems abandoned. + The last version 0.0.78 was released in 2018. + CI -- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 56f25415..cba7db16 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -50,7 +50,7 @@ Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, py-postgresql_ and pg8000_ -are supported; SQLite_ has a built-in driver, PySQLite_ or supersqlite_. +are supported; SQLite_ has a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) @@ -72,7 +72,6 @@ PostgreSQL and MSSQL but have problems (not all tests passed). .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ .. _PySQLite: https://github.com/ghaering/pysqlite -.. _supersqlite: https://github.com/plasticityai/supersqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ .. _fdb: http://www.firebirdsql.org/en/devel-python-driver/ .. _kinterbasdb: http://kinterbasdb.sourceforge.net/ @@ -1861,8 +1860,8 @@ multi-threaded environment. The user can choose a DB API driver for SQLite by using a ``driver`` parameter in DB URI or SQLiteConnection that can be a comma-separated list of driver names. Possible drivers are: ``pysqlite2`` (alias ``sqlite2``), -``sqlite3``, ``sqlite`` (alias ``sqlite1``), ``supersqlite``. Default is to -test supersqlite, pysqlite2, sqlite3 and sqlite in that order. +``sqlite3``, ``sqlite`` (alias ``sqlite1``). Default is to +test pysqlite2, sqlite3 and sqlite in that order. Connection-specific parameters are: ``encoding``, ``mode``, ``timeout``, ``check_same_thread``, ``use_table_info``. diff --git a/docs/download.rst b/docs/download.rst index 69069dd9..77f46159 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -79,7 +79,7 @@ pygresql pypostgresql py-postgresql pg8000 SQLite ^^^^^^ -sqlite pysqlite supersqlite +pysqlite sqlite The rest ^^^^^^^^ diff --git a/setup.py b/setup.py index db824658..d6a04e77 100755 --- a/setup.py +++ b/setup.py @@ -142,7 +142,6 @@ # 'sapdb': ['sapdb'], 'sqlite': ['pysqlite'], - 'supersqlite': ['supersqlite'], 'sybase': ['Sybase'], }, ) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 80da75e2..6285c44c 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -34,16 +34,13 @@ class SQLiteConnection(DBAPI): def __init__(self, filename, autoCommit=1, **kw): drivers = kw.pop('driver', None) or \ - 'supersqlite,pysqlite2,sqlite3,sqlite' + 'pysqlite2,sqlite3,sqlite' for driver in drivers.split(','): driver = driver.strip() if not driver: continue try: - if driver == 'supersqlite': - from supersqlite import sqlite3 as sqlite - self.using_sqlite2 = True - elif driver in ('sqlite2', 'pysqlite2'): + if driver in ('sqlite2', 'pysqlite2'): from pysqlite2 import dbapi2 as sqlite self.using_sqlite2 = True elif driver == 'sqlite3': @@ -55,7 +52,7 @@ def __init__(self, filename, autoCommit=1, **kw): else: raise ValueError( 'Unknown SQLite driver "%s", ' - 'expected supersqlite, pysqlite2, sqlite3 ' + 'expected pysqlite2, sqlite3 ' 'or sqlite' % driver) except ImportError: pass diff --git a/tox.ini b/tox.ini index 0b16290b..7a24ecc2 100644 --- a/tox.ini +++ b/tox.ini @@ -29,7 +29,6 @@ deps = pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc - supersqlite: supersqlite firebird-fdb: fdb firebirdsql: firebirdsql passenv = CI @@ -322,21 +321,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory] commands = {[sqlite-memory]commands} -[sqlite-supersqlite] -commands = - {[testenv]commands} - -rm -f /tmp/sqlobject_test.sqdb - -pytest -D "sqlite:///tmp/sqlobject_test.sqdb?driver=supersqlite&debug=1" - rm -f /tmp/sqlobject_test.sqdb - -[testenv:py27-sqlite-supersqlite] -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[sqlite-supersqlite]commands} - -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-supersqlite] -commands = {[sqlite-supersqlite]commands} - # Firebird database test environments [fdb] From 59a0894945676fd175d3c2206eefbdb7446be2bb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 11:43:37 +0300 Subject: [PATCH 189/295] Tests,CI: Python 3.12 --- .github/workflows/run-tests.yaml | 2 +- .../requirements_connector_python.txt | 3 +- .../requirements/requirements_tests.txt | 8 +-- docs/News.rst | 5 ++ setup.py | 1 + tox.ini | 70 +++++++++---------- 6 files changed, 46 insertions(+), 43 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 392147f2..3593f6a6 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] include: - os: ubuntu-latest os-name: Linux diff --git a/devscripts/requirements/requirements_connector_python.txt b/devscripts/requirements/requirements_connector_python.txt index e4bffe7a..0cee2ac1 100644 --- a/devscripts/requirements/requirements_connector_python.txt +++ b/devscripts/requirements/requirements_connector_python.txt @@ -7,5 +7,4 @@ mysql-connector-python <= 8.0.29, >= 8.0.13; python_version == '3.7' mysql-connector-python <= 8.0.29, >= 8.0.19; python_version == '3.8' mysql-connector-python <= 8.0.29, >= 8.0.24; python_version == '3.9' mysql-connector-python <= 8.0.29, >= 8.0.28; python_version == '3.10' -#mysql-connector-python >= 8.0.31; python_version >= '3.11' -mysql-connector-python == 8.0.29; python_version >= '3.11' +mysql-connector-python >= 8.0.29; python_version >= '3.11' diff --git a/devscripts/requirements/requirements_tests.txt b/devscripts/requirements/requirements_tests.txt index b4390fd0..c328e74a 100644 --- a/devscripts/requirements/requirements_tests.txt +++ b/devscripts/requirements/requirements_tests.txt @@ -1,11 +1,9 @@ -r requirements.txt +setuptools pytest < 5.0; python_version == '2.7' or python_version == '3.4' - -# Pytest 7.0 introduced a major bug; see -# https://github.com/pytest-dev/pytest/issues/9620 - -pytest < 7.0; python_version >= '3.5' +pytest < 7.0; python_version >= '3.5' and python_version <= '3.11' +pytest; python_version >= '3.12' pendulum < 2.1; python_version == '3.4' pendulum; python_version == '2.7' or (python_version >= '3.5' and python_version <= '3.11') diff --git a/docs/News.rst b/docs/News.rst index fe8c9f75..b7c8e233 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -30,6 +30,11 @@ Drivers * Dropped ``supersqlite``. It seems abandoned. The last version 0.0.78 was released in 2018. +Tests +----- + +* Run tests with Python 3.12. + CI -- diff --git a/setup.py b/setup.py index d6a04e77..b1dea834 100755 --- a/setup.py +++ b/setup.py @@ -63,6 +63,7 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index 7a24ecc2..caa5945c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10,11}-sqlite{,-memory},py{27,36,311}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10,11,12}-sqlite{,-memory},py{27,37,312}-flake8 # Base test environment settings [testenv] @@ -60,7 +60,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -76,7 +76,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -92,7 +92,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector] commands = {[mysql-connector]commands} [mysql-connector-python] @@ -108,7 +108,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-python]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-python{,-w32}] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-python{,-w32}] commands = {[mysql-connector-python]commands} [oursql] @@ -124,7 +124,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -140,7 +140,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -155,7 +155,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11}-mariadb] +[testenv:py3{6,7,8,9,10,11,12}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -172,7 +172,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -188,7 +188,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -205,7 +205,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg] commands = {[psycopg]commands} [pygresql] @@ -221,7 +221,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -236,7 +236,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -255,7 +255,7 @@ commands = [testenv:py3{4,5,6}-postgres-pg8000] commands = {[pg8000]commands} -[testenv:py3{7,8,9,10,11}-postgres-pg8000-noauto] +[testenv:py3{7,8,9,10,11,12}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -272,7 +272,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -288,7 +288,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -305,7 +305,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -318,7 +318,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory] commands = {[sqlite-memory]commands} @@ -336,7 +336,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11,12}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -352,12 +352,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11,12}-firebirdsql] commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39,310,311}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311,312}-flake8] changedir = ./ deps = flake8 @@ -383,7 +383,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -402,7 +402,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -421,7 +421,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pymysql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pymysql-w32] platform = win32 commands = {[pymysql-w32]commands} @@ -439,7 +439,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11,12}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -459,7 +459,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -479,7 +479,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -498,7 +498,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -517,7 +517,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -535,7 +535,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypostgresql-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -554,7 +554,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -574,7 +574,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -594,7 +594,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -611,7 +611,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -627,6 +627,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From e151c186e647aa111254eecbd900462933733984 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Oct 2023 16:53:52 +0300 Subject: [PATCH 190/295] Fix(SQLRelatedJoin): Relax aliasing Relaxed aliasing in `SQLRelatedJoin` introduced in 3.10.2 - aliasing is required only when the table joins with itself. When there're two tables to join aliasing prevents filtering -- wrong SQL is generated in `relJoinCol.filter(thisClass.q.column)`. --- docs/News.rst | 8 ++++ sqlobject/joins.py | 59 +++++++++++++++++--------- sqlobject/tests/test_SQLRelatedJoin.py | 27 +++++++++++- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index b7c8e233..e8ee45c4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +Bug fixes +--------- + +* Relaxed aliasing in ``SQLRelatedJoin`` introduced in 3.10.2 - aliasing + is required only when the table joins with itself. When there're two + tables to join aliasing prevents filtering -- wrong SQL is generated + in ``relJoinCol.filter(thisClass.q.column)``. + Drivers ------- diff --git a/sqlobject/joins.py b/sqlobject/joins.py index fa2b337c..34d9c59f 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -291,52 +291,63 @@ class RelatedJoin(MultipleJoin): class OtherTableToJoin(sqlbuilder.SQLExpression): - def __init__(self, otherTable, otherIdName, interTable, joinColumn): + def __init__(self, otherTable, otherIdName, interTable, joinColumn, alias): self.otherTable = otherTable self.otherIdName = otherIdName self.interTable = interTable self.joinColumn = joinColumn + self.alias = alias def tablesUsedImmediate(self): return [ - '%s _SO_SQLRelatedJoin_OtherTable' % self.otherTable, + '%s %s' % (self.otherTable, self.alias) + if self.alias else self.otherTable, self.interTable, ] def __sqlrepr__(self, db): - return '_SO_SQLRelatedJoin_OtherTable.%s = %s.%s' % ( + return '%s.%s = %s.%s' % ( + self.alias if self.alias else self.otherTable, self.otherIdName, self.interTable, self.joinColumn) class JoinToTable(sqlbuilder.SQLExpression): - def __init__(self, table, idName, interTable, joinColumn): + def __init__(self, table, idName, interTable, joinColumn, alias): self.table = table self.idName = idName self.interTable = interTable self.joinColumn = joinColumn + self.alias = alias def tablesUsedImmediate(self): return [ - '%s _SO_SQLRelatedJoin_ThisTable' % self.table, + '%s %s' % (self.table, self.alias) + if self.alias else self.table, self.interTable, ] def __sqlrepr__(self, db): - return '%s.%s = _SO_SQLRelatedJoin_ThisTable.%s' % ( - self.interTable, self.joinColumn, self.idName) + return '%s.%s = %s.%s' % ( + self.interTable, self.joinColumn, + self.alias if self.alias else self.table, self.idName) class TableToId(sqlbuilder.SQLExpression): - def __init__(self, table, idName, idValue): + def __init__(self, table, idName, idValue, alias): self.table = table self.idName = idName self.idValue = idValue + self.alias = alias def tablesUsedImmediate(self): - return ['%s _SO_SQLRelatedJoin_ThisTable' % self.table] + return [ + '%s %s' % (self.table, self.alias) + if self.alias else self.table, + ] def __sqlrepr__(self, db): - return '_SO_SQLRelatedJoin_ThisTable.%s = %s' % ( + return '%s.%s = %s' % ( + self.alias if self.alias else self.table, self.idName, self.idValue) @@ -346,23 +357,33 @@ def performJoin(self, inst): conn = inst._connection else: conn = None - results = sqlbuilder.Alias( - self.otherClass, '_SO_SQLRelatedJoin_OtherTable' - ).select(sqlbuilder.AND( + needAlias = self.soClass is self.otherClass + if needAlias: + source = sqlbuilder.Alias( + self.otherClass, '_SO_SQLRelatedJoin_OtherTable') + else: + source = self.otherClass + results = source.select(sqlbuilder.AND( OtherTableToJoin( self.otherClass.sqlmeta.table, self.otherClass.sqlmeta.idName, - self.intermediateTable, self.otherColumn + self.intermediateTable, self.otherColumn, + '_SO_SQLRelatedJoin_OtherTable' if needAlias else '', ), JoinToTable( self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - self.intermediateTable, self.joinColumn + self.intermediateTable, self.joinColumn, + '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + ), + TableToId( + self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, + inst.id, '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', ), - TableToId(self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - inst.id), ), clauseTables=( - '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table, + '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table + if needAlias else self.soClass.sqlmeta.table, '%s _SO_SQLRelatedJoin_OtherTable' % - self.otherClass.sqlmeta.table, + self.otherClass.sqlmeta.table + if needAlias else self.otherClass.sqlmeta.table, self.intermediateTable), connection=conn) return results.orderBy(self.orderBy) diff --git a/sqlobject/tests/test_SQLRelatedJoin.py b/sqlobject/tests/test_SQLRelatedJoin.py index 5e235dde..e7d7e414 100644 --- a/sqlobject/tests/test_SQLRelatedJoin.py +++ b/sqlobject/tests/test_SQLRelatedJoin.py @@ -1,6 +1,7 @@ import pytest from sqlobject import RelatedJoin, SQLObject, SQLRelatedJoin, StringCol, \ ForeignKey +from sqlobject.sqlbuilder import Alias from sqlobject.tests.dbtest import setupClass, supports @@ -24,7 +25,7 @@ def createAllTables(): setupClass(Tourtment) -def test_1(): +def createData(): createAllTables() # create some tourtments t1 = Tourtment(name='Tourtment #1') @@ -44,7 +45,11 @@ def test_1(): t2.addFighter(trunks) t3.addFighter(gohan) t3.addFighter(trunks) - # do some selects + return t1, t2, t3, gokou, vegeta, gohan, trunks + + +def test_1(): + t1, t2, t3, gokou, vegeta, gohan, trunks = createData() for i, j in zip(t1.fightersAsList, t1.fightersAsSResult): assert i is j assert len(t2.fightersAsList) == t2.fightersAsSResult.count() @@ -65,6 +70,15 @@ def test_related_join_transaction(): Tourtment._connection.autoCommit = True +def test_related_join_filter(): + t1, t2, t3, gokou, vegeta, gohan, trunks = createData() + filteredFighters = t1.fightersAsSResult.filter( + Fighter.q.name.startswith('go') + ).orderBy('id') + for i, j in zip(filteredFighters, [gokou, gohan]): + assert i is j + + class RecursiveGroup(SQLObject): name = StringCol(length=255, unique=True) subgroups = SQLRelatedJoin( @@ -89,3 +103,12 @@ def test_rec_group(): a.addRecursiveGroup(a2) assert sorted(a.subgroups, key=lambda x: x.name) == [a1, a2] + + # Please note this is a wrong result! + # Do not filter by the table, use alias. See the example below. + assert list( + a.subgroups.filter(RecursiveGroup.q.name == 'a1').orderBy('name') + ) == [a1, a2] + + rgroupAlias = Alias(RecursiveGroup, '_SO_SQLRelatedJoin_OtherTable') + assert list(a.subgroups.filter(rgroupAlias.q.name == 'a1')) == [a1] From 27d347f0d25f29fbd8245d860d387cc306398c42 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 19:16:19 +0300 Subject: [PATCH 191/295] Release 3.10.3 --- ANNOUNCE.rst | 65 ++++++++++++++++++++++++++------------- README.rst | 4 +-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++-- sqlobject/__version__.py | 4 +-- 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 216844c3..4b6d859d 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,37 +1,58 @@ Hello! -I'm pleased to announce version 3.10.3a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. +I'm pleased to announce version 3.10.3, the 3rd bugfix release of branch +3.10 of SQLObject. -I'm pleased to announce version 3.10.3a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. -I'm pleased to announce version 3.10.3b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.10.3rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. +The contributors for this release are +Igor Yudytskiy and shuffle (github.com/shuffleyxf). +Thanks! -I'm pleased to announce version 3.10.3, the first bugfix release of branch -3.10 of SQLObject. +Bug fixes +--------- +* Relaxed aliasing in ``SQLRelatedJoin`` introduced in 3.10.2 - aliasing + is required only when the table joins with itself. When there're two + tables to join aliasing prevents filtering -- wrong SQL is generated + in ``relJoinCol.filter(thisClass.q.column)``. -What's new in SQLObject -======================= +Drivers +------- -The contributors for this release are ... Thanks! +* Fix(SQLiteConnection): Release connections from threads that are + no longer active. This fixes memory leak in multithreaded programs + in Windows. -Minor features --------------- + ``SQLite`` requires different connections per thread so + ``SQLiteConnection`` creates and stores a connection per thread. + When a thread finishes its connections should be closed. + But if a program doesn't cooperate and doesn't close connections at + the end of a thread SQLObject leaks memory as connection objects are + stuck in ``SQLiteConnection``. On Linux the leak is negligible as + Linux reuses thread IDs so new connections replace old ones and old + connections are garbage collected. But Windows doesn't reuse thread + IDs so old connections pile and never released. To fix the problem + ``SQLiteConnection`` now enumerates threads and releases connections + from non-existing threads. -* Class ``Alias`` grows a method ``.select()`` to match ``SQLObject.select()``. +* Dropped ``supersqlite``. It seems abandoned. + The last version 0.0.78 was released in 2018. -Bug fixes ---------- +Tests +----- + +* Run tests with Python 3.12. + +CI +-- + +* GHActions: Ensure ``pip`` only if needed -* Fixed a bug in ``SQLRelatedJoin`` in the case where the table joins with - itself; in the resulting SQL two instances of the table must use different - aliases. Thanks to Igor Yudytskiy for providing an elaborated bug report. + This is to work around a problem in conda with Python 3.7 - + it brings in wrong version of ``setuptools`` incompatible with Python 3.7. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -63,7 +84,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.3a0.dev20230810/ +https://pypi.org/project/SQLObject/3.10.3 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 074d26ae..39ece0be 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.3a0 -================== +SQLObject 3.10.3 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index d633b097..4e7aaa5d 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.2 && +build_docs 3.10.3 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index e8ee45c4..dabc1938 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.10.3 +================ + +Released 2023 Oct 25. Bug fixes --------- diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 8bf191f3..c1c41ab7 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.2' +version = '3.10.3' major = 3 minor = 10 -micro = 2 +micro = 3 release_level = 'final' serial = 0 version_info = (major, minor, micro, release_level, serial) From 25e4fac9844618f54fdb3ecf8cf3114071b7ecf8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 19:23:36 +0300 Subject: [PATCH 192/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 60 ++++++++++++--------------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ 3 files changed, 19 insertions(+), 48 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 4b6d859d..c2d4289a 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,58 +1,26 @@ Hello! -I'm pleased to announce version 3.10.3, the 3rd bugfix release of branch -3.10 of SQLObject. - - -What's new in SQLObject -======================= - -The contributors for this release are -Igor Yudytskiy and shuffle (github.com/shuffleyxf). -Thanks! +I'm pleased to announce version 3.10.4a1, the first alpha of the upcoming +release of branch 3.10 of SQLObject. -Bug fixes ---------- +I'm pleased to announce version 3.10.4a2, the second alpha of the upcoming +release of branch 3.10 of SQLObject. -* Relaxed aliasing in ``SQLRelatedJoin`` introduced in 3.10.2 - aliasing - is required only when the table joins with itself. When there're two - tables to join aliasing prevents filtering -- wrong SQL is generated - in ``relJoinCol.filter(thisClass.q.column)``. +I'm pleased to announce version 3.10.4b1, the first beta of the upcoming +release of branch 3.10 of SQLObject. -Drivers -------- +I'm pleased to announce version 3.10.4rc1, the first release candidate +of the upcoming release of branch 3.10 of SQLObject. -* Fix(SQLiteConnection): Release connections from threads that are - no longer active. This fixes memory leak in multithreaded programs - in Windows. - - ``SQLite`` requires different connections per thread so - ``SQLiteConnection`` creates and stores a connection per thread. - When a thread finishes its connections should be closed. - But if a program doesn't cooperate and doesn't close connections at - the end of a thread SQLObject leaks memory as connection objects are - stuck in ``SQLiteConnection``. On Linux the leak is negligible as - Linux reuses thread IDs so new connections replace old ones and old - connections are garbage collected. But Windows doesn't reuse thread - IDs so old connections pile and never released. To fix the problem - ``SQLiteConnection`` now enumerates threads and releases connections - from non-existing threads. - -* Dropped ``supersqlite``. It seems abandoned. - The last version 0.0.78 was released in 2018. - -Tests ------ +I'm pleased to announce version 3.10.4, the fourth bugfix release of branch +3.10 of SQLObject. -* Run tests with Python 3.12. -CI --- +What's new in SQLObject +======================= -* GHActions: Ensure ``pip`` only if needed +The contributors for this release are ... Thanks! - This is to work around a problem in conda with Python 3.7 - - it brings in wrong version of ``setuptools`` incompatible with Python 3.7. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -84,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.3 +https://pypi.org/project/SQLObject/3.10.4a0.dev20231025/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 39ece0be..e6db9d4a 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.10.3 -================ +SQLObject 3.10.4a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index dabc1938..c6a01e48 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.10.3 ================ From 15bda4c25923597b0371b5af50d42c4db78fb206 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 22:33:53 +0300 Subject: [PATCH 193/295] Build(devscripts): Feat `prerelease`: set trove classifier [skip ci] --- devscripts/prerelease | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/devscripts/prerelease b/devscripts/prerelease index dd788c6f..196e9d7e 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -22,5 +22,18 @@ micro = $micro release_level = '$state' serial = $serial version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && + +if [ "$state" = alpha ]; then + trove_cls='3 - Alpha' +elif [ "$state" = beta -o "$state" = 'release candidate' ]; then + trove_cls='4 - Beta' +elif [ "$state" = final -o "$state" = post ]; then + trove_cls='5 - Production/Stable' +else + echo "Error: unknown state $state" >&2 + exit 1 +fi && +sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && + `git var GIT_EDITOR` devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py && exec git commit --message="Release $tag" devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py From d07860bdf349573c993da82f5b154f7e67dbd1d6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Oct 2023 23:52:47 +0300 Subject: [PATCH 194/295] Build(devscripts): Feat `prerelease`: Set version in `README.rst` [skip ci] --- devscripts/prerelease | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/devscripts/prerelease b/devscripts/prerelease index 196e9d7e..f3f5c219 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -23,6 +23,11 @@ release_level = '$state' serial = $serial version_info = (major, minor, micro, release_level, serial)" > sqlobject/__version__.py && +sqlo_tag="SQLObject $tag" && +sqlo_tag_len=${#sqlo_tag} && +sed -Ei "1s/^SQLObject [1-9].+\$/$sqlo_tag/" README.rst && +sed -Ei "2s/^==========+\$/`python -c \"print('='*$sqlo_tag_len)\"`/" README.rst && + if [ "$state" = alpha ]; then trove_cls='3 - Alpha' elif [ "$state" = beta -o "$state" = 'release candidate' ]; then From 99e0d142b7d00f3f3232aa9ce21de1a764117dba Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Oct 2023 13:59:03 +0300 Subject: [PATCH 195/295] Refactor(SOSQLRelatedJoin): Pass `orderBy` right in `SelectResults.clone()` copies a lot. It's more efficient to pass all arguments at once. --- sqlobject/joins.py | 51 ++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/sqlobject/joins.py b/sqlobject/joins.py index 34d9c59f..85cdf878 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -363,30 +363,37 @@ def performJoin(self, inst): self.otherClass, '_SO_SQLRelatedJoin_OtherTable') else: source = self.otherClass - results = source.select(sqlbuilder.AND( - OtherTableToJoin( - self.otherClass.sqlmeta.table, self.otherClass.sqlmeta.idName, - self.intermediateTable, self.otherColumn, - '_SO_SQLRelatedJoin_OtherTable' if needAlias else '', + results = source.select( + sqlbuilder.AND( + OtherTableToJoin( + self.otherClass.sqlmeta.table, + self.otherClass.sqlmeta.idName, + self.intermediateTable, self.otherColumn, + '_SO_SQLRelatedJoin_OtherTable' if needAlias else '', + ), + JoinToTable( + self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, + self.intermediateTable, self.joinColumn, + '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + ), + TableToId( + self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, + inst.id, + '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + ), ), - JoinToTable( - self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - self.intermediateTable, self.joinColumn, - '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', + clauseTables=( + '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table + if needAlias else self.soClass.sqlmeta.table, + '%s _SO_SQLRelatedJoin_OtherTable' % + self.otherClass.sqlmeta.table + if needAlias else self.otherClass.sqlmeta.table, + self.intermediateTable, ), - TableToId( - self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, - inst.id, '_SO_SQLRelatedJoin_ThisTable' if needAlias else '', - ), - ), clauseTables=( - '%s _SO_SQLRelatedJoin_ThisTable' % self.soClass.sqlmeta.table - if needAlias else self.soClass.sqlmeta.table, - '%s _SO_SQLRelatedJoin_OtherTable' % - self.otherClass.sqlmeta.table - if needAlias else self.otherClass.sqlmeta.table, - self.intermediateTable), - connection=conn) - return results.orderBy(self.orderBy) + connection=conn, + orderBy=self.orderBy, + ) + return results class SQLRelatedJoin(RelatedJoin): From 391d4b180bd8493bc75cec97cf0b972586c74fcc Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Oct 2023 16:06:33 +0300 Subject: [PATCH 196/295] Refactor(SOSQLRelatedJoin): Directly use `SelectResults` --- sqlobject/joins.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlobject/joins.py b/sqlobject/joins.py index 85cdf878..de479e7e 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -363,7 +363,8 @@ def performJoin(self, inst): self.otherClass, '_SO_SQLRelatedJoin_OtherTable') else: source = self.otherClass - results = source.select( + results = self.otherClass.SelectResultsClass( + source, sqlbuilder.AND( OtherTableToJoin( self.otherClass.sqlmeta.table, From b29ab6e30703a0458a72e01262ff903e539356c5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 28 Oct 2023 16:39:25 +0300 Subject: [PATCH 197/295] Feat(SOSQLRelatedJoin): Raise error for filter without alias Closes: #187. --- docs/News.rst | 8 ++++++++ sqlobject/joins.py | 21 ++++++++++++++++++++- sqlobject/tests/test_SQLRelatedJoin.py | 10 +++++----- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index c6a01e48..20213a34 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,14 @@ News SQLObject (master) ================== +Features +-------- + +* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. + When a table joins with itself calling + ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` + hinting that an alias is required for filtering. + SQLObject 3.10.3 ================ diff --git a/sqlobject/joins.py b/sqlobject/joins.py index de479e7e..948d04d3 100644 --- a/sqlobject/joins.py +++ b/sqlobject/joins.py @@ -2,6 +2,7 @@ from . import boundattributes from . import classregistry from . import events +from . import sresults from . import styles from . import sqlbuilder from .styles import capword @@ -351,6 +352,21 @@ def __sqlrepr__(self, db): self.idName, self.idValue) +class SQLJoinSelectResults(sresults.SelectResults): + def filter(self, filter_clause): + clause_tables = filter_clause.tablesUsed(None) + if self._SOSQLRelatedJoin_realSourceClass.sqlmeta.table \ + in clause_tables: + tableClass = self._SOSQLRelatedJoin_realSourceClass.__name__ + raise ValueError( + "Using table '%s' in the filter expression without an alias " + "could produce wrong SQL. Most probably you need " + "Alias(%s, '_SO_SQLRelatedJoin_OtherTable') instead." + % (tableClass, tableClass) + ) + return sresults.SelectResults.filter(self, filter_clause) + + class SOSQLRelatedJoin(SORelatedJoin): def performJoin(self, inst): if inst.sqlmeta._perConnection: @@ -361,9 +377,11 @@ def performJoin(self, inst): if needAlias: source = sqlbuilder.Alias( self.otherClass, '_SO_SQLRelatedJoin_OtherTable') + sresultsClass = SQLJoinSelectResults else: source = self.otherClass - results = self.otherClass.SelectResultsClass( + sresultsClass = self.otherClass.SelectResultsClass + results = sresultsClass( source, sqlbuilder.AND( OtherTableToJoin( @@ -394,6 +412,7 @@ def performJoin(self, inst): connection=conn, orderBy=self.orderBy, ) + results._SOSQLRelatedJoin_realSourceClass = self.otherClass return results diff --git a/sqlobject/tests/test_SQLRelatedJoin.py b/sqlobject/tests/test_SQLRelatedJoin.py index e7d7e414..babd9f6b 100644 --- a/sqlobject/tests/test_SQLRelatedJoin.py +++ b/sqlobject/tests/test_SQLRelatedJoin.py @@ -104,11 +104,11 @@ def test_rec_group(): assert sorted(a.subgroups, key=lambda x: x.name) == [a1, a2] - # Please note this is a wrong result! - # Do not filter by the table, use alias. See the example below. - assert list( - a.subgroups.filter(RecursiveGroup.q.name == 'a1').orderBy('name') - ) == [a1, a2] + pytest.raises( + ValueError, + a.subgroups.filter, + RecursiveGroup.q.name == 'a1', + ) rgroupAlias = Alias(RecursiveGroup, '_SO_SQLRelatedJoin_OtherTable') assert list(a.subgroups.filter(rgroupAlias.q.name == 'a1')) == [a1] From c830a55eb4bb55521b5393acfac099c4c6e110c0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Oct 2023 14:35:24 +0300 Subject: [PATCH 198/295] Feat: `idType` must be either `int` or `str` --- docs/News.rst | 2 ++ docs/SQLObject.rst | 5 +++-- sqlobject/main.py | 3 +++ sqlobject/mysql/mysqlconnection.py | 5 ++++- sqlobject/sqlite/sqliteconnection.py | 5 ++++- sqlobject/tests/test_basic.py | 10 ++++++++++ 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 20213a34..66bc112f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,8 @@ Features ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` hinting that an alias is required for filtering. +* Test that ``idType`` is either ``int`` or ``str``. + SQLObject 3.10.3 ================ diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index cba7db16..e2350d79 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -764,8 +764,9 @@ values are: is ``id``. `idType`: - A function that coerces/normalizes IDs when setting IDs. This - is ``int`` by default (all IDs are normalized to integers). + A type that coerces/normalizes IDs when setting IDs. Must be ``int`` + or ``str``. This is ``int`` by default (all IDs are normalized to + integers). `style`: A style object -- this object allows you to use other algorithms diff --git a/sqlobject/main.py b/sqlobject/main.py index 827db2cd..c0f8a881 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -268,6 +268,9 @@ def send(cls, signal, *args, **kw): @classmethod def setClass(cls, soClass): + if cls.idType not in (int, str): + raise TypeError('sqlmeta.idType must be int or str, not %r' + % cls.idType) cls.soClass = soClass if not cls.style: cls.style = styles.defaultStyle diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 76b11724..b1ab6c24 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -359,8 +359,11 @@ def createIndexSQL(self, soClass, index): return index.mysqlCreateIndexSQL(soClass) def createIDColumn(self, soClass): - if soClass.sqlmeta.idType == str: + if soClass.sqlmeta.idType is str: return '%s TEXT PRIMARY KEY' % soClass.sqlmeta.idName + if soClass.sqlmeta.idType is not int: + raise TypeError('sqlmeta.idType must be int or str, not %r' + % soClass.sqlmeta.idType) return '%s INT PRIMARY KEY AUTO_INCREMENT' % soClass.sqlmeta.idName def joinSQLType(self, join): diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index 6285c44c..d6df5c58 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -311,8 +311,11 @@ def createIDColumn(self, soClass): return self._createIDColumn(soClass.sqlmeta) def _createIDColumn(self, sqlmeta): - if sqlmeta.idType == str: + if sqlmeta.idType is str: return '%s TEXT PRIMARY KEY' % sqlmeta.idName + if sqlmeta.idType is not int: + raise TypeError('sqlmeta.idType must be int or str, not %r' + % sqlmeta.idType) return '%s INTEGER PRIMARY KEY AUTOINCREMENT' % sqlmeta.idName def joinSQLType(self, join): diff --git a/sqlobject/tests/test_basic.py b/sqlobject/tests/test_basic.py index d9d1a2e4..12dff999 100644 --- a/sqlobject/tests/test_basic.py +++ b/sqlobject/tests/test_basic.py @@ -337,3 +337,13 @@ class SOTestSO13(SQLObject): assert SOTestSO13._connection.uri() == 'sqlite:///db2' del sqlhub.processConnection + + +def _test_wrong_sqlmeta_idType(): + class SOTestSO13(SQLObject): + class sqlmeta: + idType = dict + + +def test_wrong_sqlmeta_idType(): + pytest.raises(TypeError, _test_wrong_sqlmeta_idType) From a0459c0f93bdd0bda61a172ed8e717e2a239b7d2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Oct 2023 15:16:52 +0300 Subject: [PATCH 199/295] Feat: `sqlmeta.idSize` to set `id` size --- docs/News.rst | 7 +++++++ docs/SQLObject.rst | 7 +++++++ sqlobject/main.py | 5 +++++ sqlobject/mysql/mysqlconnection.py | 11 ++++++++++- sqlobject/postgres/pgconnection.py | 17 ++++++++++++++++- sqlobject/tests/test_basic.py | 10 ++++++++++ sqlobject/tests/test_mysql.py | 10 ++++++++++ sqlobject/tests/test_postgres.py | 10 ++++++++++ 8 files changed, 75 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 66bc112f..d644a2d4 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -18,6 +18,13 @@ Features * Test that ``idType`` is either ``int`` or ``str``. +* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` + for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, + ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres + mapped to ``smallserial``/``serial``/``bigserial``. For other backends + it's currently ignored. Feature request by Meet Gujrathi at + https://stackoverflow.com/q/77360075/7976758 + SQLObject 3.10.3 ================ diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index e2350d79..e67aea23 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -768,6 +768,13 @@ values are: or ``str``. This is ``int`` by default (all IDs are normalized to integers). +`idSize`: + This sets the size of integer column ``id`` for MySQL and PostgreSQL. + Allowed values are ``'TINY'``, ``'SMALL'``, ``'MEDIUM'``, ``'BIG'``, + ``None``; default is ``None``. For Postgres mapped to + ``smallserial``/``serial``/``bigserial``. For other backends it's + currently ignored. + `style`: A style object -- this object allows you to use other algorithms for translating between Python attribute and class names, and the diff --git a/sqlobject/main.py b/sqlobject/main.py index c0f8a881..7d2fd1c3 100644 --- a/sqlobject/main.py +++ b/sqlobject/main.py @@ -190,6 +190,7 @@ class sqlmeta(with_metaclass(declarative.DeclarativeMeta, object)): table = None idName = None + idSize = None # Allowed values are 'TINY/SMALL/MEDIUM/BIG/None' idSequence = None # This function is used to coerce IDs into the proper format, # so you should replace it with str, or another function, if you @@ -271,6 +272,10 @@ def setClass(cls, soClass): if cls.idType not in (int, str): raise TypeError('sqlmeta.idType must be int or str, not %r' % cls.idType) + if cls.idSize not in ('TINY', 'SMALL', 'MEDIUM', 'BIG', None): + raise ValueError( + "sqlmeta.idType must be 'TINY', 'SMALL', 'MEDIUM', 'BIG' " + "or None, not %r" % cls.idSize) cls.soClass = soClass if not cls.style: cls.style = styles.defaultStyle diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index b1ab6c24..1fcf0a7b 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -364,7 +364,16 @@ def createIDColumn(self, soClass): if soClass.sqlmeta.idType is not int: raise TypeError('sqlmeta.idType must be int or str, not %r' % soClass.sqlmeta.idType) - return '%s INT PRIMARY KEY AUTO_INCREMENT' % soClass.sqlmeta.idName + if soClass.sqlmeta.idSize is None: + mysql_int_type = 'INT' + elif soClass.sqlmeta.idSize in ('TINY', 'SMALL', 'MEDIUM', 'BIG'): + mysql_int_type = '%sINT' % soClass.sqlmeta.idSize + else: + raise ValueError( + "sqlmeta.idSize must be 'TINY', 'SMALL', 'MEDIUM', 'BIG' " + "or None, not %r" % soClass.sqlmeta.idSize) + return '%s %s PRIMARY KEY AUTO_INCREMENT' \ + % (soClass.sqlmeta.idName, mysql_int_type) def joinSQLType(self, join): return 'INT NOT NULL' diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 722f3d4e..5bc6778d 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -341,7 +341,22 @@ def createIndexSQL(self, soClass, index): return index.postgresCreateIndexSQL(soClass) def createIDColumn(self, soClass): - key_type = {int: "SERIAL", str: "TEXT"}[soClass.sqlmeta.idType] + if soClass.sqlmeta.idType is int: + if soClass.sqlmeta.idSize in ('TINY', 'SMALL'): + key_type = 'SMALLSERIAL' + elif soClass.sqlmeta.idSize in ('MEDIUM', None): + key_type = 'SERIAL' + elif soClass.sqlmeta.idSize == 'BIG': + key_type = 'BIGSERIAL' + else: + raise ValueError( + "sqlmeta.idSize must be 'TINY', 'SMALL', 'MEDIUM', 'BIG' " + "or None, not %r" % soClass.sqlmeta.idSize) + elif soClass.sqlmeta.idType is str: + key_type = "TEXT" + else: + raise TypeError('sqlmeta.idType must be int or str, not %r' + % soClass.sqlmeta.idType) return '%s %s PRIMARY KEY' % (soClass.sqlmeta.idName, key_type) def dropTable(self, tableName, cascade=False): diff --git a/sqlobject/tests/test_basic.py b/sqlobject/tests/test_basic.py index 12dff999..361bf935 100644 --- a/sqlobject/tests/test_basic.py +++ b/sqlobject/tests/test_basic.py @@ -347,3 +347,13 @@ class sqlmeta: def test_wrong_sqlmeta_idType(): pytest.raises(TypeError, _test_wrong_sqlmeta_idType) + + +def _test_wrong_sqlmeta_idSize(): + class SOTestSO14(SQLObject): + class sqlmeta: + idSize = 'DEFAULT' + + +def test_wrong_sqlmeta_idSize(): + pytest.raises(ValueError, _test_wrong_sqlmeta_idSize) diff --git a/sqlobject/tests/test_mysql.py b/sqlobject/tests/test_mysql.py index 5f41bd96..5a15aca0 100644 --- a/sqlobject/tests/test_mysql.py +++ b/sqlobject/tests/test_mysql.py @@ -38,3 +38,13 @@ def test_ANY(): SOTestANY(value=30) assert len(list(SOTestANY.select( SOTestANY.q.value > ANY(Select([SOTestANY.q.value]))))) == 2 + + +class SOTestMySQLidSize(SQLObject): + class sqlmeta: + idSize = 'BIG' + + +def test_idSize(): + assert 'id BIGINT PRIMARY KEY AUTO_INCREMENT' \ + in SOTestMySQLidSize.createTableSQL(connection=connection)[0] diff --git a/sqlobject/tests/test_postgres.py b/sqlobject/tests/test_postgres.py index dbe62c04..037a78a8 100644 --- a/sqlobject/tests/test_postgres.py +++ b/sqlobject/tests/test_postgres.py @@ -70,3 +70,13 @@ def test_SOME(): SOTestSOME(value=30) assert len(list(SOTestSOME.select( SOTestSOME.q.value > SOME(Select([SOTestSOME.q.value]))))) == 2 + + +class SOTestPgidSize(SQLObject): + class sqlmeta: + idSize = 'BIG' + + +def test_idSize(): + assert 'id BIGSERIAL PRIMARY KEY' \ + in SOTestPgidSize.createTableSQL(connection=connection)[0] From ee9624c5f76e5458876cd624fae9010ac4ad32b4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 4 Nov 2023 14:45:56 +0300 Subject: [PATCH 200/295] Release 3.11.0b1 --- ANNOUNCE.rst | 34 ++++++++++++++++++---------------- README.rst | 2 +- setup.py | 2 +- sqlobject/__version__.py | 10 +++++----- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index c2d4289a..9677b854 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,28 @@ Hello! -I'm pleased to announce version 3.10.4a1, the first alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4a2, the second alpha of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4b1, the first beta of the upcoming -release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4rc1, the first release candidate -of the upcoming release of branch 3.10 of SQLObject. - -I'm pleased to announce version 3.10.4, the fourth bugfix release of branch -3.10 of SQLObject. +I'm pleased to announce version 3.11.0b1, the first beta of the upcoming +release of branch 3.11 of SQLObject. What's new in SQLObject ======================= -The contributors for this release are ... Thanks! +Features +-------- + +* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. + When a table joins with itself calling + ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` + hinting that an alias is required for filtering. + +* Test that ``idType`` is either ``int`` or ``str``. +* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` + for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, + ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres + mapped to ``smallserial``/``serial``/``bigserial``. For other backends + it's currently ignored. Feature request by Meet Gujrathi at + https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +54,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.10.4a0.dev20231025/ +https://pypi.org/project/SQLObject/3.11.0b1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index e6db9d4a..1ac14c48 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.10.4a0 +SQLObject 3.11.0b1 ================== SQLObject is a free and open-source (LGPL) Python object-relational diff --git a/setup.py b/setup.py index b1dea834..cf98bf0d 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index c1c41ab7..eb595220 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.10.3' +version = '3.11.0b1' major = 3 -minor = 10 -micro = 3 -release_level = 'final' -serial = 0 +minor = 11 +micro = 0 +release_level = 'beta' +serial = 1 version_info = (major, minor, micro, release_level, serial) From 2dddc9e4d9421f1b4dc8f438c96cdd24567a4864 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 4 Nov 2023 14:54:29 +0300 Subject: [PATCH 201/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9677b854..d29e8755 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,26 @@ Hello! +I'm pleased to announce version 3.11.0a1, the first alpha of the upcoming +release of branch 3.11 of SQLObject. + +I'm pleased to announce version 3.11.0a2, the second alpha of the upcoming +release of branch 3.11 of SQLObject. + I'm pleased to announce version 3.11.0b1, the first beta of the upcoming release of branch 3.11 of SQLObject. +I'm pleased to announce version 3.11.0rc1, the first release candidate +of the upcoming release of branch 3.11 of SQLObject. -What's new in SQLObject -======================= +I'm pleased to announce version 3.11.0, the fourth bugfix release of branch +3.11 of SQLObject. -Features --------- -* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. - When a table joins with itself calling - ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` - hinting that an alias is required for filtering. +What's new in SQLObject +======================= -* Test that ``idType`` is either ``int`` or ``str``. +The contributors for this release are ... Thanks! -* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` - for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, - ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres - mapped to ``smallserial``/``serial``/``bigserial``. For other backends - it's currently ignored. Feature request by Meet Gujrathi at - https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.0b1 +https://pypi.org/project/SQLObject/3.11.0a0.dev20231105/ News and changes: http://sqlobject.org/News.html From bcc6084516541c73dd8b2e467e30b4ff7118ea82 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:05:59 +0300 Subject: [PATCH 202/295] Build(devscripts/prerelease): Fix replace expression Escape a slash. [skip ci] --- devscripts/prerelease | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/prerelease b/devscripts/prerelease index f3f5c219..53e8956d 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -33,7 +33,7 @@ if [ "$state" = alpha ]; then elif [ "$state" = beta -o "$state" = 'release candidate' ]; then trove_cls='4 - Beta' elif [ "$state" = final -o "$state" = post ]; then - trove_cls='5 - Production/Stable' + trove_cls='5 - Production\/Stable' else echo "Error: unknown state $state" >&2 exit 1 From cc185d98ac00892335778446c5f554a16e9122dd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:05:53 +0300 Subject: [PATCH 203/295] Release 3.11.0 --- ANNOUNCE.rst | 34 ++++++++++++++++++---------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 4 ++-- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d29e8755..fbb6112a 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,28 @@ Hello! -I'm pleased to announce version 3.11.0a1, the first alpha of the upcoming -release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0a2, the second alpha of the upcoming -release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0b1, the first beta of the upcoming -release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0rc1, the first release candidate -of the upcoming release of branch 3.11 of SQLObject. - -I'm pleased to announce version 3.11.0, the fourth bugfix release of branch -3.11 of SQLObject. +I'm pleased to announce version 3.11.0, the first stable release +of branch 3.11 of SQLObject. What's new in SQLObject ======================= -The contributors for this release are ... Thanks! +Features +-------- + +* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. + When a table joins with itself calling + ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` + hinting that an alias is required for filtering. + +* Test that ``idType`` is either ``int`` or ``str``. +* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` + for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, + ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres + mapped to ``smallserial``/``serial``/``bigserial``. For other backends + it's currently ignored. Feature request by Meet Gujrathi at + https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +54,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.0a0.dev20231105/ +https://pypi.org/project/SQLObject/3.11.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 1ac14c48..8e895397 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.11.0b1 -================== +SQLObject 3.11.0 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 4e7aaa5d..63d78c2b 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.10.3 && +build_docs 3.11.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index d644a2d4..e5aa90e6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,8 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.11.0 +================ Features -------- diff --git a/setup.py b/setup.py index cf98bf0d..b1dea834 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index eb595220..19a73b78 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.11.0b1' +version = '3.11.0' major = 3 minor = 11 micro = 0 -release_level = 'beta' -serial = 1 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From c714f55a9aa4990020711494d2d3911faf9566c4 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:13:36 +0300 Subject: [PATCH 204/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 34 ++++++++++++++++------------------ README.rst | 4 ++-- docs/News.rst | 5 +++++ setup.py | 2 +- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index fbb6112a..2faac814 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,28 +1,26 @@ Hello! -I'm pleased to announce version 3.11.0, the first stable release -of branch 3.11 of SQLObject. +I'm pleased to announce version 3.11.1a1, the first alpha of the upcoming +release of branch 3.11 of SQLObject. +I'm pleased to announce version 3.11.1a2, the second alpha of the upcoming +release of branch 3.11 of SQLObject. -What's new in SQLObject -======================= +I'm pleased to announce version 3.11.1b1, the first beta of the upcoming +release of branch 3.11 of SQLObject. + +I'm pleased to announce version 3.11.1rc1, the first release candidate +of the upcoming release of branch 3.11 of SQLObject. -Features --------- +I'm pleased to announce version 3.11.1, the first bugfix release of branch +3.11 of SQLObject. -* Continue working on ``SQLRelatedJoin`` aliasing introduced in 3.10.2. - When a table joins with itself calling - ``relJoinCol.filter(thisClass.q.column)`` raises ``ValueError`` - hinting that an alias is required for filtering. -* Test that ``idType`` is either ``int`` or ``str``. +What's new in SQLObject +======================= + +The contributors for this release are ... Thanks! -* Added ``sqlmeta.idSize``. This sets the size of integer column ``id`` - for MySQL and PostgreSQL. Allowed values are ``'TINY'``, ``'SMALL'``, - ``'MEDIUM'``, ``'BIG'``, ``None``; default is ``None``. For Postgres - mapped to ``smallserial``/``serial``/``bigserial``. For other backends - it's currently ignored. Feature request by Meet Gujrathi at - https://stackoverflow.com/q/77360075/7976758 For a more complete list, please see the news: http://sqlobject.org/News.html @@ -54,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.0 +https://pypi.org/project/SQLObject/3.11.1a0.dev20231112/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 8e895397..d9390c7f 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.11.0 -================ +SQLObject 3.11.1a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index e5aa90e6..270a44a7 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,9 +5,14 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.11.0 ================ +Released 2023 Nov 11. + Features -------- diff --git a/setup.py b/setup.py index b1dea834..28a634b5 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 61151b8015d67de07a7a1e19d9161e7534b00800 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 11 Nov 2023 16:19:51 +0300 Subject: [PATCH 205/295] Build(devscripts/postrelease): Restore alpha state [skip ci] --- devscripts/postrelease | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devscripts/postrelease b/devscripts/postrelease index 0a9c73a5..246e9e3f 100755 --- a/devscripts/postrelease +++ b/devscripts/postrelease @@ -2,5 +2,8 @@ git checkout HEAD~ ANNOUNCE.rst setup.cfg && +trove_cls='3 - Alpha' && +sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && + `git var GIT_EDITOR` ANNOUNCE.rst setup.cfg README.rst docs/News.rst && exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst From 782091b5712fdaadbc4ae8b88a4a52562bfc5d2b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 14 Dec 2023 23:15:05 +0300 Subject: [PATCH 206/295] Build(setup.cfg): Remove `validators.py` We no longer carry `validators.py` with us. [skip ci] --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index af28274e..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -10,7 +10,7 @@ tag_date = 0 tag_svn_revision = 0 [flake8] -exclude = .git,.tox,docs/europython/*.py,validators.py +exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 # W503 line break before binary operator # W605 invalid escape sequence From 5396e8151f13215a6a2076ea24c52482489af5b8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 3 Jan 2024 02:02:14 +0300 Subject: [PATCH 207/295] Build(GHActions): Use `checkout@v4` instead of outdated `v2` --- .github/workflows/run-tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 3593f6a6..b38d006a 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -39,7 +39,7 @@ jobs: if: ${{ runner.os == 'Windows' }} # Setup Python/pip - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: s-weigand/setup-conda@v1 with: conda-channels: conda-forge From 06901b4af66de626daaa8ae35bc370bf3d787f50 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 23 Jan 2024 11:37:53 +0300 Subject: [PATCH 208/295] Build(git): Simplify regular expressions for `compileall` [skip ci] --- devscripts/git-hooks/post-checkout | 4 ++-- devscripts/git-hooks/post-merge | 4 ++-- devscripts/git-hooks/post-rewrite | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index 40f7bd71..c615fc8b 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -16,7 +16,7 @@ if [ "$new_branch" = 1 ]; then rm -rf docs/_build/html docs/html fi && -python -m compileall -q -x '\.tox/.+' . && -python -O -m compileall -q -x '\.tox/.+' . +python -m compileall -q -x '\.tox/' . && +python -O -m compileall -q -x '\.tox/' . exit 0 diff --git a/devscripts/git-hooks/post-merge b/devscripts/git-hooks/post-merge index 633a1d0d..2df0670c 100755 --- a/devscripts/git-hooks/post-merge +++ b/devscripts/git-hooks/post-merge @@ -2,7 +2,7 @@ # post-merge hook that compiles python files to byte code -python -m compileall -q -x '\.tox/.+' . && -python -O -m compileall -q -x '\.tox/.+' . +python -m compileall -q -x '\.tox/' . && +python -O -m compileall -q -x '\.tox/' . exit 0 diff --git a/devscripts/git-hooks/post-rewrite b/devscripts/git-hooks/post-rewrite index df284420..59efb3dc 100755 --- a/devscripts/git-hooks/post-rewrite +++ b/devscripts/git-hooks/post-rewrite @@ -2,7 +2,7 @@ # post-rewrite hook that compiles python files to byte code -python -m compileall -q -x '\.tox/.+' . && -python -O -m compileall -q -x '\.tox/.+' . +python -m compileall -q -x '\.tox/' . && +python -O -m compileall -q -x '\.tox/' . exit 0 From 3dc10840dbf50bee098ec9cc006fb41380ed45cb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2024 21:48:12 +0300 Subject: [PATCH 209/295] CI: Run tests with `PyGreSQL` --- docs/News.rst | 5 +++++ tox.ini | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 270a44a7..d65b6e55 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +CI +-- + +* Run tests with ``PyGreSQL`` on w32, do not ignore errors. + SQLObject 3.11.0 ================ diff --git a/tox.ini b/tox.ini index caa5945c..c660a752 100644 --- a/tox.ini +++ b/tox.ini @@ -508,10 +508,10 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - -pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pygresql&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pygresql-noauto-w32] +[testenv:py27-postgres-pygresql-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base From 93864e0f548ef3a70e0d5640bcaa74718aa52bec Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 24 Feb 2024 22:20:24 +0300 Subject: [PATCH 210/295] CI: Skip tests with `pg8000` --- docs/News.rst | 2 ++ tox.ini | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index d65b6e55..1060920d 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -13,6 +13,8 @@ CI * Run tests with ``PyGreSQL`` on w32, do not ignore errors. +* Skip tests with ``pg8000`` on w32. + SQLObject 3.11.0 ================ diff --git a/tox.ini b/tox.ini index c660a752..4d1b6197 100644 --- a/tox.ini +++ b/tox.ini @@ -554,7 +554,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-noauto-w32] platform = win32 commands = {[pg8000-w32]commands} From 5e5f588771c94dea2a40829726000ef6917a1b32 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 21 May 2024 23:19:20 +0300 Subject: [PATCH 211/295] Build(requirements): PyMySQL 1.0.3 dropped support for Python 3.6 --- devscripts/requirements/requirements_pymysql.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devscripts/requirements/requirements_pymysql.txt b/devscripts/requirements/requirements_pymysql.txt index b8c7bc6a..4333b47c 100644 --- a/devscripts/requirements/requirements_pymysql.txt +++ b/devscripts/requirements/requirements_pymysql.txt @@ -1,3 +1,4 @@ pymysql < 1.0; python_version == '2.7' or python_version == '3.5' pymysql < 0.10.0; python_version == '3.4' -pymysql; python_version >= '3.6' +pymysql < 1.0.3; python_version == '3.6' +pymysql; python_version >= '3.7' From 1b9b3aa51986028bbc203e111f78846cafbd524c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 24 Jul 2024 20:57:21 +0300 Subject: [PATCH 212/295] CI(GHActions): Switch to `setup-miniconda` --- .github/workflows/run-tests.yaml | 16 +++++++++++++--- docs/News.rst | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index b38d006a..10d845be 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -40,15 +40,19 @@ jobs: # Setup Python/pip - uses: actions/checkout@v4 - - uses: s-weigand/setup-conda@v1 + - uses: conda-incubator/setup-miniconda@v3 with: - conda-channels: conda-forge + miniforge-version: latest python-version: ${{ matrix.python-version }} if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} if: ${{ contains(fromJSON(env.not_in_conda), matrix.python-version) }} + - uses: actions/cache@v3 + with: + path: ~/conda_pkgs_dir + key: ${{ runner.os }}-conda - name: Cache pip uses: actions/cache@v3 with: @@ -63,8 +67,10 @@ jobs: python -m pip install --upgrade pip setuptools wheel pip --version pip install --upgrade virtualenv "tox >= 3.15, < 4" + shell: bash -el {0} - name: Set PYVER run: | + python -c " import os, sys ld_library_path = None pyver = '%d%d' % tuple(sys.version_info[:2]) @@ -77,11 +83,13 @@ jobs: f.write('LD_LIBRARY_PATH=' + ld_library_path + '\n') f.write('PYVER=' + pyver + '\n') f.write('PGPASSWORD=test\n') - shell: python + " + shell: bash -el {0} - name: tox version run: | tox --version + shell: bash -el {0} - name: Run tox @ Linux run: | devscripts/tox-select-envs $PYVER-mysql @@ -89,9 +97,11 @@ jobs: devscripts/tox-select-envs $PYVER-sqlite devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} + shell: bash -el {0} - name: Run tox @ w32 run: | devscripts\tox-select-envs.cmd %PYVER%-mysql devscripts\tox-select-envs.cmd %PYVER%-postgres devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} + shell: cmd /C CALL {0} diff --git a/docs/News.rst b/docs/News.rst index 1060920d..6d75172b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -15,6 +15,8 @@ CI * Skip tests with ``pg8000`` on w32. +* GHActions: Switch to ``setup-miniconda``. + SQLObject 3.11.0 ================ From f34450feec071f0b9495d0919b929d06204b4eea Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 24 Jul 2024 18:23:04 +0300 Subject: [PATCH 213/295] CI(GHActions): Exclude Python 2.7 at w32 It requires VC9 and cannot be installed. --- .github/workflows/run-tests.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 10d845be..4439ef23 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -11,6 +11,9 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + exclude: + - os: windows-latest + python-version: "2.7" include: - os: ubuntu-latest os-name: Linux From ba965063611f185dff46d0bb27659408efef1c6c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 28 Aug 2024 20:49:02 +0300 Subject: [PATCH 214/295] Build(git-hooks): Remove `python -m compileall` The project is developed for a range of different Pythons, recompilation for all supported versions takes too long and must be done in a separate step. [skip ci] --- devscripts/git-hooks/post-checkout | 7 +------ devscripts/git-hooks/post-merge | 8 -------- devscripts/git-hooks/post-rewrite | 8 -------- 3 files changed, 1 insertion(+), 22 deletions(-) delete mode 100755 devscripts/git-hooks/post-merge delete mode 100755 devscripts/git-hooks/post-rewrite diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index c615fc8b..4192e0d6 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -14,9 +14,4 @@ if [ "$new_branch" = 1 ]; then if [ "`echo $d/*`" = "$d/*" ]; then rm -rf $d; fi done && rm -rf docs/_build/html docs/html -fi && - -python -m compileall -q -x '\.tox/' . && -python -O -m compileall -q -x '\.tox/' . - -exit 0 +fi diff --git a/devscripts/git-hooks/post-merge b/devscripts/git-hooks/post-merge deleted file mode 100755 index 2df0670c..00000000 --- a/devscripts/git-hooks/post-merge +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# post-merge hook that compiles python files to byte code - -python -m compileall -q -x '\.tox/' . && -python -O -m compileall -q -x '\.tox/' . - -exit 0 diff --git a/devscripts/git-hooks/post-rewrite b/devscripts/git-hooks/post-rewrite deleted file mode 100755 index 59efb3dc..00000000 --- a/devscripts/git-hooks/post-rewrite +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# post-rewrite hook that compiles python files to byte code - -python -m compileall -q -x '\.tox/' . && -python -O -m compileall -q -x '\.tox/' . - -exit 0 From d365886888d1fcde1c7886a09493b5f1ec7ad8a7 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 28 Aug 2024 20:51:37 +0300 Subject: [PATCH 215/295] Build(git-hooks/post-checkout): Use `rmdir` [skip ci] --- devscripts/git-hooks/post-checkout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/git-hooks/post-checkout b/devscripts/git-hooks/post-checkout index 4192e0d6..7b065f5a 100755 --- a/devscripts/git-hooks/post-checkout +++ b/devscripts/git-hooks/post-checkout @@ -11,7 +11,7 @@ if [ "$new_branch" = 1 ]; then # empty directories and outdated docs find . -name '*.py[co]' -delete && for d in sqlobject/include/pydispatch sqlobject/include/tests; do - if [ "`echo $d/*`" = "$d/*" ]; then rm -rf $d; fi + if [ "`echo $d/*`" = "$d/*" ]; then rmdir $d; fi done && rm -rf docs/_build/html docs/html fi From cf96c5e4974cd2241f182e61abd955bdc189fa8c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 24 Sep 2024 22:53:22 +0300 Subject: [PATCH 216/295] Tests, CI(GHActions): Run tests with Python 3.13 Excluding psycopg2 -- it's not yet compatible. Excluding PyMySQL under w32 -- it's also not yet compatible. --- .github/workflows/run-tests.yaml | 3 +- devscripts/requirements/requirements.txt | 4 +- docs/News.rst | 7 +++ setup.py | 8 ++- tox.ini | 64 ++++++++++++------------ 5 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 4439ef23..e61a0c4e 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] exclude: - os: windows-latest python-version: "2.7" @@ -45,6 +45,7 @@ jobs: - uses: actions/checkout@v4 - uses: conda-incubator/setup-miniconda@v3 with: + channels: conda-forge, conda-forge/label/python_rc miniforge-version: latest python-version: ${{ matrix.python-version }} if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index a419296d..befc10e6 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -2,5 +2,7 @@ DateTime FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0' -FormEncode >= 1.3.1; python_version >= '3.4' +FormEncode >= 1.3.1; python_version >= '3.4' and python_version < '3.13' +git+https://github.com/formencode/formencode.git; python_version >= '3.13' + PyDispatcher >= 2.0.4 diff --git a/docs/News.rst b/docs/News.rst index 6d75172b..631d418f 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Tests +----- + +* Run tests with Python 3.13. + CI -- @@ -17,6 +22,8 @@ CI * GHActions: Switch to ``setup-miniconda``. +* GHActions: Python 3.13. + SQLObject 3.11.0 ================ diff --git a/setup.py b/setup.py index 28a634b5..356331ca 100755 --- a/setup.py +++ b/setup.py @@ -64,6 +64,7 @@ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", @@ -103,9 +104,12 @@ requires=['FormEncode', 'PyDispatcher'], install_requires=[ "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", - "FormEncode>=1.3.1; python_version>='3.4'", + "FormEncode>=1.3.1; python_version>='3.4' and python_version < '3.13'", "PyDispatcher>=2.0.4", - ], + ] + [ + "formencode @ " + "git+https://github.com/formencode/formencode.git#egg=formencode" + ] if sys.version_info >= (3, 13) else [], extras_require={ # Firebird/Interbase 'fdb': ['fdb'], diff --git a/tox.ini b/tox.ini index 4d1b6197..91dce16b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10,11,12}-sqlite{,-memory},py{27,37,312}-flake8 +envlist = py27,py3{4,5,6,7,8,9,10,11,12,13}-sqlite{,-memory},py{27,37,312}-flake8 # Base test environment settings [testenv] @@ -60,7 +60,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqldb] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb] commands = {envpython} -c "print('MySQL-python requires Python 2.7')" deps = @@ -76,7 +76,7 @@ commands = commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -92,7 +92,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] commands = {[mysql-connector]commands} [mysql-connector-python] @@ -108,7 +108,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-python]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-python{,-w32}] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python{,-w32}] commands = {[mysql-connector-python]commands} [oursql] @@ -124,7 +124,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[oursql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-oursql3-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-oursql3-noauto] commands = {[oursql]commands} [pymysql] @@ -140,7 +140,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -155,7 +155,7 @@ commands = commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11,12}-mariadb] +[testenv:py3{6,7,8,9,10,11,12,13}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -172,7 +172,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -188,7 +188,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -221,7 +221,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql] commands = {[pygresql]commands} [pypostgresql] @@ -236,7 +236,7 @@ commands = commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} [pg8000] @@ -255,7 +255,7 @@ commands = [testenv:py3{4,5,6}-postgres-pg8000] commands = {[pg8000]commands} -[testenv:py3{7,8,9,10,11,12}-postgres-pg8000-noauto] +[testenv:py3{7,8,9,10,11,12,13}-postgres-pg8000-noauto] commands = {[pg8000]commands} [postgres-pyodbc] @@ -272,7 +272,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -288,7 +288,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -305,7 +305,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -318,7 +318,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory] commands = {[sqlite-memory]commands} @@ -336,7 +336,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -352,12 +352,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebirdsql] commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39,310,311,312}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311,312,313}-flake8] changedir = ./ deps = flake8 @@ -383,7 +383,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -402,7 +402,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -439,7 +439,7 @@ platform = win32 commands = {envpython} -c "print('mariadb requires Python 3.6+')" deps = -[testenv:py3{6,7,8,9,10,11,12}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -459,7 +459,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -479,7 +479,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -517,7 +517,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -535,7 +535,7 @@ platform = win32 commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" deps = -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypostgresql-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} @@ -554,7 +554,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pg8000-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-noauto-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -574,7 +574,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -594,7 +594,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -611,7 +611,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -627,6 +627,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From 8fb726180c7c0a1a60003efc8ba45edcc79b5e20 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 16:53:58 +0300 Subject: [PATCH 217/295] Feat(Pg): Separate `psycopg` and `psycopg2` --- docs/News.rst | 6 ++++ docs/SQLObject.rst | 23 +++++++-------- docs/download.rst | 3 +- setup.py | 2 +- sqlobject/postgres/pgconnection.py | 12 ++++++-- sqlobject/tests/test_exceptions.py | 2 -- tox.ini | 45 +++++++++++++++++++++++------- 7 files changed, 65 insertions(+), 28 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 631d418f..6e4fbeb2 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (master) ================== +Drivers +------- + +* Separate ``psycopg`` and ``psycopg2``; + ``psycopg`` is actually ``psycopg3`` now. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index e67aea23..94a41420 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -49,13 +49,13 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For -PostgreSQL_ psycopg2_ is recommended; PyGreSQL_, py-postgresql_ and pg8000_ -are supported; SQLite_ has a built-in driver or PySQLite_. -Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is -supported but has problems. `MAX DB`_ (also known as SAP DB) is supported -via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) -or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for MySQL, -PostgreSQL and MSSQL but have problems (not all tests passed). +PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, +py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver or +PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ +is supported but has problems. `MAX DB`_ (also known as SAP DB) is +supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ +FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for +MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQL: https://www.mysql.com/ .. _MariaDB: https://mariadb.org/ @@ -66,7 +66,8 @@ PostgreSQL and MSSQL but have problems (not all tests passed). .. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org -.. _psycopg2: http://initd.org/psycopg/ +.. _psycopg: https://pypi.org/project/psycopg/ +.. _psycopg2: https://www.psycopg.org/ .. _PyGreSQL: http://www.pygresql.org/ .. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ @@ -1843,9 +1844,9 @@ PostgresConnection supports transactions and all other features. The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated -list of driver names. Possible drivers are: ``psycopg2``, -``psycopg`` (alias for ``psycopg2``), ``pygresql``, ``pypostgresql``, -``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +list of driver names. Possible drivers are: ``psycopg``, ``psycopg2``, +``pygresql``, ``pypostgresql``, ``pg8000``, +``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``). Default is ``psycopg``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, diff --git a/docs/download.rst b/docs/download.rst index 77f46159..bc283155 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -73,7 +73,8 @@ pyodbc pypyodbc odbc (synonym for pyodbc) PostgreSQL ^^^^^^^^^^ -psycopg2 psycopg postgres postgresql (synonyms for psycopg2) +psycopg +psycopg2 postgres postgresql (synonyms for psycopg2) pygresql pypostgresql py-postgresql pg8000 SQLite diff --git a/setup.py b/setup.py index 356331ca..e90c10f6 100755 --- a/setup.py +++ b/setup.py @@ -134,8 +134,8 @@ 'pyodbc': ['pyodbc'], 'pypyodbc': ['pypyodbc'], # PostgreSQL + 'psycopg:python_version>="3.6"': ['psycopg[binary]'], 'psycopg2': ['psycopg2'], - 'psycopg': ['psycopg2'], 'postgres': ['psycopg2'], 'postgresql': ['psycopg2'], 'pygresql': ['pygresql'], diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 5bc6778d..87921c26 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -60,9 +60,12 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if not driver: continue try: - if driver in ('psycopg', 'psycopg2'): - import psycopg2 as psycopg + if driver == 'psycopg': + import psycopg self.module = psycopg + elif driver == 'psycopg2': + import psycopg2 + self.module = psycopg2 elif driver == 'pygresql': import pgdb self.module = pgdb @@ -133,7 +136,10 @@ def __init__(self, dsn=None, host=None, port=None, db=None, else: dsn_dict["port"] = port if db: - dsn_dict["database"] = db + if driver == 'psycopg': + dsn_dict["dbname"] = db + else: + dsn_dict["database"] = db if user: dsn_dict["user"] = user if password: diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 42dd134c..86559efe 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -25,8 +25,6 @@ def test_exceptions(): raises(DuplicateEntryError, SOTestException, name="test") connection = getConnection() - if connection.module.__name__ != 'psycopg2': - return SOTestExceptionWithNonexistingTable.setConnection(connection) try: list(SOTestExceptionWithNonexistingTable.select()) diff --git a/tox.ini b/tox.ini index 91dce16b..1b64b4c7 100644 --- a/tox.ini +++ b/tox.ini @@ -22,8 +22,9 @@ deps = mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - py34-psycopg: psycopg2-binary==2.8.4 - !py34-psycopg: psycopg2-binary + psycopg: psycopg[binary] + py34-psycopg2: psycopg2-binary==2.8.4 + !py34-psycopg2: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt @@ -200,13 +201,24 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-psycopg] +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto] +commands = {[psycopg]commands} + +[psycopg2] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py27-postgres-psycopg2] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[psycopg]commands} + {[psycopg2]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg] -commands = {[psycopg]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2] +commands = {[psycopg2]commands} [pygresql] commands = @@ -485,6 +497,19 @@ commands = {[mysql-pypyodbc-w32]commands} [psycopg-w32] platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto-w32] +platform = win32 +commands = {[psycopg-w32]commands} + +[psycopg2-w32] +platform = win32 commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test @@ -492,15 +517,15 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-psycopg-w32] +[testenv:py27-postgres-psycopg2-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[psycopg-w32]commands} + {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2-w32] platform = win32 -commands = {[psycopg-w32]commands} +commands = {[psycopg2-w32]commands} [pygresql-w32] platform = win32 From 07e74e51d5877217aa6af5413371a6e5ac1055b6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 17:45:32 +0300 Subject: [PATCH 218/295] Tests(test_exceptions): MariaDB returns a different error code --- docs/News.rst | 2 ++ sqlobject/tests/test_exceptions.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 6e4fbeb2..fd0fbdf6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,6 +19,8 @@ Tests * Run tests with Python 3.13. +* Fix ``test_exceptions.py``: MariaDB returns a different error code. + CI -- diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 86559efe..72991919 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -29,6 +29,6 @@ def test_exceptions(): try: list(SOTestExceptionWithNonexistingTable.select()) except ProgrammingError as e: - assert e.args[0].code == '42P01' + assert e.args[0].code in (1146, '42P01') else: assert False, "DID NOT RAISE" From 48eb837ded57b314f73d2dc7f4bf1defcdc2ec9a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 18:12:16 +0300 Subject: [PATCH 219/295] Fix(Pg): Minor fix in getting error code from PyGreSQL --- docs/News.rst | 2 ++ sqlobject/postgres/pgconnection.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/docs/News.rst b/docs/News.rst index fd0fbdf6..a4c11e15 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,8 @@ Drivers * Separate ``psycopg`` and ``psycopg2``; ``psycopg`` is actually ``psycopg3`` now. +* Minor fix in getting error code from PyGreSQL. + Tests ----- diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 87921c26..bb76afa4 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -21,6 +21,9 @@ def __new__(cls, e, append_msg=''): # pg8000 for Python 3.5+ ecode = eargs0['C'] eerror = emessage = eargs0['M'] + elif e.__module__ == 'pg': # PyGreSQL + ecode = e.sqlstate + eerror = emessage = e.args[0] elif hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors ecode = getattr(e, 'pgcode', None) eerror = getattr(e, 'pgerror', None) From 9429cdd5f33d7293fb1f751f9e88a61d3071674e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 25 Sep 2024 18:37:46 +0300 Subject: [PATCH 220/295] Tests(test_exceptions): Fix under SQLite --- docs/News.rst | 2 +- sqlobject/tests/test_exceptions.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a4c11e15..6685d9cf 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -21,7 +21,7 @@ Tests * Run tests with Python 3.13. -* Fix ``test_exceptions.py``: MariaDB returns a different error code. +* Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. CI -- diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 72991919..169ca188 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -1,6 +1,7 @@ import pytest from sqlobject import SQLObject, StringCol -from sqlobject.dberrors import DuplicateEntryError, ProgrammingError +from sqlobject.dberrors import DuplicateEntryError, OperationalError, \ + ProgrammingError from sqlobject.tests.dbtest import getConnection, raises, setupClass, supports @@ -30,5 +31,7 @@ def test_exceptions(): list(SOTestExceptionWithNonexistingTable.select()) except ProgrammingError as e: assert e.args[0].code in (1146, '42P01') + except OperationalError: + assert connection.dbName == 'sqlite' else: assert False, "DID NOT RAISE" From bfcc0f135bb0008692bf57ad3e31e8aeb08b8c8a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 26 Sep 2024 13:45:50 +0300 Subject: [PATCH 221/295] Build(requirements): Fix Python version at 2.7 There will never be 2.8. [skip ci] --- devscripts/requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index befc10e6..ce36de21 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -1,7 +1,7 @@ # DateTime from Zope DateTime -FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0' +FormEncode >= 1.1.1, != 1.3.0; python_version == '2.7' FormEncode >= 1.3.1; python_version >= '3.4' and python_version < '3.13' git+https://github.com/formencode/formencode.git; python_version >= '3.13' From 5b3832184e19308c3712d9393eb7540e74dab8ed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 26 Sep 2024 17:10:01 +0300 Subject: [PATCH 222/295] Feat(MySQL): Drop `oursql` --- docs/News.rst | 2 ++ docs/SQLObject.rst | 5 ++--- docs/download.rst | 2 +- setup.py | 4 ---- sqlobject/mysql/mysqlconnection.py | 21 +++------------------ tox.ini | 18 ------------------ 6 files changed, 8 insertions(+), 44 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 6685d9cf..2afb1855 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -16,6 +16,8 @@ Drivers * Minor fix in getting error code from PyGreSQL. +* Dropped ``oursql``. It wasn't updated in years. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 94a41420..699020bc 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,7 +48,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, -oursql_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver or PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ @@ -62,7 +62,6 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ -.. _oursql: https://github.com/python-oursql/oursql .. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org @@ -1798,7 +1797,7 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``oursql``, ``pymysql`` +Supported drivers are ``mysqldb``, ``connector``, ``pymysql`` and ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); defualt is ``mysqldb``. diff --git a/docs/download.rst b/docs/download.rst index bc283155..d3dd39f4 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector oursql pymysql mariadb +mysql-connector pymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index e90c10f6..be078818 100755 --- a/setup.py +++ b/setup.py @@ -123,10 +123,6 @@ 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], 'mysql-connector-python': ['mysql-connector-python'], - 'oursql:python_version=="2.7"': [ - 'oursql @ git+https://github.com/sqlobject/oursql.git@master'], - 'oursql:python_version>="3.4"': [ - 'oursql3 @ git+https://github.com/sqlobject/oursql.git@py3k'], 'pymysql': ['pymysql'], 'mariadb': ['mariadb'], # ODBC diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 1fcf0a7b..4f2a85d5 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -71,13 +71,6 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.connector_type = 'mysql.connector-python' else: self.connector_type = 'mysql.connector' - elif driver == 'oursql': - import oursql - self.module = oursql - self.CR_SERVER_GONE_ERROR = \ - oursql.errnos['CR_SERVER_GONE_ERROR'] - self.CR_SERVER_LOST = oursql.errnos['CR_SERVER_LOST'] - self.ER_DUP_ENTRY = oursql.errnos['ER_DUP_ENTRY'] elif driver == 'mariadb': import mariadb self.module = mariadb @@ -97,7 +90,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, connector-python, ' - 'oursql, pymysql, mariadb, ' + 'pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -149,12 +142,6 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): db, host, port, user, password ) - elif driver == 'oursql': - if "use_unicode" not in self.kw: - self.kw["use_unicode"] = not PY2 - # oursql doesn't implement ping(True) yet - self.kw["autoreconnect"] = True - elif driver == 'mariadb': self.kw.pop("charset", None) @@ -206,7 +193,7 @@ def character_set_name(self): # mariadb doesn't implement ping(True) conn.auto_reconnect = True conn.ping() - elif self.driver != 'oursql': + else: # Attempt to reconnect. This setting is persistent. conn.ping(True) except self.module.OperationalError as e: @@ -228,8 +215,6 @@ def character_set_name(self): conn.setencoding(encoding=dbEncoding) elif hasattr(conn, 'set_character_set'): conn.set_character_set(dbEncoding) - elif self.driver == 'oursql': - conn.charset = dbEncoding elif hasattr(conn, 'query'): # works along with monkeypatching code above conn.query("SET NAMES %s" % dbEncoding) @@ -257,7 +242,7 @@ def _executeRetry(self, conn, cursor, query): dbEncoding = self.dbEncoding if dbEncoding and not isinstance(query, bytes) and ( self.driver in ('mysqldb', 'connector', 'connector-python', - 'oursql', 'mariadb')): + 'mariadb')): query = query.encode(dbEncoding, 'surrogateescape') # When a server connection is lost and a query is attempted, most of # the time the query will raise a SERVER_LOST exception, then at the diff --git a/tox.ini b/tox.ini index 1b64b4c7..632b9d72 100644 --- a/tox.ini +++ b/tox.ini @@ -18,8 +18,6 @@ deps = mysqlclient: mysqlclient mysql-connector: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt - mysql-oursql: git+https://github.com/sqlobject/oursql.git@master#egg=oursql - mysql-oursql3: git+https://github.com/sqlobject/oursql.git@py3k#egg=oursql pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb psycopg: psycopg[binary] @@ -112,22 +110,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python{,-w32}] commands = {[mysql-connector-python]commands} -[oursql] -commands = - {[testenv]commands} - -mysql --execute="drop database sqlobject_test;" - mysql --execute="create database sqlobject_test;" - pytest -D "mysql://localhost/sqlobject_test?driver=oursql&charset=utf8&debug=1" - mysql --execute="drop database sqlobject_test;" - -[testenv:py27-mysql-oursql-noauto] -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[oursql]commands} - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-oursql3-noauto] -commands = {[oursql]commands} - [pymysql] commands = {[testenv]commands} From 321ba16a6deb93285c43913ed60d971e4d8897de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 26 Sep 2024 17:34:59 +0300 Subject: [PATCH 223/295] Feat(SQLite): Dropped `PySQLite2` Only builtin ``sqlite3`` is supported. --- ANNOUNCE.rst | 4 +- README.rst | 4 +- docs/News.rst | 2 + docs/SQLObject.rst | 13 ++--- docs/download.rst | 5 -- setup.py | 1 - sqlobject/sqlite/sqliteconnection.py | 81 +++++++--------------------- sqlobject/tests/test_datetime.py | 7 ++- sqlobject/tests/test_select.py | 5 +- sqlobject/tests/test_sqlite.py | 14 ----- 10 files changed, 31 insertions(+), 105 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 2faac814..404614f1 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -37,8 +37,8 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``); connections to other backends +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/README.rst b/README.rst index d9390c7f..b657d322 100644 --- a/README.rst +++ b/README.rst @@ -9,8 +9,8 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, ``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite``, -``pysqlite``); connections to other backends +partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less debugged). diff --git a/docs/News.rst b/docs/News.rst index 2afb1855..f235b381 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -18,6 +18,8 @@ Drivers * Dropped ``oursql``. It wasn't updated in years. +* Dropped ``PySQLite2``. Only builtin ``sqlite3`` is supported. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 699020bc..fe94aa6d 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -50,8 +50,8 @@ Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, -py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver or -PySQLite_. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ +py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. +Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for @@ -62,7 +62,7 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _MySQLdb: https://sourceforge.net/projects/mysql-python/ .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ -.. _PyMySQL: https://github.com/PyMySQL/PyMySQL/ +.. _PyMySQL: https://pypi.org/project/PyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ @@ -71,7 +71,6 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ -.. _PySQLite: https://github.com/ghaering/pysqlite .. _Firebird: http://www.firebirdsql.org/en/python-driver/ .. _fdb: http://www.firebirdsql.org/en/devel-python-driver/ .. _kinterbasdb: http://kinterbasdb.sourceforge.net/ @@ -1865,12 +1864,6 @@ column -- strings can go in integer columns, dates in integers, etc. SQLite may have concurrency issues, depending on your usage in a multi-threaded environment. -The user can choose a DB API driver for SQLite by using a ``driver`` -parameter in DB URI or SQLiteConnection that can be a comma-separated list -of driver names. Possible drivers are: ``pysqlite2`` (alias ``sqlite2``), -``sqlite3``, ``sqlite`` (alias ``sqlite1``). Default is to -test pysqlite2, sqlite3 and sqlite in that order. - Connection-specific parameters are: ``encoding``, ``mode``, ``timeout``, ``check_same_thread``, ``use_table_info``. diff --git a/docs/download.rst b/docs/download.rst index d3dd39f4..88bc739c 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -77,11 +77,6 @@ psycopg psycopg2 postgres postgresql (synonyms for psycopg2) pygresql pypostgresql py-postgresql pg8000 -SQLite -^^^^^^ - -pysqlite sqlite - The rest ^^^^^^^^ diff --git a/setup.py b/setup.py index be078818..b5847d13 100755 --- a/setup.py +++ b/setup.py @@ -142,7 +142,6 @@ 'pg8000:python_version>="3.5"': ['pg8000'], # 'sapdb': ['sapdb'], - 'sqlite': ['pysqlite'], 'sybase': ['Sybase'], }, ) diff --git a/sqlobject/sqlite/sqliteconnection.py b/sqlobject/sqlite/sqliteconnection.py index d6df5c58..9d491d94 100644 --- a/sqlobject/sqlite/sqliteconnection.py +++ b/sqlobject/sqlite/sqliteconnection.py @@ -33,67 +33,27 @@ class SQLiteConnection(DBAPI): schemes = [dbName] def __init__(self, filename, autoCommit=1, **kw): - drivers = kw.pop('driver', None) or \ - 'pysqlite2,sqlite3,sqlite' - for driver in drivers.split(','): - driver = driver.strip() - if not driver: - continue - try: - if driver in ('sqlite2', 'pysqlite2'): - from pysqlite2 import dbapi2 as sqlite - self.using_sqlite2 = True - elif driver == 'sqlite3': - import sqlite3 as sqlite - self.using_sqlite2 = True - elif driver in ('sqlite', 'sqlite1'): - import sqlite - self.using_sqlite2 = False - else: - raise ValueError( - 'Unknown SQLite driver "%s", ' - 'expected pysqlite2, sqlite3 ' - 'or sqlite' % driver) - except ImportError: - pass - else: - break - else: - raise ImportError( - 'Cannot find an SQLite driver, tried %s' % drivers) - if self.using_sqlite2: - sqlite.encode = base64.b64encode - sqlite.decode = base64.b64decode + import sqlite3 as sqlite + sqlite.encode = base64.b64encode + sqlite.decode = base64.b64decode self.module = sqlite self.filename = filename # full path to sqlite-db-file self._memory = filename == ':memory:' - if self._memory and not self.using_sqlite2: - raise ValueError("You must use sqlite2 to use in-memory databases") # connection options opts = {} - if self.using_sqlite2: - if autoCommit: - opts["isolation_level"] = None - global sqlite2_Binary - if sqlite2_Binary is None: - sqlite2_Binary = sqlite.Binary - sqlite.Binary = lambda s: sqlite2_Binary(sqlite.encode(s)) - if 'factory' in kw: - factory = kw.pop('factory') - if isinstance(factory, str): - factory = globals()[factory] - opts['factory'] = factory(sqlite) - else: - opts['autocommit'] = Boolean(autoCommit) - if 'encoding' in kw: - opts['encoding'] = kw.pop('encoding') - if 'mode' in kw: - opts['mode'] = int(kw.pop('mode'), 0) + if autoCommit: + opts["isolation_level"] = None + global sqlite2_Binary + if sqlite2_Binary is None: + sqlite2_Binary = sqlite.Binary + sqlite.Binary = lambda s: sqlite2_Binary(sqlite.encode(s)) + if 'factory' in kw: + factory = kw.pop('factory') + if isinstance(factory, str): + factory = globals()[factory] + opts['factory'] = factory(sqlite) if 'timeout' in kw: - if self.using_sqlite2: - opts['timeout'] = float(kw.pop('timeout')) - else: - opts['timeout'] = int(float(kw.pop('timeout')) * 1000) + opts['timeout'] = float(kw.pop('timeout')) if 'check_same_thread' in kw: opts["check_same_thread"] = Boolean(kw.pop('check_same_thread')) # use only one connection for sqlite - supports multiple) @@ -186,17 +146,12 @@ def releaseConnection(self, conn, explicit=False): conn.close() def _setAutoCommit(self, conn, auto): - if self.using_sqlite2: - if auto: - conn.isolation_level = None - else: - conn.isolation_level = "" + if auto: + conn.isolation_level = None else: - conn.autocommit = auto + conn.isolation_level = "" def _setIsolationLevel(self, conn, level): - if not self.using_sqlite2: - return conn.isolation_level = level def makeMemoryConnection(self): diff --git a/sqlobject/tests/test_datetime.py b/sqlobject/tests/test_datetime.py index b40e4dd4..ae22adce 100644 --- a/sqlobject/tests/test_datetime.py +++ b/sqlobject/tests/test_datetime.py @@ -93,10 +93,9 @@ def test_microseconds(): pass else: if connection.dbName == "sqlite": - if connection.using_sqlite2: - # mxDateTime sends and PySQLite2 returns - # full date/time for dates - dateFormat = "%Y-%m-%d %H:%M:%S.%f" + # mxDateTime sends and sqlite3 returns + # full date/time for dates + dateFormat = "%Y-%m-%d %H:%M:%S.%f" class DateTime2(SQLObject): col1 = DateTimeCol() diff --git a/sqlobject/tests/test_select.py b/sqlobject/tests/test_select.py index 12677063..ab132768 100644 --- a/sqlobject/tests/test_select.py +++ b/sqlobject/tests/test_select.py @@ -183,10 +183,7 @@ def test_select_RLIKE(): setupClass(IterTest) if IterTest._connection.dbName == "sqlite": - if not IterTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - - # Implement regexp() function for SQLite; only works with PySQLite2 + # Implement regexp() function for SQLite import re def regexp(regexp, test): diff --git a/sqlobject/tests/test_sqlite.py b/sqlobject/tests/test_sqlite.py index 2ec1d422..8858bcab 100644 --- a/sqlobject/tests/test_sqlite.py +++ b/sqlobject/tests/test_sqlite.py @@ -25,10 +25,6 @@ class SQLiteFactoryTest(SQLObject): def test_sqlite_factory(): setupClass(SQLiteFactoryTest) - - if not SQLiteFactoryTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - factory = [None] def SQLiteConnectionFactory(sqlite): @@ -46,10 +42,6 @@ class MyConnection(sqlite.Connection): def test_sqlite_factory_str(): setupClass(SQLiteFactoryTest) - - if not SQLiteFactoryTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - factory = [None] def SQLiteConnectionFactory(sqlite): @@ -72,9 +64,6 @@ class MyConnection(sqlite.Connection): def test_sqlite_aggregate(): setupClass(SQLiteFactoryTest) - if not SQLiteFactoryTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - def SQLiteConnectionFactory(sqlite): class MyConnection(sqlite.Connection): def __init__(self, *args, **kwargs): @@ -156,9 +145,6 @@ def test_truediv(): setupClass(SQLiteTruedivTest) if SQLiteTruedivTest._connection.dbName == "sqlite": - if not SQLiteTruedivTest._connection.using_sqlite2: - pytest.skip("These tests require SQLite v2+") - def SQLiteConnectionFactory(sqlite): class MyConnection(sqlite.Connection): def __init__(self, *args, **kwargs): From 44e92542e66b985adec84c96387446483f880037 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Sep 2024 13:15:45 +0300 Subject: [PATCH 224/295] Refactor(mysqlconnection): Call `driver.lower()` once globally --- sqlobject/mysql/mysqlconnection.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 4f2a85d5..07961e30 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -32,23 +32,23 @@ class MySQLConnection(DBAPI): def __init__(self, db, user, password='', host='localhost', port=0, **kw): drivers = kw.pop('driver', None) or 'mysqldb' for driver in drivers.split(','): - driver = driver.strip() + driver = driver.strip().lower() if not driver: continue try: - if driver.lower() in ('mysqldb', 'pymysql'): - if driver.lower() == 'pymysql': + if driver in ('mysqldb', 'pymysql'): + if driver == 'pymysql': import pymysql pymysql.install_as_MySQLdb() import MySQLdb - if driver.lower() == 'mysqldb': + if driver == 'mysqldb': if MySQLdb.version_info[:3] < (1, 2, 2): raise ValueError( 'SQLObject requires MySQLdb 1.2.2 or later') import MySQLdb.constants.CR import MySQLdb.constants.ER self.module = MySQLdb - if driver.lower() == 'mysqldb': + if driver == 'mysqldb': self.CR_SERVER_GONE_ERROR = \ MySQLdb.constants.CR.SERVER_GONE_ERROR self.CR_SERVER_LOST = \ @@ -169,7 +169,7 @@ def _connectionFromParams(cls, user, password, host, port, path, args): def makeConnection(self): dbEncoding = self.dbEncoding if dbEncoding: - if self.driver.lower() in ('mysqldb', 'pymysql'): + if self.driver in ('mysqldb', 'pymysql'): from MySQLdb.connections import Connection if not hasattr(Connection, 'set_character_set'): # monkeypatch pre MySQLdb 1.2.1 @@ -230,7 +230,7 @@ def _setAutoCommit(self, conn, auto): conn.autocommit = auto def _force_reconnect(self, conn): - if self.driver.lower() == 'pymysql': + if self.driver == 'pymysql': conn.ping(True) self._setAutoCommit(conn, bool(self.autoCommit)) if self.dbEncoding: @@ -268,7 +268,7 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) if self.debug: self.printDebug(conn, str(e), 'ERROR') - if self.driver.lower() == 'pymysql': + if self.driver == 'pymysql': self._force_reconnect(conn) else: raise dberrors.OperationalError(ErrorMessage(e)) From d16586274a3834e651f4c5715d8143ba27956f6a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 29 Sep 2024 13:27:24 +0300 Subject: [PATCH 225/295] Feat(MySQL): Add support for CyMySQL --- docs/News.rst | 2 ++ docs/SQLObject.rst | 7 ++--- docs/download.rst | 2 +- setup.py | 1 + sqlobject/mysql/mysqlconnection.py | 43 +++++++++++++++++++++--------- tox.ini | 36 +++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 16 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index f235b381..37fb94cb 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,8 @@ SQLObject (master) Drivers ------- +* Add support for CyMySQL; there're some problems with unicode yet. + * Separate ``psycopg`` and ``psycopg2``; ``psycopg`` is actually ``psycopg3`` now. diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index fe94aa6d..13485ae5 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,7 +48,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, -PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ @@ -63,6 +63,7 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ .. _PyMySQL: https://pypi.org/project/PyMySQL/ +.. _CyMySQL: https://pypi.org/project/CyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ @@ -1796,8 +1797,8 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``pymysql`` -and ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and +Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``cymysql``, +``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); defualt is ``mysqldb``. diff --git a/docs/download.rst b/docs/download.rst index 88bc739c..da11fa1a 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector pymysql mariadb +mysql-connector pymysql cymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index b5847d13..717b4773 100755 --- a/setup.py +++ b/setup.py @@ -124,6 +124,7 @@ 'mysql-connector': ['mysql-connector'], 'mysql-connector-python': ['mysql-connector-python'], 'pymysql': ['pymysql'], + 'cymysql': ['cymysql'], 'mariadb': ['mariadb'], # ODBC 'odbc': ['pyodbc'], diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 07961e30..557adb95 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,19 +1,28 @@ from sqlobject import col, dberrors -from sqlobject.compat import PY2 +from sqlobject.compat import PY2, string_type from sqlobject.converters import registerConverter, StringLikeConverter from sqlobject.dbconnection import DBAPI class ErrorMessage(str): def __new__(cls, e, append_msg=''): - if len(e.args) > 1: - obj = str.__new__(cls, e.args[1] + append_msg) + if e.__module__ == 'cymysql.err': + if isinstance(e.errmsg, string_type): + errmsg = e.errmsg + else: + errmsg = e.errmsg.reason + errcode = e.errno else: - obj = str.__new__(cls, append_msg) - try: - obj.code = int(e.args[0]) - except ValueError: - obj.code = e.args[0] + if len(e.args) > 1: + errmsg = e.args[1] + else: + errmsg = '' + try: + errcode = int(e.args[0]) + except ValueError: + errcode = e.args[0] + obj = str.__new__(cls, errmsg + append_msg) + obj.code = errcode obj.module = e.__module__ obj.exception = e.__class__.__name__ return obj @@ -59,6 +68,16 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ MySQLdb.constants.CR.CR_SERVER_LOST self.ER_DUP_ENTRY = MySQLdb.constants.ER.DUP_ENTRY + elif driver == 'cymysql': + import cymysql + import cymysql.constants.CR + import cymysql.constants.ER + self.module = cymysql + self.CR_SERVER_GONE_ERROR = \ + cymysql.constants.CR.CR_SERVER_GONE_ERROR + self.CR_SERVER_LOST = \ + cymysql.constants.CR.CR_SERVER_LOST + self.ER_DUP_ENTRY = cymysql.constants.ER.DUP_ENTRY elif driver in ('connector', 'connector-python'): import mysql.connector self.module = mysql.connector @@ -90,7 +109,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, connector-python, ' - 'pymysql, mariadb, ' + 'pymysql, cymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -230,7 +249,7 @@ def _setAutoCommit(self, conn, auto): conn.autocommit = auto def _force_reconnect(self, conn): - if self.driver == 'pymysql': + if self.driver in ('pymysql', 'cymysql'): conn.ping(True) self._setAutoCommit(conn, bool(self.autoCommit)) if self.dbEncoding: @@ -256,7 +275,7 @@ def _executeRetry(self, conn, cursor, query): # reconnect flag must be set when making the connection to indicate # that autoreconnecting is desired. In MySQLdb 1.2.2 or newer this is # done by calling ping(True) on the connection. - # PyMySQL needs explicit reconnect + # [PC]yMySQL need explicit reconnect # each time we detect connection timeout. for count in range(3): try: @@ -268,7 +287,7 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) if self.debug: self.printDebug(conn, str(e), 'ERROR') - if self.driver == 'pymysql': + if self.driver in ('pymysql', 'cymysql'): self._force_reconnect(conn) else: raise dberrors.OperationalError(ErrorMessage(e)) diff --git a/tox.ini b/tox.ini index 632b9d72..caf1d035 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,7 @@ deps = mysql-connector: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt + cymysql: cymysql mariadb: mariadb psycopg: psycopg[binary] py34-psycopg2: psycopg2-binary==2.8.4 @@ -126,6 +127,22 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] commands = {[pymysql]commands} +[cymysql] +commands = + {[testenv]commands} + -mysql --execute="drop database sqlobject_test;" + mysql --execute="create database sqlobject_test;" + pytest -D "mysql://localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" + mysql --execute="drop database sqlobject_test;" + +[testenv:py27-mysql-cymysql-noauto] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[cymysql]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cymysql-noauto] +commands = {[cymysql]commands} + [mariadb] commands = {[testenv]commands} @@ -419,6 +436,25 @@ commands = platform = win32 commands = {[pymysql-w32]commands} +[cymysql-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27-mysql-cymysql-w32-noauto] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[cymysql-w32]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-cymysql-w32-noauto] +platform = win32 +commands = {[cymysql-w32]commands} + [mariadb-w32] platform = win32 commands = From 8bae132a9f988e06cbf9f21116182dfd2215ea69 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 1 Oct 2024 16:31:42 +0300 Subject: [PATCH 226/295] Build(setup.py): Always install `psycopg2-binary` [skip ci] --- docs/SQLObject.rst | 4 +++- setup.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 13485ae5..8969c38d 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -49,7 +49,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For -PostgreSQL_ psycopg_ and psycopg2_ are recommended; PyGreSQL_, +PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is @@ -67,7 +67,9 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ +.. _psycopg-binary: https://pypi.org/project/psycopg-binary/ .. _psycopg2: https://www.psycopg.org/ +.. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/ .. _PyGreSQL: http://www.pygresql.org/ .. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ diff --git a/setup.py b/setup.py index 717b4773..c8f24e32 100755 --- a/setup.py +++ b/setup.py @@ -132,9 +132,9 @@ 'pypyodbc': ['pypyodbc'], # PostgreSQL 'psycopg:python_version>="3.6"': ['psycopg[binary]'], - 'psycopg2': ['psycopg2'], - 'postgres': ['psycopg2'], - 'postgresql': ['psycopg2'], + 'psycopg2': ['psycopg2-binary'], + 'postgres': ['psycopg2-binary'], + 'postgresql': ['psycopg2-binary'], 'pygresql': ['pygresql'], 'pypostgresql': ['py-postgresql'], 'py-postgresql': ['py-postgresql'], From 32c1ce111d56025594083a8c8889994f205acc9c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 1 Oct 2024 16:43:08 +0300 Subject: [PATCH 227/295] Tests(Pg): Run tests with `psycopg-c` [skip ci] --- docs/News.rst | 4 +++- docs/SQLObject.rst | 17 ++++++++++------- setup.py | 1 + tox.ini | 25 +++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 37fb94cb..69fedec6 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,7 +14,7 @@ Drivers * Add support for CyMySQL; there're some problems with unicode yet. * Separate ``psycopg`` and ``psycopg2``; - ``psycopg`` is actually ``psycopg3`` now. + ``psycopg`` is actually ``psycopg3`` now; not all tests pass. * Minor fix in getting error code from PyGreSQL. @@ -27,6 +27,8 @@ Tests * Run tests with Python 3.13. +* Run tests with ``psycopg-c``; not all tests pass. + * Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. CI diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 8969c38d..c6bbd17b 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -49,13 +49,15 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For -PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; PyGreSQL_, -py-postgresql_ and pg8000_ are supported; SQLite_ has a built-in driver. -Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ -is supported but has problems. `MAX DB`_ (also known as SAP DB) is -supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via pymssql_ (+ -FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are supported for -MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). +PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their +precompiled wheels psycopg-binary_ and psycopg2-binary_; see also optimized +psycopg-c_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ +has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; +pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP +DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via +pymssql_ (+ FreeTDS_) or adodbapi_ (Win32). PyODBC_ and PyPyODBC_ are +supported for MySQL, PostgreSQL and MSSQL but have problems (not all tests +passed). .. _MySQL: https://www.mysql.com/ .. _MariaDB: https://mariadb.org/ @@ -68,6 +70,7 @@ MySQL, PostgreSQL and MSSQL but have problems (not all tests passed). .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ .. _psycopg-binary: https://pypi.org/project/psycopg-binary/ +.. _psycopg-c: https://pypi.org/project/psycopg-c/ .. _psycopg2: https://www.psycopg.org/ .. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/ .. _PyGreSQL: http://www.pygresql.org/ diff --git a/setup.py b/setup.py index c8f24e32..899e333b 100755 --- a/setup.py +++ b/setup.py @@ -132,6 +132,7 @@ 'pypyodbc': ['pypyodbc'], # PostgreSQL 'psycopg:python_version>="3.6"': ['psycopg[binary]'], + 'psycopg-c:python_version>="3.6"': ['psycopg-c'], 'psycopg2': ['psycopg2-binary'], 'postgres': ['psycopg2-binary'], 'postgresql': ['psycopg2-binary'], diff --git a/tox.ini b/tox.ini index caf1d035..5dc9d1b6 100644 --- a/tox.ini +++ b/tox.ini @@ -22,6 +22,7 @@ deps = cymysql: cymysql mariadb: mariadb psycopg: psycopg[binary] + psycopg_c: psycopg[c] py34-psycopg2: psycopg2-binary==2.8.4 !py34-psycopg2: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt @@ -203,6 +204,17 @@ commands = [testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto] commands = {[psycopg]commands} +[psycopg_c] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto] +commands = {[psycopg_c]commands} + [psycopg2] commands = {[testenv]commands} @@ -526,6 +538,19 @@ commands = platform = win32 commands = {[psycopg-w32]commands} +[psycopg_c-w32] +platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto-w32] +platform = win32 +commands = {[psycopg_c-w32]commands} + [psycopg2-w32] platform = win32 commands = From 7a114b78a43c5f3c19df7f0299347b4d651727f5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 4 Dec 2024 17:02:46 +0300 Subject: [PATCH 228/295] Build(setup.py): Use declarative syntax for FormEnode under Python 3.13 --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 899e333b..5c60cd8d 100755 --- a/setup.py +++ b/setup.py @@ -106,10 +106,10 @@ "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", "FormEncode>=1.3.1; python_version>='3.4' and python_version < '3.13'", "PyDispatcher>=2.0.4", - ] + [ "formencode @ " "git+https://github.com/formencode/formencode.git#egg=formencode" - ] if sys.version_info >= (3, 13) else [], + " ; python_version >= '3.13'", + ], extras_require={ # Firebird/Interbase 'fdb': ['fdb'], From 7f7c368ec8fc72a4e527aab0df9c5e6ddb8d82f8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 4 Dec 2024 17:38:45 +0300 Subject: [PATCH 229/295] Build(setup.py): Improve declarative dependencies --- setup.py | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 5c60cd8d..9f5bea09 100755 --- a/setup.py +++ b/setup.py @@ -122,8 +122,29 @@ 'mysql:python_version=="2.7"': ['MySQL-python'], 'mysql:python_version>="3.4"': ['mysqlclient'], 'mysql-connector': ['mysql-connector'], - 'mysql-connector-python': ['mysql-connector-python'], - 'pymysql': ['pymysql'], + 'mysql-connector-python:python_version=="2.7"': + ['mysql-connector-python <= 8.0.23'], + 'mysql-connector-python:python_version=="3.4"': + ['mysql-connector-python <= 8.0.22, > 2.0', 'protobuf < 3.19'], + 'mysql-connector-python:python_version=="3.5"': + ['mysql-connector-python <= 8.0.23, >= 8.0.5'], + 'mysql-connector-python:python_version=="3.6"': + ['mysql-connector-python <= 8.0.28, >= 8.0.6'], + 'mysql-connector-python:python_version=="3.7"': + ['mysql-connector-python <= 8.0.29, >= 8.0.13'], + 'mysql-connector-python:python_version=="3.8"': + ['mysql-connector-python <= 8.0.29, >= 8.0.19'], + 'mysql-connector-python:python_version=="3.9"': + ['mysql-connector-python <= 8.0.29, >= 8.0.24'], + 'mysql-connector-python:python_version=="3.10"': + ['mysql-connector-python <= 8.0.29, >= 8.0.28'], + 'mysql-connector-python:python_version>="3.11"': + ['mysql-connector-python >= 8.0.29'], + 'pymysql:python_version == "2.7" or python_version == "3.5"': + ['pymysql < 1.0'], + 'pymysql:python_version == "3.4"': ['pymysql < 0.10.0'], + 'pymysql:python_version == "3.6"': ['pymysql < 1.0.3'], + 'pymysql:python_version >= "3.7"': ['pymysql'], 'cymysql': ['cymysql'], 'mariadb': ['mariadb'], # ODBC @@ -136,15 +157,21 @@ 'psycopg2': ['psycopg2-binary'], 'postgres': ['psycopg2-binary'], 'postgresql': ['psycopg2-binary'], - 'pygresql': ['pygresql'], + 'psycopg2-binary:python_version=="3.4"': ['psycopg2-binary == 2.8.4'], + 'psycopg2-binary:python_version!="3.4"': ['psycopg2-binary'], + 'pygresql:python_version=="3.4"': ['pygresql < 5.2'], + 'pygresql:python_version!="3.4"': ['pygresql'], 'pypostgresql': ['py-postgresql'], 'py-postgresql': ['py-postgresql'], - 'pg8000:python_version=="2.7"': ['pg8000<1.13'], - 'pg8000:python_version=="3.4"': ['pg8000<1.12.4'], + 'pg8000:python_version=="2.7"': ['pg8000 < 1.13'], + 'pg8000:python_version=="3.4"': ['pg8000 < 1.12.4'], 'pg8000:python_version>="3.5"': ['pg8000'], # 'sapdb': ['sapdb'], 'sybase': ['Sybase'], + # Non-DB API drivers + 'zope-dt:python_version=="3.4"': ['zope.datetime < 4.3'], + 'zope-dt:python_version!="3.4"': ['zope.datetime'], }, ) From 60b8683d88cdd59d18ff7c74e38c94948fa19b8f Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 4 Dec 2024 19:25:12 +0300 Subject: [PATCH 230/295] Tests(tox): Run tests with psycopg under Python 3.13 There're still some problems so the tests are not ran automatically. --- tox.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tox.ini b/tox.ini index 5dc9d1b6..86641b93 100644 --- a/tox.ini +++ b/tox.ini @@ -201,7 +201,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto] commands = {[psycopg]commands} [psycopg_c] @@ -212,7 +212,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto] commands = {[psycopg_c]commands} [psycopg2] @@ -534,7 +534,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -547,7 +547,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12}-postgres-psycopg_c-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto-w32] platform = win32 commands = {[psycopg_c-w32]commands} From 7ebf297f6e1bbcaec2cf58fd4b859d2d78f0ef7e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 5 Dec 2024 17:26:58 +0300 Subject: [PATCH 231/295] Tests(py-postgres): Set `sslmode` to `allow` Upstream changed default to `prefer`. [skip ci] --- docs/News.rst | 3 +++ tox.ini | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 69fedec6..84597bd3 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -31,6 +31,9 @@ Tests * Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. +* ``py-postgres``: Set ``sslmode`` to ``allow``; + upstream changed default to ``prefer``. + CI -- diff --git a/tox.ini b/tox.ini index 86641b93..82b39a49 100644 --- a/tox.ini +++ b/tox.ini @@ -252,7 +252,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-noauto] @@ -595,7 +595,7 @@ commands = {[testenv]commands} -dropdb --username=runner --no-password sqlobject_test createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&charset=utf-8&debug=1" + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test [testenv:py27-postgres-pypostgresql-noauto-w32] From e4d9aadd81a703877161537a757839b9ef708221 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:33:04 +0300 Subject: [PATCH 232/295] Build(devscripts/release): PEP 625 [skip ci] --- devscripts/release | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devscripts/release b/devscripts/release index 8893a52f..cb4ce229 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,5 +24,9 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && +cd dist && +mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && +cd .. && + twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From fd927abafd29bb6261d2603b73b3fefcb8efdbec Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:43:51 +0300 Subject: [PATCH 233/295] Release 3.12.0b1 --- ANNOUNCE.rst | 50 +++++++++++++++++++++++++++++----------- README.rst | 2 +- docs/News.rst | 2 +- setup.cfg | 5 ---- setup.py | 2 +- sqlobject/__version__.py | 8 +++---- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 404614f1..9528f2ea 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,48 @@ Hello! -I'm pleased to announce version 3.11.1a1, the first alpha of the upcoming -release of branch 3.11 of SQLObject. +I'm pleased to announce version 3.12.0b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. -I'm pleased to announce version 3.11.1a2, the second alpha of the upcoming -release of branch 3.11 of SQLObject. -I'm pleased to announce version 3.11.1b1, the first beta of the upcoming -release of branch 3.11 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.11.1rc1, the first release candidate -of the upcoming release of branch 3.11 of SQLObject. +Drivers +------- -I'm pleased to announce version 3.11.1, the first bugfix release of branch -3.11 of SQLObject. +* Add support for CyMySQL; there're some problems with unicode yet. +* Separate ``psycopg`` and ``psycopg2``; + ``psycopg`` is actually ``psycopg3`` now; not all tests pass. -What's new in SQLObject -======================= +* Minor fix in getting error code from PyGreSQL. + +* Dropped ``oursql``. It wasn't updated in years. + +* Dropped ``PySQLite2``. Only builtin ``sqlite3`` is supported. + +Tests +----- + +* Run tests with Python 3.13. + +* Run tests with ``psycopg-c``; not all tests pass. + +* Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. + +* ``py-postgres``: Set ``sslmode`` to ``allow``; + upstream changed default to ``prefer``. + +CI +-- + +* Run tests with ``PyGreSQL`` on w32, do not ignore errors. + +* Skip tests with ``pg8000`` on w32. -The contributors for this release are ... Thanks! +* GHActions: Switch to ``setup-miniconda``. +* GHActions: Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +74,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.11.1a0.dev20231112/ +https://pypi.org/project/SQLObject/3.12.0b1 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index b657d322..7ed8189c 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -SQLObject 3.11.1a0 +SQLObject 3.12.0b1 ================== SQLObject is a free and open-source (LGPL) Python object-relational diff --git a/docs/News.rst b/docs/News.rst index 84597bd3..c90ef06e 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,7 +5,7 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) +SQLObject 3.12.0b1 ================== Drivers diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 9f5bea09..1a755e67 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 19a73b78..d38b7048 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.11.0' +version = '3.12.0b1' major = 3 -minor = 11 +minor = 12 micro = 0 -release_level = 'final' -serial = 0 +release_level = 'beta' +serial = 1 version_info = (major, minor, micro, release_level, serial) From 3e265f765ea2395cc4b66834aca47bf6e33c1412 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:50:12 +0300 Subject: [PATCH 234/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 48 +++++++++++++----------------------------------- setup.cfg | 5 +++++ setup.py | 2 +- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9528f2ea..92e72480 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,48 +1,26 @@ Hello! -I'm pleased to announce version 3.12.0b1, the first beta of the upcoming +I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming release of branch 3.12 of SQLObject. +I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming +release of branch 3.12 of SQLObject. -What's new in SQLObject -======================= - -Drivers -------- - -* Add support for CyMySQL; there're some problems with unicode yet. - -* Separate ``psycopg`` and ``psycopg2``; - ``psycopg`` is actually ``psycopg3`` now; not all tests pass. - -* Minor fix in getting error code from PyGreSQL. - -* Dropped ``oursql``. It wasn't updated in years. - -* Dropped ``PySQLite2``. Only builtin ``sqlite3`` is supported. - -Tests ------ - -* Run tests with Python 3.13. - -* Run tests with ``psycopg-c``; not all tests pass. - -* Fix ``test_exceptions.py`` under MariaDB, PostgreSQL and SQLite. +I'm pleased to announce version 3.12.1b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. -* ``py-postgres``: Set ``sslmode`` to ``allow``; - upstream changed default to ``prefer``. +I'm pleased to announce version 3.12.1rc1, the first release candidate +of the upcoming release of branch 3.12 of SQLObject. -CI --- +I'm pleased to announce version 3.12.1, the first bugfix release of branch +3.12 of SQLObject. -* Run tests with ``PyGreSQL`` on w32, do not ignore errors. -* Skip tests with ``pg8000`` on w32. +What's new in SQLObject +======================= -* GHActions: Switch to ``setup-miniconda``. +The contributors for this release are ... Thanks! -* GHActions: Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -74,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.0b1 +https://pypi.org/project/SQLObject/3.12.1a0.dev20241218/ News and changes: http://sqlobject.org/News.html diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 1a755e67..9f5bea09 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From fcb25a4b17af178c4980f200fe33ab6a15c2e5a2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 14:51:51 +0300 Subject: [PATCH 235/295] Build(devscripts/postrelease): Commit `setup.py` [skip ci] --- devscripts/postrelease | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/postrelease b/devscripts/postrelease index 246e9e3f..a799b553 100755 --- a/devscripts/postrelease +++ b/devscripts/postrelease @@ -6,4 +6,4 @@ trove_cls='3 - Alpha' && sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && `git var GIT_EDITOR` ANNOUNCE.rst setup.cfg README.rst docs/News.rst && -exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst +exec git commit --message="Build: Prepare for the next release" --message="[skip ci]" ANNOUNCE.rst setup.cfg README.rst docs/News.rst setup.py From a6a9cac105522ee8781dd6a67626590912419ba0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 18 Dec 2024 15:06:37 +0300 Subject: [PATCH 236/295] Build(devscripts/prerelease): For prerelease do not edit `build-all-docs` For alpha/beta versions do not change stable version docs. [skip ci] --- devscripts/prerelease | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/devscripts/prerelease b/devscripts/prerelease index 53e8956d..7fe520db 100755 --- a/devscripts/prerelease +++ b/devscripts/prerelease @@ -40,5 +40,9 @@ else fi && sed -Ei "s/Development Status :: .+\",\$/Development Status :: $trove_cls\",/" setup.py && -`git var GIT_EDITOR` devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py && +if [ "$state" = final -o "$state" = post ]; then + dbad=devscripts/build-all-docs +fi && + +`git var GIT_EDITOR` $dbad docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py && exec git commit --message="Release $tag" devscripts/build-all-docs docs/News.rst ANNOUNCE.rst sqlobject/__version__.py README.rst setup.cfg setup.py From 784592927509ebc7365227cba4366e0aef54463b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 19 Dec 2024 17:02:52 +0300 Subject: [PATCH 237/295] Build(devscripts/release): Check if sdist is (not) PEP-625 compatible [skip ci] --- devscripts/release | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/devscripts/release b/devscripts/release index cb4ce229..f5a2e576 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,9 +24,11 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -cd dist && -mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && -cd .. && +if [ -f dist/SQLObject-$version.tar.gz ]; then + cd dist && + mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && + cd .. +fi && twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 0ead85f0d058a4e0ada04f80bd41cc942a5f18df Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Dec 2024 15:16:34 +0300 Subject: [PATCH 238/295] Release 3.12.0 --- ANNOUNCE.rst | 16 ++-------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- setup.cfg | 5 ----- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 7 files changed, 13 insertions(+), 28 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 92e72480..0ebac766 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,18 +1,6 @@ Hello! -I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1b1, the first beta of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1rc1, the first release candidate -of the upcoming release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1, the first bugfix release of branch +I'm pleased to announce version 3.12.0, the release of branch 3.12 of SQLObject. @@ -52,7 +40,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.1a0.dev20241218/ +https://pypi.org/project/SQLObject/3.12.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 7ed8189c..980aae82 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.12.0b1 -================== +SQLObject 3.12.0 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 63d78c2b..648f2f18 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.11.0 && +build_docs 3.12.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index c90ef06e..86c19145 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject 3.12.0b1 -================== +SQLObject 3.12.0 +================ + +Released 2024 Dec 20. Drivers ------- diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 9f5bea09..52811dc8 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index d38b7048..767a40ea 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.12.0b1' +version = '3.12.0' major = 3 minor = 12 micro = 0 -release_level = 'beta' -serial = 1 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From 500a70b21b62956202aeea8059e2a17889a2a919 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 20 Dec 2024 15:36:21 +0300 Subject: [PATCH 239/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 16 ++++++++++++++-- docs/News.rst | 3 +++ setup.cfg | 5 +++++ setup.py | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 0ebac766..8fb113f5 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,6 +1,18 @@ Hello! -I'm pleased to announce version 3.12.0, the release of branch +I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1rc1, the first release candidate +of the upcoming release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1, the first bugfix release of branch 3.12 of SQLObject. @@ -40,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.0 +https://pypi.org/project/SQLObject/3.12.1a0.dev20241220/ News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 86c19145..030a6513 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (master) +================== + SQLObject 3.12.0 ================ diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 52811dc8..9f5bea09 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 194151f2670321684e34bbfb7d77c501492725b5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 13 Jan 2025 19:29:22 +0300 Subject: [PATCH 240/295] CI(GHActions): Upgrade `setup-python` and `cache` actions --- .github/workflows/run-tests.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index e61a0c4e..16119295 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -49,16 +49,16 @@ jobs: miniforge-version: latest python-version: ${{ matrix.python-version }} if: ${{ !contains(fromJSON(env.not_in_conda), matrix.python-version) }} - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} if: ${{ contains(fromJSON(env.not_in_conda), matrix.python-version) }} - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ~/conda_pkgs_dir key: ${{ runner.os }}-conda - name: Cache pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ matrix.pip-cache-path }} key: ${{ runner.os }}-pip From 7f5284a05e1de651fdf99d90bdcaddfd10f68128 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 14 Jan 2025 00:20:58 +0300 Subject: [PATCH 241/295] Tests(tox): Change syntax for `envlist` `[testenv:]` doesn't allow lists like `[testenv:py27,py3{4,5}]`; it only allows syntax like `[testenv:py{27,34,35}]`. This commit changes syntax for `envlist` to make it closer to `[testenv:]`. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 82b39a49..a0df8f37 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py27,py3{4,5,6,7,8,9,10,11,12,13}-sqlite{,-memory},py{27,37,312}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,312}-flake8 # Base test environment settings [testenv] From 738920611f57aefb355d6551863eb3a3aba34a2b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Feb 2025 21:17:42 +0300 Subject: [PATCH 242/295] Build(requirements): Use `FormEncode` 2.1.1 for Python 3.13 --- devscripts/requirements/requirements.txt | 4 ++-- docs/News.rst | 5 +++++ setup.py | 6 ++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/devscripts/requirements/requirements.txt b/devscripts/requirements/requirements.txt index ce36de21..02833990 100644 --- a/devscripts/requirements/requirements.txt +++ b/devscripts/requirements/requirements.txt @@ -2,7 +2,7 @@ DateTime FormEncode >= 1.1.1, != 1.3.0; python_version == '2.7' -FormEncode >= 1.3.1; python_version >= '3.4' and python_version < '3.13' -git+https://github.com/formencode/formencode.git; python_version >= '3.13' +FormEncode >= 1.3.1; python_version >= '3.4' +FormEncode >= 2.1.1; python_version >= '3.13' PyDispatcher >= 2.0.4 diff --git a/docs/News.rst b/docs/News.rst index 030a6513..95ed3c4b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,11 @@ News SQLObject (master) ================== +Installation/dependencies +------------------------- + +* Use ``FormEncode`` 2.1.1 for Python 3.13. + SQLObject 3.12.0 ================ diff --git a/setup.py b/setup.py index 9f5bea09..1eeb42c7 100755 --- a/setup.py +++ b/setup.py @@ -104,11 +104,9 @@ requires=['FormEncode', 'PyDispatcher'], install_requires=[ "FormEncode>=1.1.1,!=1.3.0; python_version=='2.7'", - "FormEncode>=1.3.1; python_version>='3.4' and python_version < '3.13'", + "FormEncode>=1.3.1; python_version>='3.4'", + "FormEncode>=2.1.1; python_version >= '3.13'", "PyDispatcher>=2.0.4", - "formencode @ " - "git+https://github.com/formencode/formencode.git#egg=formencode" - " ; python_version >= '3.13'", ], extras_require={ # Firebird/Interbase From 749f3c83307895ac556f1eb30e437a5c5a3e2f40 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Feb 2025 21:46:43 +0300 Subject: [PATCH 243/295] Release 3.12.0.post2 --- ANNOUNCE.rst | 22 ++++++---------------- README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- setup.cfg | 5 ----- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 7 files changed, 17 insertions(+), 30 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 8fb113f5..d0b2fc13 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,26 +1,16 @@ Hello! -I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1b1, the first beta of the upcoming -release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1rc1, the first release candidate -of the upcoming release of branch 3.12 of SQLObject. - -I'm pleased to announce version 3.12.1, the first bugfix release of branch -3.12 of SQLObject. +I'm pleased to announce version 3.12.0.post2, the second post-release +of release 3.12.0 of branch 3.12 of SQLObject. What's new in SQLObject ======================= -The contributors for this release are ... Thanks! +Installation/dependencies +------------------------- +* Use ``FormEncode`` 2.1.1 for Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -52,7 +42,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.1a0.dev20241220/ +https://pypi.org/project/SQLObject/3.12.0.post2 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 980aae82..1829efc9 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.12.0 -================ +SQLObject 3.12.0.post2 +====================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 648f2f18..8d508b27 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.12.0 && +build_docs 3.12.0.post2 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 95ed3c4b..bc14736c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (master) -================== +SQLObject 3.12.0.post2 +====================== + +Released 2025 Feb 01. Installation/dependencies ------------------------- diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 1eeb42c7..48e7a9d8 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 767a40ea..9a310a1e 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.12.0' +version = '3.12.0.post2' major = 3 minor = 12 micro = 0 -release_level = 'final' -serial = 0 +release_level = 'post' +serial = 2 version_info = (major, minor, micro, release_level, serial) From d13705e34c49158b2c23675958752b779165ba1d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Feb 2025 22:18:34 +0300 Subject: [PATCH 244/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 22 ++++++++++++++++------ docs/News.rst | 3 +++ setup.cfg | 5 +++++ setup.py | 2 +- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index d0b2fc13..47a37342 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,16 +1,26 @@ Hello! -I'm pleased to announce version 3.12.0.post2, the second post-release -of release 3.12.0 of branch 3.12 of SQLObject. +I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1b1, the first beta of the upcoming +release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1rc1, the first release candidate +of the upcoming release of branch 3.12 of SQLObject. + +I'm pleased to announce version 3.12.1, the first bugfix release of branch +3.12 of SQLObject. What's new in SQLObject ======================= -Installation/dependencies -------------------------- +The contributors for this release are ... Thanks! -* Use ``FormEncode`` 2.1.1 for Python 3.13. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -42,7 +52,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.0.post2 +https://pypi.org/project/SQLObject/3.12.1a0.dev20250201/ News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index bc14736c..83a60ba1 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject (development) +======================= + SQLObject 3.12.0.post2 ====================== diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 48e7a9d8..1eeb42c7 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 6ac086505501cb878066577072be951539db4b2d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 13 Jan 2025 21:05:30 +0300 Subject: [PATCH 245/295] Feat(MySQL): Extend default list of drivers The list is now `mysqldb`, `mysqlclient`, `mysql-connector`, `mysql-connector-python`, `pymysql`. --- docs/News.rst | 6 ++++++ docs/SQLObject.rst | 3 ++- sqlobject/mysql/mysqlconnection.py | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 83a60ba1..3cba1662 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,12 @@ News SQLObject (development) ======================= +Drivers +------- + +* Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, + ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. + SQLObject 3.12.0.post2 ====================== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index c6bbd17b..8f089413 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1804,7 +1804,8 @@ define the backend using ``sqlmeta.createSQL``. Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``cymysql``, ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and -``pypyodbc``); defualt is ``mysqldb``. +``pypyodbc``); default are ``mysqldb``, ``mysqlclient``, +``mysql-connector``, ``mysql-connector-python``, ``pymysql``. Keyword argument ``conv`` allows to pass a list of custom converters. diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 557adb95..8ba4a99e 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -39,7 +39,8 @@ class MySQLConnection(DBAPI): odbc_keywords = ('Server', 'Port', 'UID', 'Password', 'Database') def __init__(self, db, user, password='', host='localhost', port=0, **kw): - drivers = kw.pop('driver', None) or 'mysqldb' + drivers = kw.pop('driver', None) or 'mysqldb,mysqlclient,' + \ + 'mysql-connector,mysql-connector-python,pymysql' for driver in drivers.split(','): driver = driver.strip().lower() if not driver: From edb3970a31c93033b7e12b0f40b7cda52b7c3b6d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 13 Jan 2025 21:10:20 +0300 Subject: [PATCH 246/295] Feat(Pg): Extend default list of drivers The list is now `psycopg`, `psycopg2`, `pygresql`. --- docs/News.rst | 3 +++ docs/SQLObject.rst | 2 +- sqlobject/postgres/pgconnection.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 3cba1662..53e959cf 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -14,6 +14,9 @@ Drivers * Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. +* Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, + ``pygresql``. + SQLObject 3.12.0.post2 ====================== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 8f089413..9f46fa30 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -1852,7 +1852,7 @@ parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg``, ``psycopg2``, ``pygresql``, ``pypostgresql``, ``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and -``pypyodbc``). Default is ``psycopg``. +``pypyodbc``). Default are ``psycopg``, ``psycopg2``, ``pygresql``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index bb76afa4..fb24f951 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -57,7 +57,7 @@ class PostgresConnection(DBAPI): def __init__(self, dsn=None, host=None, port=None, db=None, user=None, password=None, **kw): - drivers = kw.pop('driver', None) or 'psycopg' + drivers = kw.pop('driver', None) or 'psycopg,psycopg2,pygresql' for driver in drivers.split(','): driver = driver.strip() if not driver: From 33a25016093e8cbdaddbf14715ab60ecb13084de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 21 Feb 2025 12:42:46 +0300 Subject: [PATCH 247/295] Fix(mysqlconnection): Drop support for CyMySQL Its author refused to fix unicode-related problems. --- docs/News.rst | 3 +++ docs/SQLObject.rst | 5 ++-- docs/download.rst | 2 +- setup.py | 1 - sqlobject/mysql/mysqlconnection.py | 39 +++++++++--------------------- tox.ini | 36 --------------------------- 6 files changed, 17 insertions(+), 69 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 53e959cf..faf967ff 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,9 @@ Drivers * Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, ``pygresql``. +* Dropped support for CyMySQL; + its author refused to fix unicode-related problems. + SQLObject 3.12.0.post2 ====================== diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 9f46fa30..896686be 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -48,7 +48,7 @@ Requirements Currently SQLObject supports MySQL_ and MariaDB_ via MySQLdb_ aka MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, -PyMySQL_, CyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For +PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; see also optimized psycopg-c_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ @@ -65,7 +65,6 @@ passed). .. _mysqlclient: https://pypi.org/project/mysqlclient/ .. _`MySQL Connector`: https://pypi.org/project/mysql-connector/ .. _PyMySQL: https://pypi.org/project/PyMySQL/ -.. _CyMySQL: https://pypi.org/project/CyMySQL/ .. _mariadb connector: https://pypi.org/project/mariadb/ .. _PostgreSQL: https://postgresql.org .. _psycopg: https://pypi.org/project/psycopg/ @@ -1802,7 +1801,7 @@ MySQLConnection supports all the features, though MySQL only supports transactions_ when using the InnoDB backend; SQLObject can explicitly define the backend using ``sqlmeta.createSQL``. -Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``cymysql``, +Supported drivers are ``mysqldb``, ``connector``, ``pymysql``, ``mariadb``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and ``pypyodbc``); default are ``mysqldb``, ``mysqlclient``, ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. diff --git a/docs/download.rst b/docs/download.rst index da11fa1a..88bc739c 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -63,7 +63,7 @@ MySQL ^^^^^ mysql (installs MySQL-python for Python 2.7 and mysqlclient for Python 3.4+) -mysql-connector pymysql cymysql mariadb +mysql-connector pymysql mariadb ODBC ^^^^ diff --git a/setup.py b/setup.py index 1eeb42c7..82699846 100755 --- a/setup.py +++ b/setup.py @@ -143,7 +143,6 @@ 'pymysql:python_version == "3.4"': ['pymysql < 0.10.0'], 'pymysql:python_version == "3.6"': ['pymysql < 1.0.3'], 'pymysql:python_version >= "3.7"': ['pymysql'], - 'cymysql': ['cymysql'], 'mariadb': ['mariadb'], # ODBC 'odbc': ['pyodbc'], diff --git a/sqlobject/mysql/mysqlconnection.py b/sqlobject/mysql/mysqlconnection.py index 8ba4a99e..04490aa7 100644 --- a/sqlobject/mysql/mysqlconnection.py +++ b/sqlobject/mysql/mysqlconnection.py @@ -1,26 +1,19 @@ from sqlobject import col, dberrors -from sqlobject.compat import PY2, string_type +from sqlobject.compat import PY2 from sqlobject.converters import registerConverter, StringLikeConverter from sqlobject.dbconnection import DBAPI class ErrorMessage(str): def __new__(cls, e, append_msg=''): - if e.__module__ == 'cymysql.err': - if isinstance(e.errmsg, string_type): - errmsg = e.errmsg - else: - errmsg = e.errmsg.reason - errcode = e.errno + if len(e.args) > 1: + errmsg = e.args[1] else: - if len(e.args) > 1: - errmsg = e.args[1] - else: - errmsg = '' - try: - errcode = int(e.args[0]) - except ValueError: - errcode = e.args[0] + errmsg = '' + try: + errcode = int(e.args[0]) + except ValueError: + errcode = e.args[0] obj = str.__new__(cls, errmsg + append_msg) obj.code = errcode obj.module = e.__module__ @@ -69,16 +62,6 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): self.CR_SERVER_LOST = \ MySQLdb.constants.CR.CR_SERVER_LOST self.ER_DUP_ENTRY = MySQLdb.constants.ER.DUP_ENTRY - elif driver == 'cymysql': - import cymysql - import cymysql.constants.CR - import cymysql.constants.ER - self.module = cymysql - self.CR_SERVER_GONE_ERROR = \ - cymysql.constants.CR.CR_SERVER_GONE_ERROR - self.CR_SERVER_LOST = \ - cymysql.constants.CR.CR_SERVER_LOST - self.ER_DUP_ENTRY = cymysql.constants.ER.DUP_ENTRY elif driver in ('connector', 'connector-python'): import mysql.connector self.module = mysql.connector @@ -110,7 +93,7 @@ def __init__(self, db, user, password='', host='localhost', port=0, **kw): raise ValueError( 'Unknown MySQL driver "%s", ' 'expected mysqldb, connector, connector-python, ' - 'pymysql, cymysql, mariadb, ' + 'pymysql, mariadb, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -250,7 +233,7 @@ def _setAutoCommit(self, conn, auto): conn.autocommit = auto def _force_reconnect(self, conn): - if self.driver in ('pymysql', 'cymysql'): + if self.driver in ('pymysql',): conn.ping(True) self._setAutoCommit(conn, bool(self.autoCommit)) if self.dbEncoding: @@ -288,7 +271,7 @@ def _executeRetry(self, conn, cursor, query): raise dberrors.OperationalError(ErrorMessage(e)) if self.debug: self.printDebug(conn, str(e), 'ERROR') - if self.driver in ('pymysql', 'cymysql'): + if self.driver in ('pymysql',): self._force_reconnect(conn) else: raise dberrors.OperationalError(ErrorMessage(e)) diff --git a/tox.ini b/tox.ini index a0df8f37..086e7890 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,6 @@ deps = mysql-connector: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt - cymysql: cymysql mariadb: mariadb psycopg: psycopg[binary] psycopg_c: psycopg[c] @@ -128,22 +127,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] commands = {[pymysql]commands} -[cymysql] -commands = - {[testenv]commands} - -mysql --execute="drop database sqlobject_test;" - mysql --execute="create database sqlobject_test;" - pytest -D "mysql://localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" - mysql --execute="drop database sqlobject_test;" - -[testenv:py27-mysql-cymysql-noauto] -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[cymysql]commands} - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cymysql-noauto] -commands = {[cymysql]commands} - [mariadb] commands = {[testenv]commands} @@ -448,25 +431,6 @@ commands = platform = win32 commands = {[pymysql-w32]commands} -[cymysql-w32] -platform = win32 -commands = - {[testenv]commands} - -mysql --user=ODBC -e "drop database sqlobject_test;" - mysql --user=ODBC -e "create database sqlobject_test;" - pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=cymysql&charset=utf8&debug=1" - mysql --user=ODBC -e "drop database sqlobject_test;" - -[testenv:py27-mysql-cymysql-w32-noauto] -platform = win32 -commands = - easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[cymysql-w32]commands} - -[testenv:py3{4,5,6,7,8,9,10,11,12}-mysql-cymysql-w32-noauto] -platform = win32 -commands = {[cymysql-w32]commands} - [mariadb-w32] platform = win32 commands = From d2c26075783a42d9103dee8e783b7f770a981543 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 17:47:00 +0300 Subject: [PATCH 248/295] Fix(psycopg): Convert Binary type --- sqlobject/postgres/pgconnection.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index fb24f951..df478d52 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -104,7 +104,11 @@ def __init__(self, dsn=None, host=None, port=None, db=None, raise ImportError( 'Cannot find a PostgreSQL driver, tried %s' % drivers) - if driver.startswith('psycopg'): + if driver.startswith('psycopg2'): + # Register a converter for psycopg2 Binary type. + registerConverter(type(self.module.Binary('')), + Psyco2BinaryConverter) + elif driver.startswith('psycopg'): # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) @@ -588,8 +592,8 @@ def dropDatabase(self): self._createOrDropDatabase(op="DROP") -# Converter for Binary types -def PsycoBinaryConverter(value, db): +# Converters for Binary types +def Psyco2BinaryConverter(value, db): assert db == 'postgres' return str(value) @@ -608,6 +612,11 @@ def escape_bytea(value): ) +def PsycoBinaryConverter(value, db): + assert db == 'postgres' + return sqlrepr(escape_bytea(value.obj), db) + + def PostgresBinaryConverter(value, db): assert db == 'postgres' return sqlrepr(escape_bytea(value), db) From 07b0ca4b2551fe01654beb96e13a107841137762 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 17:57:45 +0300 Subject: [PATCH 249/295] Fix(psycopg): Extract error code/message --- sqlobject/postgres/pgconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index df478d52..2354142e 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -21,7 +21,7 @@ def __new__(cls, e, append_msg=''): # pg8000 for Python 3.5+ ecode = eargs0['C'] eerror = emessage = eargs0['M'] - elif e.__module__ == 'pg': # PyGreSQL + elif e.__module__ in ('psycopg.errors', 'pg'): # psycopg, PyGreSQL ecode = e.sqlstate eerror = emessage = e.args[0] elif hasattr(e, 'pgcode'): # psycopg2 or psycopg2.errors From f592d97f048387106352782dfbfa90409024b2e5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 18:05:48 +0300 Subject: [PATCH 250/295] Fix outstanding problems with `psycopg` It's now the first class driver. --- docs/News.rst | 2 ++ tox.ini | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index faf967ff..faf06bd8 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -17,6 +17,8 @@ Drivers * Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, ``pygresql``. +* Fixed outstanding problems with ``psycopg``. It's now the first class driver. + * Dropped support for CyMySQL; its author refused to fix unicode-related problems. diff --git a/tox.ini b/tox.ini index 086e7890..e450374d 100644 --- a/tox.ini +++ b/tox.ini @@ -184,7 +184,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg] commands = {[psycopg]commands} [psycopg_c] @@ -498,7 +498,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} From c2374e64a0540b8ae3ac38a0b72d6b6c66ec26c8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 19:52:11 +0300 Subject: [PATCH 251/295] Tests(GHActions): Fix old bug in the workflow on w32 If a bat/cmd file is simply executed from another it replaces the caller. To execute a few ones in a row each must be `call`ed. --- .github/workflows/run-tests.yaml | 6 +++--- docs/News.rst | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 16119295..760ec89e 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -104,8 +104,8 @@ jobs: shell: bash -el {0} - name: Run tox @ w32 run: | - devscripts\tox-select-envs.cmd %PYVER%-mysql - devscripts\tox-select-envs.cmd %PYVER%-postgres - devscripts\tox-select-envs.cmd %PYVER%-sqlite + call devscripts\tox-select-envs.cmd %PYVER%-mysql + call devscripts\tox-select-envs.cmd %PYVER%-postgres + call devscripts\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} shell: cmd /C CALL {0} diff --git a/docs/News.rst b/docs/News.rst index faf06bd8..dd0e7514 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,6 +22,11 @@ Drivers * Dropped support for CyMySQL; its author refused to fix unicode-related problems. +CI +-- + +* Tests(GHActions): Fixed old bug in the workflow on w32. + SQLObject 3.12.0.post2 ====================== From f5c41a4a0c1033fcb73d4a4300302cdac6a9e1fa Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 21:43:23 +0300 Subject: [PATCH 252/295] Tests(tox): Rename `mysql-connector` tests to `mysql-cnx` This is to avoid installing `mysql-connector` into `mysql-connector-python` tests. --- tox.ini | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tox.ini b/tox.ini index e450374d..89c6c7c6 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,7 @@ deps = !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient - mysql-connector: mysql-connector <= 2.2.2 + mysql-cnx: mysql-connector <= 2.2.2 mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb @@ -79,7 +79,7 @@ deps = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} -[mysql-connector] +[mysql-cnx] commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" @@ -87,13 +87,13 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector] +[testenv:py27-mysql-cnx] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector]commands} + {[mysql-cnx]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] -commands = {[mysql-connector]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx] +commands = {[mysql-cnx]commands} [mysql-connector-python] commands = @@ -393,7 +393,7 @@ commands = platform = win32 commands = {[mssql-pyodbc-w32]commands} -[mysql-connector-w32] +[mysql-cnx-w32] platform = win32 commands = {[testenv]commands} From 9cc652db6516aadb1dcebb395d1de53d95a1421b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 21:49:52 +0300 Subject: [PATCH 253/295] Tests(tox): Improve tests of `mysql-connector` --- docs/News.rst | 5 +++++ tox.ini | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index dd0e7514..9b573dab 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,6 +22,11 @@ Drivers * Dropped support for CyMySQL; its author refused to fix unicode-related problems. +Tests +----- + +* Improved tests of ``mysql-connector``. + CI -- diff --git a/tox.ini b/tox.ini index 89c6c7c6..48ce6eba 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,7 @@ deps = !py34: zope.datetime mysqldb: mysql-python mysqlclient: mysqlclient - mysql-cnx: mysql-connector <= 2.2.2 + mysql-cnx: mysql-connector mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb From 9d3e36f8a282c915cffb6068ef13e4aaeb5dec4c Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 21:45:13 +0300 Subject: [PATCH 254/295] Tests(tox): Fix `mysql-connector-python-w32` tests --- docs/News.rst | 2 +- tox.ini | 31 +++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 9b573dab..955ed2f5 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -25,7 +25,7 @@ Drivers Tests ----- -* Improved tests of ``mysql-connector``. +* Improved tests of ``mysql-connector`` and ``mysql-connector-python``. CI -- diff --git a/tox.ini b/tox.ini index 48ce6eba..069a7c7f 100644 --- a/tox.ini +++ b/tox.ini @@ -103,12 +103,12 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector-python{,-w32}] +[testenv:py27-mysql-connector-python] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-python]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python{,-w32}] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python] commands = {[mysql-connector-python]commands} [pymysql] @@ -402,15 +402,34 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27-mysql-connector-w32] +[testenv:py27-mysql-cnx-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector-w32]commands} + {[mysql-cnx-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx-w32] platform = win32 -commands = {[mysql-connector-w32]commands} +commands = {[mysql-cnx-w32]commands} + +[mysql-connector-python-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27-mysql-connector-python-w32] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysql-connector-python-w32]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python-w32] +platform = win32 +commands = {[mysql-connector-python-w32]commands} [pymysql-w32] platform = win32 From 6fd55a0e884c6c60f7ac811fc223740f50b47268 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 22:44:05 +0300 Subject: [PATCH 255/295] Tests(tox): Run `psycopg2` tests under Py 3.13 --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index 069a7c7f..f410030d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,312}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,313}-flake8 # Base test environment settings [testenv] @@ -211,7 +211,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2] commands = {[psycopg2]commands} [pygresql] @@ -549,7 +549,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12}-postgres-psycopg2-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} From 5c8fe5b2a97c5049f04b68ee6a97d1fcc13206e5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Feb 2025 23:23:29 +0300 Subject: [PATCH 256/295] Tests(GHActions): Better error handling Abort chain of tests on any error and fail the entire workflow. --- .github/workflows/run-tests.yaml | 14 +++++++------- docs/News.rst | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 760ec89e..d81585f4 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -96,16 +96,16 @@ jobs: shell: bash -el {0} - name: Run tox @ Linux run: | - devscripts/tox-select-envs $PYVER-mysql - devscripts/tox-select-envs $PYVER-postgres - devscripts/tox-select-envs $PYVER-sqlite + devscripts/tox-select-envs $PYVER-mysql && + devscripts/tox-select-envs $PYVER-postgres && + devscripts/tox-select-envs $PYVER-sqlite && devscripts/tox-select-envs $PYVER-flake8 if: ${{ runner.os == 'Linux' }} shell: bash -el {0} - name: Run tox @ w32 - run: | - call devscripts\tox-select-envs.cmd %PYVER%-mysql - call devscripts\tox-select-envs.cmd %PYVER%-postgres - call devscripts\tox-select-envs.cmd %PYVER%-sqlite + run: > + devscripts\\tox-select-envs.cmd %PYVER%-mysql && + devscripts\\tox-select-envs.cmd %PYVER%-postgres && + devscripts\\tox-select-envs.cmd %PYVER%-sqlite if: ${{ runner.os == 'Windows' }} shell: cmd /C CALL {0} diff --git a/docs/News.rst b/docs/News.rst index 955ed2f5..a88fac97 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -30,7 +30,7 @@ Tests CI -- -* Tests(GHActions): Fixed old bug in the workflow on w32. +* Tests(GHActions): Fixed old bugs in the workflow on w32. SQLObject 3.12.0.post2 ====================== From 3186b3d6121e93d6787754fdc569e9da4adf4aed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 07:54:29 +0300 Subject: [PATCH 257/295] Tests(tox): Skip `psycopg2` test under Py 3.8 on w32 Somehow Python cannot import `psycopg2`; could be a buggy wheel. --- tox.ini | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f410030d..0ddc4c65 100644 --- a/tox.ini +++ b/tox.ini @@ -549,7 +549,12 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2-w32] +[testenv:py38-postgres-psycopg2-noauto-w32] +platform = win32 +commands = {envpython} -c "print('Skipped...')" +deps = + +[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} From ecbb61d11bda8b795167e9c78e56ed38aeb2cd91 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 08:03:21 +0300 Subject: [PATCH 258/295] Tests: Add tests for `mysqldb` and `mysqlclient` on w32 --- .../requirements/requirements_mysqlclient.txt | 9 +++++ docs/News.rst | 3 ++ tox.ini | 40 ++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 devscripts/requirements/requirements_mysqlclient.txt diff --git a/devscripts/requirements/requirements_mysqlclient.txt b/devscripts/requirements/requirements_mysqlclient.txt new file mode 100644 index 00000000..53611366 --- /dev/null +++ b/devscripts/requirements/requirements_mysqlclient.txt @@ -0,0 +1,9 @@ +mysqlclient == 2.0.3; python_version == '3.6' and sys_platform == 'win32' +mysqlclient == 2.0.3; python_version == '3.7' and sys_platform == 'win32' +mysqlclient == 2.1.1; python_version == '3.8' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.9' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.10' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.11' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.12' and sys_platform == 'win32' +mysqlclient >= 2.2.7; python_version == '3.13' and sys_platform == 'win32' +mysqlclient; sys_platform != 'win32' diff --git a/docs/News.rst b/docs/News.rst index a88fac97..372b6130 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -25,6 +25,9 @@ Drivers Tests ----- +* Added tests for ``mysqldb`` (aka ``mysql-python``) + and ``mysqlclient`` on w32. + * Improved tests of ``mysql-connector`` and ``mysql-connector-python``. CI diff --git a/tox.ini b/tox.ini index 0ddc4c65..0df772c8 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ deps = py34: zope.datetime < 4.3 !py34: zope.datetime mysqldb: mysql-python - mysqlclient: mysqlclient + mysqlclient: -rdevscripts/requirements/requirements_mysqlclient.txt mysql-cnx: mysql-connector mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt @@ -393,6 +393,44 @@ commands = platform = win32 commands = {[mssql-pyodbc-w32]commands} +[mysqldb-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27-mysqldb-noauto-w32] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[mysqldb-w32]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb-w32] +platform = win32 +commands = {envpython} -c "print('MySQL-python requires Python 2.7')" +deps = + +[mysqlclient-w32] +platform = win32 +commands = + {[testenv]commands} + -mysql --user=ODBC -e "drop database sqlobject_test;" + mysql --user=ODBC -e "create database sqlobject_test;" + pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" + mysql --user=ODBC -e "drop database sqlobject_test;" + +[testenv:py27,py3{4,5}-mysqlclient-noauto-w32] +platform = win32 +commands = {envpython} -c "print('mysqlclient requires Python 3.6+')" +deps = + +[testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] +platform = win32 +commands = {[mysqlclient-w32]commands} + [mysql-cnx-w32] platform = win32 commands = From 2cc558e355b57a0abe15130444d5e3f843b609f6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 18:30:10 +0300 Subject: [PATCH 259/295] Tests(tox): Remove dummy environments --- tox.ini | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/tox.ini b/tox.ini index 0df772c8..331278a3 100644 --- a/tox.ini +++ b/tox.ini @@ -60,10 +60,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb] -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - [mysqlclient] commands = {[testenv]commands} @@ -72,10 +68,6 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysqlclient] -commands = {envpython} -c "print('mysqlclient requires Python 3.4+')" -deps = - [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} @@ -135,10 +127,6 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py{27,34,35}-mariadb] -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - [testenv:py3{6,7,8,9,10,11,12,13}-mariadb] commands = {[mariadb]commands} @@ -238,10 +226,6 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql-noauto] -commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" -deps = - [testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto] commands = {[pypostgresql]commands} @@ -408,11 +392,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysqldb-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqldb-w32] -platform = win32 -commands = {envpython} -c "print('MySQL-python requires Python 2.7')" -deps = - [mysqlclient-w32] platform = win32 commands = @@ -422,11 +401,6 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27,py3{4,5}-mysqlclient-noauto-w32] -platform = win32 -commands = {envpython} -c "print('mysqlclient requires Python 3.6+')" -deps = - [testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] platform = win32 commands = {[mysqlclient-w32]commands} @@ -497,11 +471,6 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py{27,34,35}-mariadb-w32] -platform = win32 -commands = {envpython} -c "print('mariadb requires Python 3.6+')" -deps = - [testenv:py3{6,7,8,9,10,11,12,13}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -587,11 +556,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py38-postgres-psycopg2-noauto-w32] -platform = win32 -commands = {envpython} -c "print('Skipped...')" -deps = - [testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} @@ -624,11 +588,6 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pypostgresql-noauto-w32] -platform = win32 -commands = {envpython} -c "print('pypostgresql requires Python 3.4+')" -deps = - [testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto-w32] platform = win32 commands = {[pypostgresql-w32]commands} From 90d193dbf3cad7679c2f277efa792207a35e7cde Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 1 Mar 2025 18:35:13 +0300 Subject: [PATCH 260/295] Tests(tox): Run tests with `psycopg[c]` --- docs/News.rst | 2 ++ tox.ini | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 372b6130..54a40fea 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -35,6 +35,8 @@ CI * Tests(GHActions): Fixed old bugs in the workflow on w32. +* Run tests with ``psycopg[c]``. + SQLObject 3.12.0.post2 ====================== diff --git a/tox.ini b/tox.ini index 331278a3..5d38525a 100644 --- a/tox.ini +++ b/tox.ini @@ -183,7 +183,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c] commands = {[psycopg_c]commands} [psycopg2] @@ -537,7 +537,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-noauto-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-w32] platform = win32 commands = {[psycopg_c-w32]commands} From 2db031376148d5153994cfd3ff5ff59e135ccc17 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Mar 2025 22:48:19 +0300 Subject: [PATCH 261/295] Docs(News): Fix literal --- docs/News.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index 54a40fea..0233fcaa 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,7 +19,7 @@ Drivers * Fixed outstanding problems with ``psycopg``. It's now the first class driver. -* Dropped support for CyMySQL; +* Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. Tests From efd01ad9d8bc56a5820852f5c6bdc7550c6f1793 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Mar 2025 22:49:06 +0300 Subject: [PATCH 262/295] Feat(Pg): Dropped support for `py-postgresql` It's completely broken with debianized `Postgres` and the authors reject fixes. --- ANNOUNCE.rst | 9 ++++----- README.rst | 9 ++++----- docs/News.rst | 3 +++ docs/SQLObject.rst | 9 ++++----- docs/download.rst | 5 ++--- setup.py | 2 -- sqlobject/postgres/pgconnection.py | 19 ++----------------- tox.ini | 25 ------------------------- 8 files changed, 19 insertions(+), 62 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 47a37342..7e3a6637 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -36,11 +36,10 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, -``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); -connections to other backends -- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less -debugged). +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg``, ``psycopg2``, ``PyGreSQL``, +partially ``pg8000``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also +known as SAPDB) - are less debugged). Python 2.7 or 3.4+ is required. diff --git a/README.rst b/README.rst index 1829efc9..3fde456b 100644 --- a/README.rst +++ b/README.rst @@ -8,11 +8,10 @@ quick to get started with. SQLObject supports a number of backends: MySQL/MariaDB (with a number of DB API drivers: ``MySQLdb``, ``mysqlclient``, ``mysql-connector``, -``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg2``, ``PyGreSQL``, -partially ``pg8000`` and ``py-postgresql``), SQLite (builtin ``sqlite3``); -connections to other backends -- Firebird, Sybase, MSSQL and MaxDB (also known as SAPDB) - are less -debugged). +``PyMySQL``, ``mariadb``), PostgreSQL (``psycopg``, ``psycopg2``, ``PyGreSQL``, +partially ``pg8000``), SQLite (builtin ``sqlite3``); +connections to other backends - Firebird, Sybase, MSSQL and MaxDB (also +known as SAPDB) - are less debugged). Python 2.7 or 3.4+ is required. diff --git a/docs/News.rst b/docs/News.rst index 0233fcaa..a6065413 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -22,6 +22,9 @@ Drivers * Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. +* Dropped support for ``py-postgresql``; it's completely broken + with debianized ``Postgres`` and the authors reject fixes. + Tests ----- diff --git a/docs/SQLObject.rst b/docs/SQLObject.rst index 896686be..1dd4dcd7 100644 --- a/docs/SQLObject.rst +++ b/docs/SQLObject.rst @@ -51,7 +51,7 @@ MySQL-python (called mysqlclient_ for Python 3), `MySQL Connector`_, PyMySQL_, `mariadb connector`_, PyODBC_ and PyPyODBC_. For PostgreSQL_ psycopg_ and psycopg2_ are recommended, especially their precompiled wheels psycopg-binary_ and psycopg2-binary_; see also optimized -psycopg-c_; PyGreSQL_, py-postgresql_ and pg8000_ are supported; SQLite_ +psycopg-c_; PyGreSQL_ and pg8000_ are supported; SQLite_ has a built-in driver. Firebird_ is supported via fdb_ or kinterbasdb_; pyfirebirdsql_ is supported but has problems. `MAX DB`_ (also known as SAP DB) is supported via sapdb_. Sybase via Sybase_. `MSSQL Server`_ via @@ -73,7 +73,6 @@ passed). .. _psycopg2: https://www.psycopg.org/ .. _psycopg2-binary: https://pypi.org/project/psycopg2-binary/ .. _PyGreSQL: http://www.pygresql.org/ -.. _py-postgresql: https://pypi.org/project/py-postgresql/ .. _pg8000: https://pypi.org/project/pg8000/ .. _SQLite: https://sqlite.org/ .. _Firebird: http://www.firebirdsql.org/en/python-driver/ @@ -1849,9 +1848,9 @@ PostgresConnection supports transactions and all other features. The user can choose a DB API driver for PostgreSQL by using a ``driver`` parameter in DB URI or PostgresConnection that can be a comma-separated list of driver names. Possible drivers are: ``psycopg``, ``psycopg2``, -``pygresql``, ``pypostgresql``, ``pg8000``, -``pyodbc``, ``pypyodbc`` or ``odbc`` (try ``pyodbc`` and -``pypyodbc``). Default are ``psycopg``, ``psycopg2``, ``pygresql``. +``pygresql``, ``pg8000``, ``pyodbc``, ``pypyodbc`` or ``odbc`` (try +``pyodbc`` and ``pypyodbc``). Default are ``psycopg``, ``psycopg2``, +``pygresql``. Connection-specific parameters are: ``sslmode``, ``unicodeCols``, ``schema``, ``charset``. diff --git a/docs/download.rst b/docs/download.rst index 88bc739c..d873d0bd 100644 --- a/docs/download.rst +++ b/docs/download.rst @@ -73,9 +73,8 @@ pyodbc pypyodbc odbc (synonym for pyodbc) PostgreSQL ^^^^^^^^^^ -psycopg -psycopg2 postgres postgresql (synonyms for psycopg2) -pygresql pypostgresql py-postgresql pg8000 +psycopg psycopg2 postgres postgresql (synonyms for psycopg2) +pygresql pg8000 The rest ^^^^^^^^ diff --git a/setup.py b/setup.py index 82699846..bc6a45a8 100755 --- a/setup.py +++ b/setup.py @@ -158,8 +158,6 @@ 'psycopg2-binary:python_version!="3.4"': ['psycopg2-binary'], 'pygresql:python_version=="3.4"': ['pygresql < 5.2'], 'pygresql:python_version!="3.4"': ['pygresql'], - 'pypostgresql': ['py-postgresql'], - 'py-postgresql': ['py-postgresql'], 'pg8000:python_version=="2.7"': ['pg8000 < 1.13'], 'pg8000:python_version=="3.4"': ['pg8000 < 1.12.4'], 'pg8000:python_version>="3.5"': ['pg8000'], diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 2354142e..a128ab8e 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -72,9 +72,6 @@ def __init__(self, dsn=None, host=None, port=None, db=None, elif driver == 'pygresql': import pgdb self.module = pgdb - elif driver in ('py-postgresql', 'pypostgresql'): - from postgresql.driver import dbapi20 - self.module = dbapi20 elif driver == 'pg8000': import pg8000 self.module = pg8000 @@ -94,7 +91,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, raise ValueError( 'Unknown PostgreSQL driver "%s", ' 'expected psycopg, psycopg2, ' - 'pygresql, pypostgresql, pg8000, ' + 'pygresql, pg8000, ' 'odbc, pyodbc or pypyodbc' % driver) except ImportError: pass @@ -112,7 +109,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, # Register a converter for psycopg Binary type. registerConverter(type(self.module.Binary('')), PsycoBinaryConverter) - elif driver in ('pygresql', 'py-postgresql', 'pypostgresql', 'pg8000'): + elif driver in ('pygresql', 'pg8000'): registerConverter(type(self.module.Binary(b'')), PostgresBinaryConverter) elif driver in ('odbc', 'pyodbc', 'pypyodbc'): @@ -184,13 +181,6 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if sslmode: dsn.append('sslmode=%s' % sslmode) dsn = ' '.join(dsn) - if driver in ('py-postgresql', 'pypostgresql'): - if host and host.startswith('/'): - dsn_dict["host"] = dsn_dict["port"] = None - dsn_dict["unix"] = host - else: - if "unix" in dsn_dict: - del dsn_dict["unix"] if driver == 'pg8000': if host and host.startswith('/'): dsn_dict["host"] = None @@ -312,11 +302,6 @@ def _queryInsertID(self, conn, soInstance, id, names, values): table = soInstance.sqlmeta.table idName = soInstance.sqlmeta.idName c = conn.cursor() - if id is None and self.driver in ('py-postgresql', 'pypostgresql'): - sequenceName = soInstance.sqlmeta.idSequence or \ - '%s_%s_seq' % (table, idName) - self._executeRetry(conn, c, "SELECT NEXTVAL('%s')" % sequenceName) - id = c.fetchone()[0] if id is not None: names = [idName] + names values = [id] + values diff --git a/tox.ini b/tox.ini index 5d38525a..24b235b6 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,6 @@ deps = py34-psycopg2: psycopg2-binary==2.8.4 !py34-psycopg2: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt - pypostgresql: git+https://github.com/sqlobject/py-postgresql.git@combined-fixes#egg=py-postgresql pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc pypyodbc: pypyodbc @@ -218,17 +217,6 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql] commands = {[pygresql]commands} -[pypostgresql] -commands = - {[testenv]commands} - -dropdb --username=runner --no-password sqlobject_test - createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" - dropdb --username=runner --no-password sqlobject_test - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto] -commands = {[pypostgresql]commands} - [pg8000] commands = {[testenv]commands} @@ -579,19 +567,6 @@ commands = platform = win32 commands = {[pygresql-w32]commands} -[pypostgresql-w32] -platform = win32 -commands = - {[testenv]commands} - -dropdb --username=runner --no-password sqlobject_test - createdb --username=runner --no-password sqlobject_test - pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pypostgresql&sslmode=allow&charset=utf-8&debug=1" - dropdb --username=runner --no-password sqlobject_test - -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypostgresql-noauto-w32] -platform = win32 -commands = {[pypostgresql-w32]commands} - [pg8000-w32] platform = win32 commands = From e2dfa497451a7c6d010ac754fbe4644527811726 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 3 Mar 2025 21:58:45 +0300 Subject: [PATCH 263/295] Fix(pg8000): Fixed all problems --- docs/News.rst | 3 +++ sqlobject/postgres/pgconnection.py | 8 ++++++-- sqlobject/tests/dbtest.py | 3 +++ sqlobject/tests/test_exceptions.py | 7 +++++-- sqlobject/tests/test_schema.py | 10 ++++++---- tox.ini | 9 +++------ 6 files changed, 26 insertions(+), 14 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index a6065413..fd4cacc3 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -19,6 +19,9 @@ Drivers * Fixed outstanding problems with ``psycopg``. It's now the first class driver. +* Fixed all problems with ``pg8000``. It's now close to become + the first class driver. + * Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index a128ab8e..ac18a6f8 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -73,8 +73,12 @@ def __init__(self, dsn=None, host=None, port=None, db=None, import pgdb self.module = pgdb elif driver == 'pg8000': - import pg8000 - self.module = pg8000 + try: + import pg8000.dbapi + self.module = pg8000.dbapi + except ImportError: + import pg8000 + self.module = pg8000 elif driver == 'pyodbc': import pyodbc self.module = pyodbc diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index e934ac51..e2693f1d 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -101,6 +101,9 @@ def getConnection(**kw): conn.debug = True if conftest.option.show_sql_output: conn.debugOutput = True + if (conn.dbName == 'postgres') and (conn.driver == 'pg8000') \ + and conn._pool is not None: + conn._pool = None if (conn.dbName == 'sqlite') and not conn._memory: speedupSQLiteConnection(conn) return conn diff --git a/sqlobject/tests/test_exceptions.py b/sqlobject/tests/test_exceptions.py index 169ca188..ff05bd0e 100644 --- a/sqlobject/tests/test_exceptions.py +++ b/sqlobject/tests/test_exceptions.py @@ -1,7 +1,7 @@ import pytest from sqlobject import SQLObject, StringCol -from sqlobject.dberrors import DuplicateEntryError, OperationalError, \ - ProgrammingError +from sqlobject.dberrors import DatabaseError, DuplicateEntryError, \ + OperationalError, ProgrammingError from sqlobject.tests.dbtest import getConnection, raises, setupClass, supports @@ -33,5 +33,8 @@ def test_exceptions(): assert e.args[0].code in (1146, '42P01') except OperationalError: assert connection.dbName == 'sqlite' + except DatabaseError: + assert connection.dbName == 'postgres' \ + and connection.driver == 'pg8000' else: assert False, "DID NOT RAISE" diff --git a/sqlobject/tests/test_schema.py b/sqlobject/tests/test_schema.py index 4a7887d4..5d4e3ad6 100644 --- a/sqlobject/tests/test_schema.py +++ b/sqlobject/tests/test_schema.py @@ -22,7 +22,9 @@ def test_connection_schema(): conn.query('SET search_path TO test') setupClass(SOTestSchema) assert SOTestSchema._connection is conn - SOTestSchema(foo='bar') - assert conn.queryAll("SELECT * FROM test.so_test_schema") - conn.schema = None - conn.query('SET search_path TO public') + try: + SOTestSchema(foo='bar') + assert conn.queryAll("SELECT * FROM test.so_test_schema") + finally: + conn.schema = None + conn.query('SET search_path TO public') diff --git a/tox.ini b/tox.ini index 24b235b6..c918dd8e 100644 --- a/tox.ini +++ b/tox.ini @@ -230,10 +230,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6}-postgres-pg8000] -commands = {[pg8000]commands} - -[testenv:py3{7,8,9,10,11,12,13}-postgres-pg8000-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -576,13 +573,13 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pg8000-noauto-w32] +[testenv:py27-postgres-pg8000-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} From c61aa5a4a23cecd712a0836ec0c2afe628795271 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 15:47:18 +0300 Subject: [PATCH 264/295] Tests(tox): Rename `mysql-connector-python` tests to `mysql-connector_py` Restored `mysql-connector`. This is to avoid confusing `mysql-connector` and `mysql-connector-python` tests. --- tox.ini | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tox.ini b/tox.ini index c918dd8e..bb8ed529 100644 --- a/tox.ini +++ b/tox.ini @@ -16,8 +16,8 @@ deps = !py34: zope.datetime mysqldb: mysql-python mysqlclient: -rdevscripts/requirements/requirements_mysqlclient.txt - mysql-cnx: mysql-connector - mysql-connector-python: -rdevscripts/requirements/requirements_connector_python.txt + mysql-connector: mysql-connector + mysql-connector_py: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb psycopg: psycopg[binary] @@ -70,7 +70,7 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] commands = {[mysqlclient]commands} -[mysql-cnx] +[mysql-connector] commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" @@ -78,15 +78,15 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-cnx] +[testenv:py27-mysql-connector] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-cnx]commands} + {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx] -commands = {[mysql-cnx]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] +commands = {[mysql-connector]commands} -[mysql-connector-python] +[mysql-connector_py] commands = {[testenv]commands} -mysql --execute="drop database sqlobject_test;" @@ -94,13 +94,13 @@ commands = pytest -D "mysql://runner:@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py27-mysql-connector-python] +[testenv:py27-mysql-connector_py] commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector-python]commands} + {[mysql-connector_py]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python] -commands = {[mysql-connector-python]commands} +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py] +commands = {[mysql-connector_py]commands} [pymysql] commands = @@ -390,7 +390,7 @@ commands = platform = win32 commands = {[mysqlclient-w32]commands} -[mysql-cnx-w32] +[mysql-connector-w32] platform = win32 commands = {[testenv]commands} @@ -399,17 +399,17 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27-mysql-cnx-w32] +[testenv:py27-mysql-connector-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-cnx-w32]commands} + {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-cnx-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] platform = win32 -commands = {[mysql-cnx-w32]commands} +commands = {[mysql-connector-w32]commands} -[mysql-connector-python-w32] +[mysql-connector_py-w32] platform = win32 commands = {[testenv]commands} @@ -418,15 +418,15 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=connector-python&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py27-mysql-connector-python-w32] +[testenv:py27-mysql-connector_py-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base - {[mysql-connector-python-w32]commands} + {[mysql-connector_py-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-python-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py-w32] platform = win32 -commands = {[mysql-connector-python-w32]commands} +commands = {[mysql-connector_py-w32]commands} [pymysql-w32] platform = win32 From e16bb5901cfb1916c23ed441435b22723a006d25 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 15:50:53 +0300 Subject: [PATCH 265/295] Feat(pg8000): Declare it the first class driver --- docs/News.rst | 5 ++--- sqlobject/postgres/pgconnection.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index fd4cacc3..9d2940eb 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -15,12 +15,11 @@ Drivers ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. * Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, - ``pygresql``. + ``pygresql``, ``pg8000``. * Fixed outstanding problems with ``psycopg``. It's now the first class driver. -* Fixed all problems with ``pg8000``. It's now close to become - the first class driver. +* Fixed all problems with ``pg8000``. It's now the first class driver. * Dropped support for ``CyMySQL``; its author refused to fix unicode-related problems. diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index ac18a6f8..7d9f918b 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -57,7 +57,7 @@ class PostgresConnection(DBAPI): def __init__(self, dsn=None, host=None, port=None, db=None, user=None, password=None, **kw): - drivers = kw.pop('driver', None) or 'psycopg,psycopg2,pygresql' + drivers = kw.pop('driver', None) or 'psycopg,psycopg2,pygresql,pg8000' for driver in drivers.split(','): driver = driver.strip() if not driver: From 0217eb3c33bf7106ffd32b8c4919a86ad71a5de2 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 16:34:59 +0300 Subject: [PATCH 266/295] Release 3.13.0 --- ANNOUNCE.rst | 48 +++++++++++++++++++++++++++------------ README.rst | 4 ++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 +++-- setup.py | 2 +- sqlobject/__version__.py | 8 +++---- 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 7e3a6637..f6dc6fee 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,25 +1,45 @@ Hello! -I'm pleased to announce version 3.12.1a1, the first alpha of the upcoming -release of branch 3.12 of SQLObject. +I'm pleased to announce version 3.13.0, the first release of branch +3.13 of SQLObject. -I'm pleased to announce version 3.12.1a2, the second alpha of the upcoming -release of branch 3.12 of SQLObject. -I'm pleased to announce version 3.12.1b1, the first beta of the upcoming -release of branch 3.12 of SQLObject. +What's new in SQLObject +======================= -I'm pleased to announce version 3.12.1rc1, the first release candidate -of the upcoming release of branch 3.12 of SQLObject. +Drivers +------- -I'm pleased to announce version 3.12.1, the first bugfix release of branch -3.12 of SQLObject. +* Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, + ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. +* Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, + ``pygresql``, ``pg8000``. -What's new in SQLObject -======================= +* Fixed outstanding problems with ``psycopg``. It's now the first class driver. + +* Fixed all problems with ``pg8000``. It's now the first class driver. + +* Dropped support for ``CyMySQL``; + its author refused to fix unicode-related problems. + +* Dropped support for ``py-postgresql``; it's completely broken + with debianized ``Postgres`` and the authors reject fixes. + +Tests +----- + +* Added tests for ``mysqldb`` (aka ``mysql-python``) + and ``mysqlclient`` on w32. + +* Improved tests of ``mysql-connector`` and ``mysql-connector-python``. + +CI +-- + +* Tests(GHActions): Fixed old bugs in the workflow on w32. -The contributors for this release are ... Thanks! +* Run tests with ``psycopg[c]``. For a more complete list, please see the news: @@ -51,7 +71,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.12.1a0.dev20250201/ +https://pypi.org/project/SQLObject/3.13.0 News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 3fde456b..4e7af749 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.12.0.post2 -====================== +SQLObject 3.13.0 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 8d508b27..3e3cda0e 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.12.0.post2 && +build_docs 3.13.0 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 9d2940eb..f4a3f403 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject (development) -======================= +SQLObject 3.13.0 +================ + +Released 2025 Mar 07. Drivers ------- diff --git a/setup.py b/setup.py index bc6a45a8..1bd4ea19 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 9a310a1e..cc6e4c51 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.12.0.post2' +version = '3.13.0' major = 3 -minor = 12 +minor = 13 micro = 0 -release_level = 'post' -serial = 2 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From 27b78f03439786ac5b9366755fc6a227bbcf1051 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 7 Mar 2025 16:47:14 +0300 Subject: [PATCH 267/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 49 ++++++++++++++++--------------------------------- docs/News.rst | 3 +++ setup.py | 2 +- 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index f6dc6fee..dfdda2c5 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,45 +1,28 @@ Hello! -I'm pleased to announce version 3.13.0, the first release of branch -3.13 of SQLObject. - - -What's new in SQLObject -======================= - -Drivers -------- - -* Extended default list of MySQL drivers to ``mysqldb``, ``mysqlclient``, - ``mysql-connector``, ``mysql-connector-python``, ``pymysql``. +I'm pleased to announce version 3.13.1a1, the first alpha of the upcoming +release of branch 3.13 of SQLObject. -* Extended default list of PostgreSQL drivers to ``psycopg``, ``psycopg2``, - ``pygresql``, ``pg8000``. +I'm pleased to announce version 3.13.1a2, the second alpha of the upcoming +release of branch 3.13 of SQLObject. -* Fixed outstanding problems with ``psycopg``. It's now the first class driver. +I'm pleased to announce version 3.13.1b1, the first beta of the upcoming +release of branch 3.13 of SQLObject. -* Fixed all problems with ``pg8000``. It's now the first class driver. +I'm pleased to announce version 3.13.1rc1, the first release candidate +of the upcoming release of branch 3.13 of SQLObject. -* Dropped support for ``CyMySQL``; - its author refused to fix unicode-related problems. - -* Dropped support for ``py-postgresql``; it's completely broken - with debianized ``Postgres`` and the authors reject fixes. - -Tests ------ - -* Added tests for ``mysqldb`` (aka ``mysql-python``) - and ``mysqlclient`` on w32. +I'm pleased to announce version 3.13.1, the first bugfix release of branch +3.13 of SQLObject. -* Improved tests of ``mysql-connector`` and ``mysql-connector-python``. +I'm pleased to announce version 3.13.0, the first release of branch +3.13 of SQLObject. -CI --- -* Tests(GHActions): Fixed old bugs in the workflow on w32. +What's new in SQLObject +======================= -* Run tests with ``psycopg[c]``. +The contributors for this release are ... Thanks! For a more complete list, please see the news: @@ -71,7 +54,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.0 +https://pypi.org/project/SQLObject/3.13.1a0.dev20250307/ News and changes: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index f4a3f403..217097af 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject development (master) +============================== + SQLObject 3.13.0 ================ diff --git a/setup.py b/setup.py index 1bd4ea19..bc6a45a8 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From f6b1c42b2046e77b20b502068b1d5a486abac726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D0=B4=D1=8B=D1=86=D0=BA=D0=B8=D0=B9=20=D0=98=D0=B3?= =?UTF-8?q?=D0=BE=D1=80=D1=8C?= Date: Wed, 9 Apr 2025 10:15:19 +0300 Subject: [PATCH 268/295] fix: connect to old mssql versions via set tds_version uri parameter --- sqlobject/mssql/mssqlconnection.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sqlobject/mssql/mssqlconnection.py b/sqlobject/mssql/mssqlconnection.py index 9c179e93..d2fff311 100644 --- a/sqlobject/mssql/mssqlconnection.py +++ b/sqlobject/mssql/mssqlconnection.py @@ -105,6 +105,8 @@ def _make_conn_str(keys): ('host', keys.host), ('port', keys.port), ('timeout', keys.timeout), + ('charset', keys.charset), + ('tds_version', keys.tds_version), ): if value: keys_dict[attr] = value @@ -118,6 +120,8 @@ def _make_conn_str(keys): self.host = host self.port = port self.db = db + self.charset = kw.pop("charset", None) + self.tds_version = kw.pop("tds_version", None) self._server_version = None self._can_use_max_types = None self._can_use_microseconds = None From 6041aa6a0e2364718094b2ce0a2f67276c5fbfce Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 9 Apr 2025 14:30:17 +0300 Subject: [PATCH 269/295] Docs(Authors): Add Igor Yudytskiy [skip ci] --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 6c5b23c9..89a9e374 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -40,6 +40,7 @@ Contributions have been made by: * James Hudson * Juergen Gmach * Hugo van Kemenade +* Igor Yudytskiy * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 From 8435099637695ab96c2e00cb17f45e08a8214e95 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Apr 2025 14:47:32 +0300 Subject: [PATCH 270/295] Build(release): Fix path to include script [skip ci] --- devscripts/release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devscripts/release b/devscripts/release index f5a2e576..ed981234 100755 --- a/devscripts/release +++ b/devscripts/release @@ -15,7 +15,7 @@ find build -name '*.py[co]' -delete && python setup.py bdist_wheel --universal && version=`python setup.py --version` -. `dirname $0`/split_tag.sh && +. devscripts/split_tag.sh && split_tag $version if [ "$state" = final ]; then From affe990d0ced03f9e7f904461873c6f501ba87c1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 11 Apr 2025 14:48:01 +0300 Subject: [PATCH 271/295] Build(release): Rename both sdist and wheel files to lower-case [skip ci] --- devscripts/release | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/devscripts/release b/devscripts/release index ed981234..2df10e0f 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,11 +24,15 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -if [ -f dist/SQLObject-$version.tar.gz ]; then - cd dist && - mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz && - cd .. +cd dist && +if [ -f SQLObject-$version.tar.gz ]; then + mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz fi && +if [ -f SQLObject-$version-py2.py3-none-any.whl ]; then + mv SQLObject-$version-py2.py3-none-any.whl \ + sqlobject-$version-py2.py3-none-any.whl +fi && +cd .. && twine upload --disable-progress-bar --skip-existing dist/* && exec rm -rf build dist docs/html SQLObject.egg-info From 49a7268d44f86d356496d637a7d211b2504ea9e0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 24 Jul 2025 15:34:45 +0300 Subject: [PATCH 272/295] Tested with Python 3.14 --- .github/workflows/run-tests.yaml | 2 +- docs/News.rst | 2 + setup.py | 1 + tox.ini | 74 ++++++++++++++++---------------- 4 files changed, 41 insertions(+), 38 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index d81585f4..54f2658f 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -10,7 +10,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] exclude: - os: windows-latest python-version: "2.7" diff --git a/docs/News.rst b/docs/News.rst index 217097af..0d67c1da 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,8 @@ News SQLObject development (master) ============================== +* Tested with Python 3.14. + SQLObject 3.13.0 ================ diff --git a/setup.py b/setup.py index bc6a45a8..02b384c1 100755 --- a/setup.py +++ b/setup.py @@ -65,6 +65,7 @@ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Database", "Topic :: Database :: Front-Ends", "Topic :: Software Development :: Libraries :: Python Modules", diff --git a/tox.ini b/tox.ini index bb8ed529..fb681afe 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py{27,34,35,36,37,38,39,310,311,312,313}-sqlite{,-memory},py{27,37,313}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313,314}-sqlite{,-memory},py{27,37,313}-flake8 # Base test environment settings [testenv] @@ -67,7 +67,7 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysqlclient] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysqlclient] commands = {[mysqlclient]commands} [mysql-connector] @@ -83,7 +83,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector] commands = {[mysql-connector]commands} [mysql-connector_py] @@ -99,7 +99,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector_py]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector_py] commands = {[mysql-connector_py]commands} [pymysql] @@ -115,7 +115,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pymysql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pymysql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pymysql] commands = {[pymysql]commands} [mariadb] @@ -126,7 +126,7 @@ commands = pytest -D "mysql://localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --execute="drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13}-mariadb] +[testenv:py3{6,7,8,9,10,11,12,13,14}-mariadb] commands = {[mariadb]commands} [mysql-pyodbc] @@ -143,7 +143,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pyodbc-noauto] commands = {[mysql-pyodbc]commands} [mysql-pypyodbc] @@ -159,7 +159,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pypyodbc-noauto] commands = {[mysql-pypyodbc]commands} # PostgreSQL test environments @@ -171,7 +171,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg] commands = {[psycopg]commands} [psycopg_c] @@ -182,7 +182,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c] commands = {[psycopg_c]commands} [psycopg2] @@ -198,7 +198,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-psycopg2] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-psycopg2] commands = {[psycopg2]commands} [pygresql] @@ -214,7 +214,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pygresql] commands = {[pygresql]commands} [pg8000] @@ -230,7 +230,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pg8000] commands = {[pg8000]commands} [postgres-pyodbc] @@ -247,7 +247,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pyodbc-noauto] commands = {[postgres-pyodbc]commands} [postgres-pypyodbc] @@ -263,7 +263,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pypyodbc-noauto] commands = {[postgres-pypyodbc]commands} @@ -280,7 +280,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite] commands = {[sqlite]commands} [sqlite-memory] @@ -293,7 +293,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite-memory] commands = {[sqlite-memory]commands} @@ -311,7 +311,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[fdb]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebird-fdb] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-firebird-fdb] commands = {[fdb]commands} [firebirdsql] @@ -327,16 +327,16 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[firebirdsql]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-firebirdsql] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-firebirdsql] commands = {[firebirdsql]commands} # Special test environments -[testenv:py{27,34,35,36,37,38,39,310,311,312,313}-flake8] +[testenv:py{27,34,35,36,37,38,39,310,311,312,313,314}-flake8] changedir = ./ deps = flake8 - pytest < 7.0 + pytest commands = {[testenv]commands} flake8 . @@ -358,7 +358,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mssql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mssql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mssql-pyodbc-noauto-w32] platform = win32 commands = {[mssql-pyodbc-w32]commands} @@ -386,7 +386,7 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-mysqlclient-w32] platform = win32 commands = {[mysqlclient-w32]commands} @@ -405,7 +405,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector-w32] platform = win32 commands = {[mysql-connector-w32]commands} @@ -424,7 +424,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-connector_py-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-connector_py-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-connector_py-w32] platform = win32 commands = {[mysql-connector_py-w32]commands} @@ -456,7 +456,7 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mariadb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13}-mariadb-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-mariadb-w32] platform = win32 commands = {[mariadb-w32]commands} @@ -476,7 +476,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pyodbc-noauto-w32] platform = win32 commands = {[mysql-pyodbc-w32]commands} @@ -496,7 +496,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[mysql-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-mysql-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-mysql-pypyodbc-noauto-w32] platform = win32 commands = {[mysql-pypyodbc-w32]commands} @@ -509,7 +509,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg-w32] platform = win32 commands = {[psycopg-w32]commands} @@ -522,7 +522,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13}-postgres-psycopg_c-w32] +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c-w32] platform = win32 commands = {[psycopg_c-w32]commands} @@ -541,7 +541,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-w32]commands} -[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-w32] +[testenv:py3{4,5,6,7,9,10,11,12,13,14}-postgres-psycopg2-w32] platform = win32 commands = {[psycopg2-w32]commands} @@ -560,7 +560,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pygresql-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pygresql-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pygresql-w32] platform = win32 commands = {[pygresql-w32]commands} @@ -579,7 +579,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[pg8000-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pg8000-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pg8000-w32] platform = win32 commands = {[pg8000-w32]commands} @@ -599,7 +599,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pyodbc-noauto-w32] platform = win32 commands = {[postgres-pyodbc-w32]commands} @@ -619,7 +619,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[postgres-pypyodbc-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-postgres-pypyodbc-noauto-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-pypyodbc-noauto-w32] platform = win32 commands = {[postgres-pypyodbc-w32]commands} @@ -636,7 +636,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite-w32] platform = win32 commands = {[sqlite-w32]commands} @@ -652,6 +652,6 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[sqlite-memory-w32]commands} -[testenv:py3{4,5,6,7,8,9,10,11,12,13}-sqlite-memory-w32] +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-sqlite-memory-w32] platform = win32 commands = {[sqlite-memory-w32]commands} From eb3fab55fbec873cafe53b7e17336756a930ac34 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 24 Jul 2025 17:12:16 +0300 Subject: [PATCH 273/295] Style(cmp): Fix `flake8` warning F824 The warning was "`global hub` is unused: name is never assigned in scope." Ok, let's remove it. --- sqlobject/tests/dbtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/tests/dbtest.py b/sqlobject/tests/dbtest.py index e2693f1d..65fcb273 100644 --- a/sqlobject/tests/dbtest.py +++ b/sqlobject/tests/dbtest.py @@ -63,7 +63,7 @@ def setupClass(soClasses, force=False): If force is true, then the database will be recreated no matter what. """ - global hub + # global hub if not isinstance(soClasses, (list, tuple)): soClasses = [soClasses] connection = getConnection() From e582afa447b43ca6c73512f842d06f7ed5bd94c3 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 15 Aug 2025 22:02:37 +0300 Subject: [PATCH 274/295] Tests(tox): Upgrade pip/setuptools/wheel --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index fb681afe..885867f1 100644 --- a/tox.ini +++ b/tox.ini @@ -30,6 +30,8 @@ deps = pypyodbc: pypyodbc firebird-fdb: fdb firebirdsql: firebirdsql +# Upgrade pip/setuptools/wheel +download = true passenv = CI setenv = PGPASSWORD = test From 4cc7daec2ff9e981db4605261ac0ee2d55e1f7e9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 16 Aug 2025 16:24:46 +0300 Subject: [PATCH 275/295] Tests(tox): Run tests with non-binary `psycopg` and `psycopg2` --- docs/News.rst | 2 ++ tox.ini | 67 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/docs/News.rst b/docs/News.rst index 0d67c1da..dc7665d5 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,6 +10,8 @@ SQLObject development (master) * Tested with Python 3.14. +* Run tests with non-binary ``psycopg`` and ``psycopg2``. + SQLObject 3.13.0 ================ diff --git a/tox.ini b/tox.ini index 885867f1..2edb614b 100644 --- a/tox.ini +++ b/tox.ini @@ -20,10 +20,12 @@ deps = mysql-connector_py: -rdevscripts/requirements/requirements_connector_python.txt pymysql: -rdevscripts/requirements/requirements_pymysql.txt mariadb: mariadb - psycopg: psycopg[binary] + psycopg: psycopg + psycopg-binary: psycopg[binary] psycopg_c: psycopg[c] - py34-psycopg2: psycopg2-binary==2.8.4 - !py34-psycopg2: psycopg2-binary + psycopg2: psycopg2 + py34-psycopg2-binary: psycopg2-binary==2.8.4 + !py34-psycopg2-binary: psycopg2-binary pygresql: -rdevscripts/requirements/requirements_pygresql.txt pg8000: -rdevscripts/requirements/requirements_pg8000.txt pyodbc: pyodbc @@ -176,6 +178,17 @@ commands = [testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg] commands = {[psycopg]commands} +[psycopg-binary] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg-binary] +commands = {[psycopg-binary]commands} + [psycopg_c] commands = {[testenv]commands} @@ -203,6 +216,22 @@ commands = [testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-psycopg2] commands = {[psycopg2]commands} +[psycopg2-binary] +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py27-postgres-psycopg2-binary] +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[psycopg2-binary]commands} + +[testenv:py3{4,5,6,7,8,9,10,11,12,13,14}-postgres-psycopg2-binary] +commands = {[psycopg2-binary]commands} + [pygresql] commands = {[testenv]commands} @@ -515,6 +544,19 @@ commands = platform = win32 commands = {[psycopg-w32]commands} +[psycopg-binary-w32] +platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg-binary-w32] +platform = win32 +commands = {[psycopg-binary-w32]commands} + [psycopg_c-w32] platform = win32 commands = @@ -547,6 +589,25 @@ commands = platform = win32 commands = {[psycopg2-w32]commands} +[psycopg2-binary-w32] +platform = win32 +commands = + {[testenv]commands} + -dropdb --username=runner --no-password sqlobject_test + createdb --username=runner --no-password sqlobject_test + pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg2&charset=utf-8&debug=1" + dropdb --username=runner --no-password sqlobject_test + +[testenv:py27-postgres-psycopg2-binary-w32] +platform = win32 +commands = + easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base + {[psycopg2-binary-w32]commands} + +[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-binary-w32] +platform = win32 +commands = {[psycopg2-binary-w32]commands} + [pygresql-w32] platform = win32 commands = From 57839aa1eac3ed43a5626b5d2109a4756586b194 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 16 Aug 2025 17:47:24 +0300 Subject: [PATCH 276/295] Tests(tox): Run default flake8 tests under Py 3.14 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 2edb614b..6cbc8df3 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.15 -envlist = py{27,34,35,36,37,38,39,310,311,312,313,314}-sqlite{,-memory},py{27,37,313}-flake8 +envlist = py{27,34,35,36,37,38,39,310,311,312,313,314}-sqlite{,-memory},py{27,37,314}-flake8 # Base test environment settings [testenv] From a6210a6e123140380312415d0efefd2a5e19d91a Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 17 Aug 2025 22:43:06 +0300 Subject: [PATCH 277/295] Tests(GHActions): Do not exclude Python 2.7 on w32 --- .github/workflows/run-tests.yaml | 3 --- tox.ini | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 54f2658f..0c9f7daf 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -11,9 +11,6 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] - exclude: - - os: windows-latest - python-version: "2.7" include: - os: ubuntu-latest os-name: Linux diff --git a/tox.ini b/tox.ini index 6cbc8df3..d36eb7be 100644 --- a/tox.ini +++ b/tox.ini @@ -636,7 +636,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=pg8000&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py27-postgres-pg8000-w32] +[testenv:py27-postgres-pg8000-noauto-w32] platform = win32 commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base From 1909f2109fd0ffdb7ae59b98b120902b38a37b2a Mon Sep 17 00:00:00 2001 From: DaveMulligan95060 <73315851+DaveMulligan95060@users.noreply.github.com> Date: Fri, 12 Sep 2025 17:44:34 -0700 Subject: [PATCH 278/295] Fix issue 195 --- sqlobject/postgres/pgconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlobject/postgres/pgconnection.py b/sqlobject/postgres/pgconnection.py index 7d9f918b..3ce5ef99 100644 --- a/sqlobject/postgres/pgconnection.py +++ b/sqlobject/postgres/pgconnection.py @@ -139,7 +139,7 @@ def __init__(self, dsn=None, host=None, port=None, db=None, if driver == 'pygresql': dsn_dict["host"] = "%s:%d" % (host, port) elif driver.startswith('psycopg') and \ - psycopg.__version__.split('.')[0] == '1': + self.module.__version__.split('.')[0] == '1': dsn_dict["port"] = str(port) else: dsn_dict["port"] = port From 4d949f49e3f45958e3166154b6a9a74813919fc1 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Sep 2025 13:00:08 +0300 Subject: [PATCH 279/295] Docs(News): Minor update "Non-binary" means "source-only". [skip ci] --- docs/News.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/News.rst b/docs/News.rst index dc7665d5..c5e0dd87 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -10,7 +10,7 @@ SQLObject development (master) * Tested with Python 3.14. -* Run tests with non-binary ``psycopg`` and ``psycopg2``. +* Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. SQLObject 3.13.0 ================ From 04b36e4fb0a10bbe2876faf14db3ef3ea1d4d1de Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Sep 2025 13:03:00 +0300 Subject: [PATCH 280/295] Docs(DeveloperGuide): Fix outdated `git://` URL `git://` protocol was disabled at GitHub long ago. Use `https://` instead. [skip ci] --- docs/DeveloperGuide.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/DeveloperGuide.rst b/docs/DeveloperGuide.rst index 2cd0f8f6..777aea14 100644 --- a/docs/DeveloperGuide.rst +++ b/docs/DeveloperGuide.rst @@ -14,13 +14,13 @@ Development Installation First install `FormEncode `_:: - $ git clone git://github.com/formencode/formencode.git + $ git clone https://github.com/formencode/formencode.git $ cd formencode $ sudo python setup.py develop Then do the same for SQLObject:: - $ git clone git clone git://github.com/sqlobject/sqlobject.git + $ git clone git clone https://github.com/sqlobject/sqlobject.git $ cd sqlobject $ sudo python setup.py develop From caa7098b471dfefa8f64eef1e61fc334676ee2e5 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 13 Sep 2025 13:11:25 +0300 Subject: [PATCH 281/295] Docs(Authors,News): Fixed #195 [skip ci] --- docs/Authors.rst | 1 + docs/News.rst | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 89a9e374..46d00465 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -41,6 +41,7 @@ Contributions have been made by: * Juergen Gmach * Hugo van Kemenade * Igor Yudytskiy +* Dave Mulligan (https://github.com/DaveMulligan95060) * Oleg Broytman .. image:: https://sourceforge.net/sflogo.php?group_id=74338&type=10 diff --git a/docs/News.rst b/docs/News.rst index c5e0dd87..2c418b43 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -8,6 +8,15 @@ News SQLObject development (master) ============================== +Bug fixes +--------- + +* Fixed #195: Minor ``NameError`` in ``pgconnection.py`` + when using ``psycopg`` version 1 with a non-default port. + +Tests +----- + * Tested with Python 3.14. * Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. From cc5e39ec0e13f01b466463c246a5fe73d64392cb Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Nov 2025 21:00:48 +0300 Subject: [PATCH 282/295] Fixes a bug in `dbconnection.ConnectionURIOpener.registerConnection` Fixes a bug triggered by non-empty instance's `name`. Fixes: #197. --- ANNOUNCE.rst | 4 ++-- docs/News.rst | 4 ++++ sqlobject/dbconnection.py | 6 +++--- sqlobject/tests/test_dbconnection.py | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 sqlobject/tests/test_dbconnection.py diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index dfdda2c5..e221f252 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,8 +22,8 @@ I'm pleased to announce version 3.13.0, the first release of branch What's new in SQLObject ======================= -The contributors for this release are ... Thanks! - +The contributor for this release is GH user ghaushe-ampere. +Thanks for finding an obscure bug! For a more complete list, please see the news: http://sqlobject.org/News.html diff --git a/docs/News.rst b/docs/News.rst index 2c418b43..0d55db2c 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,10 @@ SQLObject development (master) Bug fixes --------- +* Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` + triggered by non-empty instance's ``name``. The bug was inserted in 2004 so + it seems nobody ever used named instances. Fixed anyway. + * Fixed #195: Minor ``NameError`` in ``pgconnection.py`` when using ``psycopg`` version 1 with a non-default port. diff --git a/sqlobject/dbconnection.py b/sqlobject/dbconnection.py index e691f2d4..75176479 100644 --- a/sqlobject/dbconnection.py +++ b/sqlobject/dbconnection.py @@ -1080,12 +1080,12 @@ def registerConnection(self, schemes, builder): def registerConnectionInstance(self, inst): if inst.name: assert (inst.name not in self.instanceNames - or self.instanceNames[inst.name] is cls # noqa - ), ("A instance has already been registered " + or self.instanceNames[inst.name] is self.__class__ + ), ("An instance has already been registered " "with the name %s" % inst.name) assert inst.name.find(':') == -1, \ "You cannot include ':' " \ - "in your class names (%r)" % cls.name # noqa + "in your DB connection names (%r)" % inst.name self.instanceNames[inst.name] = inst def connectionForURI(self, uri, oldUri=False, **args): diff --git a/sqlobject/tests/test_dbconnection.py b/sqlobject/tests/test_dbconnection.py new file mode 100644 index 00000000..6e2dfc87 --- /dev/null +++ b/sqlobject/tests/test_dbconnection.py @@ -0,0 +1,17 @@ +from pytest import raises +from sqlobject.dbconnection import DBConnection + + +def test_name(): + connection = DBConnection(name='test') + connection.close = lambda: True + + with raises(AssertionError) as error: + DBConnection(name='test') + assert str(error.value) == 'An instance has already been registered ' \ + 'with the name test' + + with raises(AssertionError) as error: + DBConnection(name='test:test') + assert str(error.value) == "You cannot include ':' " \ + "in your DB connection names ('test:test')" From 1fd8272fd8861ed7b7d9011d11720d417216f30b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Nov 2025 21:22:16 +0300 Subject: [PATCH 283/295] CI(GHActions): Exclude Python 2.7 on Windows --- .github/workflows/run-tests.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 0c9f7daf..54f2658f 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -11,6 +11,9 @@ jobs: matrix: os: [ubuntu-latest, windows-latest] python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + exclude: + - os: windows-latest + python-version: "2.7" include: - os: ubuntu-latest os-name: Linux From 806c0a919a14a86997c0c4fec1237fdb5914505d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Tue, 11 Nov 2025 21:42:25 +0300 Subject: [PATCH 284/295] Tests(tox): Exclude some tests Exclude mysqlclient under Python 3.14; still is not released. Exclude psycopg[c] under Python 3.6 and 3.7; seems incompatible with GCC running at GH. --- tox.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index d36eb7be..032df079 100644 --- a/tox.ini +++ b/tox.ini @@ -197,7 +197,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c] +[testenv:py3{8,9,10,11,12,13,14}-postgres-psycopg_c] commands = {[psycopg_c]commands} [psycopg2] @@ -417,7 +417,7 @@ commands = pytest -D "mysql://ODBC@localhost/sqlobject_test?driver=mysqldb&charset=utf8&debug=1" mysql --user=ODBC -e "drop database sqlobject_test;" -[testenv:py3{6,7,8,9,10,11,12,13,14}-mysqlclient-w32] +[testenv:py3{6,7,8,9,10,11,12,13}-mysqlclient-w32] platform = win32 commands = {[mysqlclient-w32]commands} @@ -566,7 +566,7 @@ commands = pytest -D "postgres://runner:test@localhost/sqlobject_test?driver=psycopg&charset=utf-8&debug=1" dropdb --username=runner --no-password sqlobject_test -[testenv:py3{6,7,8,9,10,11,12,13,14}-postgres-psycopg_c-w32] +[testenv:py3{8,9,10,11,12,13,14}-postgres-psycopg_c-w32] platform = win32 commands = {[psycopg_c-w32]commands} From 5f9b61c58dd1d50f7f2871a833843256bf5f4f65 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Wed, 12 Nov 2025 00:12:04 +0300 Subject: [PATCH 285/295] Docs(ANNOUNCE): Add Dave Mulligan as a contributor [skip ci] --- ANNOUNCE.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index e221f252..5632cfeb 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -22,8 +22,12 @@ I'm pleased to announce version 3.13.0, the first release of branch What's new in SQLObject ======================= -The contributor for this release is GH user ghaushe-ampere. -Thanks for finding an obscure bug! +The contributors for this release are: + +* Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` + when using ``psycopg`` version 1 with a non-default port. Many thanks! + +* GH user ghaushe-ampere. Thanks for finding an obscure bug! For a more complete list, please see the news: http://sqlobject.org/News.html From 21243137a981eaac7bba32135f183f9e696f5315 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Thu, 13 Nov 2025 20:15:31 +0300 Subject: [PATCH 286/295] Docs(ANNOUNCE): Thanks Igor Yudytskiy for PR #194 [skip ci] --- ANNOUNCE.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 5632cfeb..22d6a34e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -24,11 +24,15 @@ What's new in SQLObject The contributors for this release are: +* Igor Yudytskiy. Thanks for PR #194: + fix: connect to old mssql versions via set tds_version uri parameter. + * Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` - when using ``psycopg`` version 1 with a non-default port. Many thanks! + when using ``psycopg`` version 1 with a non-default port. Thanks! * GH user ghaushe-ampere. Thanks for finding an obscure bug! + For a more complete list, please see the news: http://sqlobject.org/News.html From db991816a85a704e4b8edf6978561c1f248a5388 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 21 Nov 2025 00:43:29 +0300 Subject: [PATCH 287/295] Fix(col): `UuidValidator.from_python` accepts strings as valid input Fixes: #199. --- ANNOUNCE.rst | 2 ++ docs/News.rst | 3 +++ sqlobject/col.py | 2 ++ sqlobject/tests/test_uuidcol.py | 16 ++++++++++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 22d6a34e..ad13b0f5 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -30,6 +30,8 @@ The contributors for this release are: * Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` when using ``psycopg`` version 1 with a non-default port. Thanks! +* Chris Kauffman found a minor bug in ``UuidValidator``. + * GH user ghaushe-ampere. Thanks for finding an obscure bug! diff --git a/docs/News.rst b/docs/News.rst index 0d55db2c..96c5f77b 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -11,6 +11,9 @@ SQLObject development (master) Bug fixes --------- +* ``UuidValidator.from_python()`` now accepts strings as a valid input. + This fixes #199. + * Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` triggered by non-empty instance's ``name``. The bug was inserted in 2004 so it seems nobody ever used named instances. Fixed anyway. diff --git a/sqlobject/col.py b/sqlobject/col.py index cf9705de..49cd709a 100644 --- a/sqlobject/col.py +++ b/sqlobject/col.py @@ -2022,6 +2022,8 @@ def to_python(self, value, state): def from_python(self, value, state): if value is None: return None + if isinstance(value, str): + return value if isinstance(value, UUID): return str(value) raise validators.Invalid( diff --git a/sqlobject/tests/test_uuidcol.py b/sqlobject/tests/test_uuidcol.py index 117d80ec..d1e2c22f 100644 --- a/sqlobject/tests/test_uuidcol.py +++ b/sqlobject/tests/test_uuidcol.py @@ -12,11 +12,11 @@ class UuidContainer(SQLObject): - uuiddata = UuidCol(default=None) + uuiddata = UuidCol(alternateID=True, default=None) def test_uuidCol(): - setupClass([UuidContainer], force=True) + setupClass([UuidContainer]) my_uuid = UuidContainer(uuiddata=testuuid) iid = my_uuid.id @@ -26,3 +26,15 @@ def test_uuidCol(): my_uuid_2 = UuidContainer.get(iid) assert my_uuid_2.uuiddata == testuuid + + +def test_alternate_id(): + setupClass([UuidContainer]) + + UuidContainer(uuiddata=testuuid) + + UuidContainer._connection.cache.clear() + + my_uuid_2 = UuidContainer.byUuiddata(testuuid) + + assert my_uuid_2.uuiddata == testuuid From 69e9604b7906a53ca4771e2b0d6da2d1da2f48ed Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Nov 2025 14:22:14 +0300 Subject: [PATCH 288/295] Release 3.13.1b1 --- ANNOUNCE.rst | 17 +---------------- README.rst | 4 ++-- setup.py | 2 +- sqlobject/__version__.py | 8 ++++---- 4 files changed, 8 insertions(+), 23 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index ad13b0f5..18ed7f4d 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,22 +1,7 @@ Hello! -I'm pleased to announce version 3.13.1a1, the first alpha of the upcoming -release of branch 3.13 of SQLObject. - -I'm pleased to announce version 3.13.1a2, the second alpha of the upcoming -release of branch 3.13 of SQLObject. - I'm pleased to announce version 3.13.1b1, the first beta of the upcoming -release of branch 3.13 of SQLObject. - -I'm pleased to announce version 3.13.1rc1, the first release candidate -of the upcoming release of branch 3.13 of SQLObject. - -I'm pleased to announce version 3.13.1, the first bugfix release of branch -3.13 of SQLObject. - -I'm pleased to announce version 3.13.0, the first release of branch -3.13 of SQLObject. +bugfix release 3.13.1 of SQLObject. What's new in SQLObject diff --git a/README.rst b/README.rst index 4e7af749..840351f2 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.13.0 -================ +SQLObject 3.13.1b1 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/setup.py b/setup.py index 02b384c1..1a9d772b 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index cc6e4c51..44d9bc73 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.13.0' +version = '3.13.1b1' major = 3 minor = 13 -micro = 0 -release_level = 'final' -serial = 0 +micro = 1 +release_level = 'beta' +serial = 1 version_info = (major, minor, micro, release_level, serial) From ebd8e4e85510ba8dcea94f8ef320cc95ec770f4d Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Nov 2025 14:33:38 +0300 Subject: [PATCH 289/295] Build: Evil PyPI enforces lower-case distribution names Rename the distribution to `sqlobject`. --- devscripts/release | 12 +----------- setup.py | 8 ++++---- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/devscripts/release b/devscripts/release index 2df10e0f..664b68b0 100755 --- a/devscripts/release +++ b/devscripts/release @@ -24,15 +24,5 @@ if [ "$state" = final ]; then devscripts/sftp-frs fi && -cd dist && -if [ -f SQLObject-$version.tar.gz ]; then - mv SQLObject-$version.tar.gz sqlobject-$version.tar.gz -fi && -if [ -f SQLObject-$version-py2.py3-none-any.whl ]; then - mv SQLObject-$version-py2.py3-none-any.whl \ - sqlobject-$version-py2.py3-none-any.whl -fi && -cd .. && - twine upload --disable-progress-bar --skip-existing dist/* && -exec rm -rf build dist docs/html SQLObject.egg-info +exec rm -rf build dist docs/html sqlobject.egg-info diff --git a/setup.py b/setup.py index 1a9d772b..22fbd0ea 100755 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ 'versioning', 'versioning.test'] setup( - name="SQLObject", + name="sqlobject", version=sqlobject_version['version'], description="Object-Relational Manager, aka database wrapper", long_description="""\ @@ -75,12 +75,12 @@ maintainer="Oleg Broytman", maintainer_email="phd@phdru.name", url="http://sqlobject.org/", - download_url="https://pypi.org/project/SQLObject/%s/" % + download_url="https://pypi.org/project/sqlobject/%s/" % sqlobject_version['version'], project_urls={ 'Homepage': 'http://sqlobject.org/', 'Development docs': 'http://sqlobject.org/devel/', - 'Download': 'https://pypi.org/project/SQLObject/%s/' % + 'Download': 'https://pypi.org/project/sqlobject/%s/' % sqlobject_version['version'], 'Github repo': 'https://github.com/sqlobject', 'Issue tracker': 'https://github.com/sqlobject/sqlobject/issues', @@ -213,7 +213,7 @@ https://lists.sourceforge.net/mailman/listinfo/sqlobject-discuss Download: -https://pypi.org/project/SQLObject/@@/ +https://pypi.org/project/sqlobject/@@/ News and changes: http://sqlobject.org/docs/News.html From e9561de92bdd8c2fd2b30ed19905dc49ff12f918 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sun, 23 Nov 2025 14:41:43 +0300 Subject: [PATCH 290/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 6 +++--- README.rst | 4 ++-- setup.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 18ed7f4d..9220969c 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,7 +1,7 @@ Hello! -I'm pleased to announce version 3.13.1b1, the first beta of the upcoming -bugfix release 3.13.1 of SQLObject. +I'm pleased to announce version 3.13.1, the first bugfix of the +branch 3.13 of SQLObject. What's new in SQLObject @@ -49,7 +49,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.1a0.dev20250307/ +https://pypi.org/project/SQLObject/3.13.1a0.dev20251124/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 840351f2..157519af 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.13.1b1 -================== +SQLObject 3.13.1 +================ SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/setup.py b/setup.py index 22fbd0ea..9158ff54 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", From 7fa955ace8ece7fd1e2635c9c993494508d3757e Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Nov 2025 23:19:42 +0300 Subject: [PATCH 291/295] Build(devscripts/release): Fix `.git/objects` permissions [skip ci] --- devscripts/release | 1 + 1 file changed, 1 insertion(+) diff --git a/devscripts/release b/devscripts/release index 664b68b0..44ad33a1 100755 --- a/devscripts/release +++ b/devscripts/release @@ -3,6 +3,7 @@ cd "`dirname \"$0\"`"/.. && umask 022 && chmod -R a+rX . && +find .git/objects -type f -exec chmod u=r,go= '{}' \+ && set-commit-date.py && devscripts/build-docs && From 2402bfd127a490aad486e1d247e58cfceede3fc0 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Nov 2025 23:45:28 +0300 Subject: [PATCH 292/295] CI(GHActions): Upgrade `checkout` and `setup-python` actions --- .github/workflows/run-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml index 54f2658f..5c2b60c0 100644 --- a/.github/workflows/run-tests.yaml +++ b/.github/workflows/run-tests.yaml @@ -42,8 +42,8 @@ jobs: if: ${{ runner.os == 'Windows' }} # Setup Python/pip - - uses: actions/checkout@v4 - - uses: conda-incubator/setup-miniconda@v3 + - uses: actions/checkout@v5 + - uses: conda-incubator/setup-miniconda@v3.2.0 with: channels: conda-forge, conda-forge/label/python_rc miniforge-version: latest From 901e7e13dbe3113fd6d1589d6c13321565d7031b Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Fri, 28 Nov 2025 23:46:01 +0300 Subject: [PATCH 293/295] Tests(tox): Run tests with `psycopg2-binary` under Py 3.14 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 032df079..04bc01f5 100644 --- a/tox.ini +++ b/tox.ini @@ -604,7 +604,7 @@ commands = easy_install -i https://downloads.egenix.com/python/index/ucs2/ egenix-mx-base {[psycopg2-binary-w32]commands} -[testenv:py3{4,5,6,7,9,10,11,12,13}-postgres-psycopg2-binary-w32] +[testenv:py3{4,5,6,7,9,10,11,12,13,14}-postgres-psycopg2-binary-w32] platform = win32 commands = {[psycopg2-binary-w32]commands} From c4026af7c94274107bb1550a4bb482d9abf628b9 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 8 Dec 2025 22:15:51 +0300 Subject: [PATCH 294/295] Release 3.13.1 --- ANNOUNCE.rst | 23 +++++++++++++++++++++-- devscripts/build-all-docs | 2 +- docs/News.rst | 6 ++++-- setup.cfg | 5 ----- setup.py | 2 +- sqlobject/__version__.py | 6 +++--- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 9220969c..7088f66e 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,6 +1,6 @@ Hello! -I'm pleased to announce version 3.13.1, the first bugfix of the +I'm pleased to announce version 3.13.1, the first bugfix release of the branch 3.13 of SQLObject. @@ -19,6 +19,25 @@ The contributors for this release are: * GH user ghaushe-ampere. Thanks for finding an obscure bug! +Bug fixes +--------- + +* ``UuidValidator.from_python()`` now accepts strings as a valid input. + This fixes #199. + +* Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` + triggered by non-empty instance's ``name``. The bug was inserted in 2004 so + it seems nobody ever used named instances. Fixed anyway. + +* Fixed #195: Minor ``NameError`` in ``pgconnection.py`` + when using ``psycopg`` version 1 with a non-default port. + +Tests +----- + +* Tested with Python 3.14. + +* Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -49,7 +68,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.1a0.dev20251124/ +https://pypi.org/project/SQLObject/3.13.1 News and changes: http://sqlobject.org/News.html diff --git a/devscripts/build-all-docs b/devscripts/build-all-docs index 3e3cda0e..62020c9d 100755 --- a/devscripts/build-all-docs +++ b/devscripts/build-all-docs @@ -10,7 +10,7 @@ cd "`dirname \"$0\"`" && PROG_DIR="`pwd`" && cd .. && -build_docs 3.13.0 && +build_docs 3.13.1 && build_docs master devel && rm -rf docs/html && diff --git a/docs/News.rst b/docs/News.rst index 96c5f77b..59cd5963 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,8 +5,10 @@ News .. contents:: Contents: :backlinks: none -SQLObject development (master) -============================== +SQLObject 3.13.1 +================ + +Released 2025 Dec 08. Bug fixes --------- diff --git a/setup.cfg b/setup.cfg index 461bc50f..43bae0f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,11 +4,6 @@ universal = 1 [easy_install] optimize = 2 -[egg_info] -tag_build = -tag_date = 0 -tag_svn_revision = 0 - [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 9158ff54..8d37606e 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 3 - Alpha", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)", diff --git a/sqlobject/__version__.py b/sqlobject/__version__.py index 44d9bc73..37af2a9e 100644 --- a/sqlobject/__version__.py +++ b/sqlobject/__version__.py @@ -1,8 +1,8 @@ -version = '3.13.1b1' +version = '3.13.1' major = 3 minor = 13 micro = 1 -release_level = 'beta' -serial = 1 +release_level = 'final' +serial = 0 version_info = (major, minor, micro, release_level, serial) From 847875ade0f1af75c95ed9f9f3546a49b23204cd Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 8 Dec 2025 22:25:03 +0300 Subject: [PATCH 295/295] Build: Prepare for the next release [skip ci] --- ANNOUNCE.rst | 33 ++------------------------------- README.rst | 4 ++-- docs/News.rst | 3 +++ setup.cfg | 5 +++++ setup.py | 2 +- 5 files changed, 13 insertions(+), 34 deletions(-) diff --git a/ANNOUNCE.rst b/ANNOUNCE.rst index 7088f66e..b1d6645f 100644 --- a/ANNOUNCE.rst +++ b/ANNOUNCE.rst @@ -1,6 +1,6 @@ Hello! -I'm pleased to announce version 3.13.1, the first bugfix release of the +I'm pleased to announce version 3.13.2a0, the 2nd bugfix of the branch 3.13 of SQLObject. @@ -9,35 +9,6 @@ What's new in SQLObject The contributors for this release are: -* Igor Yudytskiy. Thanks for PR #194: - fix: connect to old mssql versions via set tds_version uri parameter. - -* Dave Mulligan fixed #195: Minor ``NameError`` in ``pgconnection.py`` - when using ``psycopg`` version 1 with a non-default port. Thanks! - -* Chris Kauffman found a minor bug in ``UuidValidator``. - -* GH user ghaushe-ampere. Thanks for finding an obscure bug! - -Bug fixes ---------- - -* ``UuidValidator.from_python()`` now accepts strings as a valid input. - This fixes #199. - -* Fixed #197: a bug in ``dbconnection.ConnectionURIOpener.registerConnection`` - triggered by non-empty instance's ``name``. The bug was inserted in 2004 so - it seems nobody ever used named instances. Fixed anyway. - -* Fixed #195: Minor ``NameError`` in ``pgconnection.py`` - when using ``psycopg`` version 1 with a non-default port. - -Tests ------ - -* Tested with Python 3.14. - -* Run tests with source-only (non-binary) ``psycopg`` and ``psycopg2``. For a more complete list, please see the news: http://sqlobject.org/News.html @@ -68,7 +39,7 @@ Site: http://sqlobject.org Download: -https://pypi.org/project/SQLObject/3.13.1 +https://pypi.org/project/SQLObject/3.13.2a0.dev20251208/ News and changes: http://sqlobject.org/News.html diff --git a/README.rst b/README.rst index 157519af..cf8a985e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -SQLObject 3.13.1 -================ +SQLObject 3.13.2a0 +================== SQLObject is a free and open-source (LGPL) Python object-relational mapper. Your database tables are described as classes, and rows are diff --git a/docs/News.rst b/docs/News.rst index 59cd5963..e01b1376 100644 --- a/docs/News.rst +++ b/docs/News.rst @@ -5,6 +5,9 @@ News .. contents:: Contents: :backlinks: none +SQLObject development (master) +============================== + SQLObject 3.13.1 ================ diff --git a/setup.cfg b/setup.cfg index 43bae0f3..461bc50f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,11 @@ universal = 1 [easy_install] optimize = 2 +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + [flake8] exclude = .git,.tox,docs/europython/*.py # E305: expected 2 blank lines after class or function definition, found 1 diff --git a/setup.py b/setup.py index 8d37606e..9158ff54 100755 --- a/setup.py +++ b/setup.py @@ -47,7 +47,7 @@ """, # noqa: E501 line too long long_description_content_type="text/x-rst", classifiers=[ - "Development Status :: 5 - Production/Stable", + "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: " "GNU Library or Lesser General Public License (LGPL)",