gemini-code-assist[bot] commented on code in PR #309:
URL: https://github.com/apache/tvm-ffi/pull/309#discussion_r2587334953


##########
python/tvm_ffi/utils/kwargs_wrapper.py:
##########
@@ -0,0 +1,330 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""Utilities for creating high-performance keyword argument wrapper functions.
+
+This module provides tools for wrapping positional-only callables with
+keyword argument support using code generation techniques.
+"""
+
+from __future__ import annotations
+
+import functools
+import inspect
+from typing import Any, Callable
+
+# Sentinel object for missing arguments
+MISSING = object()
+
+
+def _validate_argument_names(names: list[str], arg_type: str) -> None:
+    """Validate that argument names are valid Python identifiers.
+
+    Parameters
+    ----------
+    names
+        List of argument names to validate.
+    arg_type
+        Description of the argument type (e.g., "Argument", "Keyword-only 
argument").
+
+    """
+    for name in names:
+        if not isinstance(name, str):
+            raise TypeError(
+                f"{arg_type} name must be a string, got {type(name).__name__}: 
{name!r}"
+            )
+        if not name.isidentifier():
+            raise ValueError(
+                f"Invalid {arg_type.lower()} name: {name!r} is not a valid 
Python identifier"
+            )
+
+
+def _validate_wrapper_args(
+    args_names: list[str],
+    args_defaults: tuple,
+    kwargsonly_names: list[str],
+    kwargsonly_defaults: dict[str, Any],
+    reserved_names: set[str],
+) -> None:
+    """Validate all input arguments for make_kwargs_wrapper.
+
+    Parameters
+    ----------
+    args_names
+        List of positional argument names.
+    args_defaults
+        Tuple of default values for positional arguments.
+    kwargsonly_names
+        List of keyword-only argument names.
+    kwargsonly_defaults
+        Dictionary of default values for keyword-only arguments.
+    reserved_names
+        Set of reserved internal names that cannot be used as argument names.
+
+    """
+    # Validate args_names are valid Python identifiers
+    _validate_argument_names(args_names, "Argument")
+
+    # Validate args_defaults is a tuple
+    if not isinstance(args_defaults, tuple):
+        raise TypeError(f"args_defaults must be a tuple, got 
{type(args_defaults).__name__}")
+
+    # Validate args_defaults length doesn't exceed args_names length
+    if len(args_defaults) > len(args_names):
+        raise ValueError(
+            f"args_defaults has {len(args_defaults)} values but only "
+            f"{len(args_names)} positional arguments"
+        )
+
+    # Validate kwargsonly_names are valid identifiers
+    _validate_argument_names(kwargsonly_names, "Keyword-only argument")
+
+    # Validate kwargsonly_defaults keys are in kwargsonly_names
+    kwargsonly_names_set = set(kwargsonly_names)
+    for key in kwargsonly_defaults:
+        if key not in kwargsonly_names_set:
+            raise ValueError(
+                f"Default provided for '{key}' which is not in 
kwargsonly_names: {kwargsonly_names}"
+            )
+
+    # Validate no overlap between positional and keyword-only arguments
+    args_names_set = set(args_names)
+    overlap = args_names_set & kwargsonly_names_set
+    if overlap:
+        raise ValueError(f"Arguments cannot be both positional and 
keyword-only: {overlap}")
+
+    # Validate no conflict between user argument names and internal names
+    all_user_names = args_names_set | kwargsonly_names_set
+    conflicts = all_user_names & reserved_names
+    if conflicts:
+        raise ValueError(
+            f"Argument names conflict with internal names: {conflicts}. "
+            f'Please avoid using names starting with "__i_"'
+        )
+
+
+def make_kwargs_wrapper(
+    target_func: Callable,
+    args_names: list[str],
+    args_defaults: tuple = (),
+    kwargsonly_names: list[str] | None = None,
+    kwargsonly_defaults: dict[str, Any] | None = None,
+    prototype_func: Callable | None = None,
+) -> Callable:
+    """Create a wrapper with kwargs support for a function that only accepts 
positional arguments.
+
+    This function dynamically generates a wrapper using code generation to 
minimize overhead.
+    The generated wrapper uses a sentinel object (MISSING) to distinguish 
between explicitly
+    passed arguments and those that should use default values.
+
+    Parameters
+    ----------
+    target_func
+        The underlying function to be called by the wrapper. This function 
must only
+        accept positional arguments.
+    args_names
+        A list of ALL positional argument names in order. These define the 
positional
+        parameters that the wrapper will accept. Must not overlap with 
kwargsonly_names.
+    args_defaults
+        A tuple of default values for positional arguments, right-aligned to 
args_names
+        (matching Python's __defaults__ behavior). The length of this tuple 
determines
+        how many trailing arguments have defaults.
+        Example: (10, 20) with args_names=['a', 'b', 'c', 'd'] means c=10, 
d=20.
+        Empty tuple () means no defaults.
+    kwargsonly_names
+        A list of keyword-only argument names. These arguments can only be 
passed by name,
+        not positionally, and appear after a '*' separator in the signature. 
Can include both
+        required and optional keyword-only arguments. Must not overlap with 
args_names.
+        Example: ['debug', 'timeout'] creates wrapper(..., *, debug, timeout).
+    kwargsonly_defaults
+        Optional dictionary of default values for keyword-only arguments 
(matching Python's
+        __kwdefaults__ behavior). Keys must be a subset of kwargsonly_names. 
Keyword-only
+        arguments not in this dict are required.
+        Example: {'timeout': 30} with kwargsonly_names=['debug', 'timeout'] 
means 'debug'
+        is required and 'timeout' is optional.
+    prototype_func
+        Optional prototype function to copy metadata (__name__, __doc__, 
__module__,
+        __qualname__, __annotations__) from. If None, no metadata is copied.
+
+    Returns
+    -------
+        A dynamically generated wrapper function with the specified signature
+
+    """
+    # Normalize inputs
+    if kwargsonly_names is None:
+        kwargsonly_names = []
+    if kwargsonly_defaults is None:
+        kwargsonly_defaults = {}

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   The docstring for `make_kwargs_wrapper` states that `target_func` "must only 
accept positional arguments." However, the function currently does not validate 
this constraint, which could lead to a `TypeError` at runtime if `target_func` 
has `**kwargs` in its signature. Adding a check here to inspect `target_func`'s 
signature and raise an error if `**kwargs` are present would improve robustness 
by catching this issue at wrapper creation time.
   
   For example, if `target_func` is `def my_func(a, **kwargs): pass`, the 
generated wrapper would call it with positional arguments, leading to a 
`TypeError`.
   
   ```suggestion
           kwargsonly_defaults = {}
   
       # Validate target_func signature
       target_sig = inspect.signature(target_func)
       for param in target_sig.parameters.values():
           if param.kind == inspect.Parameter.VAR_KEYWORD:
               raise ValueError(
                   f"target_func must not accept **kwargs, but '{param.name}' 
was found."
               )
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to