Skip to content

Allow per-call CCD extension overrides - #960

Merged
mwcraig merged 4 commits into
astropy:mainfrom
nomad3:fix-817-ccd-extension-override
Jul 31, 2026
Merged

Allow per-call CCD extension overrides#960
mwcraig merged 4 commits into
astropy:mainfrom
nomad3:fix-817-ccd-extension-override

Conversation

@nomad3

@nomad3 nomad3 commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an optional ext argument to ImageFileCollection.ccds() for selecting a FITS data extension per call
  • keep the collection's own extension unchanged for primary-header summaries and filtering
  • continue supporting ccd_kwargs["hdu"], avoid mutating caller dictionaries, and reject contradictory selectors explicitly
  • cover integer, extension-name, (name, version), and zero-valued selectors with offline multi-extension FITS regressions
  • correct the generated NumPy-style parameter indentation so the ccds() docstring builds cleanly under Sphinx warnings-as-errors

Compatibility boundary: ext is now reserved as the per-call selector; code that needs to filter an EXT header keyword should filter the collection before calling ccds().

Fixes #817

Validation

  • initial override/conflict regression on untouched main: 7 failed
  • python -m pytest ccdproc/tests/test_image_collection.py -q — 85 passed
  • full NumPy suite — 354 passed, 29 skipped
  • full Dask suite — 349 passed, 34 skipped
  • full JAX x64 suite — 347 passed, 29 skipped, 7 established xfails
  • inspected the final cleaned docstring: ext is a parameter and every description line is indented beneath it
  • Black, Ruff, git diff --check, and git show --check

AI assistance disclosure

OpenAI Codex was used for repository inspection, test design, implementation, CI diagnosis, and automated review. The contributor has completed the final review and takes responsibility for the contribution's correctness and maintenance.

Checklist

  • For new contributors: Did you add yourself to the AUTHORS.rst file? (Present on current main through merged Exclude masked weights from average combinations #952.)
  • For documentation changes: Does the commit message include a [skip ci]? (Not a documentation-only change.)

For new functionality:

  • Did you add an entry to CHANGES.rst?
  • Did you include a meaningful docstring with Parameters?
  • Does the commit message include Fixes #817?
  • Did you include tests for the new functionality?
  • Does this PR add, rename, move, or remove an existing function or parameter? (It adds the optional ext parameter.)

nomad3 added a commit to nomad3/ccdproc that referenced this pull request Jul 19, 2026
Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
nomad3 added a commit to nomad3/ccdproc that referenced this pull request Jul 27, 2026
Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
@nomad3
nomad3 force-pushed the fix-817-ccd-extension-override branch from df72651 to 81fe53d Compare July 27, 2026 04:21
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.82%. Comparing base (b78287c) to head (21041b0).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #960   +/-   ##
=======================================
  Coverage   95.82%   95.82%           
=======================================
  Files           8        8           
  Lines        1628     1629    +1     
=======================================
+ Hits         1560     1561    +1     
  Misses         68       68           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@nomad3
nomad3 marked this pull request as ready for review July 27, 2026 13:00
@mwcraig
mwcraig requested a review from Copilot July 29, 2026 15:11

Copilot AI left a comment

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.

🟢 Ready to approve

The API change is implemented with explicit conflict handling, avoids side effects on caller inputs, and is covered by focused regression tests for the key selector modes and edge cases.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

This PR adds a per-call FITS extension override to ImageFileCollection.ccds() so callers can read CCD data from a different HDU than the collection’s configured ext, while preserving the collection extension for summaries/filtering (as needed for primary-header selection workflows like ESO multi-extension files).

Changes:

  • Add ext argument to ImageFileCollection.ccds() with explicit conflict detection against ccd_kwargs["hdu"].
  • Avoid mutating caller-provided ccd_kwargs by copying and internally extracting hdu selection in the generator.
  • Add regression tests covering integer, extension-name, (name, version) selectors, zero-valued selectors, and selector conflict behavior; plus a changelog entry.
File summaries
File Description
CHANGES.rst Documents the new ccds() per-call extension override feature.
ccdproc/tests/test_image_collection.py Adds coverage for extension override behavior (including ext=0 and conflict checks) and verifies no mutation of inputs/summary.
ccdproc/image_collection.py Implements ccds(ext=...) and supports ccd_kwargs["hdu"] without mutating caller dictionaries; updates docstring templating.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Low

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@mwcraig mwcraig left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for picking up #817 — per-call extension selection is a real gap, and the mechanics here are sound: the _generator change (ccd_hdu = ccd_kwargs.pop("hdu", self.ext) on a copy, so the caller's dict isn't mutated) is exactly right, and the tests for the selector paths are thorough.

However, the ext= parameter on ccds() introduces a silent breaking change, and after discussion we'd like the PR reshaped to avoid it.

The problem: ccds()'s **kwd namespace is a header-keyword filter — on current main, ccds(ext=1) means "the files whose EXT header card equals 1". This PR intercepts ext unconditionally, so that same call now silently yields HDU 1 of every file in the collection — wrong data, no warning. String values that used to filter (ccds(ext='SCI')) now raise KeyError instead. And the sibling methods (hdus(), headers(), data(), files_filtered()) still treat ext= as a filter, so one keyword would mean opposite things across methods that share a docstring template promising that any **kwd keyword filters.

Requested change — drop the ext= parameter and make ccd_kwargs={"hdu": ...} the supported route. The nice thing is that your _generator fix already does all the real work: with it, ccds(ccd_kwargs={"hdu": 1}) works today, overrides the collection-level default, and can't collide with filtering because ccd_kwargs was never part of the filter namespace. hdu also matches the underlying fits_ccddata_reader(hdu=...) keyword, so it's the honest name. Concretely:

  1. Remove the ext=None parameter and the ext/ccd_kwargs['hdu'] conflict check from ccds().
  2. Keep the _generator change as-is — it's the actual fix.
  3. Re-point the tests at the hdu route (your parametrization already covers it — it's mostly deleting the ext variants and the conflict-error test).
  4. Update the docstring addition to document ccd_kwargs["hdu"] (int, name string, or (name, ver) tuple) as the way to override the collection's extension per call.
  5. Reword the CHANGES.rst entry to match.

That keeps everything #817 asked for while leaving the filter contract of **kwd untouched. Sorry to ask for a restructure after you've built the ext= plumbing — the selector logic and tests all carry over, it's really just moving the entry point.

This review comment was written by Claude (via Claude Code) following Matt's review of the PR; Matt has reviewed and approved its content before posting.

nomad3 added 4 commits July 30, 2026 09:57
Fixes astropy#817

Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
Signed-off-by: Simon Aguilera <saguilera1608@gmail.com>
@nomad3
nomad3 force-pushed the fix-817-ccd-extension-override branch from 81fe53d to 21041b0 Compare July 30, 2026 14:03

@mwcraig mwcraig left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @nomad3 -- I really appreciate all of the PRs!

@mwcraig
mwcraig merged commit de10041 into astropy:main Jul 31, 2026
19 checks passed
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.

ImagerFileCollection.ccds() extension override

3 participants