183 lines
8.6 KiB
Python
183 lines
8.6 KiB
Python
#!/usr/bin/env python3
|
|
|
|
###############################################################################/
|
|
# Copyright (c) 2021 Nerian Vision GmbH
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
###############################################################################/
|
|
|
|
#
|
|
# This helper script auto-generates adapters for all current
|
|
# Nerian stereo device parameters directly from the C++ header file.
|
|
#
|
|
|
|
import pathlib
|
|
import sys
|
|
import os
|
|
|
|
class Generator(object):
|
|
def __init__(self):
|
|
self.pxdcode = \
|
|
'''
|
|
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
# !! CAUTION !!
|
|
# !! !!
|
|
# !! This file is autogenerated from the libvisiontransfer headers !!
|
|
# !! using autogen.py - manual changes are not permanent! !!
|
|
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
cdef extern from "visiontransfer/deviceparameters.h" namespace "visiontransfer":
|
|
cdef cppclass DeviceParameters:
|
|
DeviceParameters(const DeviceInfo &) except +'''.split('\n')
|
|
self.pyxcode = \
|
|
'''# distutils: language=c++
|
|
# cython: language_level=3
|
|
|
|
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
# !! CAUTION !!
|
|
# !! !!
|
|
# !! This file is autogenerated from the libvisiontransfer headers !!
|
|
# !! using autogen.py - manual changes are not permanent! !!
|
|
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
from libcpp.string cimport string
|
|
from libcpp.vector cimport vector
|
|
from libcpp cimport bool
|
|
from cython cimport view
|
|
|
|
cdef class DeviceParameters:
|
|
'''.split('\n')
|
|
|
|
self.pyxcode2 = \
|
|
'''
|
|
cdef cpp.DeviceParameters* c_obj
|
|
|
|
def __cinit__(self, DeviceInfo device_info):
|
|
self.c_obj = new cpp.DeviceParameters(device_info.c_obj)
|
|
|
|
def __dealloc__(self):
|
|
del self.c_obj
|
|
'''.split('\n')
|
|
|
|
def add_pxd(self, ret, fnname, argstr):
|
|
args = [p.strip().split() for p in argstr.split(',')]
|
|
# remove default arguments in pxd (present in pyx)
|
|
for a in args:
|
|
if len(a)>1:
|
|
a[1] = a[1].split('=')[0]
|
|
self.pxdcode.append(' '*8 + ret + ' ' + fnname + ' ('+(', '.join((a[0]+' '+a[1]) for a in args if len(a)>1))+') except +')
|
|
|
|
def add_pyx(self, ret, fnname, argstr, comment):
|
|
# Generate function name reference also used by doc extractor
|
|
args_just_names = [(a.split('=')[0].strip().split()[-1] if a.strip()!='' else '') for a in argstr.split(',')]
|
|
currentname = 'visiontransfer::DeviceParameters::' + fnname + '(' + (', '.join(args_just_names)) + ')'
|
|
fnname_snake = self.snake_case(fnname)
|
|
args = [p.strip().split() for p in argstr.split(',')]
|
|
for i in range(len(args)):
|
|
if len(args[i])>0:
|
|
if args[i][0] in ['int', 'float', 'double', 'bool', 'int&', 'float&', 'double&', 'bool&']:
|
|
pass
|
|
else:
|
|
args[i][0] = "cpp." + str(args[i][0])
|
|
if fnname.startswith('set'):
|
|
argstr = ', '.join(' '.join(a) for a in args if len(a)>0)
|
|
self.pyxcode.append(' '*4 + 'def '+ fnname_snake + '(self' + (', ' if len(argstr) else '') + argstr + '):')
|
|
self.pyxcode.append(' '*8 + '_SUBSTITUTE_DOCSTRING_FOR_("' + currentname + '")')
|
|
self.pyxcode.append(' '*8 + 'self.c_obj.'+ fnname + '(' + ', '.join(a[1].split('=')[0] for a in args if len(a)>1) + ')')
|
|
self.pyxcode.append(' '*0) # extra newline to visually separate blocks
|
|
pass
|
|
else:
|
|
argstr = '' #', '.join(' '.join(a) for a in args if len(a)>0)
|
|
newargstr_defaults = ', '.join(a[1] for a in args if len(a)>0)
|
|
newargstr_nodefaults = ', '.join(a[1].split('=')[0] for a in args if len(a)>0)
|
|
if all(' '.join(a).find('&')<0 for a in args): #len(args)==0 or len(args[0])==0:
|
|
if ret in ['int', 'float', 'double', 'bool', 'int&', 'float&', 'double&', 'bool&']:
|
|
ret = ''
|
|
ret_post = ''
|
|
else:
|
|
ret += '('
|
|
ret_post = ')'
|
|
self.pyxcode.append(' '*4 + 'def '+ fnname_snake + '(self' + (', ' if len(newargstr_defaults) else '') + newargstr_defaults + '):')
|
|
self.pyxcode.append(' '*8 + '_SUBSTITUTE_DOCSTRING_FOR_("' + currentname + '")')
|
|
self.pyxcode.append(' '*8 + 'return '+ret+'self.c_obj.'+ fnname + '(' + newargstr_nodefaults + ')' + ret_post)
|
|
else:
|
|
self.pyxcode.append(' '*4 + 'def '+ fnname_snake + '(self' + (', ' if len(argstr) else '') + argstr + '):')
|
|
self.pyxcode.append(' '*8 + '_SUBSTITUTE_DOCSTRING_FOR_("' + currentname + '")')
|
|
for a in args:
|
|
rawtype = a[0].replace('&', '')
|
|
var = a[1] if a[1].find('=')>0 else (a[1]+' = 0')
|
|
self.pyxcode.append(' '*8 + 'cdef '+rawtype+' '+var)
|
|
self.pyxcode.append(' '*8 + 'self.c_obj.'+ fnname + '(' + newargstr_nodefaults + ')')
|
|
self.pyxcode.append(' '*8 + 'return '+newargstr_nodefaults)
|
|
self.pyxcode.append(' '*0) # extra newline to visually separate blocks
|
|
|
|
def snake_case(self, fnname):
|
|
'''Convert mixed case to Python methods' snake case'''
|
|
fnname_snake = ''
|
|
for c in fnname:
|
|
if c.isupper():
|
|
fnname_snake += '_' + c.lower()
|
|
else:
|
|
fnname_snake += c
|
|
# Some conventional exceptions :)
|
|
fnname_snake = fnname_snake.replace('r_o_i', 'roi')
|
|
return fnname_snake
|
|
|
|
def generate(self, basedir):
|
|
with open(basedir + '/visiontransfer/deviceparameters.h', 'r') as f:
|
|
in_comment = False
|
|
comment = ''
|
|
level = 0
|
|
for l in [ll.strip() for ll in f.readlines()]:
|
|
if in_comment:
|
|
end = l.find('*/')
|
|
thisline = (l if end<0 else l[:end]).lstrip('*').strip()
|
|
if thisline != '':
|
|
comment += '\n' + thisline
|
|
if end >= 0:
|
|
in_comment = False
|
|
else:
|
|
start = l.find('/**')
|
|
if start >= 0:
|
|
in_comment = True
|
|
comment = l[start+3:]
|
|
else:
|
|
if level==1 and l.find(' DeviceParameters {') >= 0:
|
|
# insert class docstring
|
|
self.pyxcode.append(' '*4 + '_SUBSTITUTE_DOCSTRING_FOR_("visiontransfer::DeviceParameters")')
|
|
self.pyxcode.extend(self.pyxcode2)
|
|
self.pyxcode2 = []
|
|
comment = ''
|
|
elif level==2 and l.find('(') >= 0 and l.find('{') > 0 and (l.find('get') > 0 or l.find('set') > 0):
|
|
ret = l.split()[0]
|
|
fnname = l.split()[1].split('(')[0]
|
|
args = l.split('(')[1].split(')')[0]
|
|
self.add_pxd(ret, fnname, args)
|
|
self.add_pyx(ret, fnname, args, comment)
|
|
comment = ''
|
|
else:
|
|
pass
|
|
level += l.count('{')
|
|
level -= l.count('}')
|
|
|
|
if __name__=='__main__':
|
|
basedir = os.getenv("LIBVISIONTRANSFER_SRCDIR", '../..')
|
|
if os.path.isdir(basedir):
|
|
g = Generator()
|
|
g.generate(basedir)
|
|
pathlib.Path("visiontransfer").mkdir(parents=True, exist_ok=True)
|
|
with open('visiontransfer/visiontransfer_parameters_cpp_autogen.pxd', 'w') as f:
|
|
f.write('\n'.join(g.pxdcode))
|
|
with open('visiontransfer/visiontransfer_parameters_autogen.pyx.in', 'w') as f:
|
|
f.write('\n'.join(g.pyxcode))
|
|
else:
|
|
print("Could not open library base dir, please set a correct LIBVISIONTRANSFER_SRCDIR")
|
|
|