diff --git a/lower-constraints.txt b/lower-constraints.txt index 3fef2eb6..6e34d7ba 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -52,7 +52,6 @@ PyYAML==3.12 requests==2.14.2 requestsexceptions==1.2.0 rfc3986==0.3.1 -six==1.10.0 smmap==0.9.0 SQLAlchemy==1.2.0 sqlalchemy-migrate==0.11.0 diff --git a/oslo_db/api.py b/oslo_db/api.py index 7f927569..fc52113d 100644 --- a/oslo_db/api.py +++ b/oslo_db/api.py @@ -23,6 +23,7 @@ takes no arguments. The method can return any object that implements DB API methods. """ +import functools import logging import random import threading @@ -31,7 +32,6 @@ import time from oslo_utils import excutils from oslo_utils import importutils from oslo_utils import reflection -import six from oslo_db import exception from oslo_db import options @@ -132,7 +132,7 @@ class wrap_db_retry(object): self.max_retry_interval = max_retry_interval def __call__(self, f): - @six.wraps(f) + @functools.wraps(f) def wrapper(*args, **kwargs): sleep_time = next_interval = self.retry_interval remaining = self.max_retries diff --git a/oslo_db/exception.py b/oslo_db/exception.py index ee6bbb2e..2db34ef7 100644 --- a/oslo_db/exception.py +++ b/oslo_db/exception.py @@ -45,7 +45,6 @@ database errors. from debtcollector import moves from oslo_utils.excutils import CausedByException -import six from oslo_db._i18n import _ from oslo_db import warning @@ -61,7 +60,7 @@ class DBError(CausedByException): def __init__(self, inner_exception=None, cause=None): self.inner_exception = inner_exception - super(DBError, self).__init__(six.text_type(inner_exception), cause) + super(DBError, self).__init__(str(inner_exception), cause) class DBDuplicateEntry(DBError): diff --git a/oslo_db/sqlalchemy/enginefacade.py b/oslo_db/sqlalchemy/enginefacade.py index efe947ed..b56883fe 100644 --- a/oslo_db/sqlalchemy/enginefacade.py +++ b/oslo_db/sqlalchemy/enginefacade.py @@ -634,7 +634,6 @@ class _TransactionContext(object): # TODO(zzzeek) do we need save_and_reraise() here, # or do newer eventlets not have issues? we are using # raw "raise" in many other places in oslo.db already - # (and one six.reraise()). raise finally: self.transaction = None diff --git a/oslo_db/sqlalchemy/engines.py b/oslo_db/sqlalchemy/engines.py index 999d4c3b..25215b96 100644 --- a/oslo_db/sqlalchemy/engines.py +++ b/oslo_db/sqlalchemy/engines.py @@ -21,9 +21,9 @@ import logging import os import re import time +from urllib import parse import debtcollector.renames -import six import sqlalchemy from sqlalchemy import event from sqlalchemy import exc @@ -105,7 +105,7 @@ def _setup_logging(connection_debug=0): def _extend_url_parameters(url, connection_parameters): - for key, value in six.moves.urllib.parse.parse_qs( + for key, value in parse.parse_qs( connection_parameters).items(): if key in url.query: existing = url.query[key] @@ -262,10 +262,7 @@ def _init_connection_args(url, engine_args, **kw): # to internal usage of Python unicode objects in the driver # http://docs.sqlalchemy.org/en/rel_0_9/dialects/mysql.html if 'use_unicode' not in url.query: - if six.PY3: - engine_args['connect_args']['use_unicode'] = 1 - else: - engine_args['connect_args']['use_unicode'] = 0 + engine_args['connect_args']['use_unicode'] = 1 @utils.dispatch_for_dialect('*', multiple=True) @@ -327,7 +324,7 @@ def _init_events(engine, sqlite_synchronous=True, sqlite_fk=False, **kw): def regexp(expr, item): reg = re.compile(expr) - return reg.search(six.text_type(item)) is not None + return reg.search(str(item)) is not None @sqlalchemy.event.listens_for(engine, "connect") def _sqlite_connect_events(dbapi_con, con_record): @@ -369,7 +366,7 @@ def _test_connection(engine, max_retries, retry_interval): if max_retries == -1: attempts = itertools.count() else: - attempts = six.moves.range(max_retries) + attempts = range(max_retries) # See: http://legacy.python.org/dev/peps/pep-3110/#semantic-changes for # why we are not using 'de' directly (it can be removed from the local # scope). @@ -384,7 +381,7 @@ def _test_connection(engine, max_retries, retry_interval): de_ref = de else: if de_ref is not None: - six.reraise(type(de_ref), de_ref) + raise de_ref def _add_process_guards(engine): diff --git a/oslo_db/sqlalchemy/migration_cli/ext_base.py b/oslo_db/sqlalchemy/migration_cli/ext_base.py index 184003d2..903edd37 100644 --- a/oslo_db/sqlalchemy/migration_cli/ext_base.py +++ b/oslo_db/sqlalchemy/migration_cli/ext_base.py @@ -12,11 +12,8 @@ import abc -import six - -@six.add_metaclass(abc.ABCMeta) -class MigrationExtensionBase(object): +class MigrationExtensionBase(object, metaclass=abc.ABCMeta): # used to sort migration in logical order order = 0 diff --git a/oslo_db/sqlalchemy/models.py b/oslo_db/sqlalchemy/models.py index 6fa0f6f3..2bad0f57 100644 --- a/oslo_db/sqlalchemy/models.py +++ b/oslo_db/sqlalchemy/models.py @@ -20,8 +20,6 @@ SQLAlchemy models. """ -import six - from oslo_utils import timeutils from sqlalchemy import Column from sqlalchemy import DateTime @@ -30,7 +28,7 @@ from sqlalchemy.orm import object_mapper from oslo_db.sqlalchemy import types -class ModelBase(six.Iterator): +class ModelBase(object): """Base class for models.""" __table_initialized__ = False @@ -119,7 +117,7 @@ class ModelBase(six.Iterator): return [key for key, value in self.iteritems()] -class ModelIterator(six.Iterator): +class ModelIterator(object): def __init__(self, model, columns): self.model = model @@ -128,9 +126,8 @@ class ModelIterator(six.Iterator): def __iter__(self): return self - # In Python 3, __next__() has replaced next(). def __next__(self): - n = six.advance_iterator(self.i) + n = next(self.i) return n, getattr(self.model, n) diff --git a/oslo_db/sqlalchemy/provision.py b/oslo_db/sqlalchemy/provision.py index fb1e1917..2fc3a543 100644 --- a/oslo_db/sqlalchemy/provision.py +++ b/oslo_db/sqlalchemy/provision.py @@ -23,8 +23,6 @@ import random import re import string -import six -from six import moves import sqlalchemy from sqlalchemy.engine import url as sa_url from sqlalchemy import schema @@ -370,8 +368,7 @@ class Backend(object): Backend(database_type, url) -@six.add_metaclass(abc.ABCMeta) -class BackendImpl(object): +class BackendImpl(object, metaclass=abc.ABCMeta): """Provide database-specific implementations of key provisioning functions. @@ -627,9 +624,7 @@ class PostgresqlBackendImpl(BackendImpl): def _random_ident(): - return ''.join( - random.choice(string.ascii_lowercase) - for i in moves.range(10)) + return ''.join(random.choice(string.ascii_lowercase) for i in range(10)) Backend._setup() diff --git a/oslo_db/sqlalchemy/test_base.py b/oslo_db/sqlalchemy/test_base.py index 8c6fdbd5..b437c3ca 100644 --- a/oslo_db/sqlalchemy/test_base.py +++ b/oslo_db/sqlalchemy/test_base.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. +import functools + import debtcollector import debtcollector.moves import fixtures @@ -26,7 +28,6 @@ except ImportError: from oslo_utils import reflection -import six from oslo_db import exception from oslo_db.sqlalchemy import enginefacade @@ -200,6 +201,7 @@ class DbTestCase(test_base.BaseTestCase): class OpportunisticTestCase(DbTestCase): """Placeholder for backwards compatibility.""" + ALLOWED_DIALECTS = ['sqlite', 'mysql', 'postgresql'] @@ -209,7 +211,7 @@ def backend_specific(*dialects): ::dialects: list of dialects names under which the test will be launched. """ def wrap(f): - @six.wraps(f) + @functools.wraps(f) def ins_wrap(self): if not set(dialects).issubset(ALLOWED_DIALECTS): raise ValueError( diff --git a/oslo_db/sqlalchemy/test_migrations.py b/oslo_db/sqlalchemy/test_migrations.py index 8c8484b5..07d058ba 100644 --- a/oslo_db/sqlalchemy/test_migrations.py +++ b/oslo_db/sqlalchemy/test_migrations.py @@ -24,7 +24,6 @@ import alembic import alembic.autogenerate import alembic.migration import pkg_resources as pkg -import six import sqlalchemy import sqlalchemy.exc import sqlalchemy.sql.expression as expr @@ -37,8 +36,7 @@ from oslo_db.sqlalchemy import utils LOG = logging.getLogger(__name__) -@six.add_metaclass(abc.ABCMeta) -class WalkVersionsMixin(object): +class WalkVersionsMixin(object, metaclass=abc.ABCMeta): """Test mixin to check upgrade and downgrade ability of migration. This is only suitable for testing of migrate_ migration scripts. An @@ -274,8 +272,7 @@ class WalkVersionsMixin(object): raise -@six.add_metaclass(abc.ABCMeta) -class ModelsMigrationsSync(object): +class ModelsMigrationsSync(object, metaclass=abc.ABCMeta): """A helper class for comparison of DB migration scripts and models. It's intended to be inherited by test cases in target projects. They have diff --git a/oslo_db/sqlalchemy/utils.py b/oslo_db/sqlalchemy/utils.py index 02992f0a..b7e101e5 100644 --- a/oslo_db/sqlalchemy/utils.py +++ b/oslo_db/sqlalchemy/utils.py @@ -17,12 +17,7 @@ # under the License. import collections -# TODO(smcginnis) update this once six has support for collections.abc -# (https://github.com/benjaminp/six/pull/241) or clean up once we drop py2.7. -try: - from collections.abc import Iterable -except ImportError: - from collections import Iterable +from collections import abc import contextlib import inspect as pyinspect import itertools @@ -32,7 +27,6 @@ import re from alembic.migration import MigrationContext from alembic.operations import Operations from oslo_utils import timeutils -import six import sqlalchemy from sqlalchemy import Boolean from sqlalchemy import CheckConstraint @@ -286,7 +280,7 @@ def paginate_query(query, model, limit, sort_keys, marker=None, def to_list(x, default=None): if x is None: return default - if not isinstance(x, Iterable) or isinstance(x, six.string_types): + if not isinstance(x, abc.Iterable) or isinstance(x, str): return [x] elif isinstance(x, list): return x @@ -941,7 +935,7 @@ class DialectFunctionDispatcher(object): def _url_from_target(self, target): if isinstance(target, Connectable): return target.engine.url - elif isinstance(target, six.string_types): + elif isinstance(target, str): if "://" not in target: target_url = sa_url.make_url("%s://" % target) else: diff --git a/oslo_db/tests/sqlalchemy/test_exc_filters.py b/oslo_db/tests/sqlalchemy/test_exc_filters.py index 6b3782a3..4ba03c1e 100644 --- a/oslo_db/tests/sqlalchemy/test_exc_filters.py +++ b/oslo_db/tests/sqlalchemy/test_exc_filters.py @@ -19,7 +19,6 @@ import itertools import mock from oslotest import base as oslo_test_base -import six import sqlalchemy as sqla from sqlalchemy.engine import url as sqla_url from sqlalchemy import event @@ -53,11 +52,8 @@ class _SQLAExceptionMatcher(object): self.assertEqual(exception_type, exc.__class__.__name__) if isinstance(message, tuple): self.assertEqual( - [m.lower() - if isinstance(m, six.string_types) else m for m in message], - [a.lower() - if isinstance(a, six.string_types) else a - for a in exc.orig.args] + [m.lower() if isinstance(m, str) else m for m in message], + [a.lower() if isinstance(a, str) else a for a in exc.orig.args] ) else: self.assertEqual(message.lower(), str(exc.orig).lower()) @@ -227,14 +223,14 @@ class TestFallthroughsAndNonDBAPI(TestsExceptionFilter): # or at least not documented anywhere. uee_ref = None try: - six.u('\u2435').encode('ascii') + '\u2435'.encode('ascii') except UnicodeEncodeError as uee: # Python3.x added new scoping rules here (sadly) # http://legacy.python.org/dev/peps/pep-3110/#semantic-changes uee_ref = uee self._run_test( - "postgresql", six.u('select \u2435'), + 'postgresql', 'select \u2435', uee_ref, exception.DBInvalidUnicodeParameter ) @@ -738,42 +734,6 @@ class TestExceptionCauseMySQLSavepoint(test_base._MySQLOpportunisticTestCase): assert False, "no exception raised" -class TestDBDataErrorSQLite(_SQLAExceptionMatcher, test_base._DbTestCase): - - def setUp(self): - super(TestDBDataErrorSQLite, self).setUp() - - if six.PY3: - self.skipTest("SQLite database supports unicode value for python3") - - meta = sqla.MetaData(bind=self.engine) - - self.table_1 = sqla.Table( - "resource_foo", meta, - sqla.Column("name", sqla.String), - ) - self.table_1.create() - - def test_raise(self): - - matched = self.assertRaises( - exception.DBDataError, - self.engine.execute, - self.table_1.insert({'name': u'\u2713'.encode('utf-8')}) - ) - - self.assertInnerException( - matched, - "ProgrammingError", - "You must not use 8-bit bytestrings unless you use a " - "text_factory that can interpret 8-bit bytestrings " - "(like text_factory = str). It is highly recommended that " - "you instead just switch your application to Unicode strings.", - "INSERT INTO resource_foo (name) VALUES (?)", - (u'\u2713'.encode('utf-8'),) - ) - - class TestConstraint(TestsExceptionFilter): def test_postgresql(self): matched = self._run_test( diff --git a/oslo_db/tests/sqlalchemy/test_migrations.py b/oslo_db/tests/sqlalchemy/test_migrations.py index 17cdf8e6..5d27b074 100644 --- a/oslo_db/tests/sqlalchemy/test_migrations.py +++ b/oslo_db/tests/sqlalchemy/test_migrations.py @@ -18,7 +18,6 @@ import fixtures from migrate.versioning import api as versioning_api import mock from oslotest import base as test -import six import sqlalchemy as sa import sqlalchemy.ext.declarative as sa_decl @@ -304,8 +303,7 @@ class ModelsMigrationSyncMixin(test_base._DbTestCase): ] filter_mock.side_effect = filter_diffs - msg = six.text_type(self.assertRaises(AssertionError, - self.test_models_sync)) + msg = str(self.assertRaises(AssertionError, self.test_models_sync)) self.assertNotIn('defaulttest', msg) self.assertNotIn('defaulttest3', msg) self.assertNotIn('remove_fk', msg) @@ -342,8 +340,7 @@ class ModelsMigrationSyncMixin(test_base._DbTestCase): mysql_engine='InnoDB' ) - msg = six.text_type(self.assertRaises(AssertionError, - self.test_models_sync)) + msg = str(self.assertRaises(AssertionError, self.test_models_sync)) # NOTE(I159): Check mentioning of the table and columns. # The log is invalid json, so we can't parse it and check it for # full compliance. We have no guarantee of the log items ordering, diff --git a/oslo_db/tests/sqlalchemy/test_models.py b/oslo_db/tests/sqlalchemy/test_models.py index 302a9945..1c7339eb 100644 --- a/oslo_db/tests/sqlalchemy/test_models.py +++ b/oslo_db/tests/sqlalchemy/test_models.py @@ -13,12 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. -# TODO(smcginnis) update this once six has support for collections.abc -# (https://github.com/benjaminp/six/pull/241) or clean up once we drop py2.7. -try: - from collections.abc import Iterable -except ImportError: - from collections import Iterable +from collections import abc import datetime import mock @@ -56,7 +51,7 @@ class ModelBaseTest(test_base._DbTestCase): "Method %s() is not found" % method) def test_modelbase_is_iterable(self): - self.assertTrue(issubclass(models.ModelBase, Iterable)) + self.assertTrue(issubclass(models.ModelBase, abc.Iterable)) def test_modelbase_set(self): self.mb['world'] = 'hello' diff --git a/oslo_db/tests/sqlalchemy/test_sqlalchemy.py b/oslo_db/tests/sqlalchemy/test_sqlalchemy.py index 9ebf58c2..bde73030 100644 --- a/oslo_db/tests/sqlalchemy/test_sqlalchemy.py +++ b/oslo_db/tests/sqlalchemy/test_sqlalchemy.py @@ -24,7 +24,6 @@ import fixtures import mock from oslo_config import cfg from oslotest import base as oslo_test -import six import sqlalchemy from sqlalchemy import Column, MetaData, Table from sqlalchemy.engine import url @@ -683,12 +682,8 @@ class CreateEngineTest(oslo_test.BaseTestCase): self.assertNotIn('poolclass', self.args) def _test_mysql_connect_args_default(self, connect_args): - if six.PY3: - self.assertEqual({'charset': 'utf8', 'use_unicode': 1}, - connect_args) - else: - self.assertEqual({'charset': 'utf8', 'use_unicode': 0}, - connect_args) + self.assertEqual({'charset': 'utf8', 'use_unicode': 1}, + connect_args) def test_mysql_connect_args_default(self): engines._init_connection_args( diff --git a/oslo_db/tests/sqlalchemy/test_utils.py b/oslo_db/tests/sqlalchemy/test_utils.py index f193dfd5..4ca09e1c 100644 --- a/oslo_db/tests/sqlalchemy/test_utils.py +++ b/oslo_db/tests/sqlalchemy/test_utils.py @@ -13,10 +13,11 @@ # License for the specific language governing permissions and limitations # under the License. +from urllib import parse + import fixtures import mock from oslotest import base as test_base -from six.moves.urllib import parse import sqlalchemy from sqlalchemy.dialects import mysql from sqlalchemy import Boolean, Index, Integer, DateTime, String, SmallInteger diff --git a/oslo_db/tests/utils.py b/oslo_db/tests/utils.py index bbf1fa81..c7e1e1f1 100644 --- a/oslo_db/tests/utils.py +++ b/oslo_db/tests/utils.py @@ -17,16 +17,12 @@ import contextlib from oslo_config import cfg from oslotest import base as test_base -import six -if six.PY3: - @contextlib.contextmanager - def nested(*contexts): - with contextlib.ExitStack() as stack: - yield [stack.enter_context(c) for c in contexts] -else: - nested = contextlib.nested +@contextlib.contextmanager +def nested(*contexts): + with contextlib.ExitStack() as stack: + yield [stack.enter_context(c) for c in contexts] class BaseTestCase(test_base.BaseTestCase): diff --git a/requirements.txt b/requirements.txt index c4cd79b2..bf998e10 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,6 @@ oslo.utils>=3.33.0 # Apache-2.0 SQLAlchemy>=1.2.0 # MIT sqlalchemy-migrate>=0.11.0 # Apache-2.0 stevedore>=1.20.0 # Apache-2.0 -six>=1.10.0 # MIT # these are used by downstream libraries that require # oslo.db as one of their test requirements - do not remove! testresources>=2.0.0 # Apache-2.0/BSD