mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-21 05:05:44 +00:00
Add a script to make sure that python stubs are sensible
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
from types import ModuleType
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: {sys.argv[0]} [path/to/tmp/folder]")
|
||||
sys.exit(1)
|
||||
|
||||
destpath = os.path.join(os.path.realpath(sys.argv[1]), "rdstubs")
|
||||
|
||||
os.makedirs(destpath, exist_ok=True)
|
||||
|
||||
# do everything relative to this script
|
||||
docsdir = os.path.realpath(os.path.dirname(__file__))
|
||||
|
||||
# path to module libraries for windows
|
||||
if struct.calcsize("P") == 8:
|
||||
binpath = os.path.abspath(os.path.join(docsdir, "../x64/"))
|
||||
else:
|
||||
binpath = os.path.abspath(os.path.join(docsdir, "../Win32/"))
|
||||
|
||||
# Prioritise release over development builds
|
||||
sys.path.insert(0, os.path.abspath(binpath + "/Development/pymodules"))
|
||||
sys.path.insert(0, os.path.abspath(binpath + "/Release/pymodules"))
|
||||
|
||||
# Add the build paths to PATH so renderdoc.dll can be located
|
||||
os.environ["PATH"] += os.pathsep + os.path.abspath(binpath + "/Development/")
|
||||
os.environ["PATH"] += os.pathsep + os.path.abspath(binpath + "/Release/")
|
||||
|
||||
if sys.platform == "win32" and sys.version_info[1] >= 8:
|
||||
if os.path.exists(binpath + "/Release/"):
|
||||
os.add_dll_directory(binpath + "/Release/")
|
||||
if os.path.exists(binpath + "/Development/"):
|
||||
os.add_dll_directory(binpath + "/Development/")
|
||||
|
||||
# path to module libraries for linux
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(docsdir, "../build/lib")))
|
||||
|
||||
import shutil
|
||||
|
||||
shutil.rmtree(destpath)
|
||||
|
||||
import renderdoc as rd_module
|
||||
import qrenderdoc as qrd_module
|
||||
import stubgen
|
||||
|
||||
stubgen.gen(rd_module, destpath)
|
||||
stubgen.gen(qrd_module, destpath)
|
||||
|
||||
sys.path.insert(0, os.path.dirname(destpath))
|
||||
|
||||
from rdstubs import renderdoc as rd_stub # type: ignore
|
||||
from rdstubs import qrenderdoc as qrd_stub # type: ignore
|
||||
|
||||
import inspect, enum
|
||||
|
||||
for mod, stub in [(rd_module, rd_stub), (qrd_module, qrd_stub)]:
|
||||
stub: ModuleType
|
||||
|
||||
# we enforce in naming checks that top level items like classes and functions do not contain a _
|
||||
mod_items = [x for x in dir(mod) if "_" not in x]
|
||||
stub_items = [x for x in dir(stub) if "_" not in x]
|
||||
|
||||
missing = set(mod_items) - set(stub_items)
|
||||
|
||||
if len(missing) > 0:
|
||||
raise RuntimeError(
|
||||
f"Some module items do not have a corresponding stub item: {list(missing)}"
|
||||
)
|
||||
|
||||
for name, mod_item, stub_item in [
|
||||
(x, getattr(mod, x), getattr(stub, x)) for x in mod_items
|
||||
]:
|
||||
if inspect.isclass(mod_item):
|
||||
if issubclass(mod_item, enum.Enum):
|
||||
members = mod_item.__members__
|
||||
for val in members.keys():
|
||||
if not hasattr(stub_item, val):
|
||||
raise RuntimeError(
|
||||
f"{mod.__name__}.{name} stub for enum is missing {val}"
|
||||
)
|
||||
if getattr(stub_item, val) != members[val]:
|
||||
raise RuntimeError(
|
||||
f"{mod.__name__}.{name} stub for enum has wrong value: {members[val]} vs {getattr(stub_item, val)}"
|
||||
)
|
||||
else:
|
||||
swig_vars = [
|
||||
"disown",
|
||||
"acquire",
|
||||
"own",
|
||||
"append",
|
||||
"next",
|
||||
"this",
|
||||
"thisown",
|
||||
]
|
||||
members = [
|
||||
x for x in dir(mod_item) if x[0] != "_" and x not in swig_vars
|
||||
]
|
||||
|
||||
for member_name in members:
|
||||
if not hasattr(stub_item, member_name):
|
||||
raise RuntimeError(
|
||||
f"{mod.__name__}.{name} stub for class is missing {member_name}"
|
||||
)
|
||||
|
||||
mod_member = getattr(mod_item, member_name)
|
||||
stub_member = getattr(stub_item, member_name)
|
||||
|
||||
if inspect.ismethoddescriptor(mod_member) or inspect.isbuiltin(
|
||||
mod_member
|
||||
):
|
||||
if not inspect.isfunction(stub_member):
|
||||
raise RuntimeError(
|
||||
f"{mod.__name__}.{name}.{member_name} stub is not a member function"
|
||||
)
|
||||
elif inspect.isgetsetdescriptor(mod_member):
|
||||
if not isinstance(stub_member, property):
|
||||
raise RuntimeError(
|
||||
f"{mod.__name__}.{name}.{member_name} stub is not a property"
|
||||
)
|
||||
elif isinstance(mod_member, int):
|
||||
if mod_member != stub_member:
|
||||
raise RuntimeError(
|
||||
f"{mod.__name__}.{name}.{member_name} stub has wrong value: {mod_member} vs {stub_member}"
|
||||
)
|
||||
|
||||
shutil.rmtree(destpath)
|
||||
|
||||
print("Generated stubs look OK")
|
||||
+30
-21
@@ -1,48 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: {sys.argv[0]} [path/to/stubs/folder]")
|
||||
sys.exit(1)
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("stubspath", help="path/to/stubs/folder")
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
help="Enable debugger mode, exceptions are not caught by the framework.",
|
||||
action="store_true",
|
||||
)
|
||||
parser.epilog
|
||||
args = parser.parse_args()
|
||||
|
||||
destpath = os.path.realpath(sys.argv[1])
|
||||
destpath = os.path.realpath(args.stubspath)
|
||||
|
||||
print(f"Writing python stubs to {destpath}")
|
||||
if args.verbose:
|
||||
print(f"Writing python stubs to {destpath}")
|
||||
|
||||
os.makedirs(destpath, exist_ok=True)
|
||||
|
||||
|
||||
# do everything relative to this script
|
||||
docsdir = os.path.realpath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
# path to module libraries for windows
|
||||
if struct.calcsize("P") == 8:
|
||||
binpath = os.path.abspath(os.path.join(docsdir, '../x64/'))
|
||||
binpath = os.path.abspath(os.path.join(docsdir, "../x64/"))
|
||||
else:
|
||||
binpath = os.path.abspath(os.path.join(docsdir, '../Win32/'))
|
||||
binpath = os.path.abspath(os.path.join(docsdir, "../Win32/"))
|
||||
|
||||
# Prioritise release over development builds
|
||||
sys.path.insert(0, os.path.abspath(binpath + '/Development/pymodules'))
|
||||
sys.path.insert(0, os.path.abspath(binpath + '/Release/pymodules'))
|
||||
sys.path.insert(0, os.path.abspath(binpath + "/Development/pymodules"))
|
||||
sys.path.insert(0, os.path.abspath(binpath + "/Release/pymodules"))
|
||||
|
||||
# Add the build paths to PATH so renderdoc.dll can be located
|
||||
os.environ["PATH"] += os.pathsep + os.path.abspath(binpath + '/Development/')
|
||||
os.environ["PATH"] += os.pathsep + os.path.abspath(binpath + '/Release/')
|
||||
os.environ["PATH"] += os.pathsep + os.path.abspath(binpath + "/Development/")
|
||||
os.environ["PATH"] += os.pathsep + os.path.abspath(binpath + "/Release/")
|
||||
|
||||
if sys.platform == 'win32' and sys.version_info[1] >= 8:
|
||||
if os.path.exists(binpath + '/Release/'):
|
||||
os.add_dll_directory(binpath + '/Release/')
|
||||
if os.path.exists(binpath + '/Development/'):
|
||||
os.add_dll_directory(binpath + '/Development/')
|
||||
if sys.platform == "win32" and sys.version_info[1] >= 8:
|
||||
if os.path.exists(binpath + "/Release/"):
|
||||
os.add_dll_directory(binpath + "/Release/")
|
||||
if os.path.exists(binpath + "/Development/"):
|
||||
os.add_dll_directory(binpath + "/Development/")
|
||||
|
||||
# path to module libraries for linux
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(docsdir, '../build/lib')))
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(docsdir, "../build/lib")))
|
||||
|
||||
import renderdoc
|
||||
import qrenderdoc
|
||||
import stubgen
|
||||
|
||||
stubgen.gen(renderdoc, destpath)
|
||||
stubgen.gen(qrenderdoc, destpath)
|
||||
stubgen.gen(renderdoc, destpath, verbose=args.verbose)
|
||||
stubgen.gen(qrenderdoc, destpath, verbose=args.verbose)
|
||||
|
||||
+21
-16
@@ -17,6 +17,15 @@ if sys.platform == "msys":
|
||||
nl = "\r\n"
|
||||
|
||||
|
||||
verbose_prints = False
|
||||
|
||||
|
||||
def log(s: str):
|
||||
global verbose_prints
|
||||
if verbose_prints:
|
||||
print(s)
|
||||
|
||||
|
||||
# RenderDoc/swig specific filtering
|
||||
def shouldskip(name) -> bool:
|
||||
if name.startswith("Swig") or name.startswith("SWIG"):
|
||||
@@ -355,12 +364,8 @@ def gen_function(file: Stream, class_parent: Any, func: Callable):
|
||||
file.indent()
|
||||
file.println('"""')
|
||||
docstring = func.__doc__.strip()
|
||||
i = 0
|
||||
# trim any auto-generated function signatures
|
||||
while docstring.startswith(f"{func.__name__}("):
|
||||
i += 1
|
||||
if i > 100:
|
||||
print(docstring)
|
||||
# trim any auto-generated function signatures
|
||||
try:
|
||||
docstring = docstring[docstring.index("\n") :].strip()
|
||||
except ValueError:
|
||||
@@ -622,8 +627,10 @@ def gen_class(file: Stream, class_obj: Type):
|
||||
dependencies[class_obj.__name__] = deps
|
||||
|
||||
|
||||
def gen(module: types.ModuleType, destpath: str):
|
||||
global dependencies, dummy_types, fwd_ref
|
||||
def gen(module: types.ModuleType, destpath: str, verbose=False):
|
||||
global dependencies, dummy_types, fwd_ref, verbose_prints
|
||||
|
||||
verbose_prints = verbose
|
||||
|
||||
begin = time.time()
|
||||
|
||||
@@ -633,11 +640,11 @@ def gen(module: types.ModuleType, destpath: str):
|
||||
|
||||
output_basepath = os.path.join(destpath, module.__name__)
|
||||
if __file__ in dir(module):
|
||||
print(
|
||||
log(
|
||||
f"Generating stubs for {module.__name__} from {module.__file__}, writing to {output_basepath}"
|
||||
)
|
||||
else:
|
||||
print(f"Generating stubs for {module.__name__}, writing to {output_basepath}")
|
||||
log(f"Generating stubs for {module.__name__}, writing to {output_basepath}")
|
||||
|
||||
shutil.rmtree(output_basepath, ignore_errors=True)
|
||||
os.makedirs(output_basepath, exist_ok=True)
|
||||
@@ -763,7 +770,7 @@ def gen(module: types.ModuleType, destpath: str):
|
||||
if len(group) > 1:
|
||||
group.sort()
|
||||
group_list = ", ".join(group)
|
||||
print(f"Circular dependency detected: {group_list}")
|
||||
log(f"Circular dependency detected: {group_list}")
|
||||
|
||||
filename = f"{module.__name__}_circular{circular}"
|
||||
circular += 1
|
||||
@@ -802,10 +809,8 @@ def gen(module: types.ModuleType, destpath: str):
|
||||
dummy_types.append(local)
|
||||
|
||||
if len(dummy_types) > 0:
|
||||
print(
|
||||
f"WARNING: Some types could not be found, and were mapped to dummy types:"
|
||||
)
|
||||
print(" " + ", ".join(list(dummy_types)))
|
||||
log(f"WARNING: Some types could not be found, and were mapped to dummy types:")
|
||||
log(" " + ", ".join(list(dummy_types)))
|
||||
|
||||
for dummy in dummy_types:
|
||||
dependencies[dummy] = set()
|
||||
@@ -937,5 +942,5 @@ def gen(module: types.ModuleType, destpath: str):
|
||||
init.merge(stream)
|
||||
|
||||
end = time.time()
|
||||
print(f"Generated in {int((end-begin)*1000)} ms")
|
||||
print("")
|
||||
log(f"Generated in {int((end-begin)*1000)} ms")
|
||||
log("")
|
||||
|
||||
Reference in New Issue
Block a user