Skip to content

Commit f598b77

Browse files
Create a proper Python project for the Python scripts (#470)
* Start on improving Python project structure * Finish migrating to pyproject.toml * Add find program for python scripts * Remove existing mbed-tools, re-add dependency * Remove dependency on future * Print package dir * Augh missing quote * Oh neat reordering the commands already fixed it * Install pyocd and cysecuretools lazily * mbed-tools needs setuptools * Set min version of setuptools * Bump click version * Install cysecuretools in CI * Install xml apt packages * augh no sudo * Allow tests to be run from anywhere * Update tools/run_python_tests.sh Co-authored-by: VictorWTang <33789988+VictorWTang@users.noreply.github.com> --------- Co-authored-by: VictorWTang <33789988+VictorWTang@users.noreply.github.com>
1 parent 08df7ac commit f598b77

File tree

176 files changed

+269
-150
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

176 files changed

+269
-150
lines changed

.github/workflows/basic_checks.yml

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929
# detection output format: https://github.com/nexB/scancode-toolkit/releases/tag/v32.0.0
3030
# Need to update Mbed's scripts for the new format.
3131
run: |
32+
apt-get update
33+
apt-get install -y libxml2-dev libxslt1-dev
3234
pip install -U "scancode-toolkit<32.0" "click>=7,<8"
3335
3436
-
@@ -169,20 +171,16 @@ jobs:
169171
sudo apt-get update
170172
sudo apt-get install -y python3-venv
171173
172-
-
173-
name: install dependencies
174+
- name: Install Python packages
174175
run: |
175176
python3 -m venv venv
176177
source venv/bin/activate
177-
pip install -r tools/requirements.txt
178-
pip install -r tools/python/python_tests/requirements.txt
178+
pip install -e ./tools[unit-tests]
179179
180-
-
181-
name: Python Tests
180+
- name: Python Tests
182181
run: |
183182
source venv/bin/activate
184-
cd tools/python
185-
./run_python_tests.sh
183+
tools/run_python_tests.sh
186184
187185
check-cmsis-mcu-descriptions-matches-target-list:
188186
runs-on: ubuntu-latest
@@ -195,18 +193,18 @@ jobs:
195193
sudo apt-get update
196194
sudo apt-get install -y python3-venv
197195
198-
- name: install dependencies
196+
- name: Install Python packages
199197
run: |
200198
python3 -m venv venv
201199
source venv/bin/activate
202-
pip install -r tools/requirements.txt
200+
pip install -e ./tools
203201
204202
- name: Verify that cmsis_mcu_descriptions.json5 is in sync with targets.json5
205203
run: |
206204
source venv/bin/activate
207205
cd tools/python
208-
python -m mbed_tools.cli.main cmsis-mcu-descr find-unused
209-
python -m mbed_tools.cli.main cmsis-mcu-descr check-missing
206+
mbed-tools cmsis-mcu-descr find-unused
207+
mbed-tools cmsis-mcu-descr check-missing
210208
211209
212210
pin-validation:

.github/workflows/test_building_multiple_executables.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@ jobs:
1414
# Note: pip>=20.3 is needed to install dependencies of cysecuretools
1515
run: |
1616
python3 -m pip install --upgrade pip
17-
python3 -m pip install -r tools/requirements.txt
17+
18+
# Remove mbed-tools package that comes with the docker image, it conflicts with the one we want to install
19+
python3 -m pip uninstall -y mbed-tools
20+
21+
python3 -m pip install -e ./tools
22+
23+
# Also install cysecuretools which is not installed automatically
24+
python3 -m pip install 'cysecuretools~=6.0'
1825
1926
# Note: For this CI job we use MBED_CREATE_PYTHON_VENV=FALSE so that we can make sure
2027
# this mode works.

targets/TARGET_Cypress/scripts/mbed_set_post_build_cypress.cmake

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33

44
include(mbed_target_functions)
55

6+
# Make sure we have the python packages we need
7+
mbed_check_or_install_python_package(HAVE_PYTHON_CYSECURETOOLS cysecuretools "cysecuretools~=6.0")
8+
if(NOT HAVE_PYTHON_CYSECURETOOLS)
9+
message(FATAL_ERROR "Python package required for signing not found.")
10+
endif()
11+
612
#
713
# Merge Cortex-M4 HEX and a Cortex-M0 HEX.
814
#
@@ -63,8 +69,6 @@ macro(mbed_post_build_psoc6_sign_image
6369
)
6470
if("${cypress_psoc6_target}" STREQUAL "${MBED_TARGET}")
6571
function(mbed_post_build_function target)
66-
find_package(Python3)
67-
6872
set(post_build_command
6973
${Python3_EXECUTABLE} ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/PSOC6.py
7074
sign

targets/upload_method_cfg/SFE_ARTEMIS.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# 1. This board does not have an onboard debugger. You must use an external debugger, e.g. a PicoProbe
77
# or J-Link, if you wish to debug code.
88
# 2. Support for this device exists in PyOCD main branch but has not been released yet (as of Jun 2025).
9-
# To use PyOCD, you need to manually install it from the git repository by running (inside the Mbed OS venv):
9+
# This version will be used automatically by Mbed if the python venv is enabled. If not, you need to install it via:
1010
# pip install git+https://github.com/pyocd/pyOCD.git
1111

1212
set(UPLOAD_METHOD_DEFAULT NONE)

tools/cmake/mbed-run-greentea-test.in.cmake

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ set(MBEDHTRUN_ARGS --skip-flashing @MBED_HTRUN_ARGUMENTS@) # filled in by config
1414

1515
# Print out command
1616
string(REPLACE ";" " " MBEDHTRUN_ARGS_FOR_DISPLAY "${MBEDHTRUN_ARGS}")
17-
message("Executing: @Python3_EXECUTABLE@ -m mbed_host_tests.mbedhtrun ${MBEDHTRUN_ARGS_FOR_DISPLAY}")
17+
message("Executing: @mbedhtrun@ ${MBEDHTRUN_ARGS_FOR_DISPLAY}")
1818

1919
execute_process(
20-
COMMAND @Python3_EXECUTABLE@ -m mbed_host_tests.mbedhtrun ${MBEDHTRUN_ARGS}
21-
WORKING_DIRECTORY "@mbed-os_SOURCE_DIR@/tools/python"
20+
COMMAND @mbedhtrun@ ${MBEDHTRUN_ARGS}
2221
COMMAND_ERROR_IS_FATAL ANY)

tools/cmake/mbed_generate_configuration.cmake

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ if(MBED_NEED_TO_RECONFIGURE)
8282
# Make sure an old config file doesn't stick around
8383
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/mbed_config.cmake)
8484

85-
set(MBEDTOOLS_CONFIGURE_COMMAND ${Python3_EXECUTABLE}
86-
-m mbed_tools.cli.main
85+
set(MBEDTOOLS_CONFIGURE_COMMAND ${mbed_tools}
8786
-v -v # without at least -v, warnings (e.g. "you have tried to override a nonexistent parameter") do not get printed
8887
configure
8988
-t GCC_ARM # GCC_ARM is currently the only supported toolchain
@@ -96,7 +95,6 @@ if(MBED_NEED_TO_RECONFIGURE)
9695

9796
execute_process(
9897
COMMAND ${MBEDTOOLS_CONFIGURE_COMMAND}
99-
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../python
10098
RESULT_VARIABLE MBEDTOOLS_CONFIGURE_RESULT
10199
OUTPUT_VARIABLE MBEDTOOLS_CONFIGURE_OUTPUT
102100
ERROR_VARIABLE MBEDTOOLS_CONFIGURE_ERROR_OUTPUT
@@ -106,7 +104,7 @@ if(MBED_NEED_TO_RECONFIGURE)
106104

107105
if((NOT MBEDTOOLS_CONFIGURE_RESULT EQUAL 0) OR (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/mbed_config.cmake))
108106
string(JOIN " " MBEDTOOLS_COMMAND_SPC_SEP ${MBEDTOOLS_CONFIGURE_COMMAND})
109-
message(FATAL_ERROR "mbedtools configure failed! Cannot build this project. Command was cd ${CMAKE_CURRENT_LIST_DIR}/../python && ${MBEDTOOLS_COMMAND_SPC_SEP}")
107+
message(FATAL_ERROR "mbedtools configure failed! Cannot build this project. Command was ${MBEDTOOLS_COMMAND_SPC_SEP}")
110108
endif()
111109

112110
endif()

tools/cmake/mbed_python_interpreter.cmake

Lines changed: 104 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,64 @@
44
# CMake script to find the Python interpreter and either install or find
55
# Mbed's dependencies.
66

7+
include(CheckPythonPackage)
8+
79
option(MBED_CREATE_PYTHON_VENV "If true, Mbed OS will create its own virtual environment (venv) and install its Python packages there. This removes the need to manually install Python packages." TRUE)
810

11+
get_filename_component(MBED_CE_TOOLS_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
12+
913
if(MBED_CREATE_PYTHON_VENV)
1014
# Use the venv.
1115

1216
# Note: venv is stored in the source directory as it can be shared between all the build directories
1317
# (not target specific)
1418
set(MBED_VENV_LOCATION ${MBED_SOURCE_DIR}/venv)
1519
set(VENV_STAMP_FILE ${MBED_VENV_LOCATION}/mbed-venv.stamp)
16-
set(MBED_REQUIREMENTS_TXT_LOCATION "${CMAKE_CURRENT_LIST_DIR}/../requirements.txt")
20+
set(MBED_PYPROJECT_TOML_LOCATION "${MBED_CE_TOOLS_BASE_DIR}/pyproject.toml")
1721

18-
# Make it so modifying requirements.txt will trigger a reconfigure
19-
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MBED_REQUIREMENTS_TXT_LOCATION})
22+
# Make it so modifying pyproject.toml will trigger a reconfigure
23+
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MBED_PYPROJECT_TOML_LOCATION})
2024

21-
# Find Python3, using the venv if it already exists
22-
set (ENV{VIRTUAL_ENV} ${MBED_VENV_LOCATION})
23-
set (Python3_FIND_VIRTUALENV FIRST)
24-
find_package(Python3 REQUIRED COMPONENTS Interpreter)
25+
# Find Python3 (this will get the one in the venv if we already found it)
26+
set(ENV{VIRTUAL_ENV} ${MBED_VENV_LOCATION})
27+
set(Python3_FIND_VIRTUALENV FIRST)
28+
find_package(Python3 COMPONENTS Interpreter)
2529
include(CheckPythonPackage)
2630

2731
set(NEED_TO_CREATE_VENV FALSE)
2832
set(NEED_TO_INSTALL_PACKAGES FALSE)
29-
if(NOT EXISTS "${VENV_STAMP_FILE}")
33+
34+
# Special situation: if we have a cached interpreter location in the venv dir, but Python could be found,
35+
# this means that the venv was deleted or symlinks to a missing python install location.
36+
# So, use the system python and recreate it.
37+
if("${Python3_EXECUTABLE}" MATCHES "${MBED_VENV_LOCATION}" AND NOT Python3_FOUND)
38+
message(STATUS "Python venv deleted or unusable. Recreating using system Python...")
39+
40+
# Launch a new search for Python3
41+
unset(Python3_EXECUTABLE)
42+
unset(_Python3_EXECUTABLE CACHE)
43+
unset(_Python3_INTERPRETER_PROPERTIES CACHE)
44+
unset(_Python3_INTERPRETER_SIGNATURE CACHE)
45+
set (Python3_FIND_VIRTUALENV STANDARD)
46+
unset(ENV{VIRTUAL_ENV})
47+
find_package(Python3 REQUIRED COMPONENTS Interpreter)
48+
49+
# Reset venv configuration as above
50+
set(Python3_FIND_VIRTUALENV FIRST)
51+
set(ENV{VIRTUAL_ENV} ${MBED_VENV_LOCATION})
52+
3053
set(NEED_TO_CREATE_VENV TRUE)
3154
set(NEED_TO_INSTALL_PACKAGES TRUE)
32-
elseif("${MBED_REQUIREMENTS_TXT_LOCATION}" IS_NEWER_THAN "${VENV_STAMP_FILE}")
55+
elseif(NOT EXISTS "${VENV_STAMP_FILE}")
56+
set(NEED_TO_CREATE_VENV TRUE)
57+
set(NEED_TO_INSTALL_PACKAGES TRUE)
58+
elseif(NOT ("${Python3_EXECUTABLE}" MATCHES "${MBED_VENV_LOCATION}"))
59+
# Alternately if we think we have the venv but FindPython didn't use it, that likely means it's
60+
# missing or corrupted and we need to recreate it
61+
message(STATUS "Python venv deleted or unusable. Recreating using system Python...")
62+
set(NEED_TO_CREATE_VENV TRUE)
63+
set(NEED_TO_INSTALL_PACKAGES TRUE)
64+
elseif("${MBED_PYPROJECT_TOML_LOCATION}" IS_NEWER_THAN "${VENV_STAMP_FILE}")
3365
set(NEED_TO_INSTALL_PACKAGES TRUE)
3466
endif()
3567

@@ -47,7 +79,8 @@ if(MBED_CREATE_PYTHON_VENV)
4779
unset(_Python3_EXECUTABLE CACHE)
4880
unset(_Python3_INTERPRETER_PROPERTIES CACHE)
4981
unset(_Python3_INTERPRETER_SIGNATURE CACHE)
50-
## Launch a new search for Python3
82+
83+
## Launch a new search for Python3 in the venv
5184
find_package (Python3 REQUIRED COMPONENTS Interpreter)
5285
endif()
5386

@@ -59,41 +92,80 @@ if(MBED_CREATE_PYTHON_VENV)
5992
COMMAND_ERROR_IS_FATAL ANY
6093
)
6194
execute_process(
62-
COMMAND ${Python3_EXECUTABLE} -m pip install -r ${MBED_REQUIREMENTS_TXT_LOCATION}
95+
COMMAND ${Python3_EXECUTABLE} -m pip install -e ${MBED_CE_TOOLS_BASE_DIR}
6396
COMMAND_ERROR_IS_FATAL ANY
6497
)
6598

