From ba6b8cd21bc2153da1af49128c1523deff04dfae Mon Sep 17 00:00:00 2001 From: Culai Date: Sat, 24 Oct 2026 14:09:07 +0300 Subject: [PATCH] [atheris] Add FuzzedDataProvider and re-export the public API Add `atheris/native.pyi` (where `FuzzedDataProvider`, `Setup`, `Fuzz`, `Mutate` and `ALL_REMAINING` live at runtime) and re-export the public names from `atheris/__init__.pyi`. Co-Authored-By: Claude Opus 5.5 --- stubs/atheris/@tests/stubtest_allowlist.txt | 3 ++ stubs/atheris/atheris/__init__.pyi | 20 ++++++----- stubs/atheris/atheris/native.pyi | 39 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 stubs/atheris/@tests/stubtest_allowlist.txt create mode 100644 stubs/atheris/atheris/native.pyi diff --git a/stubs/atheris/@tests/stubtest_allowlist.txt b/stubs/atheris/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000000..432f4c6e14bf --- /dev/null +++ b/stubs/atheris/@tests/stubtest_allowlist.txt @@ -0,0 +1,3 @@ +# The metaclass of FuzzedDataProvider is pybind11_builtins.pybind11_type, which is +# not importable from a stub, and pybind11 is not a runtime dependency of atheris. +atheris.native.FuzzedDataProvider diff --git a/stubs/atheris/atheris/__init__.pyi b/stubs/atheris/atheris/__init__.pyi index 2a3312448ab0..f7d30f367566 100644 --- a/stubs/atheris/atheris/__init__.pyi +++ b/stubs/atheris/atheris/__init__.pyi @@ -1,9 +1,13 @@ -from collections.abc import Callable +from .function_hooks import enabled_hooks as enabled_hooks +from .import_hook import instrument_imports as instrument_imports +from .instrument_bytecode import instrument_all as instrument_all, instrument_func as instrument_func +from .native import ( + ALL_REMAINING as ALL_REMAINING, + Fuzz as Fuzz, + FuzzedDataProvider as FuzzedDataProvider, + Mutate as Mutate, + Setup as Setup, +) +from .utils import path as path -def Setup( - args: list[str], - test_one_input: Callable[[bytes], None], - **kwargs: bool | Callable[[bytes, int, int], str | bytes] | Callable[[bytes, bytes, int, int], str | bytes] | None, -) -> list[str]: ... -def Fuzz() -> None: ... -def Mutate(data: bytes, max_size: int) -> bytes: ... +def get_hook_dirs() -> list[str]: ... # undocumented diff --git a/stubs/atheris/atheris/native.pyi b/stubs/atheris/atheris/native.pyi new file mode 100644 index 000000000000..2ed1d830526b --- /dev/null +++ b/stubs/atheris/atheris/native.pyi @@ -0,0 +1,39 @@ +from collections.abc import Callable, Sequence +from typing import Final, TypeVar + +_T = TypeVar("_T") + +ALL_REMAINING: Final[int] # undocumented + +def Setup( + args: Sequence[str], + test_one_input: Callable[[bytes], None], + /, + **kwargs: bool | Callable[[bytes, int, int], str | bytes] | Callable[[bytes, bytes, int, int], str | bytes] | None, +) -> list[str]: ... +def Fuzz() -> None: ... +def Mutate(data: bytes, max_size: int, /) -> bytes: ... + +class FuzzedDataProvider: + def __init__(self, data: bytes, /) -> None: ... + def ConsumeUnicode(self, count: int) -> str: ... + def ConsumeUnicodeNoSurrogates(self, count: int, /) -> str: ... + def ConsumeBytes(self, count: int, /) -> bytes: ... + def ConsumeString(self, count: int, /) -> str: ... + def ConsumeInt(self, byte_size: int, /) -> int: ... + def ConsumeUInt(self, byte_size: int, /) -> int: ... + def ConsumeIntInRange(self, min: int, max: int, /) -> int: ... + def ConsumeIntList(self, count: int, byte_size: int, /) -> list[int]: ... + def ConsumeIntListInRange(self, count: int, min: int, max: int, /) -> list[int]: ... + def ConsumeFloat(self) -> float: ... + def ConsumeRegularFloat(self) -> float: ... + def ConsumeProbability(self) -> float: ... + def ConsumeFloatInRange(self, min: float, max: float, /) -> float: ... + def ConsumeFloatList(self, count: int, /) -> list[float]: ... + def ConsumeRegularFloatList(self, count: int, /) -> list[float]: ... + def ConsumeProbabilityList(self, count: int, /) -> list[float]: ... + def ConsumeFloatListInRange(self, count: int, min: float, max: float, /) -> list[float]: ... + def PickValueInList(self, values: list[_T], /) -> _T: ... + def ConsumeBool(self) -> bool: ... + def remaining_bytes(self) -> int: ... # undocumented + def buffer(self) -> bytes: ... # undocumented