Skip to content

Rework error handling#813

Open
dmamelin wants to merge 9 commits intocustom-components:masterfrom
dmamelin:rework-error-handling
Open

Rework error handling#813
dmamelin wants to merge 9 commits intocustom-components:masterfrom
dmamelin:rework-error-handling

Conversation

@dmamelin
Copy link
Contributor

@dmamelin dmamelin commented Feb 13, 2026

This is a major change in Pyscript core. Please review it very carefully, especially ast_try, ast_raise, and EvalFunc.call.
Originally this was one large change, but I split it into smaller commits to make it easier to review. Each commit is consistent. Everything works and the tests pass.

Main idea:

  • we shouldn't try to reimplement python’s exception system - we just need to avoid interfering with it
  • exceptions should not be caught in the core and passed around; they should be handled at entry points
  • exceptions should always be raised normally, and only wrapped in finally where needed to restore context
  • formatting user messages should be separated from exception handling

Exception logging:

Initially, I planned to keep the old behavior and show only a single frame where the error occurred, but I ended up implementing a full traceback 🙂

#modules/mod_test.py
def problem():
    return 0 / 0

async def no_problem(callback):
    return 0 + callback()

#test.py
from mod_test import no_problem, problem

def func1(x):
    return x + func2(x)

@pyscript_compile
async def func2(x):
    return x + await no_problem(func3)

def func3():
    return 3 + problem()

@time_trigger
def start():
    try:
        func1(1)
    except ZeroDivisionError:
        del x

#console output: 
2026-02-13 02:38:36.622 ERROR (MainThread) [custom_components.pyscript.file.test.start]
  File "/config/pyscript/test.py", line 22, in file.test.start
    func1(1)
    ~~~~~^^^
  File "/config/pyscript/test.py", line 7, in func1
    return x + func2(x)
               ~~~~~^^^
  File "/config/pyscript/test.py", line 12, in func2
    return x + await no_problem(func3)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/pyscript/modules/mod_test.py", line 9, in no_problem
    return 0 + callback()
               ~~~~~~~~^^
  File "/config/pyscript/test.py", line 16, in func3
    return 3 + problem()
               ~~~~~~~^^
  File "/config/pyscript/modules/mod_test.py", line 5, in problem
    return 0 / 0
           ~~^~~
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

  File "/config/custom_components/pyscript/trigger.py", line 1394, in do_func_call
    await ast_ctx.call_func(func, None, **kwargs)
  File "/config/pyscript/test.py", line 24, in start
    del x
NameError: name 'x' is not defined

EvalExceptionFormatter

  • standard traceback mechanisms are used, with adjustments for user code
  • iterates over the traceback and extracts all necessary data from local variables. lineno and col_offset are taken from ast.expr / ast.stmt, which results in more precise error locations
  • it isn't perfect, but it's not core functionality and doesn't affect code execution. It can be refined over time
  • there are some quirks in the core regarding context names, file names, and their source text. These are handled in formatter, but I plan to clean this up properly in the future

Tests:

There are many changes because the new mechanism closely matches native python behavior and is more precise.
Please pay attention to the last commit with exception chaining - it tests pyscript using pyscript itself.

@ALERTua
Copy link
Contributor

ALERTua commented Feb 13, 2026

you are the best!

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