python-efl/eolian/generator.py

990 lines
32 KiB
Python
Executable File

#!/usr/bin/python
import os
import textwrap
from keyword import iskeyword
# from collections import Counter
import logging
handler = logging.StreamHandler()
formatter = logging.Formatter("%(name)s %(levelname)s: %(message)s")
handler.setFormatter(formatter)
log = logging.getLogger("eolian")
log.addHandler(handler)
log_level = logging.WARN
log.setLevel(log_level)
import eolian
from converters import convert_in_param, convert_out_param, conv_type_ret, \
conv_cls_name, EolianTypeError, event_conversion_get
# XXX: C namespaces don't include this top level name
PY_EFL_TOP_LEVEL_PACKAGE = "efl"
generated_pxis = {}
def init():
eolian.init()
def shutdown():
eolian.shutdown()
def system_directory_scan():
eolian.system_directory_scan()
def all_eo_files_parse():
eolian.all_eo_files_parse()
def all_eot_files_parse():
eolian.all_eot_files_parse()
class EolianSkip(Exception):
pass
class Generator(object):
tab = " "
def __init__(self):
self.result = []
self.level = 0
def indent(self):
self.level += 1
def dedent(self):
self.level -= 1
def write(self, text=None, wrapped=False, i_ind=None, s_ind=None):
if not i_ind:
i_ind = self.level * self.tab
if not s_ind:
s_ind = self.level * self.tab
if text:
if wrapped:
self.result.append(textwrap.fill(
text,
initial_indent=i_ind,
subsequent_indent=s_ind,
width=79
))
else:
self.result.append(i_ind + text)
else:
self.result.append("")
#def docstring_write(self, docstrings):
#if not args.enable_docstrings or not docstrings:
#return
#elif len(docstrings) == 1:
#self.write('"""' + docstrings[0] + '"""')
#else:
#self.write('"""')
#for docs in docstrings:
#if docs.startswith("- ") or \
#docs.startswith(".. ") or \
#docs.startswith(":"):
#self.write(
#docs, wrapped=True,
#s_ind=self.level * self.tab + " "
#)
#elif docs.startswith(" - "):
#self.write(
#docs, wrapped=True,
#s_ind=self.level * self.tab + " "
#)
#else:
#self.write(docs, wrapped=True)
#self.write('"""')
def printout(self):
result = "\n".join(self.result)
return result
def clear(self):
self.result = []
self.level = 0
class PyxGenerator(Generator):
RET_PARAM = "py_efl_ret"
def method_header_write(self, name, params, clsm=False):
params2 = []
if clsm:
self.write("@classmethod")
params2.append("cls")
else:
params2.append("self")
for t, n in params:
params2.append(" ".join((t, n)).strip())
params2 = ", ".join(params2)
define = "def %s(%s):" % (name, params2)
self.write(define)
def out_cdefs_write(self, out_cdefs):
if not out_cdefs:
return
self.write("cdef:")
self.indent()
types = {}
for t, n in out_cdefs:
types.setdefault(t, []).append(n)
for t, names in types.items():
#t = t.c_type
if "*" in t:
# complex, write one per line
for n in names:
self.write("%s %s" % (t, n))
else:
# simple, all on one line
self.write("%s %s" % (t, ", ".join(names)))
self.dedent()
def c_call_write(self, c_name, c_params, ret_type=None):
# TODO: Eina_Bool ret value from do_start, useful?
self.write("_eo_do_start(self.obj, NULL, EINA_FALSE, CFILE, CFUNC, CLINE)")
c_call = ""
if ret_type:
c_call += "cdef " + ret_type + " " + self.RET_PARAM + " = " + "<{0}>".format(ret_type)
c_call += c_name + "("
if not c_params:
c_call += ")"
self.write(c_call)
else:
self.write(c_call)
self.indent()
for p in c_params:
self.write(p + ",")
self.write(")")
self.dedent()
self.write("_eo_do_end(&self.obj)")
class Function(object):
RET_PARAM = "py_efl_ret"
def __init__(self, func, prefix, isget=None):
self.name = func.name
self.func = func
self.prefix = prefix
self.isget = isget
self.c_name = func.full_c_name
self.c_params = []
ret_type = None
ftypes = eolian.FunctionType
if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not isget:
ret_type = func.return_type_get(eolian.FunctionType.PROP_SET)
self.c_name += "_set"
for p in func.parameters:
name = p.name
if iskeyword(name):
name += "_"
self.c_params.append((p.type.c_type, name))
if (func.type == ftypes.PROP_GET or func.type == ftypes.PROPERTY) and isget:
ret_type = func.return_type_get(eolian.FunctionType.PROP_GET)
self.c_name += "_get"
func_parameters = list(func.parameters)
if len(func_parameters) == 1 and not ret_type:
ret_type = func_parameters[0].type
else:
for p in func_parameters:
name = p.name
if iskeyword(name):
name += "_"
self.c_params.append((p.type.c_type + "*", name))
if func.type == ftypes.METHOD:
ret_type = func.return_type_get(eolian.FunctionType.METHOD)
for p in func.parameters:
name = p.name
if iskeyword(name):
name += "_"
c_type = p.type.c_type
if p.direction == eolian.ParameterDir.OUT:
c_type += "*"
self.c_params.append((c_type, name))
self.c_ret_type = ret_type.c_type if ret_type else "void"
def cdef_generate(self, gen):
func = self.func
ftypes = eolian.FunctionType
if func.type == ftypes.PROP_SET and self.isget:
return
if func.type == ftypes.PROP_GET and not self.isget:
return
rtype = self.c_ret_type
if not rtype:
rtype = "void"
line = " ".join((rtype, self.c_name))
line += "("
line += ", ".join([" ".join((t, n)) for t, n in self.c_params])
line += ")"
gen.write(line)
def generate(self, gen):
func = self.func
py_name = None
c_name = self.c_name
header_params = []
c_call_params = []
return_params = []
expand_params = []
conv_in_py_exps = []
out_cdefs = []
ret_type = None
ftypes = eolian.FunctionType
if func.type == ftypes.METHOD:
py_name = func.name
if iskeyword(py_name): # Check if name is python reserved
py_name += "_"
func_params = func.parameters
for p in func_params:
di = p.direction
c_type = p.type.c_type
p_name = p.name
if iskeyword(p_name):
p_name += "_"
if di == eolian.ParameterDir.IN:
conv_expr_py, c_type, name = convert_in_param(p.type, p_name, p.is_nonull)
conv_in_py_exps.append(conv_expr_py)
header_params.append((c_type, p_name))
c_call_params.append(name)
elif di == eolian.ParameterDir.OUT:
out_cdefs.append((c_type, p.name))
c_type, name = convert_out_param(p.type, p_name)
c_call_params.append("&" + p.name)
return_params.append((p.type, name))
elif di == eolian.ParameterDir.INOUT:
conv_expr_py, c_type, name = convert_in_param(p.type, p_name, p.is_nonull)
header_params.append((c_type, p_name))
c_call_params.append(name)
c_type, name = convert_out_param(p.type, p_name)
return_params.append((p.type, p_name))
ret_type = func.return_type_get(eolian.FunctionType.METHOD)
if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY) and not self.isget:
py_name = "__set__"
expand_params = []
if list(func.property_keys):
gen.method_header_write(py_name, (("", "tmp_value"),))
gen.indent()
gen.write("pass")
gen.dedent()
raise RuntimeError("Property keys not supported")
for p in list(func.property_values):
p_name = p.name
if iskeyword(p_name):
p_name += "_"
try:
conv_expr_py, c_type, name = convert_in_param(p.type, p_name, p.is_nonull)
except Exception:
gen.method_header_write(py_name, (("", "tmp_value"),))
gen.indent()
gen.write("pass")
gen.dedent()
raise
conv_in_py_exps.append(conv_expr_py)
expand_params.append((c_type, p_name))
c_call_params.append(name)
header_params = (("", "tmp_value"),)
#ret_type = func.return_type_get(eolian.FunctionType.PROP_SET)
if (func.type == ftypes.PROP_GET or func.type == ftypes.PROPERTY) and self.isget:
py_name = "__get__"
if list(func.property_keys):
gen.method_header_write(py_name, header_params)
gen.indent()
gen.write("pass")
gen.dedent()
raise RuntimeError("Property keys not supported")
ret_type = func.return_type_get(eolian.FunctionType.PROP_GET)
property_values = list(func.property_values)
if len(property_values) == 1 and not ret_type:
ret_type = property_values[0].type
else:
for p in list(func.property_values):
c_type = p.type.c_type
name = p.name
if iskeyword(name):
name += "_"
out_cdefs.append((c_type, name))
c_call_params.append("&%s" % (name))
try:
c_type, name = convert_out_param(p.type, name)
except Exception:
gen.method_header_write(py_name, header_params)
gen.indent()
gen.write("pass")
gen.dedent()
raise
return_params.append((p.type, name))
if not py_name:
return
gen.method_header_write(py_name, header_params)
gen.indent()
if expand_params:
tmp_prms = ", ".join(["tmp_prm%d" % (i) for i in range(len(expand_params))])
gen.write("%s = tmp_value" % (tmp_prms))
gen.write("cdef:")
gen.indent()
for i, (t, n) in enumerate(expand_params):
gen.write("%s = tmp_prm%d" % (" ".join((t, n)).strip(), i))
gen.dedent()
for e in conv_in_py_exps:
if e:
gen.write(e)
gen.out_cdefs_write(out_cdefs)
if ret_type:
ret_type2 = ret_type.c_type
else:
ret_type2 = None
gen.c_call_write(c_name, c_call_params, ret_type2)
if return_params:
rparams = []
for t, n in return_params:
name = n
if iskeyword(name):
name += "_"
try:
py_ret_type, c_ret_type = conv_type_ret(t)
except EolianTypeError:
gen.write("# FIXME: Unknown return type %s" % t.c_type)
gen.dedent()
raise
rparams.append((c_ret_type, name))
gen.write("return %s" % (", ".join([r[1] for r in rparams])))
elif ret_type:
ret = self.RET_PARAM
try:
ret_type, ret = convert_out_param(ret_type, ret)
except EolianTypeError:
gen.write("# FIXME: Unknown return type %s" % ret_type.c_type)
gen.dedent()
raise
gen.write("return %s" % (ret))
gen.dedent()
gen.write()
def doc_generate(self, gen):
func_desc = func.description_get(eolian.FunctionType.METHOD)
if func_desc:
func_desc = func_desc.split("\n\n")
for desc in func_desc:
for pat, repl in docstring_replacements:
if isinstance(pat, basestring):
desc = desc.replace(pat, repl)
else:
desc = pat.sub(repl, desc)
if desc:
self.docs.append(desc)
self.docs.append("")
self.docs.append(":param %s: %s" % (name, desc))
self.docs.append(":type %s: %s" % (name, ptype))
if self.returns:
self.docs.append(
":return: " + ", ".join([r[1] for r in self.returns]))
self.docs.append(
":rtype: " + ", ".join([r[0] for r in self.returns]))
elif self.ret_type:
if ret_desc:
self.docs.append(":return: " + ret_desc)
self.docs.append(":rtype: " + self.ret_type)
class Property(object):
def __init__(self, prop, prefix):
self.name = prop.name
self.prop = prop
self.prefix = prefix
self.py_name = prop.name
self.getter = Function(prop, prefix, isget=True)
self.setter = Function(prop, prefix, isget=False)
def cdef_generate(self, gen):
self.getter.cdef_generate(gen)
self.setter.cdef_generate(gen)
def generate(self, gen):
gen.write("property %s:" % (self.py_name))
gen.indent()
try:
self.getter.generate(gen)
self.setter.generate(gen)
finally:
gen.dedent()
class Constructor(object):
def __init__(self, ctors, prefix, clsgetter):
self.prefix = prefix
self.ctors = ctors
self.clsgetter = clsgetter
def cdef_generate(self, gen):
pass
def generate(self, gen):
cls_get = self.clsgetter
header_params = []
c_ctors = []
for ctor in self.ctors:
func = ctor.function
c_name = func.full_c_name
c_call_params = []
py_name = func.name
if iskeyword(py_name): # Check if name is python reserved
py_name += "_"
ftypes = eolian.FunctionType
if (func.type == ftypes.PROP_SET or func.type == ftypes.PROPERTY):
c_name = c_name + "_set"
for p in func.parameters:
di = p.direction
assert di == eolian.ParameterDir.IN, "other than IN param for constructor"
c_type = p.type.c_type
conv_expr_py, c_type, name = convert_in_param(p.type, p.name, p.is_nonull)
header_params.append((c_type, p.name))
c_call_params.append(name)
c_call_params = ", ".join(c_call_params)
c_ctors.append((c_name, c_call_params))
header_params.append(("_Eo", "parent=None"))
gen.write("def __init__(self, %s):" % (", ".join([" ".join((t, n)).strip() for t, n in header_params])))
gen.indent()
gen.write("cdef Eo *added_obj = eo_add_ref(")
gen.indent()
gen.write("%s(), <Eo *>parent.obj if parent is not None else NULL," % (cls_get))
for ctor in c_ctors:
gen.write("%s(%s)" % (ctor[0], ctor[1]))
gen.write(")")
gen.dedent()
gen.write("self._set_obj(added_obj)")
gen.dedent()
gen.write()
class Class(object):
def __init__(self):
self.docs = []
self.inherits = []
self.ctor = []
self.methods = []
self.props = []
self.events = []
self.default_ctor = None
# self.header_path = None
@classmethod
def parse(klass, cls):
self = klass.__new__(klass)
self.__init__()
# class_counter[cls.name] += 1
self.c_name = cls.name
self.full_c_name = cls.full_name
self.lib_name, self.name = conv_cls_name(cls)
self.cls_getter = cls.c_get_function_name
#self.inherits = list(cls.inherits)
# XXX: Hack for T1721
self.inherits = [x for x in cls.inherits if not x.startswith("Elm_Interface_Atspi")]
prefix = cls.eo_prefix
if not prefix:
log.warn("Class %s has no prefix!" % (cls.name))
prefix = cls.name.lower()
self.prefix = prefix
if cls.type == eolian.ClassType.REGULAR: # or cls.type == eolian.ClassType.MIXIN:
self.ctor.append(Constructor(cls.constructors, prefix, cls.c_get_function_name))
props = cls.functions_get(eolian.FunctionType.PROPERTY)
for prop in props:
if not prop.scope == eolian.ObjectScope.PUBLIC:
log.debug(
"Skipping non-public property %s.%s",
cls.name, prop.name
)
continue
# function_counter["_".join((prefix, prop.name))] += 1
try:
o = Property(prop, prefix)
except Exception:
log.exception(
"Skipping %s.%s because of an exception",
cls.name, prop.name
)
continue
self.props.append(o)
methods = cls.functions_get(eolian.FunctionType.METHOD)
for method in methods:
if not method.scope == eolian.ObjectScope.PUBLIC:
log.debug(
"Skipping non-public method %s.%s",
cls.name, method.name
)
continue
# function_counter["_".join((prefix, method.name))] += 1
try:
o = Function(method, prefix)
except Exception:
log.exception(
"Skipping %s.%s because of an exception"
% (cls.name, method.name))
continue
self.methods.append(o)
# generated_class_counter[cls.name] += 1
for event in cls.events:
self.events.append(Event(event))
return self
def cdefs_generate(self, gen):
gen.write("const Eo_Class *%s()" % (self.cls_getter))
# gen.write("ctypedef Eo %s" % (self.full_c_name.replace(".", "_")))
if self.ctor or self.methods or self.props or self.events:
for o in self.ctor + self.methods + self.props + self.events:
try:
o.cdef_generate(gen)
except Exception:
log.exception("Error generating cdefs for %r", o)
def pyx_generate(self, gen):
inherits = []
for i in self.inherits:
i_cls = eolian.Class.get_by_name(i)
if i_cls:
if i_cls.type == eolian.ClassType.INTERFACE or \
i_cls.type == eolian.ClassType.MIXIN:
continue
if i_cls.full_name == "Eo.Base":
inherits.append("_Eo")
continue
lib_name, name = conv_cls_name(i_cls)
inherits.append("_" + name)
else:
log.warn("Inherited class %s is unknown" % (i))
i = i.rpartition(".")[2]
inherits.append("_" + i)
if len(inherits) > 1:
log.error(
"Multiple inheritance is not supported in extension classes.\n"
"Class: %r" % (self.c_name)
)
return
if not inherits:
inherits = ("_Eo", )
inherits = ", ".join(inherits)
gen.write("cdef class _%s(%s):" % (self.name, inherits))
gen.indent()
gen.write()
# gen.write("cdef %s *ext_cls_obj" % self.full_c_name.replace(".", "_"))
# gen.write()
if self.events:
gen.write("def __cinit__(self):")
gen.indent()
for o in self.events[:]:
try:
o.generate_name_mapping(gen)
o.generate_conversion_mapping(gen)
except EolianTypeError:
log.info("Skipping %r because of unknown type", o)
except Exception:
log.exception("Error while generating %r", o)
gen.dedent()
gen.write()
for o in self.events[:]:
try:
o.generate_conversion_function(gen)
except EolianTypeError:
log.info("Skipping %r because of unknown type", o)
except Exception:
log.exception("Error while generating %r", o)
if not self.ctor and not self.props and not self.methods:
gen.write("pass")
else:
for o in (
self.ctor #+
#list(self.events)
):
try:
o.generate(gen)
except EolianTypeError:
raise
#log.error("Skipping %s constructor because of unknown type", self.full_c_name)
except Exception:
log.exception("Error while generating %s constructor", self.full_c_name)
for o in (
list(self.methods) +
list(self.props)
):
try:
o.generate(gen)
except EolianTypeError:
log.info("Skipping %r because of unknown type", o)
except Exception:
log.exception("Error while generating %r", o)
# else:
# generated_function_counter["_".join((o.prefix, o.name))] += 1
gen.dedent()
gen.write()
# --- Py class
inherits = ["_" + self.name]
#imports = [(self.lib_name, "_" + self.name)]
imports = []
for i in self.inherits:
i_cls = eolian.Class.get_by_name(i)
if i_cls:
if i_cls.type == eolian.ClassType.REGULAR or \
i_cls.type == eolian.ClassType.ABSTRACT:
continue
lib_name, name = conv_cls_name(i_cls)
else:
log.warn("Class %s is unknown" % (i))
i = i.rpartition(".")
lib_name, name = i[0], i[2]
inherits.append(lib_name.replace(".", "_") + "_" + name)
imports.append((lib_name, "_" + name))
for l, n in imports:
#l2 = PY_EFL_TOP_LEVEL_PACKAGE + "." + l.lower()
l2 = l.lower()
gen.write("from %s import %s as %s" % (l2, n, l.replace(".", "_") + n))
gen.write()
gen.write()
gen.write("class %s(%s):" % (self.name, ", ".join(inherits)))
gen.indent()
gen.write("def __init__(self, *args, **kwargs):")
gen.indent()
gen.write(
"_%s.__init__(self, *args, **kwargs)" % (
self.name
)
)
gen.dedent()
gen.dedent()
gen.write()
gen.write('_object_mapping_register("%s", %s)' % (self.full_c_name.replace(".", "_"), self.name))
gen.write()
class Event(object):
def __init__(self, event):
self.event = event
def cdef_generate(self, gen):
gen.write("enum: %s" % (self.event.c_name))
def generate_name_mapping(self, gen):
gen.write(
'eina_hash_add(self.event_desc_mapping, "%s", <const void *>%s)' % (
self.event.name, self.event.c_name
)
)
def generate_conversion_mapping(self, gen):
conv = event_conversion_get(self.event.type)
if conv:
gen.write(
'eina_hash_add(self.event_conv_mapping, %s, <const void *>self._event_conv_%s_to_python)' % (
self.event.c_name, self.event.name.replace(",", "_")
)
)
else:
pass #print("{0} - {1}".format(self.event.name, self.event.type.c_type))
def generate_conversion_function(self, gen):
conv = event_conversion_get(self.event.type)
if conv:
gen.write(
'cdef object _event_conv_%s_to_python(self, void *evi):' % (
self.event.name.replace(",", "_")
)
)
gen.indent()
gen.write('cdef {0} tmp = <{0}>evi'.format(self.event.type.c_type))
gen.write('return ' + conv)
gen.dedent()
gen.write()
class File(object):
def __init__(self, filename, header_name):
self.filename = filename
self.header_name = header_name
self.pyxgen = PyxGenerator()
self.pygen = Generator()
# if not eolian.eo_file_parse(filename):
# log.warn("Errors in parsing %s" % (filename))
self.cls = eolian.Class.get_by_file(filename)
if not self.cls:
raise RuntimeError("Could not get class from %s" % (filename))
if self.cls.full_name.startswith("Eo."):
raise EolianSkip("Skipping Eo class")
self.gencls = Class.parse(self.cls)
def cdefs_generate(self):
gen = self.pyxgen
gen.write('cdef extern from "%s":' % (self.header_name + ".h"))
gen.indent()
for i in eolian.type_aliases_get_by_file(self.filename):
base = i.base_type
if base.type == eolian.TypeType.REGULAR:
gen.write("ctypedef %s %s" % (base.name, i.name))
elif base.type == eolian.TypeType.FUNCTION:
ret_type = base.return_type
if ret_type:
ret = ret_type.c_type
else:
ret = "void"
gen.write("ctypedef %s (*%s)(%s)" % (
ret,
i.name,
", ".join([i.c_type for i in base.arguments])))
elif base.type == eolian.TypeType.STRUCT:
gen.write("ctypedef struct %s:" % (i.name))
gen.indent()
for f in base.struct_fields:
gen.write("%s %s" % (f.type.c_type, f.name))
gen.dedent()
else:
log.error("Unhandled alias! %s %s %s %s", i.name, i.full_name, i.filename, i.description)
for i in eolian.type_structs_get_by_file(self.filename):
log.error("Type struct not handled! %s %s %s %s", i.name, i.full_name, i.filename, i.description)
for i in eolian.type_enums_get_by_file(self.filename):
log.error("Type enum not handled! %s %s %s %s", i.name, i.full_name, i.filename, i.description)
for i in eolian.variable_constants_get_by_file(self.filename):
log.error("Variable constant not handled! %s", i)
for i in eolian.variable_globals_get_by_file(self.filename):
log.error("Variable global not handled! %s", i)
self.gencls.cdefs_generate(gen)
gen.dedent()
gen.write()
def pyx_generate(self):
self.gencls.pyx_generate(self.pyxgen)
def printout(self):
return self.pyxgen.printout()
# class_counter = Counter()
# generated_class_counter = Counter()
# function_counter = Counter()
# generated_function_counter = Counter()
if __name__ == "__main__":
init()
from argparse import ArgumentParser
parser = ArgumentParser(description="Python bindings generator for Eolian")
parser.add_argument(
'-v', '--verbose', action="count", help="max is -vvv")
# parser.add_argument(
# '--enable-docstrings', action="store_true")
# parser.add_argument(
# '--with-legacy-api', action="store_true")
parser.add_argument(
'-o', '--output', default="/tmp", help="output directory, defaults to /tmp")
parser.add_argument(
'-I', help="include directory")
parser.add_argument('paths', nargs="+")
args = parser.parse_args()
if args.verbose:
log_level -= 10 * args.verbose
log.setLevel(log_level)
for path in args.paths:
for dirpath, dirnames, filenames in os.walk(path):
eolian.directory_scan(dirpath)
for filename in filenames:
if filename.endswith(".eo"):
f = os.path.join(dirpath, filename)
if not eolian.eo_file_parse(f):
log.warn("Errors in parsing %s" % (f))
try:
eolf = File(filename)
except EolianSkip:
continue
except Exception:
log.exception("Exception while creating %s" % (filename))
continue
try:
eolf.cdefs_generate()
except Exception:
log.exception("Exception while generating cdefs for %s" % (filename))
continue
try:
eolf.pyx_generate()
except Exception:
log.exception("Exception while generating pyx for %s" % (filename))
continue
# try:
# eolf.py_generate()
# except Exception:
# log.exception("Exception while generating py for %s" % (filename))
# continue
path = []
cls_name = self.cls.name.lower()
filename = "generated_" + cls_name + ".pxi"
for ns in self.cls.namespaces:
path.append(ns.lower())
if not path:
log.warning("Class %s has no namespaces defined" % (self.cls.name))
nstmp = cls_name.partition("_")
path.append(nstmp[0])
filename = "generated_" + nstmp[2] + ".pxi"
path = os.path.join(*path)
pxi_path = os.path.join(args.output, path, filename)
self.pyxgen.printout(filepath=pxi_path)
generated_pxis.setdefault(os.path.join(path), []).append((path, filename, self.cls))
for pxis in generated_pxis.values():
ns, pxi_path, cls = pxis[0]
filename = os.path.join(args.output, ns, "generated_classes.pxi")
if os.path.exists(filename):
log.warn("File %s exists, removing" % (filename))
os.remove(filename)
with open(filename, "a") as f:
# for ns, pxi_path, cls in pxis:
# line = "ctypedef Eo %s\n" % (cls.full_name.replace(".", "_"))
# f.write(line)
for ns, pxi_path, cls in pxis:
line = 'include "%s"\n' % (pxi_path)
f.write(line)
# def report():
# print("===============================================")
# print("Number of classes: %d" % (len(class_counter)))
# print("Number of classes generated: %d" % (len(generated_class_counter)))
# if len(class_counter) > 0:
# print("Percentage of classes generated: %f" % (
# float(len(generated_class_counter)) / float(len(class_counter)) * 100.0
# ))
# print("Number of functions: %d" % (len(function_counter)))
# print("Number of functions generated: %d" % (
# len(generated_function_counter)))
# if len(function_counter) > 0:
# print("Percentage of functions generated: %f" % (
# float(len(generated_function_counter)) / float(len(function_counter))
# * 100.0
# ))
# report()