-
Notifications
You must be signed in to change notification settings - Fork 23
Description
Pybricksdev Package Import Bug
Issue Summary
Pybricksdev 2.3.1 fails to properly bundle Python packages with __init__.py files when uploading scripts to Pybricks devices via BLE.
Environment
- pybricksdev version: 2.3.1
- pybricks version: 3.6.1
- Python version: 3.14
- OS: Linux (Fedora 43)
Problem Description
When running scripts that import from local packages (e.g., from MyFramework.Hardware import ...), pybricksdev:
- ✅ Correctly detects the dependencies (shown in output)
- ✅ Successfully uploads the compiled files
- ❌ Fails at runtime with
ImportError: no module named 'MyFramework.Hardware'
Affected Files
All my scripts that import from packages fail:
Test.py- fails withImportError: no module named 'MyFramework.Hardware'RunLaunch1.py- fails withImportError: no module named 'MyFramework.Hardware'main.py- fails withImportError: no module named 'MyFramework'
Package Structure
The project has proper Python package structure:
MyFramework/__init__.pyexistsMyFramework/Hardware/__init__.pyexistsTeamCode/__init__.pyexists- Total: 13
__init__.pyfiles in MyFramework, 12 in TeamCode
Example Error Output
Searching for 1200...
{'MyFramework.Hardware', 'TeamCode', 'TeamCode.Launches'}
{'MyFramework.Hardware', 'TeamCode', 'TeamCode.Launches'}
100%|██████████| 402/402 [00:00<00:00, 2.79kB/s]
Traceback (most recent call last):
File "RunLaunch1.py", line 1, in <module>
ImportError: no module named 'MyFramework.Hardware'
Root Cause Analysis
Key Finding from Release Notes:
According to the v2.3.1 release notes, a major change was made:
"Changed
pybricksdev.compile.compile_multi_file()to usempy-toolto find imports instead of Python'sModuleFinder."
This change from ModuleFinder to mpy-tool appears to have introduced a regression where packages with __init__.py files are no longer properly bundled.
Technical Details:
From pybricksdev/compile.py, the compile_multi_file function docstring states:
"On the hub, all dependencies behave as independent modules. Any (leading) dots will be considered to be part of the module name. As such, relative or "package" imports will work, but there is no handling of init, etc."
This indicates that pybricksdev doesn't properly handle Python package structure with __init__.py files, and the switch to mpy-tool may have made this worse.
The Bug:
In _compile_module_and_get_imports() (line 182 of compile.py):
module_path = os.path.join(*module_name.split(".")) + ".py"When pybricksdev encounters a package import like MyFramework.Hardware, it:
- Creates path:
MyFramework/Hardware.py(line 182) - Tries to compile this file, which doesn't exist
- Gets
FileNotFoundErrorand adds it tonot_found_modules - Never checks for
MyFramework/Hardware/__init__.py(the actual package file) - Never compiles parent package
__init__.pyfiles (MyFramework/__init__.py)
The Fix Needed:
The code should check for package structure:
- First try:
MyFramework/Hardware.py(module file) - If not found, try:
MyFramework/Hardware/__init__.py(package) - Also compile parent packages:
MyFramework/__init__.py
Workaround
Scripts that only use pybricks modules (no local packages) work correctly:
from pybricks.pupdevices import Motor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase
# This works fineExpected Behavior
Pybricksdev should:
- Detect package imports (e.g.,
from MyFramework.Hardware import ...) - Compile the package's
__init__.pyfile - Compile all subpackage
__init__.pyfiles - Bundle all compiled files correctly
- Allow the script to run on the device
Steps to Reproduce
- Create a Python package with
__init__.pyfiles - Create a script that imports from the package
- Run:
pybricksdev run ble --name <device> <script>.py - Observe the
ImportErroron the device
Version Comparison Testing
Tested multiple versions of pybricksdev:
Version 2.0.0, 2.1.0, 2.2.0 (used ModuleFinder):
- ✅ Bundle packages correctly (81.7k uploaded)
- ❌ Fail with
NotImplementedError: relative import - Issue: MicroPython on device doesn't support relative imports (e.g.,
from .HardwareProvider import) - Note: These versions used Python's
ModuleFinderwhich handled package structure better
Version 2.3.1 (current, uses mpy-tool):
- ❌ Doesn't bundle packages (only 402 bytes uploaded)
- ❌ Fails with
ImportError: no module named 'MyFramework.Hardware' - Issue: Package structure not recognized/bundled
- Note: This version switched to
mpy-toolwhich appears to have broken package bundling
Additional Notes
- Local imports work fine (tested with
python3 -c "from MyFramework.Hardware import ...") - The issue is specific to how pybricksdev bundles files for device upload
- This affects all scripts using package imports, not just specific files
- There are TWO separate issues:
- Version 2.3.1: Packages not bundled at all
- Versions 2.0.0-2.2.0: Packages bundled but relative imports not supported by MicroPython