3131
3232from 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
3646ALIASES_BY_BOARD = {
3747 "circuitplayground_express" : [
4454}
4555
4656ALIASES_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
5964ADDITIONAL_MODULES = {
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
7794FROZEN_EXCLUDES = ["examples" , "docs" , "tests" , "utils" , "conf.py" , "setup.py" ]
7895"""Files and dirs at the root of a frozen directory that should be ignored.
83100
84101root_dir = pathlib .Path (__file__ ).resolve ().parent .parent
85102
103+
86104def 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
98122def get_board_mapping ():
@@ -124,8 +148,7 @@ def get_board_mapping():
124148
125149
126150def 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
137160def 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+
176200def 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+
208233def 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+
242271def 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
280311def 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+
289320def 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