gen2.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  1. #!/usr/bin/env python
  2. from __future__ import print_function
  3. import hdr_parser, sys, re, os
  4. from string import Template
  5. from pprint import pprint
  6. from collections import namedtuple
  7. if sys.version_info[0] >= 3:
  8. from io import StringIO
  9. else:
  10. from cStringIO import StringIO
  11. forbidden_arg_types = ["void*"]
  12. ignored_arg_types = ["RNG*"]
  13. pass_by_val_types = ["Point*", "Point2f*", "Rect*", "String*", "double*", "float*", "int*"]
  14. gen_template_check_self = Template("""
  15. ${cname} * self1 = 0;
  16. if (!pyopencv_${name}_getp(self, self1))
  17. return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
  18. ${pname} _self_ = ${cvt}(self1);
  19. """)
  20. gen_template_call_constructor_prelude = Template("""new (&(self->v)) Ptr<$cname>(); // init Ptr with placement new
  21. if(self) """)
  22. gen_template_call_constructor = Template("""self->v.reset(new ${cname}${py_args})""")
  23. gen_template_simple_call_constructor_prelude = Template("""if(self) """)
  24. gen_template_simple_call_constructor = Template("""new (&(self->v)) ${cname}${py_args}""")
  25. gen_template_parse_args = Template("""const char* keywords[] = { $kw_list, NULL };
  26. if( PyArg_ParseTupleAndKeywords(py_args, kw, "$fmtspec", (char**)keywords, $parse_arglist)$code_cvt )""")
  27. gen_template_func_body = Template("""$code_decl
  28. $code_parse
  29. {
  30. ${code_prelude}ERRWRAP2($code_fcall);
  31. $code_ret;
  32. }
  33. """)
  34. gen_template_mappable = Template("""
  35. {
  36. ${mappable} _src;
  37. if (pyopencv_to_safe(src, _src, info))
  38. {
  39. return cv_mappable_to(_src, dst);
  40. }
  41. }
  42. """)
  43. gen_template_type_decl = Template("""
  44. // Converter (${name})
  45. template<>
  46. struct PyOpenCV_Converter< ${cname} >
  47. {
  48. static PyObject* from(const ${cname}& r)
  49. {
  50. return pyopencv_${name}_Instance(r);
  51. }
  52. static bool to(PyObject* src, ${cname}& dst, const ArgInfo& info)
  53. {
  54. if(!src || src == Py_None)
  55. return true;
  56. ${cname} * dst_;
  57. if (pyopencv_${name}_getp(src, dst_))
  58. {
  59. dst = *dst_;
  60. return true;
  61. }
  62. ${mappable_code}
  63. failmsg("Expected ${cname} for argument '%s'", info.name);
  64. return false;
  65. }
  66. };
  67. """)
  68. gen_template_map_type_cvt = Template("""
  69. template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const ArgInfo& info);
  70. """)
  71. gen_template_set_prop_from_map = Template("""
  72. if( PyMapping_HasKeyString(src, (char*)"$propname") )
  73. {
  74. tmp = PyMapping_GetItemString(src, (char*)"$propname");
  75. ok = tmp && pyopencv_to_safe(tmp, dst.$propname, ArgInfo("$propname", false));
  76. Py_DECREF(tmp);
  77. if(!ok) return false;
  78. }""")
  79. gen_template_type_impl = Template("""
  80. // GetSet (${name})
  81. ${getset_code}
  82. // Methods (${name})
  83. ${methods_code}
  84. // Tables (${name})
  85. static PyGetSetDef pyopencv_${name}_getseters[] =
  86. {${getset_inits}
  87. {NULL} /* Sentinel */
  88. };
  89. static PyMethodDef pyopencv_${name}_methods[] =
  90. {
  91. ${methods_inits}
  92. {NULL, NULL}
  93. };
  94. """)
  95. gen_template_get_prop = Template("""
  96. static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure)
  97. {
  98. return pyopencv_from(p->v${access}${member});
  99. }
  100. """)
  101. gen_template_get_prop_algo = Template("""
  102. static PyObject* pyopencv_${name}_get_${member}(pyopencv_${name}_t* p, void *closure)
  103. {
  104. $cname* _self_ = dynamic_cast<$cname*>(p->v.get());
  105. if (!_self_)
  106. return failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
  107. return pyopencv_from(_self_${access}${member});
  108. }
  109. """)
  110. gen_template_set_prop = Template("""
  111. static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure)
  112. {
  113. if (!value)
  114. {
  115. PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
  116. return -1;
  117. }
  118. return pyopencv_to_safe(value, p->v${access}${member}, ArgInfo("value", false)) ? 0 : -1;
  119. }
  120. """)
  121. gen_template_set_prop_algo = Template("""
  122. static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value, void *closure)
  123. {
  124. if (!value)
  125. {
  126. PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute");
  127. return -1;
  128. }
  129. $cname* _self_ = dynamic_cast<$cname*>(p->v.get());
  130. if (!_self_)
  131. {
  132. failmsgp("Incorrect type of object (must be '${name}' or its derivative)");
  133. return -1;
  134. }
  135. return pyopencv_to_safe(value, _self_${access}${member}, ArgInfo("value", false)) ? 0 : -1;
  136. }
  137. """)
  138. gen_template_prop_init = Template("""
  139. {(char*)"${member}", (getter)pyopencv_${name}_get_${member}, NULL, (char*)"${member}", NULL},""")
  140. gen_template_rw_prop_init = Template("""
  141. {(char*)"${member}", (getter)pyopencv_${name}_get_${member}, (setter)pyopencv_${name}_set_${member}, (char*)"${member}", NULL},""")
  142. gen_template_overloaded_function_call = Template("""
  143. {
  144. ${variant}
  145. pyPopulateArgumentConversionErrors();
  146. }
  147. """)
  148. class FormatStrings:
  149. string = 's'
  150. unsigned_char = 'b'
  151. short_int = 'h'
  152. int = 'i'
  153. unsigned_int = 'I'
  154. long = 'l'
  155. unsigned_long = 'k'
  156. long_long = 'L'
  157. unsigned_long_long = 'K'
  158. size_t = 'n'
  159. float = 'f'
  160. double = 'd'
  161. object = 'O'
  162. ArgTypeInfo = namedtuple('ArgTypeInfo',
  163. ['atype', 'format_str', 'default_value',
  164. 'strict_conversion'])
  165. # strict_conversion is False by default
  166. ArgTypeInfo.__new__.__defaults__ = (False,)
  167. simple_argtype_mapping = {
  168. "bool": ArgTypeInfo("bool", FormatStrings.unsigned_char, "0", True),
  169. "size_t": ArgTypeInfo("size_t", FormatStrings.unsigned_long_long, "0", True),
  170. "int": ArgTypeInfo("int", FormatStrings.int, "0", True),
  171. "float": ArgTypeInfo("float", FormatStrings.float, "0.f", True),
  172. "double": ArgTypeInfo("double", FormatStrings.double, "0", True),
  173. "c_string": ArgTypeInfo("char*", FormatStrings.string, '(char*)""'),
  174. "string": ArgTypeInfo("std::string", FormatStrings.object, None, True),
  175. "Stream": ArgTypeInfo("Stream", FormatStrings.object, 'Stream::Null()', True),
  176. }
  177. # Set of reserved keywords for Python. Can be acquired via the following call
  178. # $ python -c "help('keywords')"
  179. # Keywords that are reserved in C/C++ are excluded because they can not be
  180. # used as variables identifiers
  181. python_reserved_keywords = {
  182. "True", "None", "False", "as", "assert", "def", "del", "elif", "except", "exec",
  183. "finally", "from", "global", "import", "in", "is", "lambda", "nonlocal",
  184. "pass", "print", "raise", "with", "yield"
  185. }
  186. def normalize_class_name(name):
  187. return re.sub(r"^cv\.", "", name).replace(".", "_")
  188. def get_type_format_string(arg_type_info):
  189. if arg_type_info.strict_conversion:
  190. return FormatStrings.object
  191. else:
  192. return arg_type_info.format_str
  193. class ClassProp(object):
  194. def __init__(self, decl):
  195. self.tp = decl[0].replace("*", "_ptr")
  196. self.name = decl[1]
  197. self.readonly = True
  198. if "/RW" in decl[3]:
  199. self.readonly = False
  200. class ClassInfo(object):
  201. def __init__(self, name, decl=None):
  202. self.cname = name.replace(".", "::")
  203. self.name = self.wname = normalize_class_name(name)
  204. self.sname = name[name.rfind('.') + 1:]
  205. self.ismap = False
  206. self.issimple = False
  207. self.isalgorithm = False
  208. self.methods = {}
  209. self.props = []
  210. self.mappables = []
  211. self.consts = {}
  212. self.base = None
  213. self.constructor = None
  214. customname = False
  215. if decl:
  216. bases = decl[1].split()[1:]
  217. if len(bases) > 1:
  218. print("Note: Class %s has more than 1 base class (not supported by Python C extensions)" % (self.name,))
  219. print(" Bases: ", " ".join(bases))
  220. print(" Only the first base class will be used")
  221. #return sys.exit(-1)
  222. elif len(bases) == 1:
  223. self.base = bases[0].strip(",")
  224. if self.base.startswith("cv::"):
  225. self.base = self.base[4:]
  226. if self.base == "Algorithm":
  227. self.isalgorithm = True
  228. self.base = self.base.replace("::", "_")
  229. for m in decl[2]:
  230. if m.startswith("="):
  231. wname = m[1:]
  232. npos = name.rfind('.')
  233. if npos >= 0:
  234. self.wname = normalize_class_name(name[:npos] + '.' + wname)
  235. else:
  236. self.wname = wname
  237. customname = True
  238. elif m == "/Map":
  239. self.ismap = True
  240. elif m == "/Simple":
  241. self.issimple = True
  242. self.props = [ClassProp(p) for p in decl[3]]
  243. if not customname and self.wname.startswith("Cv"):
  244. self.wname = self.wname[2:]
  245. def gen_map_code(self, codegen):
  246. all_classes = codegen.classes
  247. code = "static bool pyopencv_to(PyObject* src, %s& dst, const ArgInfo& info)\n{\n PyObject* tmp;\n bool ok;\n" % (self.cname)
  248. code += "".join([gen_template_set_prop_from_map.substitute(propname=p.name,proptype=p.tp) for p in self.props])
  249. if self.base:
  250. code += "\n return pyopencv_to_safe(src, (%s&)dst, info);\n}\n" % all_classes[self.base].cname
  251. else:
  252. code += "\n return true;\n}\n"
  253. return code
  254. def gen_code(self, codegen):
  255. all_classes = codegen.classes
  256. if self.ismap:
  257. return self.gen_map_code(codegen)
  258. getset_code = StringIO()
  259. getset_inits = StringIO()
  260. sorted_props = [(p.name, p) for p in self.props]
  261. sorted_props.sort()
  262. access_op = "->"
  263. if self.issimple:
  264. access_op = "."
  265. for pname, p in sorted_props:
  266. if self.isalgorithm:
  267. getset_code.write(gen_template_get_prop_algo.substitute(name=self.name, cname=self.cname, member=pname, membertype=p.tp, access=access_op))
  268. else:
  269. getset_code.write(gen_template_get_prop.substitute(name=self.name, member=pname, membertype=p.tp, access=access_op))
  270. if p.readonly:
  271. getset_inits.write(gen_template_prop_init.substitute(name=self.name, member=pname))
  272. else:
  273. if self.isalgorithm:
  274. getset_code.write(gen_template_set_prop_algo.substitute(name=self.name, cname=self.cname, member=pname, membertype=p.tp, access=access_op))
  275. else:
  276. getset_code.write(gen_template_set_prop.substitute(name=self.name, member=pname, membertype=p.tp, access=access_op))
  277. getset_inits.write(gen_template_rw_prop_init.substitute(name=self.name, member=pname))
  278. methods_code = StringIO()
  279. methods_inits = StringIO()
  280. sorted_methods = list(self.methods.items())
  281. sorted_methods.sort()
  282. if self.constructor is not None:
  283. methods_code.write(self.constructor.gen_code(codegen))
  284. for mname, m in sorted_methods:
  285. methods_code.write(m.gen_code(codegen))
  286. methods_inits.write(m.get_tab_entry())
  287. code = gen_template_type_impl.substitute(name=self.name, wname=self.wname, cname=self.cname,
  288. getset_code=getset_code.getvalue(), getset_inits=getset_inits.getvalue(),
  289. methods_code=methods_code.getvalue(), methods_inits=methods_inits.getvalue())
  290. return code
  291. def gen_def(self, codegen):
  292. all_classes = codegen.classes
  293. baseptr = "NoBase"
  294. if self.base and self.base in all_classes:
  295. baseptr = all_classes[self.base].name
  296. constructor_name = "0"
  297. if self.constructor is not None:
  298. constructor_name = self.constructor.get_wrapper_name()
  299. return "CVPY_TYPE({}, {}, {}, {}, {}, {});\n".format(
  300. self.wname,
  301. self.name,
  302. self.cname if self.issimple else "Ptr<{}>".format(self.cname),
  303. self.sname if self.issimple else "Ptr",
  304. baseptr,
  305. constructor_name
  306. )
  307. def handle_ptr(tp):
  308. if tp.startswith('Ptr_'):
  309. tp = 'Ptr<' + "::".join(tp.split('_')[1:]) + '>'
  310. return tp
  311. class ArgInfo(object):
  312. def __init__(self, arg_tuple):
  313. self.tp = handle_ptr(arg_tuple[0])
  314. self.name = arg_tuple[1]
  315. if self.name in python_reserved_keywords:
  316. self.name += "_"
  317. self.defval = arg_tuple[2]
  318. self.isarray = False
  319. self.arraylen = 0
  320. self.arraycvt = None
  321. self.inputarg = True
  322. self.outputarg = False
  323. self.returnarg = False
  324. self.isrvalueref = False
  325. for m in arg_tuple[3]:
  326. if m == "/O":
  327. self.inputarg = False
  328. self.outputarg = True
  329. self.returnarg = True
  330. elif m == "/IO":
  331. self.inputarg = True
  332. self.outputarg = True
  333. self.returnarg = True
  334. elif m.startswith("/A"):
  335. self.isarray = True
  336. self.arraylen = m[2:].strip()
  337. elif m.startswith("/CA"):
  338. self.isarray = True
  339. self.arraycvt = m[2:].strip()
  340. elif m == "/RRef":
  341. self.isrvalueref = True
  342. self.py_inputarg = False
  343. self.py_outputarg = False
  344. def isbig(self):
  345. return self.tp in ["Mat", "vector_Mat", "cuda::GpuMat", "GpuMat", "vector_GpuMat", "UMat", "vector_UMat"] # or self.tp.startswith("vector")
  346. def crepr(self):
  347. return "ArgInfo(\"%s\", %d)" % (self.name, self.outputarg)
  348. class FuncVariant(object):
  349. def __init__(self, classname, name, decl, isconstructor, isphantom=False):
  350. self.classname = classname
  351. self.name = self.wname = name
  352. self.isconstructor = isconstructor
  353. self.isphantom = isphantom
  354. self.docstring = decl[5]
  355. self.rettype = decl[4] or handle_ptr(decl[1])
  356. if self.rettype == "void":
  357. self.rettype = ""
  358. self.args = []
  359. self.array_counters = {}
  360. for a in decl[3]:
  361. ainfo = ArgInfo(a)
  362. if ainfo.isarray and not ainfo.arraycvt:
  363. c = ainfo.arraylen
  364. c_arrlist = self.array_counters.get(c, [])
  365. if c_arrlist:
  366. c_arrlist.append(ainfo.name)
  367. else:
  368. self.array_counters[c] = [ainfo.name]
  369. self.args.append(ainfo)
  370. self.init_pyproto()
  371. def init_pyproto(self):
  372. # string representation of argument list, with '[', ']' symbols denoting optional arguments, e.g.
  373. # "src1, src2[, dst[, mask]]" for cv.add
  374. argstr = ""
  375. # list of all input arguments of the Python function, with the argument numbers:
  376. # [("src1", 0), ("src2", 1), ("dst", 2), ("mask", 3)]
  377. # we keep an argument number to find the respective argument quickly, because
  378. # some of the arguments of C function may not present in the Python function (such as array counters)
  379. # or even go in a different order ("heavy" output parameters of the C function
  380. # become the first optional input parameters of the Python function, and thus they are placed right after
  381. # non-optional input parameters)
  382. arglist = []
  383. # the list of "heavy" output parameters. Heavy parameters are the parameters
  384. # that can be expensive to allocate each time, such as vectors and matrices (see isbig).
  385. outarr_list = []
  386. # the list of output parameters. Also includes input/output parameters.
  387. outlist = []
  388. firstoptarg = 1000000
  389. argno = -1
  390. for a in self.args:
  391. argno += 1
  392. if a.name in self.array_counters:
  393. continue
  394. assert not a.tp in forbidden_arg_types, 'Forbidden type "{}" for argument "{}" in "{}" ("{}")'.format(a.tp, a.name, self.name, self.classname)
  395. if a.tp in ignored_arg_types:
  396. continue
  397. if a.returnarg:
  398. outlist.append((a.name, argno))
  399. if (not a.inputarg) and a.isbig():
  400. outarr_list.append((a.name, argno))
  401. continue
  402. if not a.inputarg:
  403. continue
  404. if not a.defval:
  405. arglist.append((a.name, argno))
  406. else:
  407. firstoptarg = min(firstoptarg, len(arglist))
  408. # if there are some array output parameters before the first default parameter, they
  409. # are added as optional parameters before the first optional parameter
  410. if outarr_list:
  411. arglist += outarr_list
  412. outarr_list = []
  413. arglist.append((a.name, argno))
  414. if outarr_list:
  415. firstoptarg = min(firstoptarg, len(arglist))
  416. arglist += outarr_list
  417. firstoptarg = min(firstoptarg, len(arglist))
  418. noptargs = len(arglist) - firstoptarg
  419. argnamelist = [aname for aname, argno in arglist]
  420. argstr = ", ".join(argnamelist[:firstoptarg])
  421. argstr = "[, ".join([argstr] + argnamelist[firstoptarg:])
  422. argstr += "]" * noptargs
  423. if self.rettype:
  424. outlist = [("retval", -1)] + outlist
  425. elif self.isconstructor:
  426. assert outlist == []
  427. outlist = [("self", -1)]
  428. if self.isconstructor:
  429. classname = self.classname
  430. if classname.startswith("Cv"):
  431. classname=classname[2:]
  432. outstr = "<%s object>" % (classname,)
  433. elif outlist:
  434. outstr = ", ".join([o[0] for o in outlist])
  435. else:
  436. outstr = "None"
  437. self.py_arg_str = argstr
  438. self.py_return_str = outstr
  439. self.py_prototype = "%s(%s) -> %s" % (self.wname, argstr, outstr)
  440. self.py_noptargs = noptargs
  441. self.py_arglist = arglist
  442. for aname, argno in arglist:
  443. self.args[argno].py_inputarg = True
  444. for aname, argno in outlist:
  445. if argno >= 0:
  446. self.args[argno].py_outputarg = True
  447. self.py_outlist = outlist
  448. class FuncInfo(object):
  449. def __init__(self, classname, name, cname, isconstructor, namespace, is_static):
  450. self.classname = classname
  451. self.name = name
  452. self.cname = cname
  453. self.isconstructor = isconstructor
  454. self.namespace = namespace
  455. self.is_static = is_static
  456. self.variants = []
  457. def add_variant(self, decl, isphantom=False):
  458. self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor, isphantom))
  459. def get_wrapper_name(self):
  460. name = self.name
  461. if self.classname:
  462. classname = self.classname + "_"
  463. if "[" in name:
  464. name = "getelem"
  465. else:
  466. classname = ""
  467. if self.is_static:
  468. name += "_static"
  469. return "pyopencv_" + self.namespace.replace('.','_') + '_' + classname + name
  470. def get_wrapper_prototype(self, codegen):
  471. full_fname = self.get_wrapper_name()
  472. if self.isconstructor:
  473. return "static int {fn_name}(pyopencv_{type_name}_t* self, PyObject* py_args, PyObject* kw)".format(
  474. fn_name=full_fname, type_name=codegen.classes[self.classname].name)
  475. if self.classname:
  476. self_arg = "self"
  477. else:
  478. self_arg = ""
  479. return "static PyObject* %s(PyObject* %s, PyObject* py_args, PyObject* kw)" % (full_fname, self_arg)
  480. def get_tab_entry(self):
  481. prototype_list = []
  482. docstring_list = []
  483. have_empty_constructor = False
  484. for v in self.variants:
  485. s = v.py_prototype
  486. if (not v.py_arglist) and self.isconstructor:
  487. have_empty_constructor = True
  488. if s not in prototype_list:
  489. prototype_list.append(s)
  490. docstring_list.append(v.docstring)
  491. # if there are just 2 constructors: default one and some other,
  492. # we simplify the notation.
  493. # Instead of ClassName(args ...) -> object or ClassName() -> object
  494. # we write ClassName([args ...]) -> object
  495. if have_empty_constructor and len(self.variants) == 2:
  496. idx = self.variants[1].py_arglist != []
  497. s = self.variants[idx].py_prototype
  498. p1 = s.find("(")
  499. p2 = s.rfind(")")
  500. prototype_list = [s[:p1+1] + "[" + s[p1+1:p2] + "]" + s[p2:]]
  501. # The final docstring will be: Each prototype, followed by
  502. # their relevant doxygen comment
  503. full_docstring = ""
  504. for prototype, body in zip(prototype_list, docstring_list):
  505. full_docstring += Template("$prototype\n$docstring\n\n\n\n").substitute(
  506. prototype=prototype,
  507. docstring='\n'.join(
  508. ['. ' + line
  509. for line in body.split('\n')]
  510. )
  511. )
  512. # Escape backslashes, newlines, and double quotes
  513. full_docstring = full_docstring.strip().replace("\\", "\\\\").replace('\n', '\\n').replace("\"", "\\\"")
  514. # Convert unicode chars to xml representation, but keep as string instead of bytes
  515. full_docstring = full_docstring.encode('ascii', errors='xmlcharrefreplace').decode()
  516. return Template(' {"$py_funcname", CV_PY_FN_WITH_KW_($wrap_funcname, $flags), "$py_docstring"},\n'
  517. ).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
  518. flags = 'METH_STATIC' if self.is_static else '0', py_docstring = full_docstring)
  519. def gen_code(self, codegen):
  520. all_classes = codegen.classes
  521. proto = self.get_wrapper_prototype(codegen)
  522. code = "%s\n{\n" % (proto,)
  523. code += " using namespace %s;\n\n" % self.namespace.replace('.', '::')
  524. selfinfo = None
  525. ismethod = self.classname != "" and not self.isconstructor
  526. # full name is needed for error diagnostic in PyArg_ParseTupleAndKeywords
  527. fullname = self.name
  528. if self.classname:
  529. selfinfo = all_classes[self.classname]
  530. if not self.isconstructor:
  531. if not self.is_static:
  532. code += gen_template_check_self.substitute(
  533. name=selfinfo.name,
  534. cname=selfinfo.cname if selfinfo.issimple else "Ptr<{}>".format(selfinfo.cname),
  535. pname=(selfinfo.cname + '*') if selfinfo.issimple else "Ptr<{}>".format(selfinfo.cname),
  536. cvt='' if selfinfo.issimple else '*'
  537. )
  538. fullname = selfinfo.wname + "." + fullname
  539. all_code_variants = []
  540. for v in self.variants:
  541. code_decl = ""
  542. code_ret = ""
  543. code_cvt_list = []
  544. code_args = "("
  545. all_cargs = []
  546. if v.isphantom and ismethod and not self.is_static:
  547. code_args += "_self_"
  548. # declare all the C function arguments,
  549. # add necessary conversions from Python objects to code_cvt_list,
  550. # form the function/method call,
  551. # for the list of type mappings
  552. for a in v.args:
  553. if a.tp in ignored_arg_types:
  554. defval = a.defval
  555. if not defval and a.tp.endswith("*"):
  556. defval = "0"
  557. assert defval
  558. if not code_args.endswith("("):
  559. code_args += ", "
  560. code_args += defval
  561. all_cargs.append([[None, ""], ""])
  562. continue
  563. tp1 = tp = a.tp
  564. amp = ""
  565. defval0 = ""
  566. if tp in pass_by_val_types:
  567. tp = tp1 = tp[:-1]
  568. amp = "&"
  569. if tp.endswith("*"):
  570. defval0 = "0"
  571. tp1 = tp.replace("*", "_ptr")
  572. tp_candidates = [a.tp, normalize_class_name(self.namespace + "." + a.tp)]
  573. if any(tp in codegen.enums.keys() for tp in tp_candidates):
  574. defval0 = "static_cast<%s>(%d)" % (a.tp, 0)
  575. arg_type_info = simple_argtype_mapping.get(tp, ArgTypeInfo(tp, FormatStrings.object, defval0, True))
  576. parse_name = a.name
  577. if a.py_inputarg:
  578. if arg_type_info.strict_conversion:
  579. code_decl += " PyObject* pyobj_%s = NULL;\n" % (a.name,)
  580. parse_name = "pyobj_" + a.name
  581. if a.tp == 'char':
  582. code_cvt_list.append("convert_to_char(pyobj_%s, &%s, %s)" % (a.name, a.name, a.crepr()))
  583. else:
  584. code_cvt_list.append("pyopencv_to_safe(pyobj_%s, %s, %s)" % (a.name, a.name, a.crepr()))
  585. all_cargs.append([arg_type_info, parse_name])
  586. defval = a.defval
  587. if not defval:
  588. defval = arg_type_info.default_value
  589. else:
  590. if "UMat" in tp:
  591. if "Mat" in defval and "UMat" not in defval:
  592. defval = defval.replace("Mat", "UMat")
  593. if "cuda::GpuMat" in tp:
  594. if "Mat" in defval and "GpuMat" not in defval:
  595. defval = defval.replace("Mat", "cuda::GpuMat")
  596. # "tp arg = tp();" is equivalent to "tp arg;" in the case of complex types
  597. if defval == tp + "()" and arg_type_info.format_str == FormatStrings.object:
  598. defval = ""
  599. if a.outputarg and not a.inputarg:
  600. defval = ""
  601. if defval:
  602. code_decl += " %s %s=%s;\n" % (arg_type_info.atype, a.name, defval)
  603. else:
  604. code_decl += " %s %s;\n" % (arg_type_info.atype, a.name)
  605. if not code_args.endswith("("):
  606. code_args += ", "
  607. if a.isrvalueref:
  608. a.name = 'std::move(' + a.name + ')'
  609. code_args += amp + a.name
  610. code_args += ")"
  611. if self.isconstructor:
  612. if selfinfo.issimple:
  613. templ_prelude = gen_template_simple_call_constructor_prelude
  614. templ = gen_template_simple_call_constructor
  615. else:
  616. templ_prelude = gen_template_call_constructor_prelude
  617. templ = gen_template_call_constructor
  618. code_prelude = templ_prelude.substitute(name=selfinfo.name, cname=selfinfo.cname)
  619. code_fcall = templ.substitute(name=selfinfo.name, cname=selfinfo.cname, py_args=code_args)
  620. if v.isphantom:
  621. code_fcall = code_fcall.replace("new " + selfinfo.cname, self.cname.replace("::", "_"))
  622. else:
  623. code_prelude = ""
  624. code_fcall = ""
  625. if v.rettype:
  626. code_decl += " " + v.rettype + " retval;\n"
  627. code_fcall += "retval = "
  628. if not v.isphantom and ismethod and not self.is_static:
  629. code_fcall += "_self_->" + self.cname
  630. else:
  631. code_fcall += self.cname
  632. code_fcall += code_args
  633. if code_cvt_list:
  634. code_cvt_list = [""] + code_cvt_list
  635. # add info about return value, if any, to all_cargs. if there non-void return value,
  636. # it is encoded in v.py_outlist as ("retval", -1) pair.
  637. # As [-1] in Python accesses the last element of a list, we automatically handle the return value by
  638. # adding the necessary info to the end of all_cargs list.
  639. if v.rettype:
  640. tp = v.rettype
  641. tp1 = tp.replace("*", "_ptr")
  642. default_info = ArgTypeInfo(tp, FormatStrings.object, "0")
  643. arg_type_info = simple_argtype_mapping.get(tp, default_info)
  644. all_cargs.append(arg_type_info)
  645. if v.args and v.py_arglist:
  646. # form the format spec for PyArg_ParseTupleAndKeywords
  647. fmtspec = "".join([
  648. get_type_format_string(all_cargs[argno][0])
  649. for aname, argno in v.py_arglist
  650. ])
  651. if v.py_noptargs > 0:
  652. fmtspec = fmtspec[:-v.py_noptargs] + "|" + fmtspec[-v.py_noptargs:]
  653. fmtspec += ":" + fullname
  654. # form the argument parse code that:
  655. # - declares the list of keyword parameters
  656. # - calls PyArg_ParseTupleAndKeywords
  657. # - converts complex arguments from PyObject's to native OpenCV types
  658. code_parse = gen_template_parse_args.substitute(
  659. kw_list = ", ".join(['"' + aname + '"' for aname, argno in v.py_arglist]),
  660. fmtspec = fmtspec,
  661. parse_arglist = ", ".join(["&" + all_cargs[argno][1] for aname, argno in v.py_arglist]),
  662. code_cvt = " &&\n ".join(code_cvt_list))
  663. else:
  664. code_parse = "if(PyObject_Size(py_args) == 0 && (!kw || PyObject_Size(kw) == 0))"
  665. if len(v.py_outlist) == 0:
  666. code_ret = "Py_RETURN_NONE"
  667. elif len(v.py_outlist) == 1:
  668. if self.isconstructor:
  669. code_ret = "return 0"
  670. else:
  671. aname, argno = v.py_outlist[0]
  672. code_ret = "return pyopencv_from(%s)" % (aname,)
  673. else:
  674. # there is more than 1 return parameter; form the tuple out of them
  675. fmtspec = "N"*len(v.py_outlist)
  676. code_ret = "return Py_BuildValue(\"(%s)\", %s)" % \
  677. (fmtspec, ", ".join(["pyopencv_from(" + aname + ")" for aname, argno in v.py_outlist]))
  678. all_code_variants.append(gen_template_func_body.substitute(code_decl=code_decl,
  679. code_parse=code_parse, code_prelude=code_prelude, code_fcall=code_fcall, code_ret=code_ret))
  680. if len(all_code_variants)==1:
  681. # if the function/method has only 1 signature, then just put it
  682. code += all_code_variants[0]
  683. else:
  684. # try to execute each signature, add an interlude between function
  685. # calls to collect error from all conversions
  686. code += ' pyPrepareArgumentConversionErrorsStorage({});\n'.format(len(all_code_variants))
  687. code += ' \n'.join(gen_template_overloaded_function_call.substitute(variant=v)
  688. for v in all_code_variants)
  689. code += ' pyRaiseCVOverloadException("{}");\n'.format(self.name)
  690. def_ret = "NULL"
  691. if self.isconstructor:
  692. def_ret = "-1"
  693. code += "\n return %s;\n}\n\n" % def_ret
  694. cname = self.cname
  695. classinfo = None
  696. #dump = False
  697. #if dump: pprint(vars(self))
  698. #if dump: pprint(vars(self.variants[0]))
  699. if self.classname:
  700. classinfo = all_classes[self.classname]
  701. #if dump: pprint(vars(classinfo))
  702. if self.isconstructor:
  703. py_name = 'cv.' + classinfo.wname
  704. elif self.is_static:
  705. py_name = '.'.join([self.namespace, classinfo.sname + '_' + self.variants[0].wname])
  706. else:
  707. cname = classinfo.cname + '::' + cname
  708. py_name = 'cv.' + classinfo.wname + '.' + self.variants[0].wname
  709. else:
  710. py_name = '.'.join([self.namespace, self.variants[0].wname])
  711. #if dump: print(cname + " => " + py_name)
  712. py_signatures = codegen.py_signatures.setdefault(cname, [])
  713. for v in self.variants:
  714. s = dict(name=py_name, arg=v.py_arg_str, ret=v.py_return_str)
  715. for old in py_signatures:
  716. if s == old:
  717. break
  718. else:
  719. py_signatures.append(s)
  720. return code
  721. class Namespace(object):
  722. def __init__(self):
  723. self.funcs = {}
  724. self.consts = {}
  725. class PythonWrapperGenerator(object):
  726. def __init__(self):
  727. self.clear()
  728. def clear(self):
  729. self.classes = {}
  730. self.namespaces = {}
  731. self.consts = {}
  732. self.enums = {}
  733. self.code_include = StringIO()
  734. self.code_enums = StringIO()
  735. self.code_types = StringIO()
  736. self.code_funcs = StringIO()
  737. self.code_ns_reg = StringIO()
  738. self.code_ns_init = StringIO()
  739. self.code_type_publish = StringIO()
  740. self.py_signatures = dict()
  741. self.class_idx = 0
  742. def add_class(self, stype, name, decl):
  743. classinfo = ClassInfo(name, decl)
  744. classinfo.decl_idx = self.class_idx
  745. self.class_idx += 1
  746. if classinfo.name in self.classes:
  747. print("Generator error: class %s (cname=%s) already exists" \
  748. % (classinfo.name, classinfo.cname))
  749. sys.exit(-1)
  750. self.classes[classinfo.name] = classinfo
  751. # Add Class to json file.
  752. namespace, classes, name = self.split_decl_name(name)
  753. namespace = '.'.join(namespace)
  754. name = '_'.join(classes+[name])
  755. py_name = 'cv.' + classinfo.wname # use wrapper name
  756. py_signatures = self.py_signatures.setdefault(classinfo.cname, [])
  757. py_signatures.append(dict(name=py_name))
  758. #print('class: ' + classinfo.cname + " => " + py_name)
  759. def split_decl_name(self, name):
  760. chunks = name.split('.')
  761. namespace = chunks[:-1]
  762. classes = []
  763. while namespace and '.'.join(namespace) not in self.parser.namespaces:
  764. classes.insert(0, namespace.pop())
  765. return namespace, classes, chunks[-1]
  766. def add_const(self, name, decl):
  767. cname = name.replace('.','::')
  768. namespace, classes, name = self.split_decl_name(name)
  769. namespace = '.'.join(namespace)
  770. name = '_'.join(classes+[name])
  771. ns = self.namespaces.setdefault(namespace, Namespace())
  772. if name in ns.consts:
  773. print("Generator error: constant %s (cname=%s) already exists" \
  774. % (name, cname))
  775. sys.exit(-1)
  776. ns.consts[name] = cname
  777. value = decl[1]
  778. py_name = '.'.join([namespace, name])
  779. py_signatures = self.py_signatures.setdefault(cname, [])
  780. py_signatures.append(dict(name=py_name, value=value))
  781. #print(cname + ' => ' + str(py_name) + ' (value=' + value + ')')
  782. def add_enum(self, name, decl):
  783. wname = normalize_class_name(name)
  784. if wname.endswith("<unnamed>"):
  785. wname = None
  786. else:
  787. self.enums[wname] = name
  788. const_decls = decl[3]
  789. for decl in const_decls:
  790. name = decl[0]
  791. self.add_const(name.replace("const ", "").strip(), decl)
  792. def add_func(self, decl):
  793. namespace, classes, barename = self.split_decl_name(decl[0])
  794. cname = "::".join(namespace+classes+[barename])
  795. name = barename
  796. classname = ''
  797. bareclassname = ''
  798. if classes:
  799. classname = normalize_class_name('.'.join(namespace+classes))
  800. bareclassname = classes[-1]
  801. namespace_str = '.'.join(namespace)
  802. isconstructor = name == bareclassname
  803. is_static = False
  804. isphantom = False
  805. mappable = None
  806. for m in decl[2]:
  807. if m == "/S":
  808. is_static = True
  809. elif m == "/phantom":
  810. isphantom = True
  811. cname = cname.replace("::", "_")
  812. elif m.startswith("="):
  813. name = m[1:]
  814. elif m.startswith("/mappable="):
  815. mappable = m[10:]
  816. self.classes[classname].mappables.append(mappable)
  817. return
  818. if isconstructor:
  819. name = "_".join(classes[:-1]+[name])
  820. if is_static:
  821. # Add it as a method to the class
  822. func_map = self.classes[classname].methods
  823. func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace_str, is_static))
  824. func.add_variant(decl, isphantom)
  825. # Add it as global function
  826. g_name = "_".join(classes+[name])
  827. w_classes = []
  828. for i in range(0, len(classes)):
  829. classes_i = classes[:i+1]
  830. classname_i = normalize_class_name('.'.join(namespace+classes_i))
  831. w_classname = self.classes[classname_i].wname
  832. namespace_prefix = normalize_class_name('.'.join(namespace)) + '_'
  833. if w_classname.startswith(namespace_prefix):
  834. w_classname = w_classname[len(namespace_prefix):]
  835. w_classes.append(w_classname)
  836. g_wname = "_".join(w_classes+[name])
  837. func_map = self.namespaces.setdefault(namespace_str, Namespace()).funcs
  838. func = func_map.setdefault(g_name, FuncInfo("", g_name, cname, isconstructor, namespace_str, False))
  839. func.add_variant(decl, isphantom)
  840. if g_wname != g_name: # TODO OpenCV 5.0
  841. wfunc = func_map.setdefault(g_wname, FuncInfo("", g_wname, cname, isconstructor, namespace_str, False))
  842. wfunc.add_variant(decl, isphantom)
  843. else:
  844. if classname and not isconstructor:
  845. if not isphantom:
  846. cname = barename
  847. func_map = self.classes[classname].methods
  848. else:
  849. func_map = self.namespaces.setdefault(namespace_str, Namespace()).funcs
  850. func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace_str, is_static))
  851. func.add_variant(decl, isphantom)
  852. if classname and isconstructor:
  853. self.classes[classname].constructor = func
  854. def gen_namespace(self, ns_name):
  855. ns = self.namespaces[ns_name]
  856. wname = normalize_class_name(ns_name)
  857. self.code_ns_reg.write('static PyMethodDef methods_%s[] = {\n'%wname)
  858. for name, func in sorted(ns.funcs.items()):
  859. if func.isconstructor:
  860. continue
  861. self.code_ns_reg.write(func.get_tab_entry())
  862. custom_entries_macro = 'PYOPENCV_EXTRA_METHODS_{}'.format(wname.upper())
  863. self.code_ns_reg.write('#ifdef {}\n {}\n#endif\n'.format(custom_entries_macro, custom_entries_macro))
  864. self.code_ns_reg.write(' {NULL, NULL}\n};\n\n')
  865. self.code_ns_reg.write('static ConstDef consts_%s[] = {\n'%wname)
  866. for name, cname in sorted(ns.consts.items()):
  867. self.code_ns_reg.write(' {"%s", static_cast<long>(%s)},\n'%(name, cname))
  868. compat_name = re.sub(r"([a-z])([A-Z])", r"\1_\2", name).upper()
  869. if name != compat_name:
  870. self.code_ns_reg.write(' {"%s", static_cast<long>(%s)},\n'%(compat_name, cname))
  871. custom_entries_macro = 'PYOPENCV_EXTRA_CONSTANTS_{}'.format(wname.upper())
  872. self.code_ns_reg.write('#ifdef {}\n {}\n#endif\n'.format(custom_entries_macro, custom_entries_macro))
  873. self.code_ns_reg.write(' {NULL, 0}\n};\n\n')
  874. def gen_enum_reg(self, enum_name):
  875. name_seg = enum_name.split(".")
  876. is_enum_class = False
  877. if len(name_seg) >= 2 and name_seg[-1] == name_seg[-2]:
  878. enum_name = ".".join(name_seg[:-1])
  879. is_enum_class = True
  880. wname = normalize_class_name(enum_name)
  881. cname = enum_name.replace(".", "::")
  882. code = ""
  883. if re.sub(r"^cv\.", "", enum_name) != wname:
  884. code += "typedef {0} {1};\n".format(cname, wname)
  885. code += "CV_PY_FROM_ENUM({0});\nCV_PY_TO_ENUM({0});\n\n".format(wname)
  886. self.code_enums.write(code)
  887. def save(self, path, name, buf):
  888. with open(path + "/" + name, "wt") as f:
  889. f.write(buf.getvalue())
  890. def save_json(self, path, name, value):
  891. import json
  892. with open(path + "/" + name, "wt") as f:
  893. json.dump(value, f)
  894. def gen(self, srcfiles, output_path):
  895. self.clear()
  896. self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True, generate_gpumat_decls=True)
  897. # step 1: scan the headers and build more descriptive maps of classes, consts, functions
  898. for hdr in srcfiles:
  899. decls = self.parser.parse(hdr)
  900. if len(decls) == 0:
  901. continue
  902. if hdr.find('misc/python/shadow_') < 0: # Avoid including the "shadow_" files
  903. if hdr.find('opencv2/') >= 0:
  904. # put relative path
  905. self.code_include.write('#include "{0}"\n'.format(hdr[hdr.rindex('opencv2/'):]))
  906. else:
  907. self.code_include.write('#include "{0}"\n'.format(hdr))
  908. for decl in decls:
  909. name = decl[0]
  910. if name.startswith("struct") or name.startswith("class"):
  911. # class/struct
  912. p = name.find(" ")
  913. stype = name[:p]
  914. name = name[p+1:].strip()
  915. self.add_class(stype, name, decl)
  916. elif name.startswith("const"):
  917. # constant
  918. self.add_const(name.replace("const ", "").strip(), decl)
  919. elif name.startswith("enum"):
  920. # enum
  921. self.add_enum(name.rsplit(" ", 1)[1], decl)
  922. else:
  923. # function
  924. self.add_func(decl)
  925. # step 1.5 check if all base classes exist
  926. for name, classinfo in self.classes.items():
  927. if classinfo.base:
  928. chunks = classinfo.base.split('_')
  929. base = '_'.join(chunks)
  930. while base not in self.classes and len(chunks)>1:
  931. del chunks[-2]
  932. base = '_'.join(chunks)
  933. if base not in self.classes:
  934. print("Generator error: unable to resolve base %s for %s"
  935. % (classinfo.base, classinfo.name))
  936. sys.exit(-1)
  937. base_instance = self.classes[base]
  938. classinfo.base = base
  939. classinfo.isalgorithm |= base_instance.isalgorithm # wrong processing of 'isalgorithm' flag:
  940. # doesn't work for trees(graphs) with depth > 2
  941. self.classes[name] = classinfo
  942. # tree-based propagation of 'isalgorithm'
  943. processed = dict()
  944. def process_isalgorithm(classinfo):
  945. if classinfo.isalgorithm or classinfo in processed:
  946. return classinfo.isalgorithm
  947. res = False
  948. if classinfo.base:
  949. res = process_isalgorithm(self.classes[classinfo.base])
  950. #assert not (res == True or classinfo.isalgorithm is False), "Internal error: " + classinfo.name + " => " + classinfo.base
  951. classinfo.isalgorithm |= res
  952. res = classinfo.isalgorithm
  953. processed[classinfo] = True
  954. return res
  955. for name, classinfo in self.classes.items():
  956. process_isalgorithm(classinfo)
  957. # step 2: generate code for the classes and their methods
  958. classlist = list(self.classes.items())
  959. classlist.sort()
  960. for name, classinfo in classlist:
  961. self.code_types.write("//{}\n".format(80*"="))
  962. self.code_types.write("// {} ({})\n".format(name, 'Map' if classinfo.ismap else 'Generic'))
  963. self.code_types.write("//{}\n".format(80*"="))
  964. self.code_types.write(classinfo.gen_code(self))
  965. if classinfo.ismap:
  966. self.code_types.write(gen_template_map_type_cvt.substitute(name=classinfo.name, cname=classinfo.cname))
  967. else:
  968. mappable_code = "\n".join([
  969. gen_template_mappable.substitute(cname=classinfo.cname, mappable=mappable)
  970. for mappable in classinfo.mappables])
  971. code = gen_template_type_decl.substitute(
  972. name=classinfo.name,
  973. cname=classinfo.cname if classinfo.issimple else "Ptr<{}>".format(classinfo.cname),
  974. mappable_code=mappable_code
  975. )
  976. self.code_types.write(code)
  977. # register classes in the same order as they have been declared.
  978. # this way, base classes will be registered in Python before their derivatives.
  979. classlist1 = [(classinfo.decl_idx, name, classinfo) for name, classinfo in classlist]
  980. classlist1.sort()
  981. for decl_idx, name, classinfo in classlist1:
  982. if classinfo.ismap:
  983. continue
  984. self.code_type_publish.write(classinfo.gen_def(self))
  985. # step 3: generate the code for all the global functions
  986. for ns_name, ns in sorted(self.namespaces.items()):
  987. if ns_name.split('.')[0] != 'cv':
  988. continue
  989. for name, func in sorted(ns.funcs.items()):
  990. if func.isconstructor:
  991. continue
  992. code = func.gen_code(self)
  993. self.code_funcs.write(code)
  994. self.gen_namespace(ns_name)
  995. self.code_ns_init.write('CVPY_MODULE("{}", {});\n'.format(ns_name[2:], normalize_class_name(ns_name)))
  996. # step 4: generate the code for enum types
  997. enumlist = list(self.enums.values())
  998. enumlist.sort()
  999. for name in enumlist:
  1000. self.gen_enum_reg(name)
  1001. # step 5: generate the code for constants
  1002. constlist = list(self.consts.items())
  1003. constlist.sort()
  1004. for name, constinfo in constlist:
  1005. self.gen_const_reg(constinfo)
  1006. # That's it. Now save all the files
  1007. self.save(output_path, "pyopencv_generated_include.h", self.code_include)
  1008. self.save(output_path, "pyopencv_generated_funcs.h", self.code_funcs)
  1009. self.save(output_path, "pyopencv_generated_enums.h", self.code_enums)
  1010. self.save(output_path, "pyopencv_generated_types.h", self.code_type_publish)
  1011. self.save(output_path, "pyopencv_generated_types_content.h", self.code_types)
  1012. self.save(output_path, "pyopencv_generated_modules.h", self.code_ns_init)
  1013. self.save(output_path, "pyopencv_generated_modules_content.h", self.code_ns_reg)
  1014. self.save_json(output_path, "pyopencv_signatures.json", self.py_signatures)
  1015. if __name__ == "__main__":
  1016. srcfiles = hdr_parser.opencv_hdr_list
  1017. dstdir = "/Users/vp/tmp"
  1018. if len(sys.argv) > 1:
  1019. dstdir = sys.argv[1]
  1020. if len(sys.argv) > 2:
  1021. with open(sys.argv[2], 'r') as f:
  1022. srcfiles = [l.strip() for l in f.readlines()]
  1023. generator = PythonWrapperGenerator()
  1024. generator.gen(srcfiles, dstdir)