Skip to content

Let UseEnum select a member by value, not only by name or number - #979

Open
sap1110 wants to merge 1 commit into
ipython:mainfrom
sap1110:useenum-select-by-value
Open

Let UseEnum select a member by value, not only by name or number#979
sap1110 wants to merge 1 commit into
ipython:mainfrom
sap1110:useenum-select-by-value

Conversation

@sap1110

@sap1110 sap1110 commented Aug 17, 2026

Copy link
Copy Markdown

Closes #827

UseEnum resolves a member from its name, its scoped name, or (for int-valued enums) its number. There is no lookup by value, so a str-based enum whose member names differ from their values cannot be set by value:

class Color(str, enum.Enum):
    RED = "red"
    GREEN = "green"
    BLUE = "blue"

class MyEntity(HasTraits):
    color = UseEnum(Color, default_value=Color.BLUE)

MyEntity().color = "GREEN"   # fine, that is the member name
MyEntity().color = "green"   # TraitError, though it is Color.GREEN's value
TraitError: The 'color' trait of a MyEntity instance expected any of
['RED', 'BLUE', 'GREEN'], not the str 'green'.

The docstring example hides this because its member names are lowercase and equal to nothing else, so "green" happens to match a name. Give the members conventional uppercase names and the string form stops working entirely.

select_by_value is the non-numeric counterpart of the existing select_by_number, and the string branch of validate now falls back to it.

The change is additive. Name lookup is still attempted first, so every string that resolved before resolves to the same member; the new lookup only runs where a TraitError was previously raised. There is a test using an enum whose member name shadows a different member's value, so the precedence is pinned rather than incidental.

One thing worth a second opinion: info() still lists only member names, so the error text for a genuinely bad value reads expected any of ['RED', 'BLUE', 'GREEN'] even though values are now accepted too. Widening it would change message text that downstream suites may match on, so I left it alone. Happy to include it if you'd rather they agree.


🤖🍆 Prepared with the help of an AI coding agent, marked as the contributing guide asks agents to do. Reviewed and tested by me.

UseEnum accepts a member's name, its scoped name, and (for int-valued enums)
its number, but it has no lookup by value. A str-based enum whose member names
differ from their values therefore cannot be set by value at all:

    class Color(str, enum.Enum):
        RED = "red"
        GREEN = "green"

    class MyEntity(HasTraits):
        color = UseEnum(Color)

    MyEntity().color = "GREEN"   # worked, matched the member name
    MyEntity().color = "green"   # TraitError, though it is Color.GREEN's value

select_by_value mirrors the existing select_by_number for non-numeric values,
and the string branch of validate falls back to it. Name lookup is still tried
first, so any string that resolved before resolves to the same member now; the
fallback only runs where a TraitError was raised before. A test covers an enum
whose member name shadows another member's value to pin that ordering.
@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.17%. Comparing base (80756bf) to head (971a590).

Components Coverage Δ
traitlets 85.53% <100.00%> (+0.03%) ⬆️
tests 99.07% <100.00%> (+<0.01%) ⬆️

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

UseEnum does not work with str enum

1 participant