Skip to content

DM-54789: Add Codecov and mypy-coverage#189

Merged
mfisherlevine merged 8 commits intomainfrom
tickets/DM-54789
May 4, 2026
Merged

DM-54789: Add Codecov and mypy-coverage#189
mfisherlevine merged 8 commits intomainfrom
tickets/DM-54789

Conversation

@mfisherlevine
Copy link
Copy Markdown
Contributor

Runs the test suite inside the LSST scipipe w_latest container on every PR and push to main, then uploads the resulting coverage.xml to Codecov so PRs surface coverage deltas.

mfisherlevine and others added 6 commits April 26, 2026 19:51
Runs the test suite inside the LSST scipipe ``w_latest`` container on
every PR and push to main, then uploads the resulting coverage.xml to
Codecov so PRs surface coverage deltas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`getSite()` previously returned the string `"UNKOWN"` (sic) as its
fallback when none of the known Rubin sites could be detected. That
return value was never intended to be used positively — no caller
handled it, several callers pinned a narrow whitelist of sites and
failed loudly when the fallback was returned, and a dead-code check
in `efdUtils._makeEfdClient` even tested for `"UNKNOWN"` (the
correctly-spelled mirror, which the fallback could never produce).

Replace the `"UNKOWN"` fallback with `"local"`, with the new
semantics:

- `local` means "none of the known Rubin sites could be detected,
  this is probably a developer's laptop".
- Callers that need a real site (talking to S3, EFD, a Butler repo)
  should treat `local` as "no functioning site" and either raise a
  clear error or skip the operation.
- Callers that only branch on `site == "summit"` / `site == "tucson"`
  can treat `local` as a transparent no-op fallthrough — which is
  the existing behaviour of most of them.

Update the docstring to list `local` as a valid return value and
explain the intended handling.

Also fix the dead-code check in `efdUtils._makeEfdClient`: it was
comparing the return value of `getSite()` against `"UNKNOWN"` (with
an N), which could never match the old `"UNKOWN"` (without an N)
fallback. The branch now checks for `"local"` and raises a clearer
error message that spells out why an EFD client cannot be created
off-site.

Other call sites are left unchanged:
- `butlerUtils.makeDefaultButler` already raises `FileNotFoundError`
  for any site not in its `SUPPORTED_SITES` whitelist, and `"local"`
  is correctly not in that list.
- `butlerUtils._configureForSite` and `getLatissDefaultCollections`
  only branch on `"tucson"`, so `"local"` falls through cleanly.
- The four test files in `tests/` that check `site == "jenkins"`
  are unaffected.

This unblocks running `rubintv_production`'s unit tests on a
developer laptop without having to fake a site through env vars.

Written by Claude Code 4.6 Opus (high-effort).
The rubintv_production CI workflow needs a way to flag "we are
running under GHA" so that butler / uploader-bound tests can skip
themselves the same way they would on a developer laptop, but
without conflating CI with ``local`` (the laptop case). Pattern
follows the existing TTS/BTS/SUMMIT/USDF mapping inside the
``RAPID_ANALYSIS_LOCATION`` block: the workflow exports
``RAPID_ANALYSIS_LOCATION=gha`` and getSite() picks it up here.

Compared case-insensitively because the existing values above are
all upper-case shouts and "gha" reads more naturally lower-case in
the workflow file -- accept either.

Also adds RAPID_ANALYSIS_LOCATION to tests/SConscript's pass-through
list so scons-driven test runs see the same env var that getSite()
now consults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two reasons RAPID_ANALYSIS_LOCATION was the wrong signal:

1. Layering. RAPID_ANALYSIS_LOCATION is set (and read for site
   dispatch) by rubintv_production, which is downstream of
   summit_utils in the build graph. summit_utils consulting an env
   var owned by a downstream package is a layering inversion.

2. Coverage. summit_utils' own GHA workflow runs do not set (and
   should not have to set) RAPID_ANALYSIS_LOCATION, so the previous
   check would not fire there -- yet those runs are exactly the
   case where ``site == "gha"`` is most useful.

GitHub Actions sets ``GITHUB_ACTIONS=true`` automatically in every
workflow run, container or not, regardless of which repo's CI is
running. Switching the check to that fixes both problems with a
one-line edit.

