Standalone: set PYTHONPATH=AIRFLOW_HOME to match runtime image#2155
Merged
Conversation
Standalone mode previously set PYTHONPATH=AIRFLOW_HOME/include only, which diverged from the Astro runtime Docker image. The runtime image sets PYTHONPATH=AIRFLOW_HOME (see astro-runtime image/Dockerfile), making every subdirectory of the project root importable as a namespace package — e.g. `from include.utils import x` and `from dags.my_blueprints import Extract`. Because standalone only had include/ on PYTHONPATH, imports that work in production (and pass `astro deploy --parse`) failed when the same project was tested locally with `astro dev start --standalone` or `astro dev pytest --standalone`. This change aligns standalone with production by setting PYTHONPATH to AIRFLOW_HOME. Existing `from include.<module> import …` imports continue to work (include/ is still findable as a namespace package under AIRFLOW_HOME). Users who relied on flat `import <module>` from include/ will need to switch to the prefixed form, which is what the official docs already teach (https://www.astronomer.io/docs/learn/airflow-importing-custom-hooks-operators).
Coverage Report for CI Build 8Coverage increased (+0.002%) to 39.653%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
jlaneve
approved these changes
May 22, 2026
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
Aligns standalone-mode
PYTHONPATHwith the production Astro runtime Docker image.Standalone mode previously set
PYTHONPATH=AIRFLOW_HOME/includeonly. That diverged from the runtime image, which setsPYTHONPATH=AIRFLOW_HOME(astro-runtime/image/Dockerfile#L19). This change brings standalone in line with the image.Why
The previous behavior was introduced by #2060 with the stated intent of "mirroring the docker image" — but the docker image actually bakes
AIRFLOW_HOMEintoPYTHONPATH, notAIRFLOW_HOME/include. The comment in the original code was also factually inaccurate. So in practice, imports that work in production (and passastro deploy --parse) could fail when the same project was tested locally withastro dev start --standaloneorastro dev pytest --standalone.Concrete example that breaks under the current code but works in production:
The prefixed
from include.<module> import …pattern that the official docs recommend (Custom hooks and operators) continues to work both before and after this change.Behavior change
from include.foo import bar— continues to work (include/ is findable as a namespace package under AIRFLOW_HOME).from dags.foo import bar— now works (matches production).import foowherefoo.pylives flat ininclude/— no longer resolves under standalone. This only ever worked under standalone (never in docker mode), so the breakage surface is small. The fix for users is to switch tofrom include.foo import …, which the docs already teach as the canonical pattern.Test plan
go test ./airflow/ -run 'TestAirflow/TestStandaloneBuildEnv'(12 subtests, all pass)PYTHONPATH:PYTHONPATH=/some/inherited/path go test ./airflow/ -run 'TestAirflow/TestStandaloneBuildEnv$'passes (the test now callst.Setenv("PYTHONPATH", "")so the strict equality assertion doesn't flake on developer/CI envs)from dags.<module> import …in a Python DAG underastro dev pytest --standalone. Live scheduler loads the DAG;astro dev pytest --standalone(DagBag scan) passes