gen2.py 43 KB

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