Wednesday, November 18, 2009

Solving Django "ImportError: No module named" issues

So you whipped up an awesome Django (src) project following the instructions on the documentation site, and now you want to deploy it on a production slice. Inspired by RoR mongrels deployments, you setup an nginx (src) load-balancer that will proxy_pass requests to a cluster of Django instances, each inside an ultra-fast CherryPy (src) http server wrapper. Perhaps you chose to use django_cpserver (src) to extend the standard manage.py with a slick runcpserver command to fire up your django web app instances. Maybe you even write a quick utility script to fire up your django cluster all in one go:

#!/usr/bin/env python
#
# Utility script for firing up the django cluster.
#
# To use this library on python 2.5:
# http://code.google.com/p/python-multiprocessing/
#
# $Id: cluster.py,v 1.2 2009/11/17 19:44:25 l8rs Exp $

import multiprocessing
import subprocess

#from config.cluster import DJANGO_WORKERS
DJANGO_WORKERS = [
'./manage.py runcpserver host=127.0.0.1 port=8000 daemonize',
'./manage.py runcpserver host=127.0.0.1 port=8001 daemonize',
'./manage.py runcpserver host=127.0.0.1 port=8002 daemonize',
'./manage.py runcpserver host=127.0.0.1 port=8003 daemonize',
]

def work(cmd):
return subprocess.call(cmd, shell=True)

def start():
count = len(DJANGO_WORKERS)
pool = multiprocessing.Pool(count)
print pool.map(work, DJANGO_WORKERS)

if __name__ == '__main__':
start()