6699
message(STATUS "Mbed: venv created successfully")
67100
file(TOUCH ${VENV_STAMP_FILE})
68101
endif()
69102

70-
# We always have the memap deps with the venv
71-
set(HAVE_MEMAP_DEPS TRUE)
103+
# When using the venv, scripts will always be installed to the directory where Python itself is installed
104+
# (venv\Scripts on Windows, venv/bin on Linux/Mac)
105+
get_filename_component(PYTHON3_INTERP_DIR ${Python3_EXECUTABLE} DIRECTORY)
106+
set(PYTHON_SCRIPT_LOC_HINTS ${PYTHON3_INTERP_DIR})
72107

73108
else()
74109

75110
find_package(Python3 REQUIRED COMPONENTS Interpreter)
76-
include(CheckPythonPackage)
77111

112+
# The cmsis_mcu_descr module was written from scratch by Mbed CE.
113+
# So, this check will ensure that the user has installed the Mbed CE version of mbed_tools
114+
# and not the PyPI version (which we cannot update because it's owned by ARM)
115+
check_python_package(mbed_tools.cli.cmsis_mcu_descr HAVE_MBED_CE_TOOLS)
78116

79-
# Check python packages
80-
set(PYTHON_PACKAGES_TO_CHECK intelhex prettytable future jinja2)
81-
foreach(PACKAGE_NAME ${PYTHON_PACKAGES_TO_CHECK})
82-
string(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UCASE) # Ucase name needed for CMake variable
83-
string(TOLOWER ${PACKAGE_NAME} PACKAGE_NAME_LCASE) # Lcase name needed for import statement
84-
85-
check_python_package(${PACKAGE_NAME_LCASE} HAVE_PYTHON_${PACKAGE_NAME_UCASE})
86-
if(NOT HAVE_PYTHON_${PACKAGE_NAME_UCASE})
87-
message(WARNING "Missing Python dependency ${PACKAGE_NAME}")
88-
endif()
89-
endforeach()
90-
91-
# Check deps for memap
92-
if(Python3_FOUND AND HAVE_PYTHON_INTELHEX AND HAVE_PYTHON_PRETTYTABLE)
93-
set(HAVE_MEMAP_DEPS TRUE)
94-
else()
95-
set(HAVE_MEMAP_DEPS FALSE)
96-
message(STATUS "Missing Python dependencies (at least one of: python3, intelhex, prettytable) so the memory map cannot be printed")
117+
if(NOT HAVE_MBED_CE_TOOLS)
118+
message(FATAL_ERROR "Did not detect the Mbed CE Python tools installed into the python interpreter ${Python3_EXECUTABLE}. Install them with a command like: ${Python3_EXECUTABLE} -m pip install -e ${MBED_CE_TOOLS_BASE_DIR}")
97119
endif()
98120

121+
# For now, don't supply any hints and assume that the script install dir is correctly on PATH
122+
set(PYTHON_SCRIPT_LOC_HINTS)
99123
endif()
124+
125+
# Find scripts provided by the Python package
126+
find_program(mbed_tools
127+
NAMES mbed-tools
128+
HINTS ${PYTHON_SCRIPT_LOC_HINTS}
129+
DOC "Path to mbed-tools Python script."
130+
REQUIRED)
131+
132+
find_program(mbedhtrun
133+
NAMES mbedhtrun
134+
HINTS ${PYTHON_SCRIPT_LOC_HINTS}
135+
DOC "Path to mbedhtrun Python script."
136+
REQUIRED)
137+
138+
find_program(memap
139+
NAMES memap
140+
HINTS ${PYTHON_SCRIPT_LOC_HINTS}
141+
DOC "Path to memap Python script."
142+
REQUIRED)
143+
144+
#
145+
# Utility function to check for a Python package with the given import name.
146+
# If the package is not found and the Mbed venv is in use,
147+
# then the package will be installed by passing PACKAGE_INSTALL_CONSTRAINT to Pip.
148+
# If the install fails or the venv is not being used, FOUND_VAR will be set to false.
149+
#
150+
function(mbed_check_or_install_python_package FOUND_VAR PACKAGE_IMPORT_NAME PACKAGE_INSTALL_CONSTRAINT)
151+
check_python_package(${PACKAGE_IMPORT_NAME} ${FOUND_VAR})
152+
153+
if(NOT ${FOUND_VAR})
154+
# If we are using the Mbed venv, we can install the package automatically.
155+
if(MBED_CREATE_PYTHON_VENV)
156+
message(STATUS "Mbed: Installing ${PACKAGE_INSTALL_CONSTRAINT} into Mbed's Python virtualenv")
157+
execute_process(
158+
COMMAND ${Python3_EXECUTABLE} -m pip install ${PACKAGE_INSTALL_CONSTRAINT}
159+
RESULT_VARIABLE PIP_INSTALL_RESULT
160+
)
161+
if(NOT PIP_INSTALL_RESULT EQUAL 0)
162+
message(WARNING "Installation of ${PACKAGE_INSTALL_CONSTRAINT} via pip failed.")
163+
else()
164+
# Redo the check to confirm it's installed
165+
check_python_package(${PACKAGE_IMPORT_NAME} ${FOUND_VAR})
166+
endif()
167+
else()
168+
message(WARNING "Mbed: ${PACKAGE_IMPORT_NAME} cannot be installed because the Mbed virtualenv is not being used. Please install ${PACKAGE_INSTALL_CONSTRAINT} into Mbed's Python interpeter manually.")
169+
endif()
170+
endif()
171+
endfunction(mbed_check_or_install_python_package)

tools/cmake/mbed_target_functions.cmake

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ function(mbed_generate_map_file target)
6565
TARGET
6666
${target}
6767
POST_BUILD
68-
COMMAND ${Python3_EXECUTABLE} -m memap.memap
69-
-t ${MBED_TOOLCHAIN} ${CMAKE_CURRENT_BINARY_DIR}/${target}${CMAKE_EXECUTABLE_SUFFIX}.map
68+
COMMAND ${memap}
69+
-t ${MBED_TOOLCHAIN} ${target}${CMAKE_EXECUTABLE_SUFFIX}.map
7070
--depth ${MBED_MEMAP_DEPTH}
7171
${MEMORY_BANKS_ARG}
7272
WORKING_DIRECTORY
73-
${mbed-os_SOURCE_DIR}/tools/python
73+
${CMAKE_CURRENT_BINARY_DIR}
7474
)
7575

7676
# generate json file
@@ -79,14 +79,14 @@ function(mbed_generate_map_file target)
7979
TARGET
8080
${target}
8181
POST_BUILD
82-
COMMAND ${Python3_EXECUTABLE} -m memap.memap
83-
-t ${MBED_TOOLCHAIN} ${CMAKE_CURRENT_BINARY_DIR}/${target}${CMAKE_EXECUTABLE_SUFFIX}.map
82+
COMMAND ${memap}
83+
-t ${MBED_TOOLCHAIN} ${target}${CMAKE_EXECUTABLE_SUFFIX}.map
8484
--depth ${MBED_MEMAP_DEPTH}
8585
-e json
86-
-o ${CMAKE_CURRENT_BINARY_DIR}/${target}${CMAKE_EXECUTABLE_SUFFIX}.memmap.json
86+
-o ${target}${CMAKE_EXECUTABLE_SUFFIX}.memmap.json
8787
${MEMORY_BANKS_ARG}
8888
WORKING_DIRECTORY
89-
${mbed-os_SOURCE_DIR}/tools/python
89+
${CMAKE_CURRENT_BINARY_DIR}
9090
)
9191
endif()
9292

@@ -96,14 +96,14 @@ function(mbed_generate_map_file target)
9696
TARGET
9797
${target}
9898
POST_BUILD
99-
COMMAND ${Python3_EXECUTABLE} -m memap.memap
100-
-t ${MBED_TOOLCHAIN} ${CMAKE_CURRENT_BINARY_DIR}/${target}${CMAKE_EXECUTABLE_SUFFIX}.map
99+
COMMAND ${memap}
100+
-t ${MBED_TOOLCHAIN} ${target}${CMAKE_EXECUTABLE_SUFFIX}.map
101101
--depth ${MBED_MEMAP_DEPTH}
102102
-e html
103-
-o ${CMAKE_CURRENT_BINARY_DIR}/${target}${CMAKE_EXECUTABLE_SUFFIX}.memmap.html
103+
-o ${target}${CMAKE_EXECUTABLE_SUFFIX}.memmap.html
104104
${MEMORY_BANKS_ARG}
105105
WORKING_DIRECTORY
106-
${mbed-os_SOURCE_DIR}/tools/python
106+
${CMAKE_CURRENT_BINARY_DIR}
107107
)
108108
endif()
109109
endfunction()

0 commit comments

Comments
 (0)