Skip to content

Refactor color traits#924

Merged
corranwebster merged 5 commits into
mainfrom
enh/unify-color-traits
Apr 21, 2022
Merged

Refactor color traits#924
corranwebster merged 5 commits into
mainfrom
enh/unify-color-traits

Conversation

@corranwebster
Copy link
Copy Markdown
Contributor

This combines the two color traits in Enable: ColorTrait (which is mapped) and RGBAColorTrait (which is not), updating them so that they don't use the old Trait factory and are simple TraitTypes instead.

It combines validation so that they accept the same wide set of values, and makes use of the code from Pyface for parsing color values and the standard color names (Pyface's values were originally taken from Enable). It also unifies the editors, so that both traits have the same editors.

Fixes #895 (at least as much as we can right now).

This combines the two color traits in Enable: ColorTrait (which is mapped)
and RGBAColorTrait (which is not), updating them so that they don't use the
old `Trait` factory and are simple TraitTypes instead.  It combines validation
so that they accept the same wide set of values, and makes use of the code from
Pyface for parsing color values and the standard color names (Pyface's values
were originally taken from Enable).  It also unifies the editors, so that both
traits have the same editors.
Copy link
Copy Markdown
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.

Mostly LGTM; a few nitpicks, suggestions and questions in the inline comments.

Comment thread enable/colors.py Outdated
from traitsui.api import toolkit as traits_toolkit
from pyface.toolkit import toolkit

from enable.trait_defs.rgba_color_trait import (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it worth adding a # noqa: F401 here, just to make it clear to the code reader that this is an import for re-export, not for use within the module?

Comment thread enable/colors.py Outdated
convert_to_color_tuple as convert_to_color,
transparent_color_trait, white_color_trait
)
from enable.trait_defs.ui.rgba_color_editor import RGBAColorEditor as ColorEditorFactory
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nitpick: Long line (but I'm not sure what conventions are in place for code style here).

Comment thread enable/colors.py
from traitsui.wx.constants import WindowColor

color_table["sys_window"] = (
color_table["syswindow"] = (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

On a first pass I was confused by the fact that "sys_window" still appears elsewhere in the codebase and docs (notably in the AbstractWindow and ComponentEditor definitions). I realise now that the color name parsing strips underscores, so it doesn't make a difference in the end, but would it be worth updating those references too?

Comment thread enable/colors.py Outdated
"(r,g,b,a)"
)

# XXX to-do: this will not work if dark mode changes
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please could you open an issue for this and add the issue reference to the comment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Already done: #923

from enable.trait_defs.rgba_color_trait import RGBAColor

rgba_float_dtype = np.dtype([
('red', float),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nitpick-level: use "float64" instead of float, for consistency and to avoid the implicit conversion from NumPy?

Comment thread enable/trait_defs/rgba_color_trait.py Outdated
Comment thread enable/trait_defs/rgba_color_trait.py Outdated
Comment thread enable/trait_defs/rgba_color_trait.py Outdated
try:
default_value = convert_to_color_tuple(value)
except Exception:
self.error(None, None, value)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The generated error message isn't friendly here: for something like RGBAColor("octarine") we end up with the exception traits.trait_errors.TraitError: None. Proposal: leave out the try / except altogether, and just let the convert_to_color_tuple exception propagate. That would mean that the reported exception for an invalid Trait declaration would have type TypeError or ValueError instead of TraitError, but I don't see a problem with that (in fact, I think it's an improvement).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That may break use in TraitsUI - TraitsUI editors often treat TraitError as "the user typed something that is invalid for the underlying trait but otherwise OK" (and may be flagged in the UI by color changes, etc.) but treats other exceptions as being more fundamental.

So I think we want TraitError. I will look into whether the error message can be made better. I know that the existing color traits often give an unhelpful laundry list of all the possible color names.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

But this is in the trait definition, not trait validation. We definitely want TraitError in the validation - that's what TraitError is for. I'm suggesting that we don't need (or indeed want) it in the trait definition.

I think it would be extremely rare that we're trying to catch TraitError when defining a trait in a class.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

More generally, TraitError has a very specific purpose, namely allowing users (like TraitsUI editors, exactly as you describe) to catch traited attribute validation errors. But there's been a tendency to broaden that scope and use TraitError for anything vaguely traits-related. That's something I'm actively trying to reverse, since it increases the possibility that people who actually want to catch the "invalid attribute" case (the intended use-case) end up catching other errors as well.

Copy link
Copy Markdown
Contributor Author

@corranwebster corranwebster Apr 21, 2022

Choose a reason for hiding this comment

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

Oh, this is in the __init__. Yep, that's better to just let it propagate.

Comment thread enable/trait_defs/rgba_color_trait.py Outdated

def __init__(self, value="white", **metadata):
default_value = self.validate(None, None, value)
try:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we add a class-level default_value_type = DefaultValue.constant to prevent Traits from doing its own default value type inference?

Comment thread enable/colors.py Outdated
corranwebster and others added 2 commits April 21, 2022 13:12
@corranwebster
Copy link
Copy Markdown
Contributor Author

I think this now addresses all the comments.

@mdickinson
Copy link
Copy Markdown
Member

@corranwebster Looks like there's a missing import causing CI to fail.

Copy link
Copy Markdown
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

@corranwebster corranwebster merged commit 6f04712 into main Apr 21, 2022
@jwiggins jwiggins deleted the enh/unify-color-traits branch April 28, 2022 09:15
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.

Integration with Pyface Color class and trait

2 participants