Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Thursday, July 7, 2011

Simple python inheritance example

Python's Classes documentation has a bag class. Since I'm writing a program in which I want to do inheritance but haven't done it in a while and need a refresh, I thought I'd extend bag into a wet paper bag; which looses things you put in it nearly half the time. I came up with this:

class Bag(object):
    def __init__(self):
        self.data = []
    def add(self, x):
        self.data.append(x)
    def addtwice(self, x):
        self.add(x)
        self.add(x)

class WetPaper(Bag):
    def __init__(self):
        super(WetPaper, self).__init__()
    def add(self, x):
        from random import randint
        if (randint(1,10) > 4):
            super(WetPaper, self).add(x)

if __name__ == '__main__':
    bag = Bag()
    bag.addtwice(1)
    print "Bag:", bag.data
    wet = WetPaper()
    wet.addtwice(1)
    print "WetPaper:", wet.data
Since I'm extending Bag, defining the constructor was simplified and I didn't have to worry about how add() was implemented; I could just flip a coin with rand to see if the inherited add() should be called. I also didn't have to define addtwice() and it inherited the unreliable aspect of WetPaper's add().

When writing the above, the first thing I had to do was update the original Bag definition to a new style class descended from object. Until I did this I got a "TypeError: must be type, not classobj" error when I used super and I had to directly use the parent class name instead:

    def __init__(self):
        Bag.__init__(self)
While working on this I found Python's Super is nifty, but you can't use it. I also found out that in Python 3 self will become implicit in super calls so instead of:
  super(WetPaper, self).__init__()
I will just be able to do:
  super().__init__()

Saturday, June 4, 2011

web.py, mod_wsgi , RHEL6

web.py can be run in a production environment on RHEL6 with mod_wsgi using stock packages from yum with the exception of web.py itself (which can be inserted into the system Python library).

1. Install the packages that RHEL6 provides:

 yum install httpd mod_ssl mod_wsgi mysql-devel MySQL-python 

2. Insert web.py directly into RHEL's python2.6 site-packages:

cd /tmp
wget http://pypi.python.org/packages/source/w/web.py/web.py-0.35.tar.gz
tar xzf web.py-0.35.tar.gz
cd /usr/lib/python2.6/site-packages
mv /tmp/web.py-0.35/web .

3. Configure a place to host your application:

mkdir /var/www/myapp

4. Install some basic code in /var/www/myapp/code.py

import web
urls = (
        '/.*', 'hello',
        )
class hello:
        def GET(self):
                return "Hello World"
application = web.application(urls, globals()).wsgifunc()

5. Configure mod_wsgi directives for Apache in /etc/httpd/conf.d/wsgi.conf:

LoadModule wsgi_module modules/mod_wsgi.so
WSGIScriptAlias /myapp /var/www/myapp/code.py/
<Directory /var/www/tentacle/>
  Order allow,deny
  Allow from all
</Directory>

When configuring the above I used the webpy.org cookbook as a reference. Note that my previous example was development only.

web.py

I tried web.py.

I like it because it's simple and I found it intuitive and easy to learn. You can set it up quickly on Fedora with:

yum install python-webpy
yum install MySQL-python 
It was straight forward to follow the tutorial, except it's not obvious in the tutorial how to specify a different DB server besides the default localhost. The keyword argument is 'host' just like in MySQLdb.connect(), which is provided by the Python package MySQLdb; i.e. the MySQL-python yum package. Here's the example from the tutorial in which an external DB server is declared:
db = web.database(dbn='mysql',\
                  user='user',\
                  pw='password',\
                  db='todo',\
                  host='mysql.example.com')
Also, the PostgreSQL example translates into MySQL like this:
CREATE TABLE todo (   id serial primary key,   title text,   
                    created timestamp default now(),   
        `done` boolean default '0'    );
specifically boolean is an synonym for tinyint in MySQL so it uses not 'f' but '0' to represent false.

The output code from my tutorial is:

code.py:

#!/usr/bin/env python
# Filename:                code.py
# Description:             intro to web.py
# Supported Langauge(s):   Python 2.7.x
# Time-stamp:              <2011-06-04 18:15:06 someguy> 
# -------------------------------------------------------
import web
# -------------------------------------------------------
render = web.template.render('templates/')
urls = (
    '/', 'index',
    '/add', 'add'
)
app = web.application(urls, globals())
db = web.database(dbn='mysql',\
                  user='todo',\
                  pw='redacted',\
                  db='todo',\
                  host='mysql.example.com')
# -------------------------------------------------------
class index:        
    def GET(self):
        todos = db.select('todo')
        return render.index(todos)

class add:
    def POST(self):
        i = web.input()
        n = db.insert('todo', title=i.title)
        raise web.seeother('/')
# -------------------------------------------------------
if __name__ == "__main__":
    app.run()
templates/index.html
$def with (todos)
<ul>
$for todo in todos:
    <li id="t$todo.id">$todo.title</li>
</ul>

<form method="post" action="add">
<p><input type="text" name="title" /> 
<input type="submit" value="Add" /></p>
</form>

Thursday, April 7, 2011

flymake & pyflakes

I am writing Python using flymake in Emacs with pyflakes as described in chrism's blog entry on Flymake Mode for Emacs / Python.
cd ~/elisp
wget http://cvs.savannah.gnu.org/viewvc/*checkout*/emacs/emacs/lisp/progmodes/flymake.el?revision=1.2.4.41
mv flymake.el\?revision\=1.2.4.41 flymake.el
easy_install pyflakes

add the following to .emacs:

  (when (load "flymake" t) 
         (defun flymake-pyflakes-init () 
           (let* ((temp-file (flymake-init-create-temp-buffer-copy 
                              'flymake-create-temp-inplace)) 
              (local-file (file-relative-name 
                           temp-file 
                           (file-name-directory buffer-file-name)))) 
             (list "pyflakes" (list local-file)))) 

         (add-to-list 'flymake-allowed-file-name-masks 
                  '("\\.py\\'" flymake-pyflakes-init))) 

   (add-hook 'find-file-hook 'flymake-find-file-hook)

Tuesday, August 12, 2008

Python urlencode annoyance

O'Reilly has examples of how to urlencode a string for various languages. Every example has the same semantics -- a variable to define a string and a function to encode it -- except Python. Python's urlencode presumes you want to convert a dictionary whose key (which seems to be a name you should make up when you call this function) will be a GET variable that you would append to the tail of the URL. I think this presumes too much. I want to build a URL and simply encode the name of a file. I wish I could do this:
url = "http://foo.com/" + urlencode(file_name)
Instead I use a substring kludge since len("x=") is 2:
tmp = urlencode({'x':file_name})
url = "http://foo.com/" + tmp[2:]
Applying this back to O'Reilly's example:
from urllib import urlencode
artist = "Kruder & Dorfmeister"
tmp = urlencode({'x':artist})
artist = tmp[2:]
I guess Python is promoting a paradigm where URL values are arguments to methods and the syntax of a URL itself is abstracted away. But I still would have kept urlencode like the other languages and offered a variation of this function that does whatever Python is trying to promote.