-
Notifications
You must be signed in to change notification settings - Fork 289
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
Added docstrings to python bindings for interval algebra methods in TimeRange #789
Added docstrings to python bindings for interval algebra methods in TimeRange #789
Conversation
…n TimeRange. Also re-arranged the overloaded definitions so the TimeRange/RationalTime variants would have consistent ordering.
Is the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spotted a typo, otherwise looks good. Does it build all the way through to RtD?
921491c
to
e89d4b2
Compare
The docstrings did have a rendering issue in sphinx. As a note, the majority of the C++ codebase isn't getting picked up by sphinx, I've filed #790 for that. To check these docs, I commented out this line: Then added the following to the auto-generated files in
Here's an example of the rendered output: |
Docs look good. Do you know if there is a way of getting the function signature to python to not appear as the |
The fact that it renders
via kwargs, rather than something friendly is a surprise to me. Maybe we should open an issue on the Pybind11 repo? |
Because I'm a bit crazy, I've worked through another possible solution. The end result looks like this:
To achieve this, I implemented the .def("before", [](TimeRange self, py::object other, double epsilon) {
try {
auto tr = other.cast<TimeRange>();
return self.before(tr);
} catch (py::cast_error e) {
try {
auto rt = other.cast<RationalTime>();
return self.before(rt);
}
catch (py::cast_error e) {
throw py::type_error("before() argument must be TimeRange or RationalTime");
}
}
}, "other"_a, "epsilon_s"_a=opentime::DEFAULT_EPSILON_s, R"docstring(
If other is `otio.opentime.RationalTime`:
The end of `this` strictly precedes `other` by a value >= `epsilon_s`.
::
other
↓
[ this ] *
If other is `otio.opentime.TimeRange`:
The end of `this` strictly equals the start of `other` and
the start of `this` strictly equals the end of `other`.
::
[this][other]
The converse would be ``other.meets(this)``
)docstring") If we decide this is the option we want to go with, I'd love some guidance on the idiomatic C++ way to make a reusable form of this since it's used over and over for many methods. It feels like there might be a solution with either templates or method pointers? |
With the existing implementation, the legality of RationalTime and TimeInterval is explicit, and can be discovered by introspecting an object. A downside of this casting method is that the legality of RationalTime is hidden from the runtime, and the invocation of the RationalTime variant is a side effect of exception handling. That would be a C++ anti-pattern. More idiomatically, you could ask the other template if a particular cast is legal, and then branch accordingly without invoking exceptions. That said, even casting checks are expensive. Ultimately I think hiding the legality of RationalTime from the API is probably too much of a design cost. Jamming on your idea of a binding, I wonder if there is some other wrapping pattern that preserves the disclosure of legal types in the API, but avoids the ugliness of the kwargs in the autogenerated docs? |
lgtm |
Also re-arranged the overloaded definitions so the TimeRange/RationalTime variants would have consistent ordering.
Here is a summary of what the docstrings in python look like now: