This is an automated email from the ASF dual-hosted git repository.
absurdfarce pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-python-driver.git
The following commit(s) were added to refs/heads/trunk by this push:
new 2ff1672a CASSPYTHON-18: removed obsolete check for python version >
3.7+
2ff1672a is described below
commit 2ff1672ab2b1a3fa4eff5785dc2845006740bcb4
Author: Brad Schoening <[email protected]>
AuthorDate: Mon Apr 27 16:08:41 2026 -0400
CASSPYTHON-18: removed obsolete check for python version > 3.7+
patch by Brad Schoening; reviewed by Brad Schoening and Bret McGuire
---
cassandra/cluster.py | 38 +--------
cassandra/query.py | 48 ------------
test-requirements.txt | 1 -
tests/__init__.py | 7 --
.../integration/advanced/graph/fluent/__init__.py | 5 +-
tests/integration/cqlengine/base.py | 9 +--
.../cqlengine/columns/test_validation.py | 22 +++---
tests/integration/standard/test_metadata.py | 14 +---
tests/unit/advanced/test_insights.py | 22 +++---
tests/unit/test_policies.py | 7 +-
tests/unit/test_row_factories.py | 89 ----------------------
tox.ini | 1 -
12 files changed, 31 insertions(+), 232 deletions(-)
diff --git a/cassandra/cluster.py b/cassandra/cluster.py
index 6b2ab4b2..72838ee1 100644
--- a/cassandra/cluster.py
+++ b/cassandra/cluster.py
@@ -1389,7 +1389,7 @@ class Cluster(object):
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 @@ class Cluster(object):
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 40e4d63c..04c515d6 100644
--- a/cassandra/query.py
+++ b/cassandra/query.py
@@ -85,40 +85,6 @@ def tuple_factory(colnames, rows):
"""
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 @@ def named_tuple_factory(colnames, rows):
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 513451b4..92a888fe 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -9,5 +9,4 @@ gevent
eventlet
cython>=3.0
packaging
-futurist
asynctest
diff --git a/tests/__init__.py b/tests/__init__.py
index 7799b513..8b41409c 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -77,13 +77,6 @@ elif "eventlet" in EVENT_LOOP_MANAGER:
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 1c07cd46..d28fa9d3 100644
--- a/tests/integration/advanced/graph/fluent/__init__.py
+++ b/tests/integration/advanced/graph/fluent/__init__.py
@@ -585,10 +585,7 @@ def _validate_prop(key, value, unittest):
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 1b99005f..321d7b5b 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 @@ class TestQueryUpdateModel(Model):
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 @@ class BaseCassEngTestCase(unittest.TestCase):
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 48ae74b5..5c3a20eb 100644
--- a/tests/integration/cqlengine/columns/test_validation.py
+++ b/tests/integration/cqlengine/columns/test_validation.py
@@ -61,6 +61,7 @@ class TestDatetime(BaseCassEngTestCase):
class TZ(tzinfo):
def utcoffset(self, date_time):
return timedelta(hours=-1)
+
def dst(self, date_time):
return None
@@ -91,7 +92,7 @@ class TestDatetime(BaseCassEngTestCase):
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 @@ class TestDatetime(BaseCassEngTestCase):
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 @@ class TestVarInt(BaseCassEngTestCase):
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 @@ class TestBoolean(DataType, BaseCassEngTestCase):
)
super(TestBoolean, cls).setUpClass()
+
@greaterthanorequalcass3_11
class TestDuration(DataType, BaseCassEngTestCase):
@classmethod
@@ -507,7 +509,7 @@ class TestTimeUUID(BaseCassEngTestCase):
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 TestInteger(BaseCassEngTestCase):
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 @@ class TestAscii(BaseCassEngTestCase):
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 @@ class TestText(BaseCassEngTestCase):
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 @@ class TestTimeUUIDFromDatetime(BaseCassEngTestCase):
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 8f7ba048..4990f176 100644
--- a/tests/integration/standard/test_metadata.py
+++ b/tests/integration/standard/test_metadata.py
@@ -1087,14 +1087,6 @@ class TestCodeCoverage(unittest.TestCase):
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 @@ class FunctionMetadata(FunctionTest):
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 @@ class FunctionMetadata(FunctionTest):
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 e6be6fc3..aae17879 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.cluster import (
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 @@ class TestGetConfig(unittest.TestCase):
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 @@ class TestGetConfig(unittest.TestCase):
self.assertIs(insights_registry.serialize(SubclassSentinel(),
default=object()),
sentinel.serialized_superclass)
+
class TestConfigAsDict(unittest.TestCase):
# graph/query.py
@@ -253,8 +251,8 @@ class TestConfigAsDict(unittest.TestCase):
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 @@ class TestConfigAsDict(unittest.TestCase):
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 @@ class TestConfigAsDict(unittest.TestCase):
self.assertEqual(
insights_registry.serialize(RetryPolicy()),
{'type': 'RetryPolicy',
- 'namespace': 'cassandra.policies',
- 'options': {}
+ 'namespace': 'cassandra.policies',
+ 'options': {}
}
)
@@ -280,8 +278,8 @@ class TestConfigAsDict(unittest.TestCase):
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 792268cd..90c9a4b3 100644
--- a/tests/unit/test_policies.py
+++ b/tests/unit/test_policies.py
@@ -909,7 +909,7 @@ class ExponentialReconnectionPolicyTest(unittest.TestCase):
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 @@ class ExponentialReconnectionPolicyTest(unittest.TestCase):
"""
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 @@ class HostFilterPolicyQueryPlanTest(unittest.TestCase):
# 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 0055497a..00000000
--- 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 19e61061..0a494b26 100644
--- a/tox.ini
+++ b/tox.ini
@@ -10,7 +10,6 @@ deps = pytest
twisted[tls]
pure-sasl
kerberos
- futurist
lz4
cryptography>=42.0
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]