Skip to content

Commit 76d590b

Browse files
authored
Merge pull request #7725 from dhalbert/port-specific-modules-in-support-matrix
add port-specific modules to support matrix
2 parents f708048 + 069a058 commit 76d590b

File tree

2 files changed

+137
-79
lines changed

2 files changed

+137
-79
lines changed

docs/shared_bindings_matrix.py

Lines changed: 123 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,17 @@
3131

3232
from concurrent.futures import ThreadPoolExecutor
3333

34-
SUPPORTED_PORTS = ['atmel-samd', 'broadcom', 'cxd56', 'espressif', 'litex', 'mimxrt10xx', 'nrf', 'raspberrypi', 'stm']
34+
SUPPORTED_PORTS = [
35+
"atmel-samd",
36+
"broadcom",
37+
"cxd56",
38+
"espressif",
39+
"litex",
40+
"mimxrt10xx",
41+
"nrf",
42+
"raspberrypi",
43+
"stm",
44+
]
3545

3646
ALIASES_BY_BOARD = {
3747
"circuitplayground_express": [
@@ -44,16 +54,11 @@
4454
}
4555

4656
ALIASES_BRAND_NAMES = {
47-
"circuitplayground_express_4h":
48-
"Adafruit Circuit Playground Express 4-H",
49-
"circuitplayground_express_digikey_pycon2019":
50-
"Circuit Playground Express Digi-Key PyCon 2019",
51-
"edgebadge":
52-
"Adafruit EdgeBadge",
53-
"pyportal_pynt":
54-
"Adafruit PyPortal Pynt",
55-
"gemma_m0_pycon2018":
56-
"Adafruit Gemma M0 PyCon 2018",
57+
"circuitplayground_express_4h": "Adafruit Circuit Playground Express 4-H",
58+
"circuitplayground_express_digikey_pycon2019": "Circuit Playground Express Digi-Key PyCon 2019",
59+
"edgebadge": "Adafruit EdgeBadge",
60+
"pyportal_pynt": "Adafruit PyPortal Pynt",
61+
"gemma_m0_pycon2018": "Adafruit Gemma M0 PyCon 2018",
5762
}
5863

5964
ADDITIONAL_MODULES = {
@@ -72,7 +77,19 @@
7277
"usb": "CIRCUITPY_USB_HOST",
7378
}
7479

75-
MODULES_NOT_IN_SHARED_BINDINGS = ["_asyncio", "array", "binascii", "builtins", "collections", "errno", "json", "re", "select", "sys", "ulab"]
80+
MODULES_NOT_IN_BINDINGS = [
81+
"_asyncio",
82+
"array",
83+
"binascii",
84+
"builtins",
85+
"collections",
86+
"errno",
87+
"json",
88+
"re",
89+
"select",
90+
"sys",
91+
"ulab",
92+
]
7693

7794
FROZEN_EXCLUDES = ["examples", "docs", "tests", "utils", "conf.py", "setup.py"]
7895
"""Files and dirs at the root of a frozen directory that should be ignored.
@@ -83,16 +100,23 @@
83100

84101
root_dir = pathlib.Path(__file__).resolve().parent.parent
85102

103+
86104
def get_circuitpython_root_dir():
87-
""" The path to the root './circuitpython' directory.
88-
"""
105+
"""The path to the root './circuitpython' directory."""
89106
return root_dir
90107

91-
def get_shared_bindings():
92-
""" Get a list of modules in shared-bindings based on folder names.
93-
"""
94-
shared_bindings_dir = get_circuitpython_root_dir() / "shared-bindings"
95-
return [item.name for item in shared_bindings_dir.iterdir()] + MODULES_NOT_IN_SHARED_BINDINGS
108+
109+
def get_bindings():
110+
"""Get a list of modules in shared-bindings and ports/*/bindings based on folder names."""
111+
shared_bindings_modules = [
112+
module.name
113+
for module in (get_circuitpython_root_dir() / "shared-bindings").iterdir()
114+
if module.is_dir()
115+
]
116+
bindings_modules = []
117+
for d in get_circuitpython_root_dir().glob("ports/*/bindings"):
118+
bindings_modules.extend(module.name for module in d.iterdir() if d.is_dir())
119+
return shared_bindings_modules + bindings_modules + MODULES_NOT_IN_BINDINGS
96120

97121

98122
def get_board_mapping():
@@ -124,8 +148,7 @@ def get_board_mapping():
124148

125149

126150
def read_mpconfig():
127-
""" Open 'circuitpy_mpconfig.mk' and return the contents.
128-
"""
151+
"""Open 'circuitpy_mpconfig.mk' and return the contents."""
129152
configs = []
130153
cpy_mpcfg = get_circuitpython_root_dir() / "py" / "circuitpy_mpconfig.mk"
131154
with open(cpy_mpcfg) as mpconfig:
@@ -135,22 +158,22 @@ def read_mpconfig():
135158

136159

137160
def build_module_map():
138-
""" Establish the base of the JSON file, based on the contents from
139-
`configs`. Base will contain module names, if they're part of
140-
the `FULL_BUILD`, or their default value (0, 1, or a list of
141-
modules that determine default [see audiocore, audiomixer, etc.]).
161+
"""Establish the base of the JSON file, based on the contents from
162+
`configs`. Base will contain module names, if they're part of
163+
the `FULL_BUILD`, or their default value (0, 1, or a list of
164+
modules that determine default [see audiocore, audiomixer, etc.]).
142165
143166
"""
144167
base = dict()
145-
modules = get_shared_bindings()
168+
modules = get_bindings()
146169
configs = read_mpconfig()
147170
full_build = False
148171
for module in modules:
149172
full_name = module
150173
if module in ADDITIONAL_MODULES:
151174
search_identifier = ADDITIONAL_MODULES[module]
152175
else:
153-
search_identifier = 'CIRCUITPY_'+module.lstrip("_").upper()
176+
search_identifier = "CIRCUITPY_" + module.lstrip("_").upper()
154177
re_pattern = f"{re.escape(search_identifier)}\s*\??=\s*(.+)"
155178
find_config = re.findall(re_pattern, configs)
156179
if not find_config:
@@ -173,21 +196,22 @@ def build_module_map():
173196

174197
return base
175198

199+
176200
def get_settings_from_makefile(port_dir, board_name):
177-
""" Invoke make in a mode which prints the database, then parse it for
178-
settings.
201+
"""Invoke make in a mode which prints the database, then parse it for
202+
settings.
179203
180-
This means that the effect of all Makefile directives is taken
181-
into account, without having to re-encode the logic that sets them
182-
in this script, something that has proved error-prone
204+
This means that the effect of all Makefile directives is taken
205+
into account, without having to re-encode the logic that sets them
206+
in this script, something that has proved error-prone
183207
"""
184208
contents = subprocess.run(
185-
["make", "-C", port_dir, f"BOARD={board_name}", "-qp", "print-CC"],
186-
encoding="utf-8",
187-
errors="replace",
188-
stdout=subprocess.PIPE,
189-
stderr=subprocess.PIPE
190-
)
209+
["make", "-C", port_dir, f"BOARD={board_name}", "-qp", "print-CC"],
210+
encoding="utf-8",
211+
errors="replace",
212+
stdout=subprocess.PIPE,
213+
stderr=subprocess.PIPE,
214+
)
191215
# Make signals errors with exit status 2; 0 and 1 are "non-error" statuses
192216
if contents.returncode not in (0, 1):
193217
error_msg = (
@@ -197,30 +221,34 @@ def get_settings_from_makefile(port_dir, board_name):
197221
raise RuntimeError(error_msg)
198222

199223
settings = {}
200-
for line in contents.stdout.split('\n'):
224+
for line in contents.stdout.split("\n"):
201225
# Handle both = and := definitions.
202-
m = re.match(r'^([A-Z][A-Z0-9_]*) :?= (.*)$', line)
226+
m = re.match(r"^([A-Z][A-Z0-9_]*) :?= (.*)$", line)
203227
if m:
204228
settings[m.group(1)] = m.group(2)
205229

206230
return settings
207231

232+
208233
def get_repository_url(directory):
209234
if directory in repository_urls:
210235
return repository_urls[directory]
211236
readme = None
212237
for readme_path in (
213-
os.path.join(directory, "README.rst"),
214-
os.path.join(os.path.dirname(directory), "README.rst")
215-
):
238+
os.path.join(directory, "README.rst"),
239+
os.path.join(os.path.dirname(directory), "README.rst"),
240+
):
216241
if os.path.exists(readme_path):
217242
readme = readme_path
218243
break
219244
path = None
220245
if readme:
221246
with open(readme, "r") as fp:
222247
for line in fp.readlines():
223-
if m := re.match("\s+:target:\s+(http\S+(docs.circuitpython|readthedocs)\S+)\s*", line):
248+
if m := re.match(
249+
"\s+:target:\s+(http\S+(docs.circuitpython|readthedocs)\S+)\s*",
250+
line,
251+
):
224252
path = m.group(1)
225253
break
226254
if m := re.search("<(http[^>]+)>", line):
@@ -233,12 +261,13 @@ def get_repository_url(directory):
233261
errors="replace",
234262
stdout=subprocess.PIPE,
235263
stderr=subprocess.PIPE,
236-
cwd=directory
264+
cwd=directory,
237265
)
238266
path = contents.stdout.strip()
239267
repository_urls[directory] = path
240268
return path
241269

