]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
continued strictness/documentation of the type system
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 8 Jul 2009 21:10:37 +0000 (21:10 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 8 Jul 2009 21:10:37 +0000 (21:10 +0000)
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/dialects/mysql/base.py
lib/sqlalchemy/dialects/oracle/base.py
lib/sqlalchemy/dialects/oracle/cx_oracle.py
lib/sqlalchemy/dialects/postgres/pg8000.py
lib/sqlalchemy/dialects/postgres/psycopg2.py
lib/sqlalchemy/dialects/sqlite/base.py
lib/sqlalchemy/dialects/type_migration_guidelines.txt
test/dialect/test_sqlite.py
test/sql/test_select.py
test/sql/test_types.py

index 8d695f988157f63efbcce9b6e7159543fa6f001c..2d8b31bcf2dff87ecd4a7ead81bafddc8e32d0f6 100644 (file)
@@ -229,7 +229,7 @@ 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
+                                FLOAT, TIMESTAMP, DATETIME, DATE
             
 
 from sqlalchemy.dialects.mssql import information_schema as ischema
@@ -270,7 +270,7 @@ RESERVED_WORDS = set(
     ])
 
 
-class MSNumeric(sqltypes.Numeric):
+class _MSNumeric(sqltypes.Numeric):
     def result_processor(self, dialect):
         if self.asdecimal:
             def process(value):
@@ -324,19 +324,17 @@ class REAL(sqltypes.Float):
 
     def __init__(self):
         super(REAL, self).__init__(precision=24)
-MSReal = REAL
 
 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
+# strings.  MSDate/TIME check for everything, and always
 # filter bind parameters into datetime objects (required by pyodbc,
 # not sure about other dialects).
 
-class DATE(sqltypes.DATE):
+class _MSDate(sqltypes.Date):
     def bind_processor(self, dialect):
         def process(value):
             if type(value) == datetime.date:
@@ -355,7 +353,6 @@ class DATE(sqltypes.DATE):
             else:
                 return value
         return process
-MSDate = DATE
 
 class TIME(sqltypes.TIME):
     def __init__(self, precision=None, **kwargs):
@@ -384,7 +381,6 @@ class TIME(sqltypes.TIME):
                 return value
         return process
 
-MSTime = TIME
 
 class _DateTimeBase(object):
     def bind_processor(self, dialect):
@@ -396,20 +392,17 @@ class _DateTimeBase(object):
                 return value
         return process
 
-class DATETIME(_DateTimeBase, sqltypes.DATETIME):
+class _MSDateTime(_DateTimeBase, sqltypes.DateTime):
     pass
-MSDateTime = DATETIME
 
 class SMALLDATETIME(_DateTimeBase, sqltypes.DateTime):
     __visit_name__ = 'SMALLDATETIME'
-MSSmallDateTime = SMALLDATETIME
 
 class DATETIME2(_DateTimeBase, sqltypes.DateTime):
     __visit_name__ = 'DATETIME2'
     
     def __init__(self, precision=None, **kwargs):
         self.precision = precision
-MSDateTime2 = DATETIME2
 
 
 # TODO: is this not an Interval ?
@@ -418,7 +411,6 @@ class DATETIMEOFFSET(sqltypes.TypeEngine):
     
     def __init__(self, precision=None, **kwargs):
         self.precision = precision
-MSDateTimeOffset = DATETIMEOFFSET
 
 
 class _StringType(object):
@@ -454,7 +446,6 @@ class TEXT(_StringType, sqltypes.TEXT):
         collation = kw.pop('collation', None)
         _StringType.__init__(self, collation)
         sqltypes.Text.__init__(self, *args, **kw)