Ok, but when you finally start hitting the server with requests, to your shock and horror, the app that ran fine when started with `manage.py runserver` or even `manage.py runcpserver` without daemonize now can't find any of the local modules in your application?!

Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/cherrypy/wsgiserver/__init__.py", line 1210, in communicate
req.respond()
File "/usr/local/lib/python2.6/dist-packages/cherrypy/wsgiserver/__init__.py", line 729, in respond
self.server.gateway(self).respond()
File "/usr/local/lib/python2.6/dist-packages/cherrypy/wsgiserver/__init__.py", line 1889, in respond
response = self.req.server.wsgi_app(self.env, self.start_response)
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/wsgi.py", line 241, in __call__
response = self.get_response(request)
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py", line 76, in get_response
response = middleware_method(request)
File "/usr/local/lib/python2.6/dist-packages/django/middleware/common.py", line 56, in process_request
if (not _is_valid_path(request.path_info) and
File "/usr/local/lib/python2.6/dist-packages/django/middleware/common.py", line 142, in _is_valid_path
urlresolvers.resolve(path)
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 309, in resolve
return get_resolver(urlconf).resolve(path)
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 220, in resolve
for pattern in self.url_patterns:
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 249, in _get_url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 244, in _get_urlconf_module
self._urlconf_module = import_module(self.urlconf_name)
File "/usr/local/lib/python2.6/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/home/user/src/django/myproj/../myproj/urls.py", line 7, in
from myapp.module import views
ImportError: No module named myapp.module


Well, silly goose, the answer is simple (and nowhere to be found on all the internet)! You need to make sure the daemon user has permission to access the source of your web app! The default user for this setup is www-data. And when you're testing out the app, you may have put it in ~/src or something owned by your dev user. Also, when you run with daemonize on, you may have been tempted to prepend a sudo to allow the runcpserver code to generate it's default /var/run/cpserver_port.pid file... The simple fix is to pass server_user= and server_group= to the `manage.py runcpserver` command (though passing in root to these is clearly not advised from a security stand-point). The proper fix is to put your django code in a place it will live in production (/var/www/...), and to stamp it with all the right user and group permissions.

Hopefully this post saves you some heart-ache!

Friday, October 23, 2009

How to display NSData contents in XCode debugger

Actually, this is more of a gdb language tip.
  1. Set and hit some breakpoint
  2. Click SHIFT+CMD+R or Run --> Console
  3. Type the following into the gdb window that comes up:
(gdb) p (char *)[self._xmlData bytes]
$11 = 0x2058200 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\""...
Obviously substitute self._xmlData with the expression that accesses your own NSData * object.

Okay, but how do you display more lines of the output you ask? Try this:
x/10s (char*)[self._xmlData bytes]
This will display the first 10 chunks of the data as strings.

Thursday, October 01, 2009

iphone simulator screen capture made easy

There are various ways to take a clean screenshot of an iphone application. Perhaps the easiest and most reliable using the standard tools is the following process:
  • Open XCode
  • Flash app to real device
  • In XCode, Windows -> Organizer
  • In Organizer navigate to Screenshots
  • On device navigate to desired screen
  • In Organizer click take screenshot
This process is somewhat painful however when many screens are needed for two reasons:
  1. Requires a real device in the loop (doesn't work for simulator)
  2. Screenshot includes information bar with carrier and time
Enter the iPhone-Simulator Cropper tool! This handy program out of Germany provides simple single-click screenshot capability straight out of the simulator, sizes everything perfectly, automatically names the images exactly how you want, and even strips the carrier information bar if you choose. Indispensable.

Sunday, August 23, 2009

Apple AppStore silently adjusting behind the scenes

The Apple AppStore provides a nice feature of letting the developer adjust meta-data about an application in the store in near real-time via itunesconnect. The 4000 word product description that shows up in the app store, specifically, is quite malleable and can be used for late breaking clarifications and communicating directly to customers. Other attributes that are adjustable are the price, icon, category, and application long name. Recently, Apple added a keywords field too. Then all of a sudden (perhaps a few days ago), the application long name field and keywords where locked out -- you can't change these anymore... It's strange really, as the motivation for this isn't clear. Why wouldn't Apple want application developers dynamically optimizing their marketing message to be more relevant to customers?

Saturday, August 15, 2009

Throwing your junk into the Cloud

Sometime soon, everyone will join an online remote backup service en mass. Hard drives just aren't reliable, and with all the digital music and video folks are generating, this data will need a home. Enter the 15 cent/month cloud GB, and the internet version of the pay-monthly self-storage depot. So with such a compelling market need defined, who are the players and what are their offerings?

Here's the breakdown:




ServicePromoBasicProLocation / Review
LiveDrive1 month free100GB
1PC
$5/month
unlimited GB
unlimited PC
$13/month
UK Win only...
SpiderOak2GB free$10 / 100GB
unlimited PC
$10 / 100GB
unlimited PC
Illinois Promo
Mozy2GB free
unlimited GB
1 PC
$5/month
?Utah
iDrive2GB free
150 GB
$5/month
500GB
$50/month
California

Friday, August 14, 2009

What happened to Memidex?

Memidex, one of the better online dictionaries with superior mobile formatting, has been down for the last few days. All word lookups result in "Access Denied". I sometimes wonder what people would do if all websites suddenly did that, for example, say the internet "went cognizant" and just decided to keep everything to itself. :D

Sunday, August 09, 2009

Cappuccino newbie guide

Smallest Cappuccino getting started guide ever.
Required: minimal ruby environment with rake command

mkdir ~/src/cappuccino
cd ~/src/cappuccino
git clone git://github.com/280north/cappuccino.git
mkdir ~/bin/cappuccino
export CAPP_BUILD=~/bin/cappuccino
rake install
rake install
capp gen TestProject -l


"Hello World" will display upon opening ~/TestProject/index.html

Now, download and try some more advanced Demos:

Requires: wget

mkdir -p Projects
cd Projects
wget http://cappuccino.org/learn/demos/LightsOff.zip
wget http://cappuccino.org/learn/demos/FlickrPhotoDemo.zip
wget http://cappuccino.org/learn/demos/FloorPlan.zip
wget http://cappuccino.org/learn/demos/Puzzle.zip
unzip LightsOff.zip
unzip FlickrPhotoDemo.zip
unzip FloorPlan.zip
unzip Puzzle.zip

# Build and try one
cd LightsOff
rake debug


Just click on the index.html in the directory of each project to see the result.