efl/src/scripts/pyolian/eolian.py

1534 lines
45 KiB
Python

#!/usr/bin/env python3
# encoding: utf-8
"""
Pyolian: ctypes bindings for the eolian library.
This file (along with eolian_lib.py) implement full pythonic eolian bindings.
Those bindings are designed to work at runtime without any prepare/compilation
steps required. The only requirement is that we can find the eolian.so/dll
somwhere built in the source tree, look at eolian_lib.py to see the searchs
performed.
You can directly use the python API provided here if you need direct access
to eolian, or we suggest to look at the template-based generator.py if you just
need to generate some sort of text files out of the eolian database.
To use this library from outside this directory, you need to hack sys.path in
a way that this folder will be available on PYTHON_PATH, fe:
pyolian_path = os.path.join(EFL_ROOT_PATH, 'src', 'scripts')
sys.path.insert(0, pyolian_path)
from pyolian import eolian
from pyolian.generator import Template
"""
from enum import IntEnum
import atexit
from ctypes import cast, byref, c_char_p, c_void_p, c_int
import ctypes
try:
from .eolian_lib import lib
except ImportError:
from eolian_lib import lib
_already_halted = False
### Eolian Enums ############################################################
class Eolian_Function_Type(IntEnum):
UNRESOLVED = 0
PROPERTY = 1
PROP_SET = 2
PROP_GET = 3
METHOD = 4
FUNCTION_POINTER = 5
class Eolian_Parameter_Dir(IntEnum):
UNKNOWN = 0
IN = 1
OUT = 2
INOUT = 3
class Eolian_Class_Type(IntEnum):
UNKNOWN_TYPE = 0
REGULAR = 1
ABSTRACT = 2
MIXIN = 3
INTERFACE = 4
class Eolian_Object_Scope(IntEnum):
UNKNOWN = 0
PUBLIC = 1
PRIVATE = 2
PROTECTED = 3
class Eolian_Typedecl_Type(IntEnum):
UNKNOWN = 0
STRUCT = 1
STRUCT_OPAQUE = 2
ENUM = 3
ALIAS = 4
FUNCTION_POINTER = 5
class Eolian_Type_Type(IntEnum):
UNKNOWN_TYPE = 0
VOID = 1
REGULAR = 2
CLASS = 3
UNDEFINED = 4
class Eolian_Type_Builtin_Type(IntEnum):
INVALID = 0
BYTE = 1
UBYTE = 2
CHAR = 3
SHORT = 4
USHORT = 5
INT = 6
UINT = 7
LONG = 8
ULONG = 9
LLONG = 10
ULLONG = 11
INT8 = 12
UINT8 = 13
INT16 = 14
UINT16 = 15
INT32 = 16
UINT32 = 17
INT64 = 18
UINT64 = 19
INT128 = 20
UINT128 = 21
SIZE = 22
SSIZE = 23
INTPTR = 24
UINTPTR = 25
PTRDIFF = 26
TIME = 27
FLOAT = 28
DOUBLE = 29
BOOL = 30
VOID = 31
ACCESSOR = 32
ARRAY = 33
ITERATOR = 34
HASH = 35
LIST = 36
INARRAY = 37
INLIST = 38
FUTURE = 39
ANY_VALUE = 40
ANY_VALUE_PTR = 41
MSTRING = 42
STRING = 43
STRINGSHARE = 44
VOID_PTR = 45
FREE_CB = 46
class Eolian_C_Type_Type(IntEnum):
DEFAULT = 0
PARAM = 1
RETURN = 2
class Eolian_Expression_Type(IntEnum):
UNKNOWN = 0
INT = 1
UINT = 2
LONG = 3
ULONG = 4
LLONG = 5
ULLONG = 6
FLOAT = 7
DOUBLE = 8
STRING = 9
CHAR = 10
NULL = 11
BOOL = 12
NAME = 13
UNARY = 14
BINARY = 15
class Eolian_Expression_Mask(IntEnum):
SINT = 1 << 0
UINT = 1 << 1
INT = SINT | UINT
FLOAT = 1 << 2
BOOL = 1 << 3
STRING = 1 << 4
CHAR = 1 << 5
NULL = 1 << 6
SIGNED = SINT | FLOAT
NUMBER = INT | FLOAT
ALL = NUMBER | BOOL | STRING | CHAR | NULL
class Eolian_Variable_Type(IntEnum):
UNKNOWN = 0
CONSTANT = 1
GLOBAL = 2
class Eolian_Binary_Operator(IntEnum):
INVALID = 0
ADD = 1 # + int, float
SUB = 2 # - int, float
MUL = 3 # * int, float
DIV = 4 # / int, float
MOD = 5 # % int
EQ = 6 # == all types
NQ = 7 # != all types
GT = 8 # > int, float
LT = 9 # < int, float
GE = 10 # >= int, float
LE = 11 # <= int, float
AND = 12 # && all types
OR = 13 # || all types
BAND = 14 # & int
BOR = 15 # | int
BXOR = 16 # ^ int
LSH = 17 # << int
RSH = 18 # >> int
class Eolian_Unary_Operator(IntEnum):
INVALID = 0
UNM = 1 # - sint
UNP = 2 # + sint
NOT = 3 # ! int, float, bool
BNOT = 4 # ~ int
class Eolian_Declaration_Type(IntEnum):
UNKNOWN = 0
CLASS = 1
ALIAS = 2
STRUCT = 3
ENUM = 4
VAR = 5
class Eolian_Doc_Token_Type(IntEnum):
UNKNOWN = 0
TEXT = 1
REF = 2
MARK_NOTE = 3
MARK_WARNING = 4
MARK_REMARK = 5
MARK_TODO = 6
MARKUP_MONOSPACE = 7
class Eolian_Doc_Ref_Type(IntEnum):
INVALID = 0
CLASS = 1
FUNC = 2
EVENT = 3
ALIAS = 4
STRUCT = 5
STRUCT_FIELD = 6
ENUM = 7
ENUM_FIELD = 8
VAR = 9
### internal Classes ########################################################
class Iterator(object):
""" Generic eina iterator wrapper """
def __init__(self, conv_func, iterator):
self.next = self.__next__ # py2 compat
self._conv = conv_func
self._iter = c_void_p(iterator)
self._tmp = c_void_p(0)
def __iter__(self):
return self
def __next__(self):
if not self._iter or not self._iter.value:
raise StopIteration
if not lib.eina_iterator_next(self._iter, byref(self._tmp)):
lib.eina_iterator_free(self._iter)
raise StopIteration
return self._conv(self._tmp)
def free(self):
lib.eina_iterator_free(self._iter)
class cached_property(object):
""" Decorator to be used on properties that can be cached """
def __init__(self, fget, doc=None):
self.fget = fget
self.__doc__ = doc or fget.__doc__
self.__name__ = fget.__name__
self.__module__ = fget.__module__
def __get__(self, obj, cls):
obj.__dict__[self.__name__] = result = self.fget(obj)
return result
class EolianBaseObject(object):
__instances_cache = {}
def __new__(cls, c_obj_pointer=None, *args, **kargs):
# cannot cache without a pointer
if c_obj_pointer is None:
return super().__new__(cls)
# cache based on the c pointer value (assume the eolian db is stabe)
if isinstance(c_obj_pointer, c_void_p):
key = c_obj_pointer.value
elif isinstance(c_obj_pointer, int):
key = c_obj_pointer
else:
raise TypeError('Wrong EolianBaseObject constructor pointer!!')
# get instance from cache or create a new one
if key in cls.__instances_cache:
inst = cls.__instances_cache[key]
else:
inst = cls.__instances_cache[key] = super().__new__(cls)
return inst
def __init__(self, c_obj_pointer):
if isinstance(c_obj_pointer, c_void_p):
self._obj = c_void_p(c_obj_pointer.value)
elif isinstance(c_obj_pointer, int):
self._obj = c_void_p(c_obj_pointer)
else:
raise TypeError('Invalid constructor of type: %s for class: %s' % (
type(c_obj_pointer), self.__class__.__name__))
def __eq__(self, other):
if isinstance(other, EolianBaseObject):
return self._obj.value == other._obj.value
elif isinstance(other, str):
if hasattr(self, 'full_name'):
return self.full_name == other
elif hasattr(self, 'name'):
return self.name == other
return False
def __hash__(self):
return self._obj.value
### Main Eolian Unit ########################################################
class Eolian_Unit(EolianBaseObject):
def class_get_by_name(self, class_name):
c_cls = lib.eolian_class_get_by_name(self._obj, _str_to_bytes(class_name))
return Class(c_cls) if c_cls else None
def class_get_by_file(self, file_name):
c_cls = lib.eolian_class_get_by_file(self._obj, _str_to_bytes(file_name))
return Class(c_cls) if c_cls else None
@property
def all_classes(self):
return Iterator(Class, lib.eolian_all_classes_get(self._obj))
@property
def all_namespaces(self):
# TODO find a better way to find namespaces (maybe inside eolian?)
nspaces = set()
for obj in self.all_classes:
nspaces.add(Namespace(self, obj.namespace))
for obj in self.typedecl_all_aliases:
nspaces.add(Namespace(self, obj.namespace))
for obj in self.typedecl_all_structs:
nspaces.add(Namespace(self, obj.namespace))
for obj in self.typedecl_all_enums:
nspaces.add(Namespace(self, obj.namespace))
return sorted(nspaces)
def namespace_get_by_name(self, name):
return Namespace(self, name)
@property
def typedecl_all_enums(self):
return Iterator(Typedecl, lib.eolian_typedecl_all_enums_get(self._obj))
def typedecl_enum_get_by_name(self, name):
c_tdecl = lib.eolian_typedecl_enum_get_by_name(self._obj, _str_to_bytes(name))
return Typedecl(c_tdecl) if c_tdecl else None
def typedecl_enums_get_by_file(self, fname):
return Iterator(Typedecl,
lib.eolian_typedecl_enums_get_by_file(self._obj, _str_to_bytes(fname)))
@property
def typedecl_all_structs(self):
return Iterator(Typedecl, lib.eolian_typedecl_all_structs_get(self._obj))
def typedecl_struct_get_by_name(self, name):
c_tdecl = lib.eolian_typedecl_struct_get_by_name(self._obj, _str_to_bytes(name))
return Typedecl(c_tdecl) if c_tdecl else None
def typedecl_structs_get_by_file(self, fname):
return Iterator(Typedecl,
lib.eolian_typedecl_structs_get_by_file(self._obj, _str_to_bytes(fname)))
@property
def typedecl_all_aliases(self):
return Iterator(Typedecl, lib.eolian_typedecl_all_aliases_get(self._obj))
def typedecl_alias_get_by_name(self, name):
c_tdecl = lib.eolian_typedecl_alias_get_by_name(self._obj, _str_to_bytes(name))
return Typedecl(c_tdecl) if c_tdecl else None
def typedecl_aliases_get_by_file(self, fname):
return Iterator(Typedecl,
lib.eolian_typedecl_aliases_get_by_file(self._obj, _str_to_bytes(fname)))
@property
def variable_all_constants(self):
return Iterator(Variable, lib.eolian_variable_all_constants_get(self._obj))
def variable_constant_get_by_name(self, name):
c_var = lib.eolian_variable_constant_get_by_name(self._obj, _str_to_bytes(name))
return Variable(c_var) if c_var else None
def variable_constants_get_by_file(self, fname):
return Iterator(Variable,
lib.eolian_variable_constants_get_by_file(self._obj, _str_to_bytes(fname)))
@property
def variable_all_globals(self):
return Iterator(Variable, lib.eolian_variable_all_globals_get(self._obj))
def variable_global_get_by_name(self, name):
c_var = lib.eolian_variable_global_get_by_name(self._obj, _str_to_bytes(name))
return Variable(c_var) if c_var else None
def variable_globals_get_by_file(self, fname):
return Iterator(Variable,
lib.eolian_variable_globals_get_by_file(self._obj, _str_to_bytes(fname)))
@property
def all_declarations(self):
return Iterator(Declaration, lib.eolian_all_declarations_get(self._obj))
def declaration_get_by_name(self, name):
c_decl = lib.eolian_declaration_get_by_name(self._obj, _str_to_bytes(name))
return Declaration(c_decl) if c_decl else None
def declarations_get_by_file(self, fname):
return Iterator(Declaration,
lib.eolian_declarations_get_by_file(self._obj, _str_to_bytes(fname)))
class Eolian(Eolian_Unit):
def __init__(self):
self._obj = lib.eolian_new() # Eolian *
def __del__(self):
if not _already_halted: # do not free after eolian_shutdown
lib.eolian_free(self._obj)
def file_parse(self, filepath):
c_unit = lib.eolian_file_parse(self._obj, _str_to_bytes(filepath))
return Eolian_Unit(c_unit) if c_unit else None
@property
def all_eo_file_paths(self):
return Iterator(_str_to_py, lib.eolian_all_eo_file_paths_get(self._obj))
@property
def all_eot_file_paths(self):
return Iterator(_str_to_py, lib.eolian_all_eot_file_paths_get(self._obj))
@property
def all_eo_files(self):
return Iterator(_str_to_py, lib.eolian_all_eo_files_get(self._obj))
@property
def all_eot_files(self):
return Iterator(_str_to_py, lib.eolian_all_eot_files_get(self._obj))
def directory_scan(self, dir_path):
return bool(lib.eolian_directory_scan(self._obj, _str_to_bytes(dir_path)))
def system_directory_scan(self):
return bool(lib.eolian_system_directory_scan(self._obj))
def all_eo_files_parse(self):
return bool(lib.eolian_all_eo_files_parse(self._obj))
def all_eot_files_parse(self):
return bool(lib.eolian_all_eot_files_parse(self._obj))
### Namespace Utility Class #################################################
class Namespace(object):
def __init__(self, unit, namespace_name):
self._name = namespace_name
self._unit = unit
def __repr__(self):
return "<eolian.Namespace '{0._name}'>".format(self)
def __eq__(self, other):
return self.name == other.name
def __lt__(self, other):
return self.name < other.name
def __gt__(self, other):
return self.name > other.name
def __hash__(self):
return hash(self._name)
@property
def name(self):
return self._name
@property
def namespaces(self):
return self._name.split('.')
@property
def classes(self):
return [ c for c in self._unit.all_classes
if c.namespace == self._name ]
@property
def regulars(self):
return [ c for c in self._unit.all_classes
if c.type == Eolian_Class_Type.REGULAR and
c.namespace == self._name]
@property
def mixins(self):
return [ c for c in self._unit.all_classes
if c.type == Eolian_Class_Type.MIXIN and
c.namespace == self._name]
@property
def interfaces(self):
return [ c for c in self._unit.all_classes
if c.type == Eolian_Class_Type.INTERFACE and
c.namespace == self._name]
@property
def aliases(self):
return [ td for td in self._unit.typedecl_all_aliases
if td.namespace == self._name]
@property
def structs(self):
return [ td for td in self._unit.typedecl_all_structs
if td.namespace == self._name]
@property
def enums(self):
return [ td for td in self._unit.typedecl_all_enums
if td.namespace == self._name]
### Eolian Classes ##########################################################
class Class(EolianBaseObject):
def __repr__(self):
return "<eolian.Class '{0.full_name}', {0.type!s}>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_class_name_get(self._obj))
@cached_property
def full_name(self):
return _str_to_py(lib.eolian_class_full_name_get(self._obj))
@cached_property
def c_name(self):
s = lib.eolian_class_c_name_get(self._obj)
ret = _str_to_py(s)
lib.eina_stringshare_del(c_void_p(s))
return ret
@cached_property
def c_get_function_name(self):
s = lib.eolian_class_c_get_function_name_get(self._obj)
ret = _str_to_py(s)
lib.eina_stringshare_del(c_void_p(s))
return ret
@cached_property
def type(self):
return Eolian_Class_Type(lib.eolian_class_type_get(self._obj))
@cached_property
def data_type(self):
return _str_to_py(lib.eolian_class_data_type_get(self._obj))
@cached_property
def c_data_type(self):
s = lib.eolian_class_c_data_type_get(self._obj)
ret = _str_to_py(s)
lib.eina_stringshare_del(c_void_p(s))
return ret
@cached_property
def legacy_prefix(self):
return _str_to_py(lib.eolian_class_legacy_prefix_get(self._obj))
@cached_property
def eo_prefix(self):
return _str_to_py(lib.eolian_class_eo_prefix_get(self._obj))
@cached_property
def event_prefix(self):
return _str_to_py(lib.eolian_class_event_prefix_get(self._obj))
@cached_property
def documentation(self):
c_doc = lib.eolian_class_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
@property
def constructors(self):
return Iterator(Constructor, lib.eolian_class_constructors_get(self._obj))
@property
def events(self):
return Iterator(Event, lib.eolian_class_events_get(self._obj))
def event_get_by_name(self, event_name):
c_event = lib.eolian_class_event_get_by_name(self._obj,
_str_to_bytes(event_name))
return Event(c_event) if c_event else None
@property
def inherits(self):
return Iterator(Class, lib.eolian_class_inherits_get(self._obj))
@cached_property
def inherits_full(self):
L = []
def do_class_recursive(cls):
for other in cls.inherits:
if not other in L:
L.append(other)
do_class_recursive(other)
do_class_recursive(self)
return L
@cached_property
def hierarchy(self):
L = []
base = self.base_class
while base:
L.append(base)
base = base.base_class
return L
@cached_property
def base_class(self):
inherits = list(self.inherits)
if len(inherits) > 0:
return inherits[0]
@property
def namespaces(self):
return Iterator(_str_to_py, lib.eolian_class_namespaces_get(self._obj))
@cached_property
def namespace(self):
return '.'.join(self.namespaces)
@cached_property
def file(self):
return _str_to_py(lib.eolian_class_file_get(self._obj))
@cached_property
def ctor_enable(self):
return bool(lib.eolian_class_ctor_enable_get(self._obj))
@cached_property
def dtor_enable(self):
return bool(lib.eolian_class_dtor_enable_get(self._obj))
def function_get_by_name(self, func_name,
ftype=Eolian_Function_Type.UNRESOLVED):
f = lib.eolian_class_function_get_by_name(self._obj,
_str_to_bytes(func_name),
ftype)
return Function(f) if f else None
def functions_get(self, ftype):
return Iterator(Function, lib.eolian_class_functions_get(self._obj, ftype))
@property
def methods(self):
return self.functions_get(Eolian_Function_Type.METHOD)
@property
def properties(self):
return self.functions_get(Eolian_Function_Type.PROPERTY)
@property
def implements(self):
return Iterator(Implement, lib.eolian_class_implements_get(self._obj))
@property
def parts(self):
return Iterator(Part, lib.eolian_class_parts_get(self._obj))
class Part(EolianBaseObject):
def __repr__(self):
return "<eolian.Part '{0.name}'>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_part_name_get(self._obj))
@cached_property
def class_(self):
return Class(lib.eolian_part_class_get(self._obj))
@cached_property
def documentation(self):
c_doc = lib.eolian_part_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
class Constructor(EolianBaseObject):
def __repr__(self):
return "<eolian.Constructor '{0.full_name}', optional={0.is_optional}>".format(self)
@cached_property
def full_name(self):
return _str_to_py(lib.eolian_constructor_full_name_get(self._obj))
@cached_property
def function(self):
return Function(lib.eolian_constructor_function_get(self._obj))
@cached_property
def is_optional(self):
return bool(lib.eolian_constructor_is_optional(self._obj))
@cached_property
def class_(self):
return Class(lib.eolian_constructor_class_get(self._obj))
class Event(EolianBaseObject):
def __repr__(self):
return "<eolian.Event '{0.name}', c_name='{0.c_name}'>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_event_name_get(self._obj))
@cached_property
def c_name(self):
s = lib.eolian_event_c_name_get(self._obj)
ret = _str_to_py(s)
lib.eina_stringshare_del(c_void_p(s))
return ret
@cached_property
def type(self):
c_type = lib.eolian_event_type_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def documentation(self):
c_doc = lib.eolian_event_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
@cached_property
def scope(self):
return Eolian_Object_Scope(lib.eolian_event_scope_get(self._obj))
@cached_property
def is_beta(self):
return bool(lib.eolian_event_is_beta(self._obj))
@cached_property
def is_hot(self):
return bool(lib.eolian_event_is_hot(self._obj))
@cached_property
def is_restart(self):
return bool(lib.eolian_event_is_restart(self._obj))
class Function(EolianBaseObject):
def __repr__(self):
return "<eolian.Function '{0.name}'>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_function_name_get(self._obj))
def full_c_name_get(self, ftype, use_legacy=False):
s = lib.eolian_function_full_c_name_get(self._obj, ftype, use_legacy)
ret = _str_to_py(s)
lib.eina_stringshare_del(c_void_p(s))
return ret
@cached_property
def full_c_method_name(self):
return self.full_c_name_get(Eolian_Function_Type.METHOD)
@cached_property
def full_c_getter_name(self):
return self.full_c_name_get(Eolian_Function_Type.PROP_GET)
@cached_property
def full_c_setter_name(self):
return self.full_c_name_get(Eolian_Function_Type.PROP_SET)
@cached_property
def full_c_method_name_legacy(self):
return self.full_c_name_get(Eolian_Function_Type.METHOD, True)
@cached_property
def full_c_getter_name_legacy(self):
return self.full_c_name_get(Eolian_Function_Type.PROP_GET, True)
@cached_property
def full_c_setter_name_legacy(self):
return self.full_c_name_get(Eolian_Function_Type.PROP_SET, True)
@cached_property
def type(self):
return Eolian_Function_Type(lib.eolian_function_type_get(self._obj))
def scope_get(self, ftype):
return Eolian_Object_Scope(lib.eolian_function_scope_get(self._obj, ftype))
@cached_property
def method_scope(self):
return self.scope_get(Eolian_Function_Type.METHOD)
@cached_property
def getter_scope(self):
return self.scope_get(Eolian_Function_Type.PROP_GET)
@cached_property
def setter_scope(self):
return self.scope_get(Eolian_Function_Type.PROP_SET)
def legacy_get(self, ftype):
return _str_to_py(lib.eolian_function_legacy_get(self._obj, ftype))
def is_legacy_only(self, ftype):
return bool(lib.eolian_function_is_legacy_only(self._obj, ftype))
@cached_property
def is_class(self):
return bool(lib.eolian_function_is_class(self._obj))
@cached_property
def is_beta(self):
return bool(lib.eolian_function_is_beta(self._obj))
@cached_property
def object_is_const(self):
return bool(lib.eolian_function_object_is_const(self._obj))
@cached_property
def class_(self):
c_cls = lib.eolian_function_class_get(self._obj)
return Class(c_cls) if c_cls else None
def is_constructor(self, klass):
return bool(lib.eolian_function_is_constructor(self._obj, klass._obj))
# @cached_property
# def is_function_pointer(self):
# return bool(lib.eolian_function_is_function_pointer(self._obj))
@property
def parameters(self):
return Iterator(Function_Parameter,
lib.eolian_function_parameters_get(self._obj))
def values_get(self, ftype): # TODO rename in property_values_get (or implement a proper Property class?)
return Iterator(Function_Parameter,
lib.eolian_property_values_get(self._obj, ftype))
@property
def getter_values(self): # TODO rename ...
return self.values_get(Eolian_Function_Type.PROP_GET)
@property
def setter_values(self): # TODO rename ...
return self.values_get(Eolian_Function_Type.PROP_SET)
def keys_get(self, ftype): # TODO rename in property_keys_get (or implement a proper Property class?)
return Iterator(Function_Parameter,
lib.eolian_property_keys_get(self._obj, ftype))
@property
def getter_keys(self): # TODO rename ...
return self.keys_get(Eolian_Function_Type.PROP_GET)
@property
def setter_keys(self): # TODO rename ...
return self.keys_get(Eolian_Function_Type.PROP_SET)
def return_type_get(self, ftype):
c_type = lib.eolian_function_return_type_get(self._obj, ftype)
return Type(c_type) if c_type else None
def return_default_value(self, ftye):
c_expr = lib.eolian_function_return_default_value_get(sel._obj, ftype)
return Expression(c_expr) if c_expr else None
def return_documentation(self, ftype):
c_doc = lib.eolian_function_return_documentation_get(self._obj, ftype)
return Documentation(c_doc) if c_doc else None
def return_is_warn_unused(self, ftype):
return bool(lib.eolian_function_return_is_warn_unused(self._obj, ftype))
@cached_property
def method_return_type(self):
return self.return_type_get(Eolian_Function_Type.METHOD)
@cached_property
def getter_return_type(self):
return self.return_type_get(Eolian_Function_Type.PROP_GET)
@cached_property
def setter_return_type(self):
return self.return_type_get(Eolian_Function_Type.PROP_SET)
@cached_property
def prop_readable(self):
# TODO: maybe there is a better way to do this...
ftype = Eolian_Function_Type.PROP_GET
scope = lib.eolian_function_scope_get(self._obj, ftype)
return True if scope != Eolian_Object_Scope.UNKNOWN else False
@cached_property
def prop_writable(self):
# TODO: maybe there is a better way to do this...
ftype = Eolian_Function_Type.PROP_SET
scope = lib.eolian_function_scope_get(self._obj, ftype)
return True if scope != Eolian_Object_Scope.UNKNOWN else False
@cached_property
def implement(self):
c_impl = lib.eolian_function_implement_get(self._obj)
return Implement(c_impl) if c_impl else None
class Function_Parameter(EolianBaseObject):
def __repr__(self):
return "<eolian.Function_Parameter '{0.name}', type={0.type}," \
" optional={0.is_optional}, nullable={0.is_nullable}>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_parameter_name_get(self._obj))
@cached_property
def direction(self):
return Eolian_Parameter_Dir(lib.eolian_parameter_direction_get(self._obj))
@cached_property
def documentation(self):
c_doc = lib.eolian_parameter_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
@cached_property
def is_nonull(self):
return bool(lib.eolian_parameter_is_nonull(self._obj))
@cached_property
def is_nullable(self):
return bool(lib.eolian_parameter_is_nullable(self._obj))
@cached_property
def is_optional(self):
return bool(lib.eolian_parameter_is_optional(self._obj))
@cached_property
def type(self):
c_type = lib.eolian_parameter_type_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def default_value(self):
c_expr = lib.eolian_parameter_default_value_get(self._obj)
return Expression(c_expr) if c_expr else None
class Implement(EolianBaseObject):
def __repr__(self):
return "<eolian.Implement '{0.full_name}'>".format(self)
@cached_property
def full_name(self):
return _str_to_py(lib.eolian_implement_full_name_get(self._obj))
@cached_property
def class_(self):
c_cls = lib.eolian_implement_class_get(self._obj)
return Class(c_cls) if c_cls else None
@cached_property
def function(self):
c_func = lib.eolian_implement_function_get(self._obj, None)
return Function(c_func) if c_func else None
def documentation_get(self, ftype=Eolian_Function_Type.METHOD):
# something strange in this eolian api :/ (see 'documentation' property
c_doc = lib.eolian_implement_documentation_get(self._obj, ftype)
return Documentation(c_doc) if c_doc else None
# TODO implement util properties for documentation_get
def is_auto(self, ftype=Eolian_Function_Type.METHOD):
return bool(lib.eolian_implement_is_auto(self._obj, ftype))
# TODO implement util properties for is_auto
def is_empty(self, ftype=Eolian_Function_Type.METHOD):
return bool(lib.eolian_implement_is_empty(self._obj, ftype))
# TODO implement util properties for is_empty
def is_pure_virtual(self, ftype=Eolian_Function_Type.METHOD):
return bool(lib.eolian_implement_is_pure_virtual(self._obj, ftype))
# TODO implement util properties for is_pure_virtual
@cached_property
def is_prop_set(self):
return bool(lib.eolian_implement_is_prop_set(self._obj))
@cached_property
def is_prop_get(self):
return bool(lib.eolian_implement_is_prop_get(self._obj))
@property
def is_property(self):
return self.is_prop_get or self.is_prop_set
@property
def is_method(self):
return not self.is_property
class Type(EolianBaseObject):
def __repr__(self):
# return "<eolian.Type '{0.full_name}', type: {0.type!s}, c_type: '{0.c_type}'>".format(self)
return "<eolian.Type '{0.full_name}', type={0.type!s}>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_type_name_get(self._obj))
@cached_property
def full_name(self):
return _str_to_py(lib.eolian_type_full_name_get(self._obj))
@property
def namespaces(self):
return Iterator(_str_to_py, lib.eolian_type_namespaces_get(self._obj))
@cached_property
def namespace(self):
return '.'.join(self.namespaces)
@cached_property
def free_func(self):
return _str_to_py(lib.eolian_type_free_func_get(self._obj))
@cached_property
def type(self):
return Eolian_Type_Type(lib.eolian_type_type_get(self._obj))
@cached_property
def builtin_type(self):
return Eolian_Type_Builtin_Type(lib.eolian_type_builtin_type_get(self._obj))
@cached_property
def c_type(self):
return _str_to_py(lib.eolian_type_c_type_get(self._obj))
@cached_property
def typedecl(self):
c_tdecl = lib.eolian_type_typedecl_get(self._obj)
return Typedecl(c_tdecl) if c_tdecl else None
@cached_property
def base_type(self):
c_type = lib.eolian_type_base_type_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def next_type(self):
c_type = lib.eolian_type_next_type_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def aliased_base(self):
c_type = lib.eolian_type_aliased_base_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def class_(self):
c_cls = lib.eolian_type_class_get(self._obj)
return Class(c_cls) if c_cls else None
@cached_property
def file(self):
return _str_to_py(lib.eolian_type_file_get(self._obj))
@cached_property
def is_owned(self):
return bool(lib.eolian_type_is_owned(self._obj))
@cached_property
def is_const(self):
return bool(lib.eolian_type_is_const(self._obj))
@cached_property
def is_ptr(self):
return bool(lib.eolian_type_is_ptr(self._obj))
class Typedecl(EolianBaseObject):
def __repr__(self):
return "<eolian.Typedecl '{0.full_name}', type={0.type!s}>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_typedecl_name_get(self._obj))
@cached_property
def full_name(self):
return _str_to_py(lib.eolian_typedecl_full_name_get(self._obj))
@cached_property
def file(self):
return _str_to_py(lib.eolian_typedecl_file_get(self._obj))
@cached_property
def type(self):
return Eolian_Typedecl_Type(lib.eolian_typedecl_type_get(self._obj))
@cached_property
def c_type(self):
return _str_to_py(lib.eolian_typedecl_c_type_get(self._obj))
@property
def namespaces(self):
return Iterator(_str_to_py, lib.eolian_typedecl_namespaces_get(self._obj))
@cached_property
def namespace(self):
return '.'.join(self.namespaces)
@cached_property
def free_func(self):
return _str_to_py(lib.eolian_typedecl_free_func_get(self._obj))
@cached_property
def is_extern(self):
return bool(lib.eolian_typedecl_is_extern(self._obj))
@property
def enum_fields(self):
return Iterator(Enum_Type_Field,
lib.eolian_typedecl_enum_fields_get(self._obj))
def enum_field_get(self, field):
c_field = lib.eolian_typedecl_enum_field_get(self._obj, _str_to_bytes(field))
return Enum_Type_Field(c_field) if c_field else None
@property
def struct_fields(self):
return Iterator(Struct_Type_Field,
lib.eolian_typedecl_struct_fields_get(self._obj))
def struct_field_get(self, field):
c_field = lib.eolian_typedecl_struct_field_get(self._obj, _str_to_bytes(field))
return Struct_Type_Field(c_field) if c_field else None
@cached_property
def base_type(self):
c_type = lib.eolian_typedecl_base_type_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def aliased_base(self):
c_type = lib.eolian_typedecl_aliased_base_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def documentation(self):
c_doc = lib.eolian_typedecl_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
@cached_property
def enum_legacy_prefix(self):
return _str_to_py(lib.eolian_typedecl_enum_legacy_prefix_get(self._obj))
@cached_property
def function_pointer(self):
c_func = lib.eolian_typedecl_function_pointer_get(self._obj)
return Function(c_func) if c_func else None
class Enum_Type_Field(EolianBaseObject):
def __repr__(self):
return "<eolian.Enum_Type_Field '{0.name}', c_name='{0.c_name}'>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_typedecl_enum_field_name_get(self._obj))
@cached_property
def c_name(self):
s = lib.eolian_typedecl_enum_field_c_name_get(self._obj)
ret = _str_to_py(s)
lib.eina_stringshare_del(c_void_p(s))
return ret
@cached_property
def value(self):
c_expr = lib.eolian_typedecl_enum_field_value_get(self._obj, True)
return Expression(c_expr) if c_expr else None
@cached_property
def documentation(self):
c_doc = lib.eolian_typedecl_enum_field_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
class Struct_Type_Field(EolianBaseObject):
def __repr__(self):
return "<eolian.Struct_Type_Field '{0.name}', type={0.type!s}>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_typedecl_struct_field_name_get(self._obj))
@cached_property
def type(self):
c_type = lib.eolian_typedecl_struct_field_type_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def documentation(self):
c_doc = lib.eolian_typedecl_struct_field_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
class Expression(EolianBaseObject):
def __repr__(self):
return "<eolian.Expression type={0.type!s}, serialize='{0.serialize}'>".format(self)
@cached_property
def type(self):
return Eolian_Expression_Type(lib.eolian_expression_type_get(self._obj))
# TODO: EAPI Eolian_Value eolian_expression_value_get(const Eolian_Expression *expr);
@cached_property
def serialize(self):
s = lib.eolian_expression_serialize(self._obj)
ret = _str_to_py(s)
lib.eina_stringshare_del(c_void_p(s))
return ret
@cached_property
def binary_operator(self):
c_op = lib.eolian_expression_binary_operator_get(self._obj)
return Eolian_Binary_Operator(c_op) if c_op is not None else None
@cached_property
def binary_lhs(self):
c_expr = lib.eolian_expression_binary_lhs_get(self._obj)
return Expression(c_expr) if c_expr else None
@cached_property
def binary_rhs(self):
c_expr = lib.eolian_expression_binary_rhs_get(self._obj)
return Expression(c_expr) if c_expr else None
@cached_property
def unary_operator(self):
c_op = lib.eolian_expression_unary_operator_get(self._obj)
return Eolian_Unary_Operator(c_op) if c_op is not None else None
@cached_property
def unary_expression(self):
c_expr = lib.eolian_expression_unary_expression_get(self._obj)
return Expression(c_expr) if c_expr is not None else None
class Variable(EolianBaseObject):
def __repr__(self):
return "<eolian.Variable '{0.full_name}', type={0.type!s}, file={0.file}>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_variable_name_get(self._obj))
@cached_property
def full_name(self):
return _str_to_py(lib.eolian_variable_full_name_get(self._obj))
@property
def namespaces(self):
return Iterator(_str_to_py, lib.eolian_variable_namespaces_get(self._obj))
@cached_property
def namespace(self):
return '.'.join(self.namespaces)
@cached_property
def type(self):
return Eolian_Variable_Type(lib.eolian_variable_type_get(self._obj))
@cached_property
def value(self):
c_expr = lib.eolian_variable_value_get(self._obj)
return Expression(c_expr) if c_expr else None
@cached_property
def file(self):
return _str_to_py(lib.eolian_variable_file_get(self._obj))
@cached_property
def base_type(self):
c_type = lib.eolian_variable_base_type_get(self._obj)
return Type(c_type) if c_type else None
@cached_property
def is_extern(self):
return bool(lib.eolian_variable_is_extern(self._obj))
@cached_property
def documentation(self):
c_doc = lib.eolian_variable_documentation_get(self._obj)
return Documentation(c_doc) if c_doc else None
class Declaration(EolianBaseObject):
def __repr__(self):
return "<eolian.Declaration '{0.name}'>".format(self)
@cached_property
def name(self):
return _str_to_py(lib.eolian_declaration_name_get(self._obj))
@cached_property
def type(self):
return Eolian_Declaration_Type(lib.eolian_declaration_type_get(self._obj))
@cached_property
def class_(self):
c_cls = lib.eolian_declaration_class_get(self._obj)
return Class(c_cls) if c_cls else None
@cached_property
def data_type(self):
c_typedec = lib.eolian_declaration_data_type_get(self._obj)
return Typedecl(c_typedec) if c_typedec else None
@cached_property
def variable(self):
c_var = lib.eolian_declaration_variable_get(self._obj)
return Variable(c_var) if c_var else None
class _Eolian_Doc_Token_Struct(ctypes.Structure):
_fields_ = [("type", c_int),
("text", c_char_p),
("text_end", c_char_p)]
class Documentation(EolianBaseObject): # OK (1 TODO Unit*)
# def __repr__(self):
# return "<eolian.Documentation '{0.name}'>".format(self)
# this is too much for py, just use string.split('\n\n') instead
# def string_split(self, string):
# c_list = lib.eolian_documentation_string_split
@cached_property
def summary(self):
return _str_to_py(lib.eolian_documentation_summary_get(self._obj))
@cached_property
def description(self):
return _str_to_py(lib.eolian_documentation_description_get(self._obj))
@cached_property
def since(self):
return _str_to_py(lib.eolian_documentation_since_get(self._obj))
@cached_property
def summary_tokens(self):
""" return a list of paragraphs, each one is a list of tokens """
return self._tokenize(self.summary)
@cached_property
def description_tokens(self):
""" return a list of paragraphs, each one is a list of tokens """
return self._tokenize(self.description)
@classmethod
def _tokenize(cls, full_text):
paragraphs = []
if not full_text:
return paragraphs
tok = _Eolian_Doc_Token_Struct()
for paragraph in full_text.split('\n\n'):
tokens = []
c_paragraph = _str_to_bytes(paragraph) # keep c_paragraph alive !
lib.eolian_doc_token_init(byref(tok))
next_chunk = lib.eolian_documentation_tokenize(c_paragraph, byref(tok))
while next_chunk:
typ = lib.eolian_doc_token_type_get(byref(tok))
txt = lib.eolian_doc_token_text_get(byref(tok))
# ref = # TODO ... Stupido parametro '*unit' :(
tokens.append(Documentation_Token(typ, txt))
lib.free(c_void_p(txt))
next_chunk = lib.eolian_documentation_tokenize(c_char_p(next_chunk), byref(tok))
paragraphs.append(tokens)
return paragraphs
class Documentation_Token(object):
def __init__(self, c_token_type, c_text):
self._type = Eolian_Doc_Token_Type(c_token_type)
self._text = _str_to_py(c_text)
self._ref = None # TODO
def __repr__(self):
t = self.text if len(self.text) < 40 else self.text[:40] + '...'
return "<eolian.Doc_Token ({}), text='{}', len={}>".format(
self.type.name, t, len(self.text))
@property
def type(self):
return self._type
@property
def text(self):
return self._text
@property
def ref(self):
return self._ref
### internal string encode/decode ###########################################
def _str_to_bytes(s):
return s.encode('utf-8')
def _str_to_py(s):
if s is None:
return None
if isinstance(s, bytes):
return s.decode('utf-8')
if isinstance(s, c_char_p):
return s.value.decode('utf-8')
if isinstance(s, c_void_p):
return cast(s, c_char_p).value.decode('utf-8')
if isinstance(s, int):
return cast(s, c_char_p).value.decode('utf-8')
print('WARNING !!!!!!!!! Unknown type: %s' % type(s))
### module init/shutdown ####################################################
def _cleanup():
global _already_halted
lib.eolian_shutdown()
_already_halted = True
lib.eolian_init()
atexit.register(_cleanup)
### API coverage statistics #################################################
if __name__ == '__main__':
import sys
import os
import re
# find Eolian.h in source tree
script_path = os.path.dirname(os.path.realpath(__file__))
eolian_header = os.path.join(script_path, '..', '..', 'lib', 'eolian', 'Eolian.h')
eolian_header = os.path.abspath(eolian_header)
# prepare the two regexp
flags = re.S | re.M
DEFINED_RE = re.compile('^EAPI[\w\n *]*(eolian_\w*)\([\w *,]*\);', flags)
USED_RE = re.compile('lib\.(eolian_[\w]*)\(', flags)
# extract all EAPI functions from Eolian.h
defined_funcs = []
with open(eolian_header, 'r') as fh:
header = fh.read()
for match in re.finditer(DEFINED_RE, header):
func_name = match.group(1)
defined_funcs.append(func_name)
defined_funcs = set(defined_funcs)
# extract all called functions in eolian.py (this file)
used_funcs = []
with open(__file__, 'r') as fh:
source = fh.read()
for match in re.finditer(USED_RE, source):
func_name = match.group(1)
used_funcs.append(func_name)
used_funcs = set(used_funcs)
# show general info
num_def = len(defined_funcs)
num_usd = len(used_funcs)
print('Pyolian coverage results')
print('========================')
print('Found %d functions defined in Eolian.h (%s)' % (num_def, eolian_header))
print('Found %d functions used in eolian.py (hopefully not commented out)' % num_usd)
print('Total API coverage %.1f%%' % (num_usd / num_def * 100))
print()
# list all missing functions
missing = defined_funcs - used_funcs
print('{} Missing functions in eolian.py'.format(len(missing)))
print('=================================')
for i, func_name in enumerate(sorted(missing), 1):
print('{:02d}. {}'.format(i, func_name))
print()
# List all functions found in Eolian.h (--all option)
if '--all' in sys.argv:
print('{} functions found in Eolian.h'.format(num_def))
print('===============================')
for i, func_name in enumerate(sorted(defined_funcs), 1):
print('{:03d}. {}'.format(i, func_name))
print()
else:
print('Additional arguments')
print('====================')
print(' --all To list all functions found in Eolian.h')
print()