-MSText = TEXT
 
 class NTEXT(_StringType, sqltypes.UnicodeText):
     """MSSQL NTEXT type, for variable-length unicode text up to 2^30
@@ -473,7 +464,6 @@ class NTEXT(_StringType, sqltypes.UnicodeText):
         _StringType.__init__(self, collation)
         length = kwargs.pop('length', None)
         sqltypes.UnicodeText.__init__(self, length, **kwargs)
-MSNText = NTEXT
 
 
 class VARCHAR(_StringType, sqltypes.VARCHAR):
@@ -514,7 +504,6 @@ class VARCHAR(_StringType, sqltypes.VARCHAR):
         collation = kw.pop('collation', None)
         _StringType.__init__(self, collation)
         sqltypes.VARCHAR.__init__(self, *args, **kw)
-MSString = VARCHAR
 
 class NVARCHAR(_StringType, sqltypes.NVARCHAR):
     """MSSQL NVARCHAR type.
@@ -533,7 +522,6 @@ class NVARCHAR(_StringType, sqltypes.NVARCHAR):
         collation = kw.pop('collation', None)
         _StringType.__init__(self, collation)
         sqltypes.NVARCHAR.__init__(self, *args, **kw)
-MSNVarchar = NVARCHAR
 
 class CHAR(_StringType, sqltypes.CHAR):
     """MSSQL CHAR type, for fixed-length non-Unicode data with a maximum
@@ -573,7 +561,6 @@ class CHAR(_StringType, sqltypes.CHAR):
         collation = kw.pop('collation', None)
         _StringType.__init__(self, collation)
         sqltypes.CHAR.__init__(self, *args, **kw)
-MSChar = CHAR
 
 class NCHAR(_StringType, sqltypes.NCHAR):
     """MSSQL NCHAR type.
@@ -592,25 +579,20 @@ class NCHAR(_StringType, sqltypes.NCHAR):
         collation = kw.pop('collation', None)
         _StringType.__init__(self, collation)
         sqltypes.NCHAR.__init__(self, *args, **kw)
-MSNChar = NCHAR
 
 class BINARY(sqltypes.Binary):
     __visit_name__ = 'BINARY'
-MSBinary = BINARY
 
 class VARBINARY(sqltypes.Binary):
     __visit_name__ = 'VARBINARY'
-MSVarBinary = VARBINARY
         
 class IMAGE(sqltypes.Binary):
     __visit_name__ = 'IMAGE'
-MSImage = IMAGE
 
 class BIT(sqltypes.TypeEngine):
     __visit_name__ = 'BIT'
-MSBit = BIT
     
-class MSBoolean(sqltypes.Boolean):
+class _MSBoolean(sqltypes.Boolean):
     def result_processor(self, dialect):
         def process(value):
             if value is None:
@@ -632,20 +614,83 @@ class MSBoolean(sqltypes.Boolean):
 
 class MONEY(sqltypes.TypeEngine):
     __visit_name__ = 'MONEY'
-MSMoney = MONEY
 
-class SMALLMONEY(MSMoney):
+class SMALLMONEY(sqltypes.TypeEngine):
     __visit_name__ = 'SMALLMONEY'
-MSSmallMoney = SMALLMONEY
 
 class UNIQUEIDENTIFIER(sqltypes.TypeEngine):
     __visit_name__ = "UNIQUEIDENTIFIER"
-MSUniqueIdentifier = UNIQUEIDENTIFIER
 
 class SQL_VARIANT(sqltypes.TypeEngine):
     __visit_name__ = 'SQL_VARIANT'
+
+# old names.
+MSNumeric = _MSNumeric
+MSDateTime = _MSDateTime
+MSDate = _MSDate
+MSBoolean = _MSBoolean
+MSReal = REAL
+MSTinyInteger = TINYINT
+MSTime = TIME
+MSSmallDateTime = SMALLDATETIME
+MSDateTime2 = DATETIME2
+MSDateTimeOffset = DATETIMEOFFSET
+MSText = TEXT
+MSNText = NTEXT
+MSString = VARCHAR
+MSNVarchar = NVARCHAR
+MSChar = CHAR
+MSNChar = NCHAR
+MSBinary = BINARY
+MSVarBinary = VARBINARY
+MSImage = IMAGE
+MSBit = BIT
+MSMoney = MONEY
+MSSmallMoney = SMALLMONEY
+MSUniqueIdentifier = UNIQUEIDENTIFIER
 MSVariant = SQL_VARIANT
 
+colspecs = {
+    sqltypes.Numeric : _MSNumeric,
+    sqltypes.DateTime : _MSDateTime,
+    sqltypes.Date : _MSDate,
+    sqltypes.Time : TIME,
+    sqltypes.Boolean : _MSBoolean,
+}
+
+ischema_names = {
+    '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 MSTypeCompiler(compiler.GenericTypeCompiler):
     def _extend(self, spec, type_):
         """Extend a string-type declaration with standard SQL
@@ -843,46 +888,6 @@ class MSExecutionContext(default.DefaultExecutionContext):
                 pass
 
 
-colspecs = {
-    sqltypes.Numeric : MSNumeric,
-    sqltypes.DateTime : DATETIME,
-    sqltypes.Date : DATE,
-    sqltypes.Time : TIME,
-    sqltypes.Boolean : MSBoolean,
-}
-
-ischema_names = {
-    '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):
 
     extract_map = compiler.SQLCompiler.extract_map.copy()
index 3ea033fb52f9bf7ae5a948c74ca4e6d1c67b3adf..0ebaeca0dc71ac72b3a6510b46b6268bafab09d6 100644 (file)
@@ -190,7 +190,7 @@ from sqlalchemy.engine import reflection
 from sqlalchemy.engine import base as engine_base, default
 from sqlalchemy import types as sqltypes
 
-from sqlalchemy.types import DATE, DATETIME
+from sqlalchemy.types import DATE, DATETIME, BOOLEAN, TIME
 
 RESERVED_WORDS = set(
     ['accessible', 'add', 'all', 'alter', 'analyze','and', 'as', 'asc',
@@ -580,7 +580,7 @@ class BIT(sqltypes.TypeEngine):
             return value
         return process
 
-class TIME(sqltypes.TIME):
+class _MSTime(sqltypes.Time):
     """MySQL TIME type."""
 
     __visit_name__ = 'TIME'
@@ -1094,7 +1094,7 @@ class SET(_StringType):
                 return value
         return process
 
-class BOOLEAN(sqltypes.Boolean):
+class _MSBoolean(sqltypes.Boolean):
     """MySQL BOOLEAN type."""
 
     __visit_name__ = 'BOOLEAN'
@@ -1119,7 +1119,8 @@ class BOOLEAN(sqltypes.Boolean):
         return process
 
 # old names
-MSBoolean = BOOLEAN
+MSBoolean = _MSBoolean
+MSTime = _MSTime
 MSSet = SET
 MSEnum = ENUM
 MSLongBlob = LONGBLOB
@@ -1138,7 +1139,6 @@ MSTinyText = TINYTEXT
 MSText = TEXT
 MSYear = YEAR
 MSTimeStamp = TIMESTAMP
-MSTime = TIME
 MSBit = BIT
 MSSmallInteger = SMALLINT
 MSTinyInteger = TINYINT
@@ -1155,8 +1155,8 @@ colspecs = {
     sqltypes.Numeric: NUMERIC,
     sqltypes.Float: FLOAT,
     sqltypes.Binary: _BinaryType,
-    sqltypes.Boolean: BOOLEAN,
-    sqltypes.Time: TIME,
+    sqltypes.Boolean: _MSBoolean,
+    sqltypes.Time: _MSTime,
 }
 
 # Everything 3.23 through 5.1 excepting OpenGIS types.
index 36ee65be1d22d8b101def5339cfdd2407f287765..3140a63d5b566358eb0fce95a3c79ace4838522a 100644 (file)
@@ -144,7 +144,7 @@ class DOUBLE_PRECISION(sqltypes.Numeric):
 class LONG(sqltypes.Text):
     __visit_name__ = 'LONG'
     
-class OracleBoolean(sqltypes.Boolean):
+class _OracleBoolean(sqltypes.Boolean):
     def result_processor(self, dialect):
         def process(value):
             if value is None:
@@ -165,7 +165,7 @@ class OracleBoolean(sqltypes.Boolean):
         return process
 
 colspecs = {
-    sqltypes.Boolean : OracleBoolean,
+    sqltypes.Boolean : _OracleBoolean,
 }
 
 ischema_names = {
index c83ee69dd5d617c8d3d1678dd0603eb946743360..6f46224dcbcb2fa4e35ea30a692f17754e1340c3 100644 (file)
@@ -63,13 +63,13 @@ working successfully but this should be regarded as an experimental feature.
 
 """
 
-from sqlalchemy.dialects.oracle.base import OracleDialect, OracleRaw, OracleBoolean, RESERVED_WORDS
+from sqlalchemy.dialects.oracle.base import OracleDialect, RAW, _OracleBoolean, RESERVED_WORDS
 from sqlalchemy.engine.default import DefaultExecutionContext
 from sqlalchemy.engine import base
 from sqlalchemy import types as sqltypes, util
 import datetime
 
-class OracleDate(sqltypes.Date):
+class _OracleDate(sqltypes.Date):
     def bind_processor(self, dialect):
         return None
 
@@ -81,7 +81,7 @@ class OracleDate(sqltypes.Date):
                 return value.date()
         return process
 
-class OracleDateTime(sqltypes.DateTime):
+class _OracleDateTime(sqltypes.DateTime):
     def result_processor(self, dialect):
         def process(value):
             if value is None or isinstance(value, datetime.datetime):
@@ -98,7 +98,7 @@ class OracleDateTime(sqltypes.DateTime):
 # Oracle does not support TIME columns
 
 # only if cx_oracle contains TIMESTAMP
-class OracleTimestamp(sqltypes.TIMESTAMP):
+class _OracleTimestamp(sqltypes.TIMESTAMP):
     def result_processor(self, dialect):
         def process(value):
             if value is None or isinstance(value, datetime.datetime):
@@ -109,9 +109,9 @@ class OracleTimestamp(sqltypes.TIMESTAMP):
                     value.day,value.hour, value.minute, value.second)
         return process
 
-class LOBMixin(object):
+class _LOBMixin(object):
     def result_processor(self, dialect):
-        super_process = super(LOBMixin, self).result_processor(dialect)
+        super_process = super(_LOBMixin, self).result_processor(dialect)
         if not dialect.auto_convert_lobs:
             return super_process
         lob = dialect.dbapi.LOB
@@ -128,16 +128,16 @@ class LOBMixin(object):
                     return value
         return process
     
-class OracleText(LOBMixin, sqltypes.Text):
+class _OracleText(_LOBMixin, sqltypes.Text):
     def get_dbapi_type(self, dbapi):
         return dbapi.CLOB
 
-class OracleUnicodeText(LOBMixin, sqltypes.UnicodeText):
+class _OracleUnicodeText(_LOBMixin, sqltypes.UnicodeText):
     def get_dbapi_type(self, dbapi):
         return dbapi.NCLOB
 
 
-class OracleBinary(LOBMixin, sqltypes.Binary):
+class _OracleBinary(_LOBMixin, sqltypes.Binary):
     def get_dbapi_type(self, dbapi):
         return dbapi.BLOB
 
@@ -145,19 +145,19 @@ class OracleBinary(LOBMixin, sqltypes.Binary):
         return None
 
 
-class cxOracleRaw(LOBMixin, OracleRaw):
+class _OracleRaw(_LOBMixin, RAW):
     pass
 
 
 colspecs = {
-    sqltypes.DateTime : OracleDateTime,
-    sqltypes.Date : OracleDate,
-    sqltypes.Binary : OracleBinary,
-    sqltypes.Boolean : OracleBoolean,
-    sqltypes.Text : OracleText,
-    sqltypes.UnicodeText : OracleUnicodeText,
-    sqltypes.TIMESTAMP : OracleTimestamp,
-    OracleRaw: cxOracleRaw,
+    sqltypes.DateTime : _OracleDateTime,
+    sqltypes.Date : _OracleDate,
+    sqltypes.Binary : _OracleBinary,
+    sqltypes.Boolean : _OracleBoolean,
+    sqltypes.Text : _OracleText,
+    sqltypes.UnicodeText : _OracleUnicodeText,
+    sqltypes.TIMESTAMP : _OracleTimestamp,
+    RAW: _OracleRaw,
 }
 
 class Oracle_cx_oracleExecutionContext(DefaultExecutionContext):
index d42fd937c929c1c81eb0acc860d845d7e3408e2a..0dd166a9d8a8460b20cd3cfad654cf5763782f6e 100644 (file)
@@ -24,7 +24,7 @@ from sqlalchemy import util
 from sqlalchemy import types as sqltypes
 from sqlalchemy.dialects.postgres.base import PGDialect, PGCompiler
 
-class PGNumeric(sqltypes.Numeric):
+class _PGNumeric(sqltypes.Numeric):
     def bind_processor(self, dialect):
         return None
 
@@ -62,8 +62,8 @@ class Postgres_pg8000(PGDialect):
     colspecs = util.update_copy(
         PGDialect.colspecs,
         {
-            sqltypes.Numeric : PGNumeric,
-            sqltypes.Float: sqltypes.Float,  # prevents PGNumeric from being used
+            sqltypes.Numeric : _PGNumeric,
+            sqltypes.Float: sqltypes.Float,  # prevents _PGNumeric from being used
         }
     )
     
index a3ffdd84bf68ccdde4187430cce1575a2b4944aa..9f5ea5686856394bcc15ffb3ce6f1c5277952780 100644 (file)
@@ -44,7 +44,7 @@ from sqlalchemy.sql import operators as sql_operators
 from sqlalchemy import types as sqltypes
 from sqlalchemy.dialects.postgres.base import PGDialect, PGCompiler
 
-class PGNumeric(sqltypes.Numeric):
+class _PGNumeric(sqltypes.Numeric):
     def bind_processor(self, dialect):
         return None
 
@@ -111,8 +111,8 @@ class Postgres_psycopg2(PGDialect):
     colspecs = util.update_copy(
         PGDialect.colspecs,
         {
-            sqltypes.Numeric : PGNumeric,
-            sqltypes.Float: sqltypes.Float,  # prevents PGNumeric from being used
+            sqltypes.Numeric : _PGNumeric,
+            sqltypes.Float: sqltypes.Float,  # prevents _PGNumeric from being used
         }
     )
 
index 40c140569a029416a2e13ac3a31bcba3e4359de0..1b260aa6864f4899a4d746c18f6b54ff65b03438 100644 (file)
@@ -15,7 +15,7 @@ SQLite does not have built-in DATE, TIME, or DATETIME types, and pysqlite does n
 out of the box functionality for translating values between Python `datetime` objects
 and a SQLite-supported format.  SQLAlchemy's own :class:`~sqlalchemy.types.DateTime`
 and related types provide date formatting and parsing functionality when SQlite is used.
-The implementation classes are :class:`SLDateTime`, :class:`SLDate` and :class:`SLTime`.
+The implementation classes are :class:`_SLDateTime`, :class:`_SLDate` and :class:`_SLTime`.
 These types represent dates and times as ISO formatted strings, which also nicely
 support ordering.   There's no reliance on typical "libc" internals for these functions
 so historical dates are fully supported.
@@ -34,7 +34,12 @@ from sqlalchemy import util
 from sqlalchemy.sql import compiler, functions as sql_functions
 from sqlalchemy.util import NoneType
 
-class NumericMixin(object):
+from sqlalchemy.types import BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL,\
+                            FLOAT, INTEGER, NUMERIC, SMALLINT, TEXT, TIME,\
+                            TIMESTAMP, VARCHAR
+                            
+
+class _NumericMixin(object):
     def bind_processor(self, dialect):
         type_ = self.asdecimal and str or float
         def process(value):
@@ -44,16 +49,16 @@ class NumericMixin(object):
                 return value
         return process
 
-class SLNumeric(NumericMixin, sqltypes.Numeric):
+class _SLNumeric(_NumericMixin, sqltypes.Numeric):
     pass
 
