Skip to content

Commit bbe79e8

Browse files
authored
Merge pull request #858 from gaoflow/fix/856-nullhandler
fix: attach NullHandler to the edgar package logger (#856)
2 parents 58c945f + fcb58e7 commit bbe79e8

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515

16+
- **`edgar` package logger no longer leaks log output in unconfigured applications** — the package-root logger had no `NullHandler`, so when an application had not configured logging itself, edgartools warnings fell back to Python's `logging.lastResort` handler and were written to stderr. This was especially harmful in MCP / stdio environments, where stray stderr output corrupts the protocol stream. A `NullHandler` is now attached to the `edgar` logger per the Python logging HOWTO for libraries, keeping edgartools silent until the application opts into logging. ([#856](https://github.com/dgunning/edgartools/issues/856))
1617
- **BDC data sets download again after SEC URL move** — the SEC relocated the DERA BDC data-set files from `/files/structureddata/data/` to `/files/datastandardsinnovation/data/`, which made `fetch_bdc_dataset()` and related functions fail with 404; the base URL now points to the new location.
1718
- **`FormC.filer_information.ccc` no longer duplicates the CIK** — the Form C parser read the `filerCik` element into both `cik` and `ccc`; `ccc` now reads the actual `filerCcc` element (always redacted to `XXXXXXXX` in disseminated filings) and is `Optional`, returning `None` when absent.
1819
- **`FormC.filer_information.live_or_test` is no longer always `False`** — the parser looked for a `testOrLive` element under `filer`, but the schema places `liveTestFlag` under `filerInfo`; LIVE filings now correctly report `True` (older `testOrLive` documents remain supported).

edgar/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-FileCopyrightText: 2022-present Dwight Gunning <dgunning@gmail.com>
22
#
33
# SPDX-License-Identifier: MIT
4+
import logging
45
import re
56
from functools import lru_cache, partial
67
from typing import List, Optional, Union
@@ -103,6 +104,13 @@
103104
from edgar.thirteenf import THIRTEENF_FORMS, ThirteenF
104105
from edgar.xbrl import XBRL
105106

107+
# Attach a NullHandler to the package-root logger so that edgartools never emits
108+
# log output unless the application configures logging itself, per the Python
109+
# logging HOWTO guidance for libraries (#856). Without it, library warnings have
110+
# no handler in their ancestry and fall back to logging.lastResort (stderr),
111+
# which is especially harmful in MCP / stdio environments.
112+
logging.getLogger(__name__).addHandler(logging.NullHandler())
113+
106114
# Fix for Issue #457: Clear locale-corrupted cache files on first import
107115
# This is a one-time operation that only runs if the marker file doesn't exist
108116
try:
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
Regression test for Issue #856: Missing NullHandler in the edgar package logger.
3+
4+
A well-behaved library should attach a ``logging.NullHandler`` to its
5+
package-root logger so that it never emits log output unless the consuming
6+
application configures logging itself (see the Python logging HOWTO,
7+
"Configuring Logging for a Library"). Without it, edgartools warnings have no
8+
handler in their ancestry and fall back to the ``logging.lastResort`` handler,
9+
which writes to stderr -- especially harmful in MCP / stdio environments where
10+
stray stderr output corrupts the protocol stream.
11+
"""
12+
13+
import logging
14+
15+
import edgar # noqa: F401 (importing configures the package-root logger)
16+
17+
18+
class TestPackageRootNullHandler:
19+
def test_edgar_logger_has_null_handler(self):
20+
"""The 'edgar' package-root logger must carry a NullHandler."""
21+
handlers = logging.getLogger("edgar").handlers
22+
assert any(isinstance(h, logging.NullHandler) for h in handlers), (
23+
"edgartools must attach a logging.NullHandler to the 'edgar' logger "
24+
"so library logging stays silent until the application configures it"
25+
)
26+
27+
def test_edgar_logger_adds_only_null_handler(self):
28+
"""The library must not attach handlers other than NullHandler (HOWTO)."""
29+
handlers = logging.getLogger("edgar").handlers
30+
assert handlers, "the 'edgar' logger should have a NullHandler attached"
31+
assert all(isinstance(h, logging.NullHandler) for h in handlers), (
32+
"a library must not attach handlers other than NullHandler to its "
33+
"package-root logger; that is the application's responsibility"
34+
)

0 commit comments

Comments
 (0)