Skip to content
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

highlight_regex in rich.text.Text Now Expects a Compiled Regular Expression (re.compile) Has Been Passed #3347

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

PyWoody
Copy link

@PyWoody PyWoody commented Apr 27, 2024

Type of changes

  • Bug fix
  • New feature
  • Documentation / docstrings
  • Tests
  • Other

Checklist

  • I've run the latest black with default args on new code.
  • I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.
  • I've added tests for new code.
  • I accept that @willmcgugan may be pedantic in the code review.

Description

highlight_regex in rich.text.Text now expects the passed re_highlight to be a compiled regular expression. If a str is passed, as was the previous expectation, the str will be compiled as a regular expression and the method will continue on as before.

The proposed change is for a minor performance bump in the rich.highlighter.RegexHighlighter class. A user can now pass compiled regular expressions in the the list of highlights, which will be guaranteed to not re-compiled by Text. Previously, highlight_regex expected it was receiving a str so it compiled the regular expression every time.

There will be no breaking changes to the user as the user can continue to pass str in their respective RegexHighlighter.highlights. The only performance degradation will be caused by the isinstance(re_highlight, str) check, which will be minimal.

Below is a silly speed test (hopefully) showing the new highlight_regex as performing faster. I used 600 "words" for the regular expressions because Python's current re. actions use a shared internal cache of a maximum of 512[0] regular expressions and I wanted demonstrate how relying on that can cause slowdowns.

[0] https://github.com/python/cpython/blob/3.12/Lib/re/__init__.py#L277

import itertools
import re
import time

from rich.console import Console
from rich.highlighter import RegexHighlighter
from rich.theme import Theme


PHRASE = ' '.join(f'word{i}' for i in range(600))


class SillyCompiledHighlighter(RegexHighlighter):

    base_style = 'example.'
    highlights = [re.compile(rf'(?P<{i}>{i})') for i in PHRASE.split()]


class SillyStringHighlighter(RegexHighlighter):

    base_style = 'example.'
    highlights = [rf'(?P<{i}>{i})' for i in PHRASE.split()]


def run():
    colors = itertools.cycle(range(256))
    theme = Theme(
        {f'example.{v}': f'color({i})' for i, v in zip(colors, PHRASE.split())}
    )
    console = Console(
        highlighter=SillyCompiledHighlighter(), theme=theme, quiet=True
    )
    start = time.time()
    for _ in range(1_000):
        console.print(PHRASE)
    print('Compiled:', time.time() - start)
    console = Console(
        highlighter=SillyStringHighlighter(), theme=theme, quiet=True
    )
    start = time.time()
    for _ in range(1_000):
        console.print(PHRASE)
    print('String:', time.time() - start)


if __name__ == '__main__':
    run()

…t' is a compiled regular expression. If a str is passed, as was the previous assumption, the str will be compiled as a regular expression.
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.

None yet

1 participant