-class SLFloat(NumericMixin, sqltypes.Float):
+class _SLFloat(_NumericMixin, sqltypes.Float):
     pass
 
 # since SQLite has no date types, we're assuming that SQLite via ODBC
 # or JDBC would similarly have no built in date support, so the "string" based logic
 # would apply to all implementing dialects.
-class DateTimeMixin(object):
+class _DateTimeMixin(object):
     def _bind_processor(self, format, elements):
         def process(value):
             if not isinstance(value, (NoneType, datetime.date, datetime.datetime, datetime.time)):
@@ -72,7 +77,7 @@ class DateTimeMixin(object):
                 return None
         return process
 
-class SLDateTime(DateTimeMixin, sqltypes.DateTime):
+class _SLDateTime(_DateTimeMixin, sqltypes.DateTime):
     __legacy_microseconds__ = False
 
     def bind_processor(self, dialect):
@@ -91,7 +96,7 @@ class SLDateTime(DateTimeMixin, sqltypes.DateTime):
     def result_processor(self, dialect):
         return self._result_processor(datetime.datetime, self._reg)
 
-class SLDate(DateTimeMixin, sqltypes.Date):
+class _SLDate(_DateTimeMixin, sqltypes.Date):
     def bind_processor(self, dialect):
         return self._bind_processor(
                         "%4.4d-%2.2d-%2.2d", 
@@ -102,7 +107,7 @@ class SLDate(DateTimeMixin, sqltypes.Date):
     def result_processor(self, dialect):
         return self._result_processor(datetime.date, self._reg)
 
-class SLTime(DateTimeMixin, sqltypes.Time):
+class _SLTime(_DateTimeMixin, sqltypes.Time):
     __legacy_microseconds__ = False
 
     def bind_processor(self, dialect):
@@ -122,7 +127,7 @@ class SLTime(DateTimeMixin, sqltypes.Time):
         return self._result_processor(datetime.time, self._reg)
 
 
-class SLBoolean(sqltypes.Boolean):
+class _SLBoolean(sqltypes.Boolean):
     def bind_processor(self, dialect):
         def process(value):
             if value is None:
@@ -138,12 +143,12 @@ class SLBoolean(sqltypes.Boolean):
         return process
 
 colspecs = {
-    sqltypes.Boolean: SLBoolean,
-    sqltypes.Date: SLDate,
-    sqltypes.DateTime: SLDateTime,
-    sqltypes.Float: SLFloat,
-    sqltypes.Numeric: SLNumeric,
-    sqltypes.Time: SLTime,
+    sqltypes.Boolean: _SLBoolean,
+    sqltypes.Date: _SLDate,
+    sqltypes.DateTime: _SLDateTime,
+    sqltypes.Float: _SLFloat,
+    sqltypes.Numeric: _SLNumeric,
+    sqltypes.Time: _SLTime,
 }
 
 ischema_names = {
index 335311234f9e292033e40d10c49963d19c705574..3ee439dd87ed18d638f8d5359cec02f31cefac5c 100644 (file)
@@ -16,58 +16,78 @@ Rules for Migrating TypeEngine classes to 0.6
     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:
+2. the TypeEngine classes are *no longer* used for generating DDL.  Dialects
+now have a TypeCompiler subclass which uses the same visit_XXX model as
+other compilers.   
 
-    a. generating DDL
-    
 3. the "ischema_names" and "colspecs" dictionaries are now required members on
 the Dialect class.
 
 4. The names of types within dialects are now important.   If a dialect-specific type
 is a subclass of an existing generic type and is only provided for bind/result behavior, 
-the current mixed case naming can remain, i.e. PGNumeric for Numeric - in this case, 
-end users would never need to use PGNumeric directly.   However, if a dialect-specific 
+the current mixed case naming can remain, i.e. _PGNumeric for Numeric - in this case, 
+end users would never need to use _PGNumeric directly.   However, if a dialect-specific 
 type is specifying a type *or* arguments that are not present generically, it should
 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)                                                          
+    is the type meant to provide bind/result                  is the type the same name as an
+    behavior to a generic type (i.e. MixedCase)  ---- no ---> UPPERCASE type in types.py ?
+    type in types.py ?                                          |                     |
+                    |                                           no                    yes
+                   yes                                          |                     |
+                    |                                           |             does your type need special
+                    |                                           +<--- yes --- behavior or arguments ?
+                    |                                           |                               |
+                    |                                           |                              no
+           name the type using                                  |                               |
+           _MixedCase, i.e.                                     v                               V
+           _OracleBoolean. it                          name the type                        don't make a
+           stays private to the dialect                identically as that                  type, make sure the dialect's
+           and is invoked *only* via                   within the DB,                       base.py imports the types.py
+           the colspecs dict.                          using UPPERCASE                      UPPERCASE name into its namespace
+                    |                                  (i.e. BIT, NCHAR, INTERVAL).
+                    |                                  Users can import it.
+                    |                                       |
+                    v                                       v
+           subclass the closest                        is the name of this type
+           MixedCase type types.py,                    identical to an UPPERCASE
+           i.e.                        <--- no ------- name in types.py ?
+           class _DateTime(types.DateTime),
+           class DATETIME2(types.DateTime),                   |
+           class BIT(types.TypeEngine).                      yes
+                                                              |
+                                                              v
+                                                        the type should
+                                                        subclass the   
+                                                        UPPERCASE      
+                                                        type in types.py
+                                                        (i.e. class BLOB(types.BLOB))
+
+
+Example 1.   pysqlite needs bind/result processing for the DateTime type in types.py, 
+which applies to all DateTimes and subclasses.   It's named _SLDateTime and 
+subclasses types.DateTime.
+
+Example 2.  MS-SQL has a TIME type which takes a non-standard "precision" argument
+that is rendered within DDL.   So it's named TIME in the MS-SQL dialect's base.py, 
+and subclasses types.TIME.  Users can then say mssql.TIME(precision=10).
 
+Example 3.  MS-SQL dialects also need special bind/result processing for date 
+But its DATE type doesn't render DDL differently than that of a plain 
+DATE, i.e. it takes no special arguments.  Therefore we are just adding behavior
+to types.Date, so it's named _MSDate in the MS-SQL dialect's base.py, and subclasses
+types.Date.
+
+Example 4.  MySQL has a SET type, there's no analogue for this in types.py. So
+MySQL names it SET in the dialect's base.py, and it subclasses types.String, since 
+it ultimately deals with strings.
+
+Example 5.  Postgresql has a DATETIME type.  The DBAPIs handle dates correctly,
+and no special arguments are used in PG's DDL beyond what types.py provides.  
+Postgresql dialect therefore imports types.DATETIME into its base.py.
 
 Ideally one should be able to specify a schema using names imported completely from a 
 dialect, all matching the real name on that backend:
@@ -95,20 +115,14 @@ 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.   *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.
+    own subclass of that type with special bind/result behavior - reflect to the types.py
+    UPPERCASE type as much as possible.   With very few exceptions, all types
+    should reflect to an UPPERCASE type.
     
     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.VARCHAR takes a "collation" parameter which should be preserved.
     
-    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"
-    
-    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
 a subclass of compiler.GenericTypeCompiler.
 
@@ -118,8 +132,8 @@ a subclass of compiler.GenericTypeCompiler.
     
     b. the visit_UPPERCASE methods on GenericTypeCompiler should *not* be overridden with
     methods that produce a different DDL name.   Uppercase types don't do any kind of 
-    "guessing" - if the user says he wants TIMESTAMP, that's the DDL which should render, 
-    regardless of whether the DB accepts it.
+    "guessing" - if visit_TIMESTAMP is called, the DDL should render as TIMESTAMP in
+    all cases, regardless of whether or not that type is legal on the backend database.
     
     c. the visit_UPPERCASE methods *should* be overridden with methods that add additional
     arguments and flags to those types.  
@@ -127,6 +141,5 @@ a subclass of compiler.GenericTypeCompiler.
     d. the visit_lowercase methods are overridden to provide an interpretation of a generic 
     type.  E.g.  visit_binary() might be overridden to say "return self.visit_BIT(type_)".
     
-    e. when overriding a visit_lowercase method to return a different type, it should not
-    represent the DDL string within the body of the method; it should call the appropriate
-    visit_UPPERCASE name.
+    e. visit_lowercase methods should *never* render strings directly - it should always
+    be via calling a visit_UPPERCASE() method.
index 32f8a9e0722a90d371a2bf1cb3fa75ee98aebf89..e93428eb6e93085f8ebb77569efb9ab511962447 100644 (file)
@@ -19,7 +19,7 @@ class TestTypes(TestBase, AssertsExecutionResults):
         meta = MetaData(testing.db)
         t = Table('bool_table', meta,
                   Column('id', Integer, primary_key=True),
-                  Column('boo', sqlite.SLBoolean))
+                  Column('boo', Boolean))
 
         try:
             meta.create_all()
