摘要:這種表示具體的。中其他的關(guān)鍵字則是函數(shù)的參數(shù),用于表示不同的前綴。這個(gè)是這個(gè)指定的第一個(gè),作用是限制請(qǐng)求的大小。表示實(shí)現(xiàn)主要功能的應(yīng)用,是一個(gè)標(biāo)準(zhǔn)的。對(duì)象是根據(jù)中的配置來(lái)處理的。最后會(huì)把請(qǐng)求交給進(jìn)行處理。
本文會(huì)重點(diǎn)講解OpenStack中使用的API開(kāi)發(fā)框架的使用。但是本文的目的并不是覆蓋這些框架的使用細(xì)節(jié),而是通過(guò)說(shuō)明重要的部分,降低初學(xué)者的入門的門檻??蚣艿氖褂眉?xì)節(jié)都可以從文檔中找到。說(shuō)明一下,除非特殊說(shuō)明,本文中的相對(duì)路徑都是相對(duì)于項(xiàng)目源碼目錄的相對(duì)路徑。
Paste + PasteDeploy + Routes + WebOb我們?cè)?strong>API服務(wù)(1)中已經(jīng)提到了,這個(gè)框架只在早期開(kāi)始的項(xiàng)目中使用,新的項(xiàng)目都已經(jīng)轉(zhuǎn)到Pecan框架了。但是,早期的項(xiàng)目都是比較核心的項(xiàng)目,因此我們還是要學(xué)會(huì)如何使用這個(gè)框架。我們會(huì)以Keystone項(xiàng)目為例,來(lái)說(shuō)明如何閱讀使用這個(gè)框架的開(kāi)發(fā)的API代碼。
重點(diǎn)在于確定URL路由RESTful API程序的主要特點(diǎn)就是URL path會(huì)和功能對(duì)應(yīng)起來(lái)。這點(diǎn)從API文檔就可以看得出來(lái),比如用戶管理的功能一般都放在/user這個(gè)路徑下。因此,看一個(gè)RESTful API程序,一般都是看它實(shí)現(xiàn)了哪些URL path,以及每個(gè)path對(duì)應(yīng)了什么功能,這個(gè)一般都是由框架的URL路由功能負(fù)責(zé)的。所以,熟悉一個(gè)RESTful API程序的重點(diǎn)在于確定URL路由。本章所說(shuō)的這個(gè)框架對(duì)于初學(xué)者的難點(diǎn)也是如何確定URL路由。
WSGI入口和中間件作為基礎(chǔ)知識(shí),你需要先了解一下WSGI的相關(guān)概念,可以參考這篇文章WSGI簡(jiǎn)介。
WSGI入口在API服務(wù)(1)中提到了WSGI可以使用Apache進(jìn)行部署,也可以使用eventlet進(jìn)行部署。Keystone項(xiàng)目同時(shí)提供了這兩種方案的代碼,也就是我們要找的WSGI的入口。
Keystone項(xiàng)目在httpd/目錄下,存放了可以用于Apache服務(wù)器部署WSGI服務(wù)的文件。其中,wsgi-keystone.conf是一個(gè)mod_wsgi的示例配置文件,keystone.py則是WSGI應(yīng)用程序的入口文件。httpd/keystone.py也就是我們要找的入口文件之一。這個(gè)文件的內(nèi)容很簡(jiǎn)單:
import os from keystone.server import wsgi as wsgi_server name = os.path.basename(__file__) application = wsgi_server.initialize_application(name)
文件中創(chuàng)建了WSGI入口需要使用的application對(duì)象。
keystone-all命令則是采用eventlet來(lái)進(jìn)行部署時(shí)的入口,可以從setup.cfg文件按中確定keystone-all命令的入口:
[entry_points] console_scripts = keystone-all = keystone.cmd.all:main keystone-manage = keystone.cmd.manage:main
從setup.cfg文件的entry_points部分可以看出,keystone-all的入口是keystone/cmd/all.py文件中的main()函數(shù),這個(gè)函數(shù)的內(nèi)容也很簡(jiǎn)單:
def main(): eventlet_server.run(possible_topdir)
main()函數(shù)的主要作用就是啟動(dòng)一個(gè)eventlet_server,配置文件從possible_topdir中查找。因?yàn)閑ventlet的部署方式涉及到eventlet庫(kù)的使用方法,本文不再展開(kāi)說(shuō)明。讀者可以在學(xué)會(huì)確定URL路由后再回來(lái)看這個(gè)代碼。下面,繼續(xù)以httpd/keystone.py文件作為入口來(lái)說(shuō)明如何閱讀代碼。
Paste和PasteDeployhttpd/keystone.py中調(diào)用的initialize_application(name)函數(shù)載入了整個(gè)WSGI應(yīng)用,這里主要用到了Paste和PasteDeploy庫(kù)。
def initialize_application(name): ... def loadapp(): return keystone_service.loadapp( "config:%s" % config.find_paste_config(), name) _unused, application = common.setup_backends( startup_application_fn=loadapp) return application
上面是刪掉無(wú)關(guān)代碼后的initialize_application()函數(shù)。config.find_paste_config()用來(lái)查找PasteDeploy需要用到的WSGI配置文件,這個(gè)文件在源碼中是etc/keystone-paste.ini文件,如果在線上環(huán)境中,一般是/etc/keystone-paste.init。keystone_service.loadapp()函數(shù)內(nèi)部則調(diào)用了paste.deploy.loadapp()函數(shù)來(lái)加載WSGI應(yīng)用,如何加載則使用了剛才提到的keystone-paste.ini文件,這個(gè)文件也是看懂整個(gè)程序的關(guān)鍵。
name很關(guān)鍵在上面的代碼中我們可以看到,name這個(gè)變量從httpd/keystone.py文件傳遞到initialize_application()函數(shù),又被傳遞到keystone_service.loadapp()函數(shù),最終被傳遞到paste.deploy.loadapp()函數(shù)。那么,這個(gè)name變量到底起什么作用呢?先把這個(gè)問(wèn)題放在一邊,我們后面再來(lái)解決它。
paste.ini使用Paste和PasteDeploy模塊來(lái)實(shí)現(xiàn)WSGI服務(wù)時(shí),都需要一個(gè)paste.ini文件。這個(gè)文件也是Paste框架的精髓,這里需要重點(diǎn)說(shuō)明一下這個(gè)文件如何閱讀。
paste.ini文件的格式類似于INI格式,每個(gè)section的格式為[type:name]。這里重要的是理解幾種不同type的section的作用。
composite: 這種section用于將HTTP請(qǐng)求分發(fā)到指定的app。
app: 這種section表示具體的app。
filter: 實(shí)現(xiàn)一個(gè)過(guò)濾器中間件。
pipeline: 用來(lái)把把一系列的filter串起來(lái)。
上面這些section是在keystone的paste.ini中用到的,下面詳細(xì)介紹一下如何使用。這里需要用到WSGIMiddleware(WSGI中間件)的知識(shí),可以在WSGI簡(jiǎn)介這篇文章中找到。
section composite
這種section用來(lái)決定如何分發(fā)HTTP請(qǐng)求。Keystone的paste.ini文件中有兩個(gè)composite的section:
[composite:main] use = egg:Paste#urlmap /v2.0 = public_api /v3 = api_v3 / = public_version_api [composite:admin] use = egg:Paste#urlmap /v2.0 = admin_api /v3 = api_v3 / = admin_version_api
在composite seciont中,use是一個(gè)關(guān)鍵字,指定處理請(qǐng)求的代碼。egg:Paste#urlmap表示到Paste模塊的egg-info中去查找urlmap關(guān)鍵字所對(duì)應(yīng)的函數(shù)。在virtualenv環(huán)境下,是文件/lib/python2.7/site-packages/Paste-2.0.2.dist-info/metadata.json:
{ ... "extensions": { ... "python.exports": { "paste.composite_factory": { "cascade": "paste.cascade:make_cascade", "urlmap": "paste.urlmap:urlmap_factory" }, ... }
在這個(gè)文件中,你可以找到urlmap對(duì)應(yīng)的是paste.urlmap:urlmap_factory,也就是paste/urlmap.py文件中的urlmap_factory()函數(shù)。
composite section中其他的關(guān)鍵字則是urlmap_factory()函數(shù)的參數(shù),用于表示不同的URL path前綴。urlmap_factory()函數(shù)會(huì)返回一個(gè)WSGI app,其功能是根據(jù)不同的URL path前綴,把請(qǐng)求路由給不同的app。以[composite:main]為例:
[composite:main] use = egg:Paste#urlmap /v2.0 = public_api # /v2.0 開(kāi)頭的請(qǐng)求會(huì)路由給public_api處理 /v3 = api_v3 # /v3 開(kāi)頭的請(qǐng)求會(huì)路由個(gè)api_v3處理 / = public_version_api # / 開(kāi)頭的請(qǐng)求會(huì)路由給public_version_api處理
路由的對(duì)象其實(shí)就是paste.ini中其他secion的名字,類型必須是app或者pipeline。
section pipeline
pipeline是把filter和app串起來(lái)的一種section。它只有一個(gè)關(guān)鍵字就是pipeline。我們以api_v3這個(gè)pipeline為例:
[pipeline:api_v3] # The last item in this pipeline must be service_v3 or an equivalent # application. It cannot be a filter. pipeline = sizelimit url_normalize request_id build_auth_context token_auth admin_token_auth json_body ec2_extension_v3 s3_extension simple_cert_extension revoke_extension federation_extension oauth1_extension endpoint_filter_extension endpoint_policy_extension service_v3
pipeline關(guān)鍵字指定了很多個(gè)名字,這些名字也是paste.ini文件中其他section的名字。請(qǐng)求會(huì)從最前面的section開(kāi)始處理,一直向后傳遞。pipeline指定的section有如下要求:
最后一個(gè)名字對(duì)應(yīng)的section一定要是一個(gè)app
非最后一個(gè)名字對(duì)應(yīng)的section一定要是一個(gè)filter
section filter
filter是用來(lái)過(guò)濾請(qǐng)求和響應(yīng)的,以WSGI中間件的方式實(shí)現(xiàn)。
[filter:sizelimit] paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory
這個(gè)是api_v3這個(gè)pipeline指定的第一個(gè)filter,作用是限制請(qǐng)求的大小。其中的paste.filter_factory表示調(diào)用哪個(gè)函數(shù)來(lái)獲得這個(gè)filter中間件。
section app
app表示實(shí)現(xiàn)主要功能的應(yīng)用,是一個(gè)標(biāo)準(zhǔn)的WSGI application。
[app:service_v3] paste.app_factory = keystone.service:v3_app_factory
paste.app_factory表示調(diào)用哪個(gè)函數(shù)來(lái)獲得這個(gè)app。
總結(jié)一下
paste.ini中這一大堆配置的作用就是把我們用Python寫的WSGI application和middleware串起來(lái),規(guī)定好HTTP請(qǐng)求處理的路徑。
name是用來(lái)確定入口的
上面我們提到了一個(gè)問(wèn)題,就是name變量的作用到底是什么?name變量表示paste.ini中一個(gè)section的名字,指定這個(gè)section作為HTTP請(qǐng)求處理的第一站。在Keystone的paste.ini中,請(qǐng)求必須先由[composite:main]或者[composite:admin]處理,所以在keystone項(xiàng)目中,name的值必須是main或者admin。
上面提到的httpd/keystone.py文件中,name等于文件名的basename,所以實(shí)際部署中,必須把keystone.py重命名為main.py或者admin.py。
舉個(gè)例子
一般情況下,從Keystone服務(wù)獲取一個(gè)token時(shí),會(huì)使用下面這個(gè)API:
POST http://hostname:35357/v3/auth/tokens
我們根據(jù)Keystone的paste.ini來(lái)說(shuō)明這個(gè)API是如何被處理的:
hostname:35357 這一部分是由Web服務(wù)器處理的,比如Apache。然后,請(qǐng)求會(huì)被轉(zhuǎn)到WSGI的入口,也就是httpd/keystone.py中的application對(duì)象取處理。
application對(duì)象是根據(jù)paste.ini中的配置來(lái)處理的。這里會(huì)先由[composite:admin]來(lái)處理(一般是admin監(jiān)聽(tīng)35357端口,main監(jiān)聽(tīng)5000端口)。
[composite:admin]發(fā)現(xiàn)請(qǐng)求的path是/v3開(kāi)頭的,于是就把請(qǐng)求轉(zhuǎn)發(fā)給[pipeline:api_v3]去處理,轉(zhuǎn)發(fā)之前,會(huì)把/v3這個(gè)部分去掉。
[pipeline:api_v3]收到請(qǐng)求,path是/auth/tokens,然后開(kāi)始調(diào)用各個(gè)filter來(lái)處理請(qǐng)求。最后會(huì)把請(qǐng)求交給[app:service_v3]進(jìn)行處理。
[app:service_v3]收到請(qǐng)求,path是/auth/tokens,然后交給最終的WSGI app去處理。
下一步
到此為止,paste.ini中的配置的所有工作都已經(jīng)做完了。下面請(qǐng)求就要轉(zhuǎn)移到最終的app內(nèi)部去處理了。前面已經(jīng)說(shuō)過(guò)了,我們的重點(diǎn)是確定URL路由,那么現(xiàn)在還有一部分的path的路由還沒(méi)確定,/auth/tokens,這個(gè)還需要下一步的工作。
中間件的實(shí)現(xiàn)上面我們提到paste.ini中用到了許多的WSGI中間件,那么這些中間件是如何實(shí)現(xiàn)的呢?我們來(lái)看一個(gè)例子就知道了。
[filter:build_auth_context] paste.filter_factory = keystone.middleware:AuthContextMiddleware.factory
build_auth_context這個(gè)中間件的作用是在WSGI的environ中添加KEYSTONE_AUTH_CONTEXT這個(gè)鍵,包含的內(nèi)容是認(rèn)證信息的上下文。實(shí)現(xiàn)這個(gè)中間件的類繼承關(guān)系如下:
keystone.middleware.core.AuthContextMiddleware -> keystone.common.wsgi.Middleware -> keystone.common.wsgi.Application -> keystone.common.wsgi.BaseApplication
這里實(shí)現(xiàn)的關(guān)鍵主要在前面兩個(gè)類中。
keystone.common.wsgi.Middleware類實(shí)現(xiàn)了__call__()方法,這個(gè)就是WSGI中application端被調(diào)用時(shí)運(yùn)行的方法。
class Middleware(Application): ... @webob.dec.wsgify() def __call__(self, request): try: response = self.process_request(request) if response: return response response = request.get_response(self.application) return self.process_response(request, response) except exceptin.Error as e: ... ...
__call__()方法實(shí)現(xiàn)為接收一個(gè)request對(duì)象,返回一個(gè)response對(duì)象的形式,然后使用WebOB模塊的裝飾器webob.dec.wsgify()將它變成標(biāo)準(zhǔn)的WSGI application接口。這里的request和response對(duì)象分別是 webob.Request 和webob.Response。這里,__call__()方法內(nèi)部調(diào)用了self.process_request()方法,這個(gè)方法在keystone.middleware.core.AuthContextMiddleware中實(shí)現(xiàn):
class AuthContextMiddleware(wsgi.Middleware): ... def process_request(self, request): ... request.environ[authorization.AUTH_CONTEXT_ENV] = auth_context
這個(gè)函數(shù)會(huì)根據(jù)功能設(shè)計(jì)創(chuàng)建auth_context,然后賦值給request.environ["KEYSTONE_AUTH_CONTEXT]`,這樣就能通過(guò)WSGI application方法的environ傳遞到下一個(gè)WSGI application中去了。
最后的Application上面我們已經(jīng)看到了,對(duì)于/v3開(kāi)頭的請(qǐng)求,在paste.ini中會(huì)被路由到[app:service_v3]這個(gè)section,會(huì)交給keystone.service:v3_app_factory這個(gè)函數(shù)生成的application處理。最后這個(gè)application需要根據(jù)URL path中剩下的部分,/auth/tokens,來(lái)實(shí)現(xiàn)URL路由。從這里開(kāi)始,就需要用到Routes模塊了。
同樣由于篇幅限制,我們只能展示Routes模塊的大概用法。Routes模塊是用Python實(shí)現(xiàn)的類似Rails的URL路由系統(tǒng),它的主要功能就是把path映射到對(duì)應(yīng)的動(dòng)作。
Routes模塊的一般用法是創(chuàng)建一個(gè)Mapper對(duì)象,然后調(diào)用該對(duì)象的connect()方法把path和method映射到一個(gè)controller的某個(gè)action上,這里controller是一個(gè)自定義的類實(shí)例,action是表示controller對(duì)象的方法的字符串。一般調(diào)用的時(shí)候還會(huì)指定映射哪些方法,比如GET或者POST之類的。
舉個(gè)例子,來(lái)看下keystone/auth/routers.py的代碼:
class Routers(wsgi.RoutersBase): def append_v3_routers(self, mapper, routers): auth_controller = controllers.Auth() self._add_resource( mapper, auth_controller, path="/auth/tokens", get_action="validate_token", head_action="check_token", post_action="authenticate_for_token", delete_action="revoke_token", rel=json_home.build_v3_resource_relation("auth_tokens")) ...
這里調(diào)用了自己Keystone自己封裝的_add_resource()方法批量為一個(gè)/auth/tokens這個(gè)path添加多個(gè)方法的處理函數(shù)。其中,controller是一個(gè)controllers.Auth實(shí)例,也就是 keystone.auth.controllers.Auth。其他的參數(shù),我們從名稱可以猜出其作用是指定對(duì)應(yīng)方法的處理函數(shù),比如get_action用于指定GET方法的處理函數(shù)為validate_token。我們?cè)偕钊胍幌拢聪?em>_add_resource()這個(gè)方法的實(shí)現(xiàn):
def _add_resource(self, mapper, controller, path, rel, get_action=None, head_action=None, get_head_action=None, put_action=None, post_action=None, patch_action=None, delete_action=None, get_post_action=None, path_vars=None, status=json_home.Status.STABLE): ... if get_action: getattr(controller, get_action) # ensure the attribute exists mapper.connect(path, controller=controller, action=get_action, conditions=dict(method=["GET"])) ...
這個(gè)函數(shù)其實(shí)很簡(jiǎn)單,就是調(diào)用mapper對(duì)象的connect方法指定一個(gè)path的某些method的處理函數(shù)。
Keystone項(xiàng)目的代碼結(jié)構(gòu)Keystone項(xiàng)目把每個(gè)功能都分到多帶帶的目錄下,比如token相關(guān)的功能是放在keystone/token/目錄下,assignment相關(guān)的功能是放在keystone/assignment/目錄下。目錄下都一般會(huì)有三個(gè)文件:routers.py, controllers.py, core.py。routers.py中實(shí)現(xiàn)了URL路由,把URL和controllers.py中的action對(duì)應(yīng)起來(lái);controllers.py中的action調(diào)用core.py中的底層接口實(shí)現(xiàn)RESTful API承諾的功能。所以,我們要進(jìn)一步確定URL路由是如何做的,就要看routers.py文件。
注意,這個(gè)只是Keystone項(xiàng)目的結(jié)構(gòu),其他項(xiàng)目即使用了同樣的框架,也不一定是這么做的。
Keystone中的路由匯總每個(gè)模塊都定義了自己的路由,但是這些路由最終要還是要通過(guò)一個(gè)WSGI application來(lái)調(diào)用的。上面已經(jīng)提到了,在Keystone中,/v3開(kāi)頭的請(qǐng)求最終都會(huì)交給keystone.service.v3_app_factory這個(gè)函數(shù)生成的application來(lái)處理。這個(gè)函數(shù)里也包含了路由最后分發(fā)的秘密,我們來(lái)看代碼:
def v3_app_factory(global_conf, **local_conf): ... mapper = routes.Mapper() ... router_modules = [auth, assignment, catalog, credential, identity, policy, resource] ... for module in router_modules: routers_instance = module.routers.Routers() _routers.append(routers_instance) routers_instance.append_v3_routers(mapper, sub_routers) # Add in the v3 version api sub_routers.append(routers.VersionV3("public", _routers)) return wsgi.ComposingRouter(mapper, sub_routers)
v3_app_factory()函數(shù)中先遍歷了所有的模塊,將每個(gè)模塊的路由都添加到同一個(gè)mapper對(duì)象中,然后把mapper對(duì)象作為參數(shù)用于初始化wsgi.ComposingRouter對(duì)象,所以我們可以判斷,這個(gè)wsgi.ComposingRouter對(duì)象一定是一個(gè)WSGI application,我們看看代碼就知道了:
class Router(object): """WSGI middleware that maps incoming requests to WSGI apps.""" def __init__(self, mapper): self.map = mapper self._router = routes.middleware.RoutesMiddleware(self._dispatch, self.map) @webob.dec.wsgify() def __call__(self, req): return self._router ... class ComposingRouter(Router): def __init__(self, mapper=None, routers=None): ...
上述代碼證實(shí)了我們的猜測(cè)。這個(gè)ComposingRouter對(duì)象被調(diào)用時(shí)(在其父類Router中實(shí)現(xiàn)),會(huì)返回一個(gè)WSGI application。這個(gè)application中則使用了routes模塊的中間件來(lái)實(shí)現(xiàn)了請(qǐng)求路由,在routes.middleware.RoutesMiddleware中實(shí)現(xiàn)。這里對(duì)path進(jìn)行路由的結(jié)果就是返回各個(gè)模塊的controllers.py中定義的controller。各個(gè)模塊的controller都是一個(gè)WSGI application,這個(gè)你可以通過(guò)這些controller的類繼承關(guān)系看出來(lái)。
但是這里只講到了,routes模塊把path映射到了一個(gè)controller,但是如何把對(duì)path的處理映射到controller的方法呢?這個(gè)可以從controller的父類keystone.common.wsgi.Application的實(shí)現(xiàn)看出來(lái)。這個(gè)Application類中使用了environ["wsgiorg.routing_args"]中的數(shù)據(jù)來(lái)確定調(diào)用controller的哪個(gè)方法,這些數(shù)據(jù)是由上面提到的routes.middleware.RoutesMiddleware設(shè)置的。
總結(jié)到這里我們大概把Paste + PasteDeploy + Routes + WebOb這個(gè)框架的流程講了一遍,從本文的長(zhǎng)度你就可以看出這個(gè)框架有多啰嗦,用起來(lái)有多麻煩。下一篇文章我們會(huì)講Pecan框架,我們的demo也將會(huì)使用Pecan框架來(lái)開(kāi)發(fā)。
參考資源本文主要提到了Python Paste中的各種庫(kù),這些庫(kù)的相關(guān)文檔都可以在項(xiàng)目官網(wǎng)找到:http://pythonpaste.org/。
另外,routes庫(kù)的項(xiàng)目官網(wǎng)是:https://routes.readthedocs.org/en/latest/
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/37597.html
摘要:通過(guò),也就是通過(guò)各個(gè)項(xiàng)目提供的來(lái)使用各個(gè)服務(wù)的功能。通過(guò)使用的方式是由各個(gè)服務(wù)自己實(shí)現(xiàn)的,比如負(fù)責(zé)計(jì)算的項(xiàng)目實(shí)現(xiàn)了計(jì)算相關(guān)的,負(fù)責(zé)認(rèn)證的項(xiàng)目實(shí)現(xiàn)了認(rèn)證和授權(quán)相關(guān)的。的服務(wù)都是使用的方式來(lái)部署的。 使用OpenStack服務(wù)的方式 OpenStack項(xiàng)目作為一個(gè)IaaS平臺(tái),提供了三種使用方式: 通過(guò)Web界面,也就是通過(guò)Dashboard(面板)來(lái)使用平臺(tái)上的功能。 通過(guò)命令行,也就...
摘要:在實(shí)際項(xiàng)目中,這么做肯定是不行的實(shí)際項(xiàng)目中不會(huì)使用內(nèi)存數(shù)據(jù)庫(kù),這種數(shù)據(jù)庫(kù)一般只是在單元測(cè)試中使用。接下來(lái),我們將會(huì)了解中單元測(cè)試的相關(guān)知識(shí)。 在上一篇文章,我們介紹了SQLAlchemy的基本概念,也介紹了基本的使用流程。本文我們結(jié)合webdemo這個(gè)項(xiàng)目來(lái)介紹如何在項(xiàng)目中使用SQLAlchemy。另外,我們還會(huì)介紹數(shù)據(jù)庫(kù)版本管理的概念和實(shí)踐,這也是OpenStack每個(gè)項(xiàng)目都需要做的...
摘要:到這里,我們的服務(wù)的框架已經(jīng)搭建完成,并且測(cè)試服務(wù)器也跑起來(lái)了。上面的代碼也就可以修改為再次運(yùn)行我們的測(cè)試服務(wù)器,就可以返現(xiàn)返回值為格式了。我們先來(lái)完成利用來(lái)檢查返回值的代碼方法的第一個(gè)參數(shù)表示返回值的類型這樣就完成了的返回值檢查了。 上一篇文章說(shuō)到,我們將以實(shí)例的形式來(lái)繼續(xù)講述這個(gè)API服務(wù)的開(kāi)發(fā)知識(shí),這里會(huì)使用Pecan和WSME兩個(gè)庫(kù)。 設(shè)計(jì)REST API 要開(kāi)發(fā)REST AP...
摘要:本文將進(jìn)入單元測(cè)試的部分,這也是基礎(chǔ)知識(shí)中最后一個(gè)大塊。本文將重點(diǎn)講述和中的單元測(cè)試的生態(tài)環(huán)境。另外,在中指定要運(yùn)行的單元測(cè)試用例的完整語(yǔ)法是。中使用模塊管理單元測(cè)試用例。每個(gè)項(xiàng)目的單元測(cè)試代碼結(jié)構(gòu)可 本文將進(jìn)入單元測(cè)試的部分,這也是基礎(chǔ)知識(shí)中最后一個(gè)大塊。本文將重點(diǎn)講述Python和OpenStack中的單元測(cè)試的生態(tài)環(huán)境。 單元測(cè)試的重要性 github上有個(gè)人畫了一些不同語(yǔ)言的學(xué)...
摘要:從上面的例子可以看出,決定響應(yīng)類型的主要是傳遞給函數(shù)的參數(shù),我們看下函數(shù)的完整聲明參數(shù)用來(lái)指定返回值的模板,如果是就會(huì)返回內(nèi)容,這里可以指定一個(gè)文件,或者指定一個(gè)模板。用來(lái)做什么上面兩節(jié)已經(jīng)說(shuō)明了可以比較好的處理請(qǐng)求中的參數(shù)以及控制返回值。 上一篇文章我們了解了一個(gè)巨啰嗦的框架:Paste + PasteDeploy + Routes + WebOb。后來(lái)OpenStack社區(qū)的人受不...
摘要:不幸的是,在軟件包管理十分混亂,至少歷史上十分混亂。的最大改進(jìn)是將函數(shù)的參數(shù)單獨(dú)放到一個(gè)的文件中這些成為包的元數(shù)據(jù)?;诘陌姹咎?hào)管理。的版本推導(dǎo)這里重點(diǎn)說(shuō)明一下基于的版本號(hào)管理這個(gè)功能。開(kāi)發(fā)版本號(hào)的形式如下。 為什么寫這個(gè)系列 OpenStack是目前我所知的最大最復(fù)雜的基于Python項(xiàng)目。整個(gè)OpenStack項(xiàng)目包含了數(shù)十個(gè)主要的子項(xiàng)目,每個(gè)子項(xiàng)目所用到的庫(kù)也不盡相同。因此,對(duì)于...
閱讀 1890·2021-11-24 09:39
閱讀 2535·2021-10-14 09:43
閱讀 3318·2021-10-08 10:10
閱讀 2266·2021-09-22 15:54
閱讀 2340·2019-08-29 17:20
閱讀 1573·2019-08-28 18:14
閱讀 2374·2019-08-26 13:28
閱讀 1111·2019-08-26 12:16