Bug 2414940
| Summary: | argparse colorize fails if a tty is not available, like in mod_wsgi | ||
|---|---|---|---|
| Product: | [Fedora] Fedora | Reporter: | Rob Crittenden <rcritten> |
| Component: | python3.14 | Assignee: | Miro Hrončok <mhroncok> |
| Status: | CLOSED ERRATA | QA Contact: | |
| Severity: | unspecified | Docs Contact: | |
| Priority: | unspecified | ||
| Version: | 43 | CC: | ksurma, mhroncok, python-maint, python-packagers-sig, vashirov |
| Target Milestone: | --- | ||
| Target Release: | --- | ||
| Hardware: | Unspecified | ||
| OS: | Linux | ||
| Whiteboard: | |||
| Fixed In Version: | python3.14-3.14.2-1.fc43 | Doc Type: | --- |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2025-12-10 01:33:49 UTC | Type: | --- |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
| Embargoed: | |||
Reproducer not of the crash but that color=False is not honored.
I added an import pdb; pdb.set_trace() to _set_color() in /usr/lib64/python3.14/argparse.py prior to the conditional and color is True.
This is the code I used to create the parser and an option
import argparse
parser = argparse.ArgumentParser(add_help=False, color=False)
arg = parser.add_argument('-v', '--verbose', help='verbose', action='store_true', default=False)
For what it's worth this change fixes it for me:
diff -u /usr/lib64/python3.14/argparse.py /tmp/argparse.py
--- /usr/lib64/python3.14/argparse.py 2025-10-06 20:00:00.000000000 -0400
+++ /tmp/argparse.py 2025-11-13 17:31:11.678000000 -0500
@@ -2722,7 +2722,7 @@
return formatter.format_help()
def _get_formatter(self):
- formatter = self.formatter_class(prog=self.prog)
+ formatter = self.formatter_class(prog=self.prog, color=self.color)
formatter._set_color(self.color)
return formatter
(In reply to Rob Crittenden from comment #0) > argparse enables color by default. > > If an argument is added and there is no tty it will fail like: > > File "/usr/lib64/python3.14/argparse.py", line 1556, in add_argument > formatter = self._get_formatter() > File "/usr/lib64/python3.14/argparse.py", line 2725, in _get_formatter > formatter = self.formatter_class(prog=self.prog) > File "/usr/lib64/python3.14/argparse.py", line 178, in __init__ > self._set_color(color) > ~~~~~~~~~~~~~~~^^^^^^^ > File "/usr/lib64/python3.14/argparse.py", line 198, in _set_color > if color and can_colorize(): > ~~~~~~~~~~~~^^ > File "/usr/lib64/python3.14/_colorize.py", line 314, in can_colorize > return os.isatty(file.fileno()) Is there a part of this traceback missing? What is the exception? (In reply to Rob Crittenden from comment #1) > Reproducer not of the crash but that color=False is not honored. > > I added an import pdb; pdb.set_trace() to _set_color() in > /usr/lib64/python3.14/argparse.py prior to the conditional and color is True. > > This is the code I used to create the parser and an option > > import argparse > > parser = argparse.ArgumentParser(add_help=False, color=False) > arg = parser.add_argument('-v', '--verbose', help='verbose', > action='store_true', default=False) I don't really understand this code either. When I run it, what do I do next to see the problem? There's https://github.com/python/cpython/commit/734e15b70dc044f57df4049a22dd769dffdb7d18 which removed the color=self.color argument and replaced it with _set_color(self.color) I still am not entirely sure what exact problem you see. Perhaps it's related to subinterpreters. Sorry, my paste cut off. The exception raised is:
OSError: Apache/mod_wsgi log object is not associated with a file descriptor.
In order to see the problem you need to instrument argparse.py to display the value of color in _set_color(). Like this:
--- /tmp/argparse.py 2025-11-14 08:46:10.368685441 -0500
+++ /usr/lib64/python3.14/argparse.py 2025-11-14 08:46:43.186354166 -0500
@@ -195,6 +195,8 @@
def _set_color(self, color):
from _colorize import can_colorize, decolor, get_theme
+ print(color)
+ _sys.exit(1)
if color and can_colorize():
self._theme = get_theme(force_color=True).argparse
self._decolor = decolor
When you run the script you'll get the value of color as True. It should be False as ArgumentParser() was instantiated with color=False.
The code shouldn't get as far as determining if a tty is available or not because color should be False.
I'm seeing this exception in a PR to the freeipa project. I didn't post any direct links because it is full of other stuff that would just muddy the water.
So what the current argparse code does is this: 1. It initiates a HelpFormatter instance with no explicit color argument 2. The __init__ calls self._set_color(color), which is self._set_color(True) 3. Only then, it sets the color to False and call self._set_color(False) I don't know if this is intentional or not. That said, even when color is True, you probably get: OSError: Apache/mod_wsgi log object is not associated with a file descriptor. Right? So there are two possible fixes here: - the code should probably not call self._set_color(True), self._set_color(False) - The code should handle the OSError and assume it means not a tty Do I get that right? Either would be fine. How urgent is this? My upstream fix should be available in Python 3.14.1 scheduled for Tuesday, 2025-12-02. That is fine. I worked around it by modifying imports to not import the thing that invokes argparse. FEDORA-2025-e235793f10 (python3.14-3.14.2-1.fc43 and python3-docs-3.14.2-1.fc43) has been submitted as an update to Fedora 43. https://bodhi.fedoraproject.org/updates/FEDORA-2025-e235793f10 FEDORA-2025-e235793f10 (python3.14-3.14.2-1.fc43 and python3-docs-3.14.2-1.fc43) has been pushed to the Fedora 43 stable repository. If problem still persists, please make note of it in this bug report. |
argparse enables color by default. If an argument is added and there is no tty it will fail like: File "/usr/lib64/python3.14/argparse.py", line 1556, in add_argument formatter = self._get_formatter() File "/usr/lib64/python3.14/argparse.py", line 2725, in _get_formatter formatter = self.formatter_class(prog=self.prog) File "/usr/lib64/python3.14/argparse.py", line 178, in __init__ self._set_color(color) ~~~~~~~~~~~~~~~^^^^^^^ File "/usr/lib64/python3.14/argparse.py", line 198, in _set_color if color and can_colorize(): ~~~~~~~~~~~~^^ File "/usr/lib64/python3.14/_colorize.py", line 314, in can_colorize return os.isatty(file.fileno()) This is seen trying to issue a certificate using freeIPA. IPA uses lib389 which uses argparse for generating command-line options, which is done on import. So merely importing this library within mod_wsgi will cause it to fail because it can't detect that there is no tty available. Reproducible: Always