Skip to content

Pybricksdev Package Import Bug #131

@amir-yogev-gh

Description

@amir-yogev-gh

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:

  1. ✅ Correctly detects the dependencies (shown in output)
  2. ✅ Successfully uploads the compiled files
  3. ❌ Fails at runtime with ImportError: no module named 'MyFramework.Hardware'

Affected Files

All my scripts that import from packages fail:

  • Test.py - fails with ImportError: no module named 'MyFramework.Hardware'
  • RunLaunch1.py - fails with ImportError: no module named 'MyFramework.Hardware'
  • main.py - fails with ImportError: no module named 'MyFramework'

Package Structure

The project has proper Python package structure:

  • MyFramework/__init__.py exists
  • MyFramework/Hardware/__init__.py exists
  • TeamCode/__init__.py exists
  • Total: 13 __init__.py files 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 use mpy-tool to find imports instead of Python's ModuleFinder."

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:

  1. Creates path: MyFramework/Hardware.py (line 182)
  2. Tries to compile this file, which doesn't exist
  3. Gets FileNotFoundError and adds it to not_found_modules
  4. Never checks for MyFramework/Hardware/__init__.py (the actual package file)
  5. Never compiles parent package __init__.py files (MyFramework/__init__.py)

The Fix Needed:
The code should check for package structure:

  1. First try: MyFramework/Hardware.py (module file)
  2. If not found, try: MyFramework/Hardware/__init__.py (package)
  3. 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 fine

Expected Behavior

Pybricksdev should:

  1. Detect package imports (e.g., from MyFramework.Hardware import ...)
  2. Compile the package's __init__.py file
  3. Compile all subpackage __init__.py files
  4. Bundle all compiled files correctly
  5. Allow the script to run on the device

Steps to Reproduce

  1. Create a Python package with __init__.py files
  2. Create a script that imports from the package
  3. Run: pybricksdev run ble --name <device> <script>.py
  4. Observe the ImportError on 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 ModuleFinder which 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-tool which 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:
    1. Version 2.3.1: Packages not bundled at all
    2. Versions 2.0.0-2.2.0: Packages bundled but relative imports not supported by MicroPython

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions