Skip to content

pygments themes are customizable #8752

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

Merged
merged 1 commit into from
Aug 15, 2021
Merged

pygments themes are customizable #8752

merged 1 commit into from
Aug 15, 2021

Conversation

azmeuk
Copy link
Member

@azmeuk azmeuk commented Jun 11, 2021

This patchs allows users to set two environment variables (PYTEST_THEME and PYTEST_THEME_MODE) to customize the pygments theme to use. It fixes #7132

I know some people were interested in rich and suggested to wait and see, but this solution is so easy and unintrusive I think it might be worth right now.

What do you think?

Copy link
Member

@RonnyPfannschmidt RonnyPfannschmidt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like this as even tho its a workaround ,it will give people with conditions like color blindness options to work with

i believe we should have some sort of test + a UsageError on case bg/style are unknown

do you want to add such a test/error handler?

@azmeuk
Copy link
Member Author

azmeuk commented Jun 11, 2021

I can. What do you expect? Catching the pygments exception and raise a custom exception with a nicer error message when the environment variables have invalid values?

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot @azmeuk!

Please also add the new variables to the reference.rst file, in the "Environment Variables" section.

@azmeuk
Copy link
Member Author

azmeuk commented Jun 11, 2021

I added some tests and applied your suggestions.

@@ -195,16 +195,34 @@ def _write_source(self, lines: Sequence[str], indents: Sequence[str] = ()) -> No

def _highlight(self, source: str) -> str:
"""Highlight the given source code if we have markup support."""
from _pytest.config.exceptions import UsageError
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I let this import inside the function to avoid a circular import error.

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @azmeuk! Looks great!

Left two other suggestions, otherwise LGTM. 👍

@azmeuk
Copy link
Member Author

azmeuk commented Jun 11, 2021

Done :)

Copy link
Member

@The-Compiler The-Compiler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to bikeshed this, but I wonder why it should be an environment variable, when (almost) all other things are either ini settings or commandline arguments?

We already have --code-highlight from #6934, so why not --code-highlight-theme and --code-highlight-theme-mode or so?

@nicoddemus
Copy link
Member

I'm 👍 on configuring this as env vars... my thinking is that this is something you might want change just for yourself because of preference/color blindness issues, and this is not easily done with config vars (you can of course use command-line vars indirectly with PYTEST_ADDOPTS).

@azmeuk
Copy link
Member Author

azmeuk commented Jun 11, 2021

I suggested an environment variable because of this comment, and because each contributor of a given project may have its own terminal configuration, and need its own color customization.

I am open to add/replace a command line argument though.

@RonnyPfannschmidt
Copy link
Member

unless pytest gets someething nice to unify config by env var, config file and cli argument im of the oppinion that this particular one is best placed in a env var, accompanied with some google search firendly docs for people that need it

@azmeuk azmeuk requested a review from The-Compiler June 12, 2021 13:08
@azmeuk
Copy link
Member Author

azmeuk commented Jun 14, 2021

It looks like the failing tests are unrelated with this patch.

@nicoddemus
Copy link
Member

@The-Compiler do you agree with the reasoning for the environment variables? If so could you merge it then? Thanks! 🙇

@The-Compiler
Copy link
Member

Does this really work? I don't see a change in output when I set PYTEST_THEME, and the TerminalFormatter we use doesn't seem to have a style option at all.

@nicoddemus
Copy link
Member

@azmeuk did you test this yourself? Can you post some screenshots please?

@azmeuk
Copy link
Member Author

azmeuk commented Jun 14, 2021

For some reasons, just changing the theme but keeping the default dark mode, does not change anything. Here are two screenshots:

before

without

after

env PYTEST_THEME=solarized-dark PYTEST_THEME_MODE=light pytest path/to/test.py

with

@azmeuk
Copy link
Member Author

azmeuk commented Jun 14, 2021

Does this really work? I don't see a change in output when I set PYTEST_THEME, and the TerminalFormatter we use doesn't seem to have a style option at all.

I think you are right, I did not tested with other pygments themes. This piece of documentation indeed tells that TerminalFormatter does not use the style parameter. I will checks this out.

@RonnyPfannschmidt
Copy link
Member

https://github.com/pygments/pygments/blob/faf69c028f0efa7798a938163e8432d838acfda2/pygments/formatters/terminal256.py#L100 will use the color style,

https://github.com/pygments/pygments/blob/faf69c028f0efa7798a938163e8432d838acfda2/pygments/formatters/terminal.py#L25-L58 will use a color scheme argument

i believe its very safe to usually pick the 256 formatter, lets figure how to correctly pick

@RonnyPfannschmidt
Copy link
Member

pygments itself does a explicit choice - https://github.com/pygments/pygments/blob/faf69c028f0efa7798a938163e8432d838acfda2/pygments/cmdline.py#L390-L395

i wonder if the color sceme can be worked into the details

@azmeuk
Copy link
Member Author

azmeuk commented Jun 14, 2021

i wonder if the color sceme can be worked into the details

What do you mean? Use the same trick as pygments to guess if a TerminalFormatter or a Terminal256Formatter should be used?

@RonnyPfannschmidt
Copy link
Member