@@ -39,7 +39,7 @@ class TestTypes(TestBase, AssertsExecutionResults):
     def test_time_microseconds(self):
         dt = datetime.datetime(2008, 6, 27, 12, 0, 0, 125)  # 125 usec
         eq_(str(dt), '2008-06-27 12:00:00.000125')
-        sldt = sqlite.SLDateTime()
+        sldt = sqlite._SLDateTime()
         bp = sldt.bind_processor(None)
         eq_(bp(dt), '2008-06-27 12:00:00.000125')
         
index 02632025c03a12249999b89c419265b61976cd3f..8aa62a288b624a487cc925c65d527dd8d6cc89dd 100644 (file)
@@ -1370,7 +1370,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)', 'CAST(mytable.name AS NUMERIC)', 'anon_1'),
+            (cast(table1.c.name, Numeric), '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"', '')
         ):
index 16a94110a88ffff1671d106a16fa0dc9d7ef274d..821a386ffeccd3c462bff085dfdda73b36248b83 100644 (file)
@@ -13,50 +13,6 @@ from sqlalchemy.test import *
 
 
 class AdaptTest(TestBase):
-    def testmsnvarchar(self):
-        # TODO: migrate these tests to dialect modules
-
-        dialect = mssql.dialect()
-        # run the test twice to ensure the caching step works too
-        for x in range(0, 1):
-            col = Column('', Unicode(length=10))
-            dialect_type = col.type.dialect_impl(dialect)
-            assert isinstance(dialect_type, mssql.MSNVarchar)
-            eq_(dialect.type_compiler.process(dialect_type), 'NVARCHAR(10)')
-
-    def testmysqlbinary(self):
-        # TODO: migrate these tests to dialect modules
-
-        dialect = mysql.MySQLDialect()
-        t1 = mysql.MSVarBinary
-        t2 = mysql.MSVarBinary()
-        assert isinstance(dialect.type_descriptor(t1), mysql.MSVarBinary)
-        assert isinstance(dialect.type_descriptor(t2), mysql.MSVarBinary)
-
-    def teststringadapt(self):
-        """test that String with no size becomes TEXT, *all* others stay as varchar/String"""
-        
-        # TODO: migrate these tests to dialect modules
-        
-        postgres_dialect = postgres.PGDialect()
-        firebird_dialect = firebird.FBDialect()
-
-        for dialect, start, test in [
-            (postgres_dialect, String(), String),
-            (postgres_dialect, VARCHAR(), String),
-            (postgres_dialect, String(50), String),
-            (postgres_dialect, Unicode(), String),
-            (postgres_dialect, UnicodeText(), Text),
-            (postgres_dialect, NCHAR(), String),
-#            (firebird_dialect, String(), firebird.FBString),
-#            (firebird_dialect, VARCHAR(), firebird.FBString),
-#            (firebird_dialect, String(50), firebird.FBString),
-#            (firebird_dialect, Unicode(), firebird.FBString),
-#            (firebird_dialect, UnicodeText(), firebird.FBText),
-#            (firebird_dialect, NCHAR(), firebird.FBString),
-        ]:
-            assert isinstance(start.dialect_impl(dialect), test), "wanted %r got %r" % (test, start.dialect_impl(dialect))
-
     def test_uppercase_rendering(self):
         """Test that uppercase types from types.py always render as their type.