Skip to content

Commit bf3f60c

Browse files
authored
Replace click.style with an internal ANSI style helper (#2981)
1 parent eea1bcc commit bf3f60c

6 files changed

Lines changed: 57 additions & 32 deletions

File tree

uvicorn/_ansi.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from __future__ import annotations
2+
3+
_ANSI_COLORS = {
4+
"black": 30,
5+
"red": 31,
6+
"green": 32,
7+
"yellow": 33,
8+
"blue": 34,
9+
"magenta": 35,
10+
"cyan": 36,
11+
"white": 37,
12+
"bright_black": 90,
13+
"bright_red": 91,
14+
"bright_green": 92,
15+
"bright_yellow": 93,
16+
"bright_blue": 94,
17+
"bright_magenta": 95,
18+
"bright_cyan": 96,
19+
"bright_white": 97,
20+
}
21+
22+
23+
def style(text: str, fg: str | None = None, bold: bool = False) -> str:
24+
prefix = ""
25+
if fg is not None:
26+
prefix += f"\033[{_ANSI_COLORS[fg]}m"
27+
if bold:
28+
prefix += "\033[1m"
29+
return f"{prefix}{text}\033[0m"

uvicorn/config.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
from pathlib import Path
1515
from typing import IO, Any, Literal
1616

17-
import click
18-
17+
from uvicorn._ansi import style
1918
from uvicorn._compat import iscoroutinefunction
2019
from uvicorn._types import ASGIApplication
2120
from uvicorn.importer import ImportFromStringError, import_from_string
@@ -550,13 +549,13 @@ def bind_socket(self) -> socket.socket:
550549

551550
message = "Uvicorn running on unix socket %s (Press CTRL+C to quit)"
552551
sock_name_format = "%s"
553-
color_message = "Uvicorn running on " + click.style(sock_name_format, bold=True) + " (Press CTRL+C to quit)"
552+
color_message = "Uvicorn running on " + style(sock_name_format, bold=True) + " (Press CTRL+C to quit)"
554553
logger_args = [self.uds]
555554
elif self.fd is not None: # pragma: py-win32
556555
sock = socket.fromfd(self.fd, socket.AF_UNIX, socket.SOCK_STREAM)
557556
message = "Uvicorn running on socket %s (Press CTRL+C to quit)"
558557
fd_name_format = "%s"
559-
color_message = "Uvicorn running on " + click.style(fd_name_format, bold=True) + " (Press CTRL+C to quit)"
558+
color_message = "Uvicorn running on " + style(fd_name_format, bold=True) + " (Press CTRL+C to quit)"
560559
logger_args = [sock.getsockname()]
561560
else:
562561
family = socket.AF_INET
@@ -576,7 +575,7 @@ def bind_socket(self) -> socket.socket:
576575
sys.exit(1)
577576

578577
message = f"Uvicorn running on {addr_format} (Press CTRL+C to quit)"
579-
color_message = "Uvicorn running on " + click.style(addr_format, bold=True) + " (Press CTRL+C to quit)"
578+
color_message = "Uvicorn running on " + style(addr_format, bold=True) + " (Press CTRL+C to quit)"
580579
protocol_name = "https" if self.is_ssl else "http"
581580
logger_args = [protocol_name, self.host, sock.getsockname()[1]]
582581
logger.info(message, *logger_args, extra={"color_message": color_message})

uvicorn/logging.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from copy import copy
77
from typing import Literal
88

9-
import click
9+
from uvicorn._ansi import style as ansi_style
1010

1111
TRACE_LOG_LEVEL = 5
1212

@@ -21,12 +21,12 @@ class ColourizedFormatter(logging.Formatter):
2121
"""
2222

2323
level_name_colors = {
24-
TRACE_LOG_LEVEL: lambda level_name: click.style(str(level_name), fg="blue"),
25-
logging.DEBUG: lambda level_name: click.style(str(level_name), fg="cyan"),
26-
logging.INFO: lambda level_name: click.style(str(level_name), fg="green"),
27-
logging.WARNING: lambda level_name: click.style(str(level_name), fg="yellow"),
28-
logging.ERROR: lambda level_name: click.style(str(level_name), fg="red"),
29-
logging.CRITICAL: lambda level_name: click.style(str(level_name), fg="bright_red"),
24+
TRACE_LOG_LEVEL: lambda level_name: ansi_style(str(level_name), fg="blue"),
25+
logging.DEBUG: lambda level_name: ansi_style(str(level_name), fg="cyan"),
26+
logging.INFO: lambda level_name: ansi_style(str(level_name), fg="green"),
27+
logging.WARNING: lambda level_name: ansi_style(str(level_name), fg="yellow"),
28+
logging.ERROR: lambda level_name: ansi_style(str(level_name), fg="red"),
29+
logging.CRITICAL: lambda level_name: ansi_style(str(level_name), fg="bright_red"),
3030
}
3131

3232
def __init__(
@@ -72,11 +72,11 @@ def should_use_colors(self) -> bool:
7272

7373
class AccessFormatter(ColourizedFormatter):
7474
status_code_colours = {
75-
1: lambda code: click.style(str(code), fg="bright_white"),
76-
2: lambda code: click.style(str(code), fg="green"),
77-
3: lambda code: click.style(str(code), fg="yellow"),
78-
4: lambda code: click.style(str(code), fg="red"),
79-
5: lambda code: click.style(str(code), fg="bright_red"),
75+
1: lambda code: ansi_style(str(code), fg="bright_white"),
76+
2: lambda code: ansi_style(str(code), fg="green"),
77+
3: lambda code: ansi_style(str(code), fg="yellow"),
78+
4: lambda code: ansi_style(str(code), fg="red"),
79+
5: lambda code: ansi_style(str(code), fg="bright_red"),
8080
}
8181

8282
def get_status_code(self, status_code: int) -> str:
@@ -106,7 +106,7 @@ def formatMessage(self, record: logging.LogRecord) -> str:
106106
status_code = self.get_status_code(int(status_code)) # type: ignore[arg-type]
107107
request_line = f"{method} {full_path} HTTP/{http_version}"
108108
if self.use_colors:
109-
request_line = click.style(request_line, bold=True)
109+
request_line = ansi_style(request_line, bold=True)
110110
recordcopy.__dict__.update(
111111
{
112112
"client_addr": client_addr,

uvicorn/server.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
from types import FrameType
1818
from typing import TYPE_CHECKING, TypeAlias
1919

20-
import click
21-
20+
from uvicorn._ansi import style
2221
from uvicorn._compat import asyncio_run
2322
from uvicorn.config import Config
2423

@@ -88,7 +87,7 @@ async def _serve(self, sockets: list[socket.socket] | None = None) -> None:
8887
self.lifespan = config.lifespan_class(config)
8988

9089
message = "Started server process [%d]"
91-
color_message = "Started server process [" + click.style("%d", fg="cyan") + "]"
90+
color_message = "Started server process [" + style("%d", fg="cyan") + "]"
9291
logger.info(message, process_id, extra={"color_message": color_message})
9392

9493
await self.startup(sockets=sockets)
@@ -98,7 +97,7 @@ async def _serve(self, sockets: list[socket.socket] | None = None) -> None:
9897
await self.shutdown(sockets=sockets)
9998

10099
message = "Finished server process [%d]"
101-
color_message = "Finished server process [" + click.style("%d", fg="cyan") + "]"
100+
color_message = "Finished server process [" + style("%d", fg="cyan") + "]"
102101
logger.info(message, process_id, extra={"color_message": color_message})
103102

104103
async def startup(self, sockets: list[socket.socket] | None = None) -> None:
@@ -220,7 +219,7 @@ def _log_started_message(self, listeners: Sequence[socket.SocketType]) -> None:
220219

221220
protocol_name = "https" if config.ssl else "http"
222221
message = f"Uvicorn running on {addr_format} (Press CTRL+C to quit)"
223-
color_message = "Uvicorn running on " + click.style(addr_format, bold=True) + " (Press CTRL+C to quit)"
222+
color_message = "Uvicorn running on " + style(addr_format, bold=True) + " (Press CTRL+C to quit)"
224223
logger.info(
225224
message,
226225
protocol_name,

uvicorn/supervisors/basereload.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
from socket import socket
1111
from types import FrameType
1212

13-
import click
14-
13+
from uvicorn._ansi import style
1514
from uvicorn._subprocess import get_subprocess
1615
from uvicorn.config import Config
1716

@@ -73,8 +72,8 @@ def __next__(self) -> list[Path] | None:
7372
def startup(self) -> None:
7473
message = f"Started reloader process [{self.pid}] using {self.reloader_name}"
7574
color_message = "Started reloader process [{}] using {}".format(
76-
click.style(str(self.pid), fg="cyan", bold=True),
77-
click.style(str(self.reloader_name), fg="cyan", bold=True),
75+
style(str(self.pid), fg="cyan", bold=True),
76+
style(str(self.reloader_name), fg="cyan", bold=True),
7877
)
7978
logger.info(message, extra={"color_message": color_message})
8079

@@ -111,7 +110,7 @@ def shutdown(self) -> None:
111110
sock.close()
112111

113112
message = f"Stopping reloader process [{str(self.pid)}]"
114-
color_message = "Stopping reloader process [{}]".format(click.style(str(self.pid), fg="cyan", bold=True))
113+
color_message = "Stopping reloader process [{}]".format(style(str(self.pid), fg="cyan", bold=True))
115114
logger.info(message, extra={"color_message": color_message})
116115

117116
def should_restart(self) -> list[Path] | None:

uvicorn/supervisors/multiprocess.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
from socket import socket
1010
from typing import Any
1111

12-
import click
13-
12+
from uvicorn._ansi import style
1413
from uvicorn._subprocess import get_subprocess
1514
from uvicorn.config import Config
1615

@@ -144,7 +143,7 @@ def restart_all(self) -> None:
144143

145144
def run(self) -> None:
146145
message = f"Started parent process [{os.getpid()}]"
147-
color_message = "Started parent process [{}]".format(click.style(str(os.getpid()), fg="cyan", bold=True))
146+
color_message = "Started parent process [{}]".format(style(str(os.getpid()), fg="cyan", bold=True))
148147
logger.info(message, extra={"color_message": color_message})
149148

150149
self.init_processes()
@@ -157,7 +156,7 @@ def run(self) -> None:
157156
self.join_all()
158157

159158
message = f"Stopping parent process [{os.getpid()}]"
160-
color_message = "Stopping parent process [{}]".format(click.style(str(os.getpid()), fg="cyan", bold=True))
159+
color_message = "Stopping parent process [{}]".format(style(str(os.getpid()), fg="cyan", bold=True))
161160
logger.info(message, extra={"color_message": color_message})
162161

163162
def keep_subprocess_alive(self) -> None:

0 commit comments

Comments
 (0)