FirePython — no prints?

While I’m developing some web application I almost never use any debuggers or supporting tools: in 90% of cases usual print variable is enough for understanding a trouble. Of course, there are some very complicated cases, when I do import pdb; pdb.set_trace().

But I was pointed at very cool thing yesterday — FirePython. This thing consists of two parts — small library on python and plugin for Firebug. This tandem is engaged with very useful business — it displays all python logged activity1 in Firebug tab.

This tool is really helpful — now I need only two applications for development: an editor and a browser. Good news is that I don’t need to look for print output in runserver output. Regarding usual usage of logging there are some benefits too — at least you don’t need to follow files and their paths (for creation of which you may not have rights), moreover immediately you have nice viewer for logs with ability to filter them.

I’ve contributed today to development of FirePython by development of two middlewares — one for Django and one for WSGI applications, so now its usage is just a question of few movements. ;) In short: you need to install plugin itself, which depends on Firebug 1.3 (it’s still in beta stage, but I’m using Firefox 3.1, so this is not scary for me :P). After that do easy_install firepython. Another option: clone project from github and put folder firepython from python folder in sys.path or your project directory.

After that you just need to enable middleware by adding its path in MIDDLEWARE_CLASSES: firepython.django.FirePythonDjango. WSGI middleware has another path (how strange! :D): firepython.wsgi.FirePythonWSGI, which you should use as any other WSGI middleware.

Usage of whole system in code looks like:

import logging
logging.debug('what you want to debug today?')

Naturally you can use any level instead of debug — you can filter them in FirePython interface.

1

Precisely saying you will get logs which was logged while FirePython was registered as a handler in logging.

Comments: 35 (already: 5) Comment post

I haven’t tested yet, just out of curiosity and maybe you just know it: does it work on appengine as well ?

Roberto , 13:10 (after 2 days)

Yes, it was written for AppEngine initially.

Alexander Solovyov , 13:14 (after 2 days)

huh, I tried now, first I had to set simplejson class path from simplejson to django.utils.simplejson and then I got this error (on appengine):

INFO     2008-11-26 13:25:51,843 dev_appserver_main.py] Running application skast on port 8000: http://localhost:8000
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 49959)
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/SocketServer.py", line 222, in handle_request
    self.process_request(request, client_address)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/SocketServer.py", line 241, in process_request
    self.finish_request(request, client_address)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/SocketServer.py", line 254, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/local/google_appengine/google/appengine/tools/dev_appserver.py", line 2355, in __init__
    BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/SocketServer.py", line 522, in __init__
    self.handle()
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/BaseHTTPServer.py", line 316, in handle
    self.handle_one_request()
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/BaseHTTPServer.py", line 310, in handle_one_request
    method()
  File "/usr/local/google_appengine/google/appengine/tools/dev_appserver.py", line 2359, in do_GET
    self._HandleRequest()
  File "/usr/local/google_appengine/google/appengine/tools/dev_appserver.py", line 2473, in _HandleRequest
    logging.exception(msg)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/logging/__init__.py", line 1301, in exception
    apply(error, (msg,)+args, {'exc_info': 1})
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/logging/__init__.py", line 1294, in error
    apply(root.error, (msg,)+args, kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/logging/__init__.py", line 1015, in error
    apply(self._log, (ERROR, msg, args), kwargs)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/logging/__init__.py", line 1094, in _log
    fn, lno, func = self.findCaller()
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/logging/__init__.py", line 1063, in findCaller
    f = currentframe().f_back
  File "/Users/rsaccon/appengine/skast/common/firepython/__init__.py", line 27, in correctCurrentframe
    return sys.exc_traceback.tb_frame.f_back.f_back.f_back.f_back # wtf?
AttributeError: 'NoneType' object has no attribute 'exc_traceback'
----------------------------------------

Any idea what went wrong ?

and btw., amazing project, your blogengine !!!

Roberto , 13:31 (after 2 days)

Any idea what went wrong ?

Oh, yes… We will try to fix that.

and btw., amazing project, your blogengine !!!

Thanks! :-)

P.S. Indenting code with 4 spaces will render it as code, that’s a markdown syntax.

Alexander Solovyov , 13:44 (after 2 days)

Roberto, update to latest App Engine SDK. sys.exc_traceback is available during exception on my system OSX 10.5.5, Python 2.5.1, GAE SDK 1.1.7

or alternatively comment out lines around #27 in firepython/init.py it is there only for fixing incorrect paths in log records on OSX (?)

Antonin Hildebrand , 14:04 (after 2 days)

Antonin, if I check my versions, OSX 10.5.5, Python 2.5.1, GAE SDK 1.1.7 is EXACTLY what I have. Strange !

Roberto , 14:14 (after 2 days)

please try adding import sys before line return sys.exc_traceback.tb_frame.f_back.f_back.f_back.f_back

and let me know here

Antonin Hildebrand , 14:16 (after 2 days)

Got a microstep further, but now it complains about undefined simplejson (I imported it at top as django.utils.simplejson):

File "/Users/rsaccon/appengine/skast/common/firepython/__init__.py", line 34, in <module>
  class TolerantJSONEncoder(simplejson.JSONEncoder):

NameError: name ‘simplejson’ is not defined

Roberto , 14:24 (after 2 days)

Roberto, I’ve just copied simplejson folder to root of my GAE project (where is app.yaml). It doesn’t hurt.

Antonin Hildebrand , 14:29 (after 2 days)

playing with sys.path or class path is not a good idea for goole app engine. there are bugs. for me as a python newbie it is nothing but magic.

see http://code.google.com/appengine/articles/django10_zipimport.html and look for “bug”

Antonin Hildebrand , 14:31 (after 2 days)

Oh, why GAE is resetting sys.path? It’s simply bad idea. :\

