Skip to content

CASSPYTHON-13: Remove eventlet, gevent and twisted event loops - #969

Draft
mykaul wants to merge 2 commits into
scylladb:masterfrom
mykaul:cherry-pick-CASSPYTHON-13
Draft

CASSPYTHON-13: Remove eventlet, gevent and twisted event loops#969
mykaul wants to merge 2 commits into
scylladb:masterfrom
mykaul:cherry-pick-CASSPYTHON-13

Conversation

@mykaul

@mykaul mykaul commented Aug 9, 2026

Copy link
Copy Markdown

Summary

  • Cherry-pick of upstream apache/cassandra-python-driver@8b39688 (CASSPYTHON-13), removing eventlet, gevent, and twisted event loop support and their tests/docs, with conflicts resolved against this fork's divergence (e.g. asyncio in conn_fns, retained is_monkey_patched() helpers used by a fork-specific libev shutdown test).
  • Follow-up commit removes a stale EventletConnection import in Cluster._create_thread_pool_executor — fork-specific code not present upstream, left dead after the reactor module was deleted.

Test plan

  • python3 -m py_compile on all touched files
  • Full tests/unit suite run (no C extensions available in sandbox): 697 passed, 99 skipped (skips due to missing libev/cmurmur3/lz4 extensions, unrelated to this change), 0 failures
  • CI

patch by Brett Abamonte; reviewed by Bret McGuire

(cherry picked from commit 8b39688)
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 9c7e1671-7e9c-4165-abd1-6500d443872a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change removes Eventlet, gevent, and Twisted reactor integrations from runtime selection, benchmarks, tests, and documentation. Thread pools and queues now use standard-library implementations. Cloud configuration and SSL tests now use built-in ssl.SSLContext handling without PyOpenSSL branches. Supported reactor tests no longer skip under monkey-patched environments.

Possibly related PRs

Suggested labels: P2, area/Driver_-_python-driver

Suggested reviewers: lorak-mmk

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the removal of eventlet, gevent, and Twisted event-loop support.
Description check ✅ Passed The description summarizes the changes, explains fork-specific resolutions, documents validation results, and identifies CI as pending.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Note

Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.

🟡 Other comments (1)
docs/installation.rst-172-174 (1)

172-174: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document pyasyncore installation for Python 3.12+.

pip install scylla-driver does not install pyasyncore. Add a conditional dependency or document python -m pip install pyasyncore beside the driver installation command.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/installation.rst` around lines 172 - 174, Update the Python 3.12+
installation guidance in the asyncore paragraph to explicitly instruct users to
install pyasyncore separately, using the existing driver installation
instructions and a command such as python -m pip install pyasyncore; keep the
note scoped to versions where asyncore is absent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cassandra/datastax/cloud/__init__.py`:
- Around line 97-102: Harden the extraction flow in the secure-bundle handling
code around ZipFile.extractall by resolving every archive member destination and
rejecting any path outside tmp_dir before extraction. Preserve normal extraction
and parse_cloud_config behavior for safe entries, and add a regression test
covering a traversal archive member.

---

Other comments:
In `@docs/installation.rst`:
- Around line 172-174: Update the Python 3.12+ installation guidance in the
asyncore paragraph to explicitly instruct users to install pyasyncore
separately, using the existing driver installation instructions and a command
such as python -m pip install pyasyncore; keep the note scoped to versions where
asyncore is absent.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 380ff746-7fd2-4186-a4b6-7db1ee384a86

📥 Commits

Reviewing files that changed from the base of the PR and between 1d7e601 and 8b54528.

📒 Files selected for processing (26)
  • benchmarks/base.py
  • cassandra/cluster.py
  • cassandra/connection.py
  • cassandra/datastax/cloud/__init__.py
  • cassandra/datastax/insights/reporter.py
  • cassandra/io/eventletreactor.py
  • cassandra/io/geventreactor.py
  • cassandra/io/twistedreactor.py
  • docs/api/cassandra/io/eventletreactor.rst
  • docs/api/cassandra/io/geventreactor.rst
  • docs/api/cassandra/io/twistedreactor.rst
  • docs/api/index.rst
  • docs/installation.rst
  • docs/security.rst
  • tests/__init__.py
  • tests/integration/long/test_ssl.py
  • tests/integration/standard/test_connection.py
  • tests/unit/io/eventlet_utils.py
  • tests/unit/io/gevent_utils.py
  • tests/unit/io/test_asyncioreactor.py
  • tests/unit/io/test_asyncorereactor.py
  • tests/unit/io/test_eventletreactor.py
  • tests/unit/io/test_geventreactor.py
  • tests/unit/io/test_libevreactor.py
  • tests/unit/io/test_twistedreactor.py
  • tests/unit/io/utils.py
