feat: add PathLike type hints for args annotated with CV_WRAP_FILE_PATH

This commit is contained in:
Vadim Levin 2025-09-10 11:25:32 +03:00
parent ec015d48d6
commit 1fe128f7b5
4 changed files with 38 additions and 9 deletions

View File

@ -12,6 +12,7 @@ from .nodes import (
SequenceTypeNode,
AnyTypeNode,
AggregatedTypeNode,
PathLikeTypeNode,
)
from .types_conversion import (

View File

@ -4,7 +4,7 @@ import keyword
from .nodes import (ASTNode, NamespaceNode, ClassNode, FunctionNode,
EnumerationNode, ClassProperty, OptionalTypeNode,
TupleTypeNode)
TupleTypeNode, PathLikeTypeNode)
from .types_conversion import create_type_node
@ -167,12 +167,16 @@ def create_function_node_in_scope(scope: Union[NamespaceNode, ClassNode],
func_info) -> FunctionNode:
def prepare_overload_arguments_and_return_type(variant):
arguments = [] # type: list[FunctionNode.Arg]
# Enumerate is requried, because `argno` in `variant.py_arglist`
# Enumerate is required, because `argno` in `variant.py_arglist`
# refers to position of argument in C++ function interface,
# but `variant.py_noptargs` refers to position in `py_arglist`
for i, (_, argno) in enumerate(variant.py_arglist):
arg_info = variant.args[argno]
type_node = create_type_node(arg_info.tp)
# Special handling for string representation of the file system path
if arg_info.pathlike and type_node.typename == "str":
type_node = PathLikeTypeNode.string_or_pathlike_()
default_value = None
if len(arg_info.defval):
default_value = arg_info.defval

View File

@ -8,5 +8,5 @@ from .type_node import (
TypeNode, OptionalTypeNode, UnionTypeNode, NoneTypeNode, TupleTypeNode,
ASTNodeTypeNode, AliasTypeNode, SequenceTypeNode, AnyTypeNode,
AggregatedTypeNode, NDArrayTypeNode, AliasRefTypeNode, PrimitiveTypeNode,
CallableTypeNode, DictTypeNode, ClassTypeNode
CallableTypeNode, DictTypeNode, ClassTypeNode, PathLikeTypeNode
)

View File

@ -43,7 +43,7 @@ class TypeNode(abc.ABC):
Returns:
str: short name of the type node.
"""
pass
return ""
@property
def full_typename(self) -> str:
@ -123,12 +123,11 @@ class TypeNode(abc.ABC):
def is_resolved(self) -> bool:
return True
def relative_typename(self, module_full_export_name: str) -> str:
def relative_typename(self, module: str) -> str:
"""Type name relative to the provided module.
Args:
module_full_export_name (str): Full export name of the module to
get relative name to.
module (str): Full export name of the module to get relative name to.
Returns:
str: If module name of the type node doesn't match `module`, then
@ -715,11 +714,11 @@ class ContainerTypeNode(AggregatedTypeNode):
@abc.abstractproperty
def type_format(self) -> str:
pass
return ""
@abc.abstractproperty
def types_separator(self) -> str:
pass
return ""
class SequenceTypeNode(ContainerTypeNode):
@ -895,6 +894,31 @@ class ClassTypeNode(ContainerTypeNode):
return ", "
class PathLikeTypeNode(TypeNode):
"""Type node representing a PathLike object.
"""
def __init__(self, ctype_name: str) -> None:
super().__init__(ctype_name)
@property
def typename(self) -> str:
return "os.PathLike[str]"
@property
def required_usage_imports(self) -> Generator[str, None, None]:
yield "import os"
@staticmethod
def string_or_pathlike_(ctype_name: str = "string") -> UnionTypeNode:
return UnionTypeNode(
ctype_name,
items=(
PrimitiveTypeNode.str_(ctype_name),
PathLikeTypeNode(ctype_name)
)
)
def _resolve_symbol(root: Optional[ASTNode], full_symbol_name: str) -> Optional[ASTNode]:
"""Searches for a symbol with the given full export name in the AST
starting from the `root`.