Skip to content

Commit 1068fb7

Browse files
committed
Generate typing stubs for evdev.ecodes
1 parent 1818e9d commit 1068fb7

5 files changed

Lines changed: 81 additions & 28 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ __pycache__
1818

1919
evdev/*.so
2020
evdev/ecodes.c
21-
evdev/iprops.c
21+
evdev/ecodes.pyi
2222
docs/_build
2323
evdev/_ecodes.py
2424
evdev/_input.py

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
# evdev headers of the running kernel. Refer to the 'build_ecodes' distutils
33
# command in setup.py.
44
exclude evdev/ecodes.c
5+
include evdev/ecodes.pyi

evdev/genecodes.py

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
Generate a Python extension module with the constants defined in linux/input.h.
33
"""
44

5-
import os, sys, re
6-
5+
import getopt
6+
import os
7+
import re
8+
import sys
79

810
# -----------------------------------------------------------------------------
911
# The default header file locations to try.
@@ -13,8 +15,10 @@
1315
"/usr/include/linux/uinput.h",
1416
]
1517

16-
if sys.argv[1:]:
17-
headers = sys.argv[1:]
18+
opts, args = getopt.getopt(sys.argv[1:], "", ["ecodes", "stubs"])
19+
if not opts:
20+
print("usage: genecodes.py [--ecodes|--stubs] <headers>")
21+
exit(2)
1822

1923

2024
# -----------------------------------------------------------------------------
@@ -27,7 +31,7 @@
2731

2832

2933
# -----------------------------------------------------------------------------
30-
template = r"""
34+
template_ecodes = r"""
3135
#include <Python.h>
3236
#ifdef __FreeBSD__
3337
#include <dev/evdev/input.h>
@@ -37,7 +41,8 @@
3741
#endif
3842
3943
/* Automatically generated by evdev.genecodes */
40-
/* Generated on %s */
44+
/* Generated on %s */
45+
/* Generated from %s */
4146
4247
#define MODULE_NAME "_ecodes"
4348
#define MODULE_HELP "linux/input.h macros"
@@ -71,25 +76,63 @@
7176
"""
7277

7378

74-
def parse_header(header):
75-
for line in open(header):
76-
macro = macro_regex.search(line)
77-
if macro:
78-
yield " PyModule_AddIntMacro(m, %s);" % macro.group(1)
79+
template_stubs = r"""
80+
# Automatically generated by evdev.genecodes
81+
# Generated on %s
82+
# Generated from %s
83+
84+
# pylint: skip-file
85+
86+
ecodes: dict[str, int]
87+
keys: dict[int, str|list[str]]
88+
bytype: dict[int, dict[int, str|list[str]]]
89+
90+
KEY: dict[int, str|list[str]]
91+
ABS: dict[int, str|list[str]]
92+
REL: dict[int, str|list[str]]
93+
SW: dict[int, str|list[str]]
94+
MSC: dict[int, str|list[str]]
95+
LED: dict[int, str|list[str]]
96+
BTN: dict[int, str|list[str]]
97+
REP: dict[int, str|list[str]]
98+
SND: dict[int, str|list[str]]
99+
ID: dict[int, str|list[str]]
100+
EV: dict[int, str|list[str]]
101+
BUS: dict[int, str|list[str]]
102+
SYN: dict[int, str|list[str]]
103+
FF_STATUS: dict[int, str|list[str]]
104+
FF_INPUT_PROP: dict[int, str|list[str]]
105+
106+
%s
107+
"""
79108

80109

81-
all_macros = []
82-
for header in headers:
83-
try:
84-
fh = open(header)
85-
except (IOError, OSError):
86-
continue
87-
all_macros += parse_header(header)
110+
def parse_headers(headers=headers):
111+
for header in headers:
112+
try:
113+
fh = open(header)
114+
except (IOError, OSError):
115+
continue
88116

117+
for line in fh:
118+
macro = macro_regex.search(line)
119+
if macro:
120+
yield macro.group(1)
121+
122+
123+
all_macros = list(parse_headers())
89124
if not all_macros:
90125
print("no input macros found in: %s" % " ".join(headers), file=sys.stderr)
91126
sys.exit(1)
92127

93-
94-
macros = os.linesep.join(all_macros)
95-
print(template % (uname, macros))
128+
# pylint: disable=possibly-used-before-assignment, used-before-assignment
129+
if ("--ecodes", "") in opts:
130+
body = (" PyModule_AddIntMacro(m, %s);" % macro for macro in all_macros)
131+
template = template_ecodes
132+
elif ("--stubs", "") in opts:
133+
body = ("%s: int" % macro for macro in all_macros)
134+
template = template_stubs
135+
136+
body = os.linesep.join(body)
137+
text = template % (uname, headers, body)
138+
print(text.strip())

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ classifiers = [
3232
[tool.setuptools]
3333
packages = ["evdev"]
3434

35+
[tool.setuptools.data-files]
36+
"data" = ["evdev/*.pyi"]
37+
3538
[tool.ruff]
3639
line-length = 120
3740

setup.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99

1010
curdir = Path(__file__).resolve().parent
11-
ecodes_path = curdir / "evdev/ecodes.c"
11+
ecodes_c_path = curdir / "evdev/ecodes.c"
12+
ecodes_pyi_path = curdir / "evdev/ecodes.pyi"
1213

1314

1415
def create_ecodes(headers=None):
@@ -58,9 +59,14 @@ def create_ecodes(headers=None):
5859

5960
from subprocess import run
6061

61-
print("writing %s (using %s)" % (ecodes_path, " ".join(headers)))
62-
with ecodes_path.open("w") as fh:
63-
cmd = [sys.executable, "evdev/genecodes.py", *headers]
62+
print("writing %s (using %s)" % (ecodes_c_path, " ".join(headers)))
63+
with ecodes_c_path.open("w") as fh:
64+
cmd = [sys.executable, "evdev/genecodes.py", "--ecodes", *headers]
65+
run(cmd, check=True, stdout=fh)
66+
67+
print("writing %s (using %s)" % (ecodes_pyi_path, " ".join(headers)))
68+
with ecodes_pyi_path.open("w") as fh:
69+
cmd = [sys.executable, "evdev/genecodes.py", "--stubs", *headers]
6470
run(cmd, check=True, stdout=fh)
6571

6672

@@ -84,9 +90,9 @@ def run(self):
8490

8591
class build_ext(_build_ext.build_ext):
8692
def has_ecodes(self):
87-
if ecodes_path.exists():
93+
if ecodes_c_path.exists():
8894
print("ecodes.c already exists ... skipping build_ecodes")
89-
return not ecodes_path.exists()
95+
return not ecodes_c_path.exists()
9096

9197
def run(self):
9298
for cmd_name in self.get_sub_commands():

0 commit comments

Comments
 (0)