Also adds GITHUB_ACTIONS (alongside the existing site-detection env
vars) to tests/SConscript's passThrough list so scons-driven test
runs see the same env var that getSite() now consults. The
RAPID_ANALYSIS_LOCATION entry stays because the K8s pod block above
still reads it for TTS/BTS/SUMMIT/USDF.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the pattern just landed in rubintv_production tickets/DM-54789:

- mypy-coverage.yaml runs mfisherlevine/mypy_coverage on every PR
  and push to main, posting a markdown report as a sticky PR comment
  via marocchino/sticky-pull-request-comment with ``recreate: true``
  so the comment's timestamp updates each push and the PR
  conversation renders it at the bottom (after every commit). The
  walled-off "Excluded files" section is dropped (``include-excluded:
  false`` / ``--no-include-excluded``) because it's noise reviewers
  don't act on. Complementary to the existing mypy_check.yaml -- one
  is pass/fail; this one quantifies annotation coverage.

- codecov.yml sets ``comment.behavior: new`` so the Codecov bot
  delete-and-recreates its PR comment on every upload, achieving the
  same "always at the bottom" behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the matching change in rubintv_production tickets/DM-54789:
the Codecov upload was authenticating fine but coming back with
``{"message":"Repository not found"}``, almost certainly because
the action's auto-detection was resolving to the pre-rename
lsst-sitcom slug instead of the current lsst-so one. Pass the slug
explicitly via ``${{ github.repository }}`` so the lookup is
unambiguous.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mfisherlevine and others added 2 commits April 29, 2026 15:15
The cassettes were recorded with HTTPS_PROXY active at USDF, baking
sdfproxy.sdf.slac.stanford.edu:3128 into every URI. Outside USDF (and
seemingly now also at USDF, after some library or NO_PROXY drift) the
host/port matchers reject every replay. The recorded paths uniquely
identify each service, so matching on method/path/query/body is enough
and makes replay independent of proxy state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

mypy-coverage report

❌ 165 unannotated, 25 partial definition(s).

  • Root: /home/runner/work/summit_utils/summit_utils
  • Config: mypy.ini
  • Files scanned: 60
  • Files excluded: 0

Summary

metric value
❌ body-checked by mypy 78.7%
❌ fully annotated 75.4%
annotated 583
partial 25
unannotated 165

Files with gaps

file fully typed % body checked % unannotated partial
python/lsst/summit/utils/astrometry/anet.py 93.8% 100.0% 0 1
python/lsst/summit/utils/bestEffort.py 83.3% 100.0% 0 1
python/lsst/summit/utils/consdbClient.py 77.3% 100.0% 0 5
python/lsst/summit/utils/guiders/plotting.py 96.3% 96.3% 1 0
python/lsst/summit/utils/guiders/reading.py 84.6% 88.5% 6 2
python/lsst/summit/utils/guiders/transformation.py 68.0% 80.0% 5 3
python/lsst/summit/utils/imageExaminer.py 95.8% 100.0% 0 1
python/lsst/summit/utils/nightReport.py 96.0% 100.0% 0 1
python/lsst/summit/utils/plotRadialAnalysis.py 72.7% 100.0% 0 3
python/lsst/summit/utils/quickLook.py 66.7% 100.0% 0 2
python/lsst/summit/utils/simonyi/mountAnalysis.py 75.0% 87.5% 1 1
python/lsst/summit/utils/simonyi/mountData.py 80.0% 80.0% 1 0
python/lsst/summit/utils/spectrumExaminer.py 93.3% 100.0% 0 1
python/lsst/summit/utils/tmaUtils.py 93.8% 98.5% 1 3
python/lsst/summit/utils/utils.py 97.9% 100.0% 0 1
tests/test_bestEffortIsr.py 25.0% 25.0% 6 0
tests/test_blockUtils.py 40.0% 40.0% 6 0
tests/test_butlerUtils.py 8.1% 8.1% 34 0
tests/test_consdbClient.py 0.0% 0.0% 9 0
tests/test_dateTime.py 33.3% 33.3% 4 0
tests/test_efdUtils.py 15.4% 15.4% 11 0
tests/test_guider.py 94.4% 94.4% 1 0
tests/test_ics.py 33.3% 33.3% 4 0
tests/test_imageExaminer.py 40.0% 40.0% 3 0
tests/test_nightReport.py 10.5% 10.5% 17 0
tests/test_plotting.py 25.0% 25.0% 3 0
tests/test_quickLook.py 27.3% 27.3% 8 0
tests/test_tmaUtils.py 10.3% 10.3% 26 0
tests/test_utils.py 32.0% 32.0% 17 0
tests/utils.py 0.0% 0.0% 1 0

Unannotated definitions (165)

python/lsst/summit/utils/guiders/plotting.py

  • L355 GuiderPlotter.stripPlot._zero (function)

python/lsst/summit/utils/guiders/reading.py

  • L62 make_subplot (function)
  • L536 GuiderData.__iter__ (method)
  • L540 GuiderData.items (method)
  • L545 GuiderData.keys (method)
  • L549 GuiderData.values (method)
  • L554 GuiderData.__getitem__ (method)

python/lsst/summit/utils/guiders/transformation.py

  • L473 stampToCcd (function)
  • L872 DriftResult.__str__ (method)
  • L902 DriftResult.summary (method)
  • L914 getObsAltAz (function)
  • L953 DeltaAltAz (function)

python/lsst/summit/utils/simonyi/mountAnalysis.py

  • L283 plotMountErrors.offset_time_aware (function)

python/lsst/summit/utils/simonyi/mountData.py

  • L122 getAzElRotHexDataForPeriod.calcDeltaT (function)

python/lsst/summit/utils/tmaUtils.py

  • L190 getAzimuthElevationDataForEvent.calcDeltaT (function)

tests/test_bestEffortIsr.py

  • L33 BestEffortIsrTestCase.setUpClass (method)
  • L45 BestEffortIsrTestCase.test_getExposure (method)
  • L54 BestEffortIsrTestCase.test_getExposureFromExpRecord (method)
  • L72 BestEffortIsrTestCase.test_raises (method)
  • L79 BestEffortIsrTestCase.test_quicklook_connections (method)
  • L93 setup_module (function)

tests/test_blockUtils.py

  • L112 BlockParserTestCase.setUpClass (method)
  • L128 BlockParserTestCase.tearDown (method)
  • L134 BlockParserTestCase.test_parsing (method)
  • L157 BlockParserTestCase.test_notFoundBehavior (method)
  • L185 BlockParserTestCase.test_actualValues (method)
  • L208 setup_module (function)

tests/test_butlerUtils.py

  • L70 ButlerUtilsTestCase.setUp (method)
  • L117 ButlerUtilsTestCase.test_getLatissDefaultCollections (method)
  • L123 ButlerUtilsTestCase.test_RECENT_DAY (method)
  • L142 ButlerUtilsTestCase.test_sanitizeDayObs (method)
  • L152 ButlerUtilsTestCase.test_getMostRecentDayObs (method)
  • L162 ButlerUtilsTestCase.test_getSeqNumsForDayObs (method)
  • L173 ButlerUtilsTestCase.test_getMostRecentDataId (method)
  • L182 ButlerUtilsTestCase.test_getDatasetRefForDataId (method)
  • L191 ButlerUtilsTestCase.test__dayobs_present (method)
  • L199 ButlerUtilsTestCase.test__seqnum_present (method)
  • L207 ButlerUtilsTestCase.test__expid_present (method)
  • L215 ButlerUtilsTestCase.test_getDayObs (method)
  • L224 ButlerUtilsTestCase.test_getSeqNum (method)
  • L233 ButlerUtilsTestCase.test_getExpId (method)
  • L242 ButlerUtilsTestCase.test_datasetExists (method)
  • L248 ButlerUtilsTestCase.test_sortRecordsByDayObsThenSeqNum (method)
  • L271 ButlerUtilsTestCase.test_getDaysWithData (method)
  • L277 ButlerUtilsTestCase.test_getExpIdFromDayObsSeqNum (method)
  • L282 ButlerUtilsTestCase.test_updateDataIdOrDataCord (method)
  • L292 ButlerUtilsTestCase.test_fillDataId (method)
  • L308 ButlerUtilsTestCase.test_getExpRecordFromDataId (method)
  • L313 ButlerUtilsTestCase.test_getDayObsSeqNumFromExposureId (method)
  • L319 ButlerUtilsTestCase.test_removeDataProduct (method)
  • L323 ButlerUtilsTestCase.test_getLatissOnSkyDataIds (method)
  • L348 ButlerUtilsTestCase.test__assureDict (method)
  • L361 ButlerUtilsTestCase.test__get_dayobs_key (method)
  • L370 ButlerUtilsTestCase.test__get_seqnum_key (method)
  • L379 ButlerUtilsTestCase.test__get_expid_key (method)
  • L388 ButlerUtilsTestCase.test_updateDataId (method)
  • L405 ButlerUtilsTestCase.test_getExpRecord (method)
  • L434 ButlerInitTestCase.test_dafButlerRaiseTypes (method)
  • L456 ButlerInitTestCase.test_makeDefaultLatissButlerRaiseTypes (method)
  • L477 ButlerInitTestCase.test_DAF_BUTLER_REPOSITORY_INDEX_value (method)
  • L489 setup_module (function)

tests/test_consdbClient.py

  • L30 client (function)
  • L37 test_table_name (function)
  • L47 test_add_flexible_metadata_key (function)
  • L105 test_get_flexible_metadata_keys (function)
  • L120 test_get_flexible_metadata (function)
  • L147 test_insert_flexible_metadata (function)
  • L156 test_schema (function)
  • L177 test_clean_token_url_response (function)
  • L200 test_client (function)

tests/test_dateTime.py

  • L41 DateTimeTestCase.test_getDayObsAsTimes (method)
  • L64 DateTimeTestCase.test_calcDayOffset (method)
  • L75 DateTimeTestCase.test_getDayObsForTime (method)
  • L92 setup_module (function)

tests/test_efdUtils.py

  • L63 EfdUtilsTestCase.setUpClass (method)
  • L87 EfdUtilsTestCase.tearDown (method)
  • L93 EfdUtilsTestCase.test_makeEfdClient (method)
  • L97 EfdUtilsTestCase.test_getTopics (method)
  • L117 EfdUtilsTestCase.test_getEfdData (method)
  • L176 EfdUtilsTestCase.test_raiseIfTopicNotInSchema (method)
  • L189 EfdUtilsTestCase.test_getMostRecentRowWithDataBefore (method)
  • L199 EfdUtilsTestCase.test_efdTimestampToAstropy (method)
  • L204 EfdUtilsTestCase.test_astropyToEfdTimestamp (method)
  • L211 EfdUtilsTestCase.test_clipDataToEvent (method)
  • L264 setup_module (function)

tests/test_guider.py

  • L293 setup_module (function)

tests/test_ics.py

  • L44 M1M3ICSTestCase.setUp (method)
  • L60 M1M3ICSTestCase.tearDown (method)
  • L66 M1M3ICSTestCase.test_analysis (method)
  • L97 setup_module (function)

tests/test_imageExaminer.py

  • L35 ImageExaminerTestCase.setUpClass (method)
  • L49 ImageExaminerTestCase.test_imageExaminer (method)
  • L67 setup_module (function)

tests/test_nightReport.py

  • L44 NightReportTestCase.setUpClass (method)
  • L64 NightReportTestCase.test_saveAndLoad (method)
  • L78 NightReportTestCase.test_getSortedData (method)
  • L89 NightReportTestCase.test_getExpRecordDictForDayObs (method)
  • L106 NightReportTestCase.test_getObsInfoAndMetadataForSeqNum (method)
  • L116 NightReportTestCase.test_rebuild (method)
  • L127 NightReportTestCase.test_getExposureMidpoint (method)
  • L148 NightReportTestCase.test_getTimeDeltas (method)
  • L154 NightReportTestCase.test_makeStarColorAndMarkerMap (method)
  • L165 NightReportTestCase.test_printObsTable (method)
  • L175 NightReportTestCase.test_plotPerObjectAirMass (method)
  • L191 NightReportTestCase.test_makeAltAzCoveragePlot (method)
  • L205 NightReportTestCase.test_calcShutterTimes (method)
  • L213 NightReportTestCase.test_getDatesForSeqNums (method)
  • L219 NightReportTestCase.test_doesNotRaise (method)
  • L230 NightReportTestCase.test_internals (method)
  • L250 setup_module (function)

