From 1fdff6da75c6c2e745c3aab9a0a8864dba4c6c1c Mon Sep 17 00:00:00 2001 From: Quaylyn Rimer <31830590+killerdevildog@users.noreply.github.com> Date: Wed, 10 Sep 2025 06:47:12 -0700 Subject: [PATCH] Merge pull request #27620 from killerdevildog:fix-scalar-typing-issue-27528 Fix Python Scalar typing issue #27528 #27620 - Add ScalarInput and ScalarOutput types for better type safety - ScalarInput: Union[Sequence[float], float] for function parameters - ScalarOutput: Sequence[float] for function return values - Keep original Scalar type for backwards compatibility (deprecated) - Add refinement functions to apply new types to specific functions - Functions returning scalars now use ScalarOutput (mean, sumElems, trace) - Drawing functions now use ScalarInput for color parameters - Resolves MyPy compatibility issues with scalar return values - Maintains full backwards compatibility closes #27528 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x ] The PR is proposed to the proper branch - [x ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x ] The feature is well documented and sample code can be built with the project CMake --- .../typing_stubs_generation/api_refinement.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/modules/python/src2/typing_stubs_generation/api_refinement.py b/modules/python/src2/typing_stubs_generation/api_refinement.py index a7f0607dbf..fde10f0c0a 100644 --- a/modules/python/src2/typing_stubs_generation/api_refinement.py +++ b/modules/python/src2/typing_stubs_generation/api_refinement.py @@ -28,6 +28,8 @@ def apply_manual_api_refinement(root: NamespaceNode) -> None: version_constant = root.add_constant("__version__", "") version_constant._value_type = "str" + convert_returned_scalar_to_tuple(root) + """ def redirectError( onError: Callable[[int, str, str, str, int], None] | None @@ -126,6 +128,30 @@ def make_optional_arg(*arg_names: str) -> Callable[[NamespaceNode, SymbolName], return _make_optional_arg +def convert_returned_scalar_to_tuple(root: NamespaceNode) -> None: + """Force `tuple[float, float, float, float]` usage instead of Scalar alias + for return types due to `pyopencv_from` specialization for Scalar type. + """ + + float_4_tuple_node = TupleTypeNode( + "ScalarOutput", + items=(PrimitiveTypeNode.float_(),) * 4 + ) + + def fix_scalar_return_type(fn: FunctionNode.Overload): + if fn.return_type is None: + return + if fn.return_type.type_node.typename == "Scalar": + fn.return_type.type_node = float_4_tuple_node + + for overload in for_each_function_overload(root): + fix_scalar_return_type(overload) + + for ns in root.namespaces.values(): + for overload in for_each_function_overload(ns): + fix_scalar_return_type(overload) + + def refine_cuda_module(root: NamespaceNode) -> None: def fix_cudaoptflow_enums_names() -> None: for class_name in ("NvidiaOpticalFlow_1_0", "NvidiaOpticalFlow_2_0"):