💤 Files with no reviewable changes (16)
  • docs/api/cassandra/io/eventletreactor.rst
  • docs/api/cassandra/io/geventreactor.rst
  • tests/unit/io/test_eventletreactor.py
  • tests/unit/io/utils.py
  • benchmarks/base.py
  • cassandra/io/twistedreactor.py
  • tests/unit/io/test_geventreactor.py
  • docs/security.rst
  • tests/unit/io/gevent_utils.py
  • cassandra/io/eventletreactor.py
  • docs/api/index.rst
  • tests/unit/io/test_twistedreactor.py
  • tests/unit/io/eventlet_utils.py
  • tests/integration/standard/test_connection.py
  • cassandra/io/geventreactor.py
  • docs/api/cassandra/io/twistedreactor.rst

Comment on lines 97 to +102
with ZipFile(secure_bundle) as zipfile:
base_dir = tempfile.gettempdir() if use_default_tempdir else os.path.dirname(secure_bundle)
tmp_dir = tempfile.mkdtemp(dir=base_dir)
try:
zipfile.extractall(path=tmp_dir)
return parse_cloud_config(os.path.join(tmp_dir, 'config.json'), cloud_config, create_pyopenssl_context)
return parse_cloud_config(os.path.join(tmp_dir, 'config.json'), cloud_config)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Block Zip Slip paths before extraction.

extractall() accepts archive members such as ../../target. A crafted secure-connect bundle can write outside tmp_dir with the driver process permissions. Validate each resolved member path is within tmp_dir before extraction. Add a regression test with a traversal entry.

Proposed fix
-            zipfile.extractall(path=tmp_dir)
+            root = os.path.realpath(tmp_dir)
+            for member in zipfile.infolist():
+                target = os.path.realpath(os.path.join(root, member.filename))
+                if os.path.commonpath((root, target)) != root:
+                    raise ValueError("The secure connect bundle contains an unsafe path.")
+                zipfile.extract(member, root)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
with ZipFile(secure_bundle) as zipfile:
base_dir = tempfile.gettempdir() if use_default_tempdir else os.path.dirname(secure_bundle)
tmp_dir = tempfile.mkdtemp(dir=base_dir)
try:
zipfile.extractall(path=tmp_dir)
return parse_cloud_config(os.path.join(tmp_dir, 'config.json'), cloud_config, create_pyopenssl_context)
return parse_cloud_config(os.path.join(tmp_dir, 'config.json'), cloud_config)
with ZipFile(secure_bundle) as zipfile:
base_dir = tempfile.gettempdir() if use_default_tempdir else os.path.dirname(secure_bundle)
tmp_dir = tempfile.mkdtemp(dir=base_dir)
try:
root = os.path.realpath(tmp_dir)
for member in zipfile.infolist():
target = os.path.realpath(os.path.join(root, member.filename))
if os.path.commonpath((root, target)) != root:
raise ValueError("The secure connect bundle contains an unsafe path.")
zipfile.extract(member, root)
return parse_cloud_config(os.path.join(tmp_dir, 'config.json'), cloud_config)
🧰 Tools
🪛 ast-grep (0.45.0)

[error] 100-100: Calling extractall() on a zipfile.ZipFile or tarfile archive without validating member paths lets a crafted entry (e.g. "../../etc/passwd") write outside the destination directory (Zip Slip). Validate each member resolves inside the target directory, or pass a safe filter (tarfile: filter="data" / tarfile.data_filter).
Context: zipfile.extractall(path=tmp_dir)
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(archive-extractall-path-traversal-python)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cassandra/datastax/cloud/__init__.py` around lines 97 - 102, Harden the
extraction flow in the secure-bundle handling code around ZipFile.extractall by
resolving every archive member destination and rejecting any path outside
tmp_dir before extraction. Preserve normal extraction and parse_cloud_config
behavior for safe entries, and add a regression test covering a traversal
archive member.

Source: Linters/SAST tools

@mykaul
mykaul force-pushed the cherry-pick-CASSPYTHON-13 branch from 8b54528 to c8ee0f0 Compare August 9, 2026 16:18
…hread_pool_executor

This code path in cassandra/cluster.py was not part of the original
upstream removal since it doesn't exist upstream; it's fork-specific.
With eventletreactor deleted, the import always failed and the method
always fell back to a plain ThreadPoolExecutor, so drop the dead branch.
@mykaul
mykaul force-pushed the cherry-pick-CASSPYTHON-13 branch from c8ee0f0 to e97d2dd Compare August 9, 2026 16:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants