Skip to content

sagas/mpy: Use main module name instead of __main__.#2367

Merged
laurensvalk merged 3 commits intomasterfrom
__main__
Mar 19, 2026
Merged

sagas/mpy: Use main module name instead of __main__.#2367
laurensvalk merged 3 commits intomasterfrom
__main__

Conversation

@laurensvalk
Copy link
Member

@laurensvalk laurensvalk commented Mar 17, 2026

This is separate from Python's __main__ mechanism, so we shouldn't be manually renaming things to __main__ here.

This also makes file names show correctly on EV3.

See pybricks/support#2364

This is separate from Python's __main__ mechanism, so we shouldn't be manually renaming things to __main__ here.

This also makes file names show correctly on EV3.

See pybricks/support#2364
@dlech
Copy link
Member

dlech commented Mar 17, 2026

Is there any version of the firmware that checks for the name __main__.mpy? Or do all versions of the firmware just use the first file as the entry point?

@laurensvalk
Copy link
Member Author

Thanks. Hmm, because we do show the update warning, my brain was at this one:

We can work around this by making a file literally named __main__.py if we ever need to do a git bisect and run a program on the hub.

Originally posted by @dlech in #2364

But that was about the intermediate versions, and we probably still do need the following:

@dlech indicated we can just have Pybricks Code check the protocol version to use __main__ for older firmware. I'm all for it 👍

Originally posted by @laurensvalk in #2364

But we don't have access to the currently active version in that module, so needs some more work.

@dlech
Copy link
Member

dlech commented Mar 17, 2026

Should do the trick:

    const fwVersion = yield* select((s: RootState) => s.hub.deviceFirmwareVersion);

If it is empty string (because not connected to a hub), then use the "new" way since we are just doing compile check and not downloading.

@dlech
Copy link
Member

dlech commented Mar 17, 2026

Or if we want to be fancy, we could add a new state flag like useLegacyStartUserProgram that is useLegacyDunderMain.

@laurensvalk
Copy link
Member Author

Should do the trick:

Heh, I started that way but thought you'd call me out on that 😄

Or if we want to be fancy, we could add a new state flag like useLegacyStartUserProgram that is useLegacyDunderMain.

So that is indeed what I tried. I'm always a little puzzled doing this, as there seem to be so many placed to add a single boolean condition.

@dlech
Copy link
Member

dlech commented Mar 17, 2026

as there seem to be so many places to add a single boolean condition.

I think it would be fine to do:

const useLegacyMainModule = yield* select((s: RootState) => s.hub.useLegacyMainModule);

In the mpy saga so that we don't have to add it as a parameter to the action.

@laurensvalk
Copy link
Member Author

Done!

src/mpy/sagas.ts Outdated
Comment on lines +136 to +138
const mainPyPath = useLegacyMainModule
? '__main__.py'
: metadata.path ?? '__main__.py';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the change to the legacy behavior intentional?

Before, the behavior was always metadata.path ?? '__main__.py', but now the legacy behavior will be only '__main__.py'.

I would expect useLegacyMainModule to only affect mainPyName in order to preserve the old behavior.

Needed for backwards compatibility. Older firmware always look for __main__.

See pybricks/support#2364
@laurensvalk
Copy link
Member Author

laurensvalk commented Mar 19, 2026

Thanks, this was a little rushed. Updated now.


Perhaps separately, there's something off with the BLE/USB actions, e.g.:

/*
 * Returns number of available slots or 0 for slots not supported.
 */
const numOfSlots: Reducer<number> = (state = 0, action) => {
    if (blePybricksServiceDidReceiveHubCapabilities.matches(action)) {
        return action.numOfSlots;
    }

    return state;
};

This one works because the usb saga dispatches a ble action so blePybricksServiceDidReceiveHubCapabilities works, but that is not the case for bleDIServiceDidReceiveSoftwareRevision, which is only called from BLE code. The USB code calls a separate USB-namespaced action.

Maybe ble-device-info-service could be device-info-service and work with both. Likewise ble-pybricks-service and pybricks-service so USB doesn't have to call blePybricksServiceDidReceiveHubCapabilities like it currently does.

So currently, if you connect a Prime Hub with stable firmware and then an EV3 with newer firmware, the flags are bad. If you restart Pybricks Code, it only works because the various legacy flags default to false.

@laurensvalk
Copy link
Member Author

Added a commit to simply also match against the USB action. It looks like we were already doing that for firmware revisions and just missed it for software revisions.

We were already doing something similar for USB firmware revision, but this was missed for software revision.
@dlech
Copy link
Member

dlech commented Mar 19, 2026

it only works because the various legacy flags default to false.

Good catch. This is probably why we didn't notice before.

All looks good to me now.

@laurensvalk laurensvalk merged commit 660a796 into master Mar 19, 2026
2 checks passed
@laurensvalk laurensvalk deleted the __main__ branch March 19, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants