From b0475c771af2a27b2949db5e7eb50756949f53a7 Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 16:54:09 +0300 Subject: [PATCH 01/13] Save the type if a subtype is passed to fnmatch.filter/fnmatch.filterfalse. --- stdlib/fnmatch.pyi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index 018139dc482b..b1a80441ac5d 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -7,10 +7,12 @@ __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): __all__ += ["filterfalse"] +_AnyStrPathLike = TypeVar("_T", bound=str | bytes | PathLike[Any]) + def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... -def filter(names: Iterable[AnyStr | PathLike[AnyStr]], pat: AnyStr | PathLike[AnyStr]) -> list[AnyStr]: ... +def filter(names: Iterable[_AnyStrPathLike], pat: AnyStr | PathLike[AnyStr]) -> list[_AnyStrPathLike]: ... def translate(pat: str) -> str: ... if sys.version_info >= (3, 14): - def filterfalse(names: Iterable[AnyStr | PathLike[AnyStr]], pat: AnyStr | PathLike[AnyStr]) -> list[AnyStr]: ... + def filterfalse(names: Iterable[_AnyStrPathLike], pat: AnyStr | PathLike[AnyStr]) -> list[_AnyStrPathLike]: ... From c1a9d49bd5ea385caff83a256a4cefd87d07713a Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 16:55:59 +0300 Subject: [PATCH 02/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index b1a80441ac5d..9e2d6183353a 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Iterable from os import PathLike -from typing import AnyStr +from typing import AnyStr, TypeVar __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): From f7ccf67ea00a5c9edda01268ae7f344830a40392 Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 16:58:56 +0300 Subject: [PATCH 03/13] fix name --- stdlib/fnmatch.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index 9e2d6183353a..12ebb0830b4b 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -7,7 +7,7 @@ __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): __all__ += ["filterfalse"] -_AnyStrPathLike = TypeVar("_T", bound=str | bytes | PathLike[Any]) +_AnyStrPathLike = TypeVar("_AnyStrPathLike", bound=str | bytes | PathLike[Any]) def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... From a07243bdeaca3c79f9a5f457f9e9f999ab5fcaee Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:00:19 +0300 Subject: [PATCH 04/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index 12ebb0830b4b..17dd07ed8dbb 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Iterable from os import PathLike -from typing import AnyStr, TypeVar +from typing import Any, AnyStr, TypeVar __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): From 09a79015982419691ba0194d41e7d24b319163a4 Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:19:47 +0300 Subject: [PATCH 05/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index 17dd07ed8dbb..e3fafac01dfa 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -7,12 +7,12 @@ __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): __all__ += ["filterfalse"] -_AnyStrPathLike = TypeVar("_AnyStrPathLike", bound=str | bytes | PathLike[Any]) +_PathT = TypeVar("_PathT", bound=str | bytes | PathLike[Any]) def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... -def filter(names: Iterable[_AnyStrPathLike], pat: AnyStr | PathLike[AnyStr]) -> list[_AnyStrPathLike]: ... +def filter(names: Iterable[_PathT], pat: AnyStr | PathLike[AnyStr]) -> list[_PathT]: ... def translate(pat: str) -> str: ... if sys.version_info >= (3, 14): - def filterfalse(names: Iterable[_AnyStrPathLike], pat: AnyStr | PathLike[AnyStr]) -> list[_AnyStrPathLike]: ... + def filterfalse(names: Iterable[_PathT], pat: AnyStr | PathLike[AnyStr]) -> list[_PathT]: ... From c0cff08c9a076cb93571a70d0a87942f5833d2ca Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:36:06 +0300 Subject: [PATCH 06/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index e3fafac01dfa..ac00a15c9ca7 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -7,12 +7,12 @@ __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): __all__ += ["filterfalse"] -_PathT = TypeVar("_PathT", bound=str | bytes | PathLike[Any]) +_PathT = TypeVar("_PathT", str, bytes, PathLike[Any]) def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... -def filter(names: Iterable[_PathT], pat: AnyStr | PathLike[AnyStr]) -> list[_PathT]: ... +def filter(names: Iterable[_PathT], pat: _PathT) -> list[_PathT]: ... def translate(pat: str) -> str: ... if sys.version_info >= (3, 14): - def filterfalse(names: Iterable[_PathT], pat: AnyStr | PathLike[AnyStr]) -> list[_PathT]: ... + def filterfalse(names: Iterable[_PathT], pat: _PathT) -> list[_PathT]: ... From a0a41cf723332a0acd2b60910014801aba260b79 Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:43:35 +0300 Subject: [PATCH 07/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index ac00a15c9ca7..e9bee7df9fb5 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -7,7 +7,7 @@ __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): __all__ += ["filterfalse"] -_PathT = TypeVar("_PathT", str, bytes, PathLike[Any]) +_PathT = TypeVar("_PathT", str | PathLike[str], bytes | PathLike[bytes]) def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... From 971992d748dd246d90c888ed64c49512cb78a825 Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:45:43 +0300 Subject: [PATCH 08/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index e9bee7df9fb5..d6ff5a90e338 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Iterable from os import PathLike -from typing import Any, AnyStr, TypeVar +from typing import AnyStr, TypeVar __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): From 1888221205422378361688457105ad674cf4fc4f Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 17:53:27 +0300 Subject: [PATCH 09/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index d6ff5a90e338..7213945a8eff 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -1,18 +1,25 @@ import sys from collections.abc import Iterable from os import PathLike -from typing import AnyStr, TypeVar +from typing import AnyStr, TypeVar, overload __all__ = ["filter", "fnmatch", "fnmatchcase", "translate"] if sys.version_info >= (3, 14): __all__ += ["filterfalse"] -_PathT = TypeVar("_PathT", str | PathLike[str], bytes | PathLike[bytes]) +_PathT_str = TypeVar("_PathT_str", bound=str | PathLike[str]) +_PathT_bytes = TypeVar("_PathT_bytes", bound=bytes | PathLike[bytes]) def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... -def filter(names: Iterable[_PathT], pat: _PathT) -> list[_PathT]: ... +@overload +def filter(names: Iterable[_PathT_str], pat: str | PathLike[str]) -> list[_PathT_str]: ... +@overload +def filter(names: Iterable[_PathT_bytes], pat: bytes | PathLike[bytes]) -> list[_PathT_bytes]: ... def translate(pat: str) -> str: ... if sys.version_info >= (3, 14): - def filterfalse(names: Iterable[_PathT], pat: _PathT) -> list[_PathT]: ... + @overload + def filterfalse(names: Iterable[_PathT_str], pat: str | PathLike[str]) -> list[_PathT_str]: ... + @overload + def filterfalse(names: Iterable[_PathT_bytes], pat: bytes | PathLike[bytes]) -> list[_PathT_bytes]: ... From bce05279683037e8e3baceb7f486bc4e42e91817 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 14:56:18 +0000 Subject: [PATCH 10/13] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/fnmatch.pyi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index 7213945a8eff..fdee9823386f 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -12,10 +12,12 @@ _PathT_bytes = TypeVar("_PathT_bytes", bound=bytes | PathLike[bytes]) def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... + @overload def filter(names: Iterable[_PathT_str], pat: str | PathLike[str]) -> list[_PathT_str]: ... @overload def filter(names: Iterable[_PathT_bytes], pat: bytes | PathLike[bytes]) -> list[_PathT_bytes]: ... + def translate(pat: str) -> str: ... if sys.version_info >= (3, 14): From 14b40d6bf4bf9caa7a6db2253b81044c01dbbd7e Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:20:25 +0300 Subject: [PATCH 11/13] in posix names can't have PathLike --- stdlib/fnmatch.pyi | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index fdee9823386f..95f7769674f2 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -9,19 +9,34 @@ if sys.version_info >= (3, 14): _PathT_str = TypeVar("_PathT_str", bound=str | PathLike[str]) _PathT_bytes = TypeVar("_PathT_bytes", bound=bytes | PathLike[bytes]) +_T_str = TypeVar("_PathT_str", bound=str) +_T_bytes = TypeVar("_PathT_bytes", bound=bytes) + def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... -@overload -def filter(names: Iterable[_PathT_str], pat: str | PathLike[str]) -> list[_PathT_str]: ... -@overload -def filter(names: Iterable[_PathT_bytes], pat: bytes | PathLike[bytes]) -> list[_PathT_bytes]: ... +if sys.platform == "win32": + @overload + def filter(names: Iterable[_PathT_str], pat: str | PathLike[str]) -> list[_PathT_str]: ... + @overload + def filter(names: Iterable[_PathT_bytes], pat: bytes | PathLike[bytes]) -> list[_PathT_bytes]: ... +else: + @overload + def filter(names: Iterable[_T_str], pat: str | PathLike[str]) -> list[_T_str]: ... + @overload + def filter(names: Iterable[_T_bytes], pat: bytes | PathLike[bytes]) -> list[_T_bytes]: ... def translate(pat: str) -> str: ... if sys.version_info >= (3, 14): - @overload - def filterfalse(names: Iterable[_PathT_str], pat: str | PathLike[str]) -> list[_PathT_str]: ... - @overload - def filterfalse(names: Iterable[_PathT_bytes], pat: bytes | PathLike[bytes]) -> list[_PathT_bytes]: ... + if sys.platform == "win32": + @overload + def filterfalse(names: Iterable[_PathT_str], pat: str | PathLike[str]) -> list[_PathT_str]: ... + @overload + def filterfalse(names: Iterable[_PathT_bytes], pat: bytes | PathLike[bytes]) -> list[_PathT_bytes]: ... + else: + @overload + def filterfalse(names: Iterable[_T_str], pat: str | PathLike[str]) -> list[_T_str]: ... + @overload + def filterfalse(names: Iterable[_T_bytes], pat: bytes | PathLike[bytes]) -> list[_T_bytes]: ... From bf18896cea7629d920df862ee526b35ec418cb91 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 15:22:33 +0000 Subject: [PATCH 12/13] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/fnmatch.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index 95f7769674f2..0bb0284532a0 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -12,7 +12,6 @@ _PathT_bytes = TypeVar("_PathT_bytes", bound=bytes | PathLike[bytes]) _T_str = TypeVar("_PathT_str", bound=str) _T_bytes = TypeVar("_PathT_bytes", bound=bytes) - def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ... From aa6d139d6501a2c928e9338ea2ecdb1d98a725c6 Mon Sep 17 00:00:00 2001 From: zedzhen <59135268+zedzhen@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:22:56 +0300 Subject: [PATCH 13/13] Update fnmatch.pyi --- stdlib/fnmatch.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/fnmatch.pyi b/stdlib/fnmatch.pyi index 0bb0284532a0..7dc2939a34af 100644 --- a/stdlib/fnmatch.pyi +++ b/stdlib/fnmatch.pyi @@ -9,8 +9,8 @@ if sys.version_info >= (3, 14): _PathT_str = TypeVar("_PathT_str", bound=str | PathLike[str]) _PathT_bytes = TypeVar("_PathT_bytes", bound=bytes | PathLike[bytes]) -_T_str = TypeVar("_PathT_str", bound=str) -_T_bytes = TypeVar("_PathT_bytes", bound=bytes) +_T_str = TypeVar("_T_str", bound=str) +_T_bytes = TypeVar("_T_bytes", bound=bytes) def fnmatch(name: AnyStr | PathLike[AnyStr], pat: AnyStr | PathLike[AnyStr]) -> bool: ... def fnmatchcase(name: AnyStr, pat: AnyStr) -> bool: ...