Skip to content

Conversation

Copy link

Copilot AI commented Jan 12, 2026

PR Framework-R-D#245 introduced a Variant helper to register generic Python algorithms with specific C++ type annotations. This PR integrates that functionality into the Python/C++ interface improvements from PR Framework-R-D#213.

Changes

Core Integration

  • Add test/python/variant.py - Wrapper class providing custom __annotations__ and __name__ for type-specific registration
  • Modify plugins/python/src/modulewrap.cpp - Detect and unwrap Variant via phlex_callable attribute in parse_args()
  • Update test/python/adder.py - Demonstrate usage with generic add() function registered as int-specific iadd

Code Cleanup (Outstanding PR Framework-R-D#213 Review Comments)

  • Remove commented-out mutex code throughout modulewrap.cpp (GIL already provides thread safety)
  • Remove debug print statements from verify_extended.py
  • Remove debug message() calls from CMakeLists.txt
  • Replace LaTeX $\leftrightarrow$ with Unicode in copilot-instructions.md

Example Usage

from variant import Variant

def add(i: Addable, j: Addable) -> Addable:
    return i + j

# Register with C++-compatible int annotations
int_adder = Variant(add, {"i": int, "j": int, "return": int}, "iadd")
m.transform(int_adder, input_family=config["input"], output_products=config["output"])

The C++ side extracts phlex_callable when present, enabling the same Python function to be registered multiple times with different type signatures.

Original prompt

Please incorporate the Variant helper defined in Framework-R-D#245 and use thereof into this branch (Framework-R-D#213) as suggested by Framework-R-D#213 (comment).

Also, examine outstanding review comments in Framework-R-D#213 and resolve the conversation where those comments have already been addressed.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits January 12, 2026 15:20
- Added variant.py helper from PR Framework-R-D#245
- Modified modulewrap.cpp to recognize Variant wrapper via phlex_callable
- Updated adder.py to use Variant helper for type-specific registration
- Removed debug print statements from verify_extended.py
- Removed commented-out mutex code from modulewrap.cpp
- Removed debug message() calls from CMakeLists.txt
- Fixed LaTeX syntax in copilot-instructions.md (use Unicode ↔)

Co-authored-by: greenc-FNAL <[email protected]>
- Fixed docstring in adder.py to reference 'Addable' instead of 'Number'
- Fixed error message in variant.py to use correct class name 'Variant'
- Added clarifying comments in modulewrap.cpp about reference counting

Co-authored-by: greenc-FNAL <[email protected]>
Copilot AI changed the title [WIP] Incorporate Variant helper from pull request 245 into pull request 213 Integrate Variant helper from PR #245 for type-specific Python algorithm registration Jan 12, 2026
Copilot AI requested a review from greenc-FNAL January 12, 2026 15:29
@greenc-FNAL greenc-FNAL marked this pull request as ready for review January 12, 2026 16:41
Copilot AI review requested due to automatic review settings January 12, 2026 16:41
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR integrates the Variant helper from PR Framework-R-D#245 to enable type-specific Python algorithm registration while addressing outstanding code cleanup items from PR Framework-R-D#213 review comments.

Changes:

  • Adds new test/python/variant.py providing a wrapper class for registering generic Python algorithms with specific C++ type annotations
  • Modifies plugins/python/src/modulewrap.cpp to detect and unwrap Variant instances via the phlex_callable attribute
  • Updates test/python/adder.py to demonstrate Variant usage with a generic add function registered as int-specific iadd
  • Removes debug print statements, unused imports, and commented-out mutex code throughout the codebase
  • Replaces LaTeX symbols with Unicode in documentation

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/python/variant.py New wrapper class providing custom __annotations__ and __name__ for type-specific registration
test/python/adder.py Demonstrates Variant usage by converting generic add() to int-specific iadd
plugins/python/src/modulewrap.cpp Adds Variant unwrapping logic in parse_args() and removes commented-out mutex code
test/python/verify_extended.py Removes debug print statements and unused sys import
test/python/CMakeLists.txt Removes debug message() calls
.github/copilot-instructions.md Replaces LaTeX $\leftrightarrow$ with Unicode

f"Variant '{self.__name__}' was called directly. "
f"The framework should extract phlex_callable instead."
)
return self.phlex_callable(*args, **kwargs) # type: ignore
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

