using python identifier in message names
necessary to distinguish between dynamically created classes with same name
This commit is contained in:
Erik Friese 2023-09-05 12:37:29 +02:00
parent fd02cb6180
commit 8f535913a1
2 changed files with 23 additions and 5 deletions

View File

@ -20,7 +20,8 @@ pub fn create_cached_descriptor(obj: &PyAny) -> Result<MessageDescriptor> {
.lock()
.unwrap();
let name = obj.qualified_class_name()?;
let cls = obj.getattr("__class__")?;
let name = format!("{}_{}", cls.qualified_name()?, cls.py_identifier());
if let Some(desc) = pool.get_message_by_name(&name) {
return Ok(desc);
}
@ -159,6 +160,7 @@ fn add_message_to_file(
Some("google.protobuf.Duration".to_string());
}
_ => {
let cls_name = format!("{}_{}", cls_name, cls.py_identifier());
field.type_name = Some(cls_name.clone());
if message_name != cls_name
@ -179,14 +181,14 @@ fn add_message_to_file(
},
Type::Enum => {
let cls = meta.get_class(field_name)?;
let cls_name = cls.qualified_name()?;
let cls_name = format!("{}_{}", cls.qualified_name()?, cls.py_identifier());
field.type_name = Some(cls_name.to_string());
if pool.get_enum_by_name(&cls_name).is_none()
&& !file.enum_type.iter().any(|item| item.name() == cls_name)
{
let mut proto = EnumDescriptorProto {
name: Some(cls_name),
name: Some(cls_name.clone()),
..Default::default()
};
@ -194,7 +196,7 @@ fn add_message_to_file(
let item = item?;
proto.value.push(EnumValueDescriptorProto {
number: Some(item.getattr("value")?.extract()?),
name: Some(item.getattr("name")?.extract()?),
name: Some(format!("{}_{}", cls_name, item.getattr("name")?.extract::<&str>()?)),
..Default::default()
});
}

View File

@ -1,5 +1,5 @@
use crate::error::Result;
use pyo3::PyAny;
use pyo3::{PyAny, Py, sync::GILOnceCell};
pub trait PyAnyExtras {
fn qualified_name(&self) -> Result<String>;
@ -9,6 +9,7 @@ pub trait PyAnyExtras {
fn create_instance(&self, field_name: &str) -> Result<&PyAny>;
fn is_list_field(&self, field_name: &str) -> Result<bool>;
fn oneof_group(&self, field_name: &str) -> Result<Option<String>>;
fn py_identifier(&self) -> u64;
}
impl PyAnyExtras for PyAny {
@ -49,4 +50,19 @@ impl PyAnyExtras for PyAny {
.extract()?;
Ok(opt)
}
fn py_identifier(&self) -> u64 {
static FUN_CACHE: GILOnceCell<Py<PyAny>> = GILOnceCell::new();
let py = self.py();
let fun = FUN_CACHE.get_or_init(py, || {
let fun = py
.eval("id", None, None)
.expect("This is a valid Python expression");
Py::from(fun)
});
fun.call1(py, (self,))
.expect("Identity function is callable")
.extract::<u64>(py)
.expect("Identity function always returns an integer")
}
}