summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Huuhko <kai.huuhko@gmail.com>2014-05-16 10:36:50 +0300
committerKai Huuhko <kai.huuhko@gmail.com>2014-05-16 10:36:50 +0300
commitea2fa02667cd6ddc92406fd73e288ed14ab77983 (patch)
tree112ca49b06ee26c4e33782bd87cd2f34f635a262
parent5b51428bc8d50ae25a0365f582b302fb12d9cf64 (diff)
api_coverage.py: Updates
Now when omitting arguments it reports all possible combinations
-rwxr-xr-xapi_coverage.py186
1 files changed, 124 insertions, 62 deletions
diff --git a/api_coverage.py b/api_coverage.py
index b0105b3..442d9ff 100755
--- a/api_coverage.py
+++ b/api_coverage.py
@@ -7,89 +7,130 @@ import subprocess
7import argparse 7import argparse
8 8
9c_exclude_list = [ 9c_exclude_list = [
10 "elm_app", # These are only useful for C apps 10 "elm_app", # These are only useful for C apps
11 "elm_widget", # Custom widgets, probably not feasible for us to provide 11 "elm_widget", # Custom widgets, probably not feasible for us to provide
12 "elm_quicklaunch", # Is quicklaunch relevant for us? 12 "elm_quicklaunch", # Is quicklaunch relevant for us?
13 "emotion_object_extension_may_play_fast_get", # this optimization does not work from py 13 "emotion_object_extension_may_play_fast_get", # this optimization does
14 "edje_edit_", # Disabled 14 # not work from py
15 "ecore_thread_", # python has his own thread abstraction library 15 "edje_edit_", # Disabled
16 "ecore_pipe_", # python has his own pipe abstraction library 16 "ecore_thread_", # python has his own thread abstraction library
17 "ecore_getopt_", # python has his own getopt implementation 17 "ecore_pipe_", # python has his own pipe abstraction library
18 "ecore_coroutine_", # python has someting similar...maybe 18 "ecore_getopt_", # python has his own getopt implementation
19 "ecore_fork_", # low level stuff, not to be exposed 19 "ecore_coroutine_", # python has someting similar...maybe
20 "ecore_timer_dump", # this is just usefull for debugging 20 "ecore_fork_", # low level stuff, not to be exposed
21 "ecore_throttle_", # I don't know what this is :/ - davemds 21 "ecore_timer_dump", # this is just usefull for debugging
22 "elm_check_state_pointer_set", # Cannot be implemented in Python 22 "ecore_throttle_", # I don't know what this is :/ - davemds
23 "elm_access", # Access disabled until 1.9 23 "elm_check_state_pointer_set", # Cannot be implemented in Python
24 "elm_config_access", # Access disabled until 1.9 24 "elm_access", # Access disabled until 1.9
25 "elm_object_item_access", # Access disabled until 1.9 25 "elm_config_access", # Access disabled until 1.9
26 "elm_object_item_access", # Access disabled until 1.9
26] 27]
27c_excludes = "|".join(c_exclude_list) 28c_excludes = "|".join(c_exclude_list)
28 29
29py_exclude_list = [ 30py_exclude_list = [
30 "elm_naviframe_item_simple_push", # macro 31 "elm_naviframe_item_simple_push", # macro
31 "elm_object_item_content", # macro 32 "elm_object_item_content", # macro
32 "elm_object_item_text", # macro 33 "elm_object_item_text", # macro
33 "elm_object_content", # macro 34 "elm_object_content", # macro
34 "elm_object_text", # macro 35 "elm_object_text", # macro
35 "elm_layout_end", # macros 36 "elm_layout_end", # macros
36 "elm_layout_icon", # macros 37 "elm_layout_icon", # macros
37 "elm_object_domain_translatable_text", # macros 38 "elm_object_domain_translatable_text", # macros
38 "elm_object_tooltip_translatable_text", # macros 39 "elm_object_tooltip_translatable_text", # macros
39 "elm_object_translatable_text", # macros 40 "elm_object_translatable_text", # macros
40 "elm_access", # Access disabled until 1.9 41 "elm_access", # Access disabled until 1.9
41 "elm_config_access", # Access disabled until 1.9 42 "elm_config_access", # Access disabled until 1.9
42 "elm_object_item_access", # Access disabled until 1.9 43 "elm_object_item_access", # Access disabled until 1.9
43] 44]
44py_excludes = "|".join(py_exclude_list) 45py_excludes = "|".join(py_exclude_list)
45 46
46parser = argparse.ArgumentParser()
47parser.add_argument("--python", action="store_true", default=False, help="Show Python API coverage")
48parser.add_argument("--c", action="store_true", default=False, help="Show C API coverage")
49parser.add_argument("libs", nargs="+", help="Possible values are eo, evas, ecore, ecore-file, edje, emotion, elementary and all.")
50args = parser.parse_args()
51
52libs = args.libs[:]
53
54if libs == ["all"]:
55 libs = ["eo", "evas", "ecore", "ecore-file", "edje", "emotion", "elementary"]
56
57params = { 47params = {
58 "eo": ("include", "Eo", "eo"), 48 "eo": ("include", "Eo", "eo"),
59 "evas": ("include", "Evas", "evas"), 49 "evas": ("include", "Evas", "evas"),
60 "ecore": ("include", "Ecore", "ecore"), 50 "ecore": ("efl/ecore", "Ecore", "ecore"),
61 "ecore-file": ("include", "Ecore_File", "ecore_file"), 51 "ecore-file": ("efl/ecore", "Ecore_File", "ecore_file"),
52 "ecore-x": ("efl/ecore", "Ecore_X", "ecore_x"),
62 "edje": ("include", "Edje", "edje"), 53 "edje": ("include", "Edje", "edje"),
63 "emotion": ("include", "Emotion", "emotion"), 54 "emotion": ("include", "Emotion", "emotion"),
64 "elementary": ("efl/elementary", "Elementary", "elm"), 55 "elementary": ("efl/elementary", "Elementary", "elm"),
65} 56}
66 57
58EFL_MIN_VERSION = "1.9.99"
59
60parser = argparse.ArgumentParser(
61 description="Reports EFL vs. Python-EFL API functions coverage"
62 )
63api_group = parser.add_argument_group("api")
64api_group.add_argument(
65 "--python",
66 action="store_true", default=False,
67 help="Show Python API coverage"
68 )
69api_group.add_argument(
70 "--c",
71 action="store_true", default=False,
72 help="Show C API coverage"
73 )
74parser.add_argument(
75 "libs",
76 nargs="*",
77 choices=(params.keys() + ["all"]),
78 default="all"
79 )
80args = parser.parse_args()
81
82if "all" in args.libs:
83 args.libs = params.keys()
84
85if not args.python and not args.c:
86 args.python = True
87 args.c = True
88
89
67def pkg_config(require, min_vers=None): 90def pkg_config(require, min_vers=None):
68 name = require.capitalize() 91 name = require.capitalize()
69 try: 92 try:
70 sys.stdout.write("Checking for " + name + ": ") 93 sys.stdout.write("Checking for %s: " % (name))
71 ver = subprocess.check_output(["pkg-config", "--modversion", require]).decode("utf-8").strip() 94 ver = subprocess.check_output(
95 ["pkg-config", "--modversion", require]
96 ).decode("utf-8").strip()
72 if min_vers is not None: 97 if min_vers is not None:
73 assert 0 == subprocess.call(["pkg-config", "--atleast-version", min_vers, require]) 98 assert 0 == subprocess.call(
74 cflags = subprocess.check_output(["pkg-config", "--cflags-only-I", require]).decode("utf-8").split() 99 ["pkg-config", "--atleast-version", min_vers, require]
100 )
101 cflags = subprocess.check_output(
102 ["pkg-config", "--cflags-only-I", require]
103 ).decode("utf-8").split()
75 sys.stdout.write("OK, found " + ver + "\n") 104 sys.stdout.write("OK, found " + ver + "\n")
76 return cflags 105 return cflags
77 except (OSError, subprocess.CalledProcessError): 106 except (OSError, subprocess.CalledProcessError):
78 raise SystemExit("Failed to find" + name + "with 'pkg-config'. Please make sure that it is installed and available on your system path.") 107 raise SystemExit(
108 "Failed to find %s with 'pkg-config'. Please make sure that it "
109 "is installed and available on your system path."
110 ) % (name)
79 except (AssertionError): 111 except (AssertionError):
80 raise SystemExit("Failed to match version. Found: " + ver + " Needed: " + min_vers) 112 raise SystemExit(
113 "Failed to match version. Found: %s Needed: %s" % (ver, min_vers)
114 )
115
81 116
82def get_capis(inc_path, prefix): 117def get_capis(inc_path, prefix):
83 capis = [] 118 capis = []
84 capi_pattern = re.compile("^ *EAPI [A-Za-z_ *\n]+ *\**\n?(?!" + c_excludes + ")(" + prefix + "_\w+) *\(", flags = re.S|re.M) 119 capi_pattern = re.compile(
120 "^ *EAPI [A-Za-z_ *\n]+ *\**\n?(?!" +
121 c_excludes + ")(" + prefix +
122 "_\w+) *\(",
123 flags=re.S | re.M
124 )
85 125
86 for path, dirs, files in os.walk(inc_path): 126 for path, dirs, files in os.walk(inc_path):
87 for f in files: 127 for f in files:
88 if not f.endswith("legacy.h"): 128 if f.endswith(".eo.h") or not f.endswith(".h"):
89 continue 129 continue
90 open_args = (os.path.join(path, f),) 130 open_args = (os.path.join(path, f),)
91 open_kwargs = dict(mode="r") 131 open_kwargs = dict(mode="r")
92 if sys.version_info[0] > 2: open_kwargs["encoding"] = "UTF-8" 132 if sys.version_info[0] > 2:
133 open_kwargs["encoding"] = "UTF-8"
93 134
94 with open(*open_args, **open_kwargs) as header: 135 with open(*open_args, **open_kwargs) as header:
95 capi = header.read() 136 capi = header.read()
@@ -101,10 +142,17 @@ def get_capis(inc_path, prefix):
101 142
102 return capis 143 return capis
103 144
145
104def get_pyapis(pxd_path, header_name, prefix): 146def get_pyapis(pxd_path, header_name, prefix):
105 pyapis = [] 147 pyapis = []
106 pyapi_pattern1 = re.compile('(cdef extern from "' + header_name + '\.h":\n)(.+)', flags = re.S) 148 pyapi_pattern1 = re.compile(
107 pyapi_pattern2 = re.compile("^ +[a-zA-Z _*]+?(?!" + py_excludes + ")(" + prefix + "_\w+)\(", flags = re.M) 149 '(cdef extern from "' + header_name + '\.h":\n)(.+)',
150 flags=re.S
151 )
152 pyapi_pattern2 = re.compile(
153 "^ +[a-zA-Z _*]+?(?!" + py_excludes + ")(" + prefix + "_\w+)\(",
154 flags=re.M
155 )
108 156
109 for path, dirs, files in os.walk(pxd_path): 157 for path, dirs, files in os.walk(pxd_path):
110 for f in files: 158 for f in files:
@@ -112,7 +160,8 @@ def get_pyapis(pxd_path, header_name, prefix):
112 continue 160 continue
113 open_args = (os.path.join(path, f),) 161 open_args = (os.path.join(path, f),)
114 open_kwargs = dict(mode="r") 162 open_kwargs = dict(mode="r")
115 if sys.version_info[0] > 2: open_kwargs["encoding"] = "UTF-8" 163 if sys.version_info[0] > 2:
164 open_kwargs["encoding"] = "UTF-8"
116 165
117 with open(*open_args, **open_kwargs) as pxd: 166 with open(*open_args, **open_kwargs) as pxd:
118 pyapi = pxd.read() 167 pyapi = pxd.read()
@@ -127,9 +176,9 @@ def get_pyapis(pxd_path, header_name, prefix):
127 return pyapis 176 return pyapis
128 177
129 178
130for lib in libs: 179for lib in args.libs:
131 180
132 inc_paths = pkg_config(lib, "1.7.99") 181 inc_paths = pkg_config(lib, EFL_MIN_VERSION)
133 inc_path = None 182 inc_path = None
134 for p in inc_paths: 183 for p in inc_paths:
135 if lib in p: 184 if lib in p:
@@ -154,14 +203,24 @@ for lib in libs:
154 if args.c and d in pyapis: 203 if args.c and d in pyapis:
155 print("{0} is missing from C API".format(d)) 204 print("{0} is missing from C API".format(d))
156 205
157 if args.python or args.c: print("\n---") 206 if args.python or args.c:
207 print("\n---")
158 208
159 if args.python: 209 if args.python:
160 print("Number of functions missing from Python API: {0}".format(len(capis - capis.intersection(pyapis)))) 210 print(
211 "Number of functions missing from Python API: {0}".format(
212 len(capis - capis.intersection(pyapis))
213 )
214 )
161 if args.c: 215 if args.c:
162 print("Number of functions missing from C API: {0}".format(len(pyapis - capis.intersection(pyapis)))) 216 print(
217 "Number of functions missing from C API: {0}".format(
218 len(pyapis - capis.intersection(pyapis))
219 )
220 )
163 221
164 if args.python or args.c: print("---") 222 if args.python or args.c:
223 print("---")
165 224
166 if args.python: 225 if args.python:
167 print("Python API functions: {0}".format(len(pyapis))) 226 print("Python API functions: {0}".format(len(pyapis)))
@@ -169,8 +228,11 @@ for lib in libs:
169 print("C API functions: {0}".format(len(capis))) 228 print("C API functions: {0}".format(len(capis)))
170 229
171 if args.python and len(capis) > 0: 230 if args.python and len(capis) > 0:
172 percentage = float(len(capis.intersection(pyapis))) / float(len(capis)) * 100.0 231 percentage = \
232 float(len(capis.intersection(pyapis))) / \
233 float(len(capis)) * 100.0
173 print("===") 234 print("===")
174 print("Bindings coverage {0:.2f}%".format(percentage)) 235 print("Bindings coverage {0:.2f}%".format(percentage))
175 236
176 if args.python or args.c: print("---\n") 237 if args.python or args.c:
238 print("---\n")