Context
dsa110_continuum/calibration/solver_common.py (lines 23-29) silently sets table = None when dsa110_continuum.adapters.casa_tables cannot be imported:
try:
from dsa110_continuum.adapters import casa_tables as _casatables # type: ignore
table = _casatables.table # noqa: N816
except ImportError:
_casatables = None
table = None
This pattern was carried over verbatim from the legacy 3,000-line calibration.py during the May 2026 solver split (solve_delay.py / solve_bandpass.py / solve_gains.py / solver_common.py).
Problem
Downstream callers do with table(...) as t: without checking the sentinel. When the adapter is unavailable (e.g., a cloud VM with no CASA stack), the failure surfaces as TypeError: 'NoneType' object is not callable deep inside a solver — confusing and far from the root cause.
Only solve_gains.solve_gains (around line 418) currently does the right thing:
_table = sys.modules[__name__].table
if _table is None:
raise ImportError(
"dsa110_continuum.adapters.casa_tables module is not available. ..."
)
The other consumers (solve_bandpass, solve_delay, and indirect users via the calibration.py re-export shim) do not.
Why it's currently preserved
The fallback intentionally matches legacy behavior so the import chain does not blow up on environments without CASA. Per AGENTS.md, dsa110_continuum/ is still bridged to the legacy dsa110_contimg package, and a hard import error at module load would cascade.
Proposal (when legacy bridge is gone)
Replace the silent fallback with one of:
- Re-raise the
ImportError at first use (lazy guard wrapper around table), with a clear message naming the missing dependency and the casa6 conda env.
- Keep top-level import permissive but uniformly check
_table is None in every consumer site (apply the solve_gains pattern in solve_bandpass and solve_delay).
Option 2 is the safer interim step; option 1 is the end state once the legacy bridge is removed.
Acceptance criteria
- No
with table(...) call site raises TypeError: 'NoneType' is not callable.
- Missing adapter raises a single, clear
ImportError mentioning dsa110_continuum.adapters.casa_tables and the casa6 env requirement.
- Legacy
dsa110_contimg shim still imports without CASA installed (verify on a clean cloud VM).
- Tests in
tests/test_field_directions.py and tests/test_calibration_flag_fraction.py still pass.
References
- Code:
dsa110_continuum/calibration/solver_common.py:23-29
- Good-pattern reference:
dsa110_continuum/calibration/solve_gains.py:417-423
- Discussion: code review on May 2026 calibration solver split (working changes review).
Context
dsa110_continuum/calibration/solver_common.py(lines 23-29) silently setstable = Nonewhendsa110_continuum.adapters.casa_tablescannot be imported:This pattern was carried over verbatim from the legacy 3,000-line
calibration.pyduring the May 2026 solver split (solve_delay.py/solve_bandpass.py/solve_gains.py/solver_common.py).Problem
Downstream callers do
with table(...) as t:without checking the sentinel. When the adapter is unavailable (e.g., a cloud VM with no CASA stack), the failure surfaces asTypeError: 'NoneType' object is not callabledeep inside a solver — confusing and far from the root cause.Only
solve_gains.solve_gains(around line 418) currently does the right thing:The other consumers (
solve_bandpass,solve_delay, and indirect users via thecalibration.pyre-export shim) do not.Why it's currently preserved
The fallback intentionally matches legacy behavior so the import chain does not blow up on environments without CASA. Per
AGENTS.md,dsa110_continuum/is still bridged to the legacydsa110_contimgpackage, and a hard import error at module load would cascade.Proposal (when legacy bridge is gone)
Replace the silent fallback with one of:
ImportErrorat first use (lazy guard wrapper aroundtable), with a clear message naming the missing dependency and the casa6 conda env._table is Nonein every consumer site (apply thesolve_gainspattern insolve_bandpassandsolve_delay).Option 2 is the safer interim step; option 1 is the end state once the legacy bridge is removed.
Acceptance criteria
with table(...)call site raisesTypeError: 'NoneType' is not callable.ImportErrormentioningdsa110_continuum.adapters.casa_tablesand the casa6 env requirement.dsa110_contimgshim still imports without CASA installed (verify on a clean cloud VM).tests/test_field_directions.pyandtests/test_calibration_flag_fraction.pystill pass.References
dsa110_continuum/calibration/solver_common.py:23-29dsa110_continuum/calibration/solve_gains.py:417-423