Skip to content

refactor: simplify decorator type-dispatch system #276

Closed

Description

@Jammy2211

Overview

The decorator system at autoarray/structures/decorators/ handles input→output type mapping for all profile methods (e.g. Grid2D in → Array2D out, Grid2DIrregular → ArrayIrregular). It works correctly but is verbose (~648 lines), contains dead code (Grid1D path), duplicates logic across three Maker classes, and has near-zero dedicated test coverage. This task cleans it up in phases, starting with tests and targeted cleanup, with an optional follow-up to consolidate to a registry-based architecture.

Plan

  • Write comprehensive decorator unit tests covering all grid types × all decorators × edge cases (ndarray passthrough, JAX passthrough, list returns) — safety net before any refactoring
  • Remove the dead Grid1D code path from all makers — Grid1D is never passed to decorated profile methods
  • Extract shared list-return handling into a single helper used by all makers
  • Move over-sampling metadata extraction into Grid2D's construction rather than try/except in GridMaker
  • Rename grid_dec → decorators in the public API (aa.grid_dec → aa.decorators) with grep-and-replace across PyAutoGalaxy/PyAutoLens
  • Phase 3 (follow-up): If tests are solid and cleanup goes well, consolidate the three Maker classes into one generic wrapper + flat lookup table (~530 lines → ~150 lines)
Detailed implementation plan

Affected Repositories

  • PyAutoArray (primary)
  • PyAutoGalaxy (consumer — decorator usage, rename)
  • PyAutoLens (consumer — decorator usage, rename)

Work Classification

Library

Branch Survey

Repository Current Branch Dirty?
PyAutoArray main clean
PyAutoGalaxy main clean
PyAutoLens main clean

Suggested branch: feature/data-typing-simplify
Worktree root: ~/Code/PyAutoLabs-wt/data-typing-simplify/

Implementation Steps

Phase 1 — Tests (zero-risk)

  1. Expand test_autoarray/test_decorators.py with tests for:
    • @to_array with Grid2D input → asserts Array2D output with correct mask
    • @to_array with Grid2DIrregular input → asserts ArrayIrregular output
    • @to_array with raw np.ndarray → asserts np.ndarray passthrough
    • @to_vector_yx with Grid2D → asserts VectorYX2D
    • @to_vector_yx with Grid2DIrregular → asserts VectorYX2DIrregular
    • @to_grid with Grid2D → asserts Grid2D with over-sampling metadata preserved
    • @to_grid with Grid2DIrregular → asserts Grid2DIrregular
    • @transform — coordinate frame transformation applied and reversed
    • List return handling for all decorators
    • JAX array passthrough (if jax available)

Phase 2 — Targeted cleanup (low risk)

  1. Remove Grid1D isinstance branch and via_grid_1d() from all three makers (to_array.py, to_grid.py, to_vector_yx.py) and the 1D projection logic from abstract.py
  2. Extract list-return handling from each maker into a shared helper in abstract.py
  3. Move over-sampling metadata try/except from GridMaker.via_grid_2d() into cleaner getattr calls or into Grid2D's own construction
  4. Rename grid_dec → decorators in autoarray/__init__.py and update all aa.grid_dec. references in PyAutoGalaxy and PyAutoLens

Phase 3 — Registry consolidation (follow-up, moderate risk)

  1. Replace the three Maker classes with a single generic wrapper + lookup table:
    {(Grid2D, "array"): Array2D, (Grid2DIrregular, "array"): ArrayIrregular, ...}
    
  2. Keep external API (to_array, to_vector_yx, to_grid) as thin wrappers so downstream code doesn't change
  3. Run full test suites across PyAutoArray, PyAutoGalaxy, PyAutoLens

Key Files

  • autoarray/structures/decorators/abstract.py — base maker class, isinstance routing
  • autoarray/structures/decorators/to_array.py — ArrayMaker
  • autoarray/structures/decorators/to_grid.py — GridMaker (over-sampling complexity)
  • autoarray/structures/decorators/to_vector_yx.py — VectorYXMaker
  • autoarray/structures/decorators/transform.py — coordinate frame decorator
  • test_autoarray/test_decorators.py — currently near-empty (11 lines)
  • autoarray/__init__.py — exports grid_dec

