Tip dan Trik

8. Tip dan Trik

Penulis: Noprianto

8.1 Pelajarilah source code OpenERP

Melengkapi dokumentasi yang telah disediakan, apabila diperlukan, kita selalu dapat mempelajari source code OpenERP, pada bagian tertentu yang kita ingin tahu lebih lanjut.

Sebagai contoh, kita akan menjalankan server OpenERP dari source code: $ ls

debian LICENSE openerp.egg-info README setup.py doc MANIFEST.in openerp-server setup.cfg setup_rpm.sh install openerp PKG-INFO setup.nsi win32

Mari kita fokus pada subdirektori openerp: $ ls openerp

addons import_xml.rng netsvc.py release.py tests cli __init__.py osv report tools conf loglevels.py PKG-INFO service workflow exceptions.py modules pooler.py sql_db.py

Perhatikanlah bahwa ini adalah package Python dan kita bisa menemukan apa yang kita seringkali gunakan seperti package osv:

$ ls openerp/osv/ expression.py fields.py __init__.py orm.py osv.py query.py

Sebagaimana yang kita lakukan dalam import: $ PYTHONPATH=./openerp python

Python 2.7.6 (default, Mar 22 2014, 22:59:38) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from openerp.osv import orm, fields >>>

Dengan demikian, apabila kita ingin tahu lebih lanjut tentang ORM misalnya, kita dapat membaca file openerp/osv/orm.py.

Lebih lanjut, dalam mengembangkan modul OpenERP kita sendiri, kita umumnya bergantung pada addon base. Mari kita perhatikan subdirektori openerp/addons:

$ ls openerp/addons/base base_data.xml base.sql i18n module res static $ ls openerp/addons/base base_data.xml base.sql i18n module res static

Apabila kita ingin mengetahui lebih banyak tentang model res.partner misalnya, kita dapat pula membacanya dari file openerp/addons/base/res/res_partner.py.

Mempelajari source code program sebesar OpenERP tentu saja tidak mudah. Oleh karena itu, kita umumnya harus fokus pada bagian tertentu dulu. Walaupun ini juga tidak mudah, kita selalu bisa mencoba/memulai dari yang paling sederhana dulu. Begitu kita sudah lebih terbiasa, proses ini akan terasa lebih cepat dan nyaman.

Selain dokumentasi yang dituliskan pada source code (termasuk komentar), seringkali kita bisa terbantu dengan membaca isi fungsi.

8.2 Generate file konfigurasi

Ketika menjalankan server OpenERP, kita dapat meminta untuk menghasilkan template file konfigurasi dan langsung keluar dari program.

Sebagai contoh, kita akan menjalankan server OpenERP dari source code: $ ls

debian LICENSE openerp.egg-info README setup.py doc MANIFEST.in openerp-server setup.cfg setup_rpm.sh install openerp PKG-INFO setup.nsi win32

Script openerp-server dapat digunakan untuk menjalankan server. Opsi -s dapat diberikan untuk menghasilkan file konfigurasi, yang secara default, akan disimpan pada

~/.openerp_serverrc. Sebagai contoh: $ ./openerp-server -s

2014-08-11 19:51:35,062 4337 INFO ? openerp: OpenERP version 7.0-20140724-231255 … … … [CTRL-C]

$ file ~/.openerp_serverrc /home/c2/.openerp_serverrc: ASCII text

Padukanlah opsi -s dengan -c untuk menyimpan file konfigurasi yang dihasilkan pada file lain. Sebagai contoh, kita ingin menghasilkan file konfigurasi dan menyimpannya pada file config.ini di direktori aktif:

$ ./openerp-server -s -c config.ini 2014-08-11 19:54:54,445 4409 INFO ? openerp: OpenERP version 7.0-20140724-231255 … … … [CTRL-C]

$ file config.ini config.ini: ASCII text

Padukanlah lagi dengan opsi --stop-after-init agar program langsung keluar setelah menghasilkan file konfigurasi.

