Skip to content

Forward per-tool repr to the accessed tool (#3478)#3479

Merged
brendancol merged 3 commits into
mainfrom
issue-3478
Jun 24, 2026
Merged

Forward per-tool repr to the accessed tool (#3478)#3479
brendancol merged 3 commits into
mainfrom
issue-3478

Conversation

@brendancol

Copy link
Copy Markdown
Contributor

Summary

Closes #3478.

After #3477 added a categorized __repr__ to the .xrs accessor, evaluating a single tool without calling it (e.g. da.xrs.slope) printed the whole accessor catalog. da.xrs.slope is a bound method, and Python builds a bound method's repr as <bound method Cls.name of {repr(self)}>, so repr(self) routed through the accessor's catalog __repr__ and embedded the entire listing.

  • Accessor attribute access now wraps public bound methods in a small callable _AccessorTool proxy. Its __repr__ / _repr_html_ show that tool's own signature and docstring instead. Calls forward unchanged, and __doc__ / __wrapped__ are mirrored so help() and inspect keep seeing the delegated docstring.
  • The accessor-level catalog repr (da.xrs) is untouched.

Backend coverage

Pure accessor-layer change; no compute path is touched. Behaves the same across numpy / cupy / dask+numpy / dask+cupy.

Test plan

  • repr(da.xrs.slope) shows slope's signature + docstring, not the catalog
  • tools stay callable and match the direct function call
  • inspect.getdoc / help() metadata preserved on the proxy
  • HTML repr scoped to the tool
  • Dataset accessor scoped the same way
  • accessor-level catalog repr still renders
  • full test_accessor.py suite passes (86 tests), flake8 clean

Evaluating a single accessor tool such as da.xrs.slope returned a bound
method, whose repr embeds repr(self) and therefore the whole accessor
catalog added in #3477. Wrap public methods in a callable _AccessorTool
proxy on attribute access so the repr shows that tool's own signature and
docstring instead. Calls forward unchanged and the delegated docstring is
mirrored for help()/inspect.

@brendancol brendancol left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

PR Review: Forward per-tool repr to the accessed tool (#3478)

I read accessor.py in full and exercised the proxy against the edge cases below. The fix is correct and targeted. No blockers.

Blockers

None.

Suggestions

None.

Nits (optional)

  • _AccessorTool returns a fresh proxy on every attribute access, so da.xrs.slope == da.xrs.slope is now False where a bound method compared equal. Harmless for normal use, but anything downstream comparing accessor methods by equality would see the change. Low risk; not worth caching unless it bites.
  • __getattribute__ now runs for every attribute access on the accessor, including self._obj inside each method body. The early name.startswith("_") return keeps the hot path cheap (one extra call plus a startswith), so this is fine, just noting the cost is non-zero.

What looks good

  • Root cause is correctly identified: a bound method's repr embeds repr(self), which routed through the catalog __repr__. Wrapping at attribute access is the right layer.
  • The proxy mirrors __doc__ / __wrapped__ / __name__, so help(), inspect.signature, and inspect.getdoc keep working. Verified inspect.signature(da.xrs.slope) returns (**kwargs) and getdoc matches the standalone function.
  • Private attributes and the catalog __repr__ are left untouched, so da.xrs still renders the full listing.
  • Calls forward unchanged, positional args included (ndvi, rasterize are covered by the existing suite, which now all runs through the proxy).
  • Missing attributes still raise AttributeError.
  • Tests cover the scoped text repr, HTML repr, callable forwarding, help metadata, the Dataset accessor, and the unchanged catalog repr. Both accessors are handled.

Checklist

  • Root cause correctly identified
  • help()/inspect metadata preserved
  • Catalog repr unchanged
  • Calls forward unchanged (incl. positional args)
  • Both DataArray and Dataset accessors covered
  • Tests present and passing (86 in test_accessor.py), flake8 clean
  • No compute path touched; backend-agnostic

@brendancol brendancol merged commit bdfebe2 into main Jun 24, 2026
14 checks passed
@brendancol brendancol deleted the issue-3478 branch June 25, 2026 14:55
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.

repr(da.xrs.slope) prints the whole accessor catalog instead of the tool's own info

1 participant