270+
242271
def frozen_modules_from_dirs(frozen_mpy_dirs, withurl):
243272
"""
244273
Go through the list of frozen directories and extract the python modules.
@@ -261,34 +290,36 @@ def frozen_modules_from_dirs(frozen_mpy_dirs, withurl):
261290
else:
262291
frozen_modules.append(sub.name[:-3])
263292
continue
264-
if next(sub.glob("**/*.py"), None): # tests if not empty
293+
if next(sub.glob("**/*.py"), None): # tests if not empty
265294
if withurl:
266295
frozen_modules.append((sub.name, url_repository))
267296
else:
268297
frozen_modules.append(sub.name)
269298
return frozen_modules
270299

271-
def lookup_setting(settings, key, default=''):
300+
301+
def lookup_setting(settings, key, default=""):
272302
while True:
273303
value = settings.get(key, default)
274-
if not value.startswith('$'):
304+
if not value.startswith("$"):
275305
break
276306
key = value[2:-1]
277307
return value
278308

309+
279310
@functools.cache
280311
def all_ports_all_boards(ports=SUPPORTED_PORTS):
281312
for port in ports:
282-
283313
port_dir = get_circuitpython_root_dir() / "ports" / port
284314
for entry in (port_dir / "boards").iterdir():
285315
if not entry.is_dir():
286316
continue
287317
yield (port, entry)
288318

319+
289320
def support_matrix_by_board(use_branded_name=True, withurl=True):
290-
""" Compiles a list of the available core modules available for each
291-
board.
321+
"""Compiles a list of the available core modules available for each
322+
board.
292323
"""
293324
base = build_module_map()
294325

@@ -300,65 +331,79 @@ def support_matrix(arg):
300331
if use_branded_name:
301332
with open(entry / "mpconfigboard.h") as get_name:
302333
board_contents = get_name.read()
303-
board_name_re = re.search(r"(?<=MICROPY_HW_BOARD_NAME)\s+(.+)",
304-
board_contents)
334+
board_name_re = re.search(
335+
r"(?<=MICROPY_HW_BOARD_NAME)\s+(.+)", board_contents
336+
)
305337
if board_name_re:
306338
board_name = board_name_re.group(1).strip('"')
307339
else:
308340
board_name = entry.name
309341

310342
board_modules = []
311343
for module in base:
312-
key = base[module]['key']
313-
if int(lookup_setting(settings, key, '0')):
314-
board_modules.append(base[module]['name'])
344+
key = base[module]["key"]
345+
if int(lookup_setting(settings, key, "0")):
346+
board_modules.append(base[module]["name"])
315347
board_modules.sort()
316348

317349
if "CIRCUITPY_BUILD_EXTENSIONS" in settings:
318350
board_extensions = [
319-
extension.strip() for extension in
320-
settings["CIRCUITPY_BUILD_EXTENSIONS"].split(",")
351+
extension.strip()
352+
for extension in settings["CIRCUITPY_BUILD_EXTENSIONS"].split(",")
321353
]
322354
else:
323355
raise OSError(f"Board extensions undefined: {board_name}.")
324356

325357
frozen_modules = []
326358
if "FROZEN_MPY_DIRS" in settings:
327-
frozen_modules = frozen_modules_from_dirs(settings["FROZEN_MPY_DIRS"], withurl)
359+
frozen_modules = frozen_modules_from_dirs(
360+
settings["FROZEN_MPY_DIRS"], withurl
361+
)
328362
if frozen_modules:
329363
frozen_modules.sort()
330364

331365
# generate alias boards too
332-
board_matrix = [(
333-
board_name, {
334-
"modules": board_modules,
335-
"frozen_libraries": frozen_modules,
336-
"extensions": board_extensions,
337-
}
338-
)]
366+
board_matrix = [
367+
(
368+
board_name,
369+
{
370+
"modules": board_modules,
371+
"frozen_libraries": frozen_modules,
372+
"extensions": board_extensions,
373+
},
374+
)
375+
]
339376
if entry.name in ALIASES_BY_BOARD:
340377
for alias in ALIASES_BY_BOARD[entry.name]:
341378
if use_branded_name:
342379
if alias in ALIASES_BRAND_NAMES:
343380
alias = ALIASES_BRAND_NAMES[alias]
344381
else:
345-
alias = alias.replace("_"," ").title()
346-
board_matrix.append((
347-
alias, {
348-
"modules": board_modules,
349-
"frozen_libraries": frozen_modules,
350-
"extensions": board_extensions,
351-
},
352-
))
353-
354-
return board_matrix # this is now a list of (board,modules)
382+
alias = alias.replace("_", " ").title()
383+
board_matrix.append(
384+
(
385+
alias,
386+
{
387+
"modules": board_modules,
388+
"frozen_libraries": frozen_modules,
389+
"extensions": board_extensions,
390+
},
391+
)
392+
)
393+
394+
return board_matrix # this is now a list of (board,modules)
355395

356396
executor = ThreadPoolExecutor(max_workers=os.cpu_count())
357397
mapped_exec = executor.map(support_matrix, all_ports_all_boards())
358398
# flatmap with comprehensions
359-
boards = dict(sorted([board for matrix in mapped_exec for board in matrix], key=lambda x: x[0]))
399+
boards = dict(
400+
sorted(
401+
[board for matrix in mapped_exec for board in matrix], key=lambda x: x[0]
402+
)
403+
)
360404

361405
return boards
362406

363-
if __name__ == '__main__':
407+
408+
if __name__ == "__main__":
364409
print(json.dumps(support_matrix_by_board(), indent=2))

0 commit comments

Comments
 (0)