diff --git a/Cargo.lock b/Cargo.lock
index f1b356a..b6c11b1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1277,9 +1277,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3"
-version = "0.22.6"
+version = "0.23.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884"
+checksum = "57fe09249128b3173d092de9523eaa75136bf7ba85e0d69eca241c7939c933cc"
 dependencies = [
  "cfg-if",
  "indoc",
@@ -1296,9 +1296,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-build-config"
-version = "0.22.6"
+version = "0.23.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38"
+checksum = "1cd3927b5a78757a0d71aa9dff669f903b1eb64b54142a9bd9f757f8fde65fd7"
 dependencies = [
  "once_cell",
  "target-lexicon",
@@ -1306,9 +1306,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-ffi"
-version = "0.22.6"
+version = "0.23.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636"
+checksum = "dab6bb2102bd8f991e7749f130a70d05dd557613e39ed2deeee8e9ca0c4d548d"
 dependencies = [
  "libc",
  "pyo3-build-config",
@@ -1316,9 +1316,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-macros"
-version = "0.22.6"
+version = "0.23.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453"
+checksum = "91871864b353fd5ffcb3f91f2f703a22a9797c91b9ab497b1acac7b07ae509c7"
 dependencies = [
  "proc-macro2",
  "pyo3-macros-backend",
@@ -1328,9 +1328,9 @@ dependencies = [
 
 [[package]]
 name = "pyo3-macros-backend"
-version = "0.22.6"
+version = "0.23.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe"
+checksum = "43abc3b80bc20f3facd86cd3c60beed58c3e2aa26213f3cda368de39c60a27e4"
 dependencies = [
  "heck",
  "proc-macro2",
diff --git a/Cargo.toml b/Cargo.toml
index c3d03bb..026e48a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -51,7 +51,7 @@ napi = { version = "2.16", features = ["full"], optional = true }
 napi-derive = { version="2.16",  optional = true}
 
 # glue (python)
-pyo3 = { version = "0.22", features = ["extension-module", "multiple-pymethods"], optional = true}
+pyo3 = { version = "0.23", features = ["extension-module", "multiple-pymethods"], optional = true}
 
 # extra
 async-trait = { version = "0.1", optional = true }
@@ -61,7 +61,7 @@ serde = { version = "1.0", features = ["derive"], optional = true }
 # glue (js)
 napi-build = { version = "2.1", optional = true }
 # glue (python)
-pyo3-build-config = { version = "0.22", optional = true }
+pyo3-build-config = { version = "0.23", optional = true }
 
 [features]
 default = ["lua-jit", "py-abi3"]
diff --git a/src/ffi/python/controllers.rs b/src/ffi/python/controllers.rs
index 334abdd..3dd17bd 100644
--- a/src/ffi/python/controllers.rs
+++ b/src/ffi/python/controllers.rs
@@ -72,12 +72,12 @@ impl BufferController {
 	}
 
 	#[pyo3(name = "ack")]
-	fn pyack(&self, py: Python, v: Vec<i64>) -> () {
+	fn pyack(&self, v: Vec<i64>) -> () {
 		self.ack(v)
 	}
 
 	#[pyo3(name = "send")]
-	fn pysend(&self, _py: Python, op: TextChange) -> PyResult<()> {
+	fn pysend(&self, op: TextChange) -> PyResult<()> {
 		let this = self.clone();
 		this.send(op)?;
 		Ok(())
diff --git a/src/ffi/python/mod.rs b/src/ffi/python/mod.rs
index 4e6ecd1..7032e16 100644
--- a/src/ffi/python/mod.rs
+++ b/src/ffi/python/mod.rs
@@ -84,8 +84,10 @@ impl Promise {
 macro_rules! a_sync {
 	($x:expr) => {{
 		Ok($crate::ffi::python::Promise(Some(
-			$crate::ffi::python::tokio()
-				.spawn(async move { Ok($x.map(|f| Python::with_gil(|py| f.into_py(py)))?) }),
+			$crate::ffi::python::tokio().spawn(async move {
+				let res = $x?;
+				Python::with_gil(|py| Ok(res.into_pyobject(py)?.into_any().unbind()))
+			}),
 		)))
 	}};
 }
@@ -95,8 +97,10 @@ macro_rules! a_sync_allow_threads {
 	($py:ident, $x:expr) => {{
 		$py.allow_threads(move || {
 			Ok($crate::ffi::python::Promise(Some(
-				$crate::ffi::python::tokio()
-					.spawn(async move { Ok($x.map(|f| Python::with_gil(|py| f.into_py(py)))?) }),
+				$crate::ffi::python::tokio().spawn(async move {
+					let res = $x?;
+					Python::with_gil(|gil| Ok(res.into_pyobject(gil)?.into_any().unbind()))
+				}),
 			)))
 		})
 	}};
@@ -236,7 +240,7 @@ impl Selection {
 		buffer: String,
 		kwds: Option<&Bound<'_, PyDict>>,
 	) -> PyResult<Self> {
-		if let Some(kwds) = kwds {
+		if let Some(_kwds) = kwds {
 			Ok(Self {
 				start_row,
 				start_col,
@@ -277,7 +281,7 @@ impl TextChange {
 		content: String,
 		kwds: Option<&Bound<'_, PyDict>>,
 	) -> PyResult<Self> {
-		if let Some(kwds) = kwds {
+		if let Some(_kwds) = kwds {
 			Ok(Self {
 				start_idx: start,
 				end_idx: end,
@@ -300,7 +304,13 @@ impl TextChange {
 #[pyfunction]
 fn connect(py: Python, config: Py<Config>) -> PyResult<Promise> {
 	let conf: Config = config.extract(py)?;
-	a_sync!(Client::connect(conf).await)
+	Ok(Promise(Some(crate::ffi::python::tokio().spawn(
+		async move {
+			let client = Client::connect(conf).await?;
+			Python::with_gil(|py| Ok(client.into_pyobject(py)?.into_any().unbind()))
+		},
+	))))
+	// a_sync!(Client::connect(conf).await)
 }
 
 #[pyfunction]