Add documentation and tests for string conversion special methods.
This commit is contained in:
parent
3d99a4ac3c
commit
933e0ed11d
|
@ -132,7 +132,7 @@ Declares an instance method callable from Python.
|
|||
* The return type must be `PyResult<T>` for some `T` that implements `ToPyObject`.
|
||||
|
||||
## Class methods
|
||||
`@classmethod def method_name(cls, parameter-list) -> PyResult<...> { ... }
|
||||
`@classmethod def method_name(cls, parameter-list) -> PyResult<...> { ... }`
|
||||
|
||||
Declares a class method callable from Python.
|
||||
|
||||
|
@ -143,7 +143,7 @@ Declares a class method callable from Python.
|
|||
* The return type must be `PyResult<T>` for some `T` that implements `ToPyObject`.
|
||||
|
||||
## Static methods
|
||||
`@staticmethod def method_name(parameter-list) -> PyResult<...> { ... }
|
||||
`@staticmethod def method_name(parameter-list) -> PyResult<...> { ... }`
|
||||
|
||||
Declares a static method callable from Python.
|
||||
|
||||
|
@ -225,11 +225,10 @@ that use `RefCell::borrow_mut`.
|
|||
|
||||
Iterators can be defined using the Python special methods `__iter__` and `__next__`:
|
||||
|
||||
* `def __iter__(&self) -> PyResult<T>`
|
||||
* `def __next__(&self) -> PyResult<Option<T>>`
|
||||
* `def __iter__(&self) -> PyResult<impl ToPyObject>`
|
||||
* `def __next__(&self) -> PyResult<Option<impl ToPyObject>>`
|
||||
|
||||
In both cases, `T` must be a type that implements `ToPyObject`.
|
||||
Returning `Ok(None)` from `__next__` indicates that that there are no further items.
|
||||
Returning `Ok(None)` from `__next__` indicates that that there are no further items.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -252,6 +251,31 @@ py_class!(class MyIterator |py| {
|
|||
# fn main() {}
|
||||
```
|
||||
|
||||
## String Conversions
|
||||
|
||||
* `def __repr__(&self) -> PyResult<impl ToPyObject<ObjectType=PyString>>`
|
||||
* `def __str__(&self) -> PyResult<impl ToPyObject<ObjectType=PyString>>`
|
||||
|
||||
Possible return types for `__str__` and `__repr__` are `PyResult<String>` or `PyResult<PyString>`.
|
||||
|
||||
In Python 2.7, Unicode strings returned by `__str__` and `__repr__` will be converted to byte strings
|
||||
by the Python runtime, which results in an exception if the string contains non-ASCII characters.
|
||||
|
||||
* `def __bytes__(&self) -> PyResult<PyBytes>`
|
||||
|
||||
On Python 3.x, provides the conversion to `bytes`.
|
||||
On Python 2.7, `__bytes__` is allowed but has no effect.
|
||||
|
||||
* `def __unicode__(&self) -> PyResult<PyUnicode>`
|
||||
|
||||
On Python 2.7, provides the conversion to `unicode`.
|
||||
On Python 3.x, `__unicode__` is allowed but has no effect.
|
||||
|
||||
* `def __format__(&self, format_spec: &str) -> PyResult<impl ToPyObject<ObjectType=PyString>>`
|
||||
|
||||
Special method that is used by the `format()` builtin and the `str.format()` method.
|
||||
Possible return types are `PyResult<String>` or `PyResult<PyString>`.
|
||||
|
||||
*/
|
||||
#[macro_export]
|
||||
macro_rules! py_class {
|
||||
|
|
|
@ -584,8 +584,8 @@ special_names = {
|
|||
'__del__': error('__del__ is not supported by py_class!; Use a data member with a Drop impl instead.'),
|
||||
'__repr__': unary_operator('tp_repr', res_type="PyString"),
|
||||
'__str__': unary_operator('tp_str', res_type="PyString"),
|
||||
'__unicode__': unary_operator('tp_unicode', res_type="PyUnicode"),
|
||||
'__bytes__': unary_operator('tp_bytes', res_type="PyBytes"),
|
||||
'__unicode__': normal_method(),
|
||||
'__bytes__': normal_method(),
|
||||
'__format__': normal_method(),
|
||||
# Comparison Operators
|
||||
'__lt__': unimplemented(),
|
||||
|
|
|
@ -340,35 +340,6 @@ macro_rules! py_class_impl {
|
|||
} => {
|
||||
py_error! { "__bool__ is not supported by py_class! yet." }
|
||||
};
|
||||
{ $class:ident $py:ident $info:tt
|
||||
/* slots: */ {
|
||||
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
|
||||
$as_number:tt $as_sequence:tt
|
||||
}
|
||||
{ $( $imp:item )* }
|
||||
$members:tt;
|
||||
def __bytes__(&$slf:ident) -> $res_type:ty { $($body:tt)* } $($tail:tt)*
|
||||
} => { py_class_impl! {
|
||||
$class $py $info
|
||||
/* slots: */ {
|
||||
/* type_slots */ [
|
||||
$( $tp_slot_name : $tp_slot_value, )*
|
||||
tp_bytes: py_class_unary_slot!($class::__bytes__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PythonObjectCallbackConverter::<$crate::PyBytes>(::std::marker::PhantomData)),
|
||||
]
|
||||
$as_number $as_sequence
|
||||
}
|
||||
/* impl: */ {
|
||||
$($imp)*
|
||||
py_class_impl_item! { $class, $py, __bytes__(&$slf,) $res_type; { $($body)* } [] }
|
||||
}
|
||||
$members; $($tail)*
|
||||
}};
|
||||
// def __bytes__()
|
||||
{ $class:ident $py:ident $info:tt $slots:tt $impls:tt $members:tt;
|
||||
def __bytes__ $($tail:tt)*
|
||||
} => {
|
||||
py_error! { "Invalid signature for unary operator __bytes__" }
|
||||
};
|
||||
// def __call__()
|
||||
{ $class:ident $py:ident $info:tt $slots:tt $impls:tt $members:tt;
|
||||
def __call__ $($tail:tt)*
|
||||
|
@ -1061,35 +1032,6 @@ macro_rules! py_class_impl {
|
|||
} => {
|
||||
py_error! { "__truediv__ is not supported by py_class! yet." }
|
||||
};
|
||||
{ $class:ident $py:ident $info:tt
|
||||
/* slots: */ {
|
||||
/* type_slots */ [ $( $tp_slot_name:ident : $tp_slot_value:expr, )* ]
|
||||
$as_number:tt $as_sequence:tt
|
||||
}
|
||||
{ $( $imp:item )* }
|
||||
$members:tt;
|
||||
def __unicode__(&$slf:ident) -> $res_type:ty { $($body:tt)* } $($tail:tt)*
|
||||
} => { py_class_impl! {
|
||||
$class $py $info
|
||||
/* slots: */ {
|
||||
/* type_slots */ [
|
||||
$( $tp_slot_name : $tp_slot_value, )*
|
||||
tp_unicode: py_class_unary_slot!($class::__unicode__, *mut $crate::_detail::ffi::PyObject, $crate::_detail::PythonObjectCallbackConverter::<$crate::PyUnicode>(::std::marker::PhantomData)),
|
||||
]
|
||||
$as_number $as_sequence
|
||||
}
|
||||
/* impl: */ {
|
||||
$($imp)*
|
||||
py_class_impl_item! { $class, $py, __unicode__(&$slf,) $res_type; { $($body)* } [] }
|
||||
}
|
||||
$members; $($tail)*
|
||||
}};
|
||||
// def __unicode__()
|
||||
{ $class:ident $py:ident $info:tt $slots:tt $impls:tt $members:tt;
|
||||
def __unicode__ $($tail:tt)*
|
||||
} => {
|
||||
py_error! { "Invalid signature for unary operator __unicode__" }
|
||||
};
|
||||
// def __xor__()
|
||||
{ $class:ident $py:ident $info:tt $slots:tt $impls:tt $members:tt;
|
||||
def __xor__ $($tail:tt)*
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
#[macro_use] extern crate cpython;
|
||||
|
||||
use cpython::{PyObject, PythonObject, PyDrop, PyClone, PyResult, Python, NoArgs, ObjectProtocol, PyDict, exc};
|
||||
use cpython::{PyObject, PythonObject, PyDrop, PyClone, PyResult, Python, NoArgs, ObjectProtocol,
|
||||
PyDict, PyBytes, PyUnicode, exc};
|
||||
use std::{mem, isize, iter};
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
|
@ -339,8 +340,16 @@ py_class!(class StringMethods |py| {
|
|||
Ok("repr")
|
||||
}
|
||||
|
||||
def __format__(&self, formatspec: &str) -> PyResult<String> {
|
||||
Ok(format!("format({})", formatspec))
|
||||
def __format__(&self, format_spec: &str) -> PyResult<String> {
|
||||
Ok(format!("format({})", format_spec))
|
||||
}
|
||||
|
||||
def __unicode__(&self) -> PyResult<PyUnicode> {
|
||||
Ok(PyUnicode::new(py, "unicode"))
|
||||
}
|
||||
|
||||
def __bytes__(&self) -> PyResult<PyBytes> {
|
||||
Ok(PyBytes::new(py, b"bytes"))
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -355,3 +364,24 @@ fn string_methods() {
|
|||
py_assert!(py, obj, "'{0:x}'.format(obj) == 'format(x)'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="python27-sys")]
|
||||
fn python2_string_methods() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let obj = StringMethods::create_instance(py).unwrap();
|
||||
py_assert!(py, obj, "unicode(obj) == u'unicode'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="python3-sys")]
|
||||
fn python3_string_methods() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let obj = StringMethods::create_instance(py).unwrap();
|
||||
py_assert!(py, obj, "bytes(obj) == b'bytes'");
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue