This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new e77f0794b refactor: Remove scheme from python binding (#6863)
e77f0794b is described below
commit e77f0794b14db0a211bd161aecd9d5f27ade6b1f
Author: Xuanwo <[email protected]>
AuthorDate: Thu Dec 4 18:32:24 2025 +0800
refactor: Remove scheme from python binding (#6863)
* refactor: Remove schema from python binding
Signed-off-by: Xuanwo <[email protected]>
* Fix build
Signed-off-by: Xuanwo <[email protected]>
---------
Signed-off-by: Xuanwo <[email protected]>
---
bindings/python/python/opendal/operator.pyi | 14 ++
bindings/python/src/operator.rs | 64 +++--
bindings/python/src/services.rs | 376 ++++++++++++----------------
dev/src/generate/python.j2 | 81 +++---
4 files changed, 251 insertions(+), 284 deletions(-)
diff --git a/bindings/python/python/opendal/operator.pyi
b/bindings/python/python/opendal/operator.pyi
index 9ae772a22..54c9f2f9e 100644
--- a/bindings/python/python/opendal/operator.pyi
+++ b/bindings/python/python/opendal/operator.pyi
@@ -504,6 +504,13 @@ class AsyncOperator:
The blocking operator.
"""
@typing.overload
+ def __new__(
+ cls,
+ scheme: builtins.str,
+ /,
+ **kwargs: builtins.str,
+ ) -> typing_extensions.Self: ...
+ @typing.overload
def __new__(
cls,
scheme: opendal.services.Scheme.AliyunDrive |
typing.Literal["aliyun-drive"],
@@ -2737,6 +2744,13 @@ class Operator:
The async operator.
"""
@typing.overload
+ def __new__(
+ cls,
+ scheme: builtins.str,
+ /,
+ **kwargs: builtins.str,
+ ) -> typing_extensions.Self: ...
+ @typing.overload
def __new__(
cls,
scheme: opendal.services.Scheme.AliyunDrive |
typing.Literal["aliyun-drive"],
diff --git a/bindings/python/src/operator.rs b/bindings/python/src/operator.rs
index c7c360240..90015d41b 100644
--- a/bindings/python/src/operator.rs
+++ b/bindings/python/src/operator.rs
@@ -17,7 +17,6 @@
use std::collections::HashMap;
use std::path::PathBuf;
-use std::str::FromStr;
use std::time::Duration;
use pyo3::IntoPyObjectExt;
@@ -29,16 +28,13 @@ use pyo3_async_runtimes::tokio::future_into_py;
use crate::*;
-fn build_operator(
- scheme: ocore::Scheme,
- map: HashMap<String, String>,
-) -> PyResult<ocore::Operator> {
+fn build_operator(scheme: &str, map: HashMap<String, String>) ->
PyResult<ocore::Operator> {
let op = ocore::Operator::via_iter(scheme, map).map_err(format_pyerr)?;
Ok(op)
}
fn build_blocking_operator(
- scheme: ocore::Scheme,
+ scheme: &str,
map: HashMap<String, String>,
) -> PyResult<ocore::blocking::Operator> {
let op = ocore::Operator::via_iter(scheme, map).map_err(format_pyerr)?;
@@ -49,6 +45,10 @@ fn build_blocking_operator(
Ok(op)
}
+fn normalize_scheme(raw: &str) -> String {
+ raw.trim().to_ascii_lowercase().replace('_', "-")
+}
+
/// The blocking equivalent of `AsyncOperator`.
///
/// `Operator` is the entry point for all blocking APIs.
@@ -60,7 +60,7 @@ fn build_blocking_operator(
#[pyclass(module = "opendal.operator")]
pub struct Operator {
core: ocore::blocking::Operator,
- __scheme: ocore::Scheme,
+ __scheme: String,
__map: HashMap<String, String>,
}
@@ -89,19 +89,15 @@ impl Operator {
kwargs: Option<&Bound<PyDict>>,
) -> PyResult<Self> {
let scheme = if let Ok(scheme_str) = scheme.extract::<&str>() {
- ocore::Scheme::from_str(scheme_str)
- .map_err(|err| {
- ocore::Error::new(ocore::ErrorKind::Unexpected,
"unsupported scheme")
- .set_source(err)
- })
- .map_err(format_pyerr)
+ scheme_str.to_string()
} else if let Ok(py_scheme) = scheme.extract::<PyScheme>() {
- Ok(py_scheme.into())
+ String::from(py_scheme)
} else {
- Err(Unsupported::new_err(
+ return Err(Unsupported::new_err(
"Invalid type for scheme, expected str or Scheme",
- ))
- }?;
+ ));
+ };
+ let scheme = normalize_scheme(&scheme);
let map = kwargs
.map(|v| {
v.extract::<HashMap<String, String>>()
@@ -110,7 +106,7 @@ impl Operator {
.unwrap_or_default();
Ok(Operator {
- core: build_blocking_operator(scheme, map.clone())?,
+ core: build_blocking_operator(&scheme, map.clone())?,
__scheme: scheme,
__map: map,
})
@@ -135,7 +131,7 @@ impl Operator {
let op = ocore::blocking::Operator::new(op).map_err(format_pyerr)?;
Ok(Self {
core: op,
- __scheme: self.__scheme,
+ __scheme: self.__scheme.clone(),
__map: self.__map.clone(),
})
}
@@ -670,7 +666,7 @@ impl Operator {
pub fn to_async_operator(&self) -> PyResult<AsyncOperator> {
Ok(AsyncOperator {
core: self.core.clone().into(),
- __scheme: self.__scheme,
+ __scheme: self.__scheme.clone(),
__map: self.__map.clone(),
})
}
@@ -691,7 +687,7 @@ impl Operator {
#[gen_stub(skip)]
fn __getnewargs_ex__(&self, py: Python) -> PyResult<Py<PyAny>> {
- let args = vec![self.__scheme.to_string()];
+ let args = vec![self.__scheme.clone()];
let args = PyTuple::new(py, args)?.into_py_any(py)?;
let kwargs = self.__map.clone().into_py_any(py)?;
PyTuple::new(py, [args, kwargs])?.into_py_any(py)
@@ -709,7 +705,7 @@ impl Operator {
#[pyclass(module = "opendal.operator")]
pub struct AsyncOperator {
core: ocore::Operator,
- __scheme: ocore::Scheme,
+ __scheme: String,
__map: HashMap<String, String>,
}
@@ -738,19 +734,15 @@ impl AsyncOperator {
kwargs: Option<&Bound<PyDict>>,
) -> PyResult<Self> {
let scheme = if let Ok(scheme_str) = scheme.extract::<&str>() {
- ocore::Scheme::from_str(scheme_str)
- .map_err(|err| {
- ocore::Error::new(ocore::ErrorKind::Unexpected,
"unsupported scheme")
- .set_source(err)
- })
- .map_err(format_pyerr)
+ scheme_str.to_string()
} else if let Ok(py_scheme) = scheme.extract::<PyScheme>() {
- Ok(py_scheme.into())
+ String::from(py_scheme)
} else {
- Err(Unsupported::new_err(
+ return Err(Unsupported::new_err(
"Invalid type for scheme, expected str or Scheme",
- ))
- }?;
+ ));
+ };
+ let scheme = normalize_scheme(&scheme);
let map = kwargs
.map(|v| {
@@ -760,7 +752,7 @@ impl AsyncOperator {
.unwrap_or_default();
Ok(AsyncOperator {
- core: build_operator(scheme, map.clone())?,
+ core: build_operator(&scheme, map.clone())?,
__scheme: scheme,
__map: map,
})
@@ -781,7 +773,7 @@ impl AsyncOperator {
let op = layer.0.layer(self.core.clone());
Ok(Self {
core: op,
- __scheme: self.__scheme,
+ __scheme: self.__scheme.clone(),
__map: self.__map.clone(),
})
}
@@ -1608,7 +1600,7 @@ impl AsyncOperator {
Ok(Operator {
core: op,
- __scheme: self.__scheme,
+ __scheme: self.__scheme.clone(),
__map: self.__map.clone(),
})
}
@@ -1633,7 +1625,7 @@ impl AsyncOperator {
#[gen_stub(skip)]
fn __getnewargs_ex__(&self, py: Python) -> PyResult<Py<PyAny>> {
- let args = vec![self.__scheme.to_string()];
+ let args = vec![self.__scheme.clone()];
let args = PyTuple::new(py, args)?.into_py_any(py)?;
let kwargs = self.__map.clone().into_py_any(py)?;
PyTuple::new(py, [args, kwargs])?.into_py_any(py)
diff --git a/bindings/python/src/services.rs b/bindings/python/src/services.rs
index 719bee9f9..c9e48c678 100644
--- a/bindings/python/src/services.rs
+++ b/bindings/python/src/services.rs
@@ -32,6 +32,23 @@ See justfile at path ``../../justfile`` for more details.
"#
);
+submit! {
+ gen_methods_from_python! {
+ r#"
+ import builtins
+ import typing
+ import typing_extensions
+ class Operator:
+ @overload
+ def __new__(cls,
+ scheme: builtins.str,
+ /,
+ **kwargs: builtins.str,
+ ) -> typing_extensions.Self: ...
+ "#
+ }
+}
+
#[gen_stub_pyclass_enum]
#[pyclass(
eq,
@@ -149,8 +166,7 @@ impl PyScheme {
#[getter]
pub fn value(&self) -> &'static str {
- let scheme: ocore::Scheme = (*self).into();
- scheme.into_static()
+ (*self).into()
}
}
@@ -1006,6 +1022,7 @@ submit! {
scheme: typing.Union[opendal.services.Scheme.Huggingface,
typing.Literal["huggingface"]],
/,
*,
+ endpoint: builtins.str = ...,
repo_id: builtins.str = ...,
repo_type: builtins.str = ...,
revision: builtins.str = ...,
@@ -1017,13 +1034,17 @@ submit! {
Parameters
----------
+ endpoint : builtins.str, optional
+ Endpoint of the Huggingface Hub.
+ Default is "https://huggingface.co".
repo_id : builtins.str, optional
Repo id of this backend.
This is required.
repo_type : builtins.str, optional
Repo type of this backend.
Default is model.
- Available values: - model - dataset
+ Available values: - model - dataset - datasets
+ (alias for dataset)
revision : builtins.str, optional
Revision of this backend.
Default is main.
@@ -1897,7 +1918,7 @@ submit! {
HTTP headers.
This is necessary when writing to AWS S3 Buckets
with Object Lock enabled for example.
- Available options: - "crc32c"
+ Available options: - "crc32c" - "md5"
default_storage_class : builtins.str, optional
default storage_class for this backend.
Available values: - `DEEP_ARCHIVE` - `GLACIER` -
@@ -1921,7 +1942,7 @@ submit! {
Disable load credential from ec2 metadata.
This option is used to disable the default behavior
of opendal to load credential from ec2 metadata,
- a.k.a, IMDSv2
+ a.k.a., IMDSv2
disable_list_objects_v2 : builtins.bool, optional
OpenDAL uses List Objects V2 by default to list
objects.
@@ -1937,7 +1958,7 @@ submit! {
Disable write with if match so that opendal will not
send write request with if match headers.
For example, Ceph RADOS S3 doesn't support write
- with if match.
+ with if matched.
enable_request_payer : builtins.bool, optional
Indicates whether the client agrees to pay for the
requests made to the S3 bucket.
@@ -2466,6 +2487,23 @@ submit! {
}
}
+submit! {
+ gen_methods_from_python! {
+ r#"
+ import builtins
+ import typing
+ import typing_extensions
+ class AsyncOperator:
+ @overload
+ def __new__(cls,
+ scheme: builtins.str,
+ /,
+ **kwargs: builtins.str,
+ ) -> typing_extensions.Self: ...
+ "#
+ }
+}
+
submit! {
gen_methods_from_python! {
r#"
@@ -3318,6 +3356,7 @@ submit! {
scheme: typing.Union[opendal.services.Scheme.Huggingface,
typing.Literal["huggingface"]],
/,
*,
+ endpoint: builtins.str = ...,
repo_id: builtins.str = ...,
repo_type: builtins.str = ...,
revision: builtins.str = ...,
@@ -3329,13 +3368,17 @@ submit! {
Parameters
----------
+ endpoint : builtins.str, optional
+ Endpoint of the Huggingface Hub.
+ Default is "https://huggingface.co".
repo_id : builtins.str, optional
Repo id of this backend.
This is required.
repo_type : builtins.str, optional
Repo type of this backend.
Default is model.
- Available values: - model - dataset
+ Available values: - model - dataset - datasets
+ (alias for dataset)
revision : builtins.str, optional
Revision of this backend.
Default is main.
@@ -4209,7 +4252,7 @@ submit! {
HTTP headers.
This is necessary when writing to AWS S3 Buckets
with Object Lock enabled for example.
- Available options: - "crc32c"
+ Available options: - "crc32c" - "md5"
default_storage_class : builtins.str, optional
default storage_class for this backend.
Available values: - `DEEP_ARCHIVE` - `GLACIER` -
@@ -4233,7 +4276,7 @@ submit! {
Disable load credential from ec2 metadata.
This option is used to disable the default behavior
of opendal to load credential from ec2 metadata,
- a.k.a, IMDSv2
+ a.k.a., IMDSv2
disable_list_objects_v2 : builtins.bool, optional
OpenDAL uses List Objects V2 by default to list
objects.
@@ -4249,7 +4292,7 @@ submit! {
Disable write with if match so that opendal will not
send write request with if match headers.
For example, Ceph RADOS S3 doesn't support write
- with if match.
+ with if matched.
enable_request_payer : builtins.bool, optional
Indicates whether the client agrees to pay for the
requests made to the S3 bucket.
@@ -4778,225 +4821,124 @@ submit! {
}
}
-// --- Conversion Macro ---
-macro_rules! impl_enum_from {
- ($src:ty => $dst:ty { $(
+macro_rules! impl_enum_to_str {
+ ($src:ty { $(
$(#[$cfg:meta])?
- $variant:ident
+ $variant:ident => $value:literal
),* $(,)? }) => {
- impl From<$src> for $dst {
+ impl From<$src> for &'static str {
fn from(value: $src) -> Self {
match value {
$(
$(#[$cfg])?
- <$src>::$variant => <$dst>::$variant,
+ <$src>::$variant => $value,
)*
- #[allow(unreachable_patterns)]
- _ => unreachable!(
- "Unsupported scheme variant: {:?}. \
- This likely means a new variant was added to `{}` \
- but `PyScheme` or the generated bindings were not
updated.",
- value,
- stringify!($src)
- ),
}
}
}
+
+ impl From<$src> for String {
+ fn from(value: $src) -> Self {
+ let v: &'static str = value.into();
+ v.to_string()
+ }
+ }
};
}
-// --- PyScheme -> ocore::Scheme ---
-impl_enum_from!(
- PyScheme => ocore::Scheme {
- #[cfg(feature = "services-aliyun-drive")]
- AliyunDrive,
- #[cfg(feature = "services-alluxio")]
- Alluxio,
- #[cfg(feature = "services-azblob")]
- Azblob,
- #[cfg(feature = "services-azdls")]
- Azdls,
- #[cfg(feature = "services-azfile")]
- Azfile,
- #[cfg(feature = "services-b2")]
- B2,
- #[cfg(feature = "services-cacache")]
- Cacache,
- #[cfg(feature = "services-cos")]
- Cos,
- #[cfg(feature = "services-dashmap")]
- Dashmap,
- #[cfg(feature = "services-dropbox")]
- Dropbox,
- #[cfg(feature = "services-fs")]
- Fs,
- #[cfg(feature = "services-ftp")]
- Ftp,
- #[cfg(feature = "services-gcs")]
- Gcs,
- #[cfg(feature = "services-gdrive")]
- Gdrive,
- #[cfg(feature = "services-ghac")]
- Ghac,
- #[cfg(feature = "services-gridfs")]
- Gridfs,
- #[cfg(feature = "services-hdfs-native")]
- HdfsNative,
- #[cfg(feature = "services-http")]
- Http,
- #[cfg(feature = "services-huggingface")]
- Huggingface,
- #[cfg(feature = "services-ipfs")]
- Ipfs,
- #[cfg(feature = "services-ipmfs")]
- Ipmfs,
- #[cfg(feature = "services-koofr")]
- Koofr,
- #[cfg(feature = "services-memcached")]
- Memcached,
- #[cfg(feature = "services-memory")]
- Memory,
- #[cfg(feature = "services-mini-moka")]
- MiniMoka,
- #[cfg(feature = "services-moka")]
- Moka,
- #[cfg(feature = "services-mongodb")]
- Mongodb,
- #[cfg(feature = "services-mysql")]
- Mysql,
- #[cfg(feature = "services-obs")]
- Obs,
- #[cfg(feature = "services-onedrive")]
- Onedrive,
- #[cfg(feature = "services-oss")]
- Oss,
- #[cfg(feature = "services-persy")]
- Persy,
- #[cfg(feature = "services-postgresql")]
- Postgresql,
- #[cfg(feature = "services-redb")]
- Redb,
- #[cfg(feature = "services-redis")]
- Redis,
- #[cfg(feature = "services-s3")]
- S3,
- #[cfg(feature = "services-seafile")]
- Seafile,
- #[cfg(feature = "services-sftp")]
- Sftp,
- #[cfg(feature = "services-sled")]
- Sled,
- #[cfg(feature = "services-sqlite")]
- Sqlite,
- #[cfg(feature = "services-swift")]
- Swift,
- #[cfg(feature = "services-upyun")]
- Upyun,
- #[cfg(feature = "services-vercel-artifacts")]
- VercelArtifacts,
- #[cfg(feature = "services-webdav")]
- Webdav,
- #[cfg(feature = "services-webhdfs")]
- Webhdfs,
- #[cfg(feature = "services-yandex-disk")]
- YandexDisk,
- }
-);
-
-// --- ocore::Scheme -> PyScheme ---
-impl_enum_from!(
- ocore::Scheme => PyScheme {
- #[cfg(feature = "services-aliyun-drive")]
- AliyunDrive,
- #[cfg(feature = "services-alluxio")]
- Alluxio,
- #[cfg(feature = "services-azblob")]
- Azblob,
- #[cfg(feature = "services-azdls")]
- Azdls,
- #[cfg(feature = "services-azfile")]
- Azfile,
- #[cfg(feature = "services-b2")]
- B2,
- #[cfg(feature = "services-cacache")]
- Cacache,
- #[cfg(feature = "services-cos")]
- Cos,
- #[cfg(feature = "services-dashmap")]
- Dashmap,
- #[cfg(feature = "services-dropbox")]
- Dropbox,
- #[cfg(feature = "services-fs")]
- Fs,
- #[cfg(feature = "services-ftp")]
- Ftp,
- #[cfg(feature = "services-gcs")]
- Gcs,
- #[cfg(feature = "services-gdrive")]
- Gdrive,
- #[cfg(feature = "services-ghac")]
- Ghac,
- #[cfg(feature = "services-gridfs")]
- Gridfs,
- #[cfg(feature = "services-hdfs-native")]
- HdfsNative,
- #[cfg(feature = "services-http")]
- Http,
- #[cfg(feature = "services-huggingface")]
- Huggingface,
- #[cfg(feature = "services-ipfs")]
- Ipfs,
- #[cfg(feature = "services-ipmfs")]
- Ipmfs,
- #[cfg(feature = "services-koofr")]
- Koofr,
- #[cfg(feature = "services-memcached")]
- Memcached,
- #[cfg(feature = "services-memory")]
- Memory,
- #[cfg(feature = "services-mini-moka")]
- MiniMoka,
- #[cfg(feature = "services-moka")]
- Moka,
- #[cfg(feature = "services-mongodb")]
- Mongodb,
- #[cfg(feature = "services-mysql")]
- Mysql,
- #[cfg(feature = "services-obs")]
- Obs,
- #[cfg(feature = "services-onedrive")]
- Onedrive,
- #[cfg(feature = "services-oss")]
- Oss,
- #[cfg(feature = "services-persy")]
- Persy,
- #[cfg(feature = "services-postgresql")]
- Postgresql,
- #[cfg(feature = "services-redb")]
- Redb,
- #[cfg(feature = "services-redis")]
- Redis,
- #[cfg(feature = "services-s3")]
- S3,
- #[cfg(feature = "services-seafile")]
- Seafile,
- #[cfg(feature = "services-sftp")]
- Sftp,
- #[cfg(feature = "services-sled")]
- Sled,
- #[cfg(feature = "services-sqlite")]
- Sqlite,
- #[cfg(feature = "services-swift")]
- Swift,
- #[cfg(feature = "services-upyun")]
- Upyun,
- #[cfg(feature = "services-vercel-artifacts")]
- VercelArtifacts,
- #[cfg(feature = "services-webdav")]
- Webdav,
- #[cfg(feature = "services-webhdfs")]
- Webhdfs,
- #[cfg(feature = "services-yandex-disk")]
- YandexDisk,
+impl_enum_to_str!(
+ PyScheme {
+ #[cfg(feature = "services-aliyun-drive")]
+ AliyunDrive => "aliyun-drive",
+ #[cfg(feature = "services-alluxio")]
+ Alluxio => "alluxio",
+ #[cfg(feature = "services-azblob")]
+ Azblob => "azblob",
+ #[cfg(feature = "services-azdls")]
+ Azdls => "azdls",
+ #[cfg(feature = "services-azfile")]
+ Azfile => "azfile",
+ #[cfg(feature = "services-b2")]
+ B2 => "b2",
+ #[cfg(feature = "services-cacache")]
+ Cacache => "cacache",
+ #[cfg(feature = "services-cos")]
+ Cos => "cos",
+ #[cfg(feature = "services-dashmap")]
+ Dashmap => "dashmap",
+ #[cfg(feature = "services-dropbox")]
+ Dropbox => "dropbox",
+ #[cfg(feature = "services-fs")]
+ Fs => "fs",
+ #[cfg(feature = "services-ftp")]
+ Ftp => "ftp",
+ #[cfg(feature = "services-gcs")]
+ Gcs => "gcs",
+ #[cfg(feature = "services-gdrive")]
+ Gdrive => "gdrive",
+ #[cfg(feature = "services-ghac")]
+ Ghac => "ghac",
+ #[cfg(feature = "services-gridfs")]
+ Gridfs => "gridfs",
+ #[cfg(feature = "services-hdfs-native")]
+ HdfsNative => "hdfs-native",
+ #[cfg(feature = "services-http")]
+ Http => "http",
+ #[cfg(feature = "services-huggingface")]
+ Huggingface => "huggingface",
+ #[cfg(feature = "services-ipfs")]
+ Ipfs => "ipfs",
+ #[cfg(feature = "services-ipmfs")]
+ Ipmfs => "ipmfs",
+ #[cfg(feature = "services-koofr")]
+ Koofr => "koofr",
+ #[cfg(feature = "services-memcached")]
+ Memcached => "memcached",
+ #[cfg(feature = "services-memory")]
+ Memory => "memory",
+ #[cfg(feature = "services-mini-moka")]
+ MiniMoka => "mini-moka",
+ #[cfg(feature = "services-moka")]
+ Moka => "moka",
+ #[cfg(feature = "services-mongodb")]
+ Mongodb => "mongodb",
+ #[cfg(feature = "services-mysql")]
+ Mysql => "mysql",
+ #[cfg(feature = "services-obs")]
+ Obs => "obs",
+ #[cfg(feature = "services-onedrive")]
+ Onedrive => "onedrive",
+ #[cfg(feature = "services-oss")]
+ Oss => "oss",
+ #[cfg(feature = "services-persy")]
+ Persy => "persy",
+ #[cfg(feature = "services-postgresql")]
+ Postgresql => "postgresql",
+ #[cfg(feature = "services-redb")]
+ Redb => "redb",
+ #[cfg(feature = "services-redis")]
+ Redis => "redis",
+ #[cfg(feature = "services-s3")]
+ S3 => "s3",
+ #[cfg(feature = "services-seafile")]
+ Seafile => "seafile",
+ #[cfg(feature = "services-sftp")]
+ Sftp => "sftp",
+ #[cfg(feature = "services-sled")]
+ Sled => "sled",
+ #[cfg(feature = "services-sqlite")]
+ Sqlite => "sqlite",
+ #[cfg(feature = "services-swift")]
+ Swift => "swift",
+ #[cfg(feature = "services-upyun")]
+ Upyun => "upyun",
+ #[cfg(feature = "services-vercel-artifacts")]
+ VercelArtifacts => "vercel-artifacts",
+ #[cfg(feature = "services-webdav")]
+ Webdav => "webdav",
+ #[cfg(feature = "services-webhdfs")]
+ Webhdfs => "webhdfs",
+ #[cfg(feature = "services-yandex-disk")]
+ YandexDisk => "yandex-disk",
}
);
diff --git a/dev/src/generate/python.j2 b/dev/src/generate/python.j2
index cab42dffb..fabd4807a 100644
--- a/dev/src/generate/python.j2
+++ b/dev/src/generate/python.j2
@@ -32,6 +32,23 @@ See justfile at path ``../../justfile`` for more details.
"#
);
+submit! {
+ gen_methods_from_python! {
+ r#"
+ import builtins
+ import typing
+ import typing_extensions
+ class Operator:
+ @overload
+ def __new__(cls,
+ scheme: builtins.str,
+ /,
+ **kwargs: builtins.str,
+ ) -> typing_extensions.Self: ...
+ "#
+ }
+}
+
#[gen_stub_pyclass_enum]
#[pyclass(
eq,
@@ -61,8 +78,7 @@ impl PyScheme {
#[getter]
pub fn value(&self) -> &'static str {
- let scheme: ocore::Scheme = (*self).into();
- scheme.into_static()
+ (*self).into()
}
}
@@ -107,6 +123,22 @@ submit! {
}
{% endfor %}
+submit! {
+ gen_methods_from_python! {
+ r#"
+ import builtins
+ import typing
+ import typing_extensions
+ class AsyncOperator:
+ @overload
+ def __new__(cls,
+ scheme: builtins.str,
+ /,
+ **kwargs: builtins.str,
+ ) -> typing_extensions.Self: ...
+ "#
+ }
+}
{% for srv in srvs %}
submit! {
gen_methods_from_python! {
@@ -147,49 +179,36 @@ submit! {
}
}
{% endfor %}
-// --- Conversion Macro ---
-macro_rules! impl_enum_from {
- ($src:ty => $dst:ty { $(
+macro_rules! impl_enum_to_str {
+ ($src:ty { $(
$(#[$cfg:meta])?
- $variant:ident
+ $variant:ident => $value:literal
),* $(,)? }) => {
- impl From<$src> for $dst {
+ impl From<$src> for &'static str {
fn from(value: $src) -> Self {
match value {
$(
$(#[$cfg])?
- <$src>::$variant => <$dst>::$variant,
+ <$src>::$variant => $value,
)*
- #[allow(unreachable_patterns)]
- _ => unreachable!(
- "Unsupported scheme variant: {:?}. \
- This likely means a new variant was added to `{}` \
- but `PyScheme` or the generated bindings were not
updated.",
- value,
- stringify!($src)
- ),
}
}
}
+
+ impl From<$src> for String {
+ fn from(value: $src) -> Self {
+ let v: &'static str = value.into();
+ v.to_string()
+ }
+ }
};
}
-// --- PyScheme -> ocore::Scheme ---
-impl_enum_from!(
- PyScheme => ocore::Scheme {
+impl_enum_to_str!(
+ PyScheme {
{%- for name in srvs %}
- #[cfg(feature = "{{ service_to_feature(name) }}")]
- {{ service_to_pascal(name) }},
-{%- endfor %}
- }
-);
-
-// --- ocore::Scheme -> PyScheme ---
-impl_enum_from!(
- ocore::Scheme => PyScheme {
-{%- for name in srvs %}
- #[cfg(feature = "{{ service_to_feature(name) }}")]
- {{ service_to_pascal(name) }},
+ #[cfg(feature = "{{ service_to_feature(name) }}")]
+ {{ service_to_pascal(name) }} => "{{ snake_to_kebab_case(name) }}",
{%- endfor %}
}
);