31
31
32
32
from concurrent .futures import ThreadPoolExecutor
33
33
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
+ ]
35
45
36
46
ALIASES_BY_BOARD = {
37
47
"circuitplayground_express" : [
44
54
}
45
55
46
56
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" ,
57
62
}
58
63
59
64
ADDITIONAL_MODULES = {
72
77
"usb" : "CIRCUITPY_USB_HOST" ,
73
78
}
74
79
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
+ ]
76
93
77
94
FROZEN_EXCLUDES = ["examples" , "docs" , "tests" , "utils" , "conf.py" , "setup.py" ]
78
95
"""Files and dirs at the root of a frozen directory that should be ignored.
83
100
84
101
root_dir = pathlib .Path (__file__ ).resolve ().parent .parent
85
102
103
+
86
104
def get_circuitpython_root_dir ():
87
- """ The path to the root './circuitpython' directory.
88
- """
105
+ """The path to the root './circuitpython' directory."""
89
106
return root_dir
90
107
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
96
120
97
121
98
122
def get_board_mapping ():
@@ -124,8 +148,7 @@ def get_board_mapping():
124
148
125
149
126
150
def read_mpconfig ():
127
- """ Open 'circuitpy_mpconfig.mk' and return the contents.
128
- """
151
+ """Open 'circuitpy_mpconfig.mk' and return the contents."""
129
152
configs = []
130
153
cpy_mpcfg = get_circuitpython_root_dir () / "py" / "circuitpy_mpconfig.mk"
131
154
with open (cpy_mpcfg ) as mpconfig :
@@ -135,22 +158,22 @@ def read_mpconfig():
135
158
136
159
137
160
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.]).
142
165
143
166
"""
144
167
base = dict ()
145
- modules = get_shared_bindings ()
168
+ modules = get_bindings ()
146
169
configs = read_mpconfig ()
147
170
full_build = False
148
171
for module in modules :
149
172
full_name = module
150
173
if module in ADDITIONAL_MODULES :
151
174
search_identifier = ADDITIONAL_MODULES [module ]
152
175
else :
153
- search_identifier = ' CIRCUITPY_' + module .lstrip ("_" ).upper ()
176
+ search_identifier = " CIRCUITPY_" + module .lstrip ("_" ).upper ()
154
177
re_pattern = f"{ re .escape (search_identifier )} \s*\??=\s*(.+)"
155
178
find_config = re .findall (re_pattern , configs )
156
179
if not find_config :
@@ -173,21 +196,22 @@ def build_module_map():
173
196
174
197
return base
175
198
199
+
176
200
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.
179
203
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
183
207
"""
184
208
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
+ )
191
215
# Make signals errors with exit status 2; 0 and 1 are "non-error" statuses
192
216
if contents .returncode not in (0 , 1 ):
193
217
error_msg = (
@@ -197,30 +221,34 @@ def get_settings_from_makefile(port_dir, board_name):
197
221
raise RuntimeError (error_msg )
198
222
199
223
settings = {}
200
- for line in contents .stdout .split (' \n ' ):
224
+ for line in contents .stdout .split (" \n " ):
201
225
# 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 )
203
227
if m :
204
228
settings [m .group (1 )] = m .group (2 )
205
229
206
230
return settings
207
231
232
+
208
233
def get_repository_url (directory ):
209
234
if directory in repository_urls :
210
235
return repository_urls [directory ]
211
236
readme = None
212
237
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
+ ):
216
241
if os .path .exists (readme_path ):
217
242
readme = readme_path
218
243
break
219
244
path = None
220
245
if readme :
221
246
with open (readme , "r" ) as fp :
222
247
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
+ ):
224
252
path = m .group (1 )
225
253
break
226
254
if m := re .search ("<(http[^>]+)>" , line ):
@@ -233,12 +261,13 @@ def get_repository_url(directory):
233
261
errors = "replace" ,
234
262
stdout = subprocess .PIPE ,
235
263
stderr = subprocess .PIPE ,
236
- cwd = directory
264
+ cwd = directory ,
237
265
)
238
266
path = contents .stdout .strip ()
239
267
repository_urls [directory ] = path
240
268
return path
241
269
270
+
242
271
def frozen_modules_from_dirs (frozen_mpy_dirs , withurl ):
243
272
"""
244
273
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):
261
290
else :
262
291
frozen_modules .append (sub .name [:- 3 ])
263
292
continue
264
- if next (sub .glob ("**/*.py" ), None ): # tests if not empty
293
+ if next (sub .glob ("**/*.py" ), None ): # tests if not empty
265
294
if withurl :
266
295
frozen_modules .append ((sub .name , url_repository ))
267
296
else :
268
297
frozen_modules .append (sub .name )
269
298
return frozen_modules
270
299
271
- def lookup_setting (settings , key , default = '' ):
300
+
301
+ def lookup_setting (settings , key , default = "" ):
272
302
while True :
273
303
value = settings .get (key , default )
274
- if not value .startswith ('$' ):
304
+ if not value .startswith ("$" ):
275
305
break
276
306
key = value [2 :- 1 ]
277
307
return value
278
308
309
+
279
310
@functools .cache
280
311
def all_ports_all_boards (ports = SUPPORTED_PORTS ):
281
312
for port in ports :
282
-
283
313
port_dir = get_circuitpython_root_dir () / "ports" / port
284
314
for entry in (port_dir / "boards" ).iterdir ():
285
315
if not entry .is_dir ():
286
316
continue
287
317
yield (port , entry )
288
318
319
+
289
320
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.
292
323
"""
293
324
base = build_module_map ()
294
325
@@ -300,65 +331,79 @@ def support_matrix(arg):
300
331
if use_branded_name :
301
332
with open (entry / "mpconfigboard.h" ) as get_name :
302
333
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
+ )
305
337
if board_name_re :
306
338
board_name = board_name_re .group (1 ).strip ('"' )
307
339
else :
308
340
board_name = entry .name
309
341
310
342
board_modules = []
311
343
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" ])
315
347
board_modules .sort ()
316
348
317
349
if "CIRCUITPY_BUILD_EXTENSIONS" in settings :
318
350
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 ("," )
321
353
]
322
354
else :
323
355
raise OSError (f"Board extensions undefined: { board_name } ." )
324
356
325
357
frozen_modules = []
326
358
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
+ )
328
362
if frozen_modules :
329
363
frozen_modules .sort ()
330
364
331
365
# 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
+ ]
339
376
if entry .name in ALIASES_BY_BOARD :
340
377
for alias in ALIASES_BY_BOARD [entry .name ]:
341
378
if use_branded_name :
342
379
if alias in ALIASES_BRAND_NAMES :
343
380
alias = ALIASES_BRAND_NAMES [alias ]
344
381
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)
355
395
356
396
executor = ThreadPoolExecutor (max_workers = os .cpu_count ())
357
397
mapped_exec = executor .map (support_matrix , all_ports_all_boards ())
358
398
# 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
+ )
360
404
361
405
return boards
362
406
363
- if __name__ == '__main__' :
407
+
408
+ if __name__ == "__main__" :
364
409
print (json .dumps (support_matrix_by_board (), indent = 2 ))
0 commit comments