Repository navigation
feat: Add the file-based override source - #529
Draft
kinyoklion wants to merge 7 commits into
Draft
kinyoklion wants to merge 7 commits into
kinyoklion wants to merge 7 commits into
Conversation
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
September 28, 2026 20:29
042fce2 to
0e55650
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
September 28, 2026 20:29
021778c to
2074b74
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
September 30, 2026 20:31
0e55650 to
c79f244
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
September 30, 2026 20:31
2074b74 to
1950d45
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 1, 2026 23:43
c79f244 to
352d360
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 1, 2026 23:43
1950d45 to
3e47045
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 3, 2026 01:18
352d360 to
9f4108c
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 3, 2026 01:18
3e47045 to
cfb781a
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 13, 2026 21:02
9f4108c to
051cf7d
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 13, 2026 21:02
cfb781a to
ea4dc19
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 13, 2026 22:40
051cf7d to
0124739
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 13, 2026 22:40
ea4dc19 to
3de11ab
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 16, 2026 21:34
0124739 to
224677f
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 16, 2026 21:34
bb5a108 to
5e42ebc
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 28, 2026 22:17
224677f to
2b471ae
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 28, 2026 22:17
5e42ebc to
314dea2
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 28, 2026 22:40
2b471ae to
c5a69c9
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 28, 2026 22:40
314dea2 to
4bace41
Compare
Member
Author
|
bugbot review |
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 29, 2026 16:48
c5a69c9 to
70ada89
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 29, 2026 16:48
99b851f to
fac9ec8
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
October 29, 2026 17:16
70ada89 to
cad8f0b
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
October 29, 2026 17:16
fac9ec8 to
0415ec1
Compare
Adds ldclient.integrations.overrides.FileOverrideSourceBuilder, the file-based override source described by the OVERRIDE specification. The source reads one or more JSON or YAML files in the file data source document format, with optional flags, flagValues, and segments members, and supplies each successful load to the SDK's override sink as a full snapshot. Files are combined in the configured order. The duplicate keys handling is fail by default, which rejects the reload and keeps the previously loaded overrides, or ignore, which keeps the first file's entry. A configured file that does not exist contributes no overrides, so a file can be created later and deleting a file removes its overrides. A file that exists but cannot be read or parsed fails that reload, the last good overrides stay in effect, the failure is logged, and the load is retried after a bounded delay and on the next detected change. Change detection is one of two modes: polling, the default, examines the files once per second by default with a one second minimum, and watching reacts to file system notifications through the watchdog package. Watching without the watchdog package and a builder with no paths are construction errors. The initial load completes during client construction. Every applied change is logged at Info level with the overrides in effect and what each configured file supplied.
…l of the file override source Change detection is set up before the initial load, so an edit made while the files are first read is picked up. Close stops the reloader even when the change detector fails to close. The builder rejects a poll interval that is not a number or not finite.
…ntries as duplicate keys A path listed more than once would make every entry of that file a duplicate of itself: under the default fail handling the load failed, and under ignore the first listing won by accident. The builder now drops the repeats, keeps the first occurrence in its place in the order, and logs a warning once at build time. This is the behavior the Node SDK has.
…t on Windows The builder dropped repeated paths by exact string match, so on Windows a path listed twice in different case survived as two paths, and every key of that file failed as a duplicate of itself under the default fail handling. Paths are now compared with os.path.normcase, which ignores case on Windows and compares exactly elsewhere. The first spelling keeps its place in the order.
… SDKs A flagValues entry becomes a flag without client-side availability, so an all-flags state for client-side SDKs leaves it out even when the flag it overrides is client-side. A full definition with clientSide is the way to override such a flag. A test pins both.
The override source keeps the overrides in effect while it finds a file empty during an in-place rewrite. A YAML file without the pyyaml package is now a configuration error when the source is built, since the file name chooses the format and such a file can never load. The builder docs say that the file name decides the format, that files must be UTF-8, that files can be rewritten in place, how to remove a file's overrides, that an empty JSON file is not a valid document, and that a YAML file is best replaced in one operation because a partly written one can still parse. End-to-end tests rewrite the files in place, slowly, in watching and polling modes, for JSON and YAML, and check that neither the source nor a client evaluating the flag ever goes without the override.
kinyoklion
force-pushed
the
rlamb/overrides-python-events
branch
from
November 3, 2026 23:56
cad8f0b to
b6c14aa
Compare
kinyoklion
force-pushed
the
rlamb/overrides-python-file-source
branch
from
November 3, 2026 23:56
0415ec1 to
a8e9294
Compare
This was referenced Nov 3, 2026
Member
Author
|
bugbot review |
There was a problem hiding this comment.
✅ 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 a8e9294. Configure here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is the fifth step of the flag overrides port described by the OVERRIDE specification. It is based on the events branch because the phases are stacked; retarget to
feat/overridesonce that branch merges.ldclient.integrations.overrides.FileOverrideSourceBuilderis the public entry point. It is passed todatasystem.ConfigBuilder.overrides(...)and builds an override source that reads one or more local files in the file data source document format (optionalflags,flagValues, andsegmentsmembers, JSON or YAML) and supplies each successful load to the SDK's override sink as a full snapshot.flagValuesentries expand into full flag definitions, so the layer holds only full entities; as the specification describes for a value-only override, the expansion is a flag that is on and serves its single variation as the fallthrough, so the evaluation reason kind isFALLTHROUGH. The existing file data sources keep their current behavior, including their ownflagValuesexpansion.Behavior:
.yamlor.ymlis YAML, which needs thepyyamlpackage, and any other file is JSON. Files must be UTF-8. A YAML file configured withoutpyyamlis a construction error, since it could never load. An empty JSON file is not a valid document, nor is JSON that is not an object, such asnull; an empty YAML file has no entries.duplicate_keys_handlingisfailby default, which rejects the reload and keeps the previously loaded overrides, orignore, which keeps the first configured file's entry.{}also removes a file's overrides.change_detectionis one of two alternatives.polling(the default) compares modification time and size on an interval, one second by default with a one second minimum; a lower interval is raised to the minimum with a warning, and a value that is not a finite number, or longer than the runtime can wait, is a construction error.watchinguses thewatchdogpackage and is a construction error when the package is not installed. Notifications are debounced so a burst from one edit produces one reload.start, which the data system calls during client construction, so an override present at startup takes effect from the first evaluation.Flag overrides in effect: 2 flags, 1 segment (/etc/ld/a.json: 2 flags, 1 segment; /etc/ld/b.json: absent), orFlag overrides: none in effect (...).change_detectionorduplicate_keys_handlingvalues raiseValueErrorwhen set. This is stricter than the Go builder, which treats an unrecognized duplicate keys handling asfail. A path listed more than once is logged at warning level and the repeats are ignored; the first occurrence keeps its place in the order. Paths are compared the way the platform compares file names (os.path.normcase): without regard to case on Windows, exactly elsewhere.The module is added to the API reference (
docs/api-integrations.rst) and every public docstring carries the experimental note. The public docs say what an application needs (the format rule, UTF-8, in-place rewrites, how to remove overrides, replacing YAML in one operation); the hold's mechanics are described in the internal docstrings and here.Tests cover the builder validation and defaults (including a YAML file without
pyyaml), synchronous initial load, YAML, multi-file order and duplicate handling, absent files appearing and disappearing, the Info log lines, both change detection modes, last-good retention across a malformed edit in both modes, the automatic retry with no change signal, close semantics, and an end-to-end run throughLDClientwhere a file is added, changed, and cleared with{}while the client never receives LaunchDarkly data. In-place rewrite tests, for JSON and YAML in watching and polling modes, rewrite the file slowly (truncate, pause, write) and check that the source never supplies a snapshot without the override and that a client evaluating the flag throughout serves the old value and then the new one, never the default; they also cover successive rewrites at the source's own timing, an emptied JSON file keeping the overrides, and an emptied YAML file removing them after the retry delay.The in-place rewrite handling was reviewed in eight rounds as #560 (now closed, its changes moved here and into #525). The final mutation check ran 59 mutants against
test_filedata.pyandtest_file_override_source.py: 54 fail a test, and the 5 survivors are equivalent in this code. Both test files ran 10 times in a row with no failure, and the harness'sflag overridessuite passes against the sync and async test services at the top of the stack.SDK-3250
Opened from termag
Note
Overview
Adds experimental local file overrides via
FileOverrideSourceBuilder, wired throughdatasystem.ConfigBuilder.overrides(...). Operators can point at one or more JSON/YAML files (same shape as the file data source) so flag and segment definitions take precedence over LaunchDarkly without restarting the app.The source loads an initial snapshot synchronously on
start, then reloads on polling (default, 1s) or optional watchdog watching. It merges multiple files in order, supports duplicate-key fail/ignore, treats missing files as empty, keeps the last good snapshot on parse/read failures with retry, and avoids clearing overrides during in-place rewrites. Applied sets are logged at Info; API docs cover the newldclient.integrations.overridesmodule.A large integration test suite exercises builder validation, reload semantics, in-place rewrites, and end-to-end
LDClientbehavior includingoverrideAffectedand client-sideall_flags_staterules forflagValuesvs fullflags.Reviewed by Cursor Bugbot for commit a8e9294. Bugbot is set up for automated code reviews on this repo. Configure here.