Skip to content

af: catch OSError in _read_yaml so non-file ASTRO_HOME degrades gracefully#205

Merged
jlaneve merged 2 commits intomainfrom
julian/af-read-yaml-oserror
May 1, 2026
Merged

af: catch OSError in _read_yaml so non-file ASTRO_HOME degrades gracefully#205
jlaneve merged 2 commits intomainfrom
julian/af-read-yaml-oserror

Conversation

@jlaneve
Copy link
Copy Markdown
Contributor

@jlaneve jlaneve commented May 1, 2026

summary

found while smoke-testing the 0.7.0a1 alpha (#204): _read_yaml only caught FileNotFoundError, so any other read failure leaked through as an uncaught exception that detect_version then masked as "Failed to detect Airflow version"

simplest repro: ASTRO_HOME=/dev/null af api version (/dev/null/config.yaml raises NotADirectoryError, which is an OSError but not FileNotFoundError). same for permission-denied or broken symlinks

what changed

  • _read_yaml now catches OSError instead of FileNotFoundError (both the initial read and the partial-write retry)
  • regression test: ASTRO_HOME=/dev/null now surfaces AstroNotLoggedInError cleanly

test plan

  • uv run pytest --ignore=tests/integration (490/490)
  • uv run prek run --all-files
  • manual smoke: ASTRO_HOME=/dev/null af api version now reports "No astro context. Run astro login first." instead of "Failed to detect Airflow version"

…fully

_read_yaml only caught FileNotFoundError, so reading /dev/null/config.yaml
(NotADirectoryError) or any other OSError-shape failure (permission denied,
broken symlink) leaked out of the resolver as an uncaught exception that
detect_version then masked as "Failed to detect Airflow version".

Catch the broader OSError in both the initial read and the partial-write
retry, so the resolver consistently surfaces "No astro context. Run astro
login first." for any reason the file isn't readable.

Found via smoke testing 0.7.0a1 with ASTRO_HOME=/dev/null.
try:
text = path.read_text()
except FileNotFoundError:
except OSError:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Catching all of OSError is broader than the /dev/null repro needs. PermissionError on a real config (e.g. user's ~/.astro/config.yaml chmod'd 000) will now silently fall through to "Run astro login first", which is misleading — the file is there, it's just unreadable. Was the broad catch intentional, or would (FileNotFoundError, NotADirectoryError, IsADirectoryError) be enough to fix the reported bug while still surfacing genuine read failures?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good catch, narrowed in c860abf. now only catches the three OSError shapes that actually mean 'no readable config file' (FileNotFoundError, NotADirectoryError, IsADirectoryError). PermissionError and other OSErrors propagate so chmod 000 surfaces clearly instead of dead-ending at 'run astro login'

# global astro state. Reading /dev/null/config.yaml raises
# NotADirectoryError (an OSError, NOT FileNotFoundError); the
# resolver should still surface "no session" cleanly.
monkeypatch.setenv("ASTRO_HOME", "/dev/null")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

/dev/null is Unix-only. test_config.py::test_load_with_dev_null_via_env (line 549) already has the right pattern for this: os.devnull plus a pytest.skip if it's a regular file on the platform. Worth mirroring that here so the test doesn't fail on Windows.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed in c860abf, mirrors the test_load_with_dev_null_via_env pattern (os.devnull + skip when it's a regular file). thanks for the pointer

Copy link
Copy Markdown

@akshayarora akshayarora left a comment

Choose a reason for hiding this comment

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

Yeah, this is a clean and minimal fix with a good explanatory docstring. Thanks!

Address PR review feedback:

- _read_yaml now catches the specific OSError shapes that mean
  "config doesn't exist as a file" (FileNotFoundError, NotADirectoryError,
  IsADirectoryError) instead of swallowing all OSError. PermissionError
  on a real config (chmod 000) propagates so the user gets a useful
  error rather than a misleading "run astro login".
- Test uses os.devnull + skip-if-regular-file, mirroring the pattern in
  test_config.py::test_load_with_dev_null_via_env so it doesn't fail on
  Windows (where os.devnull is "nul" and behaves differently).
@jlaneve jlaneve merged commit 7cbaab4 into main May 1, 2026
10 checks passed
@jlaneve jlaneve deleted the julian/af-read-yaml-oserror branch May 1, 2026 18:46
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.

3 participants