KMKfw / kmk_firmware

Clackety Keyboards Powered by Python
https://kmkfw.zulipchat.com
Other
1.39k stars 474 forks source link

[BUG] deinit() method is interrupted by auto-reload #750

Open regicidalplutophage opened 1 year ago

regicidalplutophage commented 1 year ago

Describe the bug Auto-reload stops execution abruptly: deinit() is being interrupted.

To Reproduce A debug statement has been added to deinit():

    def deinit(self) -> None:
        for module in self.modules:
            try:
                module.deinit(self)
            except Exception as err:
                if debug.enabled:
                    debug(f'Error in {module}.deinit: {err}')
        for ext in self.extensions:
            try:
                ext.deinit(self.sandbox)
            except Exception as err:
                if debug.enabled:
                    debug(f'Error in {ext}.deinit: {err}')       
        debug('Deinitialized!')

It never shows up in serial upon autoreload:

main.py output:
Starting
579768 kmk.kmk_keyboard: Unexpected error: cleaning up

Code stopped by auto-reload. Reloading soon.

Other functions that are supposed to be called during deinit() never get called.

Expected behavior Stopping execution with ctrl+c works as it should:

main.py output:
Starting
486835 kmk.kmk_keyboard: Unexpected error: cleaning up
486841 kmk.kmk_keyboard: Deinitialized!
Traceback (most recent call last):
  File "main.py", line 202, in <module>
  File "kmk/kmk_keyboard.py", line 523, in go
  File "kmk/kmk_keyboard.py", line 607, in _main_loop
  File "kmk/kmk_keyboard.py", line 470, in after_hid_send
  File "kmk/extensions/RGB.py", line 244, in after_hid_send
  File "kmk/extensions/RGB.py", line 432, in animate
KeyboardInterrupt:

Code done running.

Autoreload should function similarly.

Debug output If applicable, add debug output from the serial console to help explain your problem.

Additional context Add any other context about the problem here.

xs5871 commented 1 year ago

I've looked into it and that's just how the supervisor does things. On an auto-reload event, it'll just drop everything. atexit doesn't help, because it requires a "successfull" exit of the vm. You'd have to take that complaint upstream to Circuitpython.

Interesting note:It still works if you touch something in the filesystem. Only actual file content writes make the supervisor kill the VM without notice, it seems like.

grasegger commented 1 year ago

Maybe a deinit py file could help?

https://docs.circuitpython.org/en/latest/shared-bindings/supervisor/index.html#supervisor.set_next_code_file

On the first go call kmk could set a file within the kmk dir to be run next. On autoreload that deinit file reads the code.py and grabs the keyboard extensions to execute deinit on all of them. Finally it enqueues the code.py to be executet and calls supervisor.reload()

xs5871 commented 1 year ago

That wouldn't work. You have to effectively re-initialize the entire keyboard in order to find out what all the extension and modules are. That would defeat the purpose of a deinit.