Skip to content

Conversation

@ever0de
Copy link
Contributor

@ever0de ever0de commented Oct 20, 2025

Add proper init validation for sqlite3.Connection to ensure base class init is called before using connection methods. This fixes the test_connection_constructor_call_check test case.

Changes:

  • Modified Connection.py_new to detect subclassing
  • For base Connection class, initialization happens immediately in py_new
  • For subclassed Connection, db is initialized as None
  • Added init method that performs actual database initialization
  • Updated _db_lock error message to match CPython: 'Base Connection.init not called.'

Summary by CodeRabbit

  • Bug Fixes

    • Clearer error message when attempting to use an uninitialized SQLite connection, making initialization issues easier to diagnose.
  • Improvements

    • Refined SQLite connection setup so base connections initialize immediately while derived connections defer initialization until explicitly initialized, ensuring correct configuration (path, timeouts, isolation) and preserving threading/locking behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 20, 2025

Walkthrough

The SQLite Connection initialization now centralizes opening logic in initialize_db(). Base Connection instances initialize eagerly in py_new, while subclassed Connection objects start uninitialized and require an explicit __init__ call; error messaging for uninitialized base connections was updated.

Changes

Cohort / File(s) Change Summary
SQLite Connection Initialization Refactor
stdlib/src/sqlite.rs
Added initialize_db(&ConnectArgs, &VirtualMachine) -> PyResult<Sqlite>; added #[pymethod] fn __init__(&self, args, vm) for subclass initialization; py_new for base Connection now calls initialize_db and stores PyMutex<Option<Sqlite>> as Some(db); subclass path sets None until __init__; changed error text from "Cannot operate on a closed database." to "Base Connection.init not called."

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant py_new
    participant initialize_db
    participant SubclassInit as __init__ (subclass)

    User->>py_new: Create Connection
    alt Base class
        py_new->>initialize_db: initialize_db(args, vm)
        initialize_db-->>py_new: Sqlite
        py_new->>py_new: store PyMutex(Some(db))
        py_new-->>User: Ready
    else Subclass
        py_new->>py_new: store PyMutex(None)
        py_new-->>User: Returned (uninitialized)
        User->>SubclassInit: __init__(args, vm)
        SubclassInit->>initialize_db: initialize_db(args, vm)
        initialize_db-->>SubclassInit: Sqlite
        SubclassInit->>SubclassInit: set PyMutex(Some(db))
        SubclassInit-->>User: Ready
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • RustPython#6198 — Parallel changes introducing lazy/uninitialized py_new paths and explicit __init__ for Connection/Cursor, matching error-message and initialization semantics.
  • RustPython#6042 — Related adjustments to sqlite Connection db access/locking and error handling that interact with the new initialization flow.

Suggested reviewers

  • youknowone

Poem

🐰 I hopped in code beneath the moonlit log,

Base wakes at once, subclasses sleep in fog,
initialize_db brings gardens green,
init nudges sprouts to be seen,
Hooray — a tidy, bouncy DB log! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Fix sqlite Connection initialization check" is fully related to the main change in the pull request and clearly summarizes it. The PR's primary objective is to add proper init validation for sqlite3.Connection to ensure the base class init is called before using connection methods, which is precisely what the title conveys. The title is concise (5 words), specific to the component and problem being addressed (sqlite Connection initialization checking), and a teammate scanning PR history would immediately understand this is about fixing initialization validation. The title contains no vague terminology, misleading content, or extraneous noise.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38e9fc5 and df09182.

📒 Files selected for processing (1)
  • stdlib/src/sqlite.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • stdlib/src/sqlite.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: Run snippets and cpython tests (ubuntu-latest)
  • GitHub Check: Run snippets and cpython tests (macos-latest)
  • GitHub Check: Check Rust code with rustfmt and clippy
  • GitHub Check: Run snippets and cpython tests on wasm-wasi
  • GitHub Check: Run snippets and cpython tests (windows-latest)
  • GitHub Check: Check the WASM package and demo
  • GitHub Check: Run tests under miri
  • GitHub Check: Run rust tests (ubuntu-latest)
  • GitHub Check: Run rust tests (macos-latest)
  • GitHub Check: Run rust tests (windows-latest)
  • GitHub Check: Ensure compilation on various targets

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ever0de ever0de force-pushed the fix/sqlite-connection-init-check branch from c015fd8 to d9bc788 Compare October 20, 2025 15:51
Add proper __init__ validation for sqlite3.Connection to ensure base class
__init__ is called before using connection methods. This fixes the
test_connection_constructor_call_check test case.

