diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py index c13a7481520..20cff8b585f 100644 --- a/Lib/test/test_sqlite3/test_factory.py +++ b/Lib/test/test_sqlite3/test_factory.py @@ -80,8 +80,6 @@ def setUp(self): def tearDown(self): self.con.close() - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_is_instance(self): cur = self.con.cursor() self.assertIsInstance(cur, sqlite.Cursor) diff --git a/crates/stdlib/src/sqlite.rs b/crates/stdlib/src/sqlite.rs index 7e0392b1f30..9b7b810b25c 100644 --- a/crates/stdlib/src/sqlite.rs +++ b/crates/stdlib/src/sqlite.rs @@ -425,6 +425,12 @@ mod _sqlite { name: PyStrRef, } + #[derive(FromArgs)] + struct CursorArgs { + #[pyarg(any, default)] + factory: OptionalArg, + } + struct CallbackData { obj: NonNull, vm: *const VirtualMachine, @@ -1023,22 +1029,29 @@ mod _sqlite { #[pymethod] fn cursor( zelf: PyRef, - factory: OptionalArg, + args: CursorArgs, vm: &VirtualMachine, - ) -> PyResult> { + ) -> PyResult { zelf.db_lock(vm).map(drop)?; - let cursor = if let OptionalArg::Present(factory) = factory { - let cursor = factory.invoke((zelf.clone(),), vm)?; - let cursor = cursor.downcast::().map_err(|x| { - vm.new_type_error(format!("factory must return a cursor, not {}", x.class())) - })?; - let _ = unsafe { cursor.row_factory.swap(zelf.row_factory.to_owned()) }; - cursor - } else { - let row_factory = zelf.row_factory.to_owned(); - Cursor::new(zelf, row_factory, vm).into_ref(&vm.ctx) + let factory = match args.factory { + OptionalArg::Present(f) => f, + OptionalArg::Missing => Cursor::class(&vm.ctx).to_owned().into(), }; + + let cursor = factory.call((zelf.clone(),), vm)?; + + if !cursor.class().fast_issubclass(Cursor::class(&vm.ctx)) { + return Err(vm.new_type_error(format!( + "factory must return a cursor, not {}", + cursor.class() + ))); + } + + if let Some(cursor_ref) = cursor.downcast_ref::() { + let _ = unsafe { cursor_ref.row_factory.swap(zelf.row_factory.to_owned()) }; + } + Ok(cursor) }