add class doc string
This commit is contained in:
parent
4d68f7f2a3
commit
d7c3d34198
|
@ -6,9 +6,12 @@ use std::collections::HashMap;
|
|||
use syn;
|
||||
use quote::Tokens;
|
||||
|
||||
use utils;
|
||||
|
||||
|
||||
pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
|
||||
let params = parse_attribute(attr);
|
||||
let doc = utils::get_doc(&ast.attrs);
|
||||
|
||||
let base = syn::Ident::from("_pyo3::PyObject");
|
||||
let mut token: Option<syn::Ident> = None;
|
||||
|
@ -26,7 +29,7 @@ pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
|
|||
}
|
||||
|
||||
let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_CLS_{}", ast.ident));
|
||||
let tokens = impl_class(&ast.ident, &base, token, params);
|
||||
let tokens = impl_class(&ast.ident, &base, token, doc, params);
|
||||
|
||||
quote! {
|
||||
#[feature(specialization)]
|
||||
|
@ -42,7 +45,8 @@ pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
|
|||
}
|
||||
|
||||
fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
||||
token: Option<syn::Ident>, params: HashMap<&'static str, syn::Ident>) -> Tokens {
|
||||
token: Option<syn::Ident>, doc: syn::Lit,
|
||||
params: HashMap<&'static str, syn::Ident>) -> Tokens {
|
||||
let cls_name = match params.get("name") {
|
||||
Some(name) => quote! { #name }.as_str().to_string(),
|
||||
None => quote! { #cls }.as_str().to_string()
|
||||
|
@ -133,9 +137,12 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
((bs + align - 1) / align * align) as isize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_name() -> &'static str { #cls_name }
|
||||
|
||||
fn type_description() -> &'static str {
|
||||
#doc
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn type_object() -> &'static mut _pyo3::ffi::PyTypeObject {
|
||||
static mut TYPE_OBJECT: _pyo3::ffi::PyTypeObject = _pyo3::ffi::PyTypeObject_INIT;
|
||||
|
@ -153,11 +160,11 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
|
|||
if (ty.tp_flags & _pyo3::ffi::Py_TPFLAGS_READY) == 0 {
|
||||
// automatically initialize the class on-demand
|
||||
let to = _pyo3::typeob::initialize_type::<#cls>(
|
||||
py, None, <#cls as _pyo3::typeob::PyTypeInfo>::type_name(), ty)
|
||||
.expect(
|
||||
format!("An error occurred while initializing class {}",
|
||||
<#cls as _pyo3::typeob::PyTypeInfo>::type_name())
|
||||
.as_ref());
|
||||
py, None, <#cls as _pyo3::typeob::PyTypeInfo>::type_name(),
|
||||
<#cls as _pyo3::typeob::PyTypeInfo>::type_description(), ty).expect(
|
||||
format!("An error occurred while initializing class {}",
|
||||
<#cls as _pyo3::typeob::PyTypeInfo>::type_name())
|
||||
.as_ref());
|
||||
py.release(to);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -67,7 +67,9 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
|
|||
}
|
||||
}
|
||||
|
||||
fn impl_proto_impl(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>, proto: &defs::Proto) -> Tokens {
|
||||
fn impl_proto_impl(ty: &Box<syn::Ty>,
|
||||
impls: &mut Vec<syn::ImplItem>, proto: &defs::Proto) -> Tokens
|
||||
{
|
||||
let mut tokens = Tokens::new();
|
||||
let mut py_methods = Vec::new();
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use syn;
|
||||
use quote::{Tokens, ToTokens};
|
||||
|
||||
|
||||
|
@ -11,3 +12,21 @@ pub fn for_err_msg(i: &ToTokens) -> String {
|
|||
i.to_tokens(&mut tokens);
|
||||
tokens.as_str().to_string()
|
||||
}
|
||||
|
||||
pub fn get_doc(attrs: &Vec<syn::Attribute>) -> syn::Lit {
|
||||
let mut doc = Vec::new();
|
||||
|
||||
for attr in attrs.iter() {
|
||||
match attr.value {
|
||||
syn::MetaItem::NameValue(ref ident, ref lit) => {
|
||||
if ident.as_ref() == "doc" {
|
||||
let s = quote!{ #lit }.to_string();
|
||||
doc.push(s[1..s.len()-1].to_owned())
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
let doc = doc.join("\n");
|
||||
syn::Lit::Str(format!("{}\0", doc), syn::StrStyle::Cooked)
|
||||
}
|
||||
|
|
|
@ -112,7 +112,10 @@ impl<'p> PyModule {
|
|||
} else {
|
||||
// automatically initialize the class
|
||||
let name = self.name(py)?;
|
||||
let to = ::typeob::initialize_type::<T>(py, Some(name), type_name, ty)
|
||||
let type_description = <T as ::typeob::PyTypeInfo>::type_description();
|
||||
|
||||
let to = ::typeob::initialize_type::<T>(
|
||||
py, Some(name), type_name, type_description, ty)
|
||||
.expect(format!("An error occurred while initializing class {}",
|
||||
<T as ::typeob::PyTypeInfo>::type_name()).as_ref());
|
||||
py.release(to);
|
||||
|
|
|
@ -29,6 +29,9 @@ pub trait PyTypeInfo {
|
|||
/// Type name
|
||||
fn type_name() -> &'static str;
|
||||
|
||||
/// Type description
|
||||
fn type_description() -> &'static str { "\0" }
|
||||
|
||||
/// PyTypeObject instance for this type
|
||||
fn type_object() -> &'static mut ffi::PyTypeObject;
|
||||
|
||||
|
@ -131,7 +134,8 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
|
|||
if (ty.tp_flags & ffi::Py_TPFLAGS_READY) == 0 {
|
||||
// automatically initialize the class on-demand
|
||||
let to = initialize_type::<T>(
|
||||
py, None, <T as PyTypeInfo>::type_name(), ty).expect(
|
||||
py, None, <T as PyTypeInfo>::type_name(),
|
||||
<T as PyTypeInfo>::type_description(), ty).expect(
|
||||
format!("An error occurred while initializing class {}",
|
||||
<T as PyTypeInfo>::type_name()).as_ref());
|
||||
py.release(to);
|
||||
|
@ -148,7 +152,8 @@ impl<T> PyTypeObject for T where T: PyObjectAlloc<T> + PyTypeInfo {
|
|||
|
||||
|
||||
pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str,
|
||||
type_object: &mut ffi::PyTypeObject) -> PyResult<PyType>
|
||||
type_description: &'static str, type_object: &mut ffi::PyTypeObject)
|
||||
-> PyResult<PyType>
|
||||
where T: PyObjectAlloc<T> + PyTypeInfo
|
||||
{
|
||||
// type name
|
||||
|
@ -160,6 +165,7 @@ pub fn initialize_type<T>(py: Python, module_name: Option<&str>, type_name: &str
|
|||
"Module name/type name must not contain NUL byte").into_raw();
|
||||
|
||||
type_object.tp_name = name;
|
||||
type_object.tp_doc = type_description.as_ptr() as *const _;
|
||||
|
||||
// dealloc
|
||||
type_object.tp_dealloc = Some(tp_dealloc_callback::<T>);
|
||||
|
|
|
@ -51,6 +51,18 @@ fn empty_class() {
|
|||
py_assert!(py, typeobj, "typeobj.__name__ == 'EmptyClass'");
|
||||
}
|
||||
|
||||
#[py::class]
|
||||
/// Line1
|
||||
/// Line2
|
||||
struct ClassWithDocs { }
|
||||
|
||||
#[test]
|
||||
fn class_with_docstr() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
let typeobj = py.get_type::<ClassWithDocs>();
|
||||
py_run!(py, typeobj, "assert typeobj.__doc__ == '/// Line1\\n/// Line2'");
|
||||
}
|
||||
|
||||
#[py::class(name=CustomName)]
|
||||
struct EmptyClass2 { }
|
||||
|
|
Loading…
Reference in New Issue