Changes:
- Modified Connection.py_new to detect subclassing
- For base Connection class, initialization happens immediately in py_new
- For subclassed Connection, db is initialized as None
- Added __init__ method that performs actual database initialization
- Updated _db_lock error message to match CPython: 'Base Connection.__init__ not called.'

This ensures CPython compatibility where attempting to use a Connection
subclass instance without calling the base __init__ raises ProgrammingError.
@ever0de ever0de force-pushed the fix/sqlite-connection-init-check branch from d9bc788 to 38e9fc5 Compare October 20, 2025 16:02
@ever0de ever0de marked this pull request as ready for review October 20, 2025 16:26
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
stdlib/src/sqlite.rs (2)

900-910: Clamp timeout to avoid c_int overflow

let timeout = (args.timeout * 1000.0) as c_int; can overflow for large timeouts. Clamp and round before casting.

Apply within this block:

-            let timeout = (args.timeout * 1000.0) as c_int;
-            db.busy_timeout(timeout);
+            // Saturate to c_int::MAX and avoid negatives
+            let timeout_ms = (args.timeout * 1000.0).clamp(0.0, i32::MAX as f64).round() as c_int;
+            db.busy_timeout(timeout_ms);

911-922: Subclass init path: good; consider making sqlite.connect() call the factory so init runs

__init__ correctly performs one-time DB open for subclassed instances. However, sqlite.connect() still constructs via Connection::py_new(...), so a factory=SubClass won’t execute the subclass’ __init__ (unlike CPython, which calls factory(...)). Recommend updating connect() to invoke the factory type, letting Python dispatch call __new__ then __init__.

Proposed approach (conceptual; outside this hunk): build args tuple matching ConnectArgs order and call the type:

// Pseudocode: call the chosen factory so __init__ runs for subclasses
// let obj = vm.invoke(args.factory.clone().into_object(),
//     (args.database, args.timeout, args.detect_types, args.isolation_level,
//      args.check_same_thread, /* omit passing 'factory' itself */
//      args.cached_statements, args.uri))?;

Please verify no downstream assumptions rely on the current “py_new-only” construction.

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcf1969 and 38e9fc5.

⛔ Files ignored due to path filters (1)
  • Lib/test/test_sqlite3/test_regression.py is excluded by !Lib/**
📒 Files selected for processing (1)
  • stdlib/src/sqlite.rs (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.rs: Format Rust code with the default rustfmt style (run cargo fmt)
Run clippy and fix any warnings or lints introduced by your changes
Follow Rust best practices for error handling and memory management

Files:

  • stdlib/src/sqlite.rs
{vm,stdlib}/**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use RustPython macros (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust

Files:

  • stdlib/src/sqlite.rs
🧬 Code graph analysis (1)
stdlib/src/sqlite.rs (3)
vm/src/builtins/type.rs (1)
  • class (147-149)
vm/src/object/core.rs (1)
  • class (671-673)
Lib/test/test_sqlite3/test_regression.py (1)
  • Connection (229-231)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run snippets and cpython tests (windows-latest)
🔇 Additional comments (2)
stdlib/src/sqlite.rs (2)

854-879: Eager base init + deferred subclass init is correct

Type check via cls.is(Connection::class(&vm.ctx).as_object()) and gating db initialization achieves the CPython-compatible behavior while preserving defaults (text_factory, thread id). Looks good.


936-940: Error text parity with CPython

Updated message “Base Connection.init not called.” matches expected test string and CPython behavior. Good.

Run the sqlite3 regression test to confirm: test_connection_constructor_call_check passes with this change.

Comment on lines 911 to 912
#[pymethod]
fn __init__(&self, args: ConnectArgs, vm: &VirtualMachine) -> PyResult<()> {
Copy link
Member

Choose a reason for hiding this comment

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

We also have an Initializer trait. It’s like the Constructor trait.
Would you apply this trait as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I'd forgotten because it's been a while. Thank you

Copy link
Member

@youknowone youknowone left a comment

Choose a reason for hiding this comment

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

Great, thank you!

@youknowone youknowone merged commit 2faa05d into RustPython:main Oct 21, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants