Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-146292: Add colour tohttp.server logs#146293

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
hugovk wants to merge6 commits intopython:main
base:main
Choose a base branch
Loading
fromhugovk:3.15-colour-http.server
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion.pre-commit-config.yaml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
repos:
-repo:https://github.com/astral-sh/ruff-pre-commit
rev:a27a2e47c7751b639d2b5badf0ef6ff11fee893f# frozen: v0.15.4
rev:e05c5c0818279e5ac248ac9e954431ba58865e61# frozen: v0.15.7
hooks:
-id:ruff-check
name:Run Ruff (lint) on Apple/
Expand Down
11 changes: 11 additions & 0 deletionsDoc/whatsnew/3.15.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -795,6 +795,17 @@ http.cookies
(Contributed by Nick Burns and Senthil Kumaran in :gh:`92936`.)


http.server
-----------

* The logging of :mod:`~http.server.BaseHTTPRequestHandler`,
as used by the :ref:`command-line interface <http-server-cli>`,
is colored by default.
This can be controlled with :ref:`environment variables
<using-on-controlling-color>`.
(Contributed by Hugo van Kemenade in :gh:`146292`.)


inspect
-------

Expand Down
20 changes: 20 additions & 0 deletionsLib/_colorize.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -200,6 +200,22 @@ class Difflib(ThemeSection):
reset: str = ANSIColors.RESET


@dataclass(frozen=True, kw_only=True)
class HttpServer(ThemeSection):
error: str = ANSIColors.YELLOW
path: str = ANSIColors.CYAN
serving: str = ANSIColors.GREEN
size: str = ANSIColors.GREY
status_informational: str = ANSIColors.RESET
status_ok: str = ANSIColors.GREEN
status_redirect: str = ANSIColors.INTENSE_CYAN
status_client_error: str = ANSIColors.YELLOW
status_server_error: str = ANSIColors.RED
timestamp: str = ANSIColors.GREY
url: str = ANSIColors.CYAN
reset: str = ANSIColors.RESET


