無為閣

不及格學士後研究

PgRest Learning Guide - Introduction

What is PgRest

[Warring] PgRest is still in a very early stage, anything described here could be changed.

To enable rest in PostgreSql.

In short, PgRest - is a JSON document store. - runing inside PostgreSql - working with existing relational data - capable of loading Node.js modules - compatible with MongoLab’s REST API - = LiveScript + Plv8 + Plv8x + Express

Example:

1
2
3
4
5
6
7
$ pgrest --db tcp://postgres@localhost/mydb 
Available collections:
users bookmarks webpages news tags        inbox 
Serving `tcp://postgres@localhost/mydb` on http://0.0.0.0:3000/collections

$ curl localhost:3000/collections/users
{"paging":{"count":1,"l":30,"sk":0},"entries":[{"provider_name":"facebook","provider_id":"1231795847","username":"hychen","display_name":null,"name":{"familyName":"Chen","givenName":"Hsin","middleName":"Yi"},"emails":[{}],"photos":null,"_id":1}]}%   

LiveScript

LiveScript is a language which compiles to JavaScript. It has a straightforward mapping to JavaScript and allows you to write expressive code devoid of repetitive boilerplate. While LiveScript adds many features to assist in functional style programming, it also has many improvements for object oriented and imperative programming.

Plv8 - Use JavaScript In PostgresSQL

PLV8 is a shared library that provides a PostgreSQL procedual language powered by V8 JavaScript Engine.

With this program you can write in JavaScript your function that is callable from SQL.

Supported features are:

  • Functions can receive any arguments, and return a value or set of records.
  • Execute any SQL commands with built-in plv8.execute() function.
  • Automatic data conversion between PostgreSQL and JavaScript, including string, numbers, timestamps, arrays, and records.
  • Records are converted to JSON which keys are column names.
  • Other types are converted to strings.
  • Partial support to write TRIGGER handlers.
  • Inline commands with DO statement for PG 9.0 or newer versions.
  • EXTENSION support for PG 9.1 or newer versions.

plv8x - Helpers for managing plv8 javascript modules

It Supports:

  • Importing nodejs modules and creating user functions
  • Calling conventions for user functions

Setup in debian/ubuntu

Add postgresql apt repository. You need to change squeeze to your distribution codename. You can get your system codename by lsb_release -c.

1
sudo sh -c "echo deb http://apt.postgresql.org/pub/repos/apt/ squeeze-pgdg main > /etc/apt/sources.list.d/postgresql.list"

Add apt repository key

1
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -

Update and install packages

1
2
$ sudo apt-get update
$ sudo apt-get install postgresql-9.2 postgresql-9.2-plv8 postgresql-server-dev-9.2

Update postgresql configuration

Edit /etc/postgresql/9.2/main/pg_hba.conf. Remove the line local all postgres peer, and add the following lines.

1
2
3
#local   all             postgres                                peer
local   all             postgres                                trust
host    all             postgres        127.0.0.1/32            trust

Restart postgresql service

1
sudo service postgresql restart

Test postgresql

make sure you could access psql console.

1
psql -U postgres

Create test database

1
createdb mydb -U postgres

Create plv8 extension in the database

1
psql -U postgres -c "create extension plv8"

Install Pgrest

1
$ sudo npm install pgrest -g

Run Pgrest

1
2
$ pgrest --db tcp://postgres@localhost/mydb
$ curl localhost:3000/collections 

if there is no error in the response of curl, then your pgrest is all set.

How does PgRest work?

PgRest exposed all tables in schema public to restful endpoints with a collections prefix.

For example, a table named users will be mapped to http://localhost:3000/collections/users endpoint and maps HTTP Request methods to pgrest CURD(create, update, read, delete) functions as the following.

  • HTTP Get to pgrest_select
  • HTTP POST to pgrest_insert
  • HTTP PUT to pgrest_upsert
  • HTTP DELETE to pgrest_delete

pgrest CURD functions are LiveScript functions for manipulate data in a table or tables in PostgreSql by embedded in a PostgreSql SQL procedure.

  • pgrest_select - get an entity or entities.
  • pgrest_insert - add an entity
  • pgrest_upsert - update an entity or entities
  • pgrest_delete - delete an entity

Example: insert a json to a existent table.

1
2
3
4
5
6
7
8
9
10
11
// assign a json to user variable
user = do
    provider_name: profile.provider
  provider_id: profile.id
  username: profile.username
  name: profile.name
  emails: profile.emails
  photos: profile.photos

// insert a json as a row 
[pgrest_insert:res] <- plx.query "select pgrest_insert($1)", [collection: \users, $: [user]]

So, with plv8, plv8x, we could import node.js module, define javascript functions, use javascript functions in database, manipulate json in databse. with pgrest, we could maps http CURD to database CURD.

Thus, we could almost move all business logic to database level,

Yap, until now, I did not explain authorization and authentication in PgRest. Those are not current supported in PgRest tunk now, but I am going to explain how to implement it in next chapter.

利用 Vagrant 開發 g0v.tw 專案

前言

因為每次 g0v.tw 黑客松時,鄉民都化太多時間在設定專案開發環境,所 以後來有個發想,看能不能用 Vagrant簡化這些步驟。

什麼是 Vagrant

Vagrant 是 VirtualBox,這類虛擬機器的自動化程式,ihower 在OSDC.TW 演講的投影片 - A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩已介紹 得很完整,如果沒聽過Vagrant可以先看完投影片再繼續。

使用流程

這邊以在linux或mac下開發 hack.g0v.tw 為例, Windows 的使用者可以看這篇

下載專案源碼跟 g0v專用Vagrant Box.

[note] 請使用 1.2版以上

事先先把 VirtualBox 跟 Vagrant 裝好,再打開Sehll執行下面的指令即可.

1
$ git clone git@github.com:g0v/hack.g0v.tw.git

準備開始開發,啟動VM

hack.g0v.tw 的 Vagrantfile 已經有指定 g0v custom box 的位置了,所以你 只需要跑 vagrant up即可。

1
2
$ cd hack.g0v.tw
$ vagrant up

這樣 hack.g0v.tw 的工作環境就準備好了,打開瀏覽器連到localhost:6987就 可以看到hack.g0v.tw的網頁。(web server 在vm執行)。

部份專案可能需要自己import box, 請使用下列指令

1
$ vagrant box add g0v https://dl.dropboxusercontent.com/u/4339854/g0v/g0v-ubuntu-precise64.box

工作完畢,關掉VM

1
$ vagrant suspend

如何製作 Base Box

Ubuntu 官方有提供 Cloud Image的 Vagrant Box, 所以若沒什麼太特別的需求, 可以這個做為Base, 再自己寫一個 Vagrantfile 重新 package 一個新的Box.

1
2
$ vagrant add cloud-precise64
http://cloud-images.ubuntu.com/precise/current/precise-server-cloudimg-vagrant-amd64-disk1.box

產生Vagrantfile

1
$ vagrant init

修改一些設定,決定VM啟動後要做什麼事

1
$ vi Vagrantfile

啟動VM

1
$ vagrant up

將當前VM重新打包

1
$ vagrant package --output g0v-ubuntu-precise64.box

幹掉目前啟動的VM

1
$ vagrant destroy

如何撰寫給專案用的 Vagrantfile

執行vagrant init 會得到一個Vagrantfile的樣板, Vagrant 支援 shell, chef, puppet 做自動化佈署,但如果專案不是太複雜, 用 shell 就差不多了。

像 hack.g0v.tw 要做的只是開機後,切到專案原碼目錄去跑安裝程式。Vagrantfile of hack.g0v.tw

1
2
3
4
5
6
7
8
9
10
11
# a known issue that symbolic link can not be created in virtualbox
#  shared fold
# we have to workround npm modules installaltion.
  $script = <<SCRIPT
  cp -arf /vagrant /tmp
  cd /tmp/vagrant
  npm i
  cp -r node_modules /vagrant
  cd /vagrant
  npm run start
  SCRIPT

註: 因為在Shared Fold裡面不能建立symbolic link,所以 npm module安裝 可 能會失敗,目前我的解法是先把Shared Fold 複製到某個地方,裝完後再把裝好 的函式庫放回去。

Binding and Assignment

所謂的 Functional Language 的變數不可改其實是不精確的。實際上它只是將變數分的更嚴謹,可修改,與不可修改。

先來說說什麼是 Binding. Binding 指的是將一個符號綁定在一個值,綁定後就不可修改,這個符號稱之為變數。以自然語言來理解的話,其實就是代名詞。

favonia: 一個變數沒有指到一個值。一個變數可以被一個值取代,但不會儲存什麼內容在裡面。

所以說下面這個例子, 必須理解為3.14的另一個稱呼叫做 PI, 而不是 PI 這個容器的值是 3.14。而 1 + PI 這個式子的另一個稱呼是 result, 而不是 1 + PI 運算後,將值放到 result 這個容器裡。 不管是PI,還是 result 都只是個代稱,而不是容器。

1
2
PI = 3.14
result = 1.0 + PI

接下來搭配 SML 來解釋什麼是 Assignment。 下面這段 code 是說 PI 是 3.14的binding, result 是 1 + PI 的binding。 程式執行時(runtime) 會把 PI 這個變數代換成3.14。

1
2
val PI = 3.14
val result = 1.0 + PI

那如果需要可修改的變數怎麼辦,SML 可以讓變數綁在值的的指標上, ref 3.14 指的是 3.14 這個值得指標指標。而因為指標指定的值是可以變的,所以現在 PI 可以當成是可以修改的。 PI := 4 只是讓 PI 的值(也就是指標) 從 3.14 指到 4,並不會產生新的binding。

1
2
3
val PI = ref 3.14 # binding
val result = 1.0 + PI # binding
val PI := 4 # assign

因此,在所有的 imperative language 裡,不管是Python, Ruby, C, Java, 變數其實都是被綁在指標上,這樣變數指到的值才能被修改。

所以說,變數只是個值的代稱,如果值是指標,那麼就可以修改指標要指到哪個 值,反之則不行。 但不管怎麼說,變數都不應該被當成是一個容器。

台南SA10月份 - Be Pythonic

好幾年答應CYJ在SA講一場,結果到了他退伍後我都沒講過一次 XD 這次透過CYJ,而有機會在台南SA分享, 簡報呢,一樣是依照慣例在演講前晚開 始趕工, 結果大綱跟之前宣傳的完全不一樣。

為什麼會這樣呢? 我想主要是之前列的大綱還是太過highlevel, 所以我很難將 他轉成簡報, 後來我在網路上找到一份CC license 的投影片,便以之為基底製 作.

由於沒講過3小時的Talk, 所以很怕講不到三小時,因此投影片弄到快100張,結 果當天講到2/3,且第二段的decorator幾乎是用帶過去的。

後來Jserv 跟我分享了一下演講的技巧,其實我簡報可以不用這麼多,只需要列 出當天要講的大綱,之後在臨場發揮就可以了。

anyway, 附上投影片,這次的主題是 Be Pythonic, 主要是說明寫python時,怎 樣會比較像在寫python,而不是其他語言。

PyCon.JP 2012

今年一樣又投了(PyCon.JP 2012)1,跟往年不一樣這次比較偏重Python本身的 特性,而非介紹自己的專案這類應用性質比較高的主題。

這次去的台灣人不少,大概有11個人吧,包括我在內則有3個人有給Talk。 地點則跟去年一樣,還是在品川大,議程跟參加人數都較往年多,甚至多了一軌 專門給英文演講。

還滿喜歡這種邊演講邊旅行的生活,但是好累啊 XD

最後附上投影片, 主要是說明Python 的 Type 跟 Object

Coscup 2012 簡報檔釋出

因為看錯時間把30分鐘要講得東西在20分鐘內說完,所以前20分鐘很多東西都快速帶過, 後10分鐘都在補講。 節奏被打亂得亂七八糟。 然後,下台後馬上就被 Thinker 說我塞太多東西在30分鐘內了。

用來說明概念的素材

Create a new instance of an object

Python

(coscup2012_new_instance.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

# To define a class object
class MyClass(object):

  def __init__(self, instance_attr):
      self.attr = instance_attr;   

# MyClass's constructor
print MyClass.__init__

# MyClass's Class is type
print type(MyClass)

# To create a new instance of 
# MyClass 
obj = MyClass.__new__(MyClass)

# To initial the new instance 
MyClass.__init__(obj, 'Attr bound on the instance')

# The result is Attr bound on the instance
print obj.attr

# The base class of MyClass is <type 'object'>
print MyClass.__base__


obj = MyClass('hi')
print obj.attr

JavaScript

(coscup2012_new_instance.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*                                                                                                                                                                                             
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
*/

// To define a function object as a Class
function MyClass(instance_attr){
  this.attr = instance_attr;
}

// To bind this to new instance and then execute MyClass
// function.
obj = new MyClass('Attr Bound on the instance');

// The output is Attr Bound on the instance
console.log(obj.attr);

// create a new instance of MyClass prototype
// run MyClass to initial obj
obj2 = Object.create(MyClass);

// The output is No!!!
MyClass.call(obj2, 'No!!!');

// The output is Attr Bound on the instance
console.log(obj2.attr);

// MyClass's constructor is [Function: MyClass]
console.log(MyClass.constructor);

// MyClass's prototype is Object
console.log(typeof(MyClass));

// The prototype of function object is {}, so
// the prototype of MyClass and instances of MyClass
// is also {}
console.log(MyClass.prototype);
console.log(obj.__proto__);

Base Object

Python

(coscup2012_base_obj.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
class NewBase(object):
  pass

class MyClass(object):
  pass

obj = MyClass()

# Use NewBase class to instead of object class, 
# but __base__ is readonly 
MyClass.__base__ = NewBase

obj2 = MyClass()

JavaScript

(coscup2012_base_obj.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*                                                                                                                                                                                         # Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
*/
function MyClass(){
}

obj = new MyClass();

// undefined
console.log(obj.name);

// change prototype to another object 
MyClass.prototype = {'name':'hello'}

obj2 = new MyClass();

// The result is still undefiend
console.log(obj.name);

// But this attribute of new instance is redirect to new prototype
console.log(obj2.name);

Trace Object Creation

JavaScript

(coscup2012_traceObj.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* 
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
*/

// Add logger function to functions of prototype
function logged(proto){
  for(prop in proto){
      var fn = proto[prop];
      proto[prop] = function(){
          console.log('-> Enter ' + prop);
          show_args(arguments);
          var ret = fn(arguments[0]);
          console.log('   Return: ' + ret);
          console.log('-> Exit ' + prop);
          return ret;
      };
  }
  return proto;
}

function show_args(args){
  for(var i=0; i<args.length;i++){
      console.log('      args:' + args[i]);
  }
}

function tail(list){
  var ret = new Array();
  for(var i=1;i<list.length;i++){
      ret[i-1] = list[i];
  }
  return ret;
}

// create traceable object based on a object
function new_traced_obj(base_obj){
  myargs = tail(arguments);
  console.log(base_obj.name);
  // create new function object
  var traced_obj = function(){
      console.log('-> Enter constructor');
      show_args(myargs);
      // execute base object constructor
      // on new instance of traced object.
      console.log('     -> Enter ' + base_obj.name);
      base_obj.call(this, myargs[0]);
      console.log('     -> Exit  ' + base_obj.name);
      console.log('<- Exit constructor');
  };
  // set new object's prototype is the base object 
  // prototype
  traced_obj.prototype = logged(base_obj.prototype);
  console.log('-> Enter - create new instance');
  // create new instance of sub object
  var new_inst = new traced_obj();
  console.log('<- Exit  - create new instance');
  return new_inst;
};

// To define a MyClass Function
function MyClass(name){
  this.name = name;
}

// Add add5 function to MyClass's prototype
MyClass.prototype.add5 = function(num){return num+5;};

// Main
instance = new_traced_obj(MyClass, 'M');
console.log('instance.name:'+instance.name);
console.log('=============================');
console.log('instance.add5(3,4): '+instance.add5(3,4));

My Slide ‘What Can Meta Class Do for You’ in PyCon Taiwan 2012

I had a chance to sharing my study notes of meta class in PyCon Taiwan 2012. It is a 30 minuts talk. The topic is roughly to introduce 5 examples to show meta class is useful and also to gave a conculution that why we use/don’t use it.

the slide is here:

Example Codes

Singleton

(metaclass_Singleton.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
# -*- encoding=utf8 -*-
#
# Author 2012 Hsin-Yi Chen
class Singleton(type):
    def __init__(cls,name,bases,dic):
        super(Singleton,cls).__init__(name,bases,dic)
        cls.instance=None

    def __call__(cls, *args, **kwargs):
            print "please use get_instance function to get the instance"

    def get_instance(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
        return cls.instance

class _db(object):
    """
    >>> obj=_db()
    please use get_instance function to get the instance
    >>> obj is None
    True
    >>> obj1 = _db.get_instance()
    connecting to 0
    >>> obj2 = _db.get_instance()
    >>> id(obj1) == id(obj2)
    True
    """
    __metaclass__ = Singleton
    session_max = 0

    def __init__(self):
        print 'connecting to {0}'.format(self.session_max)

class MySQL(_db):
    """
    >>> obj1 = MySQL.get_instance()
    connecting to 1000
    >>> obj2 = MySQL.get_instance()
    >>> id(obj1) == id(obj2)
    True
    """
    session_max = 1000

import doctest
doctest.testmod()

Countable

(metaclass_countable.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

# Goal: Class knows the count of its instances.

# metaclass
class Countable(type):

    def __new__(mbs, name, bases, dct):
        cls = type.__new__(mbs, name, bases, dct)
        cls.count = 0
        return cls

    def __call__(cls, *args, **kwargs):
        cls.count += 1
        type.__call__(cls, *args, **kwargs)


# class
class Book(object):
    __metaclass__ = Countable

    def __init__(self, title):
        self.title = title

# run
print 'I have {} books'.format(Book.count)
a=Book('A1')
b=Book('A2')
c=Book('A3')
d=Book('A4')
print 'I have {} books'.format(Book.count)

Class Verification

(metaclass_verification.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
def check(cls, inf):
    for attrname in inf.__dict__:
        if attrname.startswith('__'):
            continue
        if not attrname in cls.__dict__.keys():
            msg = 'ERROR: Can not find {} in {}'.format(attrname,
                                                cls.__name__)
            msg = msg.format(cls.__name__, inf.__name__, attrname)
            print msg

class JokeRequirement(object):
    HaHaPoint = None

class HasInterface(type):
    def __new__(mbs, name, bases, dct):
        interface = dct['__implemented__']
        cls = type.__new__(mbs, name, bases, dct)
        check(cls, interface)
        return cls

class JokeRequirement(object):
    HaHaPoint = None

class JokeInPTT(object):
    __metaclass__ = HasInterface
    __implemented__ = JokeRequirement

Delegation

(metaclass_delegation.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
class Delegated(type):

    def __new__(mbs, name, bases, dct):
        cls = type.__new__(mbs, name, bases, dct)
        def myget(self, k):
                return getattr(self.context, k)
        def myset(self, k, v):
            if not hasattr(self, 'context'):
                self.__dict__['context'] = v
            if k != 'context':
                setattr(self.context, k, v)
        cls.__getattr__ = myget
        cls.__setattr__ = myset
        return cls

class Wrapper(object):
    __metaclass__ = Delegated
    def __init__(self, context):
        self.context = context

    def dump(self):
        print 'the data is ' + repr(self.data)

class Result(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

result = Result(title='man ages', data=[1,2,3,4,5])
wrap_result = Wrapper(result)
wrap_result.dump()
wrap_result.title = 'girl args'
print result.title

Logged

(metaclass_logged.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

# Goal: Log informations to other places.
def info(msg):
    print 'info:'+msg
def error(msg):
    print 'error:'+msg

import functools

# To create a wrapped function
def log(name, fn):
    @functools.wraps(fn)
    def wrap_fn(*args, **kwargs):
        info('Enter func:{}'.format(name))
        try:
            ret = fn(*args, **kwargs)
        except Exception, e:
            error('Raised exception: {}'.format(e.message))
            raise e
        info('Got return value:{}'.format(ret))
        info('Exit func:{}'.format(name))
        return ret
    return wrap_fn

# Add logger decorator for each attr
def add_logger(name, val):
    return callable(val) and log(name, val) or val

# Metaclass
class Logged(type):

    def __new__(mbs, name, bases, dct):
        # if attr is callable log it.
        dct = {k:add_logger(k, v) for k,v in dct.items()}
        cls = type.__new__(mbs, name, bases, dct)
        return cls

# Class
class Person(object):
    __metaclass__ = Logged

    def get(self):
        return "I am get method"

# Run!
if __name__ == '__main__':
    obj =  Person()
    obj.get()

Serialized Python Function Object

想法

利用marshal把python bytecode轉成string, 就可以pickled.

把Function轉成Pickled string

1
2
3
4
5
6
7
8
import pickle
import marshal
maintask_bytecode = marshal.dumps(maintask_callback.func_code)
output = {
  'maintask_bytecode': maintask_bytecode,
  'maintask_defaults': maintask_defaults,
  'maintask_args': maintask_args}
print pickle.dumps(output)

把Pickled string轉成function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sys
import types
import marshal
import pickle
## \brief reconstruct function from bytecode
#  \param func_bytecode str marshaled bytecode of func_code
#  \param func_default dict func_defaults
#  \return Function
def reconstruct_function(func_bytecode, func_defaults):
    func_code = marshal.loads(func_bytecode)
    return types.FunctionType(func_code, globals(), func_code.co_name,
                             func_defaults)
string = sys.stdin.read()
received = pickle.loads(string)
callback = reconstruct_function(received['maintask_bytecode'],
      received['maintask_defaults'])
print callback(maintask_args)

Fix Chromium Can Not Play Mp4

I found my chromium in Ubuntu 11.10 can not play mp4 video. after I googling, the solution is to install chromium-codecs-ffmpeg-extra to solve these problems.

$ apt-get install chromium-codecs-ffmpeg-extra

How to Create a Custom Launchpad Bugs Report

I already use lp-cli to generate reports about one month and think this may benefit someone has the same requirmentation. so here you are.

This document will show

  • howto collected bugs data with custom search conditions
  • combine collected bugs data and report template

comments are welcome.