-
-
Notifications
You must be signed in to change notification settings - Fork 31k
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
gh-129061: Fix FORCE_COLOR
and NO_COLOR
when empty strings
#129140
base: main
Are you sure you want to change the base?
Conversation
b67ac03
to
c7b5419
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
🤖 New build scheduled with the buildbot fleet by @hugovk for commit ec36e22 🤖 Results will be shown at: https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F30617%2Fmerge If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again. |
Like #129137 (comment), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We only need to test pairs of environment variables that set conflicting values.
For example, NO_COLOR=1
and TERM=dumb
should be tested with FORCE_COLOR=1
and PYTHON_COLOR=1
. Tests for a single environment variable which forces color (FORCE_COLOR
and PYTHON_COLOR
) should be performed when the fallback value determined by isatty or _supports_virtual_terminal is False.
We need also to test can_colorize()
when stderr is a TTY, but stdout is not, and with an explicit file argument. Including corner cases: no file.fileno
, no file.isatty
, file.isatty()
and os.isatty(file.fileno())
return different results. BTW, I think that file.isatty()
should perhaps be tested before os.isatty(file.fileno())
.
This is a large issue and can be done in a separate PR.
Lib/test/test__colorize.py
Outdated
({"PYTHON_COLORS": "1"}, True), | ||
({"PYTHON_COLORS": "0"}, False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test also an empty value. Or other values (e.g. "2").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added "true" and "2".
Lib/test/test__colorize.py
Outdated
({"NO_COLOR": "1"}, False), | ||
({"NO_COLOR": "0"}, False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test also an empty value.
Lib/test/test__colorize.py
Outdated
({"NO_COLOR": "1"}, False), | ||
({"NO_COLOR": "0"}, False), | ||
({"NO_COLOR": "1", "PYTHON_COLORS": "1"}, True), | ||
({"FORCE_COLOR": "1"}, True), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the fallback value (determined by TERM, isatty or _supports_virtual_terminal) is True, setting FORCE_COLOR to "1" does not have any effect. We need to test it when the fallback value is False.
You can test {"TERM": "dumb", "FORCE_COLOR": "1"}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{"FORCE_COLOR": "1"}
returns early before checking TERM
, isatty
and nt._supports_virtual_terminal
, so I think there is value testing {"FORCE_COLOR": "1"}
.
I'll add {"TERM": "dumb", "FORCE_COLOR": "1"}
as well.
Lib/test/test__colorize.py
Outdated
({"FORCE_COLOR": "1", "NO_COLOR": "1"}, False), | ||
({"FORCE_COLOR": "1", "NO_COLOR": "0"}, False), | ||
({"FORCE_COLOR": "1", "NO_COLOR": ""}, True), | ||
({"FORCE_COLOR": "0", "NO_COLOR": "1"}, False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both variables set the same condition. This test does not add anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These variables are contradictory, one says to force colour, the other to disable:
"FORCE_COLOR": "0"
: the variable is present and not an empty string (regardless of its value) --> force colour"NO_COLOR": "1"
: the variable is present and not an empty string (regardless of its value) --> disable colour- But
NO_COLOR
takes priority overFORCE_COLOR
--> disable colour wins
We're testing that NO_COLOR
takes priority and that the value doesn't matter.
True, in the implementation, we return early when checking NO_COLOR
before looking at NO_COLOR
, but the tests don't care about implementation details, only the end result.
And these tests are fast to run.
Lib/test/test__colorize.py
Outdated
({"FORCE_COLOR": "1", "NO_COLOR": "0"}, False), | ||
({"FORCE_COLOR": "1", "NO_COLOR": ""}, True), | ||
({"FORCE_COLOR": "0", "NO_COLOR": "1"}, False), | ||
({"FORCE_COLOR": "", "NO_COLOR": "1"}, False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FORCE_COLOR values does not matter, and this was already tested by {"FORCE_COLOR": "1", "NO_COLOR": "1"}
. So this test is unneded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"FORCE_COLOR": ""
is empty so this has no effect."NO_COLOR": "1"
means disable colour.- So disabling colour wins.
Yes, this does have the same result as {"FORCE_COLOR": "1", "NO_COLOR": "1"}
, and because we check NO_COLOR
first and return early, FORCE_COLOR
has no effect for both.
But I think it's fine to ensure these inputs give this expected output.
However, if you feel strongly about it, I'm happy to remove them.
Some failures on Windows for: ({"PYTHON_COLORS": "true"}, True),
({"PYTHON_COLORS": "2"}, True),
({"PYTHON_COLORS": ""}, True), That's because according to the docs:
Therefore everything that is not "0" or "1" is ignored, and the result depends on other conditions. This also fails on Windows: ({"NO_COLOR": ""}, True), That's because an empty value means we ignore it, and again the result depends on other conditions. Shall we remove these four, or use them in combination with some other variables? |
See improved tests in #129234. They cover all corner cases. I propose to push it first, and then add tests for empty values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only the first two checks are necessary. Others do not add anything useful. They look out of place and make the intention of the tests less clear.
The first group tests the different values of the variables. The second group tests relative priority of the variables (it does not repeat tests for different values). Then the same is done for PYTHON_COLORS -- first the different values of PYTHON_COLORS (including the empty value), then its relative priority to other variables.
First refactor the tests into subtests, which makes it easier compare the env var inputs and expected outputs.