diff options
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r-- | lib/sqlalchemy/cextension/processors.c | 188 | ||||
-rw-r--r-- | lib/sqlalchemy/connectors/pyodbc.py | 9 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mssql/base.py | 9 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mysql/mysqlconnector.py | 26 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mysql/pymysql.py | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/oracle/base.py | 28 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/oracle/cx_oracle.py | 72 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/asyncpg.py | 3 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/psycopg2.py | 40 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/sqlite/base.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/create.py | 72 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/default.py | 103 | ||||
-rw-r--r-- | lib/sqlalchemy/processors.py | 44 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/schema.py | 7 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/sqltypes.py | 294 | ||||
-rw-r--r-- | lib/sqlalchemy/testing/profiling.py | 6 |
16 files changed, 59 insertions, 850 deletions
diff --git a/lib/sqlalchemy/cextension/processors.c b/lib/sqlalchemy/cextension/processors.c index f6f203e74..8c031b70a 100644 --- a/lib/sqlalchemy/cextension/processors.c +++ b/lib/sqlalchemy/cextension/processors.c @@ -312,192 +312,12 @@ str_to_date(PyObject *self, PyObject *arg) typedef struct { PyObject_HEAD - PyObject *encoding; - PyObject *errors; -} UnicodeResultProcessor; - -typedef struct { - PyObject_HEAD PyObject *type; PyObject *format; } DecimalResultProcessor; -/************************** - * UnicodeResultProcessor * - **************************/ - -static int -UnicodeResultProcessor_init(UnicodeResultProcessor *self, PyObject *args, - PyObject *kwds) -{ - PyObject *encoding, *errors = NULL; - static char *kwlist[] = {"encoding", "errors", NULL}; - -#if PY_MAJOR_VERSION >= 3 - if (!PyArg_ParseTupleAndKeywords(args, kwds, "U|U:__init__", kwlist, - &encoding, &errors)) - return -1; -#else - if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|S:__init__", kwlist, - &encoding, &errors)) - return -1; -#endif - -#if PY_MAJOR_VERSION >= 3 - encoding = PyUnicode_AsASCIIString(encoding); -#else - Py_INCREF(encoding); -#endif - self->encoding = encoding; - - if (errors) { -#if PY_MAJOR_VERSION >= 3 - errors = PyUnicode_AsASCIIString(errors); -#else - Py_INCREF(errors); -#endif - } else { -#if PY_MAJOR_VERSION >= 3 - errors = PyBytes_FromString("strict"); -#else - errors = PyString_FromString("strict"); -#endif - if (errors == NULL) - return -1; - } - self->errors = errors; - - return 0; -} - -static PyObject * -UnicodeResultProcessor_process(UnicodeResultProcessor *self, PyObject *value) -{ - const char *encoding, *errors; - char *str; - Py_ssize_t len; - - if (value == Py_None) - Py_RETURN_NONE; - -#if PY_MAJOR_VERSION >= 3 - if (PyBytes_AsStringAndSize(value, &str, &len)) - return NULL; - - encoding = PyBytes_AS_STRING(self->encoding); - errors = PyBytes_AS_STRING(self->errors); -#else - if (PyString_AsStringAndSize(value, &str, &len)) - return NULL; - - encoding = PyString_AS_STRING(self->encoding); - errors = PyString_AS_STRING(self->errors); -#endif - - return PyUnicode_Decode(str, len, encoding, errors); -} - -static PyObject * -UnicodeResultProcessor_conditional_process(UnicodeResultProcessor *self, PyObject *value) -{ - const char *encoding, *errors; - char *str; - Py_ssize_t len; - - if (value == Py_None) - Py_RETURN_NONE; - -#if PY_MAJOR_VERSION >= 3 - if (PyUnicode_Check(value) == 1) { - Py_INCREF(value); - return value; - } - - if (PyBytes_AsStringAndSize(value, &str, &len)) - return NULL; - - encoding = PyBytes_AS_STRING(self->encoding); - errors = PyBytes_AS_STRING(self->errors); -#else - - if (PyUnicode_Check(value) == 1) { - Py_INCREF(value); - return value; - } - - if (PyString_AsStringAndSize(value, &str, &len)) - return NULL; - - - encoding = PyString_AS_STRING(self->encoding); - errors = PyString_AS_STRING(self->errors); -#endif - - return PyUnicode_Decode(str, len, encoding, errors); -} - -static void -UnicodeResultProcessor_dealloc(UnicodeResultProcessor *self) -{ - Py_XDECREF(self->encoding); - Py_XDECREF(self->errors); -#if PY_MAJOR_VERSION >= 3 - Py_TYPE(self)->tp_free((PyObject*)self); -#else - self->ob_type->tp_free((PyObject*)self); -#endif -} - -static PyMethodDef UnicodeResultProcessor_methods[] = { - {"process", (PyCFunction)UnicodeResultProcessor_process, METH_O, - "The value processor itself."}, - {"conditional_process", (PyCFunction)UnicodeResultProcessor_conditional_process, METH_O, - "Conditional version of the value processor."}, - {NULL} /* Sentinel */ -}; - -static PyTypeObject UnicodeResultProcessorType = { - PyVarObject_HEAD_INIT(NULL, 0) - "sqlalchemy.cprocessors.UnicodeResultProcessor", /* tp_name */ - sizeof(UnicodeResultProcessor), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)UnicodeResultProcessor_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - "UnicodeResultProcessor objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - UnicodeResultProcessor_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)UnicodeResultProcessor_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; /************************** * DecimalResultProcessor * @@ -664,10 +484,6 @@ initcprocessors(void) { PyObject *m; - UnicodeResultProcessorType.tp_new = PyType_GenericNew; - if (PyType_Ready(&UnicodeResultProcessorType) < 0) - INITERROR; - DecimalResultProcessorType.tp_new = PyType_GenericNew; if (PyType_Ready(&DecimalResultProcessorType) < 0) INITERROR; @@ -682,10 +498,6 @@ initcprocessors(void) PyDateTime_IMPORT; - Py_INCREF(&UnicodeResultProcessorType); - PyModule_AddObject(m, "UnicodeResultProcessor", - (PyObject *)&UnicodeResultProcessorType); - Py_INCREF(&DecimalResultProcessorType); PyModule_AddObject(m, "DecimalResultProcessor", (PyObject *)&DecimalResultProcessorType); diff --git a/lib/sqlalchemy/connectors/pyodbc.py b/lib/sqlalchemy/connectors/pyodbc.py index c2bbdf7ce..9661015ad 100644 --- a/lib/sqlalchemy/connectors/pyodbc.py +++ b/lib/sqlalchemy/connectors/pyodbc.py @@ -18,9 +18,6 @@ class PyODBCConnector(Connector): supports_sane_rowcount_returning = True supports_sane_multi_rowcount = False - supports_unicode_statements = True - supports_unicode_binds = True - supports_native_decimal = True default_paramstyle = "named" @@ -30,12 +27,8 @@ class PyODBCConnector(Connector): # hold the desired driver name pyodbc_driver_name = None - def __init__( - self, supports_unicode_binds=None, use_setinputsizes=False, **kw - ): + def __init__(self, use_setinputsizes=False, **kw): super(PyODBCConnector, self).__init__(**kw) - if supports_unicode_binds is not None: - self.supports_unicode_binds = supports_unicode_binds self.use_setinputsizes = use_setinputsizes @classmethod diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index 8c8260f3b..f8ca1ffbf 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -1603,17 +1603,12 @@ class MSExecutionContext(default.DefaultExecutionContext): def _opt_encode(self, statement): - if not self.dialect.supports_unicode_statements: - encoded = self.dialect._encoder(statement)[0] - else: - encoded = statement - if self.compiled and self.compiled.schema_translate_map: rst = self.compiled.preparer._render_schema_translates - encoded = rst(encoded, self.compiled.schema_translate_map) + statement = rst(statement, self.compiled.schema_translate_map) - return encoded + return statement def pre_exec(self): """Activate IDENTITY_INSERT if needed.""" diff --git a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py index e17da3174..fef4f14ca 100644 --- a/lib/sqlalchemy/dialects/mysql/mysqlconnector.py +++ b/lib/sqlalchemy/dialects/mysql/mysqlconnector.py @@ -27,7 +27,6 @@ from .base import BIT from .base import MySQLCompiler from .base import MySQLDialect from .base import MySQLIdentifierPreparer -from ... import processors from ... import util @@ -87,8 +86,6 @@ class MySQLDialect_mysqlconnector(MySQLDialect): driver = "mysqlconnector" supports_statement_cache = True - supports_unicode_binds = True - supports_sane_rowcount = True supports_sane_multi_rowcount = True @@ -101,29 +98,6 @@ class MySQLDialect_mysqlconnector(MySQLDialect): colspecs = util.update_copy(MySQLDialect.colspecs, {BIT: _myconnpyBIT}) - def __init__(self, *arg, **kw): - super(MySQLDialect_mysqlconnector, self).__init__(*arg, **kw) - - # hack description encoding since mysqlconnector randomly - # returns bytes or not - self._description_decoder = ( - processors.to_conditional_unicode_processor_factory - )(self.description_encoding) - - def _check_unicode_description(self, connection): - # hack description encoding since mysqlconnector randomly - # returns bytes or not - return False - - @property - def description_encoding(self): - # total guess - return "latin-1" - - @util.memoized_property - def supports_unicode_statements(self): - return util.py3k or self._mysqlconnector_version_info > (2, 0) - @classmethod def dbapi(cls): from mysql import connector diff --git a/lib/sqlalchemy/dialects/mysql/pymysql.py b/lib/sqlalchemy/dialects/mysql/pymysql.py index 1d2c3be2d..3c30fb9ea 100644 --- a/lib/sqlalchemy/dialects/mysql/pymysql.py +++ b/lib/sqlalchemy/dialects/mysql/pymysql.py @@ -48,12 +48,6 @@ class MySQLDialect_pymysql(MySQLDialect_mysqldb): description_encoding = None - # generally, these two values should be both True - # or both False. PyMySQL unicode tests pass all the way back - # to 0.4 either way. See [ticket:3337] - supports_unicode_statements = True - supports_unicode_binds = True - @langhelpers.memoized_property def supports_server_side_cursors(self): try: diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py index 5a43205df..229a54b95 100644 --- a/lib/sqlalchemy/dialects/oracle/base.py +++ b/lib/sqlalchemy/dialects/oracle/base.py @@ -10,7 +10,7 @@ r""" :name: Oracle :full_support: 11.2, 18c :normal_support: 11+ - :best_effort: 8+ + :best_effort: 9+ Auto Increment Behavior @@ -341,6 +341,9 @@ and specify "passive_updates=False" on each relationship(). Oracle 8 Compatibility ---------------------- +.. warning:: The status of Oracle 8 compatibility is not known for SQLAlchemy + 2.0. + When Oracle 8 is detected, the dialect internally configures itself to the following behaviors: @@ -349,16 +352,12 @@ following behaviors: makes use of Oracle's (+) operator. * the NVARCHAR2 and NCLOB datatypes are no longer generated as DDL when - the :class:`~sqlalchemy.types.Unicode` is used - VARCHAR2 and CLOB are - issued instead. This because these types don't seem to work correctly on - Oracle 8 even though they are available. The - :class:`~sqlalchemy.types.NVARCHAR` and + the :class:`~sqlalchemy.types.Unicode` is used - VARCHAR2 and CLOB are issued + instead. This because these types don't seem to work correctly on Oracle 8 + even though they are available. The :class:`~sqlalchemy.types.NVARCHAR` and :class:`~sqlalchemy.dialects.oracle.NCLOB` types will always generate NVARCHAR2 and NCLOB. -* the "native unicode" mode is disabled when using cx_oracle, i.e. SQLAlchemy - encodes all Python unicode objects to "string" before passing in as bind - parameters. Synonym/DBLINK Reflection ------------------------- @@ -1439,8 +1438,6 @@ class OracleDialect(default.DefaultDialect): name = "oracle" supports_statement_cache = True supports_alter = True - supports_unicode_statements = False - supports_unicode_binds = False max_identifier_length = 128 supports_simple_order_by_label = False @@ -1576,17 +1573,6 @@ class OracleDialect(default.DefaultDialect): # use the default return None - def _check_unicode_returns(self, connection): - additional_tests = [ - expression.cast( - expression.literal_column("'test nvarchar2 returns'"), - sqltypes.NVARCHAR(60), - ) - ] - return super(OracleDialect, self)._check_unicode_returns( - connection, additional_tests - ) - _isolation_lookup = ["READ COMMITTED", "SERIALIZABLE"] def get_isolation_level(self, connection): diff --git a/lib/sqlalchemy/dialects/oracle/cx_oracle.py b/lib/sqlalchemy/dialects/oracle/cx_oracle.py index 590c9d47c..23f619a12 100644 --- a/lib/sqlalchemy/dialects/oracle/cx_oracle.py +++ b/lib/sqlalchemy/dialects/oracle/cx_oracle.py @@ -119,7 +119,7 @@ itself. These options are always passed directly to :func:`_sa.create_engine` , such as:: e = create_engine( - "oracle+cx_oracle://user:pass@dsn", coerce_to_unicode=False) + "oracle+cx_oracle://user:pass@dsn", coerce_to_decimal=False) The parameters accepted by the cx_oracle dialect are as follows: @@ -130,8 +130,6 @@ The parameters accepted by the cx_oracle dialect are as follows: * ``auto_convert_lobs`` - defaults to True; See :ref:`cx_oracle_lob`. -* ``coerce_to_unicode`` - see :ref:`cx_oracle_unicode` for detail. - * ``coerce_to_decimal`` - see :ref:`cx_oracle_numeric` for detail. * ``encoding_errors`` - see :ref:`cx_oracle_unicode_encoding_errors` for detail. @@ -210,8 +208,7 @@ Unicode ------- As is the case for all DBAPIs under Python 3, all strings are inherently -Unicode strings. Under Python 2, cx_Oracle also supports Python Unicode -objects directly. In all cases however, the driver requires an explicit +Unicode strings. In all cases however, the driver requires an explicit encoding configuration. Ensuring the Correct Client Encoding @@ -264,25 +261,6 @@ SQLAlchemy dialect to use NCHAR/NCLOB for the :class:`.Unicode` / unless the ``use_nchar_for_unicode=True`` is passed to the dialect when :func:`_sa.create_engine` is called. -Unicode Coercion of result rows under Python 2 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When result sets are fetched that include strings, under Python 3 the cx_Oracle -DBAPI returns all strings as Python Unicode objects, since Python 3 only has a -Unicode string type. This occurs for data fetched from datatypes such as -VARCHAR2, CHAR, CLOB, NCHAR, NCLOB, etc. In order to provide cross- -compatibility under Python 2, the SQLAlchemy cx_Oracle dialect will add -Unicode-conversion to string data under Python 2 as well. Historically, this -made use of converters that were supplied by cx_Oracle but were found to be -non-performant; SQLAlchemy's own converters are used for the string to Unicode -conversion under Python 2. To disable the Python 2 Unicode conversion for -VARCHAR2, CHAR, and CLOB, the flag ``coerce_to_unicode=False`` can be passed to -:func:`_sa.create_engine`. - -.. versionchanged:: 1.3 Unicode conversion is applied to all string values - by default under python 2. The ``coerce_to_unicode`` now defaults to True - and can be set to False to disable the Unicode coercion of strings that are - delivered as VARCHAR2/CHAR/CLOB data. .. _cx_oracle_unicode_encoding_errors: @@ -855,9 +833,6 @@ class OracleDialect_cx_oracle(OracleDialect): supports_sane_rowcount = True supports_sane_multi_rowcount = True - supports_unicode_statements = True - supports_unicode_binds = True - use_setinputsizes = True driver = "cx_oracle" @@ -892,6 +867,8 @@ class OracleDialect_cx_oracle(OracleDialect): _cx_oracle_threaded = None + _cursor_var_unicode_kwargs = util.immutabledict() + @util.deprecated_params( threaded=( "1.3", @@ -906,7 +883,6 @@ class OracleDialect_cx_oracle(OracleDialect): def __init__( self, auto_convert_lobs=True, - coerce_to_unicode=True, coerce_to_decimal=True, arraysize=50, encoding_errors=None, @@ -917,10 +893,13 @@ class OracleDialect_cx_oracle(OracleDialect): OracleDialect.__init__(self, **kwargs) self.arraysize = arraysize self.encoding_errors = encoding_errors + if encoding_errors: + self._cursor_var_unicode_kwargs = { + "encodingErrors": encoding_errors + } if threaded is not None: self._cx_oracle_threaded = threaded self.auto_convert_lobs = auto_convert_lobs - self.coerce_to_unicode = coerce_to_unicode self.coerce_to_decimal = coerce_to_decimal if self._use_nchar_for_unicode: self.colspecs = self.colspecs.copy() @@ -939,6 +918,13 @@ class OracleDialect_cx_oracle(OracleDialect): "cx_Oracle version 5.2 and above are supported" ) + if encoding_errors and self.cx_oracle_ver < (6, 4): + util.warn( + "cx_oracle version %r does not support encodingErrors" + % (self.cx_oracle_ver,) + ) + self._cursor_var_unicode_kwargs = util.immutabledict() + self._include_setinputsizes = { cx_Oracle.DATETIME, cx_Oracle.NCLOB, @@ -974,19 +960,6 @@ class OracleDialect_cx_oracle(OracleDialect): self._is_cx_oracle_6 = self.cx_oracle_ver >= (6,) - @property - def _cursor_var_unicode_kwargs(self): - if self.encoding_errors: - if self.cx_oracle_ver >= (6, 4): - return {"encodingErrors": self.encoding_errors} - else: - util.warn( - "cx_oracle version %r does not support encodingErrors" - % (self.cx_oracle_ver,) - ) - - return {} - def _parse_cx_oracle_ver(self, version): m = re.match(r"(\d+)\.(\d+)(?:\.(\d+))?", version) if m: @@ -1002,9 +975,6 @@ class OracleDialect_cx_oracle(OracleDialect): def initialize(self, connection): super(OracleDialect_cx_oracle, self).initialize(connection) - if self._is_oracle_8: - self.supports_unicode_binds = False - self._detect_decimal_char(connection) def get_isolation_level(self, connection): @@ -1141,9 +1111,10 @@ class OracleDialect_cx_oracle(OracleDialect): cursor, name, default_type, size, precision, scale ) - # allow all strings to come back natively as Unicode + # if unicode options were specified, add a decoder, otherwise + # cx_Oracle should return Unicode elif ( - dialect.coerce_to_unicode + dialect._cursor_var_unicode_kwargs and default_type in ( cx_Oracle.STRING, @@ -1338,13 +1309,6 @@ class OracleDialect_cx_oracle(OracleDialect): if dbtype ) - if not self.supports_unicode_binds: - # oracle 8 only - collection = ( - (self.dialect._encoder(key)[0], dbtype) - for key, dbtype in collection - ) - cursor.setinputsizes(**{key: dbtype for key, dbtype in collection}) def do_recover_twophase(self, connection): diff --git a/lib/sqlalchemy/dialects/postgresql/asyncpg.py b/lib/sqlalchemy/dialects/postgresql/asyncpg.py index fedc0b495..28374ed60 100644 --- a/lib/sqlalchemy/dialects/postgresql/asyncpg.py +++ b/lib/sqlalchemy/dialects/postgresql/asyncpg.py @@ -863,11 +863,8 @@ class PGDialect_asyncpg(PGDialect): driver = "asyncpg" supports_statement_cache = True - supports_unicode_statements = True supports_server_side_cursors = True - supports_unicode_binds = True - default_paramstyle = "format" supports_sane_multi_rowcount = False execution_ctx_cls = PGExecutionContext_asyncpg diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index 162ddde94..aadd11059 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -40,13 +40,6 @@ may be passed to :func:`_sa.create_engine()`, and include the following: :ref:`psycopg2_unicode` -* ``use_native_unicode``: Under Python 2 only, this can be set to False to - disable the use of psycopg2's native Unicode support. - - .. seealso:: - - :ref:`psycopg2_disable_native_unicode` - * ``executemany_mode``, ``executemany_batch_page_size``, ``executemany_values_page_size``: Allows use of psycopg2 @@ -295,10 +288,7 @@ size defaults to 100. These can be affected by passing new values to Unicode with Psycopg2 ---------------------- -The psycopg2 DBAPI driver supports Unicode data transparently. Under Python 2 -only, the SQLAlchemy psycopg2 dialect will enable the -``psycopg2.extensions.UNICODE`` extension by default to ensure Unicode is -handled properly; under Python 3, this is psycopg2's default behavior. +The psycopg2 DBAPI driver supports Unicode data transparently. The client character encoding can be controlled for the psycopg2 dialect in the following ways: @@ -347,21 +337,6 @@ in the following ways: # encoding client_encoding = utf8 -.. _psycopg2_disable_native_unicode: - -Disabling Native Unicode -^^^^^^^^^^^^^^^^^^^^^^^^ - -Under Python 2 only, SQLAlchemy can also be instructed to skip the usage of the -psycopg2 ``UNICODE`` extension and to instead utilize its own unicode -encode/decode services, which are normally reserved only for those DBAPIs that -don't fully support unicode directly. Passing ``use_native_unicode=False`` to -:func:`_sa.create_engine` will disable usage of ``psycopg2.extensions. -UNICODE``. SQLAlchemy will instead encode data itself into Python bytestrings -on the way in and coerce from bytes on the way back, using the value of the -:func:`_sa.create_engine` ``encoding`` parameter, which defaults to ``utf-8``. -SQLAlchemy's own unicode encode/decode functionality is steadily becoming -obsolete as most DBAPIs now support unicode fully. Transactions @@ -659,10 +634,6 @@ class PGDialect_psycopg2(PGDialect): _has_native_hstore = True - engine_config_types = PGDialect.engine_config_types.union( - {"use_native_unicode": util.asbool} - ) - colspecs = util.update_copy( PGDialect.colspecs, { @@ -678,7 +649,6 @@ class PGDialect_psycopg2(PGDialect): def __init__( self, - use_native_unicode=True, client_encoding=None, use_native_hstore=True, use_native_uuid=True, @@ -688,16 +658,10 @@ class PGDialect_psycopg2(PGDialect): **kwargs ): PGDialect.__init__(self, **kwargs) - self.use_native_unicode = use_native_unicode - if not use_native_unicode: - raise exc.ArgumentError( - "psycopg2 native_unicode mode is required under Python 3" - ) if not use_native_hstore: self._has_native_hstore = False self.use_native_hstore = use_native_hstore self.use_native_uuid = use_native_uuid - self.supports_unicode_binds = use_native_unicode self.client_encoding = client_encoding # Parse executemany_mode argument, allowing it to be only one of the @@ -892,8 +856,6 @@ class PGDialect_psycopg2(PGDialect): executemany_values = ( "(%s)" % context.compiled.insert_single_values_expr ) - if not self.supports_unicode_statements: - executemany_values = executemany_values.encode(self.encoding) # guard for statement that was altered via event hook or similar if executemany_values not in statement: diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py index e936c9080..dc8425859 100644 --- a/lib/sqlalchemy/dialects/sqlite/base.py +++ b/lib/sqlalchemy/dialects/sqlite/base.py @@ -1795,8 +1795,6 @@ class SQLiteExecutionContext(default.DefaultExecutionContext): class SQLiteDialect(default.DefaultDialect): name = "sqlite" supports_alter = False - supports_unicode_statements = True - supports_unicode_binds = True # SQlite supports "DEFAULT VALUES" but *does not* support # "VALUES (DEFAULT)" diff --git a/lib/sqlalchemy/engine/create.py b/lib/sqlalchemy/engine/create.py index bb657202f..e6da1d8e6 100644 --- a/lib/sqlalchemy/engine/create.py +++ b/lib/sqlalchemy/engine/create.py @@ -95,21 +95,6 @@ def create_engine(url, **kwargs): additional keyword arguments. See the example at :ref:`custom_dbapi_args`. - :param convert_unicode=False: if set to True, causes - all :class:`.String` datatypes to act as though the - :paramref:`.String.convert_unicode` flag has been set to ``True``, - regardless of a setting of ``False`` on an individual :class:`.String` - type. This has the effect of causing all :class:`.String` -based - columns to accommodate Python Unicode objects directly as though the - datatype were the :class:`.Unicode` type. - - .. deprecated:: 1.3 - - The :paramref:`_sa.create_engine.convert_unicode` parameter - is deprecated and will be removed in a future release. - All modern DBAPIs now support Python Unicode directly and this - parameter is unnecessary. - :param creator: a callable which returns a DBAPI connection. This creation function will be passed to the underlying connection pool and will be used to create all new database @@ -169,63 +154,6 @@ def create_engine(url, **kwargs): :ref:`change_4737` - :param encoding: **legacy Python 2 value only, where it only applies to - specific DBAPIs, not used in Python 3 for any modern DBAPI driver. - Please refer to individual dialect documentation for client encoding - behaviors.** Defaults to the string value ``utf-8``. This value - refers **only** to the character encoding that is used when SQLAlchemy - sends or receives data from a :term:`DBAPI` that does not support - Python Unicode and **is only used under Python 2**, only for certain - DBAPI drivers, and only in certain circumstances. **Python 3 users - please DISREGARD this parameter and refer to the documentation for the - specific dialect in use in order to configure character encoding - behavior.** - - .. note:: The ``encoding`` parameter deals only with in-Python - encoding issues that were prevalent with **some DBAPIS only** - under **Python 2 only**. Under Python 3 it is not used by - any modern dialect. For DBAPIs that require - client encoding configurations, which are most of those outside - of SQLite, please consult specific :ref:`dialect documentation - <dialect_toplevel>` for details. - - All modern DBAPIs that work in Python 3 necessarily feature direct - support for Python unicode strings. Under Python 2, this was not - always the case. For those scenarios where the DBAPI is detected as - not supporting a Python ``unicode`` object under Python 2, this - encoding is used to determine the source/destination encoding. It is - **not used** for those cases where the DBAPI handles unicode directly. - - To properly configure a system to accommodate Python ``unicode`` - objects, the DBAPI should be configured to handle unicode to the - greatest degree as is appropriate - see the notes on unicode pertaining - to the specific target database in use at :ref:`dialect_toplevel`. - - Areas where string encoding may need to be accommodated - outside of the DBAPI, nearly always under **Python 2 only**, - include zero or more of: - - * the values passed to bound parameters, corresponding to - the :class:`.Unicode` type or the :class:`.String` type - when ``convert_unicode`` is ``True``; - * the values returned in result set columns corresponding - to the :class:`.Unicode` type or the :class:`.String` - type when ``convert_unicode`` is ``True``; - * the string SQL statement passed to the DBAPI's - ``cursor.execute()`` method; - * the string names of the keys in the bound parameter - dictionary passed to the DBAPI's ``cursor.execute()`` - as well as ``cursor.setinputsizes()`` methods; - * the string column names retrieved from the DBAPI's - ``cursor.description`` attribute. - - When using Python 3, the DBAPI is required to support all of the above - values as Python ``unicode`` objects, which in Python 3 are just known - as ``str``. In Python 2, the DBAPI does not specify unicode behavior - at all, so SQLAlchemy must make decisions for each of the above values - on a per-DBAPI basis - implementations are completely inconsistent in - their behavior. - :param execution_options: Dictionary execution options which will be applied to all connections. See :meth:`~sqlalchemy.engine.Connection.execution_options` diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index 9a59250e9..d670cf231 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -13,7 +13,6 @@ as the base class for their own corresponding classes. """ -import codecs import functools import random import re @@ -26,7 +25,6 @@ from .base import Connection from .. import event from .. import exc from .. import pool -from .. import processors from .. import types as sqltypes from .. import util from ..sql import compiler @@ -92,7 +90,6 @@ class DefaultDialect(interfaces.Dialect): engine_config_types = util.immutabledict( [ - ("convert_unicode", util.bool_or_str("force")), ("pool_timeout", util.asint), ("echo", util.bool_or_str("debug")), ("echo_pool", util.bool_or_str("debug")), @@ -108,9 +105,6 @@ class DefaultDialect(interfaces.Dialect): # *not* the FLOAT type however. supports_native_decimal = False - supports_unicode_statements = True - supports_unicode_binds = True - returns_unicode_strings = sqltypes.String.RETURNS_UNICODE description_encoding = None name = "default" @@ -223,13 +217,6 @@ class DefaultDialect(interfaces.Dialect): NO_DIALECT_SUPPORT = NO_DIALECT_SUPPORT @util.deprecated_params( - convert_unicode=( - "1.3", - "The :paramref:`_sa.create_engine.convert_unicode` parameter " - "and corresponding dialect-level parameters are deprecated, " - "and will be removed in a future release. Modern DBAPIs support " - "Python Unicode natively and this parameter is unnecessary.", - ), empty_in_strategy=( "1.4", "The :paramref:`_sa.create_engine.empty_in_strategy` keyword is " @@ -250,7 +237,6 @@ class DefaultDialect(interfaces.Dialect): ) def __init__( self, - convert_unicode=False, encoding="utf-8", paramstyle=None, dbapi=None, @@ -279,7 +265,6 @@ class DefaultDialect(interfaces.Dialect): else: self.server_side_cursors = True - self.convert_unicode = convert_unicode self.encoding = encoding self.positional = False self._ischema = None @@ -305,16 +290,6 @@ class DefaultDialect(interfaces.Dialect): ) self.label_length = label_length self.compiler_linting = compiler_linting - if self.description_encoding == "use_encoding": - self._description_decoder = ( - processors.to_unicode_processor_factory - )(encoding) - elif self.description_encoding is not None: - self._description_decoder = ( - processors.to_unicode_processor_factory - )(self.description_encoding) - self._encoder = codecs.getencoder(self.encoding) - self._decoder = processors.to_unicode_processor_factory(self.encoding) def _ensure_has_table_connection(self, arg): @@ -391,12 +366,6 @@ class DefaultDialect(interfaces.Dialect): except NotImplementedError: self.default_isolation_level = None - if ( - self.description_encoding is not None - and self._check_unicode_description(connection) - ): - self._description_decoder = self.description_encoding = None - if not self._user_defined_max_identifier_length: max_ident_length = self._check_max_identifier_length(connection) if max_ident_length: @@ -444,22 +413,6 @@ class DefaultDialect(interfaces.Dialect): """ return self.get_isolation_level(dbapi_conn) - def _check_unicode_description(self, connection): - cast_to = util.text_type - - cursor = connection.connection.cursor() - try: - cursor.execute( - cast_to( - expression.select( - expression.literal_column("'x'").label("some_label") - ).compile(dialect=self) - ) - ) - return isinstance(cursor.description[0][0], util.text_type) - finally: - cursor.close() - def type_descriptor(self, typeobj): """Provide a database-specific :class:`.TypeEngine` object, given the generic object which comes from the types module. @@ -790,10 +743,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): self.unicode_statement, schema_translate_map ) - if not dialect.supports_unicode_statements: - self.statement = dialect._encoder(self.unicode_statement)[0] - else: - self.statement = self.unicode_statement + self.statement = self.unicode_statement self.cursor = self.create_cursor() self.compiled_parameters = [] @@ -913,12 +863,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): # final self.unicode_statement is now assigned, encode if needed # by dialect - if not dialect.supports_unicode_statements: - self.statement = self.unicode_statement.encode( - self.dialect.encoding - ) - else: - self.statement = self.unicode_statement + self.statement = self.unicode_statement # Convert the dictionary of bind parameter values # into a dict or list to be sent to the DBAPI's @@ -934,25 +879,14 @@ class DefaultExecutionContext(interfaces.ExecutionContext): ] parameters.append(dialect.execute_sequence_format(param)) else: - encode = not dialect.supports_unicode_statements - if encode: - encoder = dialect._encoder for compiled_params in self.compiled_parameters: - if encode: - param = { - encoder(key)[0]: processors[key](compiled_params[key]) - if key in processors - else compiled_params[key] - for key in compiled_params - } - else: - param = { - key: processors[key](compiled_params[key]) - if key in processors - else compiled_params[key] - for key in compiled_params - } + param = { + key: processors[key](compiled_params[key]) + if key in processors + else compiled_params[key] + for key in compiled_params + } parameters.append(param) @@ -988,13 +922,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): elif isinstance(parameters[0], dialect.execute_sequence_format): self.parameters = parameters elif isinstance(parameters[0], dict): - if dialect.supports_unicode_statements: - self.parameters = parameters - else: - self.parameters = [ - {dialect._encoder(k)[0]: d[k] for k in d} - for d in parameters - ] or [{}] + self.parameters = parameters else: self.parameters = [ dialect.execute_sequence_format(p) for p in parameters @@ -1002,13 +930,7 @@ class DefaultExecutionContext(interfaces.ExecutionContext): self.executemany = len(parameters) > 1 - if not dialect.supports_unicode_statements and isinstance( - statement, util.text_type - ): - self.unicode_statement = statement - self.statement = dialect._encoder(statement)[0] - else: - self.statement = self.unicode_statement = statement + self.statement = self.unicode_statement = statement self.cursor = self.create_cursor() return self @@ -1101,11 +1023,6 @@ class DefaultExecutionContext(interfaces.ExecutionContext): """ conn = self.root_connection - if ( - isinstance(stmt, util.text_type) - and not self.dialect.supports_unicode_statements - ): - stmt = self.dialect._encoder(stmt)[0] if "schema_translate_map" in self.execution_options: schema_translate_map = self.execution_options.get( diff --git a/lib/sqlalchemy/processors.py b/lib/sqlalchemy/processors.py index 0c0aa1bd6..156005c6a 100644 --- a/lib/sqlalchemy/processors.py +++ b/lib/sqlalchemy/processors.py @@ -13,7 +13,6 @@ They all share one common characteristic: None is passed through unchanged. """ -import codecs import datetime import re @@ -64,36 +63,6 @@ def str_to_datetime_processor_factory(regexp, type_): def py_fallback(): - def to_unicode_processor_factory(encoding, errors=None): - decoder = codecs.getdecoder(encoding) - - def process(value): - if value is None: - return None - else: - # decoder returns a tuple: (value, len). Simply dropping the - # len part is safe: it is done that way in the normal - # 'xx'.decode(encoding) code path. - return decoder(value, errors)[0] - - return process - - def to_conditional_unicode_processor_factory(encoding, errors=None): - decoder = codecs.getdecoder(encoding) - - def process(value): - if value is None: - return None - elif isinstance(value, util.text_type): - return value - else: - # decoder returns a tuple: (value, len). Simply dropping the - # len part is safe: it is done that way in the normal - # 'xx'.decode(encoding) code path. - return decoder(value, errors)[0] - - return process - def to_decimal_processor_factory(target_class, scale): fstring = "%%.%df" % scale @@ -149,19 +118,6 @@ try: from sqlalchemy.cprocessors import str_to_time # noqa from sqlalchemy.cprocessors import to_float # noqa from sqlalchemy.cprocessors import to_str # noqa - from sqlalchemy.cprocessors import UnicodeResultProcessor # noqa - - def to_unicode_processor_factory(encoding, errors=None): - if errors is not None: - return UnicodeResultProcessor(encoding, errors).process - else: - return UnicodeResultProcessor(encoding).process - - def to_conditional_unicode_processor_factory(encoding, errors=None): - if errors is not None: - return UnicodeResultProcessor(encoding, errors).conditional_process - else: - return UnicodeResultProcessor(encoding).conditional_process def to_decimal_processor_factory(target_class, scale): # Note that the scale argument is not taken into account for integer diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 89d3168a6..641e62be3 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -1639,13 +1639,6 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): if isinstance(self.default, (ColumnDefault, Sequence)): args.append(self.default) else: - if getattr(self.type, "_warn_on_bytestring", False): - if isinstance(self.default, util.binary_type): - util.warn( - "Unicode column '%s' has non-unicode " - "default value %r specified." - % (self.key, self.default) - ) args.append(ColumnDefault(self.default)) if self.server_default is not None: diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 0d7a06e31..559946072 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -9,7 +9,6 @@ """ -import codecs import datetime as dt import decimal import json @@ -127,9 +126,7 @@ class String(Concatenable, TypeEngine): """The base for all string and character types. - In SQL, corresponds to VARCHAR. Can also take Python unicode objects - and encode to the database's encoding in bind params (and the reverse for - result sets.) + In SQL, corresponds to VARCHAR. The `length` field is usually required when the `String` type is used within a CREATE TABLE statement, as VARCHAR requires a length @@ -139,91 +136,10 @@ class String(Concatenable, TypeEngine): __visit_name__ = "string" - RETURNS_UNICODE = util.symbol( - "RETURNS_UNICODE", - """Indicates that the DBAPI returns Python Unicode for VARCHAR, - NVARCHAR, and other character-based datatypes in all cases. - - This is the default value for - :attr:`.DefaultDialect.returns_unicode_strings` under Python 3. - - .. versionadded:: 1.4 - - """, - ) - - RETURNS_BYTES = util.symbol( - "RETURNS_BYTES", - """Indicates that the DBAPI returns byte objects under Python 3 - or non-Unicode string objects under Python 2 for VARCHAR, NVARCHAR, - and other character-based datatypes in all cases. - - This may be applied to the - :attr:`.DefaultDialect.returns_unicode_strings` attribute. - - .. versionadded:: 1.4 - - """, - ) - - RETURNS_CONDITIONAL = util.symbol( - "RETURNS_CONDITIONAL", - """Indicates that the DBAPI may return Unicode or bytestrings for - VARCHAR, NVARCHAR, and other character-based datatypes, and that - SQLAlchemy's default String datatype will need to test on a per-row - basis for Unicode or bytes. - - This may be applied to the - :attr:`.DefaultDialect.returns_unicode_strings` attribute. - - .. versionadded:: 1.4 - - """, - ) - - RETURNS_UNKNOWN = util.symbol( - "RETURNS_UNKNOWN", - """Indicates that the dialect should test on first connect what the - string-returning behavior of character-based datatypes is. - - This is the default value for DefaultDialect.unicode_returns under - Python 2. - - This may be applied to the - :attr:`.DefaultDialect.returns_unicode_strings` attribute under - Python 2 only. The value is disallowed under Python 3. - - .. versionadded:: 1.4 - - .. deprecated:: 1.4 This value will be removed in SQLAlchemy 2.0. - - """, - ) - - @util.deprecated_params( - convert_unicode=( - "1.3", - "The :paramref:`.String.convert_unicode` parameter is deprecated " - "and will be removed in a future release. All modern DBAPIs " - "now support Python Unicode directly and this parameter is " - "unnecessary.", - ), - unicode_error=( - "1.3", - "The :paramref:`.String.unicode_errors` parameter is deprecated " - "and will be removed in a future release. This parameter is " - "unnecessary for modern Python DBAPIs and degrades performance " - "significantly.", - ), - ) def __init__( self, length=None, collation=None, - convert_unicode=False, - unicode_error=None, - _warn_on_bytestring=False, - _expect_unicode=False, ): """ Create a string-holding type. @@ -245,65 +161,17 @@ class String(Concatenable, TypeEngine): >>> print(select(cast('some string', String(collation='utf8')))) SELECT CAST(:param_1 AS VARCHAR COLLATE utf8) AS anon_1 - :param convert_unicode: When set to ``True``, the - :class:`.String` type will assume that - input is to be passed as Python Unicode objects under Python 2, - and results returned as Python Unicode objects. - In the rare circumstance that the DBAPI does not support - Python unicode under Python 2, SQLAlchemy will use its own - encoder/decoder functionality on strings, referring to the - value of the :paramref:`_sa.create_engine.encoding` parameter - parameter passed to :func:`_sa.create_engine` as the encoding. - - For the extremely rare case that Python Unicode - is to be encoded/decoded by SQLAlchemy on a backend - that *does* natively support Python Unicode, - the string value ``"force"`` can be passed here which will - cause SQLAlchemy's encode/decode services to be - used unconditionally. - - .. note:: - - SQLAlchemy's unicode-conversion flags and features only apply - to Python 2; in Python 3, all string objects are Unicode objects. - For this reason, as well as the fact that virtually all modern - DBAPIs now support Unicode natively even under Python 2, - the :paramref:`.String.convert_unicode` flag is inherently a - legacy feature. - .. note:: - In the vast majority of cases, the :class:`.Unicode` or - :class:`.UnicodeText` datatypes should be used for a - :class:`_schema.Column` that expects to store non-ascii data. - These - datatypes will ensure that the correct types are used on the - database side as well as set up the correct Unicode behaviors - under Python 2. - - .. seealso:: - - :paramref:`_sa.create_engine.convert_unicode` - - :class:`_engine.Engine`-wide parameter - - :param unicode_error: Optional, a method to use to handle Unicode - conversion errors. Behaves like the ``errors`` keyword argument to - the standard library's ``string.decode()`` functions, requires - that :paramref:`.String.convert_unicode` is set to - ``"force"`` + In most cases, the :class:`.Unicode` or :class:`.UnicodeText` + datatypes should be used for a :class:`_schema.Column` that expects + to store non-ascii data. These datatypes will ensure that the + correct types are used on the database. """ - if unicode_error is not None and convert_unicode != "force": - raise exc.ArgumentError( - "convert_unicode must be 'force' " "when unicode_error is set." - ) self.length = length self.collation = collation - self._expect_unicode = convert_unicode or _expect_unicode - self._expect_unicode_error = unicode_error - - self._warn_on_bytestring = _warn_on_bytestring def literal_processor(self, dialect): def process(value): @@ -317,100 +185,24 @@ class String(Concatenable, TypeEngine): return process def bind_processor(self, dialect): - if self._expect_unicode or dialect.convert_unicode: - if ( - dialect.supports_unicode_binds - and self._expect_unicode != "force" - ): - if self._warn_on_bytestring: - - def process(value): - if isinstance(value, util.binary_type): - util.warn_limited( - "Unicode type received non-unicode " - "bind param value %r.", - (util.ellipses_string(value),), - ) - return value - - return process - else: - return None - else: - encoder = codecs.getencoder(dialect.encoding) - warn_on_bytestring = self._warn_on_bytestring - - def process(value): - if isinstance(value, util.text_type): - return encoder(value, self._expect_unicode_error)[0] - elif warn_on_bytestring and value is not None: - util.warn_limited( - "Unicode type received non-unicode bind " - "param value %r.", - (util.ellipses_string(value),), - ) - return value - - return process - else: - return None + return None def result_processor(self, dialect, coltype): - wants_unicode = self._expect_unicode or dialect.convert_unicode - needs_convert = wants_unicode and ( - dialect.returns_unicode_strings is not String.RETURNS_UNICODE - or self._expect_unicode in ("force", "force_nocheck") - ) - needs_isinstance = ( - needs_convert - and dialect.returns_unicode_strings - in ( - String.RETURNS_CONDITIONAL, - String.RETURNS_UNICODE, - ) - and self._expect_unicode != "force_nocheck" - ) - if needs_convert: - if needs_isinstance: - return processors.to_conditional_unicode_processor_factory( - dialect.encoding, self._expect_unicode_error - ) - else: - return processors.to_unicode_processor_factory( - dialect.encoding, self._expect_unicode_error - ) - else: - return None + return None @property def python_type(self): - if self._expect_unicode: - return util.text_type - else: - return str + return util.text_type def get_dbapi_type(self, dbapi): return dbapi.STRING - @classmethod - def _warn_deprecated_unicode(cls): - util.warn_deprecated( - "The convert_unicode on Engine and String as well as the " - "unicode_error flag on String are deprecated. All modern " - "DBAPIs now support Python Unicode natively under Python 2, and " - "under Python 3 all strings are inherently Unicode. These flags " - "will be removed in a future release.", - version="1.3", - ) - class Text(String): """A variably sized string type. - In SQL, usually corresponds to CLOB or TEXT. Can also take Python - unicode objects and encode to the database's encoding in bind - params (and the reverse for result sets.) In general, TEXT objects + In SQL, usually corresponds to CLOB or TEXT. In general, TEXT objects do not have a length; while some databases will accept a length argument here, it will be rejected by others. @@ -428,9 +220,7 @@ class Unicode(String): some backends implies an underlying column type that is explicitly supporting of non-ASCII data, such as ``NVARCHAR`` on Oracle and SQL Server. This will impact the output of ``CREATE TABLE`` statements and - ``CAST`` functions at the dialect level, and also in some cases will - indicate different behavior in the DBAPI itself in how it handles bound - parameters. + ``CAST`` functions at the dialect level. The character encoding used by the :class:`.Unicode` type that is used to transmit and receive data to the database is usually determined by the @@ -440,18 +230,10 @@ class Unicode(String): in the :ref:`dialect_toplevel` section. In modern SQLAlchemy, use of the :class:`.Unicode` datatype does not - typically imply any encoding/decoding behavior within SQLAlchemy itself. - Historically, when DBAPIs did not support Python ``unicode`` objects under - Python 2, SQLAlchemy handled unicode encoding/decoding services itself - which would be controlled by the flag :paramref:`.String.convert_unicode`; - this flag is deprecated as it is no longer needed for Python 3. - - When using Python 2, data that is passed to columns that use the - :class:`.Unicode` datatype must be of type ``unicode``, and not ``str`` - which in Python 2 is equivalent to ``bytes``. In Python 3, all data - passed to columns that use the :class:`.Unicode` datatype should be - of type ``str``. See the flag :paramref:`.String.convert_unicode` for - more discussion of unicode encode/decode behavior under Python 2. + imply any encoding/decoding behavior within SQLAlchemy itself. In Python + 3, all string objects are inherently Unicode capable, and SQLAlchemy + does not produce bytestring objects nor does it accommodate a DBAPI that + does not return Python Unicode objects in result sets for string values. .. warning:: Some database backends, particularly SQL Server with pyodbc, are known to have undesirable behaviors regarding data that is noted @@ -466,8 +248,6 @@ class Unicode(String): :class:`.UnicodeText` - unlengthed textual counterpart to :class:`.Unicode`. - :paramref:`.String.convert_unicode` - :meth:`.DialectEvents.do_setinputsizes` @@ -479,13 +259,9 @@ class Unicode(String): """ Create a :class:`.Unicode` object. - Parameters are the same as that of :class:`.String`, - with the exception that ``convert_unicode`` - defaults to ``True``. + Parameters are the same as that of :class:`.String`. """ - kwargs.setdefault("_expect_unicode", True) - kwargs.setdefault("_warn_on_bytestring", True) super(Unicode, self).__init__(length=length, **kwargs) @@ -508,18 +284,11 @@ class UnicodeText(Text): """ Create a Unicode-converting Text type. - Parameters are the same as that of :class:`_expression.TextClause`, - with the exception that ``convert_unicode`` - defaults to ``True``. + Parameters are the same as that of :class:`_expression.TextClause`. """ - kwargs.setdefault("_expect_unicode", True) - kwargs.setdefault("_warn_on_bytestring", True) super(UnicodeText, self).__init__(length=length, **kwargs) - def _warn_deprecated_unicode(self): - pass - class Integer(_LookupExpressionAdapter, TypeEngine): @@ -1306,15 +1075,6 @@ class Enum(Emulated, String, SchemaType): __visit_name__ = "enum" - @util.deprecated_params( - convert_unicode=( - "1.3", - "The :paramref:`.Enum.convert_unicode` parameter is deprecated " - "and will be removed in a future release. All modern DBAPIs " - "now support Python Unicode directly and this parameter is " - "unnecessary.", - ) - ) def __init__(self, *enums, **kw): r"""Construct an enum. @@ -1327,11 +1087,6 @@ class Enum(Emulated, String, SchemaType): .. versionadded:: 1.1 a PEP-435 style enumerated class may be passed. - :param convert_unicode: Enable unicode-aware bind parameter and - result-set processing for this Enum's data under Python 2 only. - Under Python 2, this is set automatically based on the presence of - unicode label strings. This flag will be removed in SQLAlchemy 2.0. - :param create_constraint: defaults to False. When creating a non-native enumerated type, also build a CHECK constraint on the database against the valid values. @@ -1481,14 +1236,8 @@ class Enum(Emulated, String, SchemaType): values, objects = self._parse_into_values(enums, kw) self._setup_for_values(values, objects, kw) - convert_unicode = kw.pop("convert_unicode", None) self.validate_strings = kw.pop("validate_strings", False) - if convert_unicode is None: - _expect_unicode = True - else: - _expect_unicode = convert_unicode - if self.enums: length = max(len(x) for x in self.enums) else: @@ -1504,9 +1253,7 @@ class Enum(Emulated, String, SchemaType): self._valid_lookup[None] = self._object_lookup[None] = None - super(Enum, self).__init__( - length=length, _expect_unicode=_expect_unicode - ) + super(Enum, self).__init__(length=length) if self.enum_class: kw.setdefault("name", self.enum_class.__name__.lower()) @@ -1615,9 +1362,7 @@ class Enum(Emulated, String, SchemaType): op, other_comparator ) if op is operators.concat_op: - typ = String( - self.type.length, _expect_unicode=self.type._expect_unicode - ) + typ = String(self.type.length) return op, typ comparator_factory = Comparator @@ -1659,7 +1404,6 @@ class Enum(Emulated, String, SchemaType): return util.constructor_copy(self, self._generic_type_affinity, *args) def adapt_to_emulated(self, impltype, **kw): - kw.setdefault("_expect_unicode", self._expect_unicode) kw.setdefault("validate_strings", self.validate_strings) kw.setdefault("name", self.name) kw.setdefault("schema", self.schema) @@ -2605,7 +2349,7 @@ class JSON(Indexable, TypeEngine): @util.memoized_property def _str_impl(self): - return String(_expect_unicode=True) + return String() def bind_processor(self, dialect): string_process = self._str_impl.bind_processor(dialect) diff --git a/lib/sqlalchemy/testing/profiling.py b/lib/sqlalchemy/testing/profiling.py index dd5040205..10344c8d6 100644 --- a/lib/sqlalchemy/testing/profiling.py +++ b/lib/sqlalchemy/testing/profiling.py @@ -105,11 +105,7 @@ class ProfileStatsFile(object): dbapi_key, ] - platform_tokens.append( - "nativeunicode" - if config.db.dialect.convert_unicode - else "dbapiunicode" - ) + platform_tokens.append("dbapiunicode") _has_cext = has_compiled_ext() platform_tokens.append(_has_cext and "cextensions" or "nocextensions") return "_".join(platform_tokens) |