Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Logging capture crashes when another thread registers a logger

Đang mở Phù hợp với người mới
#15,237 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@Spikhalskiy đang làm issue này rồi.

Từ ngày 21/10/2026.

  • #15238 của @Spikhalskiy — đang mở

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
78/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
backend, testing

Hướng nghiên cứu

Traceback trỏ đến _pytest/logging.py trong catching_logs.__enter__, nơi loggerDict.values() được duyệt. Hãy đọc mã thiết lập đó cùng các bài kiểm thử liên quan đến việc bắt log, sau đó tái hiện trường hợp đăng ký đồng thời trong issue. Hoàn tất khi việc thiết lập bắt log không còn phát sinh ngoại lệ trong lúc đăng ký logger đồng thời và có bài kiểm thử bao quát lỗi hồi quy.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

  • a detailed description of the bug or problem you are having
  • output of pip list from the virtual environment you are using
  • pytest and operating system versions
  • minimal example if possible

Description

catching_logs.__enter__ can raise RuntimeError: dictionary changed size during iteration when another thread calls logging.getLogger() during capture setup.

The regression was introduced by #14375 / 7e6161c68579eb58ecceaf8c6b6f6b1b2f46c28a, which iterates the live logging.root.manager.loggerDict.values() view. logging.getLogger() mutates that dictionary while holding logging's registry lock, but pytest's iteration does not use the lock or take a snapshot.

Reproduction

import logging
import threading

from _pytest.logging import catching_logs

mutation_completed = threading.Event()
worker = None

class TriggerLogger(logging.Logger):
    @property
    def propagate(self):
        global worker

        def register_logger():
            logging.getLogger("repro.concurrent-registration")
            mutation_completed.set()

        worker = threading.Thread(target=register_logger)
        worker.start()
        assert mutation_completed.wait(timeout=1)
        return True

    @propagate.setter
    def propagate(self, value):
        pass

manager = logging.root.manager
manager.loggerDict["repro.trigger"] = TriggerLogger("repro.trigger")

try:
    with catching_logs(logging.NullHandler()):
        pass
finally:
    if worker is not None:
        worker.join(timeout=1)

The property access happens after pytest's live dictionary iterator has yielded its first logger. The worker then uses the public logging.getLogger() API to mutate the registry before pytest requests the iterator's next value.

Actual result

File ".../_pytest/logging.py", line 366, in __enter__
    for logger in root_logger.manager.loggerDict.values():
RuntimeError: dictionary changed size during iteration

Expected result

Concurrent logger registration should not make capture setup fail.

Suggested fix

Snapshot the registry before inspecting the loggers:

for logger in list(root_logger.manager.loggerDict.values()):

This also matches the behavior described in #14375: loggers created after capture setup starts do not need to be discovered by that capture scope.

Environment

  • macOS 26.5.2 (Apple silicon)
  • Python 3.13.13
  • pytest 9.2.0.dev393+gc9bf1edf9 (main at c9bf1edf9e0d388f3e7bebc88576e608ffbc40a4)
  • Also reproduced with pytest 9.1.1 on Python 3.12
pip list
Package            Version
------------------ ----------------------------
argcomplete        3.6.3
attrs              25.4.0
certifi            2026.1.4
charset-normalizer 3.4.4
coverage           7.13.1
elementpath        5.1.0
execnet            2.1.2
hypothesis         6.150.0
idna               3.11
iniconfig          2.3.0
mock               5.2.0
numpy              2.4.1
packaging          25.0
pexpect             4.9.0
pluggy             1.6.0
ptyprocess         0.7.0
Pygments           2.19.2
pytest             9.2.0.dev393+gc9bf1edf9
pytest-xdist       3.8.0
PyYAML             6.0.3
requests           2.32.5
setuptools         80.9.0
sortedcontainers   2.4.0
urllib3            2.6.3
xmlschema          4.3.0
Ngôn ngữ chính
Python
Star
14.6k
Fork
3.5k
Merge trung bình
2 ngày 6 giờ
Pull request đã merge (30 ngày)
31

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của pytest-dev/pytest

Tất cả issue của pytest-dev/pytest

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.