$ ./openerp-server -s -c config.ini --stop-after-init 2014-08-11 19:58:22,589 4533 INFO ? openerp: OpenERP version 7.0-20140724-231255 …

8.3 Lebih dari satu lokasi addons

Seringkali, kita ingin mengumpulkan semua addons yang kita bangun pada direktori tersendiri, dan tidak bercampur dengan addons yang datang bersama OpenERP ataupun pihak lainnya.

Ini juga akan sangat membantu ketika dalam proses pengembangan, dimana kita tidak perlu selalu mengopikan apa yang kita bangun ke direktori addons tertentu agar dapat dikenal oleh OpenERP.

Sebagai contoh, kita akan menjalankan server OpenERP dari source code: $ ls

debian LICENSE openerp.egg-info README setup.py doc MANIFEST.in openerp-server setup.cfg setup_rpm.sh install openerp PKG-INFO setup.nsi win32

Direktori addons secara default adalah: $ ls -1 openerp/addons/ | head -n5

account account_accountant account_analytic_analysis account_analytic_default account_analytic_plans

Untuk menginformasikan lokasi addons, kita bisa menggunakan salah satu dari dua cara berikut: • File konfigurasi: variabel addons_path, atau • Opsi ketika menjalankan server OpenERP: opsi --addons-path

Lokasi-lokasi addons diberikan dengan dipisahkan oleh koma. Sebagai contoh /path/addons/1,/path/addons/2.

8.4 Pustaka notation dan notasi prefix/postfix

Untuk kriteria pencarian pada OpenERP (pengembangan), notasi yang dipergunakan adalah Polish notation, yang dikenal juga dengan prefix notation (notasi prefix). Pada notasi ini, operator ditempatkan di depan/kiri operan.

Sebagai contoh pada notasi infix: 1+2 Akan dituliskan sebagai berikut pada notasi prefix: +12 Berbeda pula apabila dituliskan pada notasi postfix: 12+ Dengan notasi prefix/postfix, kita tidak perlu menggunakan kurung untuk pengelompokan. Sebagai contoh pada OpenERP, kita akan mencari dari res.partner, untuk:

• nama yang mengandung 'tes' (tidak case-sensitive) atau untuk id < 3 • dan • website = ''

Perhatikanlah bahwa karena menggunakan Polish Notation, maka operator or '|' dan and '&' ditempatkan di depan.

Pertama-tama, kita menyusun untuk kriteria pertama (or): '|', ('name', 'ilike', 'tes'), ('id', '<', 3) Setelah itu, kita gabungkan dengan kriteria kedua (and): '&', '|', ('name', 'ilike', 'tes'), ('id', '<', 3), ('website', '=', '')

Dan, kita tempatkan pada sebuah list: ['&', '|', ('name', 'ilike', 'tes'), ('id', '<', 3), ('website', '=', '')]

Bagi yang tertarik lebih lanjut dengan notati prefix secara umum (tidak spesifik OpenERP), kita bisa pula mempergunakan pustaka notation, yang dikembangkan oleh Noprianto, salah satu anggota tim penulis buku ini, dan dapat didownload dari https://github.com/nopri/notation . Pustaka ini hanya berisikan satu file, yaitu notation.py. Pada saat buku ini ditulis, versi pustaka adalah 0.01.

Pustaka notation berisikan evaluator sederhana untuk notasi prefix dan postfix. Tersedia fungsi bantu dan sebuah class yang dapat diturunkan.

Contoh sederhana menggunakan fungsi bantu untuk notasi prefix: >>> import notation

>>> notation.simple_prefix_notation('+ 1 2') 3.0 >>> notation.simple_prefix_notation('* + 1 2 3') 9.0 >>> notation.simple_prefix_notation('- * + 1 2 3 4') 5.0 >>> notation.simple_prefix_notation('** - * + 1 2 3 4 5') 3125.0 >>> notation.simple_prefix_notation('/ ** - * + 1 2 3 4 5 6') 520.8333333333334 >>>

Contoh sederhana menggunakan fungsi bantu untuk notasi postfix: >>> notation.simple_postfix_notation('1 2 +')

3.0 >>> notation.simple_postfix_notation('1 2 + 3 *') 9.0 >>> notation.simple_postfix_notation('1 2 + 3 * 4 -') 5.0 >>> notation.simple_postfix_notation('1 2 + 3 * 4 - 5 **') 3125.0 >>> notation.simple_postfix_notation('1 2 + 3 * 4 - 5 ** 6 /') 520.8333333333334 >>>

Apabila kita ingin mengurangi, menambahkan atau mengubah operator, kita bisa menurunkan dari class SimplePrefixPostfixNotation. Pada contoh pertama, kita hanya mengenal operator +.

>>> import operator >>> from notation import SimplePrefixPostfixNotation >>> >>> class LimitedPrefixPostfixNotation(SimplePrefixPostfixNotation): ... def __init__(self, reverse=False): ... self.OPERATORS = {'+': operator.add} ... self.reverse = reverse ... >>> >>> o = LimitedPrefixPostfixNotation() >>> print o.evaluate('+ 1 2') 3.0 >>> print o.evaluate('* + 1 2 3') None >>>

Pada contoh kedua, kita menggunakan karakter 'x' (bukan '*') sebagai operator kali. >>> class AnotherPrefixPostfixNotation(SimplePrefixPostfixNotation):

... def __init__(self, reverse=False): ... SimplePrefixPostfixNotation.__init__(self, reverse) ... self.OPERATORS.pop('*') ... self.OPERATORS['x'] = operator.mul ... >>> >>> o = AnotherPrefixPostfixNotation() >>> print o.evaluate('+ 1 2') 3.0 >>> print o.evaluate('* + 1 2 3') None >>> print o.evaluate('x + 1 2 3') 9.0 >>> '''

Dalam pustaka notation ini, evaluator diimplementasikan menggunakan stack, dimana list dipergunakan sebagai stack. Untuk prefix, ekspresi akan diproses dari belakang.

Berikut adalah cuplikan fungsi evaluate0 class SimplePrefixPostfixNotation. Apabila reverse adalah True, maka dimaksudkan adalah notasi postfix.

def evaluate0(self, expression): stack = []

e = str(expression).split() if not self.reverse:

e = e[- 1 ::- 1 ]

for i in e:

if i not in self.OPERATORS.keys():

n = float(i)

# ValueError

if not self.reverse: stack.append(n) else :

stack.insert( 0 , n)

else : o1 = stack.pop() #IndexError o2 = stack.pop() #IndexError res = self.OPERATORS.get(i)(o1, o2)

if not self.reverse: stack.append(res) else :

stack.insert( 0 , res)

return stack

Fungsi evaluate hanya membantu saja:

def evaluate(self, expression): res = None try : res = self.evaluate0(expression) if not len(res) == 1 : raise Exception

res = res[ 0 ]

except : pass return res

Constructor class:

def __init__(self, reverse= False ): self.OPERATORS = { '+' : operator.add, '-' : operator.sub, '/' : operator.truediv, '*' : operator.mul, '%' : operator.mod, '**' : operator.pow,

self.reverse = reverse

Dan, fungsi-fungsi bantu diimplementasikan dengan cara: def simple_prefix_notation(expression):

o = SimplePrefixPostfixNotation() return o.evaluate(expression)

def simple_postfix_notation(expression): o = SimplePrefixPostfixNotation(reverse= True ) return o.evaluate(expression)

8.5 Lisensi pada modul OpenERP

Ketika kita mengembangkan suatu modul OpenERP, kita dapat menentukan string lisensi dalam file manifest __openerp__.py. Sebagai contoh:

{ 'name' : 'Test' , 'version' : '1.0' , 'license' : 'GPL' , 'author' : 'noprianto' , 'description' : 'Test' , 'category' : 'Buku' , 'website' : 'https://github.com/id-python/buku-openerp' , 'depends' :[ 'base' ],

Ketika melakukan update module list, terdapat pesan kesalahan ValidateError sebagai berikut: The value "GPL" for the field "ir_module_module.license" is not in the selection Apabila kita ubah license menjadi sesuatu yang lain, misal Public Domain: {

'name' : 'Test' , 'version' : '1.0' , 'license' : 'Public Domain' , 'author' : 'noprianto' , 'description' : 'Test' , 'category' : 'Buku' , 'website' : 'https://github.com/id-python/buku-openerp' , 'depends' :[ 'base' ],

} Kita akan menjumpai pesan kesalahan serupa: The value "Public Domain" for the field "ir_module_module.license" is not in the selection Untuk memahami pesan kesalahan tersebut, kita perlu lihat ke dalam file

openerp/addons/base/module/module.py, dimana license didefinisikan sebagai berikut:

'license' : fields.selection([ ( 'GPL-2' , 'GPL Version 2' ), ( 'GPL-2 or any later version' , 'GPL-2 or later version' ), ( 'GPL-3' , 'GPL Version 3' ), ( 'GPL-3 or any later version' , 'GPL-3 or later version' ), ( 'AGPL-3' , 'Affero GPL-3' ), ( 'Other OSI approved licence' , 'Other OSI Approved Licence' ),

( 'Other proprietary' , 'Other Proprietary' ) ], string= 'License' , readonly= True ),

Sehingga, salah satu pilihan yang bisa kita lakukan adalah mengubah string lisensi ke yang dikenal.

8.6 Perubahan pada file python dalam modul

Dalam pengembangan, apabila kita melakukan perubahan pada file python (.py) dalam modul (termasuk upgrade), kita dapat melakukan restart server OpenERP agar perubahan yang dilakukan dapat berefek.

8.7 Menampilkan pesan kesalahan

Walaupun kita bisa menggunakan atribut _constraints untuk membantu memastikan nilai input adalah valid, ada kalanya kita ingin menampilkan pesan kesalahan sendiri.

Untuk kebutuhan tersebut, kita bisa membangkitkan exception except_orm yang didefinisikan di dalam modul orm.py:

class except_orm(Exception): def __init__(self, name, value): self.name = name self.value = value self.args = (name, value)

Sebelumnya, kita akan import _ dari openerp.tools.translate. from openerp.tools.translate import _

Dan, exception bisa dibangkitkan seperti contoh berikut: >>> from openerp.osv import orm

>>> from openerp.tools.translate import _ >>> >>> raise orm.except_orm(_('Judul'), _('Pesan Kesalahan')) Traceback (most recent call last):

File "<stdin>", line 1, in <module> openerp.osv.orm.except_orm: ('Judul', 'Pesan Kesalahan')

8.8 Format tanggal/waktu

Apabila kita perlu melakukan format atau parsing tanggal/waktu, kita dapat mempergunakan konstanta berikut, yang didefinisikan di dalam file openerp/tools/misc.py.

DEFAULT_SERVER_DATE_FORMAT = "%Y-%m-%d" DEFAULT_SERVER_TIME_FORMAT = "%H:%M:%S" DEFAULT_SERVER_DATETIME_FORMAT = "%s %s" %(

DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_TIME_FORMAT)

File misc.py tersebut diimport oleh __init__.py: from misc import *

Contoh: >>> from openerp.tools import DEFAULT_SERVER_DATE_FORMAT

>>> from openerp.tools import DEFAULT_SERVER_TIME_FORMAT >>> from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT >>> >>> DEFAULT_SERVER_DATE_FORMAT '%Y-%m-%d' >>> DEFAULT_SERVER_TIME_FORMAT '%H:%M:%S' >>> DEFAULT_SERVER_DATETIME_FORMAT '%Y-%m-%d %H:%M:%S' >>> >>> import time >>> time.strftime(DEFAULT_SERVER_DATETIME_FORMAT) '2014-08-15 19:03:20' >>> time.strptime('2014-08-15', DEFAULT_SERVER_DATE_FORMAT) time.struct_time(tm_year=2014, tm_mon=8, tm_mday=15, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=227, tm_isdst=-1) >>>