From 0f9a7bf0c0c0322bef4eff7d254c6237b034323b Mon Sep 17 00:00:00 2001 From: Victoria Casasampere Fernandez Date: Thu, 30 Jan 2025 15:57:51 +0100 Subject: [PATCH] Update pyo3 to properly support py 3.13 --- Cargo.toml | 18 +-- reconnect.diff | 249 +++++++++++++++++++++++++++++++++++++ src/client.rs | 12 +- src/lib.rs | 5 +- src/python/client.rs | 73 +++++------ src/python/event.rs | 23 ++-- src/python/http.rs | 81 +++++++----- src/python/model/client.rs | 4 +- src/python/model/events.rs | 2 +- src/python/model/http.rs | 8 +- src/python/model/mod.rs | 6 +- src/python/model/player.rs | 8 +- src/python/model/search.rs | 2 +- src/python/model/track.rs | 14 +-- src/python/node.rs | 4 +- src/python/player.rs | 54 ++++---- 16 files changed, 417 insertions(+), 146 deletions(-) create mode 100644 reconnect.diff diff --git a/Cargo.toml b/Cargo.toml index af9f345..ae295c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ websockets-rustls-native-roots = ["tokio-websockets/rustls-native-roots", "_rust websockets-rustls-webpki-roots = ["tokio-websockets/rustls-webpki-roots", "_rustls-webpki-roots", "_websockets"] websockets-native-tls = ["tokio-websockets/native-tls", "_native-tls", "_websockets"] -python = ["pyo3", "pyo3-asyncio", "pyo3-log", "pythonize", "log", "paste", "macro_rules_attribute", "parking_lot"] +python = ["pyo3", "pyo3-async-runtimes", "pyo3-log", "pythonize", "log", "paste", "macro_rules_attribute", "parking_lot"] [package.metadata.docs.rs] features = ["tungstenite-rustls-webpki-roots", "twilight", "serenity", "songbird", "macros", "python"] @@ -121,21 +121,21 @@ version = "0.16" optional = true [dependencies.pyo3] -version = "0.20" -features = ["extension-module"] +version = "0.23" +features = ["extension-module", "py-clone"] optional = true [dependencies.pythonize] -version = "0.20" +version = "0.23" optional = true -[dependencies.pyo3-asyncio] -version = "0.20" +[dependencies.pyo3-async-runtimes] +version = "0.23" features = ["attributes", "tokio-runtime"] optional = true [dependencies.pyo3-log] -version = "0.9" +version = "0.12" optional = true [dependencies.log] @@ -157,8 +157,8 @@ optional = true [dependencies.macros-dep] package = "lavalink_rs_macros" -#version = "0.2" -path = "./lavalink_rs_macros" +version = "0.2" +#path = "./lavalink_rs_macros" optional = true diff --git a/reconnect.diff b/reconnect.diff new file mode 100644 index 0000000..efcfd84 --- /dev/null +++ b/reconnect.diff @@ -0,0 +1,249 @@ +diff --git a/examples/py_hikari_lightbulb/lavalink_voice.py b/examples/py_hikari_lightbulb/lavalink_voice.py +index 75ce9bd..ee81b75 100644 +--- a/examples/py_hikari_lightbulb/lavalink_voice.py ++++ b/examples/py_hikari_lightbulb/lavalink_voice.py +@@ -11,20 +11,17 @@ from lavalink_rs.model.player import ConnectionInfo + + + class LavalinkVoice(VoiceConnection): +- __slots__ = [ ++ __slots__ = ( + "lavalink", + "player", +- "__channel_id", +- "__guild_id", + "__session_id", +- "__is_alive", +- "__shard_id", +- "__on_close", + "__owner", +- ] ++ "__should_disconnect", ++ ) + lavalink: LavalinkClient + player: PlayerContext + ++ + def __init__( + self, + lavalink_client: LavalinkClient, +@@ -33,68 +30,56 @@ class LavalinkVoice(VoiceConnection): + channel_id: hikari.Snowflake, + guild_id: hikari.Snowflake, + session_id: str, +- is_alive: bool, + shard_id: int, + owner: VoiceComponent, +- on_close: t.Any, + ) -> None: ++ super().__init__(channel_id, guild_id, shard_id) ++ + self.player = player + self.lavalink = lavalink_client + +- self.__channel_id = channel_id +- self.__guild_id = guild_id + self.__session_id = session_id +- self.__is_alive = is_alive +- self.__shard_id = shard_id + self.__owner = owner +- self.__on_close = on_close +- +- @property +- def channel_id(self) -> hikari.Snowflake: +- """Return the ID of the voice channel this voice connection is in.""" +- return self.__channel_id + +- @property +- def guild_id(self) -> hikari.Snowflake: +- """Return the ID of the guild this voice connection is in.""" +- return self.__guild_id ++ self.__should_disconnect: bool = True + +- @property +- def is_alive(self) -> bool: +- """Return `builtins.True` if the connection is alive.""" +- return self.__is_alive + +- @property +- def shard_id(self) -> int: +- """Return the ID of the shard that requested the connection.""" +- return self.__shard_id ++ @staticmethod ++ async def reconnect(player: PlayerContext, endpoint: str, token: str, session_id: str) -> None: ++ update_player = UpdatePlayer() ++ connection_info = ConnectionInfo( ++ endpoint, token, session_id ++ ) ++ connection_info.fix() ++ update_player.voice = connection_info + +- @property +- def owner(self) -> VoiceComponent: +- """Return the component that is managing this connection.""" +- return self.__owner ++ await player.update_player(update_player, True) + + async def disconnect(self) -> None: + """Signal the process to shut down.""" +- self.__is_alive = False +- await self.lavalink.delete_player(self.__guild_id) +- await self.__on_close(self) +- +- async def join(self) -> None: +- """Wait for the process to halt before continuing.""" ++ if self.__should_disconnect: ++ await self.lavalink.delete_player(self.guild_id) ++ else: ++ self.__should_disconnect = True + + async def notify(self, event: hikari.VoiceEvent) -> None: + """Submit an event to the voice connection to be processed.""" +- if isinstance(event, hikari.VoiceServerUpdateEvent): +- # Handle the bot being moved frome one channel to another +- assert event.raw_endpoint +- update_player = UpdatePlayer() +- connection_info = ConnectionInfo( +- event.raw_endpoint, event.token, self.__session_id +- ) +- connection_info.fix() +- update_player.voice = connection_info +- await self.player.update_player(update_player, True) ++ if not isinstance(event, hikari.VoiceServerUpdateEvent): ++ return ++ ++ # TODO handle this better ++ # https://discord.com/developers/docs/topics/gateway-events#voice-server-update ++ assert event.raw_endpoint ++ ++ # Handle the bot being moved frome one channel to another ++ await LavalinkVoice.reconnect(self.player, event.raw_endpoint, event.token, self.__session_id) ++ ++ ++ @property ++ def owner(self) -> VoiceComponent: ++ """Return the component that is managing this connection.""" ++ return self.__owner ++ + + @classmethod + async def connect( +@@ -106,9 +91,19 @@ class LavalinkVoice(VoiceConnection): + player_data: t.Any, + deaf: bool = True, + ) -> LavalinkVoice: ++ try: ++ conn = client.voice.connections.get(guild_id) ++ if conn: ++ assert isinstance(conn, LavalinkVoice) ++ conn.__should_disconnect = False ++ await client.voice.disconnect(guild_id) ++ except: ++ pass ++ + voice: LavalinkVoice = await client.voice.connect_to( + guild_id, + channel_id, ++ disconnect_existing=False, + voice_connection_type=LavalinkVoice, + lavalink_client=lavalink_client, + player_data=player_data, +@@ -117,13 +112,13 @@ class LavalinkVoice(VoiceConnection): + + return voice + ++ + @classmethod + async def initialize( + cls, + channel_id: hikari.Snowflake, + endpoint: str, + guild_id: hikari.Snowflake, +- on_close: t.Any, + owner: VoiceComponent, + session_id: str, + shard_id: int, +@@ -132,14 +127,19 @@ class LavalinkVoice(VoiceConnection): + **kwargs: t.Any, + ) -> LavalinkVoice: + del user_id +- lavalink_client = kwargs["lavalink_client"] +- +- player = await lavalink_client.create_player_context( +- guild_id, endpoint, token, session_id +- ) + ++ lavalink_client = kwargs["lavalink_client"] + player_data = kwargs["player_data"] + ++ player = lavalink_client.get_player_context(guild_id) ++ ++ if player: ++ await LavalinkVoice.reconnect(player, endpoint, token, session_id) ++ else: ++ player = await lavalink_client.create_player_context( ++ guild_id, endpoint, token, session_id ++ ) ++ + if player_data: + player.data = player_data + +@@ -149,10 +149,8 @@ class LavalinkVoice(VoiceConnection): + channel_id=channel_id, + guild_id=guild_id, + session_id=session_id, +- is_alive=True, + shard_id=shard_id, + owner=owner, +- on_close=on_close, + ) + + return self +diff --git a/examples/py_hikari_lightbulb/plugins/music_basic.py b/examples/py_hikari_lightbulb/plugins/music_basic.py +index da463c3..1cb43e1 100644 +--- a/examples/py_hikari_lightbulb/plugins/music_basic.py ++++ b/examples/py_hikari_lightbulb/plugins/music_basic.py +@@ -33,27 +33,13 @@ async def _join(ctx: Context) -> t.Optional[hikari.Snowflake]: + + channel_id = voice_state.channel_id + +- voice = ctx.bot.voice.connections.get(ctx.guild_id) +- +- if not voice: +- await LavalinkVoice.connect( +- ctx.guild_id, +- channel_id, +- ctx.bot, +- ctx.bot.lavalink, +- (ctx.channel_id, ctx.bot.rest), +- ) +- else: +- assert isinstance(voice, LavalinkVoice) +- +- await LavalinkVoice.connect( +- ctx.guild_id, +- channel_id, +- ctx.bot, +- ctx.bot.lavalink, +- (ctx.channel_id, ctx.bot.rest), +- old_voice=voice, +- ) ++ await LavalinkVoice.connect( ++ ctx.guild_id, ++ channel_id, ++ ctx.bot, ++ ctx.bot.lavalink, ++ (ctx.channel_id, ctx.bot.rest), ++ ) + + return channel_id + +@@ -96,7 +82,7 @@ async def leave(ctx: Context) -> None: + await ctx.respond("Not in a voice channel") + return None + +- await voice.disconnect() ++ await ctx.bot.voice.disconnect(ctx.guild_id) + + await ctx.respond("Left the voice channel") + diff --git a/src/client.rs b/src/client.rs index 988d285..0f8ee30 100644 --- a/src/client.rs +++ b/src/client.rs @@ -19,7 +19,7 @@ use tokio::sync::Mutex; pub struct LavalinkClient { pub nodes: Vec>, pub players: Arc, Arc)>>, - pub events: events::Events, + pub events: Arc, tx: UnboundedSender, user_id: UserId, user_data: Arc, @@ -165,7 +165,7 @@ impl LavalinkClient { user_id: built_nodes[0].user_id, nodes: built_nodes, players: Arc::new(DashMap::new()), - events, + events: Arc::new(events), tx, user_data, strategy, @@ -270,21 +270,21 @@ impl LavalinkClient { Python::with_gil(|py| { let func = func.into_py(py); - let current_loop = pyo3_asyncio::tokio::get_current_loop(py).unwrap(); + let current_loop = pyo3_async_runtimes::tokio::get_current_loop(py).unwrap(); let client = client.clone(); let client2 = client.clone(); - pyo3_asyncio::tokio::future_into_py_with_locals( + pyo3_async_runtimes::tokio::future_into_py_with_locals( py, - pyo3_asyncio::TaskLocals::new(current_loop), + pyo3_async_runtimes::TaskLocals::new(current_loop), async move { let future = Python::with_gil(|py| { let coro = func .call(py, (client.into_py(py), guild_id.into_py(py)), None) .unwrap(); - pyo3_asyncio::tokio::into_future(coro.downcast(py).unwrap()) + pyo3_async_runtimes::tokio::into_future(coro.into_bound(py)) }) .unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 16df029..bc60315 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ mod python; #[cfg(feature = "python")] #[pymodule] -fn lavalink_rs(py: Python<'_>, m: &PyModule) -> PyResult<()> { +fn lavalink_rs(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { let handle = pyo3_log::Logger::new(py, pyo3_log::Caching::LoggersAndLevels)? .filter(log::LevelFilter::Trace) .install() @@ -90,7 +90,8 @@ fn lavalink_rs(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_wrapped(wrap_pymodule!(python::model::model))?; let sys = PyModule::import(py, "sys")?; - let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; + let raw_modules = sys.getattr("modules")?; + let sys_modules: &Bound<'_, PyDict> = raw_modules.downcast()?; sys_modules.set_item("lavalink_rs.model", m.getattr("model")?)?; Ok(()) diff --git a/src/python/client.rs b/src/python/client.rs index 16f0a9f..819e7a0 100644 --- a/src/python/client.rs +++ b/src/python/client.rs @@ -9,7 +9,7 @@ use pyo3::prelude::*; use pyo3::types::PyList; #[pymodule] -pub fn client(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn client(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; Ok(()) @@ -28,6 +28,7 @@ fn raw_event( #[pymethods] impl crate::client::LavalinkClient { #[pyo3(name = "new")] + #[pyo3(signature = (events, nodes, strategy, user_data=None))] #[staticmethod] fn new_py<'a>( py: Python<'a>, @@ -35,8 +36,8 @@ impl crate::client::LavalinkClient { nodes: Vec, strategy: super::model::client::NodeDistributionStrategyPy, user_data: Option, - ) -> PyResult<&'a PyAny> { - let current_loop = pyo3_asyncio::get_running_loop(py)?; + ) -> PyResult> { + let current_loop = pyo3_async_runtimes::get_running_loop(py)?; let loop_ref = PyObject::from(current_loop); let event_handler = crate::python::event::EventHandler { @@ -50,9 +51,9 @@ impl crate::client::LavalinkClient { ..Default::default() }; - pyo3_asyncio::tokio::future_into_py_with_locals( + pyo3_async_runtimes::tokio::future_into_py_with_locals( py, - pyo3_asyncio::tokio::get_current_locals(py)?, + pyo3_async_runtimes::tokio::get_current_locals(py)?, async move { if let Some(data) = user_data { Ok(crate::client::LavalinkClient::new_with_data( @@ -84,12 +85,12 @@ impl crate::client::LavalinkClient { token: String, session_id: String, user_data: Option, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py_with_locals( + pyo3_async_runtimes::tokio::future_into_py_with_locals( py, - pyo3_asyncio::tokio::get_current_locals(py)?, + pyo3_async_runtimes::tokio::get_current_locals(py)?, async move { if let Some(data) = user_data { Ok(client @@ -128,10 +129,10 @@ impl crate::client::LavalinkClient { endpoint: String, token: String, session_id: String, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player = client .create_player( guild_id, @@ -168,10 +169,10 @@ impl crate::client::LavalinkClient { &self, py: Python<'a>, guild_id: super::model::PyGuildId, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = client.get_node_for_guild(guild_id).await; Ok(Python::with_gil(|_py| super::node::Node { inner: res })) @@ -184,10 +185,10 @@ impl crate::client::LavalinkClient { py: Python<'a>, guild_id: super::model::PyGuildId, identifier: String, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let tracks = client.load_tracks(guild_id, &identifier).await?; use crate::model::track::TrackLoadData::*; @@ -221,10 +222,10 @@ impl crate::client::LavalinkClient { &self, py: Python<'a>, guild_id: super::model::PyGuildId, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { client.delete_player(guild_id).await?; Ok(()) @@ -232,10 +233,10 @@ impl crate::client::LavalinkClient { } #[pyo3(name = "delete_all_player_contexts")] - fn delete_all_player_contexts_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + fn delete_all_player_contexts_py<'a>(&self, py: Python<'a>) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { client.delete_all_player_contexts().await?; Ok(()) @@ -249,10 +250,10 @@ impl crate::client::LavalinkClient { guild_id: super::model::PyGuildId, update_player: UpdatePlayer, no_replace: bool, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player = client .update_player(guild_id, &update_player, no_replace) .await?; @@ -267,10 +268,10 @@ impl crate::client::LavalinkClient { py: Python<'a>, guild_id: super::model::PyGuildId, track: String, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let track = client.decode_track(guild_id, &track).await?; Ok(track) @@ -283,10 +284,10 @@ impl crate::client::LavalinkClient { py: Python<'a>, guild_id: super::model::PyGuildId, tracks: Vec, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let tracks = client.decode_tracks(guild_id, &tracks).await?; Ok(tracks) @@ -298,10 +299,10 @@ impl crate::client::LavalinkClient { &self, py: Python<'a>, guild_id: super::model::PyGuildId, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let version = client.request_version(guild_id).await?; Ok(version) @@ -313,10 +314,10 @@ impl crate::client::LavalinkClient { &self, py: Python<'a>, guild_id: super::model::PyGuildId, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let info = client.request_info(guild_id).await?; Ok(info) @@ -328,10 +329,10 @@ impl crate::client::LavalinkClient { &self, py: Python<'a>, guild_id: super::model::PyGuildId, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let stats = client.request_stats(guild_id).await?; Ok(stats) @@ -343,10 +344,10 @@ impl crate::client::LavalinkClient { &self, py: Python<'a>, guild_id: super::model::PyGuildId, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player = client.request_player(guild_id).await?; Ok(player) @@ -358,10 +359,10 @@ impl crate::client::LavalinkClient { &self, py: Python<'a>, guild_id: super::model::PyGuildId, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let players = client.request_all_players(guild_id).await?; Ok(players) @@ -415,11 +416,11 @@ impl crate::client::LavalinkClient { py: Python<'a>, guild_id: super::model::PyGuildId, timeout: u64, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let timeout = std::time::Duration::from_millis(timeout); let client = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let connection_info = client.get_connection_info(guild_id, timeout).await?; Ok(connection_info) diff --git a/src/python/event.rs b/src/python/event.rs index ab0d3da..e52f4c1 100644 --- a/src/python/event.rs +++ b/src/python/event.rs @@ -6,7 +6,7 @@ use pyo3::prelude::*; pyo3::import_exception!(builtins, NameError); #[pymodule] -pub fn event(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn event(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; Ok(()) @@ -23,7 +23,7 @@ pub struct EventHandler { impl EventHandler { #[new] fn new(py: Python<'_>) -> PyResult { - let current_loop = pyo3_asyncio::get_running_loop(py)?; + let current_loop = pyo3_async_runtimes::get_running_loop(py)?; let loop_ref = PyObject::from(current_loop); Ok(Self { @@ -125,30 +125,31 @@ impl EventHandler { } } -fn call_event + 'static>( +fn call_event pyo3::IntoPyObject<'a> + 'static>( handler: &EventHandler, client: LavalinkClient, session_id: String, event: T, name: &'static str, ) { - let slf1 = handler.clone(); - let slf2 = handler.clone(); + let (slf1, slf2) = Python::with_gil(|_| { + (handler.clone(), handler.clone()) + }); Python::with_gil(|py| { - let current_loop = slf1.current_loop.as_ref(py); + let current_loop = slf1.current_loop.into_bound(py); - pyo3_asyncio::tokio::future_into_py_with_locals( + pyo3_async_runtimes::tokio::future_into_py_with_locals( py, - pyo3_asyncio::TaskLocals::new(current_loop), + pyo3_async_runtimes::TaskLocals::new(current_loop), async move { let future = Python::with_gil(|py| { - let py_event_handler = slf2.inner.as_ref(py); let coro_result = - py_event_handler.call_method(name, (client, session_id, event), None); + slf2.inner + .call_method(py, name, (client, session_id, event), None); if let Ok(coro) = coro_result { - pyo3_asyncio::tokio::into_future(coro) + pyo3_async_runtimes::tokio::into_future(coro.into_bound(py)) } else { Err(NameError::new_err("Undefined event")) } diff --git a/src/python/http.rs b/src/python/http.rs index dea3c35..f41ffdf 100644 --- a/src/python/http.rs +++ b/src/python/http.rs @@ -3,7 +3,7 @@ use pyo3::types::PyList; use pythonize::{depythonize, pythonize}; #[pymodule] -pub fn http(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn http(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; Ok(()) @@ -53,12 +53,14 @@ impl Http { method: String, uri: String, data: PyObject, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { - let data = - Python::with_gil(|py| depythonize::>(data.as_ref(py)))?; + pyo3_async_runtimes::tokio::future_into_py(py, async move { + let data = Python::with_gil(|py| { + depythonize::>(data.downcast_bound(py)?) + })?; + let res = http .request::( ::http::Method::from_bytes(method.as_bytes()) @@ -68,7 +70,9 @@ impl Http { ) .await?; - Ok(Python::with_gil(|py| pythonize(py, &res))?) + Ok(Python::with_gil(|py| { + PyObject::from(pythonize(py, &res).unwrap()) + })) }) } @@ -78,12 +82,13 @@ impl Http { method: String, uri: String, data: PyObject, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { - let data = - Python::with_gil(|py| depythonize::>(data.as_ref(py)))?; + pyo3_async_runtimes::tokio::future_into_py(py, async move { + let data = Python::with_gil(|py| { + depythonize::>(data.downcast_bound(py)?) + })?; let res = http .raw_request( @@ -104,10 +109,10 @@ impl Http { py: Python<'a>, guild_id: super::model::PyGuildId, session_id: String, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.delete_player(guild_id, &session_id).await?; Ok(Python::with_gil(|_py| res)) @@ -122,10 +127,10 @@ impl Http { session_id: String, data: crate::model::http::UpdatePlayer, no_replace: bool, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http .update_player(guild_id, &session_id, &data, no_replace) .await?; @@ -140,10 +145,10 @@ impl Http { py: Python<'a>, session_id: String, resuming_state: crate::model::http::ResumingState, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http .set_resuming_state(&session_id, &resuming_state) .await?; @@ -160,10 +165,14 @@ impl Http { /// - Can be a url: "https://youtu.be/watch?v=DrM2lo6B04I" /// - A unique identifier: "DrM2lo6B04I" /// - A search: "ytsearch:Ne Obliviscaris - Forget Not" - pub fn load_tracks<'a>(&self, py: Python<'a>, identifier: String) -> PyResult<&'a PyAny> { + pub fn load_tracks<'a>( + &self, + py: Python<'a>, + identifier: String, + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let tracks = http.load_tracks(&identifier).await?; use crate::model::track::TrackLoadData::*; @@ -193,10 +202,10 @@ impl Http { } /// Request Lavalink server version. - pub fn version<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + pub fn version<'a>(&self, py: Python<'a>) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.version().await?; Ok(Python::with_gil(|_py| res)) @@ -206,10 +215,10 @@ impl Http { /// Request Lavalink statistics. /// /// NOTE: The frame stats will never be returned. - pub fn stats<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + pub fn stats<'a>(&self, py: Python<'a>) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.stats().await?; Ok(Python::with_gil(|_py| res)) @@ -217,10 +226,10 @@ impl Http { } /// Request Lavalink server information. - pub fn info<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + pub fn info<'a>(&self, py: Python<'a>) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.info().await?; Ok(Python::with_gil(|_py| res)) @@ -232,10 +241,10 @@ impl Http { /// # Parameters /// /// - `track`: base64 encoded track data. - pub fn decode_track<'a>(&self, py: Python<'a>, track: String) -> PyResult<&'a PyAny> { + pub fn decode_track<'a>(&self, py: Python<'a>, track: String) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.decode_track(&track).await?; Ok(Python::with_gil(|_py| res)) @@ -247,10 +256,14 @@ impl Http { /// # Parameters /// /// - `tracks`: base64 encoded tracks. - pub fn decode_tracks<'a>(&self, py: Python<'a>, tracks: Vec) -> PyResult<&'a PyAny> { + pub fn decode_tracks<'a>( + &self, + py: Python<'a>, + tracks: Vec, + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.decode_tracks(&tracks).await?; Ok(Python::with_gil(|_py| res)) @@ -263,10 +276,10 @@ impl Http { py: Python<'a>, guild_id: super::model::PyGuildId, session_id: String, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.get_player(guild_id, &session_id).await?; Ok(Python::with_gil(|_py| res)) @@ -274,10 +287,14 @@ impl Http { } /// Returns a list of players in this specific session. - pub fn get_players<'a>(&self, py: Python<'a>, session_id: String) -> PyResult<&'a PyAny> { + pub fn get_players<'a>( + &self, + py: Python<'a>, + session_id: String, + ) -> PyResult> { let http = self.inner.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = http.get_players(&session_id).await?; Ok(Python::with_gil(|_py| res)) diff --git a/src/python/model/client.rs b/src/python/model/client.rs index ee53210..318e7a1 100644 --- a/src/python/model/client.rs +++ b/src/python/model/client.rs @@ -1,12 +1,12 @@ use crate::model::client::NodeDistributionStrategy; use pyo3::prelude::*; -pub fn client(py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn client(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { let client = PyModule::new(py, "client")?; client.add_class::()?; - m.add_submodule(client)?; + m.add_submodule(&client)?; Ok(()) } diff --git a/src/python/model/events.rs b/src/python/model/events.rs index bec65d5..d26f106 100644 --- a/src/python/model/events.rs +++ b/src/python/model/events.rs @@ -3,7 +3,7 @@ use crate::model::events::*; use pyo3::prelude::*; #[pymodule] -pub fn events(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn events(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/src/python/model/http.rs b/src/python/model/http.rs index ccfa093..3297aab 100644 --- a/src/python/model/http.rs +++ b/src/python/model/http.rs @@ -3,7 +3,7 @@ use crate::model::http::*; use pyo3::prelude::*; use pythonize::{depythonize, pythonize}; -pub fn http(py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn http(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { let http = PyModule::new(py, "http")?; http.add_class::()?; @@ -14,7 +14,7 @@ pub fn http(py: Python<'_>, m: &PyModule) -> PyResult<()> { http.add_class::()?; http.add_class::()?; - m.add_submodule(http)?; + m.add_submodule(&http)?; Ok(()) } @@ -39,11 +39,11 @@ impl UpdatePlayerTrack { #[getter(user_data)] fn get_user_data(&self, py: Python<'_>) -> PyObject { - pythonize(py, &self.user_data).unwrap() + pythonize(py, &self.user_data).unwrap().into() } #[setter(user_data)] fn set_user_data(&mut self, py: Python<'_>, input: PyObject) { - self.user_data = depythonize(input.as_ref(py)).unwrap() + self.user_data = depythonize(&input.into_bound(py)).unwrap() } } diff --git a/src/python/model/mod.rs b/src/python/model/mod.rs index fd80adf..742664c 100644 --- a/src/python/model/mod.rs +++ b/src/python/model/mod.rs @@ -10,7 +10,7 @@ use pyo3::types::PyDict; use pyo3::wrap_pymodule; #[pymodule] -pub fn model(py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn model(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -23,7 +23,9 @@ pub fn model(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_wrapped(wrap_pymodule!(self::track::track))?; let sys = PyModule::import(py, "sys")?; - let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?; + let raw_modules = sys.getattr("modules")?; + let sys_modules: &Bound<'_, PyDict> = raw_modules.downcast()?; + sys_modules.set_item("lavalink_rs.model.client", m.getattr("client")?)?; sys_modules.set_item("lavalink_rs.model.events", m.getattr("events")?)?; sys_modules.set_item("lavalink_rs.model.http", m.getattr("http")?)?; diff --git a/src/python/model/player.rs b/src/python/model/player.rs index 47b5199..4041727 100644 --- a/src/python/model/player.rs +++ b/src/python/model/player.rs @@ -3,7 +3,7 @@ use crate::model::player::*; use pyo3::prelude::*; use pythonize::{depythonize, pythonize}; -pub fn player(py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn player(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { let player = PyModule::new(py, "player")?; player.add_class::()?; @@ -19,7 +19,7 @@ pub fn player(py: Python<'_>, m: &PyModule) -> PyResult<()> { player.add_class::()?; player.add_class::()?; - m.add_submodule(player)?; + m.add_submodule(&player)?; Ok(()) } @@ -128,11 +128,11 @@ impl Filters { #[getter(plugin_filters)] fn get_plugin_filters(&self, py: Python<'_>) -> PyObject { - pythonize(py, &self.plugin_filters).unwrap() + pythonize(py, &self.plugin_filters).unwrap().into() } #[setter(plugin_filters)] fn set_plugin_filters(&mut self, py: Python<'_>, input: PyObject) { - self.plugin_filters = depythonize(input.as_ref(py)).unwrap() + self.plugin_filters = depythonize(&input.into_bound(py)).unwrap() } } diff --git a/src/python/model/search.rs b/src/python/model/search.rs index f7299a2..a141c4a 100644 --- a/src/python/model/search.rs +++ b/src/python/model/search.rs @@ -4,7 +4,7 @@ use crate::model::search::*; use pyo3::prelude::*; #[pymodule] -pub fn search(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn search(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/src/python/model/track.rs b/src/python/model/track.rs index ae52c33..cc40bac 100644 --- a/src/python/model/track.rs +++ b/src/python/model/track.rs @@ -4,7 +4,7 @@ use pyo3::prelude::*; use pythonize::{depythonize, pythonize}; #[pymodule] -pub fn track(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn track(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; //m.add_class::()?; m.add_class::()?; @@ -30,22 +30,22 @@ impl TrackData { #[getter(plugin_info)] fn get_plugin_info(&self, py: Python<'_>) -> PyObject { - pythonize(py, &self.plugin_info).unwrap() + pythonize(py, &self.plugin_info).unwrap().into() } #[setter(plugin_info)] fn set_plugin_info(&mut self, py: Python<'_>, input: PyObject) { - self.plugin_info = depythonize(input.as_ref(py)).unwrap() + self.plugin_info = depythonize(&input.into_bound(py)).unwrap() } #[getter(user_data)] fn get_user_data(&self, py: Python<'_>) -> PyObject { - pythonize(py, &self.user_data).unwrap() + pythonize(py, &self.user_data).unwrap().into() } #[setter(user_data)] fn set_user_data(&mut self, py: Python<'_>, input: PyObject) { - self.user_data = depythonize(input.as_ref(py)).unwrap() + self.user_data = depythonize(&input.into_bound(py)).unwrap() } } @@ -56,11 +56,11 @@ impl PlaylistData { #[getter(plugin_info)] fn get_plugin_info(&self, py: Python<'_>) -> PyObject { - pythonize(py, &self.plugin_info).unwrap() + pythonize(py, &self.plugin_info).unwrap().into() } #[setter(plugin_info)] fn set_plugin_info(&mut self, py: Python<'_>, input: PyObject) { - self.plugin_info = depythonize(input.as_ref(py)).unwrap() + self.plugin_info = depythonize(&input.into_bound(py)).unwrap() } } diff --git a/src/python/node.rs b/src/python/node.rs index a1156a9..5f45f1e 100644 --- a/src/python/node.rs +++ b/src/python/node.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use pyo3::prelude::*; #[pymodule] -pub fn node(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn node(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; @@ -50,7 +50,7 @@ impl crate::node::NodeBuilder { events: Option, ) -> PyResult { let events = if let Some(events) = events { - let current_loop = pyo3_asyncio::get_running_loop(py)?; + let current_loop = pyo3_async_runtimes::get_running_loop(py)?; let loop_ref = PyObject::from(current_loop); let event_handler = crate::python::event::EventHandler { diff --git a/src/python/player.rs b/src/python/player.rs index e180f4a..56531e9 100644 --- a/src/python/player.rs +++ b/src/python/player.rs @@ -13,7 +13,7 @@ use parking_lot::RwLock; use pyo3::prelude::*; #[pymodule] -pub fn player(_py: Python<'_>, m: &PyModule) -> PyResult<()> { +pub fn player(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; @@ -29,10 +29,10 @@ impl crate::player_context::PlayerContext { } #[pyo3(name = "get_player")] - fn get_player_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + fn get_player_py<'a>(&self, py: Python<'a>) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player_inner = player.get_player().await?; Ok(Python::with_gil(|_py| player_inner)) @@ -45,10 +45,10 @@ impl crate::player_context::PlayerContext { py: Python<'a>, update_player: UpdatePlayer, no_replace: bool, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player_inner = player.update_player(&update_player, no_replace).await?; Ok(Python::with_gil(|_py| player_inner)) @@ -60,10 +60,10 @@ impl crate::player_context::PlayerContext { &self, py: Python<'a>, track: crate::model::track::TrackData, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { player.play(&track).await?; Ok(Python::with_gil(|py| py.None())) @@ -75,10 +75,10 @@ impl crate::player_context::PlayerContext { &self, py: Python<'a>, track: crate::model::track::TrackData, - ) -> PyResult<&'a PyAny> { + ) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { player.play_now(&track).await?; Ok(Python::with_gil(|py| py.None())) @@ -86,10 +86,10 @@ impl crate::player_context::PlayerContext { } #[pyo3(name = "stop_now")] - fn stop_now_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + fn stop_now_py<'a>(&self, py: Python<'a>) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player_inner = player.stop_now().await?; Ok(Python::with_gil(|_py| player_inner)) @@ -97,10 +97,10 @@ impl crate::player_context::PlayerContext { } #[pyo3(name = "set_pause")] - fn set_pause_py<'a>(&self, py: Python<'a>, pause: bool) -> PyResult<&'a PyAny> { + fn set_pause_py<'a>(&self, py: Python<'a>, pause: bool) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player_inner = player.set_pause(pause).await?; Ok(Python::with_gil(|_py| player_inner)) @@ -108,10 +108,10 @@ impl crate::player_context::PlayerContext { } #[pyo3(name = "set_volume")] - fn set_volume_py<'a>(&self, py: Python<'a>, volume: u16) -> PyResult<&'a PyAny> { + fn set_volume_py<'a>(&self, py: Python<'a>, volume: u16) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player_inner = player.set_volume(volume).await?; Ok(Python::with_gil(|_py| player_inner)) @@ -119,10 +119,10 @@ impl crate::player_context::PlayerContext { } #[pyo3(name = "set_filters")] - fn set_filters_py<'a>(&self, py: Python<'a>, filters: Filters) -> PyResult<&'a PyAny> { + fn set_filters_py<'a>(&self, py: Python<'a>, filters: Filters) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player_inner = player.set_filters(filters).await?; Ok(Python::with_gil(|_py| player_inner)) @@ -130,10 +130,10 @@ impl crate::player_context::PlayerContext { } #[pyo3(name = "set_position_ms")] - fn set_position_ms_py<'a>(&self, py: Python<'a>, position: u64) -> PyResult<&'a PyAny> { + fn set_position_ms_py<'a>(&self, py: Python<'a>, position: u64) -> PyResult> { let player = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let player_inner = player.set_position(Duration::from_millis(position)).await?; Ok(Python::with_gil(|_py| player_inner)) @@ -194,10 +194,10 @@ impl crate::player_context::PlayerContext { #[pymethods] impl crate::player_context::QueueRef { #[pyo3(name = "get_queue")] - fn get_queue_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + fn get_queue_py<'a>(&self, py: Python<'a>) -> PyResult> { let queue = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let q: Vec<_> = queue.get_queue().await?.into(); Ok(Python::with_gil(|_py| q)) @@ -205,10 +205,10 @@ impl crate::player_context::QueueRef { } #[pyo3(name = "get_track")] - fn get_track_py<'a>(&self, py: Python<'a>, index: usize) -> PyResult<&'a PyAny> { + fn get_track_py<'a>(&self, py: Python<'a>, index: usize) -> PyResult> { let queue = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let q = queue.get_track(index).await?; Ok(Python::with_gil(|_py| q)) @@ -216,10 +216,10 @@ impl crate::player_context::QueueRef { } #[pyo3(name = "get_count")] - fn get_count_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> { + fn get_count_py<'a>(&self, py: Python<'a>) -> PyResult> { let queue = self.clone(); - pyo3_asyncio::tokio::future_into_py(py, async move { + pyo3_async_runtimes::tokio::future_into_py(py, async move { let q = queue.get_count().await?; Ok(Python::with_gil(|_py| q)) @@ -269,10 +269,10 @@ impl crate::player_context::QueueRef { // TODO: pyo3 0.21 // https://github.com/PyO3/pyo3/pull/3661 //#[pyo3(name = "__anext__")] - //fn async_for_impl<'a>(&mut self, py: Python<'a>) -> PyResult<&'a PyAny> { + //fn async_for_impl<'a>(&mut self, py: Python<'a>) -> PyResult> { // use futures::StreamExt; - // pyo3_asyncio::tokio::future_into_py(py, async move { Ok(self.next().await) }) + // pyo3_async_runtimes::tokio::future_into_py(py, async move { Ok(self.next().await) }) //} }