mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-08 04:50:07 +01:00
Extract type information in makePyArgsString
One unexpected type of '...' required adding a new transformation that modifies both the name and the type to just '*args', so added a preferred method `FixWxPrefix.parseNameAndType` which processes both strings at once. Also fixes cleanType to recursively call cleanType on sub-types (was improperly calling cleanName). With this, method and function signatures now have type annotations which are mostly correct (100% correct in the "it compiles" sense). Thankfully, the incorrect type-hints don't cause errors due to using stringized annotations (by importing annotations from __future__). Importantly, the overload signatures now have been fully sanitized. Before this, there was one instance of a variable named `is`, and another named `/Transfer/` - both invalid identifiers. I stopped looking after those. Since theses signatures are valid Python code, this opens up the opportunity to use `typing.overload` to fully expose those. Edge-cases in type-hints will be addressed in later commits.
This commit is contained in:
@@ -462,9 +462,6 @@ class FunctionDef(BaseDef, FixWxPrefix):
|
||||
"""
|
||||
Create a pythonized version of the argsString in function and method
|
||||
items that can be used as part of the docstring.
|
||||
|
||||
TODO: Maybe (optionally) use this syntax to document arg types?
|
||||
http://www.python.org/dev/peps/pep-3107/
|
||||
"""
|
||||
params = list()
|
||||
returns = list()
|
||||
@@ -477,6 +474,7 @@ class FunctionDef(BaseDef, FixWxPrefix):
|
||||
'wxString()': '""',
|
||||
'wxArrayString()' : '[]',
|
||||
'wxArrayInt()' : '[]',
|
||||
'wxEmptyString': "''", # Makes signatures much shorter
|
||||
}
|
||||
if isinstance(self, CppMethodDef):
|
||||
# rip apart the argsString instead of using the (empty) list of parameters
|
||||
@@ -495,7 +493,14 @@ class FunctionDef(BaseDef, FixWxPrefix):
|
||||
else:
|
||||
default = self.fixWxPrefix(default, True)
|
||||
# now grab just the last word, it should be the variable name
|
||||
arg = arg.split()[-1]
|
||||
# The rest will be the type information
|
||||
arg_type, arg = arg.rsplit(None, 1)
|
||||
arg, arg_type = self.parseNameAndType(arg, arg_type)
|
||||
if arg_type:
|
||||
if default == 'None':
|
||||
arg = f'{arg}: {arg_type} | None'
|
||||
else:
|
||||
arg = f'{arg}: {arg_type}'
|
||||
if default:
|
||||
arg += '=' + default
|
||||
params.append(arg)
|
||||
@@ -506,25 +511,33 @@ class FunctionDef(BaseDef, FixWxPrefix):
|
||||
continue
|
||||
if param.arraySize:
|
||||
continue
|
||||
s = param.pyName or param.name
|
||||
s, param_type = self.parseNameAndType(param.pyName or param.name, param.type)
|
||||
if param.out:
|
||||
returns.append(s)
|
||||
if param_type:
|
||||
returns.append(param_type)
|
||||
else:
|
||||
if param.inOut:
|
||||
returns.append(s)
|
||||
if param_type:
|
||||
returns.append(param_type)
|
||||
if param_type:
|
||||
s = f'{s}: {param_type}'
|
||||
if param.default:
|
||||
default = param.default
|
||||
if default in defValueMap:
|
||||
default = defValueMap.get(default)
|
||||
if param_type and default == 'None':
|
||||
s = f'{s} | None'
|
||||
default = '|'.join([self.cleanName(x, True) for x in default.split('|')])
|
||||
s = f'{s}={default}'
|
||||
params.append(s)
|
||||
|
||||
self.pyArgsString = '(' + ', '.join(params) + ')'
|
||||
if len(returns) == 1:
|
||||
self.pyArgsString += ' -> ' + returns[0]
|
||||
if len(returns) > 1:
|
||||
self.pyArgsString += ' -> (' + ', '.join(returns) + ')'
|
||||
self.pyArgsString = f"({', '.join(params)})"
|
||||
if not returns:
|
||||
self.pyArgsString = f'{self.pyArgsString} -> None'
|
||||
elif len(returns) == 1:
|
||||
self.pyArgsString = f'{self.pyArgsString} -> {returns[0]}'
|
||||
elif len(returns) > 1:
|
||||
self.pyArgsString = f"{self.pyArgsString} -> tuple[{', '.join(returns)}]"
|
||||
|
||||
|
||||
def collectPySignatures(self):
|
||||
|
||||
@@ -169,11 +169,12 @@ class FixWxPrefix(object):
|
||||
type_map = {
|
||||
# Some types are guesses, marked with TODO to verify automatic
|
||||
# conversion actually happens. Also, these are the type-names
|
||||
# after processing by cleanName (so spaces are removed)
|
||||
# after processing by cleanName (so spaces are removed), or
|
||||
# after potentially lopping off an 'Array' prefix.
|
||||
# --String types
|
||||
'String': 'str',
|
||||
'Char': 'str',
|
||||
'char':' str',
|
||||
'char': 'str',
|
||||
'FileName': 'str', # TODO: check conversion
|
||||
# --Int types
|
||||
'byte': 'int',
|
||||
@@ -196,20 +197,38 @@ class FixWxPrefix(object):
|
||||
# --Others
|
||||
'PyObject': 'Any',
|
||||
'WindowID': 'int', # defined in wx/defs.h
|
||||
# A few instances, for example in LogInfo:
|
||||
}
|
||||
type_name = self.cleanName(type_name)
|
||||
# Special handling of Vector<type> types -
|
||||
if type_name.startswith('Vector<') and type_name.endswith('>'):
|
||||
# Special handling for 'Vector<type>' types
|
||||
type_name = self.cleanName(type_name[7:-1])
|
||||
type_name = self.cleanType(type_name[7:-1])
|
||||
return f'list[{type_name}]'
|
||||
if type_name.startswith('Array'):
|
||||
type_name = self.cleanName(type_name[5:])
|
||||
type_name = self.cleanType(type_name[5:])
|
||||
if type_name:
|
||||
return f'list[{type_name}]'
|
||||
else:
|
||||
return 'list'
|
||||
return type_map.get(type_name, type_name)
|
||||
|
||||
def parseNameAndType(self, name_string: str, type_string: str | None) -> tuple[str, str | None]:
|
||||
"""Given an identifier name and an optional type annotation, process
|
||||
these per cleanName and cleanType. Further performs transforms on the
|
||||
identifier name that may be required due to the type annotation.
|
||||
Ex. The transformation "any_identifier : ..." -> "*args" requires
|
||||
modifying both the identifier name and the annotation.
|
||||
"""
|
||||
name_string = self.cleanName(name_string)
|
||||
if type_string:
|
||||
type_string = self.cleanType(type_string)
|
||||
if type_string == '...':
|
||||
name_string = '*args'
|
||||
type_string = None
|
||||
if not type_string:
|
||||
type_string = None
|
||||
return name_string, type_string
|
||||
|
||||
|
||||
def ignoreAssignmentOperators(node):
|
||||
|
||||
Reference in New Issue
Block a user