Skip to content

Conversation

@aaronsteers
Copy link
Contributor

@aaronsteers aaronsteers commented Dec 17, 2025

Summary

Fixes #868 - Declarative YAML connectors were not receiving user config, causing template expressions like {{ config['hello'] }} to resolve to empty values.

This PR threads the config parameter from get_source() through get_connector_executor() to DeclarativeExecutor, so declarative manifests can access user-provided configuration.

Key changes:

  • Add config parameter to DeclarativeExecutor.__init__()
  • Add config parameter to get_connector_executor() factory
  • Pass config from get_source() through the call chain
  • Use config.copy() if config is not None else {} to avoid mutable default argument issues (B006 lint error)

This supersedes PR #869 from @adileo, incorporating their fix plus addressing the mutable default argument issues flagged by CodeRabbit.

Review & Testing Checklist for Human

  • Test with a declarative manifest - Create a source with source_manifest=True or a custom manifest dict, pass a config with values, and verify the connector receives the config (e.g., template {{ config['api_key'] }} resolves correctly)
  • Verify no mutation of caller's config - The .copy() call should prevent the executor from mutating the original config dict passed by the caller
  • Check all DeclarativeExecutor instantiation sites - Confirm the two call sites in util.py (lines 335 and 351) are the only places that need updating

Notes

Summary by CodeRabbit

Release Notes

  • New Features
    • Added optional configuration parameter support during executor initialization, enabling more flexible configuration management across the initialization chain while ensuring configuration objects remain isolated and unmodified during setup.

✏️ Tip: You can customize this high-level summary in your review settings.

adileo and others added 5 commits November 16, 2025 18:22
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Change config parameter default from {} to None in DeclarativeExecutor.__init__
- Change config parameter default from {} to None in get_connector_executor
- Use config.copy() to avoid mutating caller's dict
- Add missing Any import to util.py

This fixes the B006 lint error (mutable default argument) which could cause
shared state bugs across multiple calls.

Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration
Copy link
Contributor

Original prompt from AJ Steers
Received message in Slack channel #ask-devin-ai:

@Devin - Triage the latest 10 issues in the PyAirbyte repo that are from external community members / contributors. Don't comment on them directly but look into them and prepare for me a set of suggestions on how to disposition each.
Thread URL: https://airbytehq-team.slack.com/archives/C08BHPUMEPJ/p1765247038245949

@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@github-actions
Copy link

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

Testing This PyAirbyte Version

You can test this version of PyAirbyte using the following:

# Run PyAirbyte CLI from this branch:
uvx --from 'git+https://github.com/airbytehq/PyAirbyte.git@devin/fix-pr-869-mutable-defaults' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/fix-pr-869-mutable-defaults'

Helpful Resources

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /fix-pr - Fixes most formatting and linting issues
  • /poetry-lock - Updates poetry.lock file
  • /test-pr - Runs tests with the updated PyAirbyte
  • /prerelease - Builds and publishes a prerelease version to PyPI

Community Support

Questions? Join the #pyairbyte channel in our Slack workspace.

📝 Edit this welcome message.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

📝 Walkthrough

Walkthrough

The changes propagate a config parameter from the public API through the executor initialization chain (get_sourceget_connector_executorDeclarativeExecutor), ensuring configuration is available when the declarative source is instantiated rather than remaining empty at initialization.

Changes

Cohort / File(s) Change Summary
Executor configuration propagation
airbyte/_executors/declarative.py, airbyte/_executors/util.py
Added optional config: dict[str, Any] | None = None parameter to DeclarativeExecutor.__init__ and get_connector_executor(). The config is now initialized in DeclarativeExecutor at construction time rather than remaining empty, and is propagated through both code paths where DeclarativeExecutor is instantiated in get_connector_executor().
Source API integration
airbyte/sources/util.py
Propagates config parameter from get_source() to get_connector_executor(), ensuring the executor receives the same configuration dict provided to the Source object.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Parameter threading consistency: Verify that config is correctly forwarded through all three call sites without omission or incorrect placement.
  • Issue resolution validation: Confirm the fix addresses the root cause in issue #868 by checking that self._config_dict is now populated during initialization and accessible when declarative_source property is invoked.
  • Type annotation compliance: Ensure dict[str, Any] | None type hints are consistent across all three files.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: passing user-provided config down to DeclarativeExecutor instead of leaving it empty, which is the primary objective of the PR.
Linked Issues check ✅ Passed All coding requirements from issue #868 are met: config parameter added to DeclarativeExecutor.init, threaded through get_connector_executor and get_source, and config.copy() pattern used to prevent mutation.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the config propagation issue; no unrelated modifications or refactoring detected across the three modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch devin/fix-pr-869-mutable-defaults

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
airbyte/_executors/declarative.py (1)

44-51: Config parameter correctly added to signature.

The new config parameter with type dict[str, Any] | None = None follows Python best practices by using None as the default instead of a mutable default argument. This allows the executor to receive user-provided configuration at initialization time, resolving issue #868.

One minor observation: the docstring (lines 52-59) doesn't explicitly document the new config parameter—wdyt about adding a brief note?

If you'd like to document it, consider:

     """Initialize a declarative executor.

+    Args:
+        name: Connector name.
+        manifest: Declarative manifest (dict or Path to YAML file).
+        config: Optional user-provided configuration dict.
+        components_py: Optional custom components.py content or path.
+        components_py_checksum: Optional checksum for components_py validation.
+
     - If `manifest` is a path, it will be read as a json file.
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2ea38f and 72d6e76.

📒 Files selected for processing (3)
  • airbyte/_executors/declarative.py (2 hunks)
  • airbyte/_executors/util.py (4 hunks)
  • airbyte/sources/util.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: aaronsteers
Repo: airbytehq/PyAirbyte PR: 415
File: airbyte/cli.py:0-0
Timestamp: 2024-10-09T21:11:11.706Z
Learning: In `_resolve_source_job`, returning `None` when `config` is falsy distinguishes between empty config and not-yet-provided config, allowing `_resolve_config()` to handle non-null inputs effectively.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Pytest (All, Python 3.10, Windows)
  • GitHub Check: Pytest (All, Python 3.10, Ubuntu)
  • GitHub Check: Pytest (Fast)
  • GitHub Check: Pytest (No Creds)
  • GitHub Check: Pytest (All, Python 3.11, Windows)
  • GitHub Check: Pytest (All, Python 3.11, Ubuntu)
🔇 Additional comments (6)
airbyte/_executors/declarative.py (1)

70-70: Excellent use of config.copy() to prevent mutation.

Creating a copy of the provided config ensures that subsequent modifications (like injecting components at lines 78-81) don't mutate the caller's dictionary. Using a shallow copy is appropriate here since only top-level keys are added to config_dict.

airbyte/_executors/util.py (4)

8-8: Import addition looks good.

The Any import is necessary for the config: dict[str, Any] | None type hint and is correctly placed in alphabetical order.


172-172: Config parameter correctly added to factory function.

The new parameter properly extends get_connector_executor() to accept configuration, with the correct type hint and safe default value. The parameter is positioned at the end of the signature, which is a reasonable choice given the function already has many parameters.


335-340: Config correctly passed to DeclarativeExecutor (first instantiation site).

When source_manifest is a dict or Path, the config is now properly threaded to the DeclarativeExecutor, ensuring user-provided configuration is available to the declarative source.


351-357: Config correctly passed to DeclarativeExecutor (second instantiation site).

When the manifest is fetched from a URL, the config is properly propagated to the DeclarativeExecutor. Both instantiation sites (lines 335-340 and 351-357) now consistently receive the config parameter, ensuring declarative sources always have access to user-provided configuration.

airbyte/sources/util.py (1)

131-131: Config parameter correctly threaded to executor factory.

The config is now properly passed from get_source() to get_connector_executor(), ensuring all DeclarativeExecutor instantiation sites receive the user-provided configuration. Both manifest-based execution paths (Path and URL-based) pass config through correctly.

@github-actions
Copy link

PyTest Results (Fast Tests Only, No Creds)

348 tests  ±0   348 ✅ ±0   5m 58s ⏱️ +13s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 72d6e76. ± Comparison against base commit a2ea38f.

@github-actions
Copy link

PyTest Results (Full)

416 tests  ±0   399 ✅ ±0   24m 32s ⏱️ - 2m 22s
  1 suites ±0    17 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 72d6e76. ± Comparison against base commit a2ea38f.

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.

DeclarativeExecutor passing down empty configs

3 participants