theduke hari 1

Apakah ada cara untuk belajar pemrograman selain dengan membuat sebuah
project? oleh karena itu setelah membaca specifikasi wsgi, maka saya
memutuskan untuk membuat sebuah blog engine project dengan menggunakan
python dan wsgi.

blog engine ini akan saya namankan project ‘theduke’, bukan duke
maskot Java, akan tetapi theduke, diilhami oleh nama anak buah Jet
dari film animasi Avatar.

Senjata yang digunakan:

  1. werkzeug

    Kenapa harus werkzeug?, tidak ada alasn khusus, saya hanya
    tertarik dengan namanya saja.Tentu saja, ada calon kuat yang lain
    diantaranya adalah webob, akan tetapi saya melihat werkzeug lebih
    sederhana daripada webob/paste.

  2. sqlalchemy

    Kalo yang ini tidak harus ditanyakan.

  3. jinja

    Tutorial werkzeug banyak menggunakan Jinja, jadi saya pilih Jinja
    saja.

Ada pertanyaan, kenapa tidak menggunakan framework yang sudah jadi
saja, seperti django? hmm, django adalah framework yang bagus, tapi
untuk project ini saya cenderung lebih ke antiframework. werkzueg
sendiri berfungsi seperti glue (lem) yang menghubungkan antara model
dan view. Dan juga sepertinya untuk newbie seperti saya, lebih baik
belajar dari bawah (dalam hal ini lebih ke wsgi).

Untuk project theduke, paling tidak ada beberapa model dasar, yaitu:

  • post
  • author
  • tag
  • comment

dimana hubungan antara model-model tersebut antara lain:

  • one-to-many : author -> post
  • one-to-many : post ->comment
  • many-to-many: post ->tag

berikut ini adalah module database yang menggambarkan table, object,
dan mapper antara table dan object.

#table author
author_table = Table('authors',metadata,
                     Column('id',Integer,primary_key=True),
                     Column('username',String(255),nullable=False,unique=True),
                     Column('password',String(255)),
                     Column('email',String(255),nullable=False,unique=True))

#table post
post_table = Table('posts',metadata,
                   Column('id',Integer,primary_key=True),
                   Column('author_id',Integer,ForeignKey('authors.id')),
                   Column('content',Text),
                   Column('title',String(255)),
                   Column('slugs',String(255),unique=True),
                   Column('excerpt',Text),
                   Column('status',Integer),
                   Column('comment_status',Integer(3)),
                   Column('created',DateTime,default=datetime.datetime.now()),
                   Column('updated',DateTime,default=datetime.datetime.now(),onupdate=datetime.datetime.now()))

#table comment
comment_table = Table('comments',metadata,
                      Column('id',Integer,primary_key=True),
                      Column('author_name',String(255),nullable=False),
                      Column('author_email',String(255),nullable=False),
                      Column('author_url',String(255),nullable=False),
                      Column('author_content',Text),
                      Column('post_id',Integer,ForeignKey('posts.id')))

#table tag
tag_table = Table('tags',metadata,
                  Column('id',Integer,primary_key=True),
                  Column('tag_string',String(255),nullable=False),
                  Column('slugs',String(255),nullable=False))

#table for many to many post and tag
post_tag_table = Table('post_tag',metadata,
                       Column('post_id',Integer,ForeignKey('posts.id')),
                       Column('tag_id',Integer,ForeignKey('tags.id')))

class Author(object):
    pass

class Post(object):
    def __init__(self,title,content,excerpt="",status=0,comment_status=0):
        self.title = title
        self.content = content
        self.excerpt = excerpt
        self.status = status
        self.comment_statut = comment_status
        self.slug_title()

    def slug_title(self):
        self.slugs = self.title.replace(" ","-")


class Comment(object):
    pass

class Tag(object):
    def __init__(self,tag_string):
        self.tag_string = tag_string
        self.create_slugs()

    def create_slugs(self):
        if not self.tag_string:
            raise Exception

        self.slugs = self.tag_string.replace(' ','-')



mapper(Author,author_table,
       properties={'posts':relation( Post, backref='author' )})

#one to many with comments
#many to many with tags
mapper(Post,post_table,
       properties={'comments':relation(Comment, backref='post'),
                   'tags':relation(Tag,secondary=post_tag_table,backref='posts')})

mapper(Comment,comment_table)
mapper(Tag,tag_table)

saya juga membuat sebuah fungsi test

def test(db_uri='sqlite:///test.db'):
    """
    This is just for testing
    """
    engine = create_engine(db_uri)
    metadata.drop_all(bind=engine)
    metadata.create_all(bind=engine)
    Session = sessionmaker(bind=engine)

    #create post
    p = Post("this is a hello world","Hello world")

    t = Tag("tag")
    t1 = Tag("tag2")

    p.tags.append(t)
    p.tags.append(t1)

    session = Session()
    session.save(p)
    session.commit()

    #qtag = session.query(Tag)
    #qtag = session.query(Post)
    return session

dan test langsung dari python console

 c = theduke.database.test()
 d = c.query(theduke.database.Tag)

langkah selanjutnya? Routing

mengenal WSGI

Tentang WSGI

Apa itu WSGI

wsgi::
Web Server Gateway Interface

untuk membuat standard interface antara web aplikasi yang dibuat
dengan python dengan web server.
WSGI mempunyai dua sisi:

  1. sisi server
  2. aplikasi / framework
  3. WSGI pada dasarnya hanya sebuah referensi interface yang harus
    diimplementasi baik oleh server maupun oleh applikasi, sehingga
    sebuah applikasi yang mengimplementasi wsgi dapat di-deploy,
    diserver mana saja asalkan server itu juga mengimplementasi WSGI
    interface.

    Ini dapat dibandingkan dengan dunia java, dimana banyak terdapat web
    framework, akan tetapi web framework itu bisa diapplikasikan di java
    web server mana saja, karena baik web framework maupun java web
    server mengimplentasi JavaEE interface yang salah satunya adalah
    servlet.

    Cara Kerja WSGI

    Server berhubungan dengan applikasi dengan memanggil sebuah callable
    (baik itu fungsi maupun object) yang disediakan oleh
    applikasi. callable itu mempunyai dua buah argumen yaitu environ dan
    start_response. Environ berupa python dictionary sedangkan
    start_response berupa fungsi.

    Sedangkan applikasi berhubungan dengan server, dengan mengirimkan
    header (dapat diartikan sebagai http header), dan memanggil
    start_response dan memberi argumen http response dan http header,
    kemudian mengembalikan list python yang berisi response. Agak
    membingunkan bila cuma membaca spesikasi, akan lebih mudah bila kita
    melihat contohnya

     def application(environ, start_response):
        "Contoh Sederhana dari WSGI Application"
        status = "200 OK"
        headers = [("Content-type","plain/text")]
        start_response(status,headers)
        return ['Hello world !\n']
      
    

    dari contoh diatas, bisa kita lihat bagaimana applikasi berhubungan
    dengan server, dimana applikasi mengirimkan status dan header dengan
    menggunakan fungsi start_response, dan mengembalikan body response
    kepada server.

    Middleware

    Yang dimaksud dengan middleware, adalah sebuah komponen python, yang
    mempunyai dua fungsi sebagai server, sekaligus sebagai
    applikasi. Pada awalnya memang membuat bingung, bagaimana bisa
    sebuah component dapat berfungsi sebagai server sekaligus sebagai
    aplikasi?.
    Jadi bila sebuah komponen berfungsi sebagai middleware, maka dia
    bertindak sebagai penengah/buffer/pembungkus dari applikasi
    lain. Jadi server tidak akan memanggil fungsi dari wsgi dari
    aplikasi,akan tetapi memanggil fungsi wsgi dari komponen middleware,
    yang nantinya akan memanggil fungsi wsgi dari applikasi.
    Middleware itu sendiri bisa merubah keluaran dari applikasi,
    melakukan routing dan berbagai macam hal lainnya.
    Contoh code dari Middleware

    class Upperware:
       def __init__(self, app):
          self.wrapped_app = app
    
       def __call__(self, environ, start_response):
          for data in self.wrapped_app(environ, start_response):
             return data.upper()
    
      
    

    contoh diatas , akan merubah keluaran dari aplikasi yang dibungkus
    middleware, menjadi huruf besar semua.

    contoh penggunaan:

      wrapped_app = Upperware(simple_app)
      serve(wrapped_app)
      
    

    Isi dari Environ

    Environ sendiri adalah sebuah dictionary yang berisi key dan value
    yang berasal dari CGI environment.

    berikut ini beberapa key yang terdapat pada environ:

    REQUEST_METHOD

    HTTP method, dapat berupa post atau get ataupun HTTP method lainya.
    SCRIPT_NAME

    PATH_INFO

    QUERY_STRING

    Query String

    CONTENT_TYPE

    CONTENT_LENGTH

    SERVER_NAME, SERVER_PORT

    SERVER_PROTOCOL

    HTTP_ Variables

    referensi
    http://python.org/dev/peps/pep-0333/
    WSGI Gateway or Glue

python dan glob

Hari ini saya mencari cara mudah untuk melakukan iterasi terhadap file-file yang ada di folder.

O ya, karena sedang belajar python, maka saya mencari cara untuk hal diatas dengan menggunakan python style

setelah membaca manual, maka kita dapat menggunakan modul os. Yang kita butuhkan terdapat dalam perintah listdir.

import os

listfile = os.listdir(‘.’)

Akan tetapi, bila kita ingin membuat list yang hanya berisi file jpg, paling tidak harus melakukan langkah kedua

import os

listfile = os.listdir(‘.’)
listjpg = [x for x in listfile if x.endswith(‘jpg’)]

Ternyata terdapat cara(module) lain yang dapat melakukan hal diatas dengan cara yang lebih mudah, module tersebut adalah glob.

import glob

glob.glob(‘*.jpg’)

me and BeanShell

Recently I got an assignment to fool around with a java library, Since I
kind in bad mood, I was thinking a way to fool around with an easy
way, not using code, compile, see because it’s just too much work. So
I remember about java scripting, there are lot of scripting in java
today, here some of it bsh, groovy, jacl, jython, rhino and others.

So I’ve to pick up one from many, I started with bsh, since the
syntax resembling java syntax with some improvement (pre java 5.0). So
I started to download it [ in ubuntu bsh already in synaptix ], and
start to playing around with it.

my first problem is how to add a jar to bsh classpath, luckily in bsh
documentation, there is a command to add jar into classpath,
here’s my snippet

BeanShell 2.0b4 - by Pat Niemeyer (pat@pat.net)
bsh % addClassPath("lib/my.jar");
addClassPath("lib/my.jar");
bsh %

after that, I smoothly played around with the API. so bsh can be a
tool for black-box testing, and I quite satisfied using it. I know
that the other scripting can be use for it, but for now I keep with
bsh for black box testing.

TCL & uplevel

perintah uplevel digunakan untuk menjalankan perintah2 yang berada di
stack frame yang berbeda, stack frame telah dijelaskan di
https://inthegarage.wordpress.com/2007/06/13/tcl-upvar/,

Mungkin lebih baik langsung pada contoh

proc a {} {
    set x 10
    set y 20

    b
}

proc b {} {
    uplevel 1 {set x 20; puts "nilai dari x : $x"}
    uplevel 1 {incr x 20}
    uplevel 1 {puts $x}
}

dan hasilnya adalah sebagai berikut

%a
nilai dari x : 20
40
% 3

contoh lain dari penggunaan uplevel adalah untuk mengkustomisasi
struktur, misalnya adalah perintah loop yang tidak terdapat pada tcl,
misalnya syntax dari loop adalah loop 1 0 {..}, maka implementasinya
adalah

proc loop {from to body} {
    for {set var $from} {$var < $to} {incr var} {uplevel 1 $body}
}

perintah uplevel pada loop untuk menjalankan perintah pada body, yang
mempunyai 1 level lebih tinggi daripada perintah loop.

TCL & upvar

berdasarkan tcl manual, perintah upvar berguna untuk membuat link
(?hubungan?) ke variabel yang berada pada stack yang berbeda. Syntax
dari perintah upvar sendiri adalah sebagai berikut :

upvar ?level? otherVar myVar ?otherVar myVar ...?

Berdasarkan definisi diatas akan menimbulkan pertanyaan lain, apakah
yang dimaksud dengan lingkup stack (stack frame) yang berbeda?
untuk mengetahui lebih jelasnya, misalkan kita membuat method a, dan
didalam method a tersebut kita memanggil method b, ketika method a
dibuat, maka tcl akan membuat stack frame untuk method a dimana
seluruh local variabel akan disimpan, dan ketika memanggil method b
maka tcl akan membuat lagi stack frame untuk method b, sehingga method
a dan b mempunyai stack frame yang berbeda, dan juga method a dan b
mempunyai level yang berbeda dimana method a mempunyai level 1 (bila
diasumsikan method a dipanggil dari lingkup global), sedangkan method
b mempunyai level 2.
Untuk mengetahui level dari method/procedure dapat digunakan perintah

info level.

Karena method a dan b mempunyai stack frame yang berbeda maka method b
tidak dapat mengaksed variabel yang berada pada method a, nah perintah
upvar dapat membuat method b untuk mengakses variabel yang terdapat
pada method a.

proc top {} {
    set x 10
    bottom
    puts "setelah memanggil bottom $x"

}

proc bottom {} {
   upvar 1 x localx
   incr localx 20
}

setelah kita panggil top

% top 20
setelah memanggil bottom 30
%

selain itu perintah upvar berguna untuk mengimplementasikan
call-by-name procedure, contohnya adalah sebagai berikut.


proc top {topArg} {
    set localArg [expr $topArg+1]
    puts "before calling bottom is : $localArg"
    bottom localArg
    puts "after calling  is : $localArg"
}

proc bottom {bottomArg} {
    upvar $bottomArg arg
    puts "bottom is passed $bottomArg with value $arg"
    incr arg
}

hasilnya bila kita panggil top 30

top 30
before calling bottom is : 31
bottom is passed localArg with value 31
after calling  is : 32

TCL & Scopes

Tcl mempunyai 2 jenis variabel scope (atau mungkin bila diterjemahkan
menjadi lingkup :P).

  • global
  • global variabel dapat diakses diseluruh script, akan tetapi sebuah
    prosedur/method dapat melakukan overshadow global variabel dengan
    mendefinisikan variable lokal dengan nama yang sama.

  • lokal
  • lokal variabel hanya dapat diakses dalam lingkup sebuah fungsi.

bila didalam fungsi/method ingin menggunakan variabel global, maka
kita menggunakan peringah global, berikut ini adalah contoh dari
program yang menggunakan lokal dan global variabel.

set a 10
set b 20

puts "$a $b"

proc test_scope {} {
    global a
    set a "me good"
    set b "but I feel not good"
    puts "$a $b"

}

test_scope
puts "Nilai dari a sekarang : $a"
puts "Nilai dari b sekarang : $b"

hasilnya adalah sebagai berikut.

% source scope.tcl
10 20
me good but I feel not good
Nilai dari a sekarang : me good
Nilai dari b sekarang : 20
%

dapat dilihat pada fungsi test_scope, bahwa global variabel a, dapat
digunakan apabila kita menggunakan perintah global terlebih dahulu.