Skip to content

feat: add the experimental-API mark (functions, methods, properties) - #4279

Draft
TaiSakuma wants to merge 3 commits into
scikit-hep:mainfrom
TaiSakuma:experimental-mark
Draft

feat: add the experimental-API mark (functions, methods, properties)#4279
TaiSakuma wants to merge 3 commits into
scikit-hep:mainfrom
TaiSakuma:experimental-mark

Conversation

@TaiSakuma

Copy link
Copy Markdown
Member

Implements step 1 of the implementation order proposed in discussion #4197 (design comment): the experimental mark for functions, methods, and properties — one shared wrapper.

One new public name: awkward.errors.ExperimentalWarning, a UserWarning subclass, because users reference it in warning filters. The decorator itself is internal (awkward._experimental.experimental).

Behavior, as specified in the design comment:

  • @experimental and @experimental() are equivalent; the decorator takes no arguments in the initial release (any argument raises TypeError), and the parenthesized form is where configuration options can be added later.
  • The mark sits directly above the def, below @property/@classmethod/@staticmethod, so it always receives a plain function.
  • Everything user-visible derives from the decorated object: the name from __qualname__, the defining module from __module__.
  • Each marked function warns once per process, on its first call — for a property, on its first access. The state is the wrapper's own, independent of the warnings filter state and registry.
  • The warning's stacklevel is computed by walking the stack to the first frame outside awkward (the pattern of pandas' find_stack_level), so the reported location stays on the user's line even through @high_level_function() dispatch; a fixed number would attribute it to _dispatch.py. The warning also fires when a third-party array intercepts the operation through __awkward_function__, because the dispatcher calls the wrapper eagerly.

Example warning:

/home/user/analysis.py:12: ExperimentalWarning: stupendous_reduce is experimental.
    It may change or be removed in any release, without a deprecation period.
    Defined in: awkward.operations.ak_stupendous_reduce
  result = ak.stupendous_reduce(events)

One interaction worth recording: the module-level warnings.filterwarnings("default", module="awkward.*") in awkward._errors matches the frame a warning is attributed to, and this warning is attributed to user code, so that filter never governs ExperimentalWarning — visibility comes from UserWarning's default handling, and the once-per-process behavior from the wrapper's own state.

No real API is marked in this PR; it is machinery and tests only. 19 tests were written first and pin the message text, the warn-once behavior (including under simplefilter("always") and when the body raises), metadata preservation via functools.wraps (which high_level_function depends on for the dispatch name), stacklevel attribution directly and through generator-style and plain-function dispatch, and the warning under interception.

No docs change: sphinx-autoapi generates the class page automatically, matching the existing awkward.errors.FieldNotFoundError precedent.

🤖 Generated with Claude Code

TaiSakuma and others added 2 commits July 31, 2026 13:22
Implement step 1 of the API design in discussion scikit-hep#4197: an internal
dual-form decorator, awkward._experimental.experimental, marking a
public function, method, or property accessor as experimental, plus one
new public name, awkward.errors.ExperimentalWarning.

The mark derives everything user-visible from the decorated object
(__qualname__, __module__), warns once per process per marked function
on its first call (property: first access), and computes the warning's
stacklevel by walking to the first frame outside awkward, so the
warning is attributed to the caller's line even through
@high_level_function() dispatch, including when a third-party array
intercepts via __awkward_function__.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename tests/test_experimental_mark.py to
tests/test_4279_experimental_mark.py per the
tests/test_XXXX_description.py convention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the type/feat PR title type: feat (set automatically) label Jul 31, 2026
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.99%. Comparing base (1b161d3) to head (ffcb6b4).

Additional details and impacted files
Files with missing lines Coverage Δ
src/awkward/_experimental.py 100.00% <100.00%> (ø)
src/awkward/errors.py 100.00% <100.00%> (ø)

@github-actions

Copy link
Copy Markdown

The documentation preview is ready to be viewed at http://preview.awkward-array.org.s3-website.us-east-1.amazonaws.com/PR4279

Add two tests for awkward._experimental._find_stack_level: the
currentframe()-returns-None fallback (implementations without
stack-frame support) and the walk running off the top of the stack when
every frame matches the package prefix. Line and branch coverage of
src/awkward/_experimental.py is now 100%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/feat PR title type: feat (set automatically)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant