From dae186780e79dca717b90a300c7788677278d632 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 30 Jan 2009 19:22:43 +0000 Subject: [PATCH] - sql round trips are coming on line for sqlite, pg8000 - pg8000 returns col.description as bytes, heh - absolute module imports play havoc with "python test/foo/test.py" - start using -m --- README.unittests | 26 +++++++++++++++------- lib/sqlalchemy/dialects/postgres/base.py | 11 ++++++++- lib/sqlalchemy/dialects/sqlite/pysqlite.py | 1 + lib/sqlalchemy/engine/base.py | 2 -- lib/sqlalchemy/engine/default.py | 14 +++++++++++- lib/sqlalchemy/pool.py | 10 ++++----- test/testenv.py | 2 +- 7 files changed, 48 insertions(+), 18 deletions(-) diff --git a/README.unittests b/README.unittests index 4698494234..bb1ac3253b 100644 --- a/README.unittests +++ b/README.unittests @@ -26,30 +26,39 @@ sys.path. This forces the local version of SQLAlchemy to be used, bypassing any setuptools-installed installations (setuptools places .egg files ahead of plain directories, even if on PYTHONPATH, unfortunately). +NEW INSTRUCTIONS FOR ABSOLUTE MODULE IMPORTS +-------------------------------------------- +Py3K imports modules absolutely. This means the old way of running unittests, +such as "python test/sql/query.py", can break things badly. How ? By name +conflicts in our test suite. We have a unit test called "test/sql/select.py". +The pg8000 DBAPI uses the Python "select" module. If you run a script +called "test/sql/query.py", now "test/sql" is part of the import path, and +pg8000 pulls in "test/sql/select.py" instead. Kaboom ! So we run +the tests using -m now. RUNNING ALL TESTS ----------------- To run all tests: - $ python test/alltests.py + $ python -m alltests RUNNING INDIVIDUAL TESTS ------------------------- Any unittest module can be run directly from the module file: - python test/orm/mapper.py + python -m orm.mapper To run a specific test within the module, specify it as ClassName.methodname: - python test/orm/mapper.py MapperTest.testget + python -m orm.mapper MapperTest.testget COMMAND LINE OPTIONS -------------------- Help is available via --help - $ python test/alltests.py --help + $ python -m alltests --help usage: alltests.py [options] [tests...] @@ -78,7 +87,7 @@ preexisting tables will interfere with the tests If you'll be running the tests frequently, database aliases can save a lot of typing. The --dbs option lists the built-in aliases and their matching URLs: - $ python test/alltests.py --dbs + $ python -m alltests --dbs Available --db options (use --dburi to override) mysql mysql://scott:tiger@127.0.0.1:3306/test oracle oracle://scott:tiger@127.0.0.1:1521 @@ -87,7 +96,7 @@ typing. The --dbs option lists the built-in aliases and their matching URLs: To run tests against an aliased database: - $ python test/alltests.py --db=postgres + $ python -m alltests --db=postgres To customize the URLs with your own users or hostnames, make a simple .ini file called `test.cfg` at the top level of the SQLAlchemy source distribution @@ -106,7 +115,7 @@ SQLAlchemy logs its activity and debugging through Python's logging package. Any log target can be directed to the console with command line options, such as: - $ python test/orm/unitofwork.py --log-info=sqlalchemy.orm.mapper \ + $ python -m orm.unitofwork --log-info=sqlalchemy.orm.mapper \ --log-debug=sqlalchemy.pool --log-info=sqlalchemy.engine This would log mapper configuration, connection pool checkouts, and SQL @@ -125,7 +134,8 @@ After the suite has been run with --coverage, an annotated version of any source file can be generated, marking statements that are executed with > and statements that are missed with !, by running the coverage.py utility with the "-a" (annotate) option, such as: - + + # TODO: need to adjust this for -m flag $ python ./test/testlib/coverage.py -a ./lib/sqlalchemy/sql.py This will create a new annotated file ./lib/sqlalchemy/sql.py,cover. Pretty diff --git a/lib/sqlalchemy/dialects/postgres/base.py b/lib/sqlalchemy/dialects/postgres/base.py index 0f514e3f4f..5221df5494 100644 --- a/lib/sqlalchemy/dialects/postgres/base.py +++ b/lib/sqlalchemy/dialects/postgres/base.py @@ -337,7 +337,11 @@ class PGDefaultRunner(base.DefaultRunner): exc = "select nextval('\"%s\".\"%s_%s_seq\"')" % (sch, column.table.name, column.name) else: exc = "select nextval('\"%s_%s_seq\"')" % (column.table.name, column.name) - return self.execute_string(exc.encode(self.dialect.encoding)) + + if self.dialect.supports_unicode_statements: + return self.execute_string(exc) + else: + return self.execute_string(exc.encode(self.dialect.encoding)) return super(PGDefaultRunner, self).get_column_default(column) @@ -500,8 +504,11 @@ class PGDialect(default.DefaultDialect): if table.schema is not None: schema_where_clause = "n.nspname = :schema" schemaname = table.schema + + # Py2K if isinstance(schemaname, str): schemaname = schemaname.decode(self.encoding) + # end Py2K else: schema_where_clause = "pg_catalog.pg_table_is_visible(c.oid)" schemaname = None @@ -526,8 +533,10 @@ class PGDialect(default.DefaultDialect): s = sql.text(SQL_COLS, bindparams=[sql.bindparam('table_name', type_=sqltypes.Unicode), sql.bindparam('schema', type_=sqltypes.Unicode)], typemap={'attname':sqltypes.Unicode, 'default':sqltypes.Unicode}) tablename = table.name + # Py2K if isinstance(tablename, str): tablename = tablename.decode(self.encoding) + # end Py2K c = connection.execute(s, table_name=tablename, schema=schemaname) rows = c.fetchall() diff --git a/lib/sqlalchemy/dialects/sqlite/pysqlite.py b/lib/sqlalchemy/dialects/sqlite/pysqlite.py index 9183bfbe89..9ccbd62707 100644 --- a/lib/sqlalchemy/dialects/sqlite/pysqlite.py +++ b/lib/sqlalchemy/dialects/sqlite/pysqlite.py @@ -121,6 +121,7 @@ class SQLite_pysqlite(SQLiteDialect): default_paramstyle = 'qmark' poolclass = pool.SingletonThreadPool execution_ctx_cls = SQLite_pysqliteExecutionContext + description_encoding = None driver = 'pysqlite' def __init__(self, **kwargs): diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index e0ade2c8d3..6944a52624 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -1485,10 +1485,8 @@ class ResultProxy(object): for i, item in enumerate(metadata): colname = item[0] - # Py2K if self.dialect.description_encoding: colname = colname.decode(self.dialect.description_encoding) - # end Py2K if '.' in colname: # sqlite will in some circumstances prepend table name to colnames, so strip diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 42608b8ac4..b136622704 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -31,8 +31,14 @@ class DefaultDialect(base.Dialect): supports_alter = True supports_sequences = False sequences_optional = False + + # Py3K + #supports_unicode_statements = True + #supports_unicode_binds = True + # Py2K supports_unicode_statements = False supports_unicode_binds = False + # end Py2K name = 'default' max_identifier_length = 9999 @@ -67,7 +73,13 @@ class DefaultDialect(base.Dialect): if label_length and label_length > self.max_identifier_length: raise exc.ArgumentError("Label length of %d is greater than this dialect's maximum identifier length of %d" % (label_length, self.max_identifier_length)) self.label_length = label_length - self.description_encoding = getattr(self, 'description_encoding', encoding) + + if not hasattr(self, 'description_encoding'): + self.description_encoding = getattr(self, 'description_encoding', encoding) + + # Py3K + #self.supports_unicode_statements = True + #self.supports_unicode_binds = True @classmethod def type_descriptor(cls, typeobj): diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py index dabc2929ee..2d4e223c45 100644 --- a/lib/sqlalchemy/pool.py +++ b/lib/sqlalchemy/pool.py @@ -19,7 +19,7 @@ SQLAlchemy connection pool. import weakref, time, threading from sqlalchemy import exc, log -from sqlalchemy import queue as Queue +from sqlalchemy import queue as sqla_queue from sqlalchemy.util import thread, threading, pickle, as_interface proxies = {} @@ -593,7 +593,7 @@ class QueuePool(Pool): """ Pool.__init__(self, creator, **params) - self._pool = Queue.Queue(pool_size) + self._pool = sqla_queue.Queue(pool_size) self._overflow = 0 - pool_size self._max_overflow = max_overflow self._timeout = timeout @@ -606,7 +606,7 @@ class QueuePool(Pool): def do_return_conn(self, conn): try: self._pool.put(conn, False) - except Queue.Full: + except sqla_queue.Full: if self._overflow_lock is None: self._overflow -= 1 else: @@ -620,7 +620,7 @@ class QueuePool(Pool): try: wait = self._max_overflow > -1 and self._overflow >= self._max_overflow return self._pool.get(wait, self._timeout) - except Queue.Empty: + except sqla_queue.Empty: if self._max_overflow > -1 and self._overflow >= self._max_overflow: if not wait: return self.do_get() @@ -648,7 +648,7 @@ class QueuePool(Pool): try: conn = self._pool.get(False) conn.close() - except Queue.Empty: + except sqla_queue.Empty: break self._overflow = 0 - self.size() diff --git a/test/testenv.py b/test/testenv.py index 808a3c5f0e..1cf6617c37 100644 --- a/test/testenv.py +++ b/test/testenv.py @@ -20,8 +20,8 @@ def configure_for_tests(): sys.path.insert(0, os.path.join(os.getcwd(), 'lib')) logging.basicConfig() - testlib.config.configure() _setup = True + testlib.config.configure() def simple_setup(): """import testenv; testenv.simple_setup()""" -- 2.47.3