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

Add allow_none flag for Callable trait #885

Merged
merged 9 commits into from
Feb 14, 2020

Conversation

midhun-pm
Copy link
Contributor

Fixes #773

PR adds a new optional argument allow_none to the Callable trait, which if set to False prevents None from being assigned to the trait.

If not specified, defaults to allow_none=True, leaving the current behavior unchanged.

@midhun-pm
Copy link
Contributor Author

I'm not sure whether validate_trait_complex (which verifies a complex trait definitions) need to be updated as well as it currently allows callables that are None and no way to turn it off.

@mdickinson
Copy link
Member

I'm not sure whether validate_trait_complex [...] need to be updated as well

It probably does: the validation in validate_trait_complex should match the validation in the dedicated validation function.

@codecov-io
Copy link

codecov-io commented Feb 7, 2020

Codecov Report

Merging #885 into master will increase coverage by 0.24%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #885      +/-   ##
==========================================
+ Coverage   72.58%   72.82%   +0.24%     
==========================================
  Files          51       51              
  Lines        6471     6474       +3     
  Branches     1302     1302              
==========================================
+ Hits         4697     4715      +18     
+ Misses       1378     1360      -18     
- Partials      396      399       +3
Impacted Files Coverage Δ
traits/trait_types.py 71.07% <100%> (-0.09%) ⬇️
traits/editor_factories.py 81.25% <0%> (-3.13%) ⬇️
traits/traits.py 76.92% <0%> (+4.04%) ⬆️
traits/etsconfig/etsconfig.py 63.8% <0%> (+6.13%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2815c85...50bba9c. Read the comment docs.

traits/ctraits.c Outdated

if ((value == Py_None) || PyCallable_Check(value)) {
if ((allow_none && value == Py_None) || PyCallable_Check(value)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something of a micro-optimisation, but I think we should only unpack and interpret the second element of trait->py_validate after we've checked value == Py_None: the == Py_None check is cheap, but the PyObject_IsTrue call will be more time-consuming.

We also need to catch the case where PyObject_IsTrue returns -1: in that case, something unexpected has happened and we should be returning NULL immediately.

traits/ctraits.c Outdated
goto done;
{
int allow_none = PyObject_IsTrue(PyTuple_GET_ITEM(type_info, 1));
if ((allow_none && value == Py_None) || PyCallable_Check(value)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar comments to those for validate_trait_callable apply here: we need to do an error check on the return value of PyObject_IsTrue, and it probably makes sense to defer the PyObject_IsTrue call until after checking that value == Py_None.

Copy link
Member

@mdickinson mdickinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor changes needed in the C code.

Would it be worth adding a test for the default of allow_none? i.e., a new unit test that checks that a foo = Callable() trait does allow None?

traits/ctraits.c Outdated
@@ -4269,7 +4273,7 @@ _trait_set_validate(trait_object *trait, PyObject *args)
break;

case 22: /* Callable check: */
if (n == 1) {
if (n == 2) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether there's a potential pickle compatibility problem here: if a Callable trait has been pickled with Traits 6.0.0, does this check prevent it from being unpickled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will be a problem since the expected number of arguments is different, I currently don't ensure that there are 2 arguments before I index into the second one. I think i'll count the args and also change the above to n <=2 and then choose the correct flow accordingly.

@mdickinson mdickinson self-assigned this Feb 12, 2020
Copy link
Member

@mdickinson mdickinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; a few nitpicks. Feel free either to merge after applying the suggested changes, or to disagree with the suggested changes and not apply them. :-)

traits/ctraits.c Outdated Show resolved Hide resolved
traits/ctraits.c Outdated Show resolved Hide resolved
traits/ctraits.c Outdated Show resolved Hide resolved
traits/ctraits.c Outdated Show resolved Hide resolved
traits/ctraits.c Outdated Show resolved Hide resolved
Copy link
Member

@mdickinson mdickinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few more suggested changes

traits/ctraits.c Outdated Show resolved Hide resolved
traits/ctraits.c Outdated Show resolved Hide resolved
@midhun-pm midhun-pm merged commit ba0c0ca into master Feb 14, 2020
@midhun-pm midhun-pm deleted the feature/support_allow_none_for_callable_trait branch February 14, 2020 15:37
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.

Consider adding allow_none option to Callable
3 participants