-
-
Notifications
You must be signed in to change notification settings - Fork 8.4k
Fix importing of frozen modules (fixes #2322) #5057
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In CircuitPython, we use |
To retain existing behaviour |
You are right, on devices (I tested only esp8266/esp32) frozen modules take precedence because sys.path always has I did not consider backwards compatibility up until now (not intentionally) but wonder if it's good that frozen modules take precedence. If frozen modules come after the current directory in search order, it would allow overriding frozen code (e.g. for testing/hot-fixing) without having to rebuild/reflash the firmware, while the other way around this is not possible. On the unix port specifically, it feels a bit more aligned with CPython (see my tests documented in #3509) and . Would it make sense to have a different default search order on different ports? e.g. have the unix port search frozen modules last (it would still be before builtins), while bare-metal ports search them first? (Would not be my choice, but maybe it's an option?) (Btw, I like |
We use that idea to be able to override the modules we've frozen for RAM-space-saving. CircuitPython's default To emphasize, our primary use for frozen code has been to save RAM on low-RAM boards. We don't bother on boards with more RAM. We haven't had the need yet to freeze mandatory initialization code. If we needed to do that we might consider adding another virtual directory that came earlier in |
It can be done by having the following in import sys
sys.path.append(sys.path.pop(0)) |
@dhalbert do you still use |
@dhalbert any update on your experience with the Are you aware of any limitations/issues that could be nice to address, or does it work as expected? If so and with your permission, I would actually propose using the code as it is in CircuitPython (except perhaps removing the double check as mentioned here adafruit#235 (review)). I could update this PR accordingly. |
This prevents timer leakage on builds without pwmio. Fixes micropython#5057
ebe9854
to
1d2135b
Compare
I have now rebased this branch on the latest master and improved the change:
I also tested this:
Update: I fixed some build failures:
|
This change "moves" frozen modules into a virtual directory called ".frozen". This allows controlling the search order for frozen modules, relative to other directories. Before this change, frozen modules were found via the current directory (i.e. the "" entry in sys.path). However, when a file is executed from the command line the first entry in sys.path (which is normally the empty string ""), is replaced by the base path of the executing file (correct behaviour as per CPython). This made loading frozen modules fail. With this change, frozen modules have their own entry in sys.path, which also allows the user to control the order of search when looking for frozen modules. By default, the virtual ".frozen" directory is the last entry in sys.path (i.e. it gets searched last). Fixes issue micropython#2322.
The fix ensures main.c is included when searching for qstrs like MP_QSTR_Foo. This requires including tinyusb header files during the qstr preprocessing step and also requires setting the MICROPY_MODULE_FROZEN compile definition (this is for the step that generates qstr.i.last - during the later compile stage the define is correctly set).
1d2135b
to
2918097
Compare
Any update on this? |
I apologize for not replying to this earlier. I subscribe to all MicroPython repo notifications, and this slipped by. We still use the same path: |
I think A possible alternative is to use For example if I'd frozen foo/bar/baz.py, the current behaviour is that I can do
With this PR, I'd now append |
Superseded by #8079, which was merged, see 86394f7 Thanks @wnienhaus for this initial implementation! |
This aims to fix how frozen modules are handled/identified/distinguished.
It prefixes all frozen files with a "virtual directory", which is then added to sys.path (as opposed to before, where frozen files were found via the
''
current directory). This is essentially option #2 suggested in issue #2322.The virtual directory is called
{frozen}
, a name chosen to be highly unlikely to ever be a real directory name. (The:frozen:
name suggested in issue #2322 was not suitable, because the colon (:) character is used as the path separator in the string representation of sys.path)While the initial fix for the unix port was quite easy (prefix all frozen filenames with
{frozen}/
and add{frozen}
as the last entry in the default sys.path), it ended up being a bit of a rabbit hole, requiring more changes/fixes in the test suite and other ports, even revealing a potential bug which I will report/fix separately.One issue I am not 100% happy about: some platforms use
pyexec_frozen_module
to run frozen py files on boot up. This function does not search paths defined in sys.path, and arguably shouldn't need to, since it uses the arrays with frozen files/strings and essentially "knows" where to find frozen files/modules. But due to the prefix of filenames in the array, it currently needs to be passed the prefix too. Changing this, so the function (and those it calls) internally skip over the prefix while matching file names is another rabbit hole, which I haven't yet gone into. So for now,pyexec_frozen_module
must be given filenames with the prefix. I am happy for thoughts around this - maybe there is a nicer way to solve this.