From 155062d6008b5316b625cc011bd7f9b10bc6a267 Mon Sep 17 00:00:00 2001 From: J Rob Gant Date: Fri, 6 Feb 2026 12:21:10 -0500 Subject: [PATCH 1/3] [stdlib] Allow FileHandler.stream to be None FileHandler sets self.stream = None in two CPython code paths: delay=True in __init__ and after close(). Override the inherited StreamHandler.stream type to reflect this. --- stdlib/@tests/test_cases/check_logging.py | 7 +++++++ stdlib/logging/__init__.pyi | 1 + 2 files changed, 8 insertions(+) diff --git a/stdlib/@tests/test_cases/check_logging.py b/stdlib/@tests/test_cases/check_logging.py index fe3d8eb16fd0..bf29276b4c58 100644 --- a/stdlib/@tests/test_cases/check_logging.py +++ b/stdlib/@tests/test_cases/check_logging.py @@ -1,11 +1,14 @@ from __future__ import annotations +import io import logging import logging.handlers import multiprocessing import queue from typing import Any +from typing_extensions import assert_type + # This pattern comes from the logging docs, and should therefore pass a type checker # See https://docs.python.org/3/library/logging.html#logrecord-objects @@ -28,3 +31,7 @@ def record_factory(*args: Any, **kwargs: Any) -> logging.LogRecord: logging.handlers.QueueListener(queue.Queue()) logging.handlers.QueueListener(queue.SimpleQueue()) logging.handlers.QueueListener(multiprocessing.Queue()) + +# FileHandler.stream can be None when delay=True or after close() +fh = logging.FileHandler("test.log", delay=True) +assert_type(fh.stream, io.TextIOWrapper | None) diff --git a/stdlib/logging/__init__.pyi b/stdlib/logging/__init__.pyi index 8248f82ea87a..3a79e3a65d19 100644 --- a/stdlib/logging/__init__.pyi +++ b/stdlib/logging/__init__.pyi @@ -616,6 +616,7 @@ class FileHandler(StreamHandler[TextIOWrapper]): encoding: str | None # undocumented delay: bool # undocumented errors: str | None # undocumented + stream: TextIOWrapper | None # type: ignore[assignment] # None when delay=True or after close() def __init__( self, filename: StrPath, mode: str = "a", encoding: str | None = None, delay: bool = False, errors: str | None = None ) -> None: ... From fe0fb9826ff3418ec2bbcddb8a743f6bbe6efe03 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:28:12 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/@tests/test_cases/check_logging.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/@tests/test_cases/check_logging.py b/stdlib/@tests/test_cases/check_logging.py index bf29276b4c58..cb3b1fb5ae70 100644 --- a/stdlib/@tests/test_cases/check_logging.py +++ b/stdlib/@tests/test_cases/check_logging.py @@ -6,7 +6,6 @@ import multiprocessing import queue from typing import Any - from typing_extensions import assert_type # This pattern comes from the logging docs, and should therefore pass a type checker From a701f7f22b4b99be6caa2bea3e2f5515eb55c2c1 Mon Sep 17 00:00:00 2001 From: J Rob Gant Date: Fri, 6 Feb 2026 12:41:06 -0500 Subject: [PATCH 3/3] [stdlib] Use Union syntax for Python 3.9 compatibility in test --- stdlib/@tests/test_cases/check_logging.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/@tests/test_cases/check_logging.py b/stdlib/@tests/test_cases/check_logging.py index cb3b1fb5ae70..5e39b066fd68 100644 --- a/stdlib/@tests/test_cases/check_logging.py +++ b/stdlib/@tests/test_cases/check_logging.py @@ -5,7 +5,7 @@ import logging.handlers import multiprocessing import queue -from typing import Any +from typing import Any, Union from typing_extensions import assert_type # This pattern comes from the logging docs, and should therefore pass a type checker @@ -33,4 +33,4 @@ def record_factory(*args: Any, **kwargs: Any) -> logging.LogRecord: # FileHandler.stream can be None when delay=True or after close() fh = logging.FileHandler("test.log", delay=True) -assert_type(fh.stream, io.TextIOWrapper | None) +assert_type(fh.stream, Union[io.TextIOWrapper, None])