@dataclass(frozen=True, kw_only=True)
class LiveProfiler(ThemeSection):
"""Theme section for the live profiling TUI (Tachyon profiler).
Expand DownExpand Up@@ -354,6 +370,7 @@ class Theme:
"""
argparse: Argparse = field(default_factory=Argparse)
difflib: Difflib = field(default_factory=Difflib)
http_server: HttpServer = field(default_factory=HttpServer)
live_profiler: LiveProfiler = field(default_factory=LiveProfiler)
syntax: Syntax = field(default_factory=Syntax)
traceback: Traceback = field(default_factory=Traceback)
Expand All@@ -364,6 +381,7 @@ def copy_with(
*,
argparse: Argparse | None = None,
difflib: Difflib | None = None,
http_server: HttpServer | None = None,
live_profiler: LiveProfiler | None = None,
syntax: Syntax | None = None,
traceback: Traceback | None = None,
Expand All@@ -377,6 +395,7 @@ def copy_with(
return type(self)(
argparse=argparse or self.argparse,
difflib=difflib or self.difflib,
http_server=http_server or self.http_server,
live_profiler=live_profiler or self.live_profiler,
syntax=syntax or self.syntax,
traceback=traceback or self.traceback,
Expand All@@ -394,6 +413,7 @@ def no_colors(cls) -> Self:
return cls(
argparse=Argparse.no_colors(),
difflib=Difflib.no_colors(),
http_server=HttpServer.no_colors(),
live_profiler=LiveProfiler.no_colors(),
syntax=Syntax.no_colors(),
traceback=Traceback.no_colors(),
Expand Down
58 changes: 49 additions & 9 deletionsLib/http/server.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -85,6 +85,8 @@

from http import HTTPStatus

lazy import _colorize


# Default error message template
DEFAULT_ERROR_MESSAGE = """\
Expand DownExpand Up@@ -574,6 +576,31 @@ def flush_headers(self):
self.wfile.write(b"".join(self._headers_buffer))
self._headers_buffer = []

def _colorize_request(self, code, size, t):
try:
code_int = int(code)
except (TypeError, ValueError):
code_color = ""
else:
if code_int >= 500:
code_color = t.status_server_error
elif code_int >= 400:
code_color = t.status_client_error
elif code_int >= 300:
code_color = t.status_redirect
elif code_int >= 200:
code_color = t.status_ok
else:
code_color = t.status_informational

request_line = self.requestline.translate(self._control_char_table)
parts = request_line.split(None, 2)
if len(parts) == 3:
method, path, version = parts
request_line = f"{method} {t.path}{path}{t.reset} {version}"

return f'"{request_line}" {code_color}{code} {t.size}{size}{t.reset}'

def log_request(self, code='-', size='-'):
"""Log an accepted request.

Expand All@@ -582,6 +609,7 @@ def log_request(self, code='-', size='-'):
"""
if isinstance(code, HTTPStatus):
code = code.value
self._log_request_info = (code, size)
self.log_message('"%s" %s %s',
self.requestline, str(code), str(size))

Expand All@@ -596,7 +624,7 @@ def log_error(self, format, *args):
XXX This should go to the separate error log.

"""

self._log_is_error = True
self.log_message(format, *args)

# https://en.wikipedia.org/wiki/List_of_Unicode_characters#Control_codes
Expand All@@ -623,12 +651,22 @@ def log_message(self, format, *args):
before writing the output to stderr.

"""

message = format % args
sys.stderr.write("%s - - [%s] %s\n" %
(self.address_string(),
self.log_date_time_string(),
message.translate(self._control_char_table)))
message = (format % args).translate(self._control_char_table)
t = _colorize.get_theme(tty_file=sys.stderr).http_server

info = getattr(self, "_log_request_info", None)
if info is not None:
self._log_request_info = None
message = self._colorize_request(*info, t)
elif getattr(self, "_log_is_error", False):
self._log_is_error = False
message = f"{t.error}{message}{t.reset}"

sys.stderr.write(
f"{t.timestamp}{self.address_string()} - - "
f"[{self.log_date_time_string()}]{t.reset} "
f"{message}\n"
)

def version_string(self):
"""Return the server software version string."""
Expand DownExpand Up@@ -994,9 +1032,11 @@ def test(HandlerClass=BaseHTTPRequestHandler,
host, port = httpd.socket.getsockname()[:2]
url_host = f'[{host}]' if ':' in host else host
protocol = 'HTTPS' if tls_cert else 'HTTP'
t = _colorize.get_theme().http_server
url = f"{protocol.lower()}://{url_host}:{port}/"
print(
f"Serving {protocol} on {host} port {port} "
f"({protocol.lower()}://{url_host}:{port}/) ..."
f"{t.serving}Serving {protocol} on {host} port {port}{t.reset} "
f"({t.url}{url}{t.reset}) ..."
)
try:
httpd.serve_forever()
Expand Down
2 changes: 1 addition & 1 deletionLib/test/.ruff.toml
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
extend = "../../.ruff.toml" # Inherit the project-wide settings

# Unlike Tools/, tests can use newer syntax than PYTHON_FOR_REGEN
target-version = "py314"
target-version = "py315"

extend-exclude = [
# Excluded (run with the other AC files in its own separate ruff job in pre-commit)
Expand Down
38 changes: 38 additions & 0 deletionsLib/test/test_httpservers.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,10 +28,12 @@
import threading
from unittest import mock
from io import BytesIO, StringIO
from _colorize import get_theme

import unittest
from test import support
from test.support import (
force_not_colorized,
is_apple, import_helper, os_helper, threading_helper
)
from test.support.script_helper import kill_python, spawn_python
Expand DownExpand Up@@ -480,6 +482,7 @@ def do_GET(self):
def do_ERROR(self):
self.send_error(HTTPStatus.NOT_FOUND, 'File not found')

@force_not_colorized
def test_get(self):
self.con = http.client.HTTPConnection(self.HOST, self.PORT)
self.con.connect()
Expand All@@ -490,6 +493,7 @@ def test_get(self):

self.assertEndsWith(err.getvalue(), '"GET / HTTP/1.1" 200 -\n')

@force_not_colorized
def test_err(self):
self.con = http.client.HTTPConnection(self.HOST, self.PORT)
self.con.connect()
Expand All@@ -503,6 +507,39 @@ def test_err(self):
self.assertEndsWith(lines[1], '"ERROR / HTTP/1.1" 404 -')


@support.force_colorized_test_class
class RequestHandlerColorizedLoggingTestCase(RequestHandlerLoggingTestCase):

def test_get(self):
t = get_theme(force_color=True).http_server
self.con = http.client.HTTPConnection(self.HOST, self.PORT)
self.con.connect()

with support.captured_stderr() as err:
self.con.request("GET", "/")
self.con.getresponse()

output = err.getvalue()
self.assertIn(f"{t.path}/{t.reset}", output)
self.assertIn(f"{t.status_ok}200", output)
self.assertIn(t.reset, output)

def test_err(self):
t = get_theme(force_color=True).http_server
self.con = http.client.HTTPConnection(self.HOST, self.PORT)
self.con.connect()

with support.captured_stderr() as err:
self.con.request("ERROR", "/")
self.con.getresponse()

lines = err.getvalue().split("\n")
self.assertIn(
f"{t.error}code 404, message File not found{t.reset}", lines[0]
)
self.assertIn(f"{t.status_client_error}404", lines[1])


class SimpleHTTPServerTestCase(BaseTestCase):
class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler):
pass
Expand DownExpand Up@@ -935,6 +972,7 @@ def verify_http_server_response(self, response):
match = self.HTTPResponseMatch.search(response)
self.assertIsNotNone(match)

@force_not_colorized
def test_unprintable_not_logged(self):
# We call the method from the class directly as our Socketless
# Handler subclass overrode it... nice for everything BUT this test.
Expand Down
3 changes: 2 additions & 1 deletionLib/test/test_wsgiref.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
from unittest import mock
from test import support
from test.support import socket_helper, control_characters_c0
from test.support importforce_not_colorized,socket_helper, control_characters_c0
from test.test_httpservers import NoLogRequestHandler
from unittest import TestCase
from wsgiref.util import setup_testing_defaults
Expand DownExpand Up@@ -192,6 +192,7 @@ def bad_app(e,s):
err.splitlines()[-2], "AssertionError"
)

@force_not_colorized
def test_bytes_validation(self):
def app(e, s):
s("200 OK", [
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
Add colour to :mod:`~http.server.BaseHTTPRequestHandler` logs, as used by
the :mod:`http.server` CLI. Patch by Hugo van Kemenade.
Loading

[8]ページ先頭

©2009-2026 Movatter.jp