Original Prompt

Click to expand starting prompt

The different data structures in PyAutoArray are quite confusing, in some ways:

  • Array2D
  • ArrayIrregular
  • Grid2D
  • GridIrregular

And so on.

They serve an important purpose, unifying the API and abstractions in a way which ensures a user can understand
that data and grids can be paired to something uniform or not. Furthermore, the slam / native API is important
in making both accessible, and streamlining how masked data vectors are stored.

First, we should assess if this code can be simplified at all or if its acceptable. I dont have a better idea.

You would probably benefit from reading @autolens_workspace/scripts/guides/data_structures.py to see how a user
interfaces with these objects.

However, things get more complex, as these objects are used to define mappings at the profile level of
@PyAutoGalaxy/autogalaxy/profiles. For example for this function:

class Isothermal(PowerLaw):
def init(self, centre, ell_comps, einstein_radius):
super().init(centre=centre, ell_comps=ell_comps, einstein_radius=einstein_radius, slope=2.0)

@aa.grid_dec.to_vector_yx
@aa.grid_dec.transform
def deflections_yx_2d_from(self, grid, xp=np, **kwargs):
    ...

The decorator @aa.grid_dec.to_vector_yx is used to understand that for this function, the result
that comes out must be a VectorYX object. It handles more typing, for example if a Grid2DIrregular comes in
a VectorYXIrregular comes out, but a Grid2D produces a VectorYX object.

There is also behaviour where if a numpy ndarray comes in, a numpy ndarray comes out without type casting,
with the same behaviour for a JAX array.

The problem is really just how complex things got in this decorator, which is all handled at
@PyAutoArray/autoarray/structures/decorators. Its complicated, messy and hard to trace.

So, can you give me your assessment of whether there's a quite large, sweeping restructure that can simplify this
code but retain the desired functionality and behaviour? Think hard, this could require a good chunk of planning
and no doubt extensive testing after!

Activity

  1. Jammy2211 commented on Apr 13, 2026

    @Jammy2211
    CollaboratorAuthor

    Smoke Test Results — 2026-04-13

    Workspace Passed Failed Total
    autofit_workspace 7 0 7
    autogalaxy_workspace 4 2 6
    autolens_workspace 5 1 6
    autolens_workspace_test 5 2 7

    All failures are pre-existing (missing FITS files for interferometer scripts, missing dataset files) — none caused by decorator changes.

    Fix applied

    Grid1D was removed from the decorator type-dispatch system. Workspace scripts that used Grid1D.uniform_from_zero() for 1D radial profiles were updated to use Grid2DIrregular with coordinates along the x-axis instead.

    Workspace scripts updated

    • autogalaxy_workspace/scripts/guides/galaxies.py — Grid1D → Grid2DIrregular
    • autogalaxy_workspace/scripts/guides/plot/examples/plotters.py — Grid1D → Grid2DIrregular
    • autolens_workspace/scripts/guides/plot/examples/plotters.py — Grid1D → Grid2DIrregular

    Unit test results

    • PyAutoArray: 733 passed
    • PyAutoGalaxy: 834 passed
    • PyAutoLens: 246 passed
  2. Jammy2211 commented on Apr 13, 2026

    @Jammy2211
    CollaboratorAuthor

    Shipped — 2026-04-13

    PRs

    Summary

    Simplified the decorator type-dispatch system in PyAutoArray. Removed Grid1D from the decorator chain entirely, cleaned up over-sampling metadata handling (try/except → getattr), added aa.decorators as the canonical alias (replacing aa.grid_dec), and added missing test coverage (ndarray passthrough + transform decorator tests). Updated 3 workspace scripts to use Grid2DIrregular instead of Grid1D for 1D radial profiles. All 1,813 unit tests pass, all smoke tests pass.

    Session Notes

    • Grid1D removal initially caused a regression in autogalaxy_workspace/scripts/guides/galaxies.py which passes Grid1D to image_2d_from. Fixed by updating the workspace scripts to use Grid2DIrregular instead of restoring Grid1D support in the decorators.
    • Notebooks (.ipynb) still reference Grid1D and will need separate updates.
  3. Jammy2211 commented on May 28, 2026

    @Jammy2211
    CollaboratorAuthor

    Shipped via #277. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions