mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 07:13:02 +04:00
Merge branch 4.x
This commit is contained in:
@@ -13,6 +13,21 @@ else:
|
||||
from distutils.dir_util import copy_tree
|
||||
|
||||
|
||||
def _remove_stale_pyi_files(directory):
|
||||
"""Remove .pyi files and py.typed markers from the directory tree.
|
||||
|
||||
During incremental builds, disabling a previously enabled module leaves
|
||||
stale typing stubs in the loader directory from a previous copy. Since
|
||||
copy_tree merges rather than replaces, those stale files persist.
|
||||
Removing all stub files before copying ensures only stubs for currently
|
||||
enabled modules are present. Runtime .py files are not affected.
|
||||
"""
|
||||
for dirpath, dirnames, filenames in os.walk(directory):
|
||||
for fname in filenames:
|
||||
if fname.endswith('.pyi') or fname == 'py.typed':
|
||||
os.remove(os.path.join(dirpath, fname))
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_arguments()
|
||||
py_typed_path = os.path.join(args.stubs_dir, 'py.typed')
|
||||
@@ -24,6 +39,8 @@ def main():
|
||||
'generation phase.'.format(py_typed_path)
|
||||
)
|
||||
return
|
||||
if os.path.isdir(args.output_dir):
|
||||
_remove_stale_pyi_files(args.output_dir)
|
||||
copy_tree(args.stubs_dir, args.output_dir)
|
||||
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ static PyObject* createSubmodule(PyObject* parent_module, const std::string& nam
|
||||
}
|
||||
/// Populates parent module dictionary. Submodule lifetime should be managed
|
||||
/// by the global modules dictionary and parent module dictionary, so Py_DECREF after
|
||||
/// successfull call to the `PyDict_SetItemString` is redundant.
|
||||
/// successful call to the `PyDict_SetItemString` is redundant.
|
||||
if (PyDict_SetItemString(parent_module_dict, submodule_name.c_str(), submodule) < 0) {
|
||||
return PyErr_Format(PyExc_ImportError,
|
||||
"Can't register a submodule '%s' (full name: '%s')",
|
||||
|
||||
@@ -8,7 +8,7 @@ from .nodes import (NamespaceNode, FunctionNode, OptionalTypeNode, TypeNode,
|
||||
ClassProperty, PrimitiveTypeNode, ASTNodeTypeNode,
|
||||
AggregatedTypeNode, CallableTypeNode, AnyTypeNode,
|
||||
TupleTypeNode, UnionTypeNode, ProtocolClassNode,
|
||||
DictTypeNode, ClassTypeNode)
|
||||
DictTypeNode, ClassTypeNode, AliasRefTypeNode)
|
||||
from .ast_utils import (find_function_node, SymbolName,
|
||||
for_each_function_overload)
|
||||
from .types_conversion import create_type_node
|
||||
@@ -376,6 +376,62 @@ def _find_argument_index(arguments: Sequence[FunctionNode.Arg],
|
||||
return None
|
||||
|
||||
|
||||
def make_matlike_or_scalar_arg(*arg_names: str) -> Callable[[NamespaceNode, SymbolName], None]:
|
||||
"""Make arguments accept both MatLike and Scalar types.
|
||||
|
||||
This is used for functions like inRange where the C++ InputArray parameter
|
||||
can accept both Mat objects and Scalar values (tuples, floats, etc.).
|
||||
|
||||
Example: cv2.inRange(img, (0, 0, 0), (255, 255, 255)) should be valid.
|
||||
"""
|
||||
def _make_matlike_or_scalar_arg(root_node: NamespaceNode,
|
||||
function_symbol_name: SymbolName) -> None:
|
||||
from .predefined_types import PREDEFINED_TYPES
|
||||
|
||||
function = find_function_node(root_node, function_symbol_name)
|
||||
for arg_name in arg_names:
|
||||
found_overload_with_arg = False
|
||||
|
||||
for overload in function.overloads:
|
||||
arg_idx = _find_argument_index(overload.arguments, arg_name)
|
||||
|
||||
# skip overloads without this argument
|
||||
if arg_idx is None:
|
||||
continue
|
||||
|
||||
current_type = overload.arguments[arg_idx].type_node
|
||||
|
||||
# Check if it's already a union or if it already includes Scalar
|
||||
if isinstance(current_type, UnionTypeNode):
|
||||
# Check if Scalar is already in the union
|
||||
has_scalar = any(
|
||||
isinstance(item, AliasRefTypeNode) and item.typename == "Scalar"
|
||||
for item in current_type.items
|
||||
)
|
||||
if has_scalar:
|
||||
continue
|
||||
# Add Scalar to existing union
|
||||
scalar_ref = AliasRefTypeNode("Scalar")
|
||||
current_type.items = current_type.items + (scalar_ref,)
|
||||
else:
|
||||
# Create a union of current type and Scalar
|
||||
scalar_ref = AliasRefTypeNode("Scalar")
|
||||
overload.arguments[arg_idx].type_node = UnionTypeNode(
|
||||
f"{arg_name}_type",
|
||||
(cast(TypeNode, current_type), scalar_ref)
|
||||
)
|
||||
|
||||
found_overload_with_arg = True
|
||||
|
||||
if not found_overload_with_arg:
|
||||
raise RuntimeError(
|
||||
f"Failed to find argument with name: '{arg_name}'"
|
||||
f" in '{function_symbol_name.name}' overloads"
|
||||
)
|
||||
|
||||
return _make_matlike_or_scalar_arg
|
||||
|
||||
|
||||
NODES_TO_REFINE = {
|
||||
SymbolName(("cv", ), (), "resize"): make_optional_arg("dsize"),
|
||||
SymbolName(("cv", ), (), "calcHist"): make_optional_arg("mask"),
|
||||
@@ -401,6 +457,11 @@ NODES_TO_REFINE = {
|
||||
SymbolName(("cv", "fisheye"), (), "initUndistortRectifyMap"): make_optional_arg("D"),
|
||||
SymbolName(("cv", ), (), "imread"): make_optional_none_return,
|
||||
SymbolName(("cv", ), (), "imdecode"): make_optional_none_return,
|
||||
SymbolName(("cv", ), (), "HoughCircles"): make_optional_none_return,
|
||||
SymbolName(("cv", ), (), "HoughLines"): make_optional_none_return,
|
||||
SymbolName(("cv", ), (), "HoughLinesP"): make_optional_none_return,
|
||||
# Fix for issue #28534: inRange should accept Scalar for lowerb and upperb
|
||||
SymbolName(("cv", ), (), "inRange"): make_matlike_or_scalar_arg("lowerb", "upperb"),
|
||||
}
|
||||
|
||||
ERROR_CLASS_PROPERTIES = (
|
||||
|
||||
@@ -3,6 +3,7 @@ __all__ = ("generate_typing_stubs", )
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
from typing import (Callable, NamedTuple, Union, Set, Dict,
|
||||
Collection, Tuple, List)
|
||||
import warnings
|
||||
@@ -24,6 +25,22 @@ from .nodes.type_node import (TypeNode, AliasTypeNode, AliasRefTypeNode,
|
||||
ConditionalAliasTypeNode, PrimitiveTypeNode)
|
||||
|
||||
|
||||
def _clean_stale_stubs_dirs(stubs_root: Path) -> None:
|
||||
"""Remove all subdirectories under stubs_root.
|
||||
|
||||
During incremental builds, disabling a previously enabled module leaves
|
||||
behind its typing stub directory (e.g. cv2/gapi/). Removing all
|
||||
subdirectories before regeneration ensures only stubs for currently
|
||||
enabled modules are present. Top-level files (py.typed, __init__.pyi)
|
||||
are kept because they are managed separately.
|
||||
"""
|
||||
if not stubs_root.is_dir():
|
||||
return
|
||||
for item in stubs_root.iterdir():
|
||||
if item.is_dir():
|
||||
shutil.rmtree(item)
|
||||
|
||||
|
||||
def generate_typing_stubs(root: NamespaceNode, output_path: Path):
|
||||
"""Generates typing stubs for the AST with root `root` and outputs
|
||||
created files tree to directory pointed by `output_path`.
|
||||
@@ -88,6 +105,12 @@ def generate_typing_stubs(root: NamespaceNode, output_path: Path):
|
||||
# The whole process should fail !only! when all possible scopes are
|
||||
# checked and at least 1 node is still unresolved.
|
||||
root.resolve_type_nodes()
|
||||
# Remove stale typing stub subdirectories from previous builds.
|
||||
# In incremental builds, disabling a module (e.g. -DBUILD_opencv_gapi=OFF)
|
||||
# no longer generates its stubs, but leftover directories from a previous
|
||||
# build persist and propagate through the copy/install steps, causing
|
||||
# type-checker errors for stubs referencing unavailable modules.
|
||||
_clean_stale_stubs_dirs(Path(output_path) / root.export_name)
|
||||
_generate_typing_module(root, output_path)
|
||||
_populate_reexported_symbols(root)
|
||||
_generate_typing_stubs(root, output_path)
|
||||
@@ -708,7 +731,7 @@ def _generate_typing_module(root: NamespaceNode, output_path: Path) -> None:
|
||||
"""
|
||||
|
||||
def has_all_required_modules(type_node: TypeNode) -> bool:
|
||||
return all(em in root.namespaces for em in node.required_modules)
|
||||
return all(em in root.namespaces for em in type_node.required_modules)
|
||||
|
||||
def register_alias_links_from_aggregated_type(type_node: TypeNode) -> None:
|
||||
assert isinstance(type_node, AggregatedTypeNode), \
|
||||
|
||||
Reference in New Issue
Block a user