Skip to content

Commit b8b5d83

Browse files
committed
Merge pull request opencv#9566 from alalek:python_signatures
2 parents 93c3f20 + 572a7bf commit b8b5d83

File tree

2 files changed

+58
-21
lines changed

2 files changed

+58
-21
lines changed

modules/python/common.cmake

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,28 @@ set(cv2_generated_hdrs
4848
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_funcs.h"
4949
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_types.h"
5050
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_type_reg.h"
51-
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_ns_reg.h")
51+
"${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_ns_reg.h"
52+
)
53+
54+
set(OPENCV_${PYTHON}_SIGNATURES_FILE "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_signatures.json" CACHE INTERNAL "")
55+
56+
set(cv2_generated_files ${cv2_generated_hdrs}
57+
"${OPENCV_${PYTHON}_SIGNATURES_FILE}"
58+
)
5259

5360
string(REPLACE ";" "\n" opencv_hdrs_ "${opencv_hdrs}")
5461
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs_}")
5562
add_custom_command(
56-
OUTPUT ${cv2_generated_hdrs}
57-
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${PYTHON_SOURCE_DIR}/src2/gen2.py" ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${PYTHON}"
58-
DEPENDS ${PYTHON_SOURCE_DIR}/src2/gen2.py
59-
DEPENDS ${PYTHON_SOURCE_DIR}/src2/hdr_parser.py
60-
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
61-
DEPENDS ${opencv_hdrs})
63+
OUTPUT ${cv2_generated_files}
64+
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${PYTHON_SOURCE_DIR}/src2/gen2.py" ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${PYTHON}"
65+
DEPENDS ${PYTHON_SOURCE_DIR}/src2/gen2.py
66+
DEPENDS ${PYTHON_SOURCE_DIR}/src2/hdr_parser.py
67+
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
68+
DEPENDS ${opencv_hdrs}
69+
COMMENT "Generate files for ${the_module}"
70+
)
71+
72+
add_custom_target(gen_${the_module} DEPENDS ${cv2_generated_files})
6273

6374
set(cv2_custom_hdr "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_custom_headers.h")
6475
file(WRITE ${cv2_custom_hdr} "//user-defined headers\n")
@@ -67,6 +78,7 @@ foreach(uh ${opencv_userdef_hdrs})
6778
endforeach(uh)
6879

6980
ocv_add_library(${the_module} MODULE ${PYTHON_SOURCE_DIR}/src2/cv2.cpp ${cv2_generated_hdrs} ${opencv_userdef_hdrs} ${cv2_custom_hdr})
81+
add_dependencies(${the_module} gen_${the_module})
7082

7183
if(APPLE)
7284
set_target_properties(${the_module} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")

modules/python/src2/gen2.py

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ def __init__(self, name, decl=None):
310310
if not customname and self.wname.startswith("Cv"):
311311
self.wname = self.wname[2:]
312312

313-
def gen_map_code(self, all_classes):
313+
def gen_map_code(self, codegen):
314+
all_classes = codegen.classes
314315
code = "static bool pyopencv_to(PyObject* src, %s& dst, const char* name)\n{\n PyObject* tmp;\n bool ok;\n" % (self.cname)
315316
code += "".join([gen_template_set_prop_from_map.substitute(propname=p.name,proptype=p.tp) for p in self.props])
316317
if self.base:
@@ -319,9 +320,10 @@ def gen_map_code(self, all_classes):
319320
code += "\n return true;\n}\n"
320321
return code
321322

322-
def gen_code(self, all_classes):
323+
def gen_code(self, codegen):
324+
all_classes = codegen.classes
323325
if self.ismap:
324-
return self.gen_map_code(all_classes)
326+
return self.gen_map_code(codegen)
325327

326328
getset_code = StringIO()
327329
getset_inits = StringIO()
@@ -354,10 +356,10 @@ def gen_code(self, all_classes):
354356
sorted_methods.sort()
355357

356358
if self.constructor is not None:
357-
methods_code.write(self.constructor.gen_code(all_classes))
359+
methods_code.write(self.constructor.gen_code(codegen))
358360

359361
for mname, m in sorted_methods:
360-
methods_code.write(m.gen_code(all_classes))
362+
methods_code.write(m.gen_code(codegen))
361363
methods_inits.write(m.get_tab_entry())
362364

363365
baseptr = "NULL"
@@ -516,6 +518,8 @@ def init_pyproto(self):
516518
else:
517519
outstr = "None"
518520

521+
self.py_arg_str = argstr
522+
self.py_return_str = outstr
519523
self.py_prototype = "%s(%s) -> %s" % (self.wname, argstr, outstr)
520524
self.py_noptargs = noptargs
521525
self.py_arglist = arglist
@@ -554,11 +558,11 @@ def get_wrapper_name(self):
554558

555559
return "pyopencv_" + self.namespace.replace('.','_') + '_' + classname + name
556560

557-
def get_wrapper_prototype(self, all_classes):
561+
def get_wrapper_prototype(self, codegen):
558562
full_fname = self.get_wrapper_name()
559563
if self.isconstructor:
560564
return "static int {fn_name}(pyopencv_{type_name}_t* self, PyObject* args, PyObject* kw)".format(
561-
fn_name=full_fname, type_name=all_classes[self.classname].name)
565+
fn_name=full_fname, type_name=codegen.classes[self.classname].name)
562566

