carloea2 commented on code in PR #5603:
URL: https://github.com/apache/texera/pull/5603#discussion_r3417948884
##########
amber/src/main/python/pytexera/udf/udf_operator.py:
##########
@@ -16,12 +16,127 @@
# under the License.
from abc import abstractmethod
-from typing import Iterator, Optional, Union
+from dataclasses import dataclass
+import functools
+from typing import Any, Dict, Iterator, Optional, Union
from pyamber import *
+from core.models.schema.attribute_type import AttributeType,
FROM_STRING_PARSER_MAPPING
-class UDFOperatorV2(TupleOperatorV2):
+@dataclass(frozen=True)
+class _UiParameterValue:
+ name: str
+ type: AttributeType
+ value: Any
+
+
+class _UiParameterSupport:
+ _ui_parameter_injected_values: Dict[str, Any]
+ _ui_parameter_name_types: Dict[str, AttributeType]
+ _unsupported_ui_parameter_types = {
+ AttributeType.BINARY,
+ AttributeType.LARGE_BINARY,
+ }
+
+ # Reserved hook name. Backend injector will generate this in the user's
class.
+ def _texera_injected_ui_parameters(self) -> Dict[str, Any]:
+ return {}
+
+ def _ensure_ui_parameter_state(self) -> None:
+ if "_ui_parameter_injected_values" not in self.__dict__:
+ self._ui_parameter_injected_values = {}
+ if "_ui_parameter_name_types" not in self.__dict__:
+ self._ui_parameter_name_types = {}
+
+ def _texera_apply_injected_ui_parameters(self) -> None:
+ self._ensure_ui_parameter_state()
+ values = self._texera_injected_ui_parameters()
+ self._ui_parameter_injected_values = dict(values or {})
+ self._ui_parameter_name_types = {}
+
+ def __init_subclass__(cls, **kwargs):
+ super().__init_subclass__(**kwargs)
+
+ # Wrap the effective open() method once per subclass.
+ original_open = getattr(cls, "open", None)
+ if original_open is None:
+ return
+
+ # Avoid double wrapping
+ if getattr(original_open, "__texera_ui_params_wrapped__", False):
+ return
+
+ @functools.wraps(original_open)
+ def wrapped_open(self, *args, **kwargs):
+ self._texera_apply_injected_ui_parameters()
+ return original_open(self, *args, **kwargs)
+
+ setattr(wrapped_open, "__texera_ui_params_wrapped__", True)
+ cls.open = wrapped_open
+
+ def UiParameter(
+ self, name: str, attr_type: Optional[AttributeType] = None, **kwargs:
Any
+ ) -> _UiParameterValue:
+ if "type" in kwargs:
+ if attr_type is not None:
+ raise TypeError("UiParameter.type was provided multiple
times.")
+ attr_type = kwargs.pop("type")
+
+ if kwargs:
+ unexpected_arguments = ", ".join(sorted(kwargs))
+ raise TypeError(
+ f"UiParameter got unexpected keyword argument(s): "
+ f"{unexpected_arguments}."
+ )
+
+ if attr_type is None:
+ raise TypeError("UiParameter.type is required.")
+
+ if not isinstance(attr_type, AttributeType):
+ raise TypeError(
+ f"UiParameter.type must be an AttributeType, got
{attr_type!r}."
+ )
+
+ self._ensure_ui_parameter_state()
+ existing_type = self._ui_parameter_name_types.get(name)
+ if existing_type is not None and existing_type != attr_type:
+ raise ValueError(
+ f"Duplicate UiParameter name '{name}' with conflicting types: "
+ f"{existing_type.name} vs {attr_type.name}."
+ )
+
+ self._ui_parameter_name_types[name] = attr_type
+ raw_value = self._ui_parameter_injected_values.get(name)
Review Comment:
Done. UiParameter now logs a warning when a requested name was not injected,
while still returning None for compatibility.
The runtime also warns after open() if any injected UI parameter values were
never consumed, with tests covering both cases
--
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]