Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

Wednesday, December 10, 2014

pyenv Quick Start (Utunbu 14.04)

installation

Requirements

$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm

install pyenv

$ cd ~
$ git clone git://github.com/yyuu/pyenv.git .pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(pyenv init -)"' >> ~/.bashrc

install pyenv-virtualenv

$ git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv 
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
$ exec $SHELL

Common Usage (Command Reference)

List all available versions

$ pyenv version -l  

Install python2.7.8 to pyenv

$ pyenv install 2.7.8  

List installed versions

$ pyenv versions
* system (set by /home/oopsmonk/.pyenv/version)
  2.7.8
  3.4.2

Creating a virtualenv

$ pyenv virtualenv 2.7.8 mypy-2.7.8

List virtualenvs

$ pyenv virtualenvs
  mypy-2.7.8 (created from /home/oopsmonk/.pyenv/versions/2.7.8)
  mypy-3.4.2 (created from /home/oopsmonk/.pyenv/versions/3.4.2)

# current versions 
$ pyenv versions
  * system (set by /home/oopsmonk/.pyenv/version)
  2.7.8
  3.4.2
  mypy-2.7.8
  mypy-3.4.2

Use python via virtualenv

# show current version
oopsmonk@VBox:~/markdown-note$ python --version
Python 2.7.6

# Change to other version
oopsmonk@VBox:~/markdown-note$ pyenv activate mypy-2.7.8
(mypy-2.7.8)oopsmonk@VBox:~/markdown-note$ python --version
Python 2.7.8

# Deactivate
(mypy-2.7.8)oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv deactivate
oopsmonk@oopsmonk-VBox:~/markdown-note$  python --version
Python 2.7.8
# Why current version is 2.7.8? it's supposed to 2.7.6.

oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv activate mypy-3.4.2
(mypy-3.4.2) oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv deactivate
oopsmonk@oopsmonk-VBox:~/markdown-note$ python --version
Python 3.4.2

oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv versions
  system
  2.7.8
  3.4.2
  mypy-2.7.8
* mypy-3.4.2 (set by PYENV_VERSION environment variable)

# delete a virtualenv   
$ pyenv uninstall mypy-2.7.8

# Go back to original system version  
$ alias pyenv_deactivate='pyenv deactivate && unset PYENV_VERSION'
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv activate mypy-3.4.2
(mypy-3.4.2) oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv_deactivate
oopsmonk@oopsmonk-VBox:~/markdown-note$ python --version
Python 2.7.6

Use python via pyenv

# Global python version
$ pyenv global 

# python version in current folder
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv local mypy-3.4.2
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv version
mypy-3.4.2 (set by /home/oopsmonk/markdown-note/.python-version)
oopsmonk@oopsmonk-VBox:~/markdown-note$ cd ..
oopsmonk@oopsmonk-VBox:~$ pyenv version
system (set by /home/oopsmonk/.pyenv/version)
oopsmonk@oopsmonk-VBox:~$ cd -
/home/oopsmonk/markdown-note
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv version
mypy-3.4.2 (set by /home/oopsmonk/markdown-note/.python-version)
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv local --unset
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv version
system (set by /home/oopsmonk/.pyenv/version)

# python version in current shell 
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv shell mypy-3.4.2
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv version
mypy-3.4.2 (set by PYENV_VERSION environment variable)
oopsmonk@oopsmonk-VBox:~/markdown-note$ cd -
/home/oopsmonk
oopsmonk@oopsmonk-VBox:~$ pyenv version
mypy-3.4.2 (set by PYENV_VERSION environment variable)
oopsmonk@oopsmonk-VBox:~$ pyenv shell --unset
oopsmonk@oopsmonk-VBox:~$ pyenv version
system (set by /home/oopsmonk/.pyenv/version)
oopsmonk@oopsmonk-VBox:~$ cd -
/home/oopsmonk/markdown-note
oopsmonk@oopsmonk-VBox:~/markdown-note$ pyenv version
system (set by /home/oopsmonk/.pyenv/version)

Wednesday, August 7, 2013

Web dev example : JSON & jQuery Mobile & Bottle.

Bottle is a fast, simple and lightweight WSGI micro web-framework for Python.
jQuery Mobile base on jQuery for mobile device.
jQuery vs. jQuery Mobile vs. jQuery UI

Install bottle:

$ sudo apt-get install python-setuptools
$ easy_install bottle

Demo server deployment

file structure:

BottlejQuery
├── bottleJQuery.py
└── index.html

run command:

$ ./bottleJQuery.py

connect to server:

http://localhost:8080/bottle  

Building simple web server use bottle

bottleJQuery.py

#!/usr/bin/env python
from bottle import route, static_file, debug, run, get, redirect
from bottle import post, request
import os, inspect, json

#enable bottle debug
debug(True)

# WebApp route path
routePath = '/bottle'
# get directory of WebApp (bottleJQuery.py's dir)
rootPath = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))

@route(routePath)
def rootHome():
    return redirect(routePath+'/index.html')

@route(routePath + '/<filename:re:.*\.html>')
def html_file(filename):
    return static_file(filename, root=rootPath)

@get(routePath + '/jsontest')
def testJsonGET():
    print "GET Header : \n %s" % dict(request.headers) #for debug header
    return {"id":2,"name":"Jone"}

@post(routePath + '/jsontest')
def testJsonPost():
    print "POST Header : \n %s" % dict(request.headers) #for debug header
    data = request.json
    print "data : %s" % data 
    if data == None:
        return json.dumps({'Status':"Failed!"})
    else:
        return json.dumps({'Status':"Success!"})

run(host='localhost', port=8080, reloader=True)

Test GET request:

$ curl -i -X GET http://localhost:8080/bottle/jsontest

HTTP/1.0 200 OK
Date: Wed, 07 Aug 2013 16:03:53 GMT
Server: WSGIServer/0.1 Python/2.7.3
Content-Length: 25
Content-Type: application/json

{"id": 2, "name": "Jone"}

bottle debug message:

GET Header :
 {'Host': 'localhost:8080', 'Content-Type': 'text/plain', 'Content-Length': '', 'Accept': '*/*', 'User-Agent': 'curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3'}
localhost - - [08/Aug/2013 00:03:53] "GET /bottle/jsontest HTTP/1.1" 200 25

Test POST request:

$ curl -X POST -H "Content-Type: application/json" -d '{"name":"OopsMonk","pwd":"abc"}' http://localhost:8080/bottle/jsontest
{"Status": "Success!"}

bottle debug message:

POST Header :
 {'Host': 'localhost:8080', 'Content-Type': 'application/json', 'Content-Length': '31', 'Accept': '*/*', 'User-Agent': 'curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3'}
data : {u'pwd': u'abc', u'name': u'OopsMonk'}
localhost - - [08/Aug/2013 00:04:56] "POST /bottle/jsontest HTTP/1.1" 200 22

Building simple web page

Create 4 buttons in the index.html file:

  • jQuery.getJSON : use jQuery.getJSON API.
    bottle debug message:

    GET Header :
     {'Content-Length': '', 'Accept-Language': 'zh-tw,zh;q=0.8,en-us;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Host': '127.0.0.1:8080', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0', 'Connection': 'close', 'X-Requested-With': 'XMLHttpRequest', 'Referer': 'http://192.168.1.38/bottle/index.html', 'Content-Type': 'text/plain'}  
    localhost - - [08/Aug/2013 00:42:08] "GET /bottle/jsontest HTTP/1.0" 200 25
  • jQuery.post : use jQuery.post API.
    Unfortunately it's not work, because the content-Type is fixed 'application/x-www-form-urlencoded; charset=UTF-8', that's a problem when using bottle.request.json API to retrieve JSON from request.
    For this perpose we have to overwirte jQuery.post or use jQuery.ajax.
    bottle debug message:

    POST Header :
     {'Content-Length': '22', 'Accept-Language': 'zh-tw,zh;q=0.8,en-us;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Host': '127.0.0.1:8080', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0', 'Connection': 'close', 'X-Requested-With': 'XMLHttpRequest', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'Referer': 'http://192.168.1.38/bottle/index.html', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
    data : None
    localhost - - [08/Aug/2013 00:55:17] "POST /bottle/jsontest HTTP/1.0" 200 21
  • jQuery.ajax GET, jQuery.ajax POST : use jQuery.ajax API.
    GET debug message:

    GET Header :
     {'Content-Length': '', 'Accept-Language': 'zh-tw,zh;q=0.8,en-us;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Host': '127.0.0.1:8080', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0', 'Connection': 'close', 'X-Requested-With': 'XMLHttpRequest', 'Referer': 'http://192.168.1.38/bottle/index.html', 'Content-Type': 'text/plain'}
    localhost - - [08/Aug/2013 01:00:17] "GET /bottle/jsontest HTTP/1.0" 200 25

    POST debug message:

    POST Header :
     {'Content-Length': '22', 'Accept-Language': 'zh-tw,zh;q=0.8,en-us;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate', 'Host': '127.0.0.1:8080', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0', 'Connection': 'close', 'X-Requested-With': 'XMLHttpRequest', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'Referer': 'http://192.168.1.38/bottle/index.html', 'Content-Type': 'application/json; charset=utf-8'}
    data : {u'id': 3, u'name': u'Ping'}
    localhost - - [08/Aug/2013 01:01:40] "POST /bottle/jsontest HTTP/1.0" 200 22

index.html

<!DOCTYPE html>
<html>
<head>
<title>Bottle & jQuery Mobile</title>

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>

</head>

<body>
<h3>This is a example using jQuery Mobile and pyhton bottle fromwork. </h3>
<div data-role="controlgroup" data-type="horizontal">
    <a href="#" id="btnGetJSON" data-role="button">jQuery.getJSON</a>
    <a href="#" id="btnPOSTJSON" data-role="button">jQuery.post</a>
    <a href="#" id="btnAJAXGet" data-role="button">jQuery.ajax GET</a>
    <a href="#" id="btnAJAXPOST" data-role="button">jQuery.ajax POST</a>
</div>

<script>
    //button action 
    $("#btnGetJSON").click(function(){
        $.getJSON("jsontest", function(data){
            $.each(data, function(index, value){
                alert("index: " + index + " , value: "+ value);
            });
        });
    });

    $("#btnPOSTJSON").click(function(){
        alert("Not easy work on bottle !!!");
        /*
        It's not work, send JSON via jQuery.post().
        because the content-Type is not 'application/json',
        The content type is fixed :
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
        that's a problem on bottle.request.json.
        */

        $.post(
        "jsontest", 
        JSON.stringify({"id":3, "name":"Ping"}), 
        function(ret_data, st){
            $.each(ret_data, function(index, value){
                alert("index: " + index + " , value: "+ value);
            });
            alert("Server return status : " + st); 
        },
        'json'
        );
    });

    $("#btnAJAXGet").click(function(){
        $.ajax
        ({
            url: 'jsontest',
            success: function(data){
                $.each(data, function(index, value){
                    alert("index: " + index + " , value: "+ value);
                });
            },
            /*
            if dataType not set, the Accept in request header is:
            'Accept': '* / *'
            dataType = json :
            'Accept': 'application/json, text/javascript, * /*; q=0.01'
            */
            dataType: 'json'
        });
    });

    $("#btnAJAXPOST").click(function(){
        var post_data = {"id":3, "name":"Ping"};
        $.ajax
        ({
            type: 'POST',
            url: 'jsontest',
            data:JSON.stringify(post_data),
            contentType: "application/json; charset=utf-8",
            dataType: 'json',
            success: function(data){
                $.each(data, function(index, value){
                    alert("index: " + index + " , value: "+ value);
                });
            }
        });
    });
</script>
</body>
</html>

Wednesday, July 31, 2013

Sending HTML Mail Using SMTP With Authorization

Here is a text/plain MIME type parts in official exmaple code.
I remove it from my sample code, because it's not show up in mail at Office Outlook 2010.

#!/usr/bin/env python
"""
File name: sendMail.py
Python send HTML mail using SMTP with authorization

Usage :
./sendMail.py to@gmail.com Subtitle [ FilePath | txt ]
"""

import smtplib
import sys,traceback
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from time import gmtime, strftime

#log file location
log_path = "./mail-log";
#log timestamp format
logger_tstamp = "%Y-%m-%d %H:%M:%S"

#SMPT server
smtp_server = "smtp.gmail.com"
#gmail 465 or 578
smtp_port = 587

#mail from 
user = "from@gmail.com"
pwd = "password"

# log method
class Logger:
    file = 1
    err = 2

class ContentType:
    file = 1
    txt = 2

#select log method 
debug_log = Logger.err
#select content type
content_type = ContentType.txt

def debug(msg):
    if debug_log == Logger.file:
        with open(log_path, 'a') as log_file:
            log_file.write(strftime(logger_tstamp, gmtime()) + msg)
        log_file.close()

    elif debug_log == Logger.err:
        sys.stderr.write(strftime(logger_tstamp, gmtime()) + msg)

    else: 
        print(strftime(logger_tstamp, gmtime()) + msg)

#check argument number
arg_count = len(sys.argv)
if arg_count !=4:
    debug("[Error]: invalid argument\n")
    sys.exit(1)
try:
    mail_to = sys.argv[1]
    subject = sys.argv[2]
    if content_type == ContentType.file:
        content_path = sys.argv[3]
        with open(content_path, 'r') as f_content:
            content = f_content.read()
        f_content.close()
    else:
        content = sys.argv[3]

    serv = smtplib.SMTP(smtp_server, smtp_port)
#    serv.ehlo()
    serv.starttls()
#    serv.ehlo()
    serv.login(user, pwd);
    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = user
    msg['To'] = mail_to
    part1 = MIMEText(content, 'html')
    msg.attach(part1)
    serv.sendmail(user, mail_to, msg.as_string())
    serv.quit()
    debug("[Debug] subject : " + subject + "\n")
except:
    debug("[Error]: send mail error\n")
    debug("[Error]:\n" + traceback.format_exc())
    sys.exit(2);

Reference:
email: Examples
smtplib
How to send email in Python via SMTPLIB

Monday, May 27, 2013

Web Micro Framework Battle

WSGI Micro Framworks

這陣子一直在找適合的Micro Framwork玩第一次的Web Application.
最後選擇用Bottle, 原因是:

  • Single file module, no dependencies with other library.
  • Document

但是好不好用又是另一回事, 用了就知道..XD

以下是由WSGI.org列出的Micro Framwork:

  • bobo
    Bobo is a light-weight framework. Its goal is to be easy to use and remember.

  • Bottle
    Bottle is a fast and simple micro-framework for small web-applications. It offers request dispatching (Routes) with url parameter support, Templates, key/value Databases, a build-in HTTP Server and adapters for many third party WSGI/HTTP-server and template engines. All in a single file and with no dependencies other than the Python Standard Library.

  • Flask
    Flask is a microframework for Python based on Werkzeug, Jinja 2 and good intentions. It inherits its high WSGI usage and compliance from Werkzeug.

  • Pyramid
    Merger of the Pylons and repoze.bfg projects, Pyramid is a minimalist web framework aiming at composability and making developers paying only for what they use.

  • web.py
    Makes web apps. A small RESTful library.

Micro Framworks Battle

Rank Framwork Point
1 Bottle 7
2 pesto 6
3 itty 4
4 flask, cgi+wsgiref 3
5 werkzeug 2
6 web.py 1
7 cherrypy 0
8 bobo -7
9 aspen.io -5

Reference :
Web Micro Framework Battle 1
Web Micro Framework Battle 2

Tuesday, May 21, 2013

uWSGI & Nginx on Ubuntu

Install uWSGI

Configure uWSGI

$ sudo apt-get install python-dev python-pip  
$ sudo pip uwsgi  
################# uWSGI configuration #################  
pcre = False  
kernel = Linux  
malloc = libc  
execinfo = False  
ifaddrs = True  
ssl = True  
matheval = False  
zlib = True  
locking = pthread_mutex  
plugin_dir = .  
timer = timerfd  
yaml = True  
json = False  
filemonitor = inotify  
routing = False  
debug = False  
zeromq = False  
capabilities = False  
xml = expat  
event = epoll  
############## end of uWSGI configuration #############  
*** uWSGI is ready, launch it with /usr/local/bin/uwsgi ***  
Successfully installed uwsgi  
Cleaning up...  
$  

Test uWSGI

Create test file called hello.py:
def application(env, start_response):  
    start_response('200 OK', [('Content-Type','text/html')])  
    return "Hello WSGI!!"  
Run uWSGI:
uwsgi --http :8000 --wsgi-file hello.py  
Open browser connect on port 8000.
http://localhost:8000

Install Nginx

Configure nginx

$ sudo apt-get install nginx-full  
The configure file path : /etc/nginx/sites-enabled/default Add your site in nginx configure file.
    location /wsgi/ {
            uwsgi_pass 127.0.0.1:8001;
            include uwsgi_params;
    }  
Use localhost port 8001 for uwsgi protocol, and 80 port for nginx. Run uwsgi and start nginx.
$ uwsgi --socket :8001 --wsgi-file hello.py  
$ sudo service nginx start  
Test your web site:
http://your-ip/wsgi/  
or
http://localhost/wsgi/
Ref:
uWSGI Tutorial - Django and nginx
WSGI using uWSGI and nginx on Ubuntu 12.04 (Precise Pangolin)