From 6751cc0dbea2a7c7f8eda6dc86fe999f395915d6 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 8 Jul 2009 02:17:18 +0000 Subject: [PATCH] - type renaming extravaganza - changed the contract a bit on reflection.cache --- doc/build/reference/dialects/mysql.rst | 66 +-- lib/sqlalchemy/dialects/maxdb/base.py | 7 - lib/sqlalchemy/dialects/mssql/base.py | 152 +++--- lib/sqlalchemy/dialects/mysql/base.py | 482 ++++++++---------- lib/sqlalchemy/dialects/oracle/base.py | 53 +- lib/sqlalchemy/dialects/sybase/base.py | 6 - .../dialects/type_migration_guidelines.txt | 38 ++ lib/sqlalchemy/engine/reflection.py | 8 +- lib/sqlalchemy/types.py | 9 - test/dialect/test_mysql.py | 8 +- test/engine/test_reflection.py | 9 +- test/sql/test_types.py | 7 - 12 files changed, 419 insertions(+), 426 deletions(-) diff --git a/doc/build/reference/dialects/mysql.rst b/doc/build/reference/dialects/mysql.rst index 7df1c98434..a3a4f0e72c 100644 --- a/doc/build/reference/dialects/mysql.rst +++ b/doc/build/reference/dialects/mysql.rst @@ -6,135 +6,135 @@ MySQL MySQL Column Types ------------------ -.. autoclass:: MSNumeric +.. autoclass:: NUMERIC :members: __init__ :show-inheritance: -.. autoclass:: MSDecimal +.. autoclass:: DECIMAL :members: __init__ :show-inheritance: -.. autoclass:: MSDouble +.. autoclass:: DOUBLE :members: __init__ :show-inheritance: -.. autoclass:: MSReal +.. autoclass:: REAL :members: __init__ :show-inheritance: -.. autoclass:: MSFloat +.. autoclass:: FLOAT :members: __init__ :show-inheritance: -.. autoclass:: MSInteger +.. autoclass:: INTEGER :members: __init__ :show-inheritance: -.. autoclass:: MSBigInteger +.. autoclass:: BIGINT :members: __init__ :show-inheritance: -.. autoclass:: MSMediumInteger +.. autoclass:: MEDIUMINT :members: __init__ :show-inheritance: -.. autoclass:: MSTinyInteger +.. autoclass:: TINYINT :members: __init__ :show-inheritance: -.. autoclass:: MSSmallInteger +.. autoclass:: SMALLINT :members: __init__ :show-inheritance: -.. autoclass:: MSBit +.. autoclass:: BIT :members: __init__ :show-inheritance: -.. autoclass:: MSDateTime +.. autoclass:: DATETIME :members: __init__ :show-inheritance: -.. autoclass:: MSDate +.. autoclass:: DATE :members: __init__ :show-inheritance: -.. autoclass:: MSTime +.. autoclass:: TIME :members: __init__ :show-inheritance: -.. autoclass:: MSTimeStamp +.. autoclass:: TIMESTAMP :members: __init__ :show-inheritance: -.. autoclass:: MSYear +.. autoclass:: YEAR :members: __init__ :show-inheritance: -.. autoclass:: MSText +.. autoclass:: TEXT :members: __init__ :show-inheritance: -.. autoclass:: MSTinyText +.. autoclass:: TINYTEXT :members: __init__ :show-inheritance: -.. autoclass:: MSMediumText +.. autoclass:: MEDIUMTEXT :members: __init__ :show-inheritance: -.. autoclass:: MSLongText +.. autoclass:: LONGTEXT :members: __init__ :show-inheritance: -.. autoclass:: MSString +.. autoclass:: VARCHAR :members: __init__ :show-inheritance: -.. autoclass:: MSChar +.. autoclass:: CHAR :members: __init__ :show-inheritance: -.. autoclass:: MSNVarChar +.. autoclass:: NVARCHAR :members: __init__ :show-inheritance: -.. autoclass:: MSNChar +.. autoclass:: NCHAR :members: __init__ :show-inheritance: -.. autoclass:: MSVarBinary +.. autoclass:: VARBINARY :members: __init__ :show-inheritance: -.. autoclass:: MSBinary +.. autoclass:: BINARY :members: __init__ :show-inheritance: -.. autoclass:: MSBlob +.. autoclass:: BLOB :members: __init__ :show-inheritance: -.. autoclass:: MSTinyBlob +.. autoclass:: TINYBLOB :members: __init__ :show-inheritance: -.. autoclass:: MSMediumBlob +.. autoclass:: MEDIUMBLOB :members: __init__ :show-inheritance: -.. autoclass:: MSLongBlob +.. autoclass:: LONGBLOB :members: __init__ :show-inheritance: -.. autoclass:: MSEnum +.. autoclass:: ENUM :members: __init__ :show-inheritance: -.. autoclass:: MSSet +.. autoclass:: SET :members: __init__ :show-inheritance: -.. autoclass:: MSBoolean +.. autoclass:: BOOLEAN :members: __init__ :show-inheritance: diff --git a/lib/sqlalchemy/dialects/maxdb/base.py b/lib/sqlalchemy/dialects/maxdb/base.py index e81ecccb9b..b5201c5590 100644 --- a/lib/sqlalchemy/dialects/maxdb/base.py +++ b/lib/sqlalchemy/dialects/maxdb/base.py @@ -67,13 +67,6 @@ from sqlalchemy.engine import base as engine_base, default from sqlalchemy import types as sqltypes -__all__ = [ - 'MaxString', 'MaxUnicode', 'MaxChar', 'MaxText', 'MaxInteger', - 'MaxSmallInteger', 'MaxNumeric', 'MaxFloat', 'MaxTimestamp', - 'MaxDate', 'MaxTime', 'MaxBoolean', 'MaxBlob', - ] - - class _StringType(sqltypes.String): _type = None diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index fdec5741db..8d695f9881 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -228,6 +228,9 @@ from sqlalchemy.sql import select, compiler, expression, operators as sql_operat from sqlalchemy.engine import default, base, reflection from sqlalchemy import types as sqltypes from decimal import Decimal as _python_Decimal +from sqlalchemy.types import INTEGER, BIGINT, SMALLINT, DECIMAL, NUMERIC, \ + FLOAT, TIMESTAMP + from sqlalchemy.dialects.mssql import information_schema as ischema @@ -314,23 +317,26 @@ class MSNumeric(sqltypes.Numeric): return process -class MSReal(sqltypes.Float): +class REAL(sqltypes.Float): """A type for ``real`` numbers.""" __visit_name__ = 'REAL' def __init__(self): - super(MSReal, self).__init__(precision=24) + super(REAL, self).__init__(precision=24) +MSReal = REAL -class MSTinyInteger(sqltypes.Integer): +class TINYINT(sqltypes.Integer): __visit_name__ = 'TINYINT' +MSTinyInteger = TINYINT + # MSSQL DATE/TIME types have varied behavior, sometimes returning # strings. MSDate/MSTime check for everything, and always # filter bind parameters into datetime objects (required by pyodbc, # not sure about other dialects). -class MSDate(sqltypes.Date): +class DATE(sqltypes.DATE): def bind_processor(self, dialect): def process(value): if type(value) == datetime.date: @@ -349,11 +355,12 @@ class MSDate(sqltypes.Date): else: return value return process - -class MSTime(sqltypes.Time): +MSDate = DATE + +class TIME(sqltypes.TIME): def __init__(self, precision=None, **kwargs): self.precision = precision - super(MSTime, self).__init__() + super(TIME, self).__init__() __zero_date = datetime.date(1900, 1, 1) @@ -377,32 +384,42 @@ class MSTime(sqltypes.Time): return value return process +MSTime = TIME + class _DateTimeBase(object): def bind_processor(self, dialect): def process(value): + # TODO: why ? if type(value) == datetime.date: return datetime.datetime(value.year, value.month, value.day) else: return value return process -class MSDateTime(_DateTimeBase, sqltypes.DATETIME): +class DATETIME(_DateTimeBase, sqltypes.DATETIME): pass - -class MSSmallDateTime(_DateTimeBase, sqltypes.DateTime): +MSDateTime = DATETIME + +class SMALLDATETIME(_DateTimeBase, sqltypes.DateTime): __visit_name__ = 'SMALLDATETIME' +MSSmallDateTime = SMALLDATETIME -class MSDateTime2(_DateTimeBase, sqltypes.DateTime): +class DATETIME2(_DateTimeBase, sqltypes.DateTime): __visit_name__ = 'DATETIME2' def __init__(self, precision=None, **kwargs): self.precision = precision +MSDateTime2 = DATETIME2 -class MSDateTimeOffset(sqltypes.TypeEngine): + +# TODO: is this not an Interval ? +class DATETIMEOFFSET(sqltypes.TypeEngine): __visit_name__ = 'DATETIMEOFFSET' def __init__(self, precision=None, **kwargs): self.precision = precision +MSDateTimeOffset = DATETIMEOFFSET + class _StringType(object): """Base for MSSQL string types.""" @@ -424,7 +441,7 @@ class _StringType(object): ', '.join(['%s=%r' % (k, params[k]) for k in params])) -class MSText(_StringType, sqltypes.TEXT): +class TEXT(_StringType, sqltypes.TEXT): """MSSQL TEXT type, for variable-length text up to 2^31 characters.""" def __init__(self, *args, **kw): @@ -437,8 +454,9 @@ class MSText(_StringType, sqltypes.TEXT): collation = kw.pop('collation', None) _StringType.__init__(self, collation) sqltypes.Text.__init__(self, *args, **kw) +MSText = TEXT -class MSNText(_StringType, sqltypes.UnicodeText): +class NTEXT(_StringType, sqltypes.UnicodeText): """MSSQL NTEXT type, for variable-length unicode text up to 2^30 characters.""" @@ -455,10 +473,10 @@ class MSNText(_StringType, sqltypes.UnicodeText): _StringType.__init__(self, collation) length = kwargs.pop('length', None) sqltypes.UnicodeText.__init__(self, length, **kwargs) +MSNText = NTEXT - -class MSString(_StringType, sqltypes.VARCHAR): +class VARCHAR(_StringType, sqltypes.VARCHAR): """MSSQL VARCHAR type, for variable-length non-Unicode data with a maximum of 8,000 characters.""" @@ -496,8 +514,9 @@ class MSString(_StringType, sqltypes.VARCHAR): collation = kw.pop('collation', None) _StringType.__init__(self, collation) sqltypes.VARCHAR.__init__(self, *args, **kw) +MSString = VARCHAR -class MSNVarchar(_StringType, sqltypes.NVARCHAR): +class NVARCHAR(_StringType, sqltypes.NVARCHAR): """MSSQL NVARCHAR type. For variable-length unicode character data up to 4,000 characters.""" @@ -514,9 +533,9 @@ class MSNVarchar(_StringType, sqltypes.NVARCHAR): collation = kw.pop('collation', None) _StringType.__init__(self, collation) sqltypes.NVARCHAR.__init__(self, *args, **kw) +MSNVarchar = NVARCHAR - -class MSChar(_StringType, sqltypes.CHAR): +class CHAR(_StringType, sqltypes.CHAR): """MSSQL CHAR type, for fixed-length non-Unicode data with a maximum of 8,000 characters.""" @@ -554,9 +573,9 @@ class MSChar(_StringType, sqltypes.CHAR): collation = kw.pop('collation', None) _StringType.__init__(self, collation) sqltypes.CHAR.__init__(self, *args, **kw) +MSChar = CHAR - -class MSNChar(_StringType, sqltypes.NCHAR): +class NCHAR(_StringType, sqltypes.NCHAR): """MSSQL NCHAR type. For fixed-length unicode character data up to 4,000 characters.""" @@ -573,19 +592,23 @@ class MSNChar(_StringType, sqltypes.NCHAR): collation = kw.pop('collation', None) _StringType.__init__(self, collation) sqltypes.NCHAR.__init__(self, *args, **kw) +MSNChar = NCHAR -class MSBinary(sqltypes.Binary): +class BINARY(sqltypes.Binary): __visit_name__ = 'BINARY' +MSBinary = BINARY -class MSVarBinary(sqltypes.Binary): +class VARBINARY(sqltypes.Binary): __visit_name__ = 'VARBINARY' - +MSVarBinary = VARBINARY -class MSImage(sqltypes.Binary): +class IMAGE(sqltypes.Binary): __visit_name__ = 'IMAGE' +MSImage = IMAGE -class MSBit(sqltypes.TypeEngine): +class BIT(sqltypes.TypeEngine): __visit_name__ = 'BIT' +MSBit = BIT class MSBoolean(sqltypes.Boolean): def result_processor(self, dialect): @@ -607,18 +630,21 @@ class MSBoolean(sqltypes.Boolean): return value and True or False return process -class MSMoney(sqltypes.TypeEngine): +class MONEY(sqltypes.TypeEngine): __visit_name__ = 'MONEY' +MSMoney = MONEY -class MSSmallMoney(MSMoney): +class SMALLMONEY(MSMoney): __visit_name__ = 'SMALLMONEY' +MSSmallMoney = SMALLMONEY - -class MSUniqueIdentifier(sqltypes.TypeEngine): +class UNIQUEIDENTIFIER(sqltypes.TypeEngine): __visit_name__ = "UNIQUEIDENTIFIER" +MSUniqueIdentifier = UNIQUEIDENTIFIER -class MSVariant(sqltypes.TypeEngine): +class SQL_VARIANT(sqltypes.TypeEngine): __visit_name__ = 'SQL_VARIANT' +MSVariant = SQL_VARIANT class MSTypeCompiler(compiler.GenericTypeCompiler): def _extend(self, spec, type_): @@ -819,42 +845,42 @@ class MSExecutionContext(default.DefaultExecutionContext): colspecs = { sqltypes.Numeric : MSNumeric, - sqltypes.DateTime : MSDateTime, - sqltypes.Date : MSDate, - sqltypes.Time : MSTime, + sqltypes.DateTime : DATETIME, + sqltypes.Date : DATE, + sqltypes.Time : TIME, sqltypes.Boolean : MSBoolean, } ischema_names = { - 'int' : sqltypes.INTEGER, - 'bigint': sqltypes.BigInteger, - 'smallint' : sqltypes.SmallInteger, - 'tinyint' : MSTinyInteger, - 'varchar' : MSString, - 'nvarchar' : MSNVarchar, - 'char' : MSChar, - 'nchar' : MSNChar, - 'text' : MSText, - 'ntext' : MSNText, - 'decimal' : sqltypes.DECIMAL, - 'numeric' : sqltypes.NUMERIC, - 'float' : sqltypes.FLOAT, - 'datetime' : sqltypes.DATETIME, - 'datetime2' : MSDateTime2, - 'datetimeoffset' : MSDateTimeOffset, - 'date': sqltypes.DATE, - 'time': MSTime, - 'smalldatetime' : MSSmallDateTime, - 'binary' : MSBinary, - 'varbinary' : MSVarBinary, - 'bit': sqltypes.Boolean, - 'real' : MSReal, - 'image' : MSImage, - 'timestamp': sqltypes.TIMESTAMP, - 'money': MSMoney, - 'smallmoney': MSSmallMoney, - 'uniqueidentifier': MSUniqueIdentifier, - 'sql_variant': MSVariant, + 'int' : INTEGER, + 'bigint': BIGINT, + 'smallint' : SMALLINT, + 'tinyint' : TINYINT, + 'varchar' : VARCHAR, + 'nvarchar' : NVARCHAR, + 'char' : CHAR, + 'nchar' : NCHAR, + 'text' : TEXT, + 'ntext' : NTEXT, + 'decimal' : DECIMAL, + 'numeric' : NUMERIC, + 'float' : FLOAT, + 'datetime' : DATETIME, + 'datetime2' : DATETIME2, + 'datetimeoffset' : DATETIMEOFFSET, + 'date': DATE, + 'time': TIME, + 'smalldatetime' : SMALLDATETIME, + 'binary' : BINARY, + 'varbinary' : VARBINARY, + 'bit': BIT, + 'real' : REAL, + 'image' : IMAGE, + 'timestamp': TIMESTAMP, + 'money': MONEY, + 'smallmoney': SMALLMONEY, + 'uniqueidentifier': UNIQUEIDENTIFIER, + 'sql_variant': SQL_VARIANT, } class MSSQLCompiler(compiler.SQLCompiler): diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index de315ab459..3ea033fb52 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -23,8 +23,8 @@ then you will need to import them from this module:: Table('mytable', metadata, Column('id', Integer, primary_key=True), - Column('ittybittyblob', mysql.MSTinyBlob), - Column('biggy', mysql.MSBigInteger(unsigned=True))) + Column('ittybittyblob', mysql.TINYBLOB), + Column('biggy', mysql.BIGINT(unsigned=True))) All standard MySQL column types are supported. The OpenGIS types are available for use via table reflection but have no special support or mapping @@ -190,16 +190,7 @@ from sqlalchemy.engine import reflection from sqlalchemy.engine import base as engine_base, default from sqlalchemy import types as sqltypes - -__all__ = ( - 'MSBigInteger', 'MSMediumInteger', 'MSBinary', 'MSBit', 'MSBlob', 'MSBoolean', - 'MSChar', 'MSDate', 'MSDateTime', 'MSDecimal', 'MSDouble', - 'MSEnum', 'MSFloat', 'MSInteger', 'MSLongBlob', 'MSLongText', - 'MSMediumBlob', 'MSMediumText', 'MSNChar', 'MSNVarChar', - 'MSNumeric', 'MSSet', 'MSSmallInteger', 'MSString', 'MSText', - 'MSTime', 'MSTimeStamp', 'MSTinyBlob', 'MSTinyInteger', - 'MSTinyText', 'MSVarBinary', 'MSYear' ) - +from sqlalchemy.types import DATE, DATETIME RESERVED_WORDS = set( ['accessible', 'add', 'all', 'alter', 'analyze','and', 'as', 'asc', @@ -254,25 +245,62 @@ SET_RE = re.compile( class _NumericType(object): """Base for MySQL numeric types.""" - def __init__(self, kw): + def __init__(self, **kw): self.unsigned = kw.pop('unsigned', False) self.zerofill = kw.pop('zerofill', False) + super(_NumericType, self).__init__(**kw) + +class _FloatType(_NumericType, sqltypes.Float): + def __init__(self, precision=None, scale=None, asdecimal=True, **kw): + if isinstance(self, (REAL, DOUBLE)) and \ + ( + (precision is None and scale is not None) or + (precision is not None and scale is None) + ): + raise exc.ArgumentError( + "You must specify both precision and scale or omit " + "both altogether.") + + super(_FloatType, self).__init__(precision=precision, asdecimal=asdecimal, **kw) + self.scale = scale + +class _DecimalType(_NumericType): + def bind_processor(self, dialect): + return None + + def result_processor(self, dialect): + # TODO: this behavior might by MySQLdb specific, + # i.e. that Decimals are returned by the DBAPI + if not self.asdecimal: + def process(value): + if isinstance(value, decimal.Decimal): + return float(value) + else: + return value + return process + else: + return None +class _IntegerType(_NumericType, sqltypes.Integer): + def __init__(self, display_width=None, **kw): + self.display_width = display_width + super(_IntegerType, self).__init__(**kw) -class _StringType(object): +class _StringType(sqltypes.String): """Base for MySQL string types.""" def __init__(self, charset=None, collation=None, ascii=False, unicode=False, binary=False, - national=False, **kwargs): + national=False, **kw): self.charset = charset # allow collate= or collation= - self.collation = kwargs.get('collate', collation) + self.collation = kw.pop('collate', collation) self.ascii = ascii self.unicode = unicode self.binary = binary self.national = national - + super(_StringType, self).__init__(**kw) + def __repr__(self): attributes = inspect.getargspec(self.__init__)[0][1:] attributes.extend(inspect.getargspec(_StringType.__init__)[0][1:]) @@ -287,7 +315,18 @@ class _StringType(object): ', '.join(['%s=%r' % (k, params[k]) for k in params])) -class MSNumeric(sqltypes.Numeric, _NumericType): +class _BinaryType(sqltypes.Binary): + """Base for MySQL binary types.""" + + def result_processor(self, dialect): + def process(value): + if value is None: + return None + else: + return util.buffer(value) + return process + +class NUMERIC(_DecimalType, sqltypes.NUMERIC): """MySQL NUMERIC type.""" __visit_name__ = 'NUMERIC' @@ -308,25 +347,10 @@ class MSNumeric(sqltypes.Numeric, _NumericType): numeric. """ - _NumericType.__init__(self, kw) - sqltypes.Numeric.__init__(self, precision, scale, asdecimal=asdecimal, **kw) + super(NUMERIC, self).__init__(precision=precision, scale=scale, asdecimal=asdecimal, **kw) - def bind_processor(self, dialect): - return None - def result_processor(self, dialect): - if not self.asdecimal: - def process(value): - if isinstance(value, decimal.Decimal): - return float(value) - else: - return value - return process - else: - return None - - -class MSDecimal(MSNumeric): +class DECIMAL(_DecimalType, sqltypes.DECIMAL): """MySQL DECIMAL type.""" __visit_name__ = 'DECIMAL' @@ -347,10 +371,10 @@ class MSDecimal(MSNumeric): numeric. """ - super(MSDecimal, self).__init__(precision, scale, asdecimal=asdecimal, **kw) - + super(DECIMAL, self).__init__(precision=precision, scale=scale, asdecimal=asdecimal, **kw) -class MSDouble(sqltypes.Float, _NumericType): + +class DOUBLE(_FloatType): """MySQL DOUBLE type.""" __visit_name__ = 'DOUBLE' @@ -371,19 +395,9 @@ class MSDouble(sqltypes.Float, _NumericType): numeric. """ - if ((precision is None and scale is not None) or - (precision is not None and scale is None)): - raise exc.ArgumentError( - "You must specify both precision and scale or omit " - "both altogether.") - - _NumericType.__init__(self, kw) - sqltypes.Float.__init__(self, asdecimal=asdecimal, **kw) - self.scale = scale - self.precision = precision + super(DOUBLE, self).__init__(precision=precision, scale=scale, asdecimal=asdecimal, **kw) - -class MSReal(MSDouble): +class REAL(_FloatType): """MySQL REAL type.""" __visit_name__ = 'REAL' @@ -404,10 +418,9 @@ class MSReal(MSDouble): numeric. """ - MSDouble.__init__(self, precision, scale, asdecimal, **kw) - + super(REAL, self).__init__(precision=precision, scale=scale, asdecimal=asdecimal, **kw) -class MSFloat(sqltypes.Float, _NumericType): +class FLOAT(_FloatType, sqltypes.FLOAT): """MySQL FLOAT type.""" __visit_name__ = 'FLOAT' @@ -428,16 +441,12 @@ class MSFloat(sqltypes.Float, _NumericType): numeric. """ - _NumericType.__init__(self, kw) - sqltypes.Float.__init__(self, asdecimal=asdecimal, **kw) - self.scale = scale - self.precision = precision + super(FLOAT, self).__init__(precision=precision, scale=scale, asdecimal=asdecimal, **kw) def bind_processor(self, dialect): return None - -class MSInteger(sqltypes.Integer, _NumericType): +class INTEGER(_IntegerType, sqltypes.INTEGER): """MySQL INTEGER type.""" __visit_name__ = 'INTEGER' @@ -455,16 +464,9 @@ class MSInteger(sqltypes.Integer, _NumericType): numeric. """ - if 'length' in kw: - util.warn_deprecated("'length' is deprecated for MSInteger and subclasses. Use 'display_width'.") - self.display_width = kw.pop('length') - else: - self.display_width = display_width - _NumericType.__init__(self, kw) - sqltypes.Integer.__init__(self, **kw) - + super(INTEGER, self).__init__(display_width=display_width, **kw) -class MSBigInteger(MSInteger): +class BIGINT(_IntegerType, sqltypes.BIGINT): """MySQL BIGINTEGER type.""" __visit_name__ = 'BIGINT' @@ -482,10 +484,9 @@ class MSBigInteger(MSInteger): numeric. """ - super(MSBigInteger, self).__init__(display_width, **kw) + super(BIGINT, self).__init__(display_width=display_width, **kw) - -class MSMediumInteger(MSInteger): +class MEDIUMINT(_IntegerType): """MySQL MEDIUMINTEGER type.""" __visit_name__ = 'MEDIUMINT' @@ -503,10 +504,9 @@ class MSMediumInteger(MSInteger): numeric. """ - super(MSMediumInteger, self).__init__(display_width, **kw) - + super(MEDIUMINT, self).__init__(display_width=display_width, **kw) -class MSTinyInteger(MSInteger): +class TINYINT(_IntegerType): """MySQL TINYINT type.""" __visit_name__ = 'TINYINT' @@ -528,10 +528,9 @@ class MSTinyInteger(MSInteger): numeric. """ - super(MSTinyInteger, self).__init__(display_width, **kw) + super(TINYINT, self).__init__(display_width=display_width, **kw) - -class MSSmallInteger(sqltypes.SmallInteger, MSInteger): +class SMALLINT(_IntegerType, sqltypes.SMALLINT): """MySQL SMALLINTEGER type.""" __visit_name__ = 'SMALLINT' @@ -549,12 +548,9 @@ class MSSmallInteger(sqltypes.SmallInteger, MSInteger): numeric. """ - self.display_width = display_width - _NumericType.__init__(self, kw) - sqltypes.SmallInteger.__init__(self, **kw) + super(SMALLINT, self).__init__(display_width=display_width, **kw) - -class MSBit(sqltypes.TypeEngine): +class BIT(sqltypes.TypeEngine): """MySQL BIT type. This type is for MySQL 5.0.3 or greater for MyISAM, and 5.0.5 or greater for @@ -584,21 +580,7 @@ class MSBit(sqltypes.TypeEngine): return value return process -# TODO: probably don't need datetime/date types since no behavior changes - -class MSDateTime(sqltypes.DateTime): - """MySQL DATETIME type.""" - - __visit_name__ = 'DATETIME' - - -class MSDate(sqltypes.Date): - """MySQL DATE type.""" - __visit_name__ = 'DATE' - - - -class MSTime(sqltypes.Time): +class TIME(sqltypes.TIME): """MySQL TIME type.""" __visit_name__ = 'TIME' @@ -612,28 +594,11 @@ class MSTime(sqltypes.Time): return None return process -class MSTimeStamp(sqltypes.TIMESTAMP): - """MySQL TIMESTAMP type. - - To signal the orm to automatically re-select modified rows to retrieve the - updated timestamp, add a ``server_default`` to your - :class:`~sqlalchemy.Column` specification:: - - from sqlalchemy.databases import mysql - Column('updated', mysql.MSTimeStamp, - server_default=sql.text('CURRENT_TIMESTAMP') - ) - - The full range of MySQL 4.1+ TIMESTAMP defaults can be specified in - the the default:: - - server_default=sql.text('CURRENT TIMESTAMP ON UPDATE CURRENT_TIMESTAMP') - - """ +class TIMESTAMP(sqltypes.TIMESTAMP): + """MySQL TIMESTAMP type.""" __visit_name__ = 'TIMESTAMP' - -class MSYear(sqltypes.TypeEngine): +class YEAR(sqltypes.TypeEngine): """MySQL YEAR type, for single byte storage of years 1901-2155.""" __visit_name__ = 'YEAR' @@ -641,13 +606,12 @@ class MSYear(sqltypes.TypeEngine): def __init__(self, display_width=None): self.display_width = display_width - -class MSText(_StringType, sqltypes.Text): +class TEXT(_StringType, sqltypes.TEXT): """MySQL TEXT type, for text up to 2^16 characters.""" __visit_name__ = 'TEXT' - def __init__(self, length=None, **kwargs): + def __init__(self, length=None, **kw): """Construct a TEXT. :param length: Optional, if provided the server may optimize storage @@ -675,12 +639,9 @@ class MSText(_StringType, sqltypes.Text): only the collation of character data. """ - _StringType.__init__(self, **kwargs) - sqltypes.Text.__init__(self, length, - kwargs.get('convert_unicode', False), kwargs.get('assert_unicode', None)) - + super(TEXT, self).__init__(length=length, **kw) -class MSTinyText(MSText): +class TINYTEXT(_StringType): """MySQL TINYTEXT type, for text up to 2^8 characters.""" __visit_name__ = 'TINYTEXT' @@ -709,11 +670,9 @@ class MSTinyText(MSText): only the collation of character data. """ + super(TINYTEXT, self).__init__(**kwargs) - super(MSTinyText, self).__init__(**kwargs) - - -class MSMediumText(MSText): +class MEDIUMTEXT(_StringType): """MySQL MEDIUMTEXT type, for text up to 2^24 characters.""" __visit_name__ = 'MEDIUMTEXT' @@ -742,9 +701,9 @@ class MSMediumText(MSText): only the collation of character data. """ - super(MSMediumText, self).__init__(**kwargs) + super(MEDIUMTEXT, self).__init__(**kwargs) -class MSLongText(MSText): +class LONGTEXT(_StringType): """MySQL LONGTEXT type, for text up to 2^32 characters.""" __visit_name__ = 'LONGTEXT' @@ -773,11 +732,10 @@ class MSLongText(MSText): only the collation of character data. """ - super(MSLongText, self).__init__(**kwargs) - - + super(LONGTEXT, self).__init__(**kwargs) -class MSString(_StringType, sqltypes.String): + +class VARCHAR(_StringType, sqltypes.VARCHAR): """MySQL VARCHAR type, for variable-length character data.""" __visit_name__ = 'VARCHAR' @@ -806,12 +764,9 @@ class MSString(_StringType, sqltypes.String): only the collation of character data. """ - _StringType.__init__(self, **kwargs) - sqltypes.String.__init__(self, length, - kwargs.get('convert_unicode', False), kwargs.get('assert_unicode', None)) - + super(VARCHAR, self).__init__(length=length, **kwargs) -class MSChar(_StringType, sqltypes.CHAR): +class CHAR(_StringType, sqltypes.CHAR): """MySQL CHAR type, for fixed-length character data.""" __visit_name__ = 'CHAR' @@ -829,13 +784,9 @@ class MSChar(_StringType, sqltypes.CHAR): compatible with the national character set. """ - _StringType.__init__(self, **kwargs) - sqltypes.CHAR.__init__(self, length, - kwargs.get('convert_unicode', False)) - - + super(CHAR, self).__init__(length=length, **kwargs) -class MSNVarChar(_StringType, sqltypes.String): +class NVARCHAR(_StringType, sqltypes.NVARCHAR): """MySQL NVARCHAR type. For variable-length character data in the server's configured national @@ -858,13 +809,10 @@ class MSNVarChar(_StringType, sqltypes.String): """ kwargs['national'] = True - _StringType.__init__(self, **kwargs) - sqltypes.String.__init__(self, length, - kwargs.get('convert_unicode', False)) + super(NVARCHAR, self).__init__(length=length, **kwargs) - -class MSNChar(_StringType, sqltypes.CHAR): +class NCHAR(_StringType, sqltypes.NCHAR): """MySQL NCHAR type. For fixed-length character data in the server's configured national @@ -887,23 +835,11 @@ class MSNChar(_StringType, sqltypes.CHAR): """ kwargs['national'] = True - _StringType.__init__(self, **kwargs) - sqltypes.CHAR.__init__(self, length, - kwargs.get('convert_unicode', False)) - + super(NCHAR, self).__init__(length=length, **kwargs) -class _BinaryType(sqltypes.Binary): - """Base for MySQL binary types.""" - def result_processor(self, dialect): - def process(value): - if value is None: - return None - else: - return util.buffer(value) - return process -class MSVarBinary(_BinaryType): +class VARBINARY(_BinaryType): """MySQL VARBINARY type, for variable length binary data.""" __visit_name__ = 'VARBINARY' @@ -914,10 +850,9 @@ class MSVarBinary(_BinaryType): :param length: Maximum data length, in characters. """ - super(MSVarBinary, self).__init__(length, **kw) - + super(VARBINARY, self).__init__(length=length, **kw) -class MSBinary(_BinaryType): +class BINARY(_BinaryType): """MySQL BINARY type, for fixed length binary data""" __visit_name__ = 'BINARY' @@ -932,17 +867,9 @@ class MSBinary(_BinaryType): specified, this will generate a BLOB. This usage is deprecated. """ - super(MSBinary, self).__init__(length, **kw) + super(BINARY, self).__init__(length=length, **kw) - def result_processor(self, dialect): - def process(value): - if value is None: - return None - else: - return util.buffer(value) - return process - -class MSBlob(_BinaryType): +class BLOB(_BinaryType, sqltypes.BLOB): """MySQL BLOB type, for binary data up to 2^16 bytes""" __visit_name__ = 'BLOB' @@ -955,39 +882,25 @@ class MSBlob(_BinaryType): ``length`` characters. """ - super(MSBlob, self).__init__(length, **kw) + super(BLOB, self).__init__(length=length, **kw) - def result_processor(self, dialect): - def process(value): - if value is None: - return None - else: - return util.buffer(value) - return process - - def __repr__(self): - return "%s()" % self.__class__.__name__ - -class MSTinyBlob(MSBlob): +class TINYBLOB(_BinaryType): """MySQL TINYBLOB type, for binary data up to 2^8 bytes.""" __visit_name__ = 'TINYBLOB' - -class MSMediumBlob(MSBlob): +class MEDIUMBLOB(_BinaryType): """MySQL MEDIUMBLOB type, for binary data up to 2^24 bytes.""" __visit_name__ = 'MEDIUMBLOB' - -class MSLongBlob(MSBlob): +class LONGBLOB(_BinaryType): """MySQL LONGBLOB type, for binary data up to 2^32 bytes.""" __visit_name__ = 'LONGBLOB' - -class MSEnum(MSString): +class ENUM(_StringType): """MySQL ENUM type.""" __visit_name__ = 'ENUM' @@ -1078,10 +991,10 @@ class MSEnum(MSString): self.strict = kw.pop('strict', False) length = max([len(v) for v in self.enums] + [0]) - super(MSEnum, self).__init__(length, **kw) + super(ENUM, self).__init__(length=length, **kw) def bind_processor(self, dialect): - super_convert = super(MSEnum, self).bind_processor(dialect) + super_convert = super(ENUM, self).bind_processor(dialect) def process(value): if self.strict and value is not None and value not in self.enums: raise exc.InvalidRequestError('"%s" not a valid value for ' @@ -1092,7 +1005,7 @@ class MSEnum(MSString): return value return process -class MSSet(MSString): +class SET(_StringType): """MySQL SET type.""" __visit_name__ = 'SET' @@ -1141,7 +1054,7 @@ class MSSet(MSString): self.values = strip_values length = max([len(v) for v in strip_values] + [0]) - super(MSSet, self).__init__(length, **kw) + super(SET, self).__init__(length=length, **kw) def result_processor(self, dialect): def process(value): @@ -1165,7 +1078,7 @@ class MSSet(MSString): return process def bind_processor(self, dialect): - super_convert = super(MSSet, self).bind_processor(dialect) + super_convert = super(SET, self).bind_processor(dialect) def process(value): if value is None or isinstance(value, (int, long, basestring)): pass @@ -1181,8 +1094,7 @@ class MSSet(MSString): return value return process - -class MSBoolean(sqltypes.Boolean): +class BOOLEAN(sqltypes.Boolean): """MySQL BOOLEAN type.""" __visit_name__ = 'BOOLEAN' @@ -1206,63 +1118,83 @@ class MSBoolean(sqltypes.Boolean): return value and True or False return process +# old names +MSBoolean = BOOLEAN +MSSet = SET +MSEnum = ENUM +MSLongBlob = LONGBLOB +MSMediumBlob = MEDIUMBLOB +MSTinyBlob = TINYBLOB +MSBlob = BLOB +MSBinary = BINARY +MSVarBinary = VARBINARY +MSNChar = NCHAR +MSNVarChar = NVARCHAR +MSChar = CHAR +MSString = VARCHAR +MSLongText = LONGTEXT +MSMediumText = MEDIUMTEXT +MSTinyText = TINYTEXT +MSText = TEXT +MSYear = YEAR +MSTimeStamp = TIMESTAMP +MSTime = TIME +MSBit = BIT +MSSmallInteger = SMALLINT +MSTinyInteger = TINYINT +MSMediumInteger = MEDIUMINT +MSBigInteger = BIGINT +MSNumeric = NUMERIC +MSDecimal = DECIMAL +MSDouble = DOUBLE +MSReal = REAL +MSFloat = FLOAT +MSInteger = INTEGER + colspecs = { - sqltypes.Integer: MSInteger, - sqltypes.SmallInteger: MSSmallInteger, - sqltypes.Numeric: MSNumeric, - sqltypes.Float: MSFloat, - sqltypes.DateTime: MSDateTime, - sqltypes.Date: MSDate, - sqltypes.Time: MSTime, - sqltypes.String: MSString, - sqltypes.Binary: MSBlob, - sqltypes.Boolean: MSBoolean, - sqltypes.Text: MSText, - sqltypes.CHAR: MSChar, - sqltypes.NCHAR: MSNChar, - sqltypes.TIMESTAMP: MSTimeStamp, - sqltypes.BLOB: MSBlob, - MSDouble: MSDouble, - MSReal: MSReal, - _BinaryType: _BinaryType, + sqltypes.Numeric: NUMERIC, + sqltypes.Float: FLOAT, + sqltypes.Binary: _BinaryType, + sqltypes.Boolean: BOOLEAN, + sqltypes.Time: TIME, } # Everything 3.23 through 5.1 excepting OpenGIS types. ischema_names = { - 'bigint': MSBigInteger, - 'binary': MSBinary, - 'bit': MSBit, - 'blob': MSBlob, - 'boolean':MSBoolean, - 'char': MSChar, - 'date': MSDate, - 'datetime': MSDateTime, - 'decimal': MSDecimal, - 'double': MSDouble, - 'enum': MSEnum, - 'fixed': MSDecimal, - 'float': MSFloat, - 'int': MSInteger, - 'integer': MSInteger, - 'longblob': MSLongBlob, - 'longtext': MSLongText, - 'mediumblob': MSMediumBlob, - 'mediumint': MSMediumInteger, - 'mediumtext': MSMediumText, - 'nchar': MSNChar, - 'nvarchar': MSNVarChar, - 'numeric': MSNumeric, - 'set': MSSet, - 'smallint': MSSmallInteger, - 'text': MSText, - 'time': MSTime, - 'timestamp': MSTimeStamp, - 'tinyblob': MSTinyBlob, - 'tinyint': MSTinyInteger, - 'tinytext': MSTinyText, - 'varbinary': MSVarBinary, - 'varchar': MSString, - 'year': MSYear, + 'bigint': BIGINT, + 'binary': BINARY, + 'bit': BIT, + 'blob': BLOB, + 'boolean':BOOLEAN, + 'char': CHAR, + 'date': DATE, + 'datetime': DATETIME, + 'decimal': DECIMAL, + 'double': DOUBLE, + 'enum': ENUM, + 'fixed': DECIMAL, + 'float': FLOAT, + 'int': INTEGER, + 'integer': INTEGER, + 'longblob': LONGBLOB, + 'longtext': LONGTEXT, + 'mediumblob': MEDIUMBLOB, + 'mediumint': MEDIUMINT, + 'mediumtext': MEDIUMTEXT, + 'nchar': NCHAR, + 'nvarchar': NVARCHAR, + 'numeric': NUMERIC, + 'set': SET, + 'smallint': SMALLINT, + 'text': TEXT, + 'time': TIME, + 'timestamp': TIMESTAMP, + 'tinyblob': TINYBLOB, + 'tinyint': TINYINT, + 'tinytext': TINYTEXT, + 'varbinary': VARBINARY, + 'varchar': VARCHAR, + 'year': YEAR, } class MySQLExecutionContext(default.DefaultExecutionContext): @@ -1305,29 +1237,27 @@ class MySQLCompiler(compiler.SQLCompiler): def visit_typeclause(self, typeclause): type_ = typeclause.type.dialect_impl(self.dialect) - if isinstance(type_, MSInteger): + if isinstance(type_, sqltypes.Integer): if getattr(type_, 'unsigned', False): return 'UNSIGNED INTEGER' else: return 'SIGNED INTEGER' - elif isinstance(type_, (MSDecimal, MSDateTime, MSDate, MSTime)): + elif isinstance(type_, sqltypes.TIMESTAMP): + return 'DATETIME' + elif isinstance(type_, (sqltypes.DECIMAL, sqltypes.DateTime, sqltypes.Date, sqltypes.Time)): return self.dialect.type_compiler.process(type_) - elif isinstance(type_, MSText): + elif isinstance(type_, sqltypes.Text): return 'CHAR' - elif (isinstance(type_, _StringType) and not - isinstance(type_, (MSEnum, MSSet))): + elif (isinstance(type_, sqltypes.String) and not + isinstance(type_, (ENUM, SET))): if getattr(type_, 'length'): return 'CHAR(%s)' % type_.length else: return 'CHAR' - elif isinstance(type_, _BinaryType): + elif isinstance(type_, sqltypes.Binary): return 'BINARY' - elif isinstance(type_, MSNumeric): + elif isinstance(type_, NUMERIC): return self.dialect.type_compiler.process(type_).replace('NUMERIC', 'DECIMAL') - elif isinstance(type_, MSTimeStamp): - return 'DATETIME' - elif isinstance(type_, (MSDateTime, MSDate, MSTime)): - return self.dialect.type_compiler.process(type_) else: return None @@ -1890,13 +1820,11 @@ class MySQLDialect(default.DefaultDialect): @reflection.cache def get_columns(self, connection, table_name, schema=None, **kw): - parsed_state = self._parsed_state_or_create(connection, table_name, schema, **kw) return parsed_state.columns @reflection.cache def get_primary_keys(self, connection, table_name, schema=None, **kw): - parsed_state = self._parsed_state_or_create(connection, table_name, schema, **kw) for key in parsed_state.keys: if key['type'] == 'PRIMARY': @@ -1910,7 +1838,7 @@ class MySQLDialect(default.DefaultDialect): parsed_state = self._parsed_state_or_create(connection, table_name, schema, **kw) default_schema = None - + fkeys = [] for spec in parsed_state.constraints: @@ -1982,13 +1910,15 @@ class MySQLDialect(default.DefaultDialect): return sql def _parsed_state_or_create(self, connection, table_name, schema=None, **kw): - if 'parsed_state' in kw: - return kw['parsed_state'] - else: - return self._setup_parser(connection, table_name, schema) + return self._setup_parser( + connection, + table_name, + schema, + info_cache=kw.get('info_cache', None) + ) - def _setup_parser(self, connection, table_name, schema=None): - + @reflection.cache + def _setup_parser(self, connection, table_name, schema=None, **kw): charset = self._connection_charset try: parser = self.parser diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py index dff0f52fac..36ee65be1d 100644 --- a/lib/sqlalchemy/dialects/oracle/base.py +++ b/lib/sqlalchemy/dialects/oracle/base.py @@ -117,12 +117,33 @@ from sqlalchemy.engine import default, base, reflection from sqlalchemy.sql import compiler, visitors, expression from sqlalchemy.sql import operators as sql_operators, functions as sql_functions from sqlalchemy import types as sqltypes - +from sqlalchemy.types import VARCHAR, NVARCHAR, CHAR, DATE, DATETIME, \ + BLOB, CLOB, TIMESTAMP, FLOAT + RESERVED_WORDS = set('''SHARE RAW DROP BETWEEN FROM DESC OPTION PRIOR LONG THEN DEFAULT ALTER IS INTO MINUS INTEGER NUMBER GRANT IDENTIFIED ALL TO ORDER ON FLOAT DATE HAVING CLUSTER NOWAIT RESOURCE ANY TABLE INDEX FOR UPDATE WHERE CHECK SMALLINT WITH DELETE BY ASC REVOKE LIKE SIZE RENAME NOCOMPRESS NULL GROUP VALUES AS IN VIEW EXCLUSIVE COMPRESS SYNONYM SELECT INSERT EXISTS NOT TRIGGER ELSE CREATE INTERSECT PCTFREE DISTINCT CONNECT SET MODE OF UNIQUE VARCHAR2 VARCHAR LOCK OR CHAR DECIMAL UNION PUBLIC AND START UID COMMENT'''.split()) -class OracleRaw(sqltypes.Binary): +class RAW(sqltypes.Binary): pass +OracleRaw = RAW + +class NCLOB(sqltypes.Text): + __visit_name__ = 'NCLOB' + +VARCHAR2 = VARCHAR +NVARCHAR2 = NVARCHAR +class NUMBER(sqltypes.Numeric): + __visit_name__ = 'NUMBER' + +class BFILE(sqltypes.Binary): + __visit_name__ = 'BFILE' + +class DOUBLE_PRECISION(sqltypes.Numeric): + __visit_name__ = 'DOUBLE_PRECISION' + +class LONG(sqltypes.Text): + __visit_name__ = 'LONG' + class OracleBoolean(sqltypes.Boolean): def result_processor(self, dialect): def process(value): @@ -148,20 +169,20 @@ colspecs = { } ischema_names = { - 'VARCHAR2' : sqltypes.VARCHAR, - 'NVARCHAR2' : sqltypes.NVARCHAR, - 'CHAR' : sqltypes.CHAR, - 'DATE' : sqltypes.DATE, - 'DATETIME' : sqltypes.DATETIME, - 'NUMBER' : sqltypes.Numeric, - 'BLOB' : sqltypes.BLOB, - 'BFILE' : sqltypes.Binary, - 'CLOB' : sqltypes.CLOB, - 'TIMESTAMP' : sqltypes.TIMESTAMP, - 'RAW' : OracleRaw, - 'FLOAT' : sqltypes.Float, - 'DOUBLE PRECISION' : sqltypes.Numeric, - 'LONG' : sqltypes.Text, + 'VARCHAR2' : VARCHAR, + 'NVARCHAR2' : NVARCHAR, + 'CHAR' : CHAR, + 'DATE' : DATE, + 'DATETIME' : DATETIME, + 'NUMBER' : NUMBER, + 'BLOB' : BLOB, + 'BFILE' : BFILE, + 'CLOB' : CLOB, + 'TIMESTAMP' : TIMESTAMP, + 'RAW' : RAW, + 'FLOAT' : FLOAT, + 'DOUBLE PRECISION' : DOUBLE_PRECISION, + 'LONG' : LONG, } diff --git a/lib/sqlalchemy/dialects/sybase/base.py b/lib/sqlalchemy/dialects/sybase/base.py index 0612e8c382..3c90ca0087 100644 --- a/lib/sqlalchemy/dialects/sybase/base.py +++ b/lib/sqlalchemy/dialects/sybase/base.py @@ -35,12 +35,6 @@ from sqlalchemy import MetaData, Table, Column from sqlalchemy import String, Integer, SMALLINT, CHAR, ForeignKey from sqlalchemy.dialects.sybase.schema import * -__all__ = [ - 'SybaseMoney', 'SybaseSmallMoney', - 'SybaseUniqueIdentifier', - ] - - RESERVED_WORDS = set([ "add", "all", "alter", "and", "any", "as", "asc", "backup", diff --git a/lib/sqlalchemy/dialects/type_migration_guidelines.txt b/lib/sqlalchemy/dialects/type_migration_guidelines.txt index 63a1115d58..335311234f 100644 --- a/lib/sqlalchemy/dialects/type_migration_guidelines.txt +++ b/lib/sqlalchemy/dialects/type_migration_guidelines.txt @@ -31,6 +31,44 @@ type is specifying a type *or* arguments that are not present generically, it sh match the real name of the type on that backend, in uppercase. E.g. postgres.INET, mysql.ENUM, postgres.ARRAY. +Or follow this handy flowchart: + + is the type in types.py as an UPPERCASE type ? + | | + | yes ---> does your type need special behavior or arguments ? no ----> don't make a + | ^ yes type, make sure the dialect's + | no | base.py imports the types.py + | | | UPPERCASE name into its namespace + v is it v + no -------- a native yes -----> build new type + DB type? | + v + is this type native to the database ? + (i.e. BIT is native to MySQL, "Boolean" is *not* native to Oracle) + yes no + | | + v v + name the type THE SAME name the type using + as that of the DB, MixedCase, i.e. + using UPPERCASE OracleBoolean + (i.e. BIT, NCHAR, INTERVAL) | + | | + +----------------+----------------+ + | + v + the type should is the name of this type + subclass the <----- yes identical to an UPPERCASE name + UPPERCASE in types.py? + type in types.py no + (i.e. class BLOB(types.BLOB)) | + v + subclass the closest + MixedCase type types.py, + i.e. + class DATETIME2(types.DateTime), + class BIT(types.TypeEngine) + + Ideally one should be able to specify a schema using names imported completely from a dialect, all matching the real name on that backend: diff --git a/lib/sqlalchemy/engine/reflection.py b/lib/sqlalchemy/engine/reflection.py index bb1f501992..e4dd1ed489 100644 --- a/lib/sqlalchemy/engine/reflection.py +++ b/lib/sqlalchemy/engine/reflection.py @@ -27,10 +27,14 @@ from sqlalchemy import schema as sa_schema @util.decorator def cache(fn, self, con, *args, **kw): - info_cache = kw.pop('info_cache', None) + info_cache = kw.get('info_cache', None) if info_cache is None: return fn(self, con, *args, **kw) - key = (fn.__name__, args, str(kw)) + key = ( + fn.__name__, + tuple(a for a in args if isinstance(a, basestring)), + tuple((k, v) for k, v in kw.iteritems() if isinstance(v, basestring)) + ) ret = info_cache.get(key) if ret is None: ret = fn(self, con, *args, **kw) diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 6e2f22c9ff..965849df02 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -966,15 +966,6 @@ class CLOB(Text): __visit_name__ = 'CLOB' -class NCLOB(Text): - """The NCLOB type. - - TODO: is this only Oracle ? - """ - - __visit_name__ = 'NCLOB' - - class VARCHAR(String): """The SQL VARCHAR type.""" diff --git a/test/dialect/test_mysql.py b/test/dialect/test_mysql.py index 44cfe11f2c..fd70b79635 100644 --- a/test/dialect/test_mysql.py +++ b/test/dialect/test_mysql.py @@ -704,8 +704,8 @@ class TypesTest(TestBase, AssertsExecutionResults): ( mysql.MSSmallInteger(4), mysql.MSSmallInteger(4), ), ( mysql.MSMediumInteger(), mysql.MSMediumInteger(), ), ( mysql.MSMediumInteger(8), mysql.MSMediumInteger(8), ), - ( Binary(3), mysql.MSBlob(3), ), - ( Binary(), mysql.MSBlob() ), + ( Binary(3), mysql.TINYBLOB(), ), + ( Binary(), mysql.BLOB() ), ( mysql.MSBinary(3), mysql.MSBinary(3), ), ( mysql.MSVarBinary(3),), ( mysql.MSVarBinary(), mysql.MSBlob()), @@ -933,8 +933,8 @@ class SQLTest(TestBase, AssertsCompiledSQL): (DateTime, "CAST(t.col AS DATETIME)"), (Date, "CAST(t.col AS DATE)"), (Time, "CAST(t.col AS TIME)"), - (m.MSDateTime, "CAST(t.col AS DATETIME)"), - (m.MSDate, "CAST(t.col AS DATE)"), + (DateTime, "CAST(t.col AS DATETIME)"), + (Date, "CAST(t.col AS DATE)"), (m.MSTime, "CAST(t.col AS TIME)"), (m.MSTimeStamp, "CAST(t.col AS DATETIME)"), (m.MSYear, "t.col"), diff --git a/test/engine/test_reflection.py b/test/engine/test_reflection.py index 3d115b9a3d..06451bbc4d 100644 --- a/test/engine/test_reflection.py +++ b/test/engine/test_reflection.py @@ -64,13 +64,16 @@ class ReflectionTest(TestBase, ComparesTables): t1 = Table('t1', meta, Column('id', sa.Integer, primary_key=True), Column('t2id', sa.Integer, sa.ForeignKey('t2.id')), - Column('t3id', sa.Integer, sa.ForeignKey('t3.id')) + Column('t3id', sa.Integer, sa.ForeignKey('t3.id')), + test_needs_fk=True ) t2 = Table('t2', meta, - Column('id', sa.Integer, primary_key=True) + Column('id', sa.Integer, primary_key=True), + test_needs_fk=True ) t3 = Table('t3', meta, - Column('id', sa.Integer, primary_key=True) + Column('id', sa.Integer, primary_key=True), + test_needs_fk=True ) meta.create_all() try: diff --git a/test/sql/test_types.py b/test/sql/test_types.py index c3c331bed6..16a94110a8 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -38,17 +38,10 @@ class AdaptTest(TestBase): # TODO: migrate these tests to dialect modules - mysql_dialect = mysql.MySQLDialect() postgres_dialect = postgres.PGDialect() firebird_dialect = firebird.FBDialect() for dialect, start, test in [ - (mysql_dialect, String(), mysql.MSString), - (mysql_dialect, VARCHAR(), mysql.MSString), - (mysql_dialect, String(50), mysql.MSString), - (mysql_dialect, Unicode(), mysql.MSString), - (mysql_dialect, UnicodeText(), mysql.MSText), - (mysql_dialect, NCHAR(), mysql.MSNChar), (postgres_dialect, String(), String), (postgres_dialect, VARCHAR(), String), (postgres_dialect, String(50), String), -- 2.47.3