-
-
Notifications
You must be signed in to change notification settings - Fork 30.4k
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
Enum: modify __repr__, __str__; update docs #84247
Comments
Serhiy had the idea of having Enum._convert also modify the __str__ and __repr__ of newly created enumerations to display the module name instead of the enumeration name (https://bugs.python.org/msg325007): --> socket.AF_UNIX --> print(socket.AF_UNIX) Thoughts? |
Yes. And repr should be inverse of eval, but it's probably too late for that. :-/ |
Looks like the >>> import re
>>> re.I
re.IGNORECASE
>>> print(re.I)
# should also be re.IGNORECASE
>>> re.I|re.S|re.X
re.IGNORECASE|re.DOTALL|re.VERBOSE For stdlib Enum conversions are we happy with that? Or should __str__ just print the numeric value? |
If it's considered to be not too backwards-incompatible, I think it would be nice to have str different from repr. That way we can finetune what exactly we need. But we can already do almost exactly that with *int* instead of *str*, so it's not too compelling. Much more important thing is the "repr as inverse of eval". Is there any way we can have that for our own enums (as a mixin or a decorator)? @module_global(re)
class RegexFlag(Enum):
... It would be fantastic. :-) |
"repr as inverse of eval" is nice to have, but it is not a requirement. |
Noone said it is a requirement, I just said it would be nice to have it factored out as a decorator or something instead of having to write __repr__ over and over again. |
At this point, the PR has made the following changes:
|
Python-Dev thread [0], summary below:
After discussions with Guido I made a (largely done) PR [3] which: for stdlib global constants (such as RE)
for stdlib non-global constants, and enums in general
The questions I would most appreciate an answer to at this point:
As a reminder, the underlying issue is trying to keep at least the stdlib Enum representations the same for those that are replacing preexisting constants. [1] I'm working on making their creation faster. If anyone wanted to convert EnumMeta to C I would be grateful. [2] https://bugs.python.org/issue36548 [3] #22392 |
Absolutely.
Well, standard backward compatibility stuff. :-) |
It breaks doctests, and probably some other unit tests, too, e.g. for output formatting. What should we suggest users to do? Replace >>> get_flag(…)
<app_enums.TrickyFlag: 1> by >>> get_flag(…) == app_enums.TrickyFlag or get_flag(…) # (also show result on failure)
True and assertEqual(
"You caught the %s flag!" % result,
"You caught the app_enums.TrickyFlag flag!") by
? Note that using "%r" does not help, since it's also backwards incompatible. For their own enums, users can probably backport (or forward-port) "__str__()" and "__repr__()" themselves in order to work around this difference. But it's something they would have to do. I certainly understand the reasoning, and it also makes new Py3.10-only doctests nicer, actually, but IMHO it counts as deliberate breakage. |
I'm probably a bit late to the party as well, but as some additional datapoints:
|
Thank you for the feedback. The new str() and repr() make more sense for Flag-based enumerations, and I'm hesitant to have different formats for Enum- vs Flag-based enums. Would it be helpful to have another base Enum class to derive from that maintained the original str() and repr() formats? |
It may be helpful for the enum module to come with transitional functions like "pre310_str()" "pre310_repr()" "pre310_flag_str()" etc. so that people who are writing doctests that need to function on both < 3.10 and 3.10+ can temporarily do a "Enum.__str__ = pre310_str" in their test suites (and of course restore it later) until <=3.9 is no longer supported. Otherwise everyone with doctest suites will be doing this ourselves. |
#74767 broke doc tests in 3.11 branch: File "library/enum.rst", line ?, in default
Failed example:
Color(0)
Exception raised:
Traceback (most recent call last):
File "/home/runner/work/cpython/cpython/Lib/doctest.py", line 1346, in __run
exec(compile(example.source, filename, "single",
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<doctest default[0]>", line 1, in <module>
Color(0)
^^^^^
NameError: name 'Color' is not defined |
This also broke our Solaris build with the following error: ====================================================================== Traceback (most recent call last):
File "/..../cpython-main/Lib/test/test_socket.py", line 1523, in testGetaddrinfo
self.assertEqual(repr(type), '<SocketKind.SOCK_STREAM: 1>')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: '<SocketKind.SOCK_STREAM: 2>' != '<SocketKind.SOCK_STREAM: 1>'
- <SocketKind.SOCK_STREAM: 2>
? ^
+ <SocketKind.SOCK_STREAM: 1>
? ^ (test.test_socket.GeneralModuleTests fails with the same error). The issue is almost certainly that on Solaris, SOCK_STREAM is defined as 2 rather than 1; the following simple program confirms that: #include <stdio.h>
#include <sys/socket.h>
void main() {
printf("%d\n", SOCK_STREAM);
} I'm just not sure whether to fix this with |
Sorry, I had to revert the change since it broke the CI and it prevented to merge new PRs. Tell me if I can help to get this test fixed and to get this change merged again. By the way, the PR 30582 was merged even if the Docs CI failed. |
After merging in doc fix by kumaraditya303, I'll update tests so Solaris passes. |
For this one, I suggest to replace the value with "..." doctest pattern. |
vstinner wrote:
That bit of code is from the unittest suite, not the doctest suite. I went with:
|
I created python/core-workflow#424 "Should we make the Docs CI mandatory on the Python main branch?". |
Python 3.11 has changed behavior of __str__ for IntEnum. Before it would return the name, like "Color.RED", now it's equivalent to str(self.value), for example "1".__repr__ is unchanged [1]. Python 3.11 also introduced StrEnum, which we can use instead of mixing in str type for our StrEnumDefinition, and that introcudes the same change of __str__ behavior: it returns the value as string. The corresponds, in spirit, to what I often did in Python: class Color(Enum): RED="red" BLUE="blue" def __str__(self): return self.value To ensure consistent behavior for different Python versions, and because we can determine our own rules for the enum types we define, we mimic the 3.11 __str__ behavior on IntEnumDefinition and StrEnumDefinition. We use the same trick, by setting the __str__ property to the version of the underlying type: str.__str__ and int.__repr__. int.__str__ won't do because int directly inherits object.__str__ that basically repr(self), and thus back to Enum.__repr__. So we need int.__repr__ to return the integer as string. [1] python/cpython#84247
support python3.11 python/cpython#100458 python/cpython#84247
repr()
andstr()
#22392Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: