why bge waste the(otherwise) perfect debug of python?

what is the sense of have an error and continue to run having then (ususally)a bunch of other errors , so the only way to know if the game is bugged is notice a strange “lag”, then press “esc” and see the consolle "wasted"where probably you cannot see more the first error that is the unique that count?i mean simply why bge not stop itself if python raise an exception? the best will be stop immediately any scrtipt but i gues can be hard .sufficient and easy should be block the next logic-tic.i normally run everithing below a try / except : bge.logic.endGame() raise, as workaround.will be possible and better do it as default? inverting the actual behaviour?ie, error unexpected = crasherror expected = add try/except manually

Stopping or continuing until it really breaks
I remember early compiler stopped at the first error they discovered. This was pretty annoying to see (after 20minutes of building) that there is a ‘;’ missing.

There are a lot of situation where the followup errors made no sense. But there are quite a lot of situations where you can fix several errors before running the compile again.

Game flow
At the level of game flow there are no such critical errors that the system can’t recover. When the system can recover there is no reason to stop at each little error.

Conflicting Preferences
I would not like to have my game stopped all the time by default. There are situations when I want it. There are even situations when I want my game to stop after running a single frame regardless of errors. But these are really rare cases.

Ending the game session at each single uncaught error might be fine to you, but would prevent me from following my development style.
The way it is now does not disturb you as you can already change it.

Python error handling
The Python default error handler will catch the errors that are not dealt with by your custom (or third party) code. This means the error gets pushed up until the top of the call stack is reached.

The default error handler prints the stack trace + error message and ends the python session.

A pure python application ends. A python process terminates.

The BGE is no python application. The current python process ends (the current controller execution). That is what the BGE is waiting for … the controller’s execution end. The outcome of the controller is … whatever the code did before the error. So the game session continues with the further steps.

Default error handler
As you seem to like to exit the game I suggest to define your own Python default error handler. I haven’t done that before, but I know it is possible. The Python documentation should help you there. This way you do not need to surround your code with explicit try/except.

Debugging
Btw. debugging does not mean to stop the process. It suspends it to allow you to analyse the situation (check process flow, check states). That is not possible at stopped processes.

My solution to this entire problem is two-fold:

  1. A logging tool. I use the python logger module instead of printing messages.
  2. A custom scheduler.

Instead of having an object running always->python, I have it running init->python, and register itself with a scheduler. The scheduler I wrote has the option to either exit on the first error, or to not. Either way, errors are saved in a file because of the logging tool.

Advantages:
- Aways get error info, even if the game engine crashed, or quit, or something else covered the terminal massively

  • Stops immediately when testing, but you can easily disable this when you distribute it to people.

Disadvantages:

  • Requires a scheduler which (may) add (a very small amount) of overhead.
  • Slightly different program design required
  • Effort to set up initially.

If you want to see the scheduler, have a look at the code for CaveX16

I’m like the OP in that I prefer to have execution stop immediately if there is an unhandled exception. Thankfully, Python lets you easily define your own exception-handler that is called as soon as an unhandled exception is raised. Here’s something similar to what I use:

import bge
import sys

def exception_handler(type_, value, tb):
    # print the exception
    import traceback
    traceback.print_exception(type_, value, tb)

    # start the python debugger
    # (remove these two lines if you don't want to use pdb)
    import pdb
    pdb.pm()
    
    # stop the game engine after you finish with pdb
    bge.logic.endGame()

# tell Python to use your function
sys.excepthook = exception_handler

You only need to execute this code once at the start of your game. Note that I like to immediately start a Python debugger session so I can quickly see the stack frame the error occurred in and view the contents of any attributes. This will make your game freeze while you use the debugger in the console window. You can remove the lines with pdb if you prefer not to do this.

maybe, just because it work so from years , the actual behaviour can be the default one .but having the choice with one click to choose a behaviour a bit more debug oriented.the actual one probably* work well for a game already debugged more or less ended.for me is no annoyng have a game(my game) crashing “each time” .each time that crash mean there is an error, (at least i can know)and normally the error need to be solved , no matter if is just “:” that lack . otherwise my game is broken anyway just continue to run broken …

i guess to know more or less this way.

ie, sort of: one empty spawner that add, register all objects, and then call all
afaik in this way you lost the ability to use cont.activate().
plus you have to clean the lists…
in some games is perfectly fine ,you had more control of game, maybe more margin for optimization.
but in other games seem one thing “excessive” …

:evilgrin::cool::RocknRoll:
THANKS!

i had removed the lines with pdb “as suggested” (otherwise it freeze … and i not know what do :))
and it work very well.
with it i can just add an empty with one script , and remove the need of put “try/except everywhere”.

plus i made some other experiment, the mode 3 print(almost) only the first error (+ some contoller info that anyway occupe ever only one line so the consolle still meanly almost perfectly clean)

mode 0 print(almost) nothing
mode 1 is the actual mode
mode 2 is the equivalent of put try except in each controller
mode 3 print(almost) only the fist error


"""
### code originally written by Mobious
# thanks a lot !


import sys
def exception_handler(type_, value, tb):
    # print the exception
    import traceback
    traceback.print_exception(type_, value, tb)


    # start the python debugger
    # (remove these two lines if you don't want to use pdb)
    #import pdb
    #pdb.pm()


    # stop the game engine after you finish with pdb
    bge.logic.endGame()


# tell Python to use your function
sys.excepthook = exception_handler
"""






import bge
import sys
import traceback


_error_raised = False
_DEFAULT_MODE = 3


def _debug_0(type_, value, tb):
    pass


def _debug_1(type_, value, tb):
    traceback.print_exception(type_, value, tb)


def _debug_2(type_, value, tb):
    traceback.print_exception(type_, value, tb)
    bge.logic.endGame()


def _debug_3(type_, value, tb):
    global _error_raised
    if _error_raised:
        return
    _error_raised = True
    traceback.print_exception(type_, value, tb)
    bge.logic.endGame()








def set_mode(mode=_DEFAULT_MODE):
    if mode == 0:
        exception_handler = _debug_0
    elif mode == 1:
        exception_handler = _debug_1
    elif mode == 2:
        exception_handler = _debug_2
    elif mode == 3:
        exception_handler = _debug_3
    sys.excepthook = exception_handler






set_mode(3)