The file ends with a trailing blank line (line 80). According to the project's text formatting standards, all text files must have their final line be non-empty and terminated with a single newline character, leaving no trailing blank lines. Remove the blank line at the end of the file.

Copilot generated this review using guidance from repository custom instructions.
>>> def add(i: Number, j: Number) -> Number:
... return i + j
...
>>> int_adder = variant(add, {"i": int, "j": int, "return": int}, "iadd")
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

The example code uses lowercase variant instead of the actual class name Variant. This would cause a NameError if someone tried to run this example.

Suggested change
>>> int_adder = variant(add, {"i": int, "j": int, "return": int}, "iadd")
>>> int_adder = Variant(add, {"i": int, "j": int, "return": int}, "iadd")

Copilot uses AI. Check for mistakes.


class AddableProtocol[T](Protocol):
"""Typer bound for any types that can be added."""
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

Typo in docstring: "Typer bound" should be "Type bound".

Suggested change
"""Typer bound for any types that can be added."""
"""Type bound for any types that can be added."""

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +79
class Variant:
"""Wrapper to associate custom annotations with a callable.

This class wraps a callable and provides custom ``__annotations__`` and
``__name__`` attributes, allowing the same underlying function or callable
object to be registered multiple times with different type annotations.

By default, the provided callable is kept by reference, but can be cloned
(e.g. for callable instances) if requested.

Phlex will recognize the "phlex_callable" data member, allowing an unwrap
and thus saving an indirection. To detect performance degradation, the
wrapper is not callable by default.

Attributes:
phlex_callable (Callable): The underlying callable (public).
__annotations__ (dict): Type information of arguments and return product.
__name__ (str): The name associated with this variant.

Examples:
>>> def add(i: Number, j: Number) -> Number:
... return i + j
...
>>> int_adder = variant(add, {"i": int, "j": int, "return": int}, "iadd")
"""

def __init__(
self,
f: Callable,
annotations: dict[str, str | type | Any],
name: str,
clone: bool | str = False,
allow_call: bool = False,
):
"""Annotate the callable F.

Args:
f (Callable): Annotable function.
annotations (dict): Type information of arguments and return product.
name (str): Name to assign to this variant.
clone (bool|str): If True (or "deep"), creates a shallow (deep) copy
of the callable.
allow_call (bool): Allow this wrapper to forward to the callable.
"""
if clone == 'deep':
self.phlex_callable = copy.deepcopy(f)
elif clone:
self.phlex_callable = copy.copy(f)
else:
self.phlex_callable = f
self.__annotations__ = annotations
self.__name__ = name
self._allow_call = allow_call

def __call__(self, *args, **kwargs):
"""Raises an error if called directly.

Variant instances should not be called directly. The framework should
extract ``phlex_callable`` instead and call that.

Raises:
AssertionError: To indicate incorrect usage, unless overridden.
"""
assert self._allow_call, (
f"Variant '{self.__name__}' was called directly. "
f"The framework should extract phlex_callable instead."
)
return self.phlex_callable(*args, **kwargs) # type: ignore
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

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

The new Variant class lacks test coverage. While adder.py demonstrates basic usage, there are no tests verifying:

  • That phlex_callable is correctly extracted and used by the framework
  • That the call method raises AssertionError when called directly
  • That clone functionality (shallow and deep copy) works correctly
  • That allow_call parameter works when set to True

Consider adding dedicated test cases for the Variant class to ensure the wrapper behaves correctly in various scenarios.

Copilot uses AI. Check for mistakes.
@greenc-FNAL greenc-FNAL merged commit 885a947 into maintenance/improve-test-coverage Jan 12, 2026
6 checks passed
@greenc-FNAL
Copy link
Owner

@copilot I have merged this PR into Framework-R-D#213, and I'm currently hitting Python linter issues. Please analyze the latest state of Framework-R-D#213 and address the reported ruff and mypy issues.

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.

2 participants