From 74832c6a5b2af6db316b430a8f8bb74270b2878b Mon Sep 17 00:00:00 2001 From: donbarbos Date: Tue, 21 Jul 2026 13:22:13 +0400 Subject: [PATCH 1/2] [boltons] Update to 26.1.* Closes: #15927 --- stubs/boltons/METADATA.toml | 2 +- stubs/boltons/boltons/__init__.pyi | 3 +++ stubs/boltons/boltons/dictutils.pyi | 1 + stubs/boltons/boltons/funcutils.pyi | 5 +++++ stubs/boltons/boltons/iterutils.pyi | 22 +++++++++++++--------- stubs/boltons/boltons/strutils.pyi | 6 +++--- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/stubs/boltons/METADATA.toml b/stubs/boltons/METADATA.toml index 829db8486880..9c5868f7d067 100644 --- a/stubs/boltons/METADATA.toml +++ b/stubs/boltons/METADATA.toml @@ -1,2 +1,2 @@ -version = "25.0.*" +version = "26.1.*" upstream-repository = "https://github.com/mahmoud/boltons" diff --git a/stubs/boltons/boltons/__init__.pyi b/stubs/boltons/boltons/__init__.pyi index e69de29bb2d1..c5dd95466063 100644 --- a/stubs/boltons/boltons/__init__.pyi +++ b/stubs/boltons/boltons/__init__.pyi @@ -0,0 +1,3 @@ +from typing import Final + +__version__: Final[str] diff --git a/stubs/boltons/boltons/dictutils.pyi b/stubs/boltons/boltons/dictutils.pyi index 69b5a258ea61..8d5e578437a8 100644 --- a/stubs/boltons/boltons/dictutils.pyi +++ b/stubs/boltons/boltons/dictutils.pyi @@ -8,6 +8,7 @@ _VT = TypeVar("_VT") _T = TypeVar("_T") class OrderedMultiDict(dict[_KT, _VT]): + def __reduce__(self) -> tuple[type[Self], tuple[()], list[tuple[_KT, _VT]]]: ... def add(self, k: _KT, v: _VT) -> None: ... def addlist(self, k: _KT, v: Iterable[_VT]) -> None: ... def clear(self) -> None: ... diff --git a/stubs/boltons/boltons/funcutils.pyi b/stubs/boltons/boltons/funcutils.pyi index 0102bc154b33..af5c06dc9386 100644 --- a/stubs/boltons/boltons/funcutils.pyi +++ b/stubs/boltons/boltons/funcutils.pyi @@ -1,6 +1,10 @@ import functools from _typeshed import Incomplete +from collections.abc import Callable from functools import total_ordering as total_ordering +from typing import TypeVar + +_R = TypeVar("_R") NO_DEFAULT: Incomplete @@ -61,3 +65,4 @@ class MissingArgument(ValueError): ... class ExistingArgument(ValueError): ... def noop(*args, **kwargs) -> None: ... +def once(func: Callable[[], _R]) -> Callable[[], _R]: ... diff --git a/stubs/boltons/boltons/iterutils.pyi b/stubs/boltons/boltons/iterutils.pyi index 0c16dfa66e59..cf0251567288 100644 --- a/stubs/boltons/boltons/iterutils.pyi +++ b/stubs/boltons/boltons/iterutils.pyi @@ -1,11 +1,15 @@ from _typeshed import Incomplete -from collections.abc import Generator +from collections.abc import Callable, Generator, Iterable +from typing import TypeVar +from typing_extensions import TypeIs -def is_iterable(obj) -> bool: ... -def is_scalar(obj) -> bool: ... -def is_collection(obj) -> bool: ... +_T = TypeVar("_T") + +def is_iterable(obj: Iterable[_T] | object) -> TypeIs[Iterable[_T]]: ... +def is_scalar(obj: object) -> bool: ... +def is_collection(obj: object) -> bool: ... def split(src, sep=None, maxsplit=None): ... -def split_iter(src, sep=None, maxsplit=None) -> Generator[Incomplete, None, Incomplete]: ... +def split_iter(src, sep=None, maxsplit=None) -> Generator[list[Incomplete]]: ... def lstrip(iterable, strip_value=None): ... def lstrip_iter(iterable, strip_value=None) -> Generator[Incomplete]: ... def rstrip(iterable, strip_value=None): ... @@ -13,7 +17,7 @@ def rstrip_iter(iterable, strip_value=None) -> Generator[Incomplete]: ... def strip(iterable, strip_value=None): ... def strip_iter(iterable, strip_value=None): ... def chunked(src, size, count=None, **kw): ... -def chunked_iter(src, size, **kw) -> Generator[Incomplete, None, Incomplete]: ... +def chunked_iter(src, size, **kw) -> Generator[str | bytes]: ... def chunk_ranges( input_size: int, chunk_size: int, input_offset: int = 0, overlap_size: int = 0, align: bool = False ) -> Generator[tuple[int, int]]: ... @@ -26,9 +30,9 @@ def frange(stop, start=None, step: float = 1.0): ... def backoff(start, stop, count=None, factor: float = 2.0, jitter: bool = False): ... def backoff_iter(start, stop, count=None, factor: float = 2.0, jitter: bool = False) -> Generator[Incomplete]: ... def bucketize(src, key=..., value_transform=None, key_filter=None): ... -def partition(src, key=...): ... +def partition(src, key=..., *keys: str | Callable[..., Incomplete]) -> tuple[list[Incomplete], ...]: ... def unique(src, key=None): ... -def unique_iter(src, key=None) -> Generator[Incomplete, None, Incomplete]: ... +def unique_iter(src, key=None) -> Generator[Incomplete]: ... def redundant(src, key=None, groups: bool = False): ... def one(src, default=None, key=None): ... def first(iterable, default=None, key=None): ... @@ -38,7 +42,7 @@ def same(iterable, ref=...): ... def default_visit(path, key, value): ... def default_enter(path, key, value): ... def default_exit(path, key, old_parent, new_parent, new_items): ... -def remap(root, visit=..., enter=..., exit=..., **kwargs): ... +def remap(root, visit=..., enter=..., exit=..., cache: bool = True, **kwargs): ... class PathAccessError(KeyError, IndexError, TypeError): exc: Incomplete diff --git a/stubs/boltons/boltons/strutils.pyi b/stubs/boltons/boltons/strutils.pyi index 450937729c74..2eae46714980 100644 --- a/stubs/boltons/boltons/strutils.pyi +++ b/stubs/boltons/boltons/strutils.pyi @@ -1,5 +1,5 @@ from _typeshed import ReadableBuffer -from collections.abc import Callable, Generator, Iterable, Sized +from collections.abc import Callable, Generator, Iterable, Sequence, Sized from html.parser import HTMLParser from re import Pattern from typing import Literal, overload @@ -32,8 +32,6 @@ class DeaccenterDict(dict[int, int]): def bytes2human(nbytes: int, ndigits: int = 0) -> str: ... class HTMLTextExtractor(HTMLParser): - strict: bool - convert_charrefs: bool result: list[str] def __init__(self) -> None: ... def handle_data(self, d: str) -> None: ... @@ -66,6 +64,7 @@ class MultiReplace: def multi_replace(text: str, sub_map: dict[str, str], **kwargs) -> str: ... def unwrap_text(text: str, ending: str | None = "\n\n") -> str: ... def removeprefix(text: str, prefix: str) -> str: ... +def human_readable_list(items: Sequence[str], delimiter: str = ",", conjunction: str = "and", *, oxford: bool = True) -> str: ... __all__ = [ "camel2under", @@ -100,4 +99,5 @@ __all__ = [ "multi_replace", "unwrap_text", "removeprefix", + "human_readable_list", ] From 2a9c002527eb773c4da99d2ed1675dfb06f47d86 Mon Sep 17 00:00:00 2001 From: Semyon Moroz Date: Tue, 21 Jul 2026 10:11:55 +0000 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Sebastian Rittau --- stubs/boltons/boltons/funcutils.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/boltons/boltons/funcutils.pyi b/stubs/boltons/boltons/funcutils.pyi index af5c06dc9386..d9b02dc9eb2e 100644 --- a/stubs/boltons/boltons/funcutils.pyi +++ b/stubs/boltons/boltons/funcutils.pyi @@ -1,5 +1,5 @@ import functools -from _typeshed import Incomplete +from _typeshed import Incomplete, Unused from collections.abc import Callable from functools import total_ordering as total_ordering from typing import TypeVar @@ -64,5 +64,5 @@ class FunctionBuilder: class MissingArgument(ValueError): ... class ExistingArgument(ValueError): ... -def noop(*args, **kwargs) -> None: ... +def noop(*args: Unused, **kwargs: Unused) -> None: ... def once(func: Callable[[], _R]) -> Callable[[], _R]: ...