@azmeuk no, i meant trying to figure of color schemes could be sensibly mapped to the low color terminal (or alternatively at least having color scemes for the visually imparied

@azmeuk
Copy link
Member Author

azmeuk commented Jun 14, 2021

Now rereading my PR I guess it does not really have sense anymore unless we indeed use Terminal256Formatter instead of TerminalFormatter. Is it ok for you if I do the move?

@RonnyPfannschmidt
Copy link
Member

i'm going to be happy with formatter change

i believe for full compat we should do the same check pygments does (and print a warning if a color style is passed but not supported due to lack of 256 color terminals)

a followup then could be to provide a color sceme for the color-bind either by pygments directly or by addding one and upstreaming later

@The-Compiler
Copy link
Member

We're not really in "easy and unintrusive" terrain at that point anymore, IMHO... Even pygmentize gets this wrong, checking if 256 is in $TERM is by no means sufficient to check if the terminal supports 256 colors.

Case in point, here's the pygments default output with my terminal and TerminalFormatter:

image

and here when it switches to 256 color mode:

image

So this would really make things less readable (and uniform) for many setups, rather than more so.

FWIW I still think the right solution to this is the user configuring the colors in their terminal (and sticking with the current 16-color formatter), rather than adding 256-color support just so that we can use pygment themes. Right now, the output looks like other colorized output (say, ls and such) in a terminal, while with hand-picked/hardcoded color themes, there's a much bigger chance for conflicts with how the rest of the terminal output looks.

@azmeuk
Copy link
Member Author

azmeuk commented Jun 14, 2021

I have a custom set of terminal colors (solarized), every terminal utility displays well except pytest.
I think we could meet in the middle:

  • If PYTEST_THEME is defined, use Terminal256Color or TerminalTrueColorFormatter, with the passed theme,
  • Else, by default, keep to TerminalFormatter.

What do you think @The-Compiler?

@The-Compiler
Copy link
Member

I guess that'd work indeed!

@azmeuk
Copy link
Member Author

azmeuk commented Jun 14, 2021

Ok here it is.
Here are some tests with the solarized, emacs, and tango themes.

solarized-dark
emacs
tango

Copy link
Member

@hugovk hugovk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a little typo.

@azmeuk
Copy link
Member Author

azmeuk commented Jun 15, 2021

@RonnyPfannschmidt @hugovk Thank you for your feedbacks, they are fixed.

@azmeuk
Copy link
Member Author

azmeuk commented Jun 17, 2021

@The-Compiler Is this PR acceptable to you now?

Copy link
Member

@The-Compiler The-Compiler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update! Seems fine now, other than the linting issues. I added a couple of comments for the mypy ones.

@azmeuk
Copy link
Member Author

azmeuk commented Jun 17, 2021

@The-Compiler Here it is!

@azmeuk
Copy link
Member Author

azmeuk commented Jun 20, 2021

@The-Compiler Ping! Would you consider approving this PR now?

@The-Compiler
Copy link
Member

The-Compiler commented Jun 20, 2021

While test failures are unrelated, the linters in the CI are still failing.

@azmeuk
Copy link
Member Author

azmeuk commented Jun 20, 2021

Ok. This should be fixed now.

Copy link
Member

@The-Compiler The-Compiler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good now, but I'm still confused about the test failures. I thought they were only something unrelated being flaky, but I can see them consistently happen in your branch, but apparently not on the main branch. However, I'm unable to reproduce locally... anyone has an idea what's going on there?

@azmeuk
Copy link
Member Author

azmeuk commented Jun 20, 2021

I rebased against the main branch, just in case.

@azmeuk
Copy link
Member Author

azmeuk commented Jun 21, 2021

Different tests are failing each time, but the common thing is

pytest.PytestUnraisableExceptionWarning: Exception ignored in: <_io.FileIO [closed]>
...
ResourceWarning: unclosed file <_io.TextIOWrapper name='/dev/null' mode='w' encoding='UTF-8'>

Not sure where it comes from.

@The-Compiler
Copy link
Member

I've been trying to reproduce with Python 3.9 in a Ubuntu 20.04 Docker container, but still no luck, unfortunately... Maybe someone else has an idea what could be going on.

@azmeuk
Copy link
Member Author

azmeuk commented Jul 1, 2021

@nicoddemus @RonnyPfannschmidt do you maybe have any clue?

@azmeuk
Copy link
Member Author

azmeuk commented Jul 25, 2021

I just tried -but failed- to reproduce the errors with act.

@nicoddemus
Copy link
Member

@nicoddemus @RonnyPfannschmidt do you maybe have any clue?

Sorry no clue :(

Have you tried rebasing on the latest main?

@azmeuk
Copy link
Member Author

azmeuk commented Aug 13, 2021

Have you tried rebasing on the latest main?

Yep.

I found that the errors are raised randomly on different other tests due to test_code_highlight_invalid_theme. I suppose trying to access a non existing theme in pygments has side effects that make some other tests fail, depending on the order the are executed.

Here I am looking for unclosed file descriptors and warnings...

@nicoddemus
Copy link
Member

I found that the errors are raised randomly on different other tests due to test_code_highlight_invalid_theme. I suppose trying to access a non existing theme in pygments has side effects that make some other tests fail, depending on the order the are executed.

If this is happening in a few tests, we can use pytester.runpytest_subprocess(), which will ensure no state will leak.

@azmeuk
Copy link
Member Author

azmeuk commented Aug 13, 2021

If this is happening in a few tests, we can use pytester.runpytest_subprocess(), which will ensure no state will leak.

❤️ ❤️ ❤️

Tests are green now, this patch should be mergeable!

@nicoddemus
Copy link
Member

Woot! Thanks for the patience and following through with the PR! ❤️

@azmeuk
Copy link
Member Author

azmeuk commented Aug 15, 2021

@nicoddemus @RonnyPfannschmidt @The-Compiler anyone interested in pressing the merge button?

@nicoddemus nicoddemus merged commit 0f79fc6 into pytest-dev:main Aug 15, 2021
@nicoddemus
Copy link
Member

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ability to choose syntax highlighting style by configuration
5 participants