This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: vars() manipulation encounters problems with Enum
Type: behavior Stage: resolved
Components: Versions: Python 3.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: ethan.furman Nosy List: Eric.Wieser, barry, eli.bendersky, ethan.furman
Priority: normal Keywords: patch

Created on 2017-10-17 00:21 by ethan.furman, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 5237 merged ethan.furman, 2018-01-18 23:39
Messages (3)
msg304487 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2017-10-17 00:21
The following code should work (from https://stackoverflow.com/a/46780742/208880):


    class BaudRate(Enum):

        cls = vars()
        regexp = r"(?:^|,)B(?P<rate>\d+)"
        rates = sorted(map(int, re.findall(regexp, ",".join(dir(termios)))))
        for value in rates:
            cls['B%d' % value] = value

        @classmethod
        def valid_rate(cls, value):
            return (any(value == item.value for item in cls))


This doesn't work because EnumMeta does not allow names to be reassigned nor deleted.  aenum gets around this by allowing an _ignore_ attribute which contains the names that should not be tracked (and, in fact, those names are removed from the final class).

Unless a better idea is put forward, I will add _ignore_ support to Enum.
msg306257 - (view) Author: Eric Wieser (Eric.Wieser) * Date: 2017-11-15 08:24
Not necessarily an argument against this feature, but two workarounds exist for this already:


1. Use `nonlocal` to prevent `value` going into the class namespace:

    value = None
    
    class BaudRate(enum.Enum):    
        nonlocal value
        for value in rates:
            locals()['B%d' % value] = value
    
        @classmethod
        def valid_rate(cls, value):
            return (any(value == item.value for item in cls))

2. Use `types.new_class`, which is more suited to dynamic class creation anyway:

    def make_cls(ns):
        for value in rates:
            ns['B%d' % value] = value

        @classmethod
        def valid_rate(cls, value):
            return (any(value == item.value for item in cls))

        ns['valid_rate'] = valid_rate

    types.new_class('BaudRate', (enum.Enum,), exec_body=make_cls)
msg310425 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2018-01-22 15:56
New changeset a4b1bb4801f7a941ff9e86b96da539be1c288833 by Ethan Furman in branch 'master':
bpo-31801:  Enum:  add _ignore_ as class option (#5237)
https://github.com/python/cpython/commit/a4b1bb4801f7a941ff9e86b96da539be1c288833
History
Date User Action Args
2022-04-11 14:58:53adminsetgithub: 75982
2018-09-10 18:30:27ethan.furmansetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2018-01-22 15:56:39ethan.furmansetmessages: + msg310425
2018-01-18 23:39:01ethan.furmansetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request5083
2018-01-18 19:33:12ethan.furmansetstage: test needed -> needs patch
2017-11-15 08:24:49Eric.Wiesersetnosy: + Eric.Wieser
messages: + msg306257
2017-10-17 00:21:55ethan.furmancreate