Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement property support #208

Merged
merged 4 commits into from
Feb 26, 2020
Merged

Implement property support #208

merged 4 commits into from
Feb 26, 2020

Conversation

markbt
Copy link
Collaborator

@markbt markbt commented Feb 3, 2020

Add support for defining Python properties (attributes with getters and optional setters) in Rust.

Properties are defined inside py_class! with:

@property def property_name(&self) -> PyResult<PropertyType> { ... }

where property_name is the name in Python, and PropertyType is any type that impls ToPyObject.

Property setters can optionally be defined as:

@property_name.setter def set_property_name(
    &self,
    value: Option<PropertyType>
) -> PyResult<()> { ... }

If the value is None then the caller is deleting the property (del obj.property_name).

If the value is Some(x) then the caller is setting the property to x.

For setters, the PropertyType can be any type that impls FromPyObject, or a reference or optional reference to any type that impls RefFromPyObject.

In the latter case, the type of value is Option<Option<&PropertyType>>, where None means the value is being deleted, Some(None) means the property is being set to Python None, and Some(Some(x)) means the property is being set to x.

@markbt markbt force-pushed the properties branch 2 times, most recently from f2510ca to 1870c93 Compare February 4, 2020 11:12
@Alphare
Copy link
Contributor

Alphare commented Feb 4, 2020

Looks like this needs a rebase now

Since these are just pointers or Py_ssize_t, there's not much to gain by
treating them as uninitialized, and std::mem::uninitialized is now deprecated.
This allows slot implementations with a single parameter (in particular,
__compare__, __getitem__, __delitem__, and in-place operators like __iadd__),
as well as __richcmp__ to work with reference types (types that implement
RefFromPyObject) as well as full types (types that implement FromPyObject).

Additionally, optional references are included.  This is an improvement over
normal methods, so this is extended to normal methods, too.

The syntax is the same as for methods, e.g.

    def __contains__(&self, key: &KeyType) -> PyResult<bool>

will generate a method where the key will be borrowed from the PyObject,
rather than copied.

Similarly for optional references:

    def __contains__(&self, key: Option<&KeyType>) -> PyResult<bool>

will be the same, except that the key will be `None` if the user provided
Python `None`.

The `__setitem__` method only supports reference extraction for the first
parameter (the key).  The value still needs to be a fully extracted type.

Binary arithmetic operators, like __add__, are not included.
Add support for defining Python properties (attributes with getters and
optional setters) in Rust.

Properties are defined inside `py_class!` with:

    @Property def property_name(&self) -> PyResult<PropertyType> { ... }

where `property_name` is the name in Python, and `PropertyType` is any type
that impls `ToPyObject`.

Property setters can optionally be defined as:

    @property_name.setter def set_property_name(
        &self,
        value: Option<PropertyType>
    ) -> PyResult<()> { ... }

If the value is `None` then the caller is deleting the property
(`del obj.property_name`).

If the value is `Some(x)` then the caller is setting the property to `x`.

For setters, the `PropertyType` can be any type that impls `FromPyObject`,
or a reference or optional reference to any type that impls `RefFromPyObject`.

In the latter case, the type of `value` is `Option<Option<&PropertyType>>`,
where `None` means the value is being deleted, `Some(None)` means the property
is being set to Python `None`, and `Some(Some(x))` means the property is being
set to `x`.
Like other identifiers, strip the leading 'r#' from the Python version of the
identifier name.

Also make raw identifier stripping and docstring processing consistent.
@markbt
Copy link
Collaborator Author

markbt commented Feb 4, 2020

I've rebased both PRs. It looks like @gracinet didn't spot my latest change that removed std::mem::uninitialized in favour of just initializing to zero. I've included that here, but let me know if you want to drop it.

@markbt markbt merged commit 7fb4dd2 into dgrunwald:master Feb 26, 2020
@markbt markbt deleted the properties branch February 26, 2020 10:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants