From 0c1cde4e27cc56bb177c3796f43b320676c83553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Thu, 16 Jul 2026 16:49:34 +0100 Subject: [PATCH 1/2] Fix incompatibility with pathlib.Path I was adding types to beetsplug/fetchart.py and found that this @cached_property def fallback(self) -> Path | None: return self.config["fallback"].get( confuse.Optional(confuse.templates.Path()) ) fails with beetsplug/fetchart.py:1370: error: Incompatible return value type (got "PurePath | None", expected "Path | None") [return-value] --- confuse/templates.py | 8 ++++---- docs/changelog.rst | 2 ++ test/test_valid.py | 15 +++++++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/confuse/templates.py b/confuse/templates.py index a706765..0281d30 100644 --- a/confuse/templates.py +++ b/confuse/templates.py @@ -24,7 +24,7 @@ T = TypeVar("T") T_co = TypeVar("T_co", covariant=True) K = TypeVar("K", bound=Hashable, default=str) -P = TypeVar("P", bound=pathlib.PurePath | str, default=str) +P = TypeVar("P", bound=pathlib.Path | str, default=str) V = TypeVar("V", default=object) ConfigKey = int | str | bytes ConfigKeyT = TypeVar("ConfigKeyT", bound=ConfigKey, default=str) @@ -738,7 +738,7 @@ def value( return os.path.abspath(path_str) -class Path(Filename[pathlib.PurePath]): +class Path(Filename[pathlib.Path]): """A template that validates strings as `pathlib.Path` objects. Filenames are parsed equivalent to the `Filename` template and then @@ -863,7 +863,7 @@ def as_template(value: set[T]) -> Choice[T, T]: ... @overload def as_template(value: list[T]) -> OneOf[T]: ... @overload -def as_template(value: pathlib.PurePath) -> Path: ... +def as_template(value: pathlib.Path) -> Path: ... @overload def as_template(value: None) -> Template[None]: ... @overload @@ -897,7 +897,7 @@ def as_template(value: Any) -> Template[Any]: return Number() elif isinstance(value, float): return Number(value) - elif isinstance(value, pathlib.PurePath): + elif isinstance(value, pathlib.Path): return Path(value) elif value is None: return Template(None) diff --git a/docs/changelog.rst b/docs/changelog.rst index d1fb317..733a60e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,8 @@ Unreleased - Require `typing_extensions` on older Python versions (and use `typing` on newer versions). [#189](https://github.com/beetbox/confuse/issues/189) +- Narrow `Path` template shorthand handling to concrete `pathlib.Path` values + for more accurate type checking. v2.2.0 ------ diff --git a/test/test_valid.py b/test/test_valid.py index 0b340a6..1b5be61 100644 --- a/test/test_valid.py +++ b/test/test_valid.py @@ -1,11 +1,17 @@ import enum import os +import pathlib import unittest from collections.abc import Mapping, Sequence from typing import Any import pytest +try: + from typing import assert_type # type: ignore[attr-defined] +except ImportError: # Python < 3.11 + from typing_extensions import assert_type + import confuse from . import _root @@ -461,19 +467,20 @@ def test_filename_wrong_type(self): class PathTest(unittest.TestCase): def test_path_value(self): - import pathlib - config = _root({"foo": "foo/bar"}) valid = config["foo"].get(confuse.Path()) assert valid == pathlib.Path(os.path.abspath("foo/bar")) def test_default_value(self): - import pathlib - config = _root({}) valid = config["foo"].get(confuse.Path("foo/bar")) assert valid == pathlib.Path("foo/bar") + def test_optional_value_type(self): + config = _root({"foo": "foo/bar"}) + valid = config["foo"].get(confuse.Optional(confuse.Path())) + assert_type(valid, pathlib.Path | None) + def test_default_none(self): config = _root({}) valid = config["foo"].get(confuse.Path(None)) From e24ce6eb7a6d7cb59237b946b509d4c38ee1f4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0ar=C5=ABnas=20Nejus?= Date: Thu, 16 Jul 2026 18:08:03 +0100 Subject: [PATCH 2/2] Fix confuse.Path --- confuse/__init__.py | 1 + docs/changelog.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/confuse/__init__.py b/confuse/__init__.py index 264ed60..07f24c1 100644 --- a/confuse/__init__.py +++ b/confuse/__init__.py @@ -4,5 +4,6 @@ from .exceptions import * # noqa: F403 from .sources import * # noqa: F403 from .templates import * # noqa: F403 +from .templates import Path as Path from .util import * # type: ignore[no-redef] # noqa: F403 from .yaml_util import * # noqa: F403 diff --git a/docs/changelog.rst b/docs/changelog.rst index 733a60e..56ef2b9 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,8 @@ Unreleased newer versions). [#189](https://github.com/beetbox/confuse/issues/189) - Narrow `Path` template shorthand handling to concrete `pathlib.Path` values for more accurate type checking. +- Fix `confuse.Path` which now points to `confuse.templates.Path` instead of + `pathlib.Path`. v2.2.0 ------