]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- The assert_unicode flag is deprecated. SQLAlchemy will raise
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 25 Feb 2010 22:00:58 +0000 (22:00 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 25 Feb 2010 22:00:58 +0000 (22:00 +0000)
a warning in all cases where it is asked to encode a non-unicode
Python string, and will do nothing for DBAPIs that already
accept Python unicode objects.

CHANGES
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/engine/__init__.py
lib/sqlalchemy/engine/default.py
lib/sqlalchemy/types.py
test/dialect/test_postgresql.py
test/dialect/test_sqlite.py
test/sql/test_types.py

diff --git a/CHANGES b/CHANGES
index ab0c14fffab44fcffbdf3a07a67e2f34bcc4a5ce..7c33f623986f6b23204c0350e8dcb3c11bdb666e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -181,6 +181,11 @@ CHANGES
     Note that it is *not* built/installed by default.
     See README for installation instructions.
 
+  - The assert_unicode flag is deprecated.  SQLAlchemy will raise
+    a warning in all cases where it is asked to encode a non-unicode
+    Python string, and will do nothing for DBAPIs that already 
+    accept Python unicode objects.
+    
 - metadata
   - Added the ability to strip schema information when using
     "tometadata" by passing "schema=None" as an argument. If schema
index facb16490a0fe8fa164e84fa1384aad9cec88180..1ce3cbde8c0bdeee596314ff182ceeffe6df4b11 100644 (file)
@@ -489,16 +489,6 @@ class VARCHAR(_StringType, sqltypes.VARCHAR):
           If False, may be overridden by
           :attr:`sqlalchemy.engine.base.Dialect.convert_unicode`.
 
-        :param assert_unicode:
-
-          If None (the default), no assertion will take place unless
-          overridden by :attr:`sqlalchemy.engine.base.Dialect.assert_unicode`.
-
-          If 'warn', will issue a runtime warning if a ``str``
-          instance is used as a bind value.
-
-          If true, will raise an :exc:`sqlalchemy.exc.InvalidRequestError`.
-
         :param collation: Optional, a column-level collation for this string
           value. Accepts a Windows Collation Name or a SQL Collation Name.
 
@@ -546,16 +536,6 @@ class CHAR(_StringType, sqltypes.CHAR):
           If False, may be overridden by
           :attr:`sqlalchemy.engine.base.Dialect.convert_unicode`.
 
-        :param assert_unicode:
-
-          If None (the default), no assertion will take place unless
-          overridden by :attr:`sqlalchemy.engine.base.Dialect.assert_unicode`.
-
-          If 'warn', will issue a runtime warning if a ``str``
-          instance is used as a bind value.
-
-          If true, will raise an :exc:`sqlalchemy.exc.InvalidRequestError`.
-
         :param collation: Optional, a column-level collation for this string
           value. Accepts a Windows Collation Name or a SQL Collation Name.
 
index d04907db8267b941b5b0c2e3a6d247c2e7623bc1..137218c2c087bccbd31a5d9e50d20a6eabbd9f12 100644 (file)
@@ -119,12 +119,12 @@ def create_engine(*args, **kwargs):
     are unique to that dialect.   Here, we describe the parameters
     that are common to most ``create_engine()`` usage.
     
-    :param assert_unicode=False: When set to ``True`` alongside
-        convert_unicode=``True``, asserts that incoming string bind
-        parameters are instances of ``unicode``, otherwise raises an
-        error. Only takes effect when ``convert_unicode==True``. This
-        flag is also available on the ``String`` type and its
-        descendants. New in 0.4.2.
+    :param assert_unicode:  Deprecated.  A warning is raised in all cases when a non-Unicode
+      object is passed when SQLAlchemy would coerce into an encoding
+      (note: but **not** when the DBAPI handles unicode objects natively).
+      To suppress or raise this warning to an 
+      error, use the Python warnings filter documented at:
+      http://docs.python.org/library/warnings.html
 
     :param connect_args: a dictionary of options which will be
         passed directly to the DBAPI's ``connect()`` method as
index 44c9689423c8c1a21c4204b583a46cf4ad696587..5499b34e75b1caeb000d02ed60b82ec4876e45dc 100644 (file)
@@ -78,7 +78,14 @@ class DefaultDialect(base.Dialect):
                 "The %s dialect is not yet ported to SQLAlchemy 0.6" % self.name)
         
         self.convert_unicode = convert_unicode
-        self.assert_unicode = assert_unicode
+        if assert_unicode:
+            util.warn_deprecated("assert_unicode is deprecated. "
+                                "SQLAlchemy emits a warning in all cases where it "
+                                "would otherwise like to encode a Python unicode object "
+                                "into a specific encoding but a plain bytestring is received. "
+                                "This does *not* apply to DBAPIs that coerce Unicode natively."
+                                )
+            
         self.encoding = encoding
         self.positional = False
         self._ischema = None
index 49ee3dbf334efe4bbb1f1ff94c8a8e27cdab80c3..aed17e67e4e68957461e399d3ea0b02ad1f5b7ec 100644 (file)
@@ -500,7 +500,8 @@ class String(Concatenable, TypeEngine):
 
     __visit_name__ = 'string'
 
-    def __init__(self, length=None, convert_unicode=False, assert_unicode=None, unicode_error=None):
+    def __init__(self, length=None, convert_unicode=False, 
+                        assert_unicode=None, unicode_error=None):
         """
         Create a string-holding type.
 
@@ -511,42 +512,36 @@ class String(Concatenable, TypeEngine):
           the ``CREATE TABLE`` DDL is issued.  Whether the value is
           interpreted as bytes or characters is database specific.
 
-        :param convert_unicode: defaults to False.  If True, convert
-          ``unicode`` data sent to the database to a ``str``
-          bytestring, and convert bytestrings coming back from the
-          database into ``unicode``.   
-
-          Bytestrings are encoded using the dialect's
+        :param convert_unicode: defaults to False.  If True, the 
+          type will do what is necessary in order to accept 
+          Python Unicode objects as bind parameters, and to return
+          Python Unicode objects in result rows.   This may
+          require SQLAlchemy to explicitly coerce incoming Python 
+          unicodes into an encoding, and from an encoding 
+          back to Unicode, or it may not require any interaction
+          from SQLAlchemy at all, depending on the DBAPI in use.
+
+          When SQLAlchemy performs the encoding/decoding, 
+          the encoding used is configured via
           :attr:`~sqlalchemy.engine.base.Dialect.encoding`, which
           defaults to `utf-8`.
 
-          If False, may be overridden by
-          :attr:`sqlalchemy.engine.base.Dialect.convert_unicode`.
+          The "convert_unicode" behavior can also be turned on
+          for all String types by setting 
+          :attr:`sqlalchemy.engine.base.Dialect.convert_unicode`
+          on create_engine().
           
-          If the DBAPI in use has been detected to return unicode 
-          strings from a VARCHAR result column, the String object will
-          assume all subsequent results are already unicode objects, and no
-          type detection will be done to verify this.  The 
-          rationale here is that isinstance() calls are enormously
-          expensive at the level of column-fetching.  To
-          force the check to occur regardless, set 
-          convert_unicode='force'.   This will incur significant
+          To instruct SQLAlchemy to perform Unicode encoding/decoding
+          even on a platform that already handles Unicode natively,
+          set convert_unicode='force'.  This will incur significant
           performance overhead when fetching unicode result columns.
           
-          Similarly, if the dialect is known to accept bind parameters
-          as unicode objects, no translation from unicode to bytestring
-          is performed on binds.  Again, encoding to a bytestring can be 
-          forced for special circumstances by setting convert_unicode='force'.
-
-        :param assert_unicode:
-
-          If None (the default), no assertion will take place unless
-          overridden by :attr:`sqlalchemy.engine.base.Dialect.assert_unicode`.
-
-          If 'warn', will issue a runtime warning if a ``str``
-          instance is used as a bind value.
-
-          If true, will raise an :exc:`sqlalchemy.exc.InvalidRequestError`.
+        :param assert_unicode: Deprecated.  A warning is raised in all cases when a non-Unicode
+          object is passed when SQLAlchemy would coerce into an encoding
+          (note: but **not** when the DBAPI handles unicode objects natively).
+          To suppress or raise this warning to an 
+          error, use the Python warnings filter documented at:
+          http://docs.python.org/library/warnings.html
 
         :param unicode_error: Optional, a method to use to handle Unicode
           conversion errors. Behaves like the 'errors' keyword argument to
@@ -565,56 +560,37 @@ class String(Concatenable, TypeEngine):
         if unicode_error is not None and convert_unicode != 'force':
             raise exc.ArgumentError("convert_unicode must be 'force' "
                                         "when unicode_error is set.")
+        
+        if assert_unicode:
+            util.warn_deprecated("assert_unicode is deprecated. "
+                                "SQLAlchemy emits a warning in all cases where it "
+                                "would otherwise like to encode a Python unicode object "
+                                "into a specific encoding but a plain bytestring is received. "
+                                "This does *not* apply to DBAPIs that coerce Unicode natively."
+                                )
         self.length = length
         self.convert_unicode = convert_unicode
-        self.assert_unicode = assert_unicode
         self.unicode_error = unicode_error
         
         
     def adapt(self, impltype):
         return impltype(
                     length=self.length,
-                    convert_unicode=self.convert_unicode,
-                    assert_unicode=self.assert_unicode)
+                    convert_unicode=self.convert_unicode)
 
     def bind_processor(self, dialect):
         if self.convert_unicode or dialect.convert_unicode:
-            if self.assert_unicode is None:
-                assert_unicode = dialect.assert_unicode
-            else:
-                assert_unicode = self.assert_unicode
-            
-            if dialect.supports_unicode_binds and assert_unicode:
-                def process(value):
-                    if value is None or isinstance(value, unicode):
-                        return value
-                    else:
-                        if assert_unicode == 'warn':
-                            util.warn("Unicode type received non-unicode bind "
-                                      "param value %r" % value)
-                            return value
-                        else:
-                            raise exc.InvalidRequestError(
-                                "Unicode type received non-unicode bind "
-                                "param value %r" % value)
-            elif dialect.supports_unicode_binds and self.convert_unicode != 'force':
+            if dialect.supports_unicode_binds and self.convert_unicode != 'force':
                 return None
             else:
                 encoder = codecs.getencoder(dialect.encoding)
                 def process(value):
                     if isinstance(value, unicode):
                         return encoder(value, self.unicode_error)[0]
-                    elif assert_unicode and value is not None:
-                        if assert_unicode == 'warn':
-                            util.warn("Unicode type received non-unicode bind "
-                                      "param value %r" % value)
-                            return value
-                        else:
-                            raise exc.InvalidRequestError(
-                                "Unicode type received non-unicode bind "
-                                "param value %r" % value)
-                    else:
-                        return value
+                    elif value is not None:
+                        util.warn("Unicode type received non-unicode bind "
+                                  "param value %r" % value)
+                    return value
             return process
         else:
             return None
@@ -669,7 +645,7 @@ class Unicode(String):
     database back into Python ``unicode`` objects.
     
     It's roughly equivalent to using a ``String`` object with
-    ``convert_unicode=True`` and ``assert_unicode='warn'``, however
+    ``convert_unicode=True``, however
     the type has other significances in that it implies the usage 
     of a unicode-capable type being used on the backend, such as NVARCHAR.
     This may affect what type is emitted when issuing CREATE TABLE
@@ -712,7 +688,6 @@ class Unicode(String):
           
         """
         kwargs.setdefault('convert_unicode', True)
-        kwargs.setdefault('assert_unicode', 'warn')
         super(Unicode, self).__init__(length=length, **kwargs)
 
 class UnicodeText(Text):
@@ -741,7 +716,6 @@ class UnicodeText(Text):
 
         """
         kwargs.setdefault('convert_unicode', True)
-        kwargs.setdefault('assert_unicode', 'warn')
         super(UnicodeText, self).__init__(length=length, **kwargs)
 
 
@@ -1170,9 +1144,6 @@ class Enum(String, SchemaType):
         :param \*enums: string or unicode enumeration labels. If unicode labels
             are present, the `convert_unicode` flag is auto-enabled.
 
-        :param assert_unicode: Enable unicode asserts for bind parameter values.
-            This flag is equivalent to that of ``String``.
-
         :param convert_unicode: Enable unicode-aware bind parameter and result-set
             processing for this Enum's data. This is set automatically based on
             the presence of unicode label strings.
@@ -1209,7 +1180,6 @@ class Enum(String, SchemaType):
         self.enums = enums
         self.native_enum = kw.pop('native_enum', True)
         convert_unicode= kw.pop('convert_unicode', None)
-        assert_unicode = kw.pop('assert_unicode', None)
         if convert_unicode is None:
             for e in enums:
                 if isinstance(e, unicode):
@@ -1225,7 +1195,6 @@ class Enum(String, SchemaType):
         String.__init__(self, 
                         length =length,
                         convert_unicode=convert_unicode, 
-                        assert_unicode=assert_unicode
                         )
         SchemaType.__init__(self, **kw)
 
@@ -1251,7 +1220,6 @@ class Enum(String, SchemaType):
                         schema=self.schema, 
                         metadata=self.metadata,
                         convert_unicode=self.convert_unicode,
-                        assert_unicode=self.assert_unicode,
                         *self.enums
                         )
 
index 6ab769e513e169d00ec3bf255c472f770c0e6eb3..60022e18a58f8f5c6815969d7b4e92c83f54499a 100644 (file)
@@ -1329,7 +1329,7 @@ class ArrayTest(TestBase, AssertsExecutionResults):
         arrtable = Table('arrtable', metadata,
             Column('id', Integer, primary_key=True),
             Column('intarr', postgresql.PGArray(Integer)),
-            Column('strarr', postgresql.PGArray(Unicode(assert_unicode=False)), nullable=False)
+            Column('strarr', postgresql.PGArray(Unicode()), nullable=False)
         )
         metadata.create_all()
 
index 0012a8acb748418e855bf5fc9880f9e2a9341e6b..7b428404cb7d7341afcd7c1c2f27e94fd2b59513 100644 (file)
@@ -86,10 +86,10 @@ class TestTypes(TestBase, AssertsExecutionResults):
                 CHAR(convert_unicode=True),
                 Unicode(),
                 UnicodeText(),
-                String(assert_unicode=True, convert_unicode=True),
-                CHAR(assert_unicode=True, convert_unicode=True),
-                Unicode(assert_unicode=True),
-                UnicodeText(assert_unicode=True)
+                String(convert_unicode=True),
+                CHAR(convert_unicode=True),
+                Unicode(),
+                UnicodeText()
             ):
 
             bindproc = t.dialect_impl(dialect).bind_processor(dialect)
index 27ee8709f83919f0b44550a424c913ffdbb69fa8..fb7249ae21cc2766a2afbc05c0d72a4157305267 100644 (file)
@@ -384,39 +384,23 @@ class UnicodeTest(TestBase, AssertsExecutionResults):
         unicode_table.insert().execute(unicode_varchar=u'')
         assert select([unicode_table.c.unicode_varchar]).scalar() == u''
 
-    def test_parameters(self):
-        """test the dialect convert_unicode parameters."""
+    def test_unicode_warnings(self):
+        """test the warnings raised when SQLA must coerce unicode binds."""
 
         unicodedata = u"Alors vous imaginez ma surprise, au lever du jour, quand "\
                         u"une drôle de petit voix m’a réveillé. "\
                         u"Elle disait: « S’il vous plaît… dessine-moi un mouton! »"
 
-        u = Unicode(assert_unicode=True)
-        uni = u.dialect_impl(testing.db.dialect).bind_processor(testing.db.dialect)
-        # Py3K
-        #assert_raises(exc.InvalidRequestError, uni, b'x')
-        # Py2K
-        assert_raises(exc.InvalidRequestError, uni, 'x')
-        # end Py2K
-
-        u = Unicode()
-        uni = u.dialect_impl(testing.db.dialect).bind_processor(testing.db.dialect)
-        # Py3K
-        #assert_raises(exc.SAWarning, uni, b'x')
-        # Py2K
-        assert_raises(exc.SAWarning, uni, 'x')
-        # end Py2K
-
-        unicode_engine = engines.utf8_engine(options={'convert_unicode':True,'assert_unicode':True})
+        unicode_engine = engines.utf8_engine(options={'convert_unicode':True,})
         unicode_engine.dialect.supports_unicode_binds = False
         
         s = String()
         uni = s.dialect_impl(unicode_engine.dialect).bind_processor(unicode_engine.dialect)
         # Py3K
-        #assert_raises(exc.InvalidRequestError, uni, b'x')
+        #assert_raises(exc.SAWarning, uni, b'x')
         #assert isinstance(uni(unicodedata), bytes)
         # Py2K
-        assert_raises(exc.InvalidRequestError, uni, 'x')
+        assert_raises(exc.SAWarning, uni, 'x')
         assert isinstance(uni(unicodedata), str)
         # end Py2K
         
@@ -1169,7 +1153,7 @@ class CallableTest(TestBase):
         meta.drop_all()
 
     def test_callable_as_arg(self):
-        ucode = util.partial(Unicode, assert_unicode=None)
+        ucode = util.partial(Unicode)
 
         thing_table = Table('thing', meta,
             Column('name', ucode(20))
@@ -1178,7 +1162,7 @@ class CallableTest(TestBase):
         thing_table.create()
 
     def test_callable_as_kwarg(self):
-        ucode = util.partial(Unicode, assert_unicode=None)
+        ucode = util.partial(Unicode)
 
         thang_table = Table('thang', meta,
             Column('name', type_=ucode(20), primary_key=True)