Skip to content

fix: give a useful error when ProjectionClass*D is missing - #737

Open
FanxinSun wants to merge 3 commits into
scikit-hep:mainfrom
FanxinSun:fix/missing-projection-class
Open

fix: give a useful error when ProjectionClass*D is missing#737
FanxinSun wants to merge 3 commits into
scikit-hep:mainfrom
FanxinSun:fix/missing-projection-class

Conversation

@FanxinSun

Copy link
Copy Markdown

Closes #488.

If you build a vector subclass from the awkward mixins and don't give it a ProjectionClass3D/4D (like coffea's VertexArray, which intentionally has no 4D meaning), any operation that tries to promote the result currently dies with an unhelpful AttributeError from awkward's field lookup, which says nothing about what's actually missing.

This PR routes the ProjectionClass*D lookups in the awkward backend through a small helper that raises a TypeError naming the class, the missing attribute, and how to fix it:

VertexArray does not define ProjectionClass3D: this operation implicitly converts a VertexArray into a 3D vector, but no 3D equivalent has been declared for it. Assign VertexArray.ProjectionClass3D to a suitable vector class to allow the conversion, or convert the vectors explicitly before the operation.

Also adds a regression test that builds a minimal mixin-only Vertex behavior the same way coffea does. Full awkward backend test file passes locally (51 passed).

If you build a subclass from the VectorAwkward mixins and don't give it
a ProjectionClass3D/4D (like coffea's VertexArray, which intentionally
has no 4D meaning), any operation that needs to promote the result blows
up with a confusing AttributeError from awkward's field lookup that says
nothing about what's actually missing.

Route the ProjectionClass lookups in the awkward backend through a small
helper that says which class is missing which attribute and what to do
about it.

Fixes scikit-hep#488
@codecov

codecov Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.73%. Comparing base (8cbd655) to head (92c6979).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #737   +/-   ##
=======================================
  Coverage   87.72%   87.73%           
=======================================
  Files          96       96           
  Lines       11194    11201    +7     
=======================================
+ Hits         9820     9827    +7     
  Misses       1374     1374           

☔ View full report in Codecov by Harness.
📢 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.

@Saransh-cpp Saransh-cpp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks a lot for working on this, @FanxinSun! As with your other PR: Please see #729 (comment) for my take on AI generated comments / code. I'll be happy to review this PR further if there is minimal AI usage (given that it is a good first issue).

Comment thread src/vector/backends/awkward.py Outdated
Comment thread src/vector/backends/awkward.py Outdated
cls: type[VectorProtocol], dimension: int
) -> type[VectorProtocol]:
name = f"ProjectionClass{dimension}D"
projection: type[VectorProtocol] | None = getattr(cls, name, None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is the type explicitly required here? Does mypy complain?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I checked with:

mypy: 2.1.0
Python: 3.14.4

it will not complain. And this type annotation is not required, but one caveat is about warn_unreachable. Currently it's set false, by flipping it the un-annotated function will raise
error: Statement is unreachable [unreachable]
because ProjectionClass4D is declared non-Optional.

But in general I'm not clear about the plan of that flag so keeping it or not is up to you!

Comment thread tests/backends/test_awkward.py Outdated
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.

Throw a useful error on implicit upcast if ProjectClass*D is not defined by a vector subclass

2 participants