CASSPYTHON-18: removed obsolete check for python version > 3.7+ patch by Brad Schoening; reviewed by Brad Schoening and Bret McGuire
diff --git a/cassandra/cluster.py b/cassandra/cluster.py index 6b2ab4b..72838ee 100644 --- a/cassandra/cluster.py +++ b/cassandra/cluster.py
@@ -1389,7 +1389,7 @@ HostDistance.REMOTE: DEFAULT_MAX_CONNECTIONS_PER_REMOTE_HOST } - self.executor = self._create_thread_pool_executor(max_workers=executor_threads) + self.executor = ThreadPoolExecutor(max_workers=executor_threads) self.scheduler = _Scheduler(self.executor) self._lock = RLock() @@ -1411,42 +1411,6 @@ if application_version is not None: self.application_version = application_version - def _create_thread_pool_executor(self, **kwargs): - """ - Create a ThreadPoolExecutor for the cluster. In most cases, the built-in - `concurrent.futures.ThreadPoolExecutor` is used. - - Python 3.7+ and Eventlet cause the `concurrent.futures.ThreadPoolExecutor` - to hang indefinitely. In that case, the user needs to have the `futurist` - package so we can use the `futurist.GreenThreadPoolExecutor` class instead. - - :param kwargs: All keyword args are passed to the ThreadPoolExecutor constructor. - :return: A ThreadPoolExecutor instance. - """ - tpe_class = ThreadPoolExecutor - if sys.version_info[0] >= 3 and sys.version_info[1] >= 7: - try: - from cassandra.io.eventletreactor import EventletConnection - is_eventlet = issubclass(self.connection_class, EventletConnection) - except: - # Eventlet is not available or can't be detected - return tpe_class(**kwargs) - - if is_eventlet: - try: - from futurist import GreenThreadPoolExecutor - tpe_class = GreenThreadPoolExecutor - except ImportError: - # futurist is not available - raise ImportError( - ("Python 3.7+ and Eventlet cause the `concurrent.futures.ThreadPoolExecutor` " - "to hang indefinitely. If you want to use the Eventlet reactor, you " - "need to install the `futurist` package to allow the driver to use " - "the GreenThreadPoolExecutor. See https://github.com/eventlet/eventlet/issues/508 " - "for more details.")) - - return tpe_class(**kwargs) - def register_user_type(self, keyspace, user_type, klass): """ Registers a class to use to represent a particular user-defined type.
diff --git a/cassandra/query.py b/cassandra/query.py index 40e4d63..04c515d 100644 --- a/cassandra/query.py +++ b/cassandra/query.py
@@ -85,40 +85,6 @@ """ return rows -class PseudoNamedTupleRow(object): - """ - Helper class for pseudo_named_tuple_factory. These objects provide an - __iter__ interface, as well as index- and attribute-based access to values, - but otherwise do not attempt to implement the full namedtuple or iterable - interface. - """ - def __init__(self, ordered_dict): - self._dict = ordered_dict - self._tuple = tuple(ordered_dict.values()) - - def __getattr__(self, name): - return self._dict[name] - - def __getitem__(self, idx): - return self._tuple[idx] - - def __iter__(self): - return iter(self._tuple) - - def __repr__(self): - return '{t}({od})'.format(t=self.__class__.__name__, - od=self._dict) - - -def pseudo_namedtuple_factory(colnames, rows): - """ - Returns each row as a :class:`.PseudoNamedTupleRow`. This is the fallback - factory for cases where :meth:`.named_tuple_factory` fails to create rows. - """ - return [PseudoNamedTupleRow(od) - for od in ordered_dict_factory(colnames, rows)] - - def named_tuple_factory(colnames, rows): """ Returns each row as a `namedtuple <https://docs.python.org/2/library/collections.html#collections.namedtuple>`_. @@ -151,20 +117,6 @@ clean_column_names = map(_clean_column_name, colnames) try: Row = namedtuple('Row', clean_column_names) - except SyntaxError: - warnings.warn( - "Failed creating namedtuple for a result because there were too " - "many columns. This is due to a Python limitation that affects " - "namedtuple in Python 3.0-3.6 (see issue18896). The row will be " - "created with {substitute_factory_name}, which lacks some namedtuple " - "features and is slower. To avoid slower performance accessing " - "values on row objects, Upgrade to Python 3.7, or use a different " - "row factory. (column names: {colnames})".format( - substitute_factory_name=pseudo_namedtuple_factory.__name__, - colnames=colnames - ) - ) - return pseudo_namedtuple_factory(colnames, rows) except Exception: clean_column_names = list(map(_clean_column_name, colnames)) # create list because py3 map object will be consumed by first attempt log.warning("Failed creating named tuple for results with column names %s (cleaned: %s) "
diff --git a/test-requirements.txt b/test-requirements.txt index 513451b..92a888f 100644 --- a/test-requirements.txt +++ b/test-requirements.txt
@@ -9,5 +9,4 @@ eventlet cython>=3.0 packaging -futurist asynctest
diff --git a/tests/__init__.py b/tests/__init__.py index 7799b51..8b41409 100644 --- a/tests/__init__.py +++ b/tests/__init__.py
@@ -77,13 +77,6 @@ from cassandra.io.eventletreactor import EventletConnection connection_class = EventletConnection - - try: - from futurist import GreenThreadPoolExecutor - thread_pool_executor_class = GreenThreadPoolExecutor - except: - # futurist is installed only with python >=3.7 - pass elif "asyncore" in EVENT_LOOP_MANAGER: from cassandra.io.asyncorereactor import AsyncoreConnection connection_class = AsyncoreConnection
diff --git a/tests/integration/advanced/graph/fluent/__init__.py b/tests/integration/advanced/graph/fluent/__init__.py index 1c07cd4..d28fa9d 100644 --- a/tests/integration/advanced/graph/fluent/__init__.py +++ b/tests/integration/advanced/graph/fluent/__init__.py
@@ -585,10 +585,7 @@ typ = int elif any(key.startswith(t) for t in ('long',)): - if sys.version_info >= (3, 0): - typ = int - else: - typ = long + typ = int elif any(key.startswith(t) for t in ('float', 'double')): typ = float elif any(key.startswith(t) for t in ('polygon',)):
diff --git a/tests/integration/cqlengine/base.py b/tests/integration/cqlengine/base.py index 1b99005..321d7b5 100644 --- a/tests/integration/cqlengine/base.py +++ b/tests/integration/cqlengine/base.py
@@ -15,14 +15,13 @@ # limitations under the License. import unittest -import sys - from cassandra.cqlengine.connection import get_session from cassandra.cqlengine.models import Model from cassandra.cqlengine import columns from uuid import uuid4 + class TestQueryUpdateModel(Model): partition = columns.UUID(primary_key=True, default=uuid4) @@ -33,6 +32,7 @@ text_list = columns.List(columns.Text, required=False) text_map = columns.Map(columns.Text, columns.Text, required=False) + class BaseCassEngTestCase(unittest.TestCase): session = None @@ -48,6 +48,5 @@ self.assertFalse(hasattr(obj, attr), "{0} shouldn't have the attribute: {1}".format(obj, attr)) - if sys.version_info > (3, 0): - def assertItemsEqual(self, first, second, msg=None): - return self.assertCountEqual(first, second, msg) + def assertItemsEqual(self, first, second, msg=None): + return self.assertCountEqual(first, second, msg)
diff --git a/tests/integration/cqlengine/columns/test_validation.py b/tests/integration/cqlengine/columns/test_validation.py index 48ae74b..5c3a20e 100644 --- a/tests/integration/cqlengine/columns/test_validation.py +++ b/tests/integration/cqlengine/columns/test_validation.py
@@ -61,6 +61,7 @@ class TZ(tzinfo): def utcoffset(self, date_time): return timedelta(hours=-1) + def dst(self, date_time): return None @@ -91,7 +92,7 @@ self.assertIsNone(dts[0][0]) def test_datetime_invalid(self): - dt_value= 'INVALID' + dt_value = 'INVALID' with self.assertRaises(TypeError): self.DatetimeTest.objects.create(test_id=4, created_at=dt_value) @@ -125,7 +126,7 @@ dt_truncated = datetime(2024, 12, 31, 10, 10, 10, 923000) self.DatetimeTest.objects.create(test_id=6, created_at=dt_value) dt2 = self.DatetimeTest.objects(test_id=6).first() - self.assertEqual(dt2.created_at,dt_truncated) + self.assertEqual(dt2.created_at, dt_truncated) finally: # We need to always return behavior to default DateTime.truncate_microseconds = False @@ -191,7 +192,7 @@ self.VarIntTest.objects.create(test_id=0, bignum="not_a_number") -class DataType(): +class DataType: @classmethod def setUpClass(cls): if PROTOCOL_VERSION < 4 or CASSANDRA_VERSION < Version("3.0"): @@ -344,6 +345,7 @@ ) super(TestBoolean, cls).setUpClass() + @greaterthanorequalcass3_11 class TestDuration(DataType, BaseCassEngTestCase): @classmethod @@ -507,7 +509,7 @@ class TestInteger(BaseCassEngTestCase): class IntegerTest(Model): - test_id = UUID(primary_key=True, default=lambda:uuid4()) + test_id = UUID(primary_key=True, default=lambda: uuid4()) value = Integer(default=0, required=True) def test_default_zero_fields_validate(self): @@ -519,8 +521,8 @@ class TestBigInt(BaseCassEngTestCase): class BigIntTest(Model): - test_id = UUID(primary_key=True, default=lambda:uuid4()) - value = BigInt(default=0, required=True) + test_id = UUID(primary_key=True, default=lambda: uuid4()) + value = BigInt(default=0, required=True) def test_default_zero_fields_validate(self): """ Tests that bigint columns with a default value of 0 validate """ @@ -612,10 +614,6 @@ with self.assertRaises(ValidationError): Ascii().validate('Beyonc' + chr(233)) - if sys.version_info < (3, 1): - with self.assertRaises(ValidationError): - Ascii().validate(u'Beyonc' + unichr(233)) - def test_unaltering_validation(self): """ Test the validation step doesn't re-interpret values. """ self.assertEqual(Ascii().validate(''), '') @@ -736,8 +734,6 @@ Text().validate("!#$%&\'()*+,-./") Text().validate('Beyonc' + chr(233)) - if sys.version_info < (3, 1): - Text().validate(u'Beyonc' + unichr(233)) def test_unaltering_validation(self): """ Test the validation step doesn't re-interpret values. """ @@ -810,7 +806,7 @@ from uuid import UUID assert isinstance(uuid, UUID) - ts = (uuid.time - 0x01b21dd213814000) / 1e7 # back to a timestamp + ts = (uuid.time - 0x01b21dd213814000) / 1e7 # back to a timestamp new_dt = datetime.fromtimestamp(ts, tz=timezone.utc).replace(tzinfo=None) # checks that we created a UUID1 with the proper timestamp
diff --git a/tests/integration/standard/test_metadata.py b/tests/integration/standard/test_metadata.py index 8f7ba04..4990f17 100644 --- a/tests/integration/standard/test_metadata.py +++ b/tests/integration/standard/test_metadata.py
@@ -1087,14 +1087,6 @@ Test udt exports """ - if PROTOCOL_VERSION < 3: - raise unittest.SkipTest( - "Protocol 3.0+ is required for UDT change events, currently testing against %r" - % (PROTOCOL_VERSION,)) - - if sys.version_info[0:2] != (2, 7): - raise unittest.SkipTest('This test compares static strings generated from dict items, which may change orders. Test with 2.7.') - cluster = TestCluster() session = cluster.connect() @@ -1591,7 +1583,7 @@ with self.VerifiedFunction(self, **kwargs) as vf: fn_meta = self.keyspace_function_meta[vf.signature] - self.assertRegex(fn_meta.as_cql_query(), "CREATE FUNCTION.*%s\(\) .*" % kwargs['name']) + self.assertRegex(fn_meta.as_cql_query(), r"CREATE FUNCTION.*%s\(\) .*" % kwargs['name']) def test_functions_follow_keyspace_alter(self): """ @@ -1639,12 +1631,12 @@ kwargs['called_on_null_input'] = True with self.VerifiedFunction(self, **kwargs) as vf: fn_meta = self.keyspace_function_meta[vf.signature] - self.assertRegex(fn_meta.as_cql_query(), "CREATE FUNCTION.*\) CALLED ON NULL INPUT RETURNS .*") + self.assertRegex(fn_meta.as_cql_query(), r"CREATE FUNCTION.*\) CALLED ON NULL INPUT RETURNS .*") kwargs['called_on_null_input'] = False with self.VerifiedFunction(self, **kwargs) as vf: fn_meta = self.keyspace_function_meta[vf.signature] - self.assertRegex(fn_meta.as_cql_query(), "CREATE FUNCTION.*\) RETURNS NULL ON NULL INPUT RETURNS .*") + self.assertRegex(fn_meta.as_cql_query(), r"CREATE FUNCTION.*\) RETURNS NULL ON NULL INPUT RETURNS .*") class AggregateMetadata(FunctionTest):
diff --git a/tests/unit/advanced/test_insights.py b/tests/unit/advanced/test_insights.py index e6be6fc..aae1787 100644 --- a/tests/unit/advanced/test_insights.py +++ b/tests/unit/advanced/test_insights.py
@@ -18,7 +18,6 @@ import unittest import logging -import sys from unittest.mock import sentinel from cassandra import ConsistencyLevel @@ -32,7 +31,6 @@ from cassandra.datastax.graph.query import GraphOptions from cassandra.datastax.insights.registry import insights_registry from cassandra.datastax.insights.serializers import initialize_registry -from cassandra.datastax.insights.util import namespace from cassandra.policies import ( RoundRobinPolicy, LoadBalancingPolicy, @@ -63,8 +61,7 @@ obj = NoConfAsDict() ns = 'tests.unit.advanced.test_insights' - if sys.version_info > (3,): - ns += '.TestGetConfig.test_invalid_object.<locals>' + ns += '.TestGetConfig.test_invalid_object.<locals>' # no default # ... as a policy @@ -102,6 +99,7 @@ self.assertIs(insights_registry.serialize(SubclassSentinel(), default=object()), sentinel.serialized_superclass) + class TestConfigAsDict(unittest.TestCase): # graph/query.py @@ -253,8 +251,8 @@ self.assertEqual( insights_registry.serialize(ConstantReconnectionPolicy(3, 200)), {'type': 'ConstantReconnectionPolicy', - 'namespace': 'cassandra.policies', - 'options': {'delay': 3, 'max_attempts': 200} + 'namespace': 'cassandra.policies', + 'options': {'delay': 3, 'max_attempts': 200} } ) @@ -262,8 +260,8 @@ self.assertEqual( insights_registry.serialize(ExponentialReconnectionPolicy(4, 100, 10)), {'type': 'ExponentialReconnectionPolicy', - 'namespace': 'cassandra.policies', - 'options': {'base_delay': 4, 'max_delay': 100, 'max_attempts': 10} + 'namespace': 'cassandra.policies', + 'options': {'base_delay': 4, 'max_delay': 100, 'max_attempts': 10} } ) @@ -271,8 +269,8 @@ self.assertEqual( insights_registry.serialize(RetryPolicy()), {'type': 'RetryPolicy', - 'namespace': 'cassandra.policies', - 'options': {} + 'namespace': 'cassandra.policies', + 'options': {} } ) @@ -280,8 +278,8 @@ self.assertEqual( insights_registry.serialize(SpeculativeExecutionPolicy()), {'type': 'SpeculativeExecutionPolicy', - 'namespace': 'cassandra.policies', - 'options': {} + 'namespace': 'cassandra.policies', + 'options': {} } )
diff --git a/tests/unit/test_policies.py b/tests/unit/test_policies.py index 792268c..90c9a4b 100644 --- a/tests/unit/test_policies.py +++ b/tests/unit/test_policies.py
@@ -909,7 +909,7 @@ if i == 0: self._assert_between(delay, base_delay*0.85, base_delay*1.15) elif i < 6: - value = base_delay * (2 ** i) + value = base_delay * (2 ** i) self._assert_between(delay, value*85/100, value*1.15) else: self._assert_between(delay, max_delay*85/100, max_delay*1.15) @@ -956,7 +956,7 @@ """ for i in range(100): base_delay = float(randint(2, 5)) - max_delay = (base_delay - 1) * 100.0 + max_delay = (base_delay - 1) * 100.0 ep = ExponentialReconnectionPolicy(base_delay, max_delay, max_attempts=64) schedule = ep.new_schedule() for i in range(64): @@ -1467,13 +1467,12 @@ # We don't allow randomness for ordering the replicas in RoundRobin hfp._child_policy._child_policy._position = 0 - mocked_query = Mock() query_plan = hfp.make_query_plan("keyspace", mocked_query) # First the not filtered replica, and then the rest of the allowed hosts ordered query_plan = list(query_plan) self.assertEqual(query_plan[0], Host(DefaultEndPoint("127.0.0.2"), SimpleConvictionPolicy)) - self.assertEqual(set(query_plan[1:]),{Host(DefaultEndPoint("127.0.0.3"), SimpleConvictionPolicy), + self.assertEqual(set(query_plan[1:]), {Host(DefaultEndPoint("127.0.0.3"), SimpleConvictionPolicy), Host(DefaultEndPoint("127.0.0.5"), SimpleConvictionPolicy)}) def test_create_whitelist(self):
diff --git a/tests/unit/test_row_factories.py b/tests/unit/test_row_factories.py deleted file mode 100644 index 0055497..0000000 --- a/tests/unit/test_row_factories.py +++ /dev/null
@@ -1,89 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -from cassandra.query import named_tuple_factory - -import logging -import warnings - -import sys - -from unittest import TestCase - - -log = logging.getLogger(__name__) - - -NAMEDTUPLE_CREATION_BUG = sys.version_info >= (3,) and sys.version_info < (3, 7) - -class TestNamedTupleFactory(TestCase): - - long_colnames, long_rows = ( - ['col{}'.format(x) for x in range(300)], - [ - ['value{}'.format(x) for x in range(300)] - for _ in range(100) - ] - ) - short_colnames, short_rows = ( - ['col{}'.format(x) for x in range(200)], - [ - ['value{}'.format(x) for x in range(200)] - for _ in range(100) - ] - ) - - def test_creation_warning_on_long_column_list(self): - """ - Reproduces the failure described in PYTHON-893 - - @since 3.15 - @jira_ticket PYTHON-893 - @expected_result creation fails on Python > 3 and < 3.7 - - @test_category row_factory - """ - if not NAMEDTUPLE_CREATION_BUG: - named_tuple_factory(self.long_colnames, self.long_rows) - return - - with warnings.catch_warnings(record=True) as w: - rows = named_tuple_factory(self.long_colnames, self.long_rows) - self.assertEqual(len(w), 1) - warning = w[0] - self.assertIn('pseudo_namedtuple_factory', str(warning)) - self.assertIn('3.7', str(warning)) - - for r in rows: - self.assertEqual(r.col0, self.long_rows[0][0]) - - def test_creation_no_warning_on_short_column_list(self): - """ - Tests that normal namedtuple row creation still works after PYTHON-893 fix - - @since 3.15 - @jira_ticket PYTHON-893 - @expected_result creates namedtuple-based Rows - - @test_category row_factory - """ - with warnings.catch_warnings(record=True) as w: - rows = named_tuple_factory(self.short_colnames, self.short_rows) - self.assertEqual(len(w), 0) - # check that this is a real namedtuple - self.assertTrue(hasattr(rows[0], '_fields')) - self.assertIsInstance(rows[0], tuple)
diff --git a/tox.ini b/tox.ini index 19e6106..0a494b2 100644 --- a/tox.ini +++ b/tox.ini
@@ -10,7 +10,6 @@ twisted[tls] pure-sasl kerberos - futurist lz4 cryptography>=42.0