RapidSMS 開發者指南/編碼規範和文件
文件對於每一塊程式碼都很重要,但對 RapidSMS 來說更為重要。
由於 RapidSMS 和大多數為其開發的應用程式的開放性,以及其背後的開發重點和社群,因此非常需要重用和改進。
適當的文件是讓您的應用程式被社群重用和改進的必要條件。
RapidSMS 社群遵循 PEP8 編碼規範。它是一種如何編寫程式碼的約定,可以確保程式碼的可讀性和易於貢獻。
該標準寫得很好,請閱讀它。以下是一些重點
- 行不應超過 79 個字元
- 檔案末尾沒有新行
- 運算子前後各有一個空格
- 類或函式之前有 2 行間隔
此外,除了 PEP8 標準,RapidSMS 還要求每個檔案在 shebang 之後包含格式化和編碼註釋。因此,您的檔案應始終以以下內容開頭
#!/usr/bin/env python # vim: ai ts=4 sts=4 et sw=4 coding=utf-8
實際符合 PEP8 程式碼的示例
def handle(self, message):
if not re.match(r'^ping( +|$)', message.text.lower()):
return False
identifier_match = re.match(r'^ping (?P<identifier>.+).*$', \
message.text.lower(), re.U)
if not identifier_match:
identifier = False
else:
identifier = identifier_match.group('identifier')
if self.disallow:
return False
if self.allow or \
(self.allowed and self.allowed.count(message.peer) > 0) or \
(self.func and self.func(message)):
now = datetime.now()
if identifier:
message.respond(_(u"%(pingID)s on %(date)s") % \
{'pingID': identifier, \
'date': format_datetime(now, \
locale=self.locale)})
else:
message.respond(_(u"pong on %(date)s") % \
{'date': format_datetime(now, \
locale=self.locale)})
return True
常規註釋在 RapidSMS 應用程式中非常有用
- 幫助初學者從示例中學習
- 允許其他開發人員用英語閱讀您的程式碼,而不是程式碼
- 將來當您不知道為什麼編寫了那行程式碼時,它將幫助您自己。
- 透過迫使您簡潔地描述您編寫的內容來幫助您構建一致的程式;從而發現錯誤。
上面的例子實際上有一些註釋
def handle(self, message):
# We only want to answer ping alone, or ping followed by a space
# and other characters
if not re.match(r'^ping( +|$)', message.text.lower()):
return False
identifier_match = re.match(r'^ping (?P<identifier>.+).*$', \
message.text.lower(), re.U)
if not identifier_match:
identifier = False
else:
identifier = identifier_match.group('identifier')
# deny has higher priority
if self.disallow:
return False
# allow or number in auth= or function returned True
if self.allow or \
(self.allowed and self.allowed.count(message.peer) > 0) or \
(self.func and self.func(message)):
now = datetime.now()
if identifier:
message.respond(_(u"%(pingID)s on %(date)s") % \
{'pingID': identifier, \
'date': format_datetime(now, \
locale=self.locale)})
else:
message.respond(_(u"pong on %(date)s") % \
{'date': format_datetime(now, \
locale=self.locale)})
return True
內聯文件是 Python 的一項功能,它允許您在類、函式和模組的程式碼中編寫一些註釋。然後,Python 會自動解析這些註釋並將它們格式化為漂亮的文件。
示例
def handle(self, message):
''' check authorization and respond
if auth contained deny string => return
if auth contained allow string => answer
if auth contained number and number is asking => reply
if auth_func contained function and it returned True => reply
else return'''
# We only want to answer ping alone, or ping followed by a space
# and other characters
if not re.match(r'^ping( +|$)', message.text.lower()):
return False
我們在方法開頭添加了一個多行註釋(用三引號)。Python 理解在模組、類、函式或方法開頭的所有多行註釋都是文件字串。
該文件字串可以只有一行長(儘管它仍然需要使用三引號)。
在上面的示例中,我們首先添加了簡短的描述(這是一個約定),然後在換行後添加了更多詳細的資訊。
要訪問文件,只需啟動 Python shell 並對目標物件呼叫help()。
./rapidsms shell
>> from apps.ping import app
>> help(app.App.handle)
Help on method handle in module apps.ping.app:
handle(self, message) unbound apps.ping.app.App method
check authorization and respond
if auth contained deny string => return
if auth contained allow string => answer
if auth contained number and number is asking => reply
if auth_func contained function and it returned True => reply
else return
這意味著任何開發人員現在都可以從 shell 中訪問格式良好的文件。
它也由外部工具用於生成獨立的 HTML 或其他格式的文件。
為了讓您的應用程式可以重用,社群要求使用文件字串。確保您為所有模組(檔案)、類、函式和方法新增文件字串。
完整示例
#!/usr/bin/env python
# vim: ai ts=4 sts=4 et sw=4 coding=utf-8
# maintainer: rgaudin
''' Reply to `ping` messages to confirm system is up and running. '''
import re
from datetime import datetime
import rapidsms
from django.utils.translation import ugettext_lazy as _
from babel.dates import format_datetime
from bonjour.utils import *
def import_function(func):
''' import a function from full python path string
returns function.'''Before
if '.' not in func:
f = eval(func)
else:
s = func.rsplit(".", 1)
x = __import__(s[0], fromlist=[s[0]])
f = getattr(x, s[1])
return f
def parse_numbers(sauth):
''' transform a string of comma separated cell numbers into a list
return array. '''
nums = sauth.replace(" ", "").split(",")
return [num for num in nums if num != ""]
class App (rapidsms.app.App):
''' Reply to `ping` messages to confirm system is up and running.
One can specify a number or authentication function to
limit users who can ping the system. '''
def configure(self, auth_func=None, auth=None):
''' set up authentication mechanism
configured from [ping] in rapidsms.ini '''
# store locale
self.locale = Bonjour.locale()
# add custom function
try:
self.func = import_function(auth_func)
except:
self.func = None
# add defined numbers to a list
try:
self.allowed = parse_numbers(auth)
except:
self.allowed = []
# allow everybody trigger
self.allow = auth in ('*', 'all', 'true', 'True')
# deny everybody trigger
self.disallow = auth in ('none', 'false', 'False')
def handle(self, message):
''' check authorization and respond
if auth contained deny string => return
if auth contained allow string => answer
if auth contained number and number is asking => reply
if auth_func contained function and it returned True => reply
else return'''
# We only want to answer ping alone, or ping followed by a space
# and other characters
if not re.match(r'^ping( +|$)', message.text.lower()):
return False
identifier_match = re.match(r'^ping (?P<identifier>.+).*$', \
message.text.lower(), re.U)
if not identifier_match:
identifier = False
else:
identifier = identifier_match.group('identifier')
# deny has higher priority
if self.disallow:
return False
# allow or number in auth= or function returned True
if self.allow or \
(self.allowed and message.peer in self.allowed) or \
(self.func and self.func(message)):
now = datetime.now()
if identifier:
message.respond(_(u"%(pingID)s on %(date)s") % \
{'pingID': identifier, \
'date': format_datetime(now, \
locale=self.locale)})
else:
message.respond(_(u"pong on %(date)s") % \
{'date': format_datetime(now, \
locale=self.locale)})
return True
即使您的程式碼編寫良好並正確註釋,也不希望有人花幾個小時檢視原始檔只是為了檢查他正在尋找的功能是否存在。
這就是為什麼您必須至少建立一個檔案(按照約定,在專案的根目錄中命名為README)來描述您的應用程式。
它應該包含
- 應用程式名稱
- 您的姓名和聯絡方式
- 對其功能的描述
- 它有哪些依賴項
- 如何安裝/使用它。
如果您的應用程式很複雜,請建立一個docs/資料夾並將任何進一步的文件新增到其中。
非常重要的是,您在編寫程式碼時就編寫這些註釋和文件字串,因為如果您不這樣做,會導致此文件中的錯誤,而糟糕的文件比沒有文件更糟糕。這是您想要養成的一種習慣。