Kokoropy

心から MVC Web Framework in Python

Setting

Installation

Kokoropy is a python web framework. Therefore you need to have python (recommended python 2.7) installed in your computer.

Linux & MacOS user does not need to worry anything since those OS have python pre-installed by default. Windows user should download and install python. Personally, I suggest you to use Enthought Canopy Distribution since it already has some libraries such as numpy & matplotlib.
If you are using debian-based linux (such as ubuntu)

Optional steps

Kokoropy built with scientific purpose on mind. Some examples are depended on already famous libraries, such as numpy, scikit-learn, and matplotlib. To install those libraries, you can do:

            pip install numpy
            pip install matplotlib
            pip install sklearn
        

If you are using python 3, you will need to install `python3-beaker` package

            pip install beaker
        

Mandatory steps

Download kokoropy from github repository here, or clone it by using git

            git clone git@github.com:goFrendiAsgard/kokoropy.git
        

After All prerequisites met, you can just start kokoropy by using this command:

            cd path/to/kokoropy
            python rossian.py start
        

Now, open up your browser, and type

            http://localhost:8080
        

in the address bar

Kokoropy's Directory Structure

Don't worry This is just informational, you don't have to do anything

Just like every MVC framework, kokoropy has a typical directory structure. At the development stage, you only need to pay attention to /applications directory (this is where your applications laid)

            kokoropy
                |--- /applications                THIS IS WHERE YOUR APPLICATIONS LAID
                |       |--- __init__.py          * application's bootstrap
                |       |
                |       |--- /example             * example application
                |       |       |--- __init__.py  * application's __init__.py
                |       |       |--- /assets      * application's static files
                |       |       |--- /models      * application's models
                |       |       |--- /controllers * application's controllers
                |       |       |--- /views       * application's views
                |       |       |--- routes.py    * application's routes
                |       |
                |       |--- /index               * index application
                |       |       |--- __init__.py  * application's __init__.py
                |       |       |--- /assets      * application's static files
                |       |       |--- /models      * application's models
                |       |       |--- /controllers * application's controllers
                |       |       |--- /views       * application's views
                |       |       |--- routes.py    * application's routes
                |       |
                |       |--- /[your_application]  * your application
                |       |       |--- __init__.py  * application's __init__.py
                |       |       |--- /assets      * application's static files
                |       |       |--- /models      * application's models
                |       |       |--- /controllers * application's controllers
                |       |       |--- /views       * application's views
                |       |       |--- routes.py    * application's routes
                |
                |--- /kokoropy                    THIS IS WHERE KOKOROPY'S CORE LAID
                |       |--- __init__.py          * __init__.py
                |       |--- /beaker              * beaker package
                |       |--- /sqlalchemy          * sqlalchemy package
                |       |--- /alembic             * alembic package
                |       |--- bottle.py            * bottle module
                |       |--- kokoro.py            * kokoropy's main program
                |
                |--- /db                          DATABASE EXAMPLE
                |
                |--- README.md                    DOCUMENTATION & TUTORIAL
                |
                |                                 DEVELOPMENT & DEBUGGING
                |--- rossian.py                   * script to manage kokoropy
                |
                |                                 HEROKU DEPLOYMENT FILES
                |--- heroku.sh                    * heroku command example
                |--- heroku_app.py                * bootstrapper for heroku
                |--- Procfile                     * heroku specific file
                |--- runtime.txt                  * heroku specific file
                |--- requirements.txt             * heroku specific file
        

In kokoropy, every application should contains __init__.py file.

The same rule is also applied to application's models and controllers directory. You should also put an __init__.py inside each of them.

Rossian (Script generator and more)

Building everything from scratch is such a pain. Therefore, some frameworks provide generator scripts. FuelPHP has oil, Laravel has artisan, Django has manage.py, Ruby on Rails has rails.

In kokoropy, we have rossian.py, a smart, cute, little script that help you do most of things better and faster. You can do:

            python rossian.py
        

to see how it works.

Currently, here is a list of commands that might be useful

              VERSION: 0.0.1

              USAGE:

              * Help
                 python rossian.py help

              * Run Server
                 python rossian.py start [--host=localhost --port=8080 --server=kokoro --baseurl=/ --runtimepath=.runtime --debug --reload]

              * Scaffold Application
                 python rossian.py scaffold-application APPLICATION-NAME

              * Scaffold Migration
                 python rossian.py scaffold-migration APPLICATION-NAME MIGRATION-NAME [table-name] [column-name:type] ... 

              * Scaffold Model
                 python rossian.py scaffold-model APPLICATION-NAME [table-name] [column-name:type] ... 

              * Scaffold CRUD
                 python rossian.py scaffold-crud APPLICATION-NAME [table-name] [column-name:type] ... 

              * Scaffold View (to make custom CRUD view)
                 python rossian.py scaffold-view APPLICATION-NAME [table-name] [view]

              * Scaffold CMS
                 python rossian.py scaffold-cms 

              * Migration upgrade (to the newest version)
                 python rossian.py migration-upgrade [APPLICATION-NAME]

              * Migration downgrade (to the previous version)
                 python rossian.py migration-downgrade APPLICATION-NAME

              * List of migration applied
                 python rossian.py migration-log

        

Trivia: rossian.py was named after my smart and cute ex-girlfriend, Rossian Vinatha. She was always encourage and help me to do many new things (including ride a motorbike) better. We were in relationship since 2013-12-09, and we've just broke up at 2014-08-04. That was unfortunate. I still hope her to get back, but more of it, I hope her to find her happiness.

Coding

Simple Hello world

Okay, let's try your first hello world program

First, do:

            python rossian.py scaffolding-application demo
        

This will make demo directory inside your applications

            kokoropy
                |--- /applications
                |       |--- __init__.py
                |       |
                |       |--- /demo                * (1. Make demo directory)
                |       |       |--- __init__.py  * (2. Make __init__.py)
                |       |       |--- routes.py    * (3. Make routes.py)
              (...)   (...)
        

Now, edit your routes.py and put this:

We hope the code is already self-explanatory, but if you still need some explanation, here is:

  • Line 1 : Import route decorator and base_url function which will be used later.
    base_url is used to get absolute url. For example base_url('hello') will return http://localhost:8080/kokoropy/hello
  • Line 3 - 7 : Declare say_something function. This function return string, depends on name parameter.
    If name is empty, the function will return a warm How do you do message, otherwise, it will return a welcome How are you message, along with the name
  • Line 9 - 14 : Declare urls tupple. The tupple contains several elements. Each element contains of a pair or url and function associated with the url

Important : The tupple should be named urls. This tupple is used to wrap bottle route decorator. To get more comprehensive documentation about route decorator, please visit Bottle's documentation about request routing

MVC and Automatic Routing

You might need something more complex than just a typical "hello world" program.
It's not good to put everything in routes.py, since it will be to complicated to be maintained.
Here is where MVC rocks. MVC stands for Model, View, Controller.

  • Model is the heart of your application. It define what an application can do. Imagine it as a bunch of functions which are ready to be used anytime. Model is usually, but not neccesaryly associated to database. People tend to write their database scripts (either using ORM or raw SQL) in model.
  • Controller is a gateway of your application. It define how user can interact with your application. A request from client wil be delivered to your controller. The controller then do some action, and call some routines defined in the model. And as visual feedback, controller will load a view and return it as response.
  • View (or Template) is a visual matter. You should put your HTML, javascript, and css here.

Let's make your first MVC in kokoropy. At the end of this section, you will be able to access these url:

  • http://localhost:8080/kokoropy/demo/pokemon and get all pokemon
  • http://localhost:8080/kokoropy/demo/pokemon/pi and get pokemon which it's name contains 'pi'
            kokoropy
                |--- /applications
                |       |--- __init__.py
                |       |
                |       |--- /demo                              * ( 1. Make demo directory)
                |       |       |--- __init__.py                * ( 2. Make __init__.py)
                |       |       |--- routes.py                  * ( 3. Make routes.py)
                |       |       |--- /models                    * ( 4. Make models directory)
                |       |       |       |--- __init__.py        * ( 5. Make __init__.py)
                |       |       |       |--- my_model.py        * ( 6. Make my_model.py)
                |       |       |--- /controllers               * ( 7. Make controllers directory)
                |       |       |       |--- __init__.py        * ( 8. Make __init__.py)
                |       |       |       |--- my_controller.py   * ( 9. Make my_controller.py)
                |       |       |--- /views                     * (10. Make views directory)
                |       |       |       |--- my_view.tpl        * (11. Make my_view.py)
                |       |       |--- /assets                    * (10. Make assets directory)
                |       |       |       |--- uploads            * (11. Make uploads directory)
              (...)   (...)
        

Model

Put this in my_model.py:

Since we are using SQLALchemy's ORM and a custom Model code, there are many things you don't need to write by yourself.
If you don't like (or not ready to use) ORM, you can also use classical SQL approach. SQL Alchemy supporting both ORM & classical SQL approach. Please check SQL Alchemy documentation for more information. Now, here is some explanation of the code:

  • Line 1 - 2 : Import some SQL-Alchemy's functions and classes.
  • Line 3 : Import kokoropy's Model base.
  • Line 4 : Import connection_string from configuration.
  • Line 6 - 7 : Make engine and session
  • Line 9 - 13 : Pokemon Class, inherited from Base and Mixin. It has 2 properties mapped to column, name and image.
  • Line 15 : Make the real table for the first time, otherwise you should use migration.

Controller

Put this in my_controller.py:

Here is the explanation

  • Line 1 - 2 : Import things we will need later, including Pokemon model.
  • Line 4 - 8 : Make an autoruted controller. Every autorouted controller should extend Autoroute_Controller.
  • Line 6 - 8 : Get pokemon_list, pass it to my_view view, and give the response whenever user accessing http://localhost:8080/kokoropy/my_controller/pokemon.

Every function in autorouted controller with action_, prefix will be published, and accessible with this url format:

            BASE_URL/application_name/controller_name/function_without_prefix
        

You can also use post_, get_, put_, and delete_ prefix. These prefixes are work with REST request.

Beware : Autoroute controller might looks to be fun, and it is recommended when you are on development stage. Also, it will feels familiar, if you came from CodeIgniter. However, for real-world usage, we suggest to use manual routing via routes.py. Manual routing allow you to change the url freely without touching your controller logic (and code) at all.

View

Put this in my_view.tpl:

Here we get our pokemon_list from the controller, and present it to our visitor in table. In kokoropy, Simple Template Engine is used to render the view.

  • Line 10 - 21 : Show Pokemon list.
    Kokoropy use enchanced Simple Template Engine. To get more information about Template Engine, please visit http://bottlepy.org/docs/dev/stpl.html.
    Here is a brief example to see what you can do with simple template engine:
                        % name = "Bob"  # a line of python code
                        <p>Some plain text in between</p>
                        <%
                          # A block of python code
                          name = name.title().strip()
                        %>
                        <p>More plain text</p>
                    
  • Line 24 : Call rebase function to set index/views/base as parent template

Aside from simple template engine behavior, kokoropy also provide block by using {% block block_name %} and {% endblock %} (similar to jinja2).
The blocks also support inheritance, so that you can use {% parent %} inside your child block.

Since the database is empty, you won't be able to see anything. when running this demo.
In this case, open up db/demo.db, add some data, put some images on applications/demo/assets/uploads.

Manual Routing

As we say, put autoroute controller is great for development, however sometime you need more "expressive" routing. Here is where you need manual routing. To enable manual routing, first open up your previously created controller, and remove this part:

            class My_Controller(Autoroute_Controller):
        

with this:

            class My_Controller(obj):
        

and put this in your routes.py

  • Line 2 - 3 : import My_Controller and make an instance of it
  • Line 5 - 10 : define several request routing that should be handled by my_controller.action_pokemon

More ...

Post, Get, Cookie, and Session

Custom Hook and Error

Sometime people want to define their own hook and error message. Do this is very easy, as easy as define manual routing.

  • Line 1 - 14 : Define several functions for hook and error
  • Line 16 - 25 : Define hooks and erros tupples. These tupples are used to define hook and error message redirection

Use matplotlib

Deployment

Apache

This is how to deploy kokoropy on apache web server (assuming you use ubuntu or debian):

  • Install mod-wsgi: sudo apt-get install libapache2-mod-wsgi.
  • Enable mod-wsgi: sudo a2enmod wsgi.
  • Create wsgi script /path/to/kokoropy/kokoro.wsgi.
  • Create apache configuration file /etc/apache2/sites-available/kokoro.apache_conf (For other OS, please append this file contents to httpd.conf)

                        <VirtualHost *>
                            # replace this with your absolute path to kokoropy
                            DocumentRoot /absolute/path/to/kokoropy
                            # server name, usually localhost, but you can also use another alias if DNS set correctly
                            ServerName localhost
    
                            WSGIDaemonProcess kokoropy user=www-data group=www-data processes=1 threads=5
                            # replace this with your absolute path to kokoropy + kokoro.wsgi location
                            WSGIScriptAlias / /absolute/path/to/kokoropy/kokoro.wsgi
                            # absolute path to kokoropy
                            <Directory /absolute/path/to/kokoropy>
                                WSGIProcessGroup kokoropy
                                WSGIApplicationGroup %{GLOBAL}
                                Options ExecCGI
                                Order deny,allow
                                Allow from all
                            </Directory>
    
                        </VirtualHost>
                    
    Adjust some values as follows:
    • Replace every /absolute/path/to/kokoropy with your kokoropy directory location.
    • In case of you already have php installed, please don't use localhost as ServerName. Use another valid ServerName instead.
    • You can add valid ServerName by add a line at /etc/hosts (e.g: 127.0.1.1 arcaneSanctum will add arcaneSanctum as valid ServerName).
    • Note, that by default apache will greedily take over every request and left nothing to be handled by your application. If you are using ubuntu/debian, modify /etc/apache2/sites-enabled/000-default.
      Change this part <VirtualHost *:80> into <VirtualHost localhost:80>
  • Enable this configuration by doing: sudo a2ensite kokoro.apache_conf.
  • Reload your apache by using sudo service apache2 reload. If it does not work, restart your apache by using sudo service apache2 restart.

Heroku

This is how to deploy kokoropy on heroku (assuming you use ubuntu):

  • Make heroku account, and visit https://devcenter.heroku.com/articles/python for more detail instruction
  • get and install heroku toolbelt by using this command: wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh. For other OS, please visit the heroku website for more information.
  • init a git repo by using this command: git init
  • Add several files in your kokoropy directory:
    • runtime.txt
                                  python-2.7.4
                              
    • requirements.txt
                                  argparse==1.2.1
                                  distribute==0.6.24
                                  gunicorn==17.5
                                  wsgiref==0.1.2
                                  numpy==1.7.0
                                  matplotlib==1.1.0
                                  scipy==0.11.0
                              
    • Procfile
                                  web: python heroku_app.py
                              
    • heroku_app.py
  • login to heroku (make sure you already have an account on heroku.com) by using this command: heroku login
  • Set up heroku with a special buildpack (needed for matplotlib demo) by using this command: heroku create --buildpack https://github.com/dbrgn/heroku-buildpack-python-sklearn/
  • If you do not need matplotlib at all, just do heroku create
  • If you have already do heroku create but change your mind later, and think that you need matplotlib, do this: heroku config:set BUILDPACK_URL=https://github.com/dbrgn/heroku-buildpack-python-sklearn/
  • make heroku_app.py executable by using this command chmod a+x heroku_app.py
  • detect all changes and deploy by using commit & push
                        git add . -A
                        git commit -m "Initial commit for heroku deployment"
                        git push heroku master