Skip to content

Commit 7154672

Browse files
authored
Replace colorize() with functions from _cli.util.colour (sphinx-doc#13259)
1 parent df962a4 commit 7154672

File tree

3 files changed

+71
-49
lines changed

3 files changed

+71
-49
lines changed

sphinx/_cli/util/colour.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,31 @@
22

33
from __future__ import annotations
44

5-
import os
65
import sys
7-
from collections.abc import Callable # NoQA: TC003
6+
from os import environ as _environ
7+
8+
if False:
9+
from collections.abc import Callable
810

911
if sys.platform == 'win32':
1012
import colorama
1113

14+
colorama.just_fix_windows_console()
15+
del colorama
16+
1217

1318
_COLOURING_DISABLED = False
1419

1520

1621
def terminal_supports_colour() -> bool:
1722
"""Return True if coloured terminal output is supported."""
18-
if 'NO_COLOUR' in os.environ or 'NO_COLOR' in os.environ:
23+
if 'NO_COLOUR' in _environ or 'NO_COLOR' in _environ:
1924
return False
2025
if sys.platform == 'win32':
21-
colorama.just_fix_windows_console()
2226
return True
23-
if 'FORCE_COLOUR' in os.environ or 'FORCE_COLOR' in os.environ:
27+
if 'FORCE_COLOUR' in _environ or 'FORCE_COLOR' in _environ:
2428
return True
25-
if os.environ.get('CI', '') in {'true', '1'}:
29+
if _environ.get('CI', '').lower() in {'true', '1'}:
2630
return True
2731

2832
try:
@@ -34,7 +38,7 @@ def terminal_supports_colour() -> bool:
3438
return False
3539

3640
# Do not colour output if on a dumb terminal
37-
return os.environ.get('TERM', 'unknown').lower() not in {'dumb', 'unknown'}
41+
return _environ.get('TERM', 'unknown').lower() not in {'dumb', 'unknown'}
3842

3943

4044
def disable_colour() -> None:
@@ -50,7 +54,21 @@ def enable_colour() -> None:
5054
def colourise(colour_name: str, text: str, /) -> str:
5155
if _COLOURING_DISABLED:
5256
return text
53-
return globals()[colour_name](text)
57+
if colour_name.startswith('_') or colour_name in {
58+
'annotations',
59+
'sys',
60+
'terminal_supports_colour',
61+
'disable_colour',
62+
'enable_colour',
63+
'colourise',
64+
}:
65+
msg = f'Invalid colour name: {colour_name!r}'
66+
raise ValueError(msg)
67+
try:
68+
return globals()[colour_name](text)
69+
except KeyError:
70+
msg = f'Invalid colour name: {colour_name!r}'
71+
raise ValueError(msg) from None
5472

5573

5674
def _create_colour_func(escape_code: str, /) -> Callable[[str], str]:

sphinx/cmd/quickstart.py

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,44 @@
1010
import time
1111
from typing import TYPE_CHECKING
1212

13-
# try to import readline, unix specific enhancement
14-
try:
15-
import readline
16-
17-
if TYPE_CHECKING and sys.platform == 'win32': # always false, for type checking
18-
raise ImportError # NoQA: TRY301
19-
READLINE_AVAILABLE = True
20-
if readline.__doc__ and 'libedit' in readline.__doc__:
21-
readline.parse_and_bind('bind ^I rl_complete')
22-
USE_LIBEDIT = True
23-
else:
24-
readline.parse_and_bind('tab: complete')
25-
USE_LIBEDIT = False
26-
except ImportError:
27-
READLINE_AVAILABLE = False
28-
USE_LIBEDIT = False
29-
3013
from docutils.utils import column_width
3114

3215
import sphinx.locale
3316
from sphinx import __display_version__, package_dir
3417
from sphinx._cli.util.colour import (
18+
_create_input_mode_colour_func,
3519
bold,
3620
disable_colour,
3721
red,
3822
terminal_supports_colour,
3923
)
4024
from sphinx.locale import __
41-
from sphinx.util.console import colorize
4225
from sphinx.util.osutil import ensuredir
4326
from sphinx.util.template import SphinxRenderer
4427

4528
if TYPE_CHECKING:
4629
from collections.abc import Callable, Sequence
4730
from typing import Any
4831

32+
# try to import readline, unix specific enhancement
33+
try:
34+
import readline
35+
36+
if TYPE_CHECKING and sys.platform == 'win32':
37+
# MyPy doesn't realise that this raises a ModuleNotFoundError
38+
# on Windows, and complains that 'parse_and_bind' is not defined.
39+
# This condition is always False at runtime, but tricks type checkers.
40+
raise ImportError # NoQA: TRY301
41+
except ImportError:
42+
READLINE_AVAILABLE = USE_LIBEDIT = False
43+
else:
44+
READLINE_AVAILABLE = True
45+
USE_LIBEDIT = 'libedit' in getattr(readline, '__doc__', '')
46+
if USE_LIBEDIT:
47+
readline.parse_and_bind('bind ^I rl_complete')
48+
else:
49+
readline.parse_and_bind('tab: complete')
50+
4951
EXTENSIONS = {
5052
'autodoc': __('automatically insert docstrings from modules'),
5153
'doctest': __('automatically test code snippets in doctest blocks'),
@@ -73,10 +75,17 @@
7375
PROMPT_PREFIX = '> '
7476

7577
if sys.platform == 'win32':
76-
# On Windows, show questions as bold because of color scheme of PowerShell (refs: #5294).
77-
COLOR_QUESTION = 'bold'
78+
# On Windows, show questions as bold because of PowerShell's colour scheme
79+
# (xref: https://github.com/sphinx-doc/sphinx/issues/5294).
80+
from sphinx._cli.util.colour import bold as _question_colour
7881
else:
79-
COLOR_QUESTION = 'purple'
82+
from sphinx._cli.util.colour import purple as _question_colour
83+
84+
if READLINE_AVAILABLE:
85+
# Use an input-mode colour function if readline is available
86+
if escape_code := getattr(_question_colour, '__escape_code', ''):
87+
_question_colour = _create_input_mode_colour_func(escape_code)
88+
del escape_code
8089

8190

8291
# function to get input from terminal -- overridden by the test suite
@@ -158,11 +167,8 @@ def do_prompt(
158167
# sequence (see #5335). To avoid the problem, all prompts are not colored
159168
# on libedit.
160169
pass
161-
elif READLINE_AVAILABLE:
162-
# pass input_mode=True if readline available
163-
prompt = colorize(COLOR_QUESTION, prompt, input_mode=True)
164170
else:
165-
prompt = colorize(COLOR_QUESTION, prompt, input_mode=False)
171+
prompt = _question_colour(prompt)
166172
x = term_input(prompt).strip()
167173
if default and not x:
168174
x = default

sphinx/util/logging.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
from docutils import nodes
1313
from docutils.utils import get_source_line
1414

15+
from sphinx._cli.util.colour import colourise
1516
from sphinx.errors import SphinxWarning
16-
from sphinx.util.console import colorize
1717

1818
if TYPE_CHECKING:
1919
from collections.abc import Iterator, Sequence, Set
@@ -49,14 +49,11 @@
4949
},
5050
)
5151

52-
COLOR_MAP: defaultdict[int, str] = defaultdict(
53-
lambda: 'blue',
54-
{
55-
logging.ERROR: 'darkred',
56-
logging.WARNING: 'red',
57-
logging.DEBUG: 'darkgray',
58-
},
59-
)
52+
COLOR_MAP: dict[int, str] = {
53+
logging.ERROR: 'darkred',
54+
logging.WARNING: 'red',
55+
logging.DEBUG: 'darkgray',
56+
}
6057

6158

6259
def getLogger(name: str) -> SphinxLoggerAdapter:
@@ -566,13 +563,14 @@ def get_node_location(node: Node) -> str | None:
566563
class ColorizeFormatter(logging.Formatter):
567564
def format(self, record: logging.LogRecord) -> str:
568565
message = super().format(record)
569-
color = getattr(record, 'color', None)
570-
if color is None:
571-
color = COLOR_MAP.get(record.levelno)
572-
573-
if color:
574-
return colorize(color, message)
575-
else:
566+
colour_name = getattr(record, 'color', '')
567+
if not colour_name:
568+
colour_name = COLOR_MAP.get(record.levelno, '')
569+
if not colour_name:
570+
return message
571+
try:
572+
return colourise(colour_name, message)
573+
except ValueError:
576574
return message
577575

578576

0 commit comments

Comments
 (0)