563567
if self.classname:
564568
self_arg = "self"
@@ -615,8 +619,9 @@ def get_tab_entry(self):
615619
).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
616620
flags = " | ".join(flags), py_docstring = full_docstring)
617621

618-
def gen_code(self, all_classes):
619-
proto = self.get_wrapper_prototype(all_classes)
622+
def gen_code(self, codegen):
623+
all_classes = codegen.classes
624+
proto = self.get_wrapper_prototype(codegen)
620625
code = "%s\n{\n" % (proto,)
621626
code += " using namespace %s;\n\n" % self.namespace.replace('.', '::')
622627

@@ -799,6 +804,20 @@ def gen_code(self, all_classes):
799804
if self.isconstructor:
800805
def_ret = "-1"
801806
code += "\n return %s;\n}\n\n" % def_ret
807+
808+
cname = self.cname
809+
if self.classname:
810+
classinfo = all_classes[self.classname]
811+
cname = classinfo.cname + '::' + cname
812+
py_signatures = codegen.py_signatures.setdefault(cname, [])
813+
for v in self.variants:
814+
s = dict(name=v.name, arg=v.py_arg_str, ret=v.py_return_str)
815+
for old in py_signatures:
816+
if s == old:
817+
break
818+
else:
819+
py_signatures.append(s)
820+
802821
return code
803822

804823

@@ -822,6 +841,7 @@ def clear(self):
822841
self.code_type_reg = StringIO()
823842
self.code_ns_reg = StringIO()
824843
self.code_type_publish = StringIO()
844+
self.py_signatures = dict()
825845
self.class_idx = 0
826846

827847
def add_class(self, stype, name, decl):
@@ -931,9 +951,13 @@ def gen_namespaces_reg(self):
931951

932952

933953
def save(self, path, name, buf):
934-
f = open(path + "/" + name, "wt")
935-
f.write(buf.getvalue())
936-
f.close()
954+
with open(path + "/" + name, "wt") as f:
955+
f.write(buf.getvalue())
956+
957+
def save_json(self, path, name, value):
958+
import json
959+
with open(path + "/" + name, "wt") as f:
960+
json.dump(value, f)
937961

938962
def gen(self, srcfiles, output_path):
939963
self.clear()
@@ -996,7 +1020,7 @@ def gen(self, srcfiles, output_path):
9961020
classlist1.sort()
9971021

9981022
for decl_idx, name, classinfo in classlist1:
999-
code = classinfo.gen_code(self.classes)
1023+
code = classinfo.gen_code(self)
10001024
self.code_types.write(code)
10011025
if not classinfo.ismap:
10021026
self.code_type_reg.write("MKTYPE2(%s);\n" % (classinfo.name,) )
@@ -1009,7 +1033,7 @@ def gen(self, srcfiles, output_path):
10091033
for name, func in sorted(ns.funcs.items()):
10101034
if func.isconstructor:
10111035
continue
1012-
code = func.gen_code(self.classes)
1036+
code = func.gen_code(self)
10131037
self.code_funcs.write(code)
10141038
self.gen_namespace(ns_name)
10151039
self.gen_namespaces_reg()
@@ -1027,6 +1051,7 @@ def gen(self, srcfiles, output_path):
10271051
self.save(output_path, "pyopencv_generated_type_reg.h", self.code_type_reg)
10281052
self.save(output_path, "pyopencv_generated_ns_reg.h", self.code_ns_reg)
10291053
self.save(output_path, "pyopencv_generated_type_publish.h", self.code_type_publish)
1054+
self.save_json(output_path, "pyopencv_signatures.json", self.py_signatures)
10301055

10311056
if __name__ == "__main__":
10321057
srcfiles = hdr_parser.opencv_hdr_list

0 commit comments

Comments
 (0)