Skip to content

fix: Accept a path object as an override file path - #572

Merged
kinyoklion merged 2 commits into
feat/overridesfrom
rlamb/overrides-python-file-source-paths
Nov 10, 2026
Merged

kinyoklion merged 2 commits into
feat/overridesfrom
rlamb/overrides-python-file-source-paths

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Requirements

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions
  • Sync/async parity: matching changes made to async_* siblings (or N/A). N/A: LDClient and AsyncLDClient use the same FileOverrideSourceBuilder.

Related issues

Describe the solution you've provided

FileOverrideSourceBuilder accepted one path as a str, or a list of paths. A single pathlib.Path, or any other os.PathLike, was passed to list(). A path object is not iterable, so the constructor raised TypeError: 'PosixPath' object is not iterable. The Bugbot finding describes a different failure, a path split into its components that fails every reload, but that cannot happen. The constructor raises before a client exists.

The constructor now treats a str or an os.PathLike as a single path, and converts every path with os.fspath. A path that does not name a string path raises TypeError from the constructor, with a message that names the value. That includes bytes (given alone, in a list, or named by a path object), an int, and None. bytes and bytearray count as single values, so a bare bytes path is named whole instead of being read as a sequence of integers. The type hint is Sequence rather than List, so that type checkers accept a list of path objects but not a set, whose order is not fixed. The docstring says that paths may be path objects.

Tests cover:

  • a single path object;
  • a list of path objects, which already worked;
  • a path object whose string form differs from its path, as with os.DirEntry;
  • a source that loads a file given as a path object;
  • the rejection of each of the values above.

Each of six broken variants of the constructor fails at least one of these tests, including the original code and a variant that converts with str() instead of os.fspath.

Describe alternatives you've considered

Leaving the builder to accept only strings, as its type hint said. pathlib is the usual way to build paths, a list of path objects already worked, and the error did not say what was wrong.

Additional context

This PR is stacked on #530, the top of the overrides stack, so that the approved PRs below it do not change. Retarget it as the PRs below it merge.

The review of this change found three existing gaps that this PR leaves alone:

  • An empty path resolves to the working directory, and its reads keep failing.
  • In polling mode, a path that contains a NUL character makes the source fail to start, so the client runs without overrides. In watching mode, the reload fails and keeps retrying.
  • The file data sources treat a tuple of paths differently from a list.

Testing: mypy ldclient, isort --check and pycodestyle pass locally. The test suite passes (2,111 tests). It was run without the Redis, DynamoDB and Consul store integration tests, which need servers that were not running. CI runs only for PRs based on main or feat/**, so it will not run on this PR until it is retargeted.

Opened from termag


Note

Overview
Fixes a constructor bug where a single pathlib.Path (or other os.PathLike) was passed to list(), causing TypeError: 'PosixPath' object is not iterable.

FileOverrideSourceBuilder now wraps a lone str, bytes/bytearray, or PathLike as one path, normalizes every entry with os.fspath() (so objects like os.DirEntry use their filesystem path, not str()), and stores string paths. Invalid inputs (bytes paths, ints, None, path objects that do not resolve to a str) fail fast with an explicit TypeError. Type hints use Sequence plus PathLike so callers can pass path objects while unordered collections like set are discouraged.

New tests cover single/list path objects, __fspath__ behavior, invalid types, and loading overrides from a path object.

Reviewed by Cursor Bugbot for commit 154b5b8. Bugbot is set up for automated code reviews on this repo. Configure here.

@kinyoklion

Copy link
Copy Markdown
Member Author

bugbot review

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@kinyoklion

Copy link
Copy Markdown
Member Author

bugbot review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit a1bda43. Configure here.

@kinyoklion
kinyoklion marked this pull request as ready for review November 10, 2026 20:55
@kinyoklion
kinyoklion requested a review from a team as a code owner November 10, 2026 20:55
@kinyoklion
kinyoklion force-pushed the rlamb/overrides-python-contract-tests branch from 7e42fc2 to 5d19e57 Compare November 10, 2026 22:24
@kinyoklion
kinyoklion force-pushed the rlamb/overrides-python-file-source-paths branch from a1bda43 to 5981654 Compare November 10, 2026 22:24
Base automatically changed from rlamb/overrides-python-contract-tests to feat/overrides November 10, 2026 23:27
FileOverrideSourceBuilder passed anything other than a str to list(), so a single pathlib.Path raised TypeError from the constructor. A str or an os.PathLike is now one path, and every path is converted with os.fspath. A path that does not name a string path raises TypeError.
A bare bytes or bytearray value is a single path, and a TypeError from os.fspath is replaced by the builder's own message, so every rejected path is named. The type hint is Sequence, so that type checkers reject a set, whose order is not fixed. Tests cover a path object whose string form differs from its path and every rejected value.
@kinyoklion
kinyoklion force-pushed the rlamb/overrides-python-file-source-paths branch from 5981654 to 154b5b8 Compare November 10, 2026 23:29
@kinyoklion
kinyoklion merged commit 25323bf into feat/overrides Nov 10, 2026
14 of 16 checks passed
@kinyoklion
kinyoklion deleted the rlamb/overrides-python-file-source-paths branch November 10, 2026 23:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants