autowisp.tests.test_error_context module

Class Inheritance Diagram

Inheritance diagram of Component, ErrorContext, FileKind, FindStarsError, FrozenRow, MeasurePhotometryError, PipelineError, Process, RelatedFile, SolveAstrometryError, StackToMasterError, StepError, TestAmbientAccessors, TestCaptureErrors, TestErrorContextDataclass, TestErrorContextManager, TestExitSignalDecode, TestFromConfig, TestNestingGuard, TestPoolPropagation, TestProcessQueuePropagation, TestResourceSnapshot, TestWorkerEntry, ViewError, WorkerCrashedError, _ContextTestCase

Unit tests for the ambient error context and capture layer.

The in-process tests need no pipeline fixtures or database; the cross-process tests spin up a real multiprocessing.Pool (through run_pool) and let its worker bootstrap with the real setup_process_map, which initialises a throwaway project home in a temporary directory. Each test starts from a clean ambient context (reset in setUp).

class autowisp.tests.test_error_context.TestAmbientAccessors(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestAmbientAccessors

get/set helpers and in_worker().

test_set_and_get()[source]

set_error_context installs a bundle get_error_context returns.

test_set_pipeline_run_keeps_rest()[source]

set_pipeline_run swaps only the run, preserving other fields.

class autowisp.tests.test_error_context.TestCaptureErrors(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestCaptureErrors

The capture_errors decorator stamps + optionally wraps.

test_bare_value_error_wrapped_to_step_subclass()[source]

A bare ValueError becomes the ambient step’s StepError type.

test_existing_autowisp_error_passes_through_stamped()[source]

An AutoWISPError keeps its type and gets stamped from context.

test_no_run_leaves_pipeline_run_none()[source]

With no run in context, pipeline_run/crashed stay unset.

test_pipeline_and_bui_wrapping()[source]

Component selects the wrapper class.

test_preset_step_name_not_overwritten()[source]

A step name set at the raise site survives stamping.

test_success_returns_value()[source]

The happy path returns the wrapped callable’s result.

test_unknown_step_falls_back_to_base_steperror()[source]

An unmapped step name yields a plain StepError.

test_wrap_unknown_false_passes_through()[source]

With wrap_unknown=False the original exception is untouched.

class autowisp.tests.test_error_context.TestErrorContextDataclass(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestErrorContextDataclass

The ErrorContext bundle itself.

test_defaults()[source]

A bare ErrorContext has empty/None fields.

test_frozen()[source]

ErrorContext is immutable.

class autowisp.tests.test_error_context.TestErrorContextManager(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestErrorContextManager

The error_context() scoping context manager.

test_keeps_pipeline_run_and_worker_flag()[source]

The block inherits run + in_worker from the current context.

test_nesting_innermost_step_wins_and_files_accumulate()[source]

Inner step overrides; related files from both levels stack.

test_scopes_and_restores()[source]

Step + files apply inside the block and are removed after.

class autowisp.tests.test_error_context.TestExitSignalDecode(methodName='runTest')[source]

Bases: TestCase

Inheritance diagram of autowisp.tests.test_error_context.TestExitSignalDecode

decode_exit_signals is portable and drops clean/running exits.

test_drops_running_and_clean()[source]

None (running) and 0 (clean) contribute nothing.

test_posix_signals_and_plain_codes()[source]

POSIX: negative codes decode to their signal; positive don’t.

test_windows_status_not_signal()[source]

Windows: an abnormal code is an NTSTATUS, never a POSIX signal.

Both the unsigned and signed spellings of an access violation map to the conventional hex status; a plain small code stays bare.

class autowisp.tests.test_error_context.TestFromConfig(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestFromConfig

ErrorContext.from_config rebuilds context from a config dict.

test_code_version_fallback()[source]

A missing code_version falls back to get_code_version_str().

test_empty_config()[source]

No run keys -> no snapshot, no step, main process.

test_full_config()[source]

Run keys produce a populated pipeline-run snapshot.

test_in_worker_from_parent_pid()[source]

in_worker is True iff a truthy parent_pid is present.

test_sentinel_step_names_become_none()[source]

Bootstrap sentinels are not treated as real step names.

class autowisp.tests.test_error_context.TestNestingGuard(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestNestingGuard

A worker may not launch nested workers (resource control).

test_forbid_nested_workers_only_inside_worker()[source]

The guard is a no-op in the main process, raises in a worker.

test_nested_run_pool_blocked_end_to_end()[source]

A real worker that calls run_pool is refused, not allowed to nest.

Goes through the full chain: the outer run_pool spawns a real worker via setup_process_map (which sets in_worker), the worker calls run_pool again, and the inner guard raises a PipelineError that propagates back stamped with the worker PID – so an accidental N^2 launch fails loudly instead of spawning.

class autowisp.tests.test_error_context.TestPoolPropagation(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestPoolPropagation

Errors raised in real Pool workers cross back stamped.

test_bare_exception_wrapped_to_mapped_step_error()[source]

A worker’s bare exception returns as the step’s StepError subclass.

The worker raises a plain ValueError; _wrap maps the ambient step name to its concrete subclass, so the parent receives a MeasurePhotometryError. The original is not kept as a live __cause__ across the Pool (our pickling carries only the fields, and multiprocessing replaces __cause__ with its RemoteTraceback); the durable record is the formatted traceback in details.

test_faulthandler_dumps_native_traceback()[source]

A segfaulting worker leaves a native dump in its own log.

Proves the faulthandler armed in setup_process_map turns an otherwise-silent SIGSEGV into a collectable C-level traceback – which is what distinguishes the faulted worker from the innocents the executor merely terminates.

test_step_error_propagates_with_context()[source]

A worker StepError returns same-typed, stamped, with traceback.

Exercises the full run_pool round trip: the worker bootstraps its context from config (via the real setup_process_map), raises a FindStarsError, and the parent receives the same type carrying the worker’s subprocess_id (a different PID), the step name and pipeline-run snapshot rebuilt in the worker, and the worker traceback both in details and as the Pool’s RemoteTraceback cause.

test_worker_crashed_carries_scoped_config()[source]

A crash carries the failing step’s config, scoped by the manager.

The parent’s own context holds the base add_images_to_db config, so the failing step’s config must come from the error_context(config=...) the manager scopes at dispatch (here simulated around run_pool) – not from the parent context.

test_worker_crashed_carries_step_name()[source]

The synthesised WorkerCrashedError records the ambient step.

Regression for the “no matching logs found” crash-report gap: the step name must reach the queryable step_name attribute (which the persistence layer writes to error.step_name and crash-report log-collection resolves the run/step logs from), not only the free-text message. The parent stamps it from its ambient context – in the pipeline it is inside error_context(step_name=...) when it launches the pool.

A batch-constant file appears once across many in-flight items.

Two workers in flight against the same reference -> the reference is promoted once, not once per crashed input.

test_worker_crashed_names_inflight_input()[source]

A silent death records the in-flight item(s), not a head sample.

The wrapped worker writes its item into the shared in-flight map before running; a hard os._exit leaves it there, so _worker_crashed can name the culprit in details["crashed_inputs"] (bounded by the worker count).

A silent death promotes the in-flight item to a related file.

So a WorkerCrashedError links straight to the offending file (rendered / FK-resolved), not only a details string.

test_worker_crashed_records_exit_signal()[source]

A native crash records the decoded killing signal.

The tell for OOM/jetsam (SIGKILL) vs. a native crash (SIGSEGV); here a segfault is expected to surface as SIGSEGV. (On Windows the code is an NTSTATUS, not a signal – that path is covered by TestExitSignalDecode.)

test_worker_crashed_records_resources()[source]

A crash records a memory snapshot + the worker count.

N workers vs. total RAM is what makes an OOM/jetsam death easy to judge (paired with a SIGKILL and no native dump from items 4-5).

test_worker_error_carries_config()[source]

A worker error carries its process config (via from_config).

The resolved config lives only at runtime, so recording it is the only way a report shows the settings the step actually ran with.

test_worker_error_carries_reference_files()[source]

A multi-file classifier attaches item and batch constants.

Mirrors the detrending call site: the classifier returns the light curve plus the single photometric reference, so an error carries both.

A worker error carries the item it was processing as a file.

The related_files classifier scopes the item as the ambient related file inside the worker, so an error raised for it (here a FindStarsError) crosses back carrying that file – the datum a config-vs-file-content failure most needs.

test_worker_hard_exit_raises_worker_crashed()[source]

A worker that hard-exits surfaces as WorkerCrashedError, no hang.

ProcessPoolExecutor reports the death as BrokenProcessPool (a bare multiprocessing.Pool would hang here), which run_pool converts into a WorkerCrashedError describing the in-flight inputs instead of blocking the pipeline forever.

class autowisp.tests.test_error_context.TestProcessQueuePropagation(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestProcessQueuePropagation

Process + Queue workers return stamped errors over a queue.

test_all_workers_dead_raises_worker_crashed()[source]

A worker that hard-exits is detected by the parent, not a hang.

manage_astrometry polls is_alive() while waiting on the result queue; when every worker has died without queuing a result it raises a WorkerCrashedError recording the OS exit codes (normalised to the same exit_signal shape as Scheme A), instead of blocking forever.

test_queue_worker_error_round_trips()[source]

A failed queue worker yields a stamped error the parent re-raises.

Mirrors solve_astrometry: a Process worker bootstraps its context, fails with a bare ValueError, and puts capture_for_queue(...) on the queue. The object pulled off is the step’s mapped AutoWISPError (here SolveAstrometryError) carrying the worker subprocess_id, the run snapshot, and the traceback in details; reraise_from_worker then raises it.

class autowisp.tests.test_error_context.TestResourceSnapshot(methodName='runTest')[source]

Bases: TestCase

Inheritance diagram of autowisp.tests.test_error_context.TestResourceSnapshot

collect_resource_snapshot is best-effort and never raises.

test_empty_when_psutil_unavailable()[source]

A missing psutil degrades to an empty dict, never a raise.

test_memory_fields_present_and_sane()[source]

psutil is a hard dependency, so the memory fields are present.

class autowisp.tests.test_error_context.TestWorkerEntry(methodName='runTest')[source]

Bases: _ContextTestCase

Inheritance diagram of autowisp.tests.test_error_context.TestWorkerEntry

worker_entry stamps subprocess_id and stays picklable.

test_autowisp_error_passes_through_stamped()[source]

An AutoWISPError keeps its type and gains subprocess_id.

test_bare_exception_wrapped_to_step_subclass()[source]

A bare worker exception becomes the mapped, picklable StepError.

test_inflight_map_cleared_on_error()[source]

A failing task still clears its in-flight entry.

test_inflight_map_tracks_then_clears_item()[source]

The item is in the in-flight map while running, gone after.

(A plain dict stands in for the Manager().dict() proxy; the write/clear logic is the same.)

A classifier may return several files (item + batch constants).

A FileKind wraps a path item; a callable is used as given.

No classifier, no item, or a bad classifier -> empty, no raise.

test_subprocess_id_not_overwritten_by_later_stamp()[source]

An already-stamped subprocess_id survives a second boundary.

Models an exception stamped by one except that then passes through another on its way out of the same worker: the second stamp is a no-op (stamp_subprocess is idempotent), so the first PID wins rather than being overwritten.

test_success_returns_value()[source]

worker_entry is transparent on the happy path.

class autowisp.tests.test_error_context._ContextTestCase(methodName='runTest')[source]

Bases: TestCase

Base resetting the ambient context to empty before each test.

setUp()[source]

Hook method for setting up the test fixture before exercising it.

autowisp.tests.test_error_context._dr_file(path='/tmp/x.h5', role='input')[source]

A small RelatedFile for related-files assertions.

autowisp.tests.test_error_context._hard_exit_worker(_)[source]

Module-level Pool worker that hard-exits without an exception.

autowisp.tests.test_error_context._instant_exit()[source]

Module-level Process target that hard-exits without an exception.

autowisp.tests.test_error_context._lc_with_reference(item)[source]

A related_files classifier: the item plus a batch-constant ref.

Module-level (so it is picklable to workers) and returns multiple files – the per-item lightcurve and the single photometric reference the whole batch shares – exactly the shape the detrending call site builds via functools.partial.

autowisp.tests.test_error_context._nested_run_pool_worker(item)[source]

Worker that (illegally) tries to launch its own pool.

Used to prove the no-nested-workers guard end-to-end: this runs inside a real worker (so setup_process_map has set in_worker), and the inner run_pool must refuse before spawning anything.

autowisp.tests.test_error_context._noop(*args, **kwargs)[source]

Do-nothing stand-in for the per-image mark_start / mark_end hooks.

autowisp.tests.test_error_context._pool_config(project_home, *, run_id, step='find_stars')[source]

Minimal per-process config for run_pool’s bootstrap.

setup_process_map runs in each worker; pointing it at a temporary project_home keeps its side effects (a throwaway SQLite DB and the per-worker log / stdout-stderr files) inside the temp dir.

autowisp.tests.test_error_context._process_queue_worker(result_queue, config)[source]

Process worker that bootstraps, fails, and queues the stamped error.

Mirrors solve_astrometry.astrometry_process: bootstrap the ambient context from config, catch the failure, and put the result of capture_for_queue (a stamped, picklable error) on the queue rather than raising out of the process.

autowisp.tests.test_error_context._raise_find_stars_error(item)[source]

Module-level Pool worker that raises a StepError.

Must be top-level (not a closure/lambda) so Pool.map can pickle it to the worker.

autowisp.tests.test_error_context._raise_value_error(item)[source]

Module-level Pool worker that raises a bare (non-AutoWISP) error.

autowisp.tests.test_error_context._segfault_worker(_)[source]

Module-level Pool worker that crashes with a real SIGSEGV.

Used to prove faulthandler (armed in setup_process_map) dumps a native traceback into the worker’s own redirected log before it dies.