fix(file-based): fire the duplicate-file guard in file-transfer mode - #1111
Draft
devin-ai-integration[bot] wants to merge 2 commits into
Draft
fix(file-based): fire the duplicate-file guard in file-transfer mode#1111devin-ai-integration[bot] wants to merge 2 commits into
devin-ai-integration[bot] wants to merge 2 commits into
Conversation
Co-Authored-By: bot_apk <apk@cognition.ai>
Contributor
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksTesting This CDK VersionYou can test this version of the CDK using the following: # Run the CLI from this branch:
uvx 'git+https://github.com/airbytehq/airbyte-python-cdk.git@devin/1786420148-file-based-duplicate-guard#egg=airbyte-python-cdk[dev]' --help
# Update a connector to use the CDK from this branch ref:
cd airbyte-integrations/connectors/source-example
poe use-cdk-branch devin/1786420148-file-based-duplicate-guardPR Slash CommandsAirbyte Maintainers can execute the following slash commands on your PR:
|
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
DefaultFileBasedStream's duplicate-file guard is supposed to stop two source files from resolving to one output path. It never fires on the configuration where that actually happens (file transfer withpreserve_directory_structureon — the default), because all three of its inputs are wrong:Three things to call out:
use_file_transferis the required gate, notpreserve_directory_structure.validate_config_transfer_modes.preserve_directory_structure()returnsTruewhenever file transfer is off, which is the only reason the old condition also excluded records mode. Dropping the gate entirely would start failing records-mode connections that have same-named files, and records mode has no output path to collide on.source_file_relative_path, noturi. That is the value_get_file_transfer_paths()turns into the staging path and destination object key.source_file_relative_pathmoves up fromUploadableRemoteFiletoRemoteFile(same body,return self.uri) so the guard needs nogetattrfallback;UploadableRemoteFileinherits it unchanged.all_files, notfiles_to_read. With the cursor-filtered list, a duplicate whose partner was synced in an earlier incremental run is invisible and the file is silently overwritten.list_files()is@cached, so this costs no extra listing calls.DuplicatedFilesError's message hardcoded "Duplicate file names are not allowed if the Preserve Sub-Directories in File Paths option is disabled", which stops being true once the guard runs in both modes; it now names the resolved output path and still lists the conflicting source URIs.FailureTypeis unchanged (config_error— the user must rename or remove a file).Connections that are green today while silently overwriting one of two duplicate files will start failing. That is the intended outcome, but it is support-visible: please pair this with a release note and a heads-up to support rather than shipping it quietly.
Resolves https://github.com/airbytehq/oncall/issues/13269:
Coverage
With
preserve_directory_structure=trueand file transfer on:/preserve=false, incremental)Reportvs fileReport.docxdata+ folderdatain one parentThis is change 3 of 3 from airbytehq/oncall#12872. It is independent of #1078 (unique per-file staging directory, still open): that one stops the
FileNotFoundExceptioncrash, this one makes the remaining destination-key overwrite loud instead of silent.Test Coverage
Added to
unit_tests/sources/file_based/stream/test_default_file_based_stream.py:test_duplicate_uris_raise_when_preserving_directory_structure— identical URIs,preserve=True, file transfer on.test_duplicate_detected_across_incremental_syncs—list_files()returns A and B, cursor returns only B; must still raise.test_guard_compares_source_file_relative_path— distincturi, collidingsource_file_relative_path.test_same_basename_different_folders_allowed_when_preserving— regression guard for the correct-behaviour case.test_records_mode_never_raises_on_duplicate_uris—use_file_transfer=Falsemust never raise.test_when_compute_slices_with_duplicatesupdated for the new message text.The first three fail on
mainwith the source changes reverted and the tests retained. Full run:poetry run pytest unit_tests/sources/file_based -q→ 799 passed, 1 skipped;ruff check,ruff format, andmypy --config-file mypy.ini airbyte_cdkall clean.Declarative-First Evaluation
Not applicable — the change is in the Python file-based CDK's stream/reader layer, not in a declarative connector manifest. No declarative component influences how the CDK resolves file-transfer output paths.
Versioning
No connector version bump or changelog entry: this repo publishes from release notes and
pyproject.toml's version is dynamic. Not a breaking change under the connector breaking-change definition (no schema, spec, stream, or state change) — but see the release-risk note above, since previously-passing syncs will now fail loudly.Link to Devin session: https://app.devin.ai/sessions/f5033729977945f5b915e68051d199c2