Jump to content
Official BF Editor Forums
Sign in to follow this  
ScoutStrike

Traceback

Recommended Posts

Is it just me, or is traceback.print_exc() broken in BF2?

Using print_exc(limit=0) gives:

debug: exception start
Traceback (most recent call last):
NameError: global name 'dostuff' is not defined
debug: exception end

This seems fine, no files/lines are reported (as requested with limit=0).

But then, using print_exc() gives:

debug: exception start
Traceback (most recent call last):
 File "mods/scout_edit/python\game\debug.py", line 29, in chatmessage

... then nothing, no 'debug: exception end' or other info

Anything after the print_exc() doesn't get executed (exception inside the exception handling? <_<).

For comparison, the python shell reports something like this:

Traceback (most recent call last):
 File "<pyshell#2>", line 2, in <module>
except: foo=sys.exc_info()
NameError: name 'sys' is not defined

Edit - Oh, my test script if you're interested, the function dostuff() doesn't exist:

def chatmessage(playerindex, text, channel, flags):
try:
	another_function()

except:
	sys.stderr.write("debug: exception start\n")
	traceback.print_exc()
	sys.stderr.write("debug: exception end\n")


def another_function():
dostuff()

As you can see it should report 2 stacks, one for chatmessage, and one for another_function.

Edit #2 - Well I figured it out.

The traceback.print_exc() function uses the linecache.getline(file, line) function internally, to display the line of code causing the error. And BF2 throws an exception if I try to use this function manually. I can read the file with a standard file.readline(), but linecache.getline() doesn't work. Great, time for a custom exception printer then. :mellow:

Edited by ScoutStrike

Share this post


Link to post
Share on other sites

Since unhandled exceptions call the same broken traceback.print_exc() function, this custom function might be useful for debugging. :)

import sys
import traceback

def print_exc():
exc_type, exc_value, exc_traceback = sys.exc_info()

sys.stderr.write("Traceback (most recent call last):")

while exc_traceback:
	# current stack
	exc_file = str(exc_traceback.tb_frame.f_code.co_filename).replace("/", "\\")
	exc_line = str(exc_traceback.tb_lineno)
	exc_name = str(exc_traceback.tb_frame.f_code.co_name)
	sys.stderr.write("  File \"" + exc_file + "\", line " + exc_line + ", in " + exc_name)

	# code line
	file = open(exc_file, 'r')
	exc_code = file.readlines()[int(exc_line)-1].strip(" ")
	file.close()
	sys.stderr.write("	" + exc_code)

	# next stack
	exc_traceback = exc_traceback.tb_next

# exception type
exc_type = str(exc_type).replace("exceptions.", "")
exc_value = str(exc_value)
sys.stderr.write(exc_type + ": " + exc_value)

Example use:

def chatmessage():
try:
	another_function(True)
except:
	print_exc()

def another_function(bool):
if bool: dostuff()

Output looks like this:

Traceback (most recent call last):
 File "mods\scout_edit\python\game\debug.py", line 29, in chatmessage
another_function(True)
 File "mods\scout_edit\python\game\debug.py", line 41, in another_function
if bool: dostuff()
NameError: global name 'dostuff' is not defined

Compared to the 'official' traceback.print_exc() function (triggered from within the python shell):

Traceback (most recent call last):
 File "<pyshell#50>", line 2, in chatmessage
another_function(True)
 File "<pyshell#53>", line 2, in another_function
if bool: dostuff()
NameError: global name 'dostuff' is not defined

Oh, and if you want to reroute the sys.stderr messages to the server chat, use something like this:

import sys

import host

def init():
sys.stderr = stderr()

class stderr:
def __init__(self): pass

def flush(self): pass

def close(self): pass

def write(self, string):
	for line in string.splitlines():
		line = line.replace("\"", "'")
		host.rcon_invoke("game.sayall \"" + line + "\"")

Feel free to use all this if you want. ;)

Share this post


Link to post
Share on other sites

i just do sys.excepthook(*sys.exc_info()) -- this prints it in the standard form you quoted to sys.stderr.

Oh, yeah that does seem to work. Meh. :(

Traceback (most recent call last):
 File "mods/scout_edit/python\game\debug.py", line 27, in chatmessage

another_function(True)
 File "mods/scout_edit/python\game\debug.py", line 35, in another_function

if bool: dostuff()
NameError
: 
global name 'dostuff' is not defined

And my custom stream is a bit buggy, any idea what the exact function of stream.write() should be?

Share this post


Link to post
Share on other sites

Ah, I just noticed I'm being a bit stupid. I forgot that calls to stream.write() don't necessarily include a newline character, I'm confused with the WriteLine() method in C#. *cough*

	 class stderr(object):

	def __init__(self):
		self.file = open("%s/python/game/stderr.txt" % host.sgl_getModDirectory(), 'w')
		self.buffer = ""

	def flush(self):
		if len(self.buffer) > 0:
			self.write("\n")
		self.file.flush()

	def close(self):
		self.file.close()

	def write(self, string):
		if string is not None and len(string) > 0:
			self.buffer += string
			if self.buffer.endswith("\n"):
				self.file.write(self.buffer)
				textMessage(self.buffer)
				self.buffer = ""

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...