Categories
Blog News

Proof of concept for a simple webserver running python code

Here is a small code example using CherryPy to run a very simple webserver that

  • generates a simple math question
  • compares the answer to the solution.

It’s meant as a proof of concept, so there is no security built in. It’s running on localhost on port 8888 (modifiable in the main part of the code).
It allows you to play around and test out your ideas.

Do not use this code on an outside network !

It’s simply an example showing how easy it is to set up a web server and how you can create pages for it using python and CherryPy. It’s been cobbled together in an evening from previous programming so there’s some cruft left in. I’ve also extensively commented the code.

Requirements:

  • python 2.7 ( 2.5 will work as well is my guess )
  • cherrypy 3.2.2 ( use easy_install or pip to download and install the latest version)
  • site.py ( the file containing the python code )

You start the server in a command prompt using : python site.py which will start the server. Leave the command prompt open.

You can then visit the webserver by opening a browser and going to http://localhost:8888 to see the index page and play around with it.

#
# MathPoc : Proof of concept of a simple math problem, bringing it to the browser
#
# Alex Boschmans
#
# Version 0.2, February 2011
#
# 0.2 Added some error checks and expanded math to not just adding but also 
# subtraction and multiplication and divisions. Extensively commented code.

header = """<HTML>
            <HEAD>
                <title>MATH Proof of Concept</title>
            </HEAD>
            <BODY>
        """
footer = "</BODY></HTML>"

indexhtml = """
        <H1>Math Proof of Concept</H1>
        <p>Please answer the following question</p>
                <p>How much is %d %s %d ? </p>
                
                <form action="/response" method="post">
                Answer: <input type="text" name="answer" />
                <input type="hidden" name="number1" value="%d">
                <input type="hidden" name="number2" value="%d">
                <input type="hidden" name="operation" value="%s">
                <input type="submit" value="Submit" />
                </form>
                
        """

def generatequestion():
    # This generates the question that we will pose using the random function
    # Generate a random question using 2 random numbers between 1 and 10
    number1 = random.randint(1,10) 
    number2 = random.randint(1,10)
    # Now we choose an operatioin
    ops = ["+", "-", "x", "/"]
    operation = random.choice(ops)
    # Let's check the division
    if operation == "/":
        # Prevent divisions with remainders using the modulo operator
        # Using module on the two numbers evaluates to 0 when no remainder is present
        # While the modulo remainder is not equal to 0, generate two new numbers
        while number1 % number2 <> 0:
                number1 = random.randint(1,10) 
                number2 = random.randint(1,10)
    # Assemble the html, inputting the numbers in the foreseen places in the html
    # In a more extensive project, you would keep this html in a template file and 
    # call it with a dictionary of items that need to be filled in the template
    question = indexhtml % (number1, operation, number2, number1, number2, operation)
    # Add common html like header and footer - these are defined just once and reused
    # for each page
    html = header + question + footer
    # Return the completed html to the calling function (in this case index)
    return html

# This is the class that the cherrypy server uses and where you create the views that the 
# webuser sees. After each definition there is a <function>.exposed=True that indicates if the 
# webuser can see this page or not. 
class MathPoc:
    def index(self):
        # This is the main index page that is shown to the user when he first visits the site.
        # We create the page by calling the function generatequestion (which is outside the class
        # MathPoc but accessible and we show it to the user by 'return'ing the page 
        page = generatequestion()
        return page
        # The webuser will now see the page and will have a chance to enter an answer.
        # In the html form I've specified that the submitted result will go to the url "response"
        # I've added all the values I want to receive either as hidden values (eg the 
        # original numbers, the operation) or as part of the form (eg the answer)
    index.exposed = True
    
    def response(self, answer, number1, number2, operation):
        # First check if we received an answer or if the user submitted without an answer
        if answer:
            # Calculate our own answer ourselves and generate a response to the user
            # We receive strings, so convert them to integers using int()
            number1 = int(number1)
            number2 = int(number2)
            answer = int(answer)
            # Answer is dependent on operation
            if operation == "+":
                solution = number1 + number2
            elif operation == "-":
                solution = number1 - number2
            elif operation == "x":
                solution = number1 * number2
            else:
                solution = number1 / number2
            # See if the answer is correct and display according the result
            # Using templates, you could put all this in one template and 
            # call the template with options so it knows what to show
            if solution <> answer:
                html = """
                <H1>Sorry.</H1>
                <p>The question was : %s %s %s = ?</p>
                <p>Your answer %s is wrong. The correct answer is %d.</p>
                <p><a href = "/">Try Again.</a></p>
                """ % (number1, operation, number2, answer, solution)
            else:
                html = """
                <H1>Correct !</H1>
                <p>The question was : %s %s %s = %s</p>
                <p>Your answer is correct !</p>
                <p><a href = "/">Try Again.</a></p>
                """ % (number1, operation, number2, answer)
        else:
            # We did not receive an answer
            html = """
            <h1>Sorry ?</h1>
            <p>You need to fill in an answer !</p>
            <p><a href = "/">Try Again.</a></p>
            """
        # Return the page to the user, adding the common html
        return header + html + footer
    response.exposed = True

if __name__ == '__main__':
    import random
    import cherrypy
    import os, sys
    # Set the current directory - this is probably not needed for this example, cruft.
    try:
        current_dir = os.path.dirname(os.path.abspath(__file__))
    except:
        # probably running inside py2exe which doesn't set __file__
        current_dir = os.path.dirname(unicode(sys.executable, sys.getfilesystemencoding( )))

    # Set up site-wide config first so we get a log if errors occur.
    # Adding the setting 'environment': 'production' to the below turns off auto-reload.
    # Otherwise CherryPy monitors the code and any change to code reloads the server - handy for development !
    cherrypy.config.update({'server.socket_port':8888,
                            'server.socket_host':'127.0.0.1',
                            'log.error_file': 'site.log',
                            'log.screen': True})
    # CherryPy will complain of an empty config but will continue
    conf = {}
    cherrypy.tree.mount(MathPoc())
    #cherrypy.config.update({'server.socket_port':8888})
    cherrypy.quickstart(MathPoc(),'/', config=conf)
Categories
Programming

Using CherryPy for webform authentication

If you are using CherryPy, I can recommend the webform-based authentication that Arnar Birgisson wrote for ease of use and extensability.

After trying out the included authentication models with CherryPy (I’m using 3.1.2, the last stable version at the moment of writing), I was disappointed in the results. Then I stumbled over a recommandation from someone on Nabble, a web-based programmar’s discussion forum, which pointed to the following wiki page on the CherryPy site:

http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions

The complete program code plus examples are on the page and are well explained.

You can have a skeleton login system (using a hardcoded dictionary) up and running in literally half an hour !

  • Just copy/paste the code on the page and save it as auth.py in your cherrypy script dir.
  • Add the hardcoded dictionary containing username and passwords to it (or script the db access, see the example included)
  • Put ‘require()’ everywhere on your cherrypy pages that need to have login protection – additionally, you can also have roles so that only admins can access certain pages.

Early last week I replaced that hardcoded dictionary and built the db lookup query for the login. Once that was working, I added a ‘my profile’ page to the application I’m working on.  Then I thought it would be nice for the admin to have a ‘create user’ form in the admin section to add users. Done that as well, using the jquery-ui to create tabs and seperate content in the admin section.

All in all, a nice week of nice work.

I’m starting to think this might make it’s way to my hosting server one of the coming weeks…  although I need to do some more work on showing the user only his keywords and not all the keywords, as well as doing something with the keywords to use them better.

Oh and one more thing: this works better under SSL than in the clear http: sky !