tests/test_plotting.py

  • L45 PlottingTestCase.setUpClass (method)
  • L49 PlottingTestCase.test_plot (method)
  • L96 setup_module (function)

tests/test_quickLook.py

  • L44 QuickLookIsrTaskTestCase.setUp (method)
  • L66 QuickLookIsrTaskTestCase.test_runQuickLook (method)
  • L90 QuickLookIsrTaskTestCase.test_runQuickLookMissingData (method)
  • L95 QuickLookIsrTaskTestCase.test_runQuickLookBadDark (method)
  • L117 QuickLookIsrTaskRunQuantumTests.setUp (method)
  • L251 QuickLookIsrTaskRunQuantumTests.tearDown (method)
  • L254 QuickLookIsrTaskRunQuantumTests.test_runQuantum (method)
  • L315 raiseExitMockError (function)

tests/test_tmaUtils.py

  • L62 getTmaEventTestTruthValues (function)
  • L88 writeNewTmaEventTestTruthValues (function)
  • L116 makeValid (function)
  • L123 _turnOn (function)
  • L139 TmaUtilsTestCase.test_tmaInit (method)
  • L155 TmaUtilsTestCase.test_tmaReferences (method)
  • L169 TmaUtilsTestCase.test_getAxisAndType (method)
  • L181 TmaUtilsTestCase.test_initStateLogic (method)
  • L222 TMAEventMakerTestCase.setUpClass (method)
  • L236 TMAEventMakerTestCase.tearDown (method)
  • L242 TMAEventMakerTestCase.test_events (method)
  • L248 TMAEventMakerTestCase.test_rowDataForValues (method)
  • L265 TMAEventMakerTestCase.test_monotonicTimeInDataframe (method)
  • L271 TMAEventMakerTestCase.test_monotonicTimeApplicationOfRows (method)
  • L288 TMAEventMakerTestCase.test_fullDaySequence (method)
  • L300 TMAEventMakerTestCase.test_endToEnd (method)
  • L325 TMAEventMakerTestCase.test_noDataBehaviour (method)
  • L337 TMAEventMakerTestCase.test_helperFunctions (method)
  • L348 TMAEventMakerTestCase.test_filterBadValues (method)
  • L445 TMAEventMakerTestCase.test_getEvent (method)
  • L466 TMAEventMakerTestCase.test_printing (method)
  • L490 TMAEventMakerTestCase.test_getAxisData (method)
  • L509 TMAEventMakerTestCase.test_plottingAndCommands (method)
  • L531 TMAEventMakerTestCase.test_findEvent (method)
  • L582 TMAEventMakerTestCase.test_eventAssociatedWith (method)
  • L633 setup_module (function)

tests/test_utils.py

  • L66 ExpSkyPositionOffsetTestCase.setUp (method)
  • L82 ExpSkyPositionOffsetTestCase.test_getExpPositionOffset (method)
  • L146 MiscUtilsTestCase.test_getFieldNameAndTileNumber (method)
  • L179 MiscUtilsTestCase.test_getAirmassSeeingCorrection (method)
  • L191 MiscUtilsTestCase.test_getFilterSeeingCorrection (method)
  • L198 MiscUtilsTestCase.test_getBandpassSeeingCorrection (method)
  • L214 MiscUtilsTestCase.test_quickSmooth (method)
  • L222 MiscUtilsTestCase.test_getCurrentDayObsDatetime (method)
  • L233 MiscUtilsTestCase.test_getCurrentDayObsInt (method)
  • L240 MiscUtilsTestCase.test_getCurrentDayObsHumanStr (method)
  • L247 MiscUtilsTestCase.test_getSunAngle (method)
  • L265 QuantileTestCase.test_quantiles (method)
  • L286 ImageBasedTestCase.test_fluxFromFootprint (method)
  • L340 IdTestCase.test_exposure_id (method)
  • L347 IdTestCase.test_ccdexposure_id (method)
  • L360 IdTestCase.test_calcEclipticCoords (method)
  • L376 setup_module (function)

tests/utils.py

  • L29 getVcr (function)

@mfisherlevine mfisherlevine merged commit 1485dcb into main May 4, 2026
14 checks passed
@codecov
Copy link
Copy Markdown

codecov Bot commented May 4, 2026

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

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.

1 participant