From e16f1aa0c512349a489927488c93dcd6bedff320 Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Wed, 14 Oct 2026 16:53:00 +0200 Subject: [PATCH 1/5] Fixed pyproject. Signed-off-by: Pavel Kirilin --- pyproject.toml | 150 ++++++++++++++++++++++++++----------------------- 1 file changed, 81 insertions(+), 69 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 283e523..c2d3a21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,108 +1,120 @@ [project] name = "scyllapy" description = "Async scylla driver for python" -requires-python = ">=3.8,<4" readme = "README.md" -license = { file = "LICENSE" } -keywords = ["scylla", "cassandra", "async-driver", "scylla-driver"] +requires-python = ">=3.11,<4" +license-files = ["LICENSE"] +keywords = ["async-driver", "cassandra", "scylla", "scylla-driver"] classifiers = [ - "Typing :: Typed", - "Topic :: Database", - "Development Status :: 4 - Beta", - "Programming Language :: Rust", - "Operating System :: MacOS", - "Operating System :: Microsoft", - "Operating System :: POSIX :: Linux", - "Intended Audience :: Developers", - "Topic :: Database :: Front-Ends", + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Operating System :: MacOS", + "Operating System :: Microsoft", + "Operating System :: POSIX :: Linux", + "Programming Language :: Rust", + "Topic :: Database", + "Topic :: Database :: Front-Ends", + "Typing :: Typed", ] dependencies = ["python-dateutil"] +dynamic = ["version"] -[tool.maturin] -python-source = "python" -module-name = "scyllapy._internal" -features = ["pyo3/extension-module"] +[build-system] +requires = ["maturin>=1.0,<2.0"] +build-backend = "maturin" [tool.isort] profile = "black" multi_line_output = 3 +[tool.maturin] +features = ["pyo3/extension-module"] +module-name = "scyllapy._internal" +python-source = "python" + [tool.mypy] strict = true mypy_path = "python" ignore_missing_imports = true -allow_subclassing_any = true -allow_untyped_calls = true +disallow_subclassing_any = false +disallow_untyped_calls = false pretty = true -show_error_codes = true implicit_reexport = true allow_untyped_decorators = true warn_return_any = false warn_unused_ignores = false -[build-system] -requires = ["maturin>=1.0,<2.0"] -build-backend = "maturin" +[tool.pytest] +anyio_mode = "auto" [tool.ruff] +target-version = "py311" +exclude = [".venv/"] +line-length = 88 + +[tool.ruff.lint] +mccabe = { max-complexity = 10 } # List of enabled rulsets. # See https://docs.astral.sh/ruff/rules/ for more information. select = [ - "E", # Error - "F", # Pyflakes - "W", # Pycodestyle - "C90", # McCabe complexity - "N", # pep8-naming - "D", # Pydocstyle - "ANN", # Pytype annotations - "S", # Bandit - "B", # Bugbear - "COM", # Commas - "C4", # Comprehensions - "ISC", # Implicit string concat - "PIE", # Unnecessary code - "T20", # Catch prints - "PYI", # validate pyi files - "Q", # Checks for quotes - "RSE", # Checks raise statements - "RET", # Checks return statements - "SLF", # Self checks - "SIM", # Simplificator - "PTH", # Pathlib checks - "ERA", # Checks for commented out code - "PL", # PyLint checks - "RUF", # Specific to Ruff checks + "E", # Error + "F", # Pyflakes + "W", # Pycodestyle + "C90", # McCabe complexity + "I", # Isort + "N", # pep8-naming + "D", # Pydocstyle + "ANN", # Pytype annotations + "S", # Bandit + "B", # Bugbear + "COM", # Commas + "C4", # Comprehensions + "ISC", # Implicit string concat + "PIE", # Unnecessary code + "T20", # Catch prints + "PYI", # validate pyi files + "Q", # Checks for quotes + "RSE", # Checks raise statements + "RET", # Checks return statements + "SLF", # Self checks + "SIM", # Simplificator + "PTH", # Pathlib checks + "ERA", # Checks for commented out code + "PL", # PyLint checks + "RUF", # Specific to Ruff checks + "UP", # Pyupgrade ] ignore = [ - "D105", # Missing docstring in magic method - "D107", # Missing docstring in __init__ - "D211", # No blank lines allowed before class docstring - "D212", # Multi-line docstring summary should start at the first line - "D401", # First line should be in imperative mood - "D104", # Missing docstring in public package - "D100", # Missing docstring in public module - "ANN102", # Missing type annotation for self in method - "ANN101", # Missing type annotation for argument - "ANN401", # typing.Any are disallowed in `**kwargs - "PLR0913", # Too many arguments for function call - "D106", # Missing docstring in public nested class + "D105", # Missing docstring in magic method + "D107", # Missing docstring in __init__ + "D212", # Multi-line docstring summary should start at the first line + "D401", # First line should be in imperative mood + "D104", # Missing docstring in public package + "D100", # Missing docstring in public module + "ANN401", # typing.Any are disallowed in `**kwargs + "PLR0913", # Too many arguments for function call + "D106", # Missing docstring in public nested class + "PYI021", # Docstrings should not be included in stubs ] -exclude = [".venv/"] -mccabe = { max-complexity = 10 } -line-length = 88 -[tool.ruff.per-file-ignores] -"python/scyllapy/*" = ["PYI021"] +[tool.ruff.lint.per-file-ignores] "python/tests/*" = [ - "S101", # Use of assert detected - "S608", # Possible SQL injection vector through string-based query construction - "D103", # Missing docstring in public function - "S311", # Standard pseudo-random generators are not suitable for security/cryptographic purposes + "S101", # Use of assert detected + "S301", # Use of pickle detected + "D103", # Missing docstring in public function + "SLF001", # Private member accessed + "S311", # Standard pseudo-random generators are not suitable for security/cryptographic purposes + "D101", # Missing docstring in public class + "PLR2004", # Magic value used in comparison + "B017", # Do not assert blind exception ] -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] convention = "pep257" ignore-decorators = ["typing.overload"] -[tool.ruff.pylint] +[tool.ruff.lint.pylint] allow-magic-value-types = ["int", "str", "float"] + +[tool.uv] +package = false From 67b91cb8a792ab29cae93c6b25f29134b7cdfdbf Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Wed, 14 Oct 2026 18:05:27 +0200 Subject: [PATCH 2/5] Updated versions. Signed-off-by: Pavel Kirilin --- Cargo.toml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 69af7ff..c2f2511 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,26 +9,26 @@ crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -chrono = "0.4.31" +chrono = "0.4.45" eq-float = "0.1.0" -futures = "0.3.28" -log = "0.4.20" -openssl = { version = "0.10.57", features = ["vendored"] } -pyo3 = { version = "0.20.0", features = [ +futures = "0.3.34" +log = "0.4.34" +openssl = { version = "0.10.81", features = ["vendored"] } +pyo3 = { version = "0.29.3", features = [ "auto-initialize", "abi3-py38", "extension-module", "chrono", ] } -pyo3-asyncio = { version = "0.20.0", features = ["tokio-runtime"] } -pyo3-log = "0.9.0" +pyo3-async-runtimes = { version = "0.29.0", features = ["tokio-runtime"] } +pyo3-log = "0.13.4" rustc-hash = "1.1.0" scylla = { version = "0.12.0", features = ["ssl", "full-serialization"] } -bigdecimal-04 = { package = "bigdecimal", version = "0.4" } -thiserror = "1.0.48" -tokio = { version = "1.32.0", features = ["bytes"] } -uuid = { version = "1.4.1", features = ["v4"] } -time = { version = "*", features = ["formatting", "macros"] } +bigdecimal-04 = { package = "bigdecimal", version = "0.4.11" } +thiserror = "1.0.69" +tokio = { version = "1.53.3", features = ["bytes"] } +uuid = { version = "1.28.0", features = ["v4"] } +time = { version = "0.3.55", features = ["formatting", "macros"] } [profile.release] lto = "fat" From 7039cb5faa753000e6de3c0739e2876efd714a2d Mon Sep 17 00:00:00 2001 From: Pavel Kirilin Date: Wed, 14 Oct 2026 18:41:45 +0200 Subject: [PATCH 3/5] Fixed code. Signed-off-by: Pavel Kirilin --- .github/workflows/test.yaml | 2 +- Cargo.toml | 2 +- src/batches.rs | 20 +++-- src/consistencies.rs | 4 +- src/exceptions/py_err.rs | 8 +- src/execution_profiles.rs | 2 +- src/extra_types.rs | 12 ++- src/lib.rs | 31 ++++++- src/load_balancing.rs | 16 ++-- src/prepared_queries.rs | 2 +- src/queries.rs | 30 ++++--- src/query_builder/delete.rs | 24 ++++-- src/query_builder/insert.rs | 25 ++++-- src/query_builder/mod.rs | 7 +- src/query_builder/select.rs | 25 +++--- src/query_builder/update.rs | 31 ++++--- src/query_results.rs | 72 +++++++++------- src/scylla_cls.rs | 31 ++++--- src/utils.rs | 160 ++++++++++++++++++------------------ tox.ini | 8 +- uv.lock | 34 ++++++++ 21 files changed, 334 insertions(+), 212 deletions(-) create mode 100644 uv.lock diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b5cb474..5e40a97 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -64,7 +64,7 @@ jobs: - 9042:9042 strategy: matrix: - py_version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + py_version: ["3.11", "3.12"] job: - os: ubuntu-latest ssl_cmd: sudo apt-get update && sudo apt-get install libssl-dev openssl diff --git a/Cargo.toml b/Cargo.toml index c2f2511..22af0d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ log = "0.4.34" openssl = { version = "0.10.81", features = ["vendored"] } pyo3 = { version = "0.29.3", features = [ "auto-initialize", - "abi3-py38", + "abi3-py311", "extension-module", "chrono", ] } diff --git a/src/batches.rs b/src/batches.rs index c13e681..7dd0370 100644 --- a/src/batches.rs +++ b/src/batches.rs @@ -1,4 +1,4 @@ -use pyo3::{pyclass, pymethods, types::PyDict, PyAny}; +use pyo3::{pyclass, pymethods, types::PyDict, Bound, PyAny}; use scylla::{ batch::{Batch, BatchStatement, BatchType}, frame::value::LegacySerializedValues, @@ -9,7 +9,7 @@ use crate::{ utils::parse_python_query_params, }; -#[pyclass(name = "BatchType")] +#[pyclass(name = "BatchType", from_py_object)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ScyllaPyBatchType { COUNTER, @@ -17,14 +17,14 @@ pub enum ScyllaPyBatchType { UNLOGGED, } -#[pyclass(name = "Batch")] +#[pyclass(name = "Batch", from_py_object)] #[derive(Clone)] pub struct ScyllaPyBatch { inner: Batch, request_params: ScyllaPyRequestParams, } -#[pyclass(name = "InlineBatch")] +#[pyclass(name = "InlineBatch", from_py_object)] #[derive(Clone)] pub struct ScyllaPyInlineBatch { inner: Batch, @@ -60,7 +60,10 @@ impl ScyllaPyBatch { batch_type = ScyllaPyBatchType::UNLOGGED, **params ))] - pub fn py_new(batch_type: ScyllaPyBatchType, params: Option<&PyDict>) -> ScyllaPyResult { + pub fn py_new( + batch_type: ScyllaPyBatchType, + params: Option<&Bound<'_, PyDict>>, + ) -> ScyllaPyResult { Ok(Self { inner: Batch::new(batch_type.into()), request_params: ScyllaPyRequestParams::from_dict(params)?, @@ -96,7 +99,10 @@ impl ScyllaPyInlineBatch { batch_type = ScyllaPyBatchType::UNLOGGED, **params ))] - pub fn py_new(batch_type: ScyllaPyBatchType, params: Option<&PyDict>) -> ScyllaPyResult { + pub fn py_new( + batch_type: ScyllaPyBatchType, + params: Option<&Bound<'_, PyDict>>, + ) -> ScyllaPyResult { Ok(Self { inner: Batch::new(batch_type.into()), request_params: ScyllaPyRequestParams::from_dict(params)?, @@ -118,7 +124,7 @@ impl ScyllaPyInlineBatch { pub fn add_query( &mut self, query: BatchQueryInput, - values: Option<&PyAny>, + values: Option<&Bound<'_, PyAny>>, ) -> ScyllaPyResult<()> { self.inner.append_statement(query); if let Some(passed_params) = values { diff --git a/src/consistencies.rs b/src/consistencies.rs index 6a20947..7983009 100644 --- a/src/consistencies.rs +++ b/src/consistencies.rs @@ -5,7 +5,7 @@ use scylla::statement::{Consistency, SerialConsistency}; /// /// This class allows to run queries /// with specific consistency levels. -#[pyclass(name = "Consistency")] +#[pyclass(name = "Consistency", from_py_object)] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[allow(non_camel_case_types)] pub enum ScyllaPyConsistency { @@ -22,7 +22,7 @@ pub enum ScyllaPyConsistency { LOCAL_SERIAL, } -#[pyclass(name = "SerialConsistency")] +#[pyclass(name = "SerialConsistency", from_py_object)] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[allow(non_camel_case_types)] pub enum ScyllaPySerialConsistency { diff --git a/src/exceptions/py_err.rs b/src/exceptions/py_err.rs index 6dc52d7..db81ca0 100644 --- a/src/exceptions/py_err.rs +++ b/src/exceptions/py_err.rs @@ -1,4 +1,8 @@ -use pyo3::{create_exception, types::PyModule, PyResult, Python}; +use pyo3::{ + create_exception, + types::{PyModule, PyModuleMethods}, + Bound, PyResult, Python, +}; create_exception!( scyllapy.exceptions, @@ -23,7 +27,7 @@ create_exception!( /// # Errors /// /// May throw an error, if module cannot be constructed. -pub fn setup_module(py: Python<'_>, module: &PyModule) -> PyResult<()> { +pub fn setup_module(py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> { module.add("ScyllaPyBaseError", py.get_type::())?; module.add("ScyllaPyDBError", py.get_type::())?; module.add( diff --git a/src/execution_profiles.rs b/src/execution_profiles.rs index 449cd4c..f11a2b7 100644 --- a/src/execution_profiles.rs +++ b/src/execution_profiles.rs @@ -8,7 +8,7 @@ use crate::{ load_balancing::ScyllaPyLoadBalancingPolicy, }; -#[pyclass(name = "ExecutionProfile")] +#[pyclass(name = "ExecutionProfile", from_py_object)] #[derive(Clone, Debug)] pub struct ScyllaPyExecutionProfile { inner: scylla::ExecutionProfile, diff --git a/src/extra_types.rs b/src/extra_types.rs index 9d946ab..df7bc02 100644 --- a/src/extra_types.rs +++ b/src/extra_types.rs @@ -1,8 +1,12 @@ -use pyo3::{pyclass, pymethods, types::PyModule, PyResult, Python}; +use pyo3::{ + pyclass, pymethods, + types::{PyModule, PyModuleMethods}, + Bound, PyResult, Python, +}; macro_rules! simple_wrapper { ($name:ident, $ttype:ty) => { - #[pyclass] + #[pyclass(from_py_object)] #[derive(Clone)] pub struct $name { inner: $ttype, @@ -37,7 +41,7 @@ simple_wrapper!(BigInt, i64); simple_wrapper!(Double, f64); simple_wrapper!(Counter, i64); -#[pyclass(name = "Unset")] +#[pyclass(name = "Unset", skip_from_py_object)] #[derive(Clone, Copy)] pub struct ScyllaPyUnset {} @@ -56,7 +60,7 @@ impl ScyllaPyUnset { /// /// May return error if module cannot be created, /// or any of classes cannot be added. -pub fn setup_module(_py: Python<'_>, module: &PyModule) -> PyResult<()> { +pub fn setup_module(_py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> { module.add_class::()?; module.add_class::()?; module.add_class::()?; diff --git a/src/lib.rs b/src/lib.rs index 0a00989..f5e8658 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,26 @@ +#![deny( + // Base lints. + clippy::all, + // Some pedantic lints. + clippy::pedantic, + // New lints which are cool. + clippy::nursery, +)] +#![ + allow( + // Beacsue some types naming conventions are + // just different to the ones that rust have. + non_camel_case_types, + // I don't care about this. + clippy::module_name_repetitions, + // Yo, the hell you should put + // it in docs, if signature is clear as sky. + clippy::missing_errors_doc, + // Because pythonic way is + // to have many args with defaults. + clippy::too_many_arguments +)] + pub mod batches; pub mod consistencies; pub mod exceptions; @@ -12,13 +35,17 @@ pub mod query_results; pub mod scylla_cls; pub mod utils; -use pyo3::{pymodule, types::PyModule, PyResult, Python}; +use pyo3::{ + pymodule, + types::{PyModule, PyModuleMethods}, + Bound, PyResult, Python, +}; use crate::utils::add_submodule; #[pymodule] #[pyo3(name = "_internal")] -fn _internal(py: Python<'_>, pymod: &PyModule) -> PyResult<()> { +fn _internal(py: Python<'_>, pymod: &Bound<'_, PyModule>) -> PyResult<()> { pyo3_log::init(); pymod.add_class::()?; pymod.add_class::()?; diff --git a/src/load_balancing.rs b/src/load_balancing.rs index 8f288f1..e57108c 100644 --- a/src/load_balancing.rs +++ b/src/load_balancing.rs @@ -2,15 +2,15 @@ use std::sync::Arc; use pyo3::{ pyclass, pymethods, - types::{PyModule, PyType}, - PyAny, PyResult, Python, + types::{PyModule, PyModuleMethods, PyType}, + Bound, PyAny, PyResult, Python, }; use scylla::load_balancing::{DefaultPolicy, LatencyAwarenessBuilder, LoadBalancingPolicy}; use std::time::Duration; use crate::{exceptions::rust_err::ScyllaPyResult, utils::scyllapy_future}; -#[pyclass(name = "LoadBalancingPolicy")] +#[pyclass(name = "LoadBalancingPolicy", from_py_object)] #[derive(Clone, Debug)] pub struct ScyllaPyLoadBalancingPolicy { inner: Arc, @@ -29,15 +29,15 @@ impl ScyllaPyLoadBalancingPolicy { latency_awareness = None, ) )] - fn build( - cls: &PyType, + fn build<'py>( + cls: &Bound<'py, PyType>, token_aware: Option, prefer_rack: Option, prefer_datacenter: Option, permit_dc_failover: Option, shuffling_replicas: Option, latency_awareness: Option, - ) -> ScyllaPyResult<&PyAny> { + ) -> ScyllaPyResult> { scyllapy_future(cls.py(), async move { let mut policy_builer = DefaultPolicy::builder(); if let Some(permit) = permit_dc_failover { @@ -66,7 +66,7 @@ impl ScyllaPyLoadBalancingPolicy { } } -#[pyclass(name = "LatencyAwareness")] +#[pyclass(name = "LatencyAwareness", from_py_object)] #[derive(Clone, Debug)] pub struct ScyllaPyLatencyAwareness { inner: LatencyAwarenessBuilder, @@ -129,7 +129,7 @@ impl From for Arc { /// # Errors /// /// If cannot add class to the module. -pub fn setup_module(_py: Python<'_>, module: &PyModule) -> PyResult<()> { +pub fn setup_module(_py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> { module.add_class::()?; module.add_class::()?; Ok(()) diff --git a/src/prepared_queries.rs b/src/prepared_queries.rs index 65ee4f9..62146e9 100644 --- a/src/prepared_queries.rs +++ b/src/prepared_queries.rs @@ -1,7 +1,7 @@ use pyo3::pyclass; use scylla::prepared_statement::PreparedStatement; -#[pyclass(name = "PreparedQuery")] +#[pyclass(name = "PreparedQuery", from_py_object)] #[derive(Clone, Debug)] pub struct ScyllaPyPreparedQuery { pub inner: PreparedStatement, diff --git a/src/queries.rs b/src/queries.rs index 01946c8..275f31c 100644 --- a/src/queries.rs +++ b/src/queries.rs @@ -5,7 +5,11 @@ use crate::{ exceptions::rust_err::ScyllaPyResult, execution_profiles::ScyllaPyExecutionProfile, }; -use pyo3::{pyclass, pymethods, types::PyDict, FromPyObject, Python}; +use pyo3::{ + pyclass, pymethods, + types::{PyAnyMethods, PyDict, PyDictMethods}, + Bound, FromPyObject, PyErr, Python, +}; use scylla::{batch::Batch, execution_profile::ExecutionProfileHandle, statement::query::Query}; #[derive(Clone, Debug, Default, FromPyObject)] @@ -60,44 +64,44 @@ impl ScyllaPyRequestParams { /// /// May result in an error if /// incorrect type passed. - pub fn from_dict(params: Option<&PyDict>) -> ScyllaPyResult { + pub fn from_dict(params: Option<&Bound<'_, PyDict>>) -> ScyllaPyResult { let Some(params) = params else { return Ok(Self::default()); }; Ok(Self { consistency: params .get_item("consistency")? - .map(pyo3::FromPyObject::extract) + .map(|obj| obj.extract().map_err(PyErr::from)) .transpose()?, serial_consistency: params .get_item("serial_consistency")? - .map(pyo3::FromPyObject::extract) + .map(|obj| obj.extract().map_err(PyErr::from)) .transpose()?, request_timeout: params .get_item("request_timeout")? - .map(pyo3::FromPyObject::extract) + .map(|obj| obj.extract()) .transpose()?, timestamp: params .get_item("timestamp")? - .map(pyo3::FromPyObject::extract) + .map(|obj| obj.extract()) .transpose()?, is_idempotent: params .get_item("is_idempotent")? - .map(pyo3::FromPyObject::extract) + .map(|obj| obj.extract()) .transpose()?, tracing: params .get_item("tracing")? - .map(pyo3::FromPyObject::extract) + .map(|obj| obj.extract()) .transpose()?, profile: params .get_item("profile")? - .map(pyo3::FromPyObject::extract) + .map(|obj| obj.extract().map_err(PyErr::from)) .transpose()?, }) } } -#[pyclass(name = "Query")] +#[pyclass(name = "Query", from_py_object)] #[derive(Clone, Debug)] pub struct ScyllaPyQuery { #[pyo3(get)] @@ -123,7 +127,11 @@ impl ScyllaPyQuery { /// /// # Errors /// May raise an error if incorrect type passed in kwargs. - pub fn py_new(_py: Python<'_>, query: String, kwargs: Option<&PyDict>) -> ScyllaPyResult { + pub fn py_new( + _py: Python<'_>, + query: String, + kwargs: Option<&Bound<'_, PyDict>>, + ) -> ScyllaPyResult { Ok(Self { query, params: ScyllaPyRequestParams::from_dict(kwargs)?, diff --git a/src/query_builder/delete.rs b/src/query_builder/delete.rs index 8a784f5..af04f55 100644 --- a/src/query_builder/delete.rs +++ b/src/query_builder/delete.rs @@ -1,4 +1,4 @@ -use pyo3::{pyclass, pymethods, types::PyDict, PyAny, PyRefMut, Python}; +use pyo3::{pyclass, pymethods, types::PyDict, Bound, PyAny, PyRefMut, Python}; use scylla::{frame::value::LegacySerializedValues, query::Query}; use super::utils::{pretty_build, IfCluase, Timeout}; @@ -10,7 +10,7 @@ use crate::{ utils::{py_to_value, ScyllaPyCQLDTO}, }; -#[pyclass] +#[pyclass(skip_from_py_object)] #[derive(Clone, Debug, Default)] pub struct Delete { table_: String, @@ -104,12 +104,12 @@ impl Delete { pub fn r#where<'a>( mut slf: PyRefMut<'a, Self>, clause: String, - values: Option>, + values: Option>>, ) -> ScyllaPyResult> { slf.where_clauses_.push(clause); if let Some(vals) = values { for value in vals { - slf.values_.push(py_to_value(value, None)?); + slf.values_.push(py_to_value(&value, None)?); } } Ok(slf) @@ -143,7 +143,7 @@ impl Delete { pub fn if_<'a>( mut slf: PyRefMut<'a, Self>, clause: String, - values: Option>, + values: Option>>, ) -> ScyllaPyResult> { let parsed_values = if let Some(vals) = values { vals.iter() @@ -178,7 +178,7 @@ impl Delete { #[pyo3(signature = (**params))] pub fn request_params<'a>( mut slf: PyRefMut<'a, Self>, - params: Option<&'a PyDict>, + params: Option<&'a Bound<'a, PyDict>>, ) -> ScyllaPyResult> { slf.request_params_ = ScyllaPyRequestParams::from_dict(params)?; Ok(slf) @@ -191,7 +191,11 @@ impl Delete { /// May return an error, if something goes wrong /// during query building /// or during query execution. - pub fn execute<'a>(&'a self, py: Python<'a>, scylla: &'a Scylla) -> ScyllaPyResult<&'a PyAny> { + pub fn execute<'a>( + &'a self, + py: Python<'a>, + scylla: &'a Bound<'a, Scylla>, + ) -> ScyllaPyResult> { let mut query = Query::new(self.build_query()?); self.request_params_.apply_to_query(&mut query); @@ -200,7 +204,9 @@ impl Delete { } else { self.values_.clone() }; - scylla.native_execute(py, Some(query), None, values, false) + scylla + .get() + .native_execute(py, Some(query), None, values, false) } /// Add to batch @@ -249,7 +255,7 @@ impl Delete { } #[must_use] - pub fn __deepcopy__(&self, _memo: &PyDict) -> Self { + pub fn __deepcopy__(&self, _memo: &Bound<'_, PyDict>) -> Self { self.clone() } } diff --git a/src/query_builder/insert.rs b/src/query_builder/insert.rs index 67ed097..a65f606 100644 --- a/src/query_builder/insert.rs +++ b/src/query_builder/insert.rs @@ -1,4 +1,8 @@ -use pyo3::{pyclass, pymethods, types::PyDict, PyAny, PyRefMut, Python}; +use pyo3::{ + pyclass, pymethods, + types::{PyAnyMethods, PyDict}, + Bound, PyAny, PyRefMut, Python, +}; use scylla::{frame::value::LegacySerializedValues, query::Query}; use crate::{ @@ -11,8 +15,9 @@ use crate::{ use super::utils::{pretty_build, Timeout}; -#[pyclass] +#[pyclass(skip_from_py_object)] #[derive(Clone, Debug, Default)] +#[allow(clippy::struct_field_names)] pub struct Insert { table_: String, if_not_exists_: bool, @@ -106,7 +111,7 @@ impl Insert { pub fn set<'a>( mut slf: PyRefMut<'a, Self>, name: String, - value: &'a PyAny, + value: &'a Bound<'a, PyAny>, ) -> ScyllaPyResult> { slf.names_.push(name); // Small optimization to speedup inserts. @@ -147,7 +152,7 @@ impl Insert { #[pyo3(signature = (**params))] pub fn request_params<'a>( mut slf: PyRefMut<'a, Self>, - params: Option<&'a PyDict>, + params: Option<&'a Bound<'a, PyDict>>, ) -> ScyllaPyResult> { slf.request_params_ = ScyllaPyRequestParams::from_dict(params)?; Ok(slf) @@ -161,10 +166,16 @@ impl Insert { /// /// If query cannot be built. /// Also proxies errors from `native_execute`. - pub fn execute<'a>(&'a self, py: Python<'a>, scylla: &'a Scylla) -> ScyllaPyResult<&'a PyAny> { + pub fn execute<'a>( + &'a self, + py: Python<'a>, + scylla: &'a Bound<'a, Scylla>, + ) -> ScyllaPyResult> { let mut query = Query::new(self.build_query()?); self.request_params_.apply_to_query(&mut query); - scylla.native_execute(py, Some(query), None, self.values_.clone(), false) + scylla + .get() + .native_execute(py, Some(query), None, self.values_.clone(), false) } /// Add to batch @@ -206,7 +217,7 @@ impl Insert { } #[must_use] - pub fn __deepcopy__(&self, _memo: &PyDict) -> Self { + pub fn __deepcopy__(&self, _memo: &Bound<'_, PyDict>) -> Self { self.clone() } } diff --git a/src/query_builder/mod.rs b/src/query_builder/mod.rs index ba1b979..c908432 100644 --- a/src/query_builder/mod.rs +++ b/src/query_builder/mod.rs @@ -1,4 +1,7 @@ -use pyo3::{types::PyModule, PyResult, Python}; +use pyo3::{ + types::{PyModule, PyModuleMethods}, + Bound, PyResult, Python, +}; use self::{delete::Delete, insert::Insert, select::Select, update::Update}; @@ -17,7 +20,7 @@ mod utils; /// /// * Cannot create module by any reason. /// * Cannot add class by some reason. -pub fn setup_module(_py: Python<'_>, module: &PyModule) -> PyResult<()> { +pub fn setup_module(_py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> { module.add_class::