[Python-ideas] Verbose traceback formatting
Oleg Broytman
phd at phdru.name
Wed Aug 29 02:05:38 CEST 2012
Hi!
On Tue, Aug 28, 2012 at 06:26:04PM -0400, Mike Graham <mikegraham at gmail.com> wrote:
> It's possible to give a lot more on error than the default traceback
> gives you. I propose that Python should ship a more verbose formatter
Good idea!
> and a command line switch to use it.
And an environment variable, as usual: PYTHONTRACEBACK=verbose.
> Here's an example of IPython's verbose formatter. I wrote a buggy program:
>
> > def f(a):
> > x = a * 4
> > y = a - 4
> > return x / y
> >
> > def main():
> > for i in xrange(100):
> > f(i)
> >
> > main()
>
>
> and then ran it in IPython with verbose tracebacks and got the following output:
>
> > ZeroDivisionError Traceback (most recent call last)
> >
> > /home/mike/foo.py in <module>()
> > 8 f(i)
> > 9
> > ---> 10 main()
> > global main = <function main at 0x10bd7d0>
> > 11
> > 12
> >
> > /home/mike/foo.py in main()
> > 6 def main():
> > 7 for i in xrange(100):
> > ----> 8 f(i)
> > global f = <function f at 0x10bd758>
> > i = 4
> > 9
> > 10 main()
> >
> > /home/mike/foo.py in f(a=4)
> > 2 x = a * 4
> > 3 y = a - 4
> > ----> 4 return x / y
> > x = 16
> > y = 0
> > 5
> > 6 def main():
> >
> > ZeroDivisionError: integer division or modulo by zero
>
>
>
> This is very handy!
100% agree! py.test produces even more verbose tracebacks and I found
them very helpful in debugging. Here is a short example and below is
much bigger one.
___________________________ test_transaction_delete ____________________________
close = False
def test_transaction_delete(close=False):
if not supports('transactions'):
return
setupClass(TestSOTrans)
trans = TestSOTrans._connection.transaction()
try:
TestSOTrans(name='bob')
bIn = TestSOTrans.byName('bob', connection=trans)
bIn.destroySelf()
bOut = TestSOTrans.select(TestSOTrans.q.name=='bob')
> assert bOut.count() == 1
E assert 0 == 1
E + where 0 = <SelectResults at a6eb7cc>.count()
test_transactions.py:65: AssertionError
Longer and more verbose:
_______________________________ test_transaction _______________________________
def test_transaction():
if not supports('transactions'):
return
> setupClass(TestSOTrans)
test_transactions.py:17:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
soClasses = [<class 'sqlobject.tests.test_transactions.TestSOTrans'>]
force = False
def setupClass(soClasses, force=False):
"""
Makes sure the classes have a corresponding and correct table.
This won't recreate the table if it already exists. It will check
that the table is properly defined (in case you change your table
definition).
You can provide a single class or a list of classes; if a list
then classes will be created in the order you provide, and
destroyed in the opposite order. So if class A depends on class
B, then do setupClass([B, A]) and B won't be destroyed or cleared
until after A is destroyed or cleared.
If force is true, then the database will be recreated no matter
what.
"""
global hub
if not isinstance(soClasses, (list, tuple)):
soClasses = [soClasses]
connection = getConnection()
for soClass in soClasses:
## This would be an alternate way to register connections...
#try:
# hub
#except NameError:
# hub = sqlobject.dbconnection.ConnectionHub()
#soClass._connection = hub
#hub.threadConnection = connection
#hub.processConnection = connection
soClass._connection = connection
> installOrClear(soClasses, force=force)
dbtest.py:83:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cls = <class 'sqlobject.tests.dbtest.InstalledTestDatabase'>
soClasses = [<class 'sqlobject.tests.test_transactions.TestSOTrans'>]
force = False
@classmethod
def installOrClear(cls, soClasses, force=False):
cls.setup()
reversed = list(soClasses)[:]
reversed.reverse()
# If anything needs to be dropped, they all must be dropped
# But if we're forcing it, then we'll always drop
if force:
any_drops = True
else:
any_drops = False
for soClass in reversed:
table = soClass.sqlmeta.table
> if not soClass._connection.tableExists(table):
dbtest.py:140:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <sqlobject.postgres.pgconnection.PostgresConnection instance at 0x8c2fa2c>
tableName = 'test_so_trans'
def tableExists(self, tableName):
result = self.queryOne("SELECT COUNT(relname) FROM pg_class WHERE relname = %s"
> % self.sqlrepr(tableName))
../postgres/pgconnection.py:235:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <sqlobject.postgres.pgconnection.PostgresConnection instance at 0x8c2fa2c>
s = "SELECT COUNT(relname) FROM pg_class WHERE relname = 'test_so_trans'"
def queryOne(self, s):
> return self._runWithConnection(self._queryOne, s)
../dbconnection.py:457:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <sqlobject.postgres.pgconnection.PostgresConnection instance at 0x8c2fa2c>
meth = <bound method PostgresConnection._queryOne of <sqlobject.postgres.pgconnection.PostgresConnection instance at 0x8c2fa2c>>
def _runWithConnection(self, meth, *args):
> conn = self.getConnection()
../dbconnection.py:325:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <sqlobject.postgres.pgconnection.PostgresConnection instance at 0x8c2fa2c>
def getConnection(self):
self._poolLock.acquire()
try:
if not self._pool:
> conn = self.makeConnection()
../dbconnection.py:336:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <sqlobject.postgres.pgconnection.PostgresConnection instance at 0x8c2fa2c>
def makeConnection(self):
try:
if self.use_dsn:
conn = self.module.connect(self.dsn)
else:
conn = self.module.connect(**self.dsn_dict)
except self.module.OperationalError, e:
> raise OperationalError("%s; used connection string %r" % (e, self.dsn))
E OperationalError: could not connect to server: No such file or directory
E Is the server running locally and accepting
E connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
E ; used connection string 'dbname=test'
../postgres/pgconnection.py:142: OperationalError
Oleg.
--
Oleg Broytman http://phdru.name/ phd at phdru.name
Programmers don't die, they just GOSUB without RETURN.
More information about the Python-ideas
mailing list