From: Mike Bayer Date: Tue, 26 May 2009 22:31:29 +0000 (+0000) Subject: schema, reflection, and type refinements. in particular the default precision/scale... X-Git-Tag: rel_0_6_6~207 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ad55fb2699a3701b0fb96941711838ea1070d54a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git schema, reflection, and type refinements. in particular the default precision/scale args are removed from Numeric/Float. --- diff --git a/06CHANGES b/06CHANGES index 70834b35c1..22b7fbf2f9 100644 --- a/06CHANGES +++ b/06CHANGES @@ -14,12 +14,19 @@ postgresql and sqlite. [ticket:443] - dialect refactor + - the "owner" keyword argument is removed from Table. Use "schema" to + represent any namespaces to be prepended to the table name. - server_version_info becomes a static attribute. - dialects receive an initialize() event on initial connection to determine connection properties. - dialects receive a visit_pool event have an opportunity to establish pool listeners. - cached TypeEngine classes are cached per-dialect class instead of per-dialect. + - Deprecated Dialect.get_params() removed. + - Dialect.get_rowcount() has been renamed to a descriptor "rowcount", and calls + cursor.rowcount directly. Dialects which need to hardwire a rowcount in for + certain calls should override the method to provide different behavior. + - mysql - all the _detect_XXX() functions now run once underneath dialect.initialize() @@ -40,3 +47,6 @@ unless the "comparator" argument with a comparsion function is specified to the type. Objects being pickled will be compared based on identity (which defeats the purpose of mutable=True) if __eq__() is not overridden or a comparison function is not provided. + - The default "precision" and "scale" arguments of Numeric and Float have been removed + and now default to None. NUMERIC and FLOAT will be rendered with no numeric arguments + by default unless these values are provided. \ No newline at end of file diff --git a/lib/sqlalchemy/dialects/maxdb/base.py b/lib/sqlalchemy/dialects/maxdb/base.py index 4be6f8f639..0d70c3df4e 100644 --- a/lib/sqlalchemy/dialects/maxdb/base.py +++ b/lib/sqlalchemy/dialects/maxdb/base.py @@ -403,6 +403,12 @@ class MaxDBExecutionContext(default.DefaultExecutionContext): return MaxDBResultProxy(self) return engine_base.ResultProxy(self) + @property + def rowcount(self): + if hasattr(self, '_rowcount'): + return self._rowcount + else: + return self.cursor.rowcount class MaxDBCachedColumnRow(engine_base.RowProxy): """A RowProxy that only runs result_processors once per column.""" diff --git a/lib/sqlalchemy/dialects/mssql/information_schema.py b/lib/sqlalchemy/dialects/mssql/information_schema.py index 0f6332b537..644e62d9d9 100644 --- a/lib/sqlalchemy/dialects/mssql/information_schema.py +++ b/lib/sqlalchemy/dialects/mssql/information_schema.py @@ -1,24 +1,24 @@ -from sqlalchemy import Table, MetaData, Column, ForeignKey, String, Integer +from sqlalchemy import Table, MetaData, Column, ForeignKey, String, Unicode, Integer ischema = MetaData() schemata = Table("SCHEMATA", ischema, - Column("CATALOG_NAME", String, key="catalog_name"), - Column("SCHEMA_NAME", String, key="schema_name"), - Column("SCHEMA_OWNER", String, key="schema_owner"), + Column("CATALOG_NAME", Unicode, key="catalog_name"), + Column("SCHEMA_NAME", Unicode, key="schema_name"), + Column("SCHEMA_OWNER", Unicode, key="schema_owner"), schema="INFORMATION_SCHEMA") tables = Table("TABLES", ischema, - Column("TABLE_CATALOG", String, key="table_catalog"), - Column("TABLE_SCHEMA", String, key="table_schema"), - Column("TABLE_NAME", String, key="table_name"), + Column("TABLE_CATALOG", Unicode, key="table_catalog"), + Column("TABLE_SCHEMA", Unicode, key="table_schema"), + Column("TABLE_NAME", Unicode, key="table_name"), Column("TABLE_TYPE", String, key="table_type"), schema="INFORMATION_SCHEMA") columns = Table("COLUMNS", ischema, - Column("TABLE_SCHEMA", String, key="table_schema"), - Column("TABLE_NAME", String, key="table_name"), - Column("COLUMN_NAME", String, key="column_name"), + Column("TABLE_SCHEMA", Unicode, key="table_schema"), + Column("TABLE_NAME", Unicode, key="table_name"), + Column("COLUMN_NAME", Unicode, key="column_name"), Column("IS_NULLABLE", Integer, key="is_nullable"), Column("DATA_TYPE", String, key="data_type"), Column("ORDINAL_POSITION", Integer, key="ordinal_position"), @@ -30,44 +30,44 @@ columns = Table("COLUMNS", ischema, schema="INFORMATION_SCHEMA") constraints = Table("TABLE_CONSTRAINTS", ischema, - Column("TABLE_SCHEMA", String, key="table_schema"), - Column("TABLE_NAME", String, key="table_name"), - Column("CONSTRAINT_NAME", String, key="constraint_name"), + Column("TABLE_SCHEMA", Unicode, key="table_schema"), + Column("TABLE_NAME", Unicode, key="table_name"), + Column("CONSTRAINT_NAME", Unicode, key="constraint_name"), Column("CONSTRAINT_TYPE", String, key="constraint_type"), schema="INFORMATION_SCHEMA") column_constraints = Table("CONSTRAINT_COLUMN_USAGE", ischema, - Column("TABLE_SCHEMA", String, key="table_schema"), - Column("TABLE_NAME", String, key="table_name"), - Column("COLUMN_NAME", String, key="column_name"), - Column("CONSTRAINT_NAME", String, key="constraint_name"), + Column("TABLE_SCHEMA", Unicode, key="table_schema"), + Column("TABLE_NAME", Unicode, key="table_name"), + Column("COLUMN_NAME", Unicode, key="column_name"), + Column("CONSTRAINT_NAME", Unicode, key="constraint_name"), schema="INFORMATION_SCHEMA") key_constraints = Table("KEY_COLUMN_USAGE", ischema, - Column("TABLE_SCHEMA", String, key="table_schema"), - Column("TABLE_NAME", String, key="table_name"), - Column("COLUMN_NAME", String, key="column_name"), - Column("CONSTRAINT_NAME", String, key="constraint_name"), + Column("TABLE_SCHEMA", Unicode, key="table_schema"), + Column("TABLE_NAME", Unicode, key="table_name"), + Column("COLUMN_NAME", Unicode, key="column_name"), + Column("CONSTRAINT_NAME", Unicode, key="constraint_name"), Column("ORDINAL_POSITION", Integer, key="ordinal_position"), schema="INFORMATION_SCHEMA") ref_constraints = Table("REFERENTIAL_CONSTRAINTS", ischema, - Column("CONSTRAINT_CATALOG", String, key="constraint_catalog"), - Column("CONSTRAINT_SCHEMA", String, key="constraint_schema"), - Column("CONSTRAINT_NAME", String, key="constraint_name"), - Column("UNIQUE_CONSTRAINT_CATLOG", String, key="unique_constraint_catalog"), - Column("UNIQUE_CONSTRAINT_SCHEMA", String, key="unique_constraint_schema"), - Column("UNIQUE_CONSTRAINT_NAME", String, key="unique_constraint_name"), + Column("CONSTRAINT_CATALOG", Unicode, key="constraint_catalog"), + Column("CONSTRAINT_SCHEMA", Unicode, key="constraint_schema"), + Column("CONSTRAINT_NAME", Unicode, key="constraint_name"), + Column("UNIQUE_CONSTRAINT_CATLOG", Unicode, key="unique_constraint_catalog"), # TODO: is CATLOG misspelled ? + Column("UNIQUE_CONSTRAINT_SCHEMA", Unicode, key="unique_constraint_schema"), + Column("UNIQUE_CONSTRAINT_NAME", Unicode, key="unique_constraint_name"), Column("MATCH_OPTION", String, key="match_option"), Column("UPDATE_RULE", String, key="update_rule"), Column("DELETE_RULE", String, key="delete_rule"), schema="INFORMATION_SCHEMA") views = Table("VIEWS", ischema, - Column("TABLE_CATALOG", String, key="table_catalog"), - Column("TABLE_SCHEMA", String, key="table_schema"), - Column("TABLE_NAME", String, key="table_name"), - Column("VIEW_DEFINITION", String, key="view_definition"), + Column("TABLE_CATALOG", Unicode, key="table_catalog"), + Column("TABLE_SCHEMA", Unicode, key="table_schema"), + Column("TABLE_NAME", Unicode, key="table_name"), + Column("VIEW_DEFINITION", Unicode, key="view_definition"), Column("CHECK_OPTION", String, key="check_option"), Column("IS_UPDATABLE", String, key="is_updatable"), schema="INFORMATION_SCHEMA") diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 3bb6536a3c..75d1442db1 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -2128,6 +2128,8 @@ class MySQLDialect(default.DefaultDialect): return rows class ReflectedState(object): + """Stores raw information about a SHOW CREATE TABLE statement.""" + def __init__(self): self.columns = [] self.table_options = {} @@ -2136,17 +2138,11 @@ class ReflectedState(object): self.constraints = [] class MySQLTableDefinitionParser(object): - - def __init__(self, dialect, preparer=None): - """Construct a MySQLSchemaReflector. - - identifier_preparer - An ANSIIdentifierPreparer type, used to determine the identifier - quoting style in effect. - """ - + """Parses the results of a SHOW CREATE TABLE statement.""" + + def __init__(self, dialect, preparer): self.dialect = dialect - self.preparer = preparer or dialect.identifier_preparer + self.preparer = preparer self._prep_regexes() def parse(self, show_create, charset): diff --git a/lib/sqlalchemy/dialects/mysql/mysqldb.py b/lib/sqlalchemy/dialects/mysql/mysqldb.py index b0fac6c44f..fc61391e5a 100644 --- a/lib/sqlalchemy/dialects/mysql/mysqldb.py +++ b/lib/sqlalchemy/dialects/mysql/mysqldb.py @@ -31,6 +31,14 @@ class MySQL_mysqldbExecutionContext(MySQLExecutionContext): def _lastrowid(self, cursor): return cursor.lastrowid + @property + def rowcount(self): + if hasattr(self, '_rowcount'): + return self._rowcount + else: + return self.cursor.rowcount + + class MySQL_mysqldbCompiler(MySQLCompiler): operators = util.update_copy( MySQLCompiler.operators, diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py index 8de8292772..bb3c00478a 100644 --- a/lib/sqlalchemy/dialects/oracle/base.py +++ b/lib/sqlalchemy/dialects/oracle/base.py @@ -473,6 +473,9 @@ class OracleDialect(default.DefaultDialect): preparer = OracleIdentifierPreparer defaultrunner = OracleDefaultRunner + reflection_options = ('oracle_resolve_synonyms', ) + + def __init__(self, use_ansi=True, optimize_limits=False, diff --git a/lib/sqlalchemy/dialects/type_migration_guidelines.txt b/lib/sqlalchemy/dialects/type_migration_guidelines.txt index 7e7e4c5a83..a22567b497 100644 --- a/lib/sqlalchemy/dialects/type_migration_guidelines.txt +++ b/lib/sqlalchemy/dialects/type_migration_guidelines.txt @@ -12,6 +12,9 @@ Rules for Migrating TypeEngine classes to 0.6 c. Specifying types where there is an analogue in sqlalchemy.types, but the database in use takes vendor-specific flags for those types. + + d. If a TypeEngine class doesn't provide any of this, it should be + *removed* from the dialect. 2. the TypeEngine classes are *no longer* used for: @@ -31,12 +34,19 @@ linked to TypeEngine classes. a. The string name should be matched to the most specific type possible within sqlalchemy.types, unless there is no matching type within sqlalchemy.types in which - case it points to a dialect type. + case it points to a dialect type. *It doesn't matter* if the dialect has it's + own subclass of that type with special bind/result behavior - reflect to the generic type + as much as possible, since the correct bind/result behavior is always invoked when needed + regardless of the type being generic or dialect-specific. + + b. If the dialect contains a matching dialect-specific type that takes extra arguments + which the generic one does not, then point to the dialect-specific type. E.g. + mssql MSString takes a "collation" parameter which should be preserved. - b. For an exact or almost exact match, point to the uppercase type. i.e. "float" + c. For an exact or almost exact match, point to the uppercase type. i.e. "float" should point to "FLOAT", "varchar" should point to "VARCHAR" - c. for a non-match, point to the lowercase type. i.e. "long" should point to "Text", + d. for a non-match, point to the lowercase type. i.e. "long" should point to "Text", "special varchar with sprinkles" points to "String". 5. DDL, or what was formerly issued by "get_col_spec()", is now handled exclusively by diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 6f45c4ef53..3e81608171 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -576,11 +576,6 @@ class Compiled(object): return self.string or '' - @util.deprecated('Deprecated. Use construct_params(). ' - '(supports Unicode key names.)') - def get_params(self, **params): - return self.construct_params(params) - def construct_params(self, params=None): """Return the bind params for this compiled object. @@ -591,6 +586,12 @@ class Compiled(object): raise NotImplementedError() + params = property(construct_params, doc=""" + Return the bind params for this compiled object. + + """) + + def execute(self, *multiparams, **params): """Execute this compiled object.""" @@ -1558,7 +1559,6 @@ class ResultProxy(object): _process_row = RowProxy def __init__(self, context): - """ResultProxy objects are constructed via the execute() method on SQLEngine.""" self.context = context self.dialect = context.dialect self.closed = False @@ -1567,12 +1567,9 @@ class ResultProxy(object): self._echo = context.engine._should_log_info self._init_metadata() - @property + @util.memoized_property def rowcount(self): - if self._rowcount is None: - return self.context.get_rowcount() - else: - return self._rowcount + return self.context.rowcount @property def lastrowid(self): @@ -1587,11 +1584,10 @@ class ResultProxy(object): if metadata is None: # no results, get rowcount (which requires open cursor on some DB's such as firebird), # then close - self._rowcount = self.context.get_rowcount() + self.rowcount self.close() return - self._rowcount = None self._props = util.populate_column_dict(None) self._props.creator = self.__key_fallback() self.keys = [] diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index cd47f90bf7..789e02f7bf 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -51,6 +51,7 @@ class DefaultDialect(base.Dialect): default_paramstyle = 'named' supports_default_values = False supports_empty_insert = True + reflection_options = () def __init__(self, convert_unicode=False, assert_unicode=False, encoding='utf-8', paramstyle=None, dbapi=None, @@ -81,11 +82,11 @@ class DefaultDialect(base.Dialect): self.description_encoding = getattr(self, 'description_encoding', encoding) # Py3K + ## work around dialects that might change these values #self.supports_unicode_statements = True #self.supports_unicode_binds = True def initialize(self, connection): - # TODO: all dialects need to implement this if hasattr(self, '_get_server_version_info'): self.server_version_info = self._get_server_version_info(connection) @@ -316,12 +317,10 @@ class DefaultExecutionContext(base.ExecutionContext): def get_result_proxy(self): return base.ResultProxy(self) - - def get_rowcount(self): - if hasattr(self, '_rowcount'): - return self._rowcount - else: - return self.cursor.rowcount + + @property + def rowcount(self): + return self.cursor.rowcount def supports_sane_rowcount(self): return self.dialect.supports_sane_rowcount diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py index d4ee364520..cc0d511c95 100644 --- a/lib/sqlalchemy/engine/reflection.py +++ b/lib/sqlalchemy/engine/reflection.py @@ -245,11 +245,7 @@ class Inspector(object): dialect._adjust_casing(table) # table attributes we might need. - oracle_resolve_synonyms = table.kwargs.get('oracle_resolve_synonyms', - False) - - # some properties that need to be figured out - fk_use_existing = True + reflection_options = dict((k, table.kwargs.get(k)) for k in dialect.reflection_options if k in table.kwargs) schema = table.schema table_name = table.name @@ -267,12 +263,10 @@ class Inspector(object): tblkw[str(k)] = v ### Py2K - # fixme - # This is breaking mssql, which can't bind unicode. - ##if isinstance(schema, str): - ## schema = schema.decode(dialect.encoding) - ##if isinstance(table_name, str): - ## table_name = table_name.decode(dialect.encoding) + if isinstance(schema, str): + schema = schema.decode(dialect.encoding) + if isinstance(table_name, str): + table_name = table_name.decode(dialect.encoding) # end Py2K # columns @@ -314,10 +308,6 @@ class Inspector(object): if pk in table.c: col = table.c[pk] table.primary_key.add(col) - # fixme - if not isinstance(dialect, MySQLDialect): - if col.default is None: - col.autoincrement = False # Foreign keys fkeys = self.get_foreign_keys(table_name, schema, **tblkw) for fkey_d in fkeys: @@ -331,8 +321,7 @@ class Inspector(object): sa_schema.Table(referred_table, table.metadata, autoload=True, schema=referred_schema, autoload_with=self.conn, - oracle_resolve_synonyms=oracle_resolve_synonyms, - useexisting=fk_use_existing + **reflection_options ) for column in referred_columns: refspec.append(".".join( @@ -340,8 +329,7 @@ class Inspector(object): else: sa_schema.Table(referred_table, table.metadata, autoload=True, autoload_with=self.conn, - oracle_resolve_synonyms=oracle_resolve_synonyms, - useexisting=fk_use_existing + **reflection_options ) for column in referred_columns: refspec.append(".".join([referred_table, column])) diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py index e62b01116e..173a138409 100644 --- a/lib/sqlalchemy/engine/strategies.py +++ b/lib/sqlalchemy/engine/strategies.py @@ -22,15 +22,10 @@ class EngineStrategy(object): Provides a ``create`` method that receives input arguments and produces an instance of base.Engine or a subclass. + """ - def __init__(self, name): - """Construct a new EngineStrategy object. - - Sets it in the list of available strategies under this name. - """ - - self.name = name + def __init__(self): strategies[self.name] = self def create(self, *args, **kwargs): @@ -42,6 +37,8 @@ class EngineStrategy(object): class DefaultEngineStrategy(EngineStrategy): """Base class for built-in stratgies.""" + pool_threadlocal = False + def create(self, name_or_url, **kwargs): # create url.URL object u = url.make_url(name_or_url) @@ -96,7 +93,7 @@ class DefaultEngineStrategy(EngineStrategy): tk = translate.get(k, k) if tk in kwargs: pool_args[k] = kwargs.pop(tk) - pool_args.setdefault('use_threadlocal', self.pool_threadlocal()) + pool_args.setdefault('use_threadlocal', self.pool_threadlocal) pool = poolclass(creator, **pool_args) else: if isinstance(pool, poollib._DBProxy): @@ -105,7 +102,7 @@ class DefaultEngineStrategy(EngineStrategy): pool = pool # create engine. - engineclass = self.get_engine_cls() + engineclass = self.engine_cls engine_args = {} for k in util.get_cls_kwargs(engineclass): if k in kwargs: @@ -127,6 +124,8 @@ class DefaultEngineStrategy(EngineStrategy): engine = engineclass(pool, dialect, u, **engine_args) if _initialize: + # some unit tests pass through _initialize=False + # to help mock engines work class OnInit(object): def first_connect(self, conn, rec): c = base.Connection(engine, connection=conn) @@ -137,39 +136,22 @@ class DefaultEngineStrategy(EngineStrategy): return engine - def pool_threadlocal(self): - raise NotImplementedError() - - def get_engine_cls(self): - raise NotImplementedError() - class PlainEngineStrategy(DefaultEngineStrategy): """Strategy for configuring a regular Engine.""" - def __init__(self): - DefaultEngineStrategy.__init__(self, 'plain') - - def pool_threadlocal(self): - return False - - def get_engine_cls(self): - return base.Engine - + name = 'plain' + engine_cls = base.Engine + PlainEngineStrategy() class ThreadLocalEngineStrategy(DefaultEngineStrategy): """Strategy for configuring an Engine with thredlocal behavior.""" - - def __init__(self): - DefaultEngineStrategy.__init__(self, 'threadlocal') - - def pool_threadlocal(self): - return True - - def get_engine_cls(self): - return threadlocal.TLEngine + + name = 'threadlocal' + pool_threadlocal = True + engine_cls = threadlocal.TLEngine ThreadLocalEngineStrategy() @@ -179,11 +161,11 @@ class MockEngineStrategy(EngineStrategy): Produces a single mock Connectable object which dispatches statement execution to a passed-in function. + """ - def __init__(self): - EngineStrategy.__init__(self, 'mock') - + name = 'mock' + def create(self, name_or_url, executor, **kwargs): # create url.URL object u = url.make_url(name_or_url) diff --git a/lib/sqlalchemy/queue.py b/lib/sqlalchemy/queue.py index 37e772547d..848c272b70 100644 --- a/lib/sqlalchemy/queue.py +++ b/lib/sqlalchemy/queue.py @@ -1,8 +1,8 @@ """An adaptation of Py2.3/2.4's Queue module which supports reentrant behavior, using RLock instead of Lock for its mutex object. -This is to support the connection pool's usage of ``__del__`` to return -connections to the underlying Queue, which can apparently in extremely +This is to support the connection pool's usage of weakref callbacks to return +connections to the underlying Queue, which can in extremely rare cases be invoked within the ``get()`` method of the Queue itself, producing a ``put()`` inside the ``get()`` and therefore a reentrant condition.""" diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 8c0418a5e2..2da2705df9 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -91,13 +91,15 @@ class _TableSingleton(visitors.VisitableType): """A metaclass used by the ``Table`` object to provide singleton behavior.""" def __call__(self, name, metadata, *args, **kwargs): - schema = kwargs.get('schema', kwargs.get('owner', None)) + schema = kwargs.get('schema', None) useexisting = kwargs.pop('useexisting', False) mustexist = kwargs.pop('mustexist', False) key = _get_table_key(name, schema) try: table = metadata.tables[key] - if not useexisting and table._cant_override(*args, **kwargs): + if not useexisting and bool(args): + import pdb + pdb.set_trace() raise exc.InvalidRequestError( "Table '%s' is already defined for this MetaData instance. " "Specify 'useexisting=True' to redefine options and " @@ -203,7 +205,7 @@ class Table(SchemaItem, expression.TableClause): """ super(Table, self).__init__(name) self.metadata = metadata - self.schema = kwargs.pop('schema', kwargs.pop('owner', None)) + self.schema = kwargs.pop('schema', None) self.indexes = set() self.constraints = set() self._columns = expression.ColumnCollection() @@ -269,16 +271,6 @@ class Table(SchemaItem, expression.TableClause): self.__extra_kwargs(**kwargs) self.__post_init(*args, **kwargs) - def _cant_override(self, *args, **kwargs): - """Return True if any argument is not supported as an override. - - Takes arguments that would be sent to Table.__init__, and returns - True if any of them would be disallowed if sent to an existing - Table singleton. - """ - return bool(args) or bool(set(kwargs).difference( - ['autoload', 'autoload_with', 'schema', 'owner'])) - def __extra_kwargs(self, **kwargs): # validate remaining kwargs that they all specify DB prefixes if len([k for k in kwargs diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index a419de431e..ab6bf0d4db 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -244,8 +244,6 @@ class SQLCompiler(engine.Compiled): pd[self.bind_names[bindparam]] = bindparam.value return pd - params = property(construct_params) - def default_from(self): """Called when a SELECT statement has no froms, and no FROM clause is to be appended. diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 3f73824534..228d8a59de 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -635,7 +635,7 @@ class Numeric(TypeEngine): __visit_name__ = 'numeric' - def __init__(self, precision=10, scale=2, asdecimal=True, length=None): + def __init__(self, precision=None, scale=None, asdecimal=True): """ Construct a Numeric. @@ -649,9 +649,6 @@ class Numeric(TypeEngine): use. """ - if length: - util.warn_deprecated("'length' is deprecated for Numeric. Use 'scale'.") - scale = length self.precision = precision self.scale = scale self.asdecimal = asdecimal @@ -687,7 +684,7 @@ class Float(Numeric): __visit_name__ = 'float' - def __init__(self, precision=10, asdecimal=False, **kwargs): + def __init__(self, precision=None, asdecimal=False, **kwargs): """ Construct a Float. diff --git a/test/engine/parseconnect.py b/test/engine/parseconnect.py index 329f020240..a540985de3 100644 --- a/test/engine/parseconnect.py +++ b/test/engine/parseconnect.py @@ -29,8 +29,6 @@ class ParseConnectTest(TestBase): 'dbtype://username:apples%2Foranges@hostspec/mydatabase', ): u = url.make_url(text) - print u, text - print "username=", u.username, "password=", u.password, "database=", u.database, "host=", u.host assert u.drivername == 'dbtype' assert u.username == 'username' or u.username is None assert u.password == 'password' or u.password == 'apples/oranges' or u.password is None diff --git a/test/sql/select.py b/test/sql/select.py index e99b953b9b..3e8733790e 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -1287,21 +1287,21 @@ UNION SELECT mytable.myid FROM mytable WHERE mytable.myid = :myid_2)") # coverage on other dialects. sel = select([tbl, cast(tbl.c.v1, Numeric)]).compile(dialect=dialect) if isinstance(dialect, type(mysql.dialect())): - self.assertEqual(str(sel), "SELECT casttest.id, casttest.v1, casttest.v2, casttest.ts, CAST(casttest.v1 AS DECIMAL(10, 2)) AS anon_1 \nFROM casttest") + self.assertEqual(str(sel), "SELECT casttest.id, casttest.v1, casttest.v2, casttest.ts, CAST(casttest.v1 AS DECIMAL) AS anon_1 \nFROM casttest") else: - self.assertEqual(str(sel), "SELECT casttest.id, casttest.v1, casttest.v2, casttest.ts, CAST(casttest.v1 AS NUMERIC(10, 2)) AS anon_1 \nFROM casttest") + self.assertEqual(str(sel), "SELECT casttest.id, casttest.v1, casttest.v2, casttest.ts, CAST(casttest.v1 AS NUMERIC) AS anon_1 \nFROM casttest") # first test with Postgres engine - check_results(postgres.dialect(), ['NUMERIC(10, 2)', 'NUMERIC(12, 9)', 'DATE', 'TEXT', 'VARCHAR(20)'], '%(param_1)s') + check_results(postgres.dialect(), ['NUMERIC', 'NUMERIC(12, 9)', 'DATE', 'TEXT', 'VARCHAR(20)'], '%(param_1)s') # then the Oracle engine - check_results(oracle.dialect(), ['NUMERIC(10, 2)', 'NUMERIC(12, 9)', 'DATE', 'CLOB', 'VARCHAR(20)'], ':param_1') + check_results(oracle.dialect(), ['NUMERIC', 'NUMERIC(12, 9)', 'DATE', 'CLOB', 'VARCHAR(20)'], ':param_1') # then the sqlite engine - check_results(sqlite.dialect(), ['NUMERIC(10, 2)', 'NUMERIC(12, 9)', 'DATE', 'TEXT', 'VARCHAR(20)'], '?') + check_results(sqlite.dialect(), ['NUMERIC', 'NUMERIC(12, 9)', 'DATE', 'TEXT', 'VARCHAR(20)'], '?') # then the MySQL engine - check_results(mysql.dialect(), ['DECIMAL(10, 2)', 'DECIMAL(12, 9)', 'DATE', 'CHAR', 'CHAR(20)'], '%s') + check_results(mysql.dialect(), ['DECIMAL', 'DECIMAL(12, 9)', 'DATE', 'CHAR', 'CHAR(20)'], '%s') self.assert_compile(cast(text('NULL'), Integer), "CAST(NULL AS INTEGER)", dialect=sqlite.dialect()) self.assert_compile(cast(null(), Integer), "CAST(NULL AS INTEGER)", dialect=sqlite.dialect()) @@ -1356,7 +1356,7 @@ UNION SELECT mytable.myid FROM mytable WHERE mytable.myid = :myid_2)") (table1.c.name, 'name', 'mytable.name', None), (table1.c.myid==12, 'mytable.myid = :myid_1', 'mytable.myid = :myid_1', 'anon_1'), (func.hoho(table1.c.myid), 'hoho(mytable.myid)', 'hoho(mytable.myid)', 'hoho_1'), - (cast(table1.c.name, sqlite.SLNumeric), 'CAST(mytable.name AS NUMERIC(10, 2))', 'CAST(mytable.name AS NUMERIC(10, 2))', 'anon_1'), + (cast(table1.c.name, sqlite.SLNumeric), 'CAST(mytable.name AS NUMERIC)', 'CAST(mytable.name AS NUMERIC)', 'anon_1'), (t1.c.col1, 'col1', 'mytable.col1', None), (column('some wacky thing'), 'some wacky thing', '"some wacky thing"', '') ): diff --git a/test/sql/testtypes.py b/test/sql/testtypes.py index 5ef2b73f15..cb733172dd 100644 --- a/test/sql/testtypes.py +++ b/test/sql/testtypes.py @@ -728,33 +728,6 @@ class NumericTest(TestBase, AssertsExecutionResults): assert isinstance(row['ncasdec'], decimal.Decimal) assert isinstance(row['fcasdec'], decimal.Decimal) - def test_length_deprecation(self): - self.assertRaises(exc.SADeprecationWarning, Numeric, length=8) - - @testing.uses_deprecated(".*is deprecated for Numeric") - def go(): - n = Numeric(length=12) - assert n.scale == 12 - go() - - n = Numeric(scale=12) - for dialect in engines.all_dialects(): - n2 = dialect.type_descriptor(n) - eq_(n2.scale, 12, dialect.name) - - # test colspec generates successfully using 'scale' - assert dialect.type_compiler.process(n2) - - # test constructor of the dialect-specific type - n3 = n2.__class__(scale=5) - eq_(n3.scale, 5, dialect.name) - - @testing.uses_deprecated(".*is deprecated for Numeric") - def go(): - n3 = n2.__class__(length=6) - eq_(n3.scale, 6, dialect.name) - go() - class IntervalTest(TestBase, AssertsExecutionResults): def setUpAll(self):