From edc2e5e9c1ad01328c560dfe78037aaf062ae4ae Mon Sep 17 00:00:00 2001 From: WU Leizhi Date: Sat, 3 Oct 2026 22:58:55 +0800 Subject: [PATCH] fix: accept compiled exclusion patterns in Box constructors --- AUTHORS.rst | 1 + CHANGES.rst | 5 +++++ box/box.py | 4 ++-- box/box.pyi | 5 +++-- test/test_box.py | 27 +++++++++++++++++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/AUTHORS.rst b/AUTHORS.rst index 6b44851..edb0af3 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -37,6 +37,7 @@ Code contributions: - Jesper Schlegel (jesperschlegel) - J vanBemmel (jbemmel) - m-janicki +- WU Leizhi (MbappeWU) Suggestions and bug reporting: diff --git a/CHANGES.rst b/CHANGES.rst index c4a347d..bf8e3f4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,11 @@ Changelog ========= +Unreleased +---------- + +* Fixing compiled Box nested construction with a compiled ``box_dots_exclude`` pattern + Version 7.4.1 ------------- diff --git a/box/box.py b/box/box.py index 8252643..6c627a0 100644 --- a/box/box.py +++ b/box/box.py @@ -206,7 +206,7 @@ def __new__( box_intact_types: tuple | list = (), box_recast: dict | None = None, box_dots: bool = False, - box_dots_exclude: str | None = None, + box_dots_exclude: str | re.Pattern[str] | None = None, box_class: dict | type[Box] | None = None, box_namespace: tuple[str, ...] | Literal[False] = (), **kwargs: Any, @@ -255,7 +255,7 @@ def __init__( box_intact_types: tuple | list = (), box_recast: dict | None = None, box_dots: bool = False, - box_dots_exclude: str | None = None, + box_dots_exclude: str | re.Pattern[str] | None = None, box_class: dict | type[Box] | None = None, box_namespace: tuple[str, ...] | Literal[False] = (), **kwargs: Any, diff --git a/box/box.pyi b/box/box.pyi index 05f0906..7a7d4cd 100644 --- a/box/box.pyi +++ b/box/box.pyi @@ -1,6 +1,7 @@ from _typeshed import Incomplete from collections.abc import Generator, Mapping from os import PathLike +import re from typing import Any, Literal class Box(dict): @@ -20,7 +21,7 @@ class Box(dict): box_intact_types: tuple | list = ..., box_recast: dict | None = ..., box_dots: bool = ..., - box_dots_exclude: str | None = ..., + box_dots_exclude: str | re.Pattern[str] | None = ..., box_class: dict | type[Box] | None = ..., box_namespace: tuple[str, ...] | Literal[False] = ..., **kwargs: Any, @@ -41,7 +42,7 @@ class Box(dict): box_intact_types: tuple | list = ..., box_recast: dict | None = ..., box_dots: bool = ..., - box_dots_exclude: str | None = ..., + box_dots_exclude: str | re.Pattern[str] | None = ..., box_class: dict | type[Box] | None = ..., box_namespace: tuple[str, ...] | Literal[False] = ..., **kwargs: Any, diff --git a/test/test_box.py b/test/test_box.py index e5c56e0..f368230 100644 --- a/test/test_box.py +++ b/test/test_box.py @@ -6,6 +6,7 @@ import os import pickle import platform +import re import shutil from multiprocessing import Queue from pathlib import Path @@ -957,6 +958,32 @@ def test_dots_exclusion(self): with pytest.raises(BoxKeyError): del bx["0"] + @pytest.mark.parametrize( + "exclude", + [r"(?im)^secret\.", re.compile(r"^secret\.", re.IGNORECASE | re.MULTILINE)], + ) + def test_dots_exclusion_pattern_propagates(self, exclude): + expected = re.compile(exclude) + bx = Box( + {"Secret.Key": 1, "nested": {"Secret.Key": 2}, "items": [{"Secret.Key": 3}]}, + box_dots=True, + box_dots_exclude=exclude, + ) + + assert bx["Secret.Key"] == 1 + assert bx.nested["Secret.Key"] == 2 + assert bx["items"][0]["Secret.Key"] == 3 + assert bx.nested._box_config["box_dots_exclude"].flags == expected.flags + assert bx["items"].box_options["box_dots_exclude"].flags == expected.flags + assert bx["items"][0]._box_config["box_dots_exclude"].flags == expected.flags + assert bx._box_config["box_dots_exclude"].flags == expected.flags + + for copied in (bx.copy(), copy.copy(bx), copy.deepcopy(bx)): + assert copied["Secret.Key"] == 1 + assert copied.nested["Secret.Key"] == 2 + assert copied["items"][0]["Secret.Key"] == 3 + assert copied._box_config["box_dots_exclude"].flags == expected.flags + def test_unicode(self): bx = Box() bx["\U0001f631"] = 4