Skip to content

fix: only proxy actual stats through Hypergraph.__getattr__ (#408)#736

Open
leotrs wants to merge 1 commit into
devfrom
fix-getattr-whitelist-stats
Open

fix: only proxy actual stats through Hypergraph.__getattr__ (#408)#736
leotrs wants to merge 1 commit into
devfrom
fix-getattr-whitelist-stats

Conversation

@leotrs

@leotrs leotrs commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #408. Hypergraph.__getattr__ (and DiHypergraph.__getattr__) blindly delegated every attribute lookup to the underlying views and wrapped whatever it found in a function that calls .asdict(). That works for actual stats but produces confusing errors when users hit view methods that happen to share a name with no stat:

>>> H.filterby()
TypeError: IDView.filterby() missing 2 required positional arguments: 'stat' and 'val'

>>> H.memberships()
AttributeError: 'dict' object has no attribute 'asdict'

>>> H.neighbors()
TypeError: IDView.neighbors() missing 1 required positional argument: 'idx'

Fix

Tighten the delegation check from stat is None to not isinstance(stat, IDStat). Built-in stats (registered via _stat_property) and user-defined stats (via @nodestat_func etc.) both return IDStat instances, so they continue to work. Non-stat view methods (filterby, neighbors, memberships, isolates, singletons, empty, members, dimembers, head, tail, ...) now correctly raise AttributeError at lookup time with the existing helpful message.

Same one-line change in both Hypergraph and DiHypergraph.

Safety check: grepped xgi/, tests/, and tutorials/ for H.filterby(, H.neighbors(, H.memberships(, etc. — zero hits. Nothing in the repo relied on the broken proxies.

Test plan

  • Two new regression tests (test_getattr_only_proxies_stats for both Hypergraph and DiHypergraph) covering: built-in stats still work, user-defined stats still work, every non-stat view method raises AttributeError, unknown attributes raise AttributeError
  • Full test suite passes (420 passed, 6 skipped)

Hypergraph.__getattr__ (and DiHypergraph.__getattr__) blindly delegated
every attribute lookup to the underlying views, wrapping whatever it
found and calling .asdict() on the result. That works for actual stats
but produces confusing errors for view methods like filterby, neighbors,
memberships, isolates, singletons, empty, etc.

Tighten the check from `stat is None` to `not isinstance(stat, IDStat)`
so only true stat objects are proxied. Non-stat view methods now raise
AttributeError as they should.

Tested with built-in and user-defined (@nodestat_func / @dinodestat_func)
stats still accessible, and a list of common non-stat view methods now
correctly inaccessible via H. / DH.

Closes #408

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.63%. Comparing base (9e1e9af) to head (e443951).
⚠️ Report is 43 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #736      +/-   ##
==========================================
+ Coverage   93.65%   94.63%   +0.97%     
==========================================
  Files          66       66              
  Lines        5168     5290     +122     
==========================================
+ Hits         4840     5006     +166     
+ Misses        328      284      -44     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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