Alexander Solovyov , 14:55 (after 2 days)

Do it like from django.utils import simplejson. I’ll patch firepython to do that by default.

Alexander Solovyov , 14:43 (after 2 days)

ok, now I got:

File "/Users/rsaccon/appengine/skast/common/firepython/__init__.py", line 27, in correctCurrentframe
  import sys

SystemError: Parent module ‘firepython’ not loaded

next I remove the “import sys” in the correctCurrentFrame() and I got the following exception:

File "/Users/rsaccon/appengine/skast/common/zip-packages/django.zip/django/core/handlers/wsgi.py", line 228, in __call__
File "/Users/rsaccon/appengine/skast/common/zip-packages/django.zip/django/core/handlers/base.py", line 40, in load_middleware
ImproperlyConfigured: Error importing middleware firepython.django: "No module named django"
INFO     2008-11-26 14:51:58,611 dev_appserver.py] "GET / HTTP/1.1" 500 —
Roberto , 14:55 (after 2 days)

Comment out line logging.currentframe = correctCurrentframe, I think you should not need it.

About Django — isn’t Django in sys.path of GAE? I’m not sure as I haven’t used GAE at all. :-(

Alexander Solovyov , 15:16 (after 2 days)

still getting:

ImproperlyConfigured: Error importing middleware firepython.django: "No module named django"

monkeypatched django is loaded from a zip file (GAE has only very old django preinstalled) and I use the monkeypatch from appenginepatch to do that, but I am not yet familiar with the hidden details of how it works (I am Python newby, sorry)

Roberto , 15:23 (after 2 days)

Ok, I’m going to try that and will comment as soon as it will work.

Alexander Solovyov , 15:42 (after 2 days)

Hey Roberto! From traceback I see that you have placed firepython module into common directory. (/Users/rsaccon/appengine/skast/common/firepython).

I’ve said don’t mess with sys.path and put all modules into root directory of gae project. You are asking for troubles.

Antonin Hildebrand , 15:44 (after 2 days)

Unfortunately that is how appenginepatch (the django monkeypatcher I am using) works.

  • Source modules go into APP_DIR/common
  • zipped modules go into APP_DIR/common/zip-packages
Roberto , 16:01 (after 2 days)

I don’t know appenginepatch, but you should be still able to place modules to root of the project. I suppose sys.path still contains PROJECT_ROOT. So, put firepython into project root and see what happens

Antonin Hildebrand , 16:09 (after 2 days)

unfortunately the same error. I think it has to do with how appenginepatch does the django monkyepatching. Will ask the appenginepatch guys for advice.

Roberto , 17:22 (after 2 days)

Please comment here if you’ll have success with that. :-)

Alexander Solovyov , 18:20 (after 2 days)

Nice plugin! :)

The traceback says it all: There indeed is no module “firepython.django”.Please try “firepython.middleware.FirePythonDjango”. Alexander, could you please update the documentation?

Waldemar Kornewald , 18:47 (after 2 days)

Oh! :D Thanks, documentation is updated.

Alexander Solovyov , 19:06 (after 2 days)

BTW, this blog post refers to “firepython.django”, too.

Waldemar Kornewald , 22:52 (after 2 days)

It was written about version 0.2, for which this is right path. ;-) I’ll better write new blog post about 0.3, when it will come out :-)

Alexander Solovyov , 23:35 (after 2 days)

Ouuuch ! That was it, no more errors now. It doesn’t log yet at the FirePython tab, so there is still something wrong in my code …

Roberto , 19:13 (after 2 days)

Yes, unfortunately GAE relies (at least in SDK part, haven’t tried GAE itself) on deprecated feature of WSGI, support for which I have committed 30 seconds ago. Look at my repo.

Alexander Solovyov , 19:28 (after 2 days)

Oops, there are troubles with threading and GAE. Fixing that right now.

Alexander Solovyov , 19:32 (after 2 days)

I was wrong. SDK works fine now.

Alexander Solovyov , 19:40 (after 2 days)

Alexander, I just updated from your git repo, now I get the following error

global name 'version' is not defined

If I check the source, the following logging statement seems to use undefined variables:

if firepython.__version__ != check.group('ver'):
        logging.debug('FireBug part of FirePython is version %s, but Python part is %s', version, __version__)

(Of course I am aware that if I am supposed to get this debug message, there is another thing wrong with my setup …)

Roberto , 20:09 (after 2 days)

Thanks for checking, this bug appeared after refactoring. Fixed and pushed to github.

Alexander Solovyov , 20:21 (after 2 days)

it’s wrong again on github, It works for me if I adapt it as follows:

version = check.group('ver')
if firepython.__version__ != version:
    logging.debug('FireBug part of FirePython is version %s, but Python part is %s', version, firepython.__version__)

The actual error message I get, produced by that statement, is:

FireBug part of FirePython is version 0.1, but Python part is 0.2

That is odd, because I have installed FirePython via mozilla addon service and the version is 0.2 (checking in the GUI, via menu Tools/Add-ons)

Roberto , 01:26 (after 3 days)

Confirmed: It is bug in 0.2 release of firebug extension.

This won’t happen in the future. I promise :-)

Antonin Hildebrand , 01:38 (after 3 days)

It works great for me except in cases where my handler does a redirect.

self.redirect(‘/’) for example, in which case the HTTP response is cleared

application = webapp.WSGIApplication(routes) from external.firepython.middleware import FirePythonWSGI application = FirePythonWSGI(application)

Using it in app engine with SDK 1.1.7

bustrofedon , 14:09 (after 7 days)

Thanks for report, I’ll look at that soon.

Alexander Solovyov , 14:26 (after 7 days)

Comment form for «FirePython - no prints?»

Required. 30 chars of fewer.

Required.

Comment post