Title: enum: _generate_next_value_ is not called if its definition occurs after calls to auto()
Type: behavior Stage: patch review
Components: Library (Lib) Versions: Python 3.9, Python 3.8, Python 3.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: ethan.furman Nosy List: Ethan Onstott, Jonathan Hsu, ankeshsaha, barry, docs@python, edd07, eli.bendersky, ethan.furman
Priority: normal Keywords: easy, patch

Created on 2020-03-20 11:25 by edd07, last changed 2020-03-30 15:23 by ankeshsaha.

File name Uploaded Description Edit
Issue40025.PNG ankeshsaha, 2020-03-30 15:23 Screenshot of the code and output
Pull Requests
URL Status Linked Edit
PR 19098 open Ethan Onstott, 2020-03-21 05:15
Messages (6)
msg364665 - (view) Author: Luis E. (edd07) Date: 2020-03-20 11:25
I ran into this issue when attempting to add a custom _generate_next_value_ method to an existing Enum. Adding the method definition to the bottom of the class causes it to not be called at all:

from enum import Enum, auto

class E(Enum):
	A = auto()
	B = auto()
	def _generate_next_value_(name, *args):
		return name

E.B.value  # Returns 2, E._generate_next_value_ is not called

class F(Enum):
	def _generate_next_value_(name, *args):
		return name
	A = auto()
	B = auto()
F.B.value  # Returns 'B', as intended

I do not believe that the order of method/attribute definition should affect the behavior of the class, or at least it should be mentioned in the documentation.
msg364707 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2020-03-20 19:09
Immediate solution is to raise an exception if `_generate_next_value_` is defined after members.

Possible future solution is to save all member definitions until after class is defined.

The exception-raising solution would require a check in `_EnumDict` where `_generate_next_value_` is saved -- if any members already exist, raise.
msg364776 - (view) Author: Jonathan Hsu (Jonathan Hsu) * Date: 2020-03-21 21:45
While the current behavior may be initially unexpected, it does match the way that python normally behaves when defining class variables. For example, the following class will throw an exception because the function number_two() is called before it is defined:

class Numbers:
    one = 1
    two = number_two()

    def number_two():
        return 2

# NameError: name 'number_two' is not defined

However, this version is fine:

class Numbers:
    one = 1

    def number_two():
        return 2

    two = number_two()
msg364784 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2020-03-22 05:20
Jonathan Hsu, you are correct -- and "don't do that" was my initial response; but Enum takes many pains to make sure the user doesn't shoot themselves in the foot, so raising a TypeError is appropriate instead of silently doing the wrong thing.
msg364967 - (view) Author: Jonathan Hsu (Jonathan Hsu) * Date: 2020-03-25 00:55
Thank you for the explanation.
msg365321 - (view) Author: Ankesh Saha (ankeshsaha) Date: 2020-03-30 15:23

I have ran the code with with _generate_next_value_ method at the bottom of the class and didn't run into any exceptions. Please refer my python file. Please let me know if I am missing something.

from enum import Enum, auto

class E(Enum):
	A = auto()
	B = auto()
	def _generate_next_value_(name, *args):
		return name

for l in (E):
Date User Action Args
2020-03-30 15:23:41ankeshsahasetfiles: + Issue40025.PNG
nosy: + ankeshsaha
messages: + msg365321

2020-03-25 00:55:55Jonathan Hsusetmessages: + msg364967
2020-03-22 05:20:26ethan.furmansetmessages: + msg364784
2020-03-21 21:45:08Jonathan Hsusetnosy: + Jonathan Hsu
messages: + msg364776
2020-03-21 05:15:28Ethan Onstottsetkeywords: + patch
nosy: + Ethan Onstott

pull_requests: + pull_request18458
stage: needs patch -> patch review
2020-03-20 19:09:21ethan.furmansetversions: + Python 3.8, Python 3.9
messages: + msg364707

assignee: docs@python -> ethan.furman
keywords: + easy
stage: needs patch
2020-03-20 13:35:17xtreaksetnosy: + barry, eli.bendersky, ethan.furman
2020-03-20 11:27:27edd07setcomponents: - Documentation
2020-03-20 11:25:03edd07create