From 5d5c14ef6e2281795d3f592384164b21c702ef96 Mon Sep 17 00:00:00 2001 From: ChenShi <280580216@qq.com> Date: Thu, 25 Aug 2016 17:59:35 +0800 Subject: [PATCH 1/2] update 405: Method Not Allowed 405: Method Not Allowed --- .idea/workspace.xml | 2 +- .vscode/.ropeproject/config.py | 100 +++++++++++++++ .vscode/settings.json | 4 + .vscode/tasks.json | 23 ++++ .../www/__pycache__/coroweb.cpython-35.pyc | Bin 6301 -> 6638 bytes .../www/__pycache__/handlers.cpython-35.pyc | Bin 693 -> 639 bytes .../www/__pycache__/orm.cpython-35.pyc | Bin 8756 -> 8946 bytes awesome-python3-webapp/www/app.py | 115 +++++++++--------- awesome-python3-webapp/www/coroweb.py | 99 ++++----------- awesome-python3-webapp/www/handlers.py | 27 ++-- awesome-python3-webapp/www/orm.py | 104 ++++++++-------- .../www/templates/test.html | 4 +- awesome-python3-webapp/www/test.py | 20 +-- 13 files changed, 299 insertions(+), 199 deletions(-) create mode 100644 .vscode/.ropeproject/config.py create mode 100644 .vscode/tasks.json diff --git a/.idea/workspace.xml b/.idea/workspace.xml index b9c9e61..a609643 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -349,7 +349,7 @@ - + diff --git a/.vscode/.ropeproject/config.py b/.vscode/.ropeproject/config.py new file mode 100644 index 0000000..d1e8f3d --- /dev/null +++ b/.vscode/.ropeproject/config.py @@ -0,0 +1,100 @@ +# The default ``config.py`` +# flake8: noqa + + +def set_prefs(prefs): + """This function is called before opening the project""" + + # Specify which files and folders to ignore in the project. + # Changes to ignored resources are not added to the history and + # VCSs. Also they are not returned in `Project.get_files()`. + # Note that ``?`` and ``*`` match all characters but slashes. + # '*.pyc': matches 'test.pyc' and 'pkg/test.pyc' + # 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc' + # '.svn': matches 'pkg/.svn' and all of its children + # 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o' + # 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o' + prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject', + '.hg', '.svn', '_svn', '.git', '.tox'] + + # Specifies which files should be considered python files. It is + # useful when you have scripts inside your project. Only files + # ending with ``.py`` are considered to be python files by + # default. + #prefs['python_files'] = ['*.py'] + + # Custom source folders: By default rope searches the project + # for finding source folders (folders that should be searched + # for finding modules). You can add paths to that list. Note + # that rope guesses project source folders correctly most of the + # time; use this if you have any problems. + # The folders should be relative to project root and use '/' for + # separating folders regardless of the platform rope is running on. + # 'src/my_source_folder' for instance. + #prefs.add('source_folders', 'src') + + # You can extend python path for looking up modules + #prefs.add('python_path', '~/python/') + + # Should rope save object information or not. + prefs['save_objectdb'] = True + prefs['compress_objectdb'] = False + + # If `True`, rope analyzes each module when it is being saved. + prefs['automatic_soa'] = True + # The depth of calls to follow in static object analysis + prefs['soa_followed_calls'] = 0 + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. + prefs['perform_doa'] = True + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True + + # How many undos to hold? + prefs['max_history_items'] = 32 + + # Shows whether to save history across sessions. + prefs['save_history'] = True + prefs['compress_history'] = False + + # Set the number spaces used for indenting. According to + # :PEP:`8`, it is best to use 4 spaces. Since most of rope's + # unit-tests use 4 spaces it is more reliable, too. + prefs['indent_size'] = 4 + + # Builtin and c-extension modules that are allowed to be imported + # and inspected by rope. + prefs['extension_modules'] = [] + + # Add all standard c-extensions to extension_modules list. + prefs['import_dynload_stdmods'] = True + + # If `True` modules with syntax errors are considered to be empty. + # The default value is `False`; When `False` syntax errors raise + # `rope.base.exceptions.ModuleSyntaxError` exception. + prefs['ignore_syntax_errors'] = False + + # If `True`, rope ignores unresolvable imports. Otherwise, they + # appear in the importing namespace. + prefs['ignore_bad_imports'] = False + + # If `True`, rope will insert new module imports as + # `from import ` by default. + prefs['prefer_module_from_imports'] = False + + # If `True`, rope will transform a comma list of imports into + # multiple separate import statements when organizing + # imports. + prefs['split_imports'] = False + + # If `True`, rope will sort imports alphabetically by module name + # instead of alphabetically by import statement, with from imports + # after normal imports. + prefs['sort_imports_alphabetically'] = False + + +def project_opened(project): + """This function is called after opening the project""" + # Do whatever you like here! diff --git a/.vscode/settings.json b/.vscode/settings.json index d6b1940..32cbf34 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ // 将设置放入此文件中以覆盖默认值和用户设置。 { + "python.pythonPath": "E:\\Program Files (x86)\\Python\\python.exe", + "python.linting.enabled": true, + "python.linting.lintOnSave": false, + "python.linting.flake8Enabled": true } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..eab2057 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,23 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "npm", + "isShellCommand": true, + "showOutput": "always", + "suppressTaskName": true, + "tasks": [ + { + "taskName": "install", + "args": ["install"] + }, + { + "taskName": "update", + "args": ["update"] + }, + { + "taskName": "test", + "args": ["run", "test"] + } + ] +} \ No newline at end of file diff --git a/awesome-python3-webapp/www/__pycache__/coroweb.cpython-35.pyc b/awesome-python3-webapp/www/__pycache__/coroweb.cpython-35.pyc index 94073f6578f92bd87829bdd970fd30747111e78f..4cd0f4348a17f409b0fba0c3bc597df0a78cc7e2 100644 GIT binary patch delta 1980 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 diff --git a/awesome-python3-webapp/www/__pycache__/handlers.cpython-35.pyc b/awesome-python3-webapp/www/__pycache__/handlers.cpython-35.pyc index 47f48f39fe04ff2a6ff6f611a84f7b47d76f98b8..88c8f152a17fd75ea25d6e74dbb2d220ca7db6b2 100644 GIT binary patch delta 209 zcmdnW`k#eMjF*>d$<%$}aZDSzco}scGcYg|D*}lU28Jv~hGqr^&lCm*k6K2C6d+<^ zNMUBEVPwc;VhGk`@td5;sHn_T!~#@)i#;tfFU2t@N0aFmdr@j(X=-sv5f@NmB|{PK zTP!7+xj-_jI6v#B0f`VMF(xHJ0A86b7Id5;cC*wvgUPdox1_p*=O(0Riz>vkrkiy8&%*eo4!o-lp%+Soh zPzw}dVn|_TNMT{9VPwc;VhGk`^{WytNi8l>2rW)6(o4(COL5G}(a@ai!l)>~a*I7D zKRrD&FZ~uvW?owUW-gG- zD$dU<;sy#&W?}NO1<4ojqY?r@?kx_R-29Z%oK!nTAg@>mNbms7gF_}UCM9M7Mf5Js diff --git a/awesome-python3-webapp/www/__pycache__/orm.cpython-35.pyc b/awesome-python3-webapp/www/__pycache__/orm.cpython-35.pyc index 035a2fc540d13118e984ff353df376a38a94a829..78851e303d831e475268d2e3b1eca4129c579748 100644 GIT binary patch delta 4122 zcmbVPU2Ggz6+U-n|2^yfU3>kv>)4L7A%Av5(mJl|q_&&@NogDsXG^sm?~LtTk7u1b zvvFeVtiTcQRH*JtRRk)cl|V(23WWzAP$ixaf`=j@F>fdmKSDgfQ;CG&oIAVT#feaZ zXXp6Nx##E3Irp6V%?ES;m>)^Tl;@5dMp|;yV5Y#xfZ2<4EQdB2sEgTQ@jg4t{wn^$9aOA00d368>j)DXjA4FPEX^elAB{D;)bAExu1=ztKgFOY9%b=vd9>D2K z2EfI)-h^Ehc2p>-;0B;t3c?<%&s~Sz0PF;y6e0s9OfcpZm6e(?X@Tu1z`rELB7kF5 zm;Buz*d3A`C3kh+4fOi5e7L&g#-M~-13hc7BOQMsiRui;i_LPVvX~8AdBk4WR>qv| z4qo1JGTd}4+%}D=%$Spn%MkD$d|OU2_CkdUcgmc1(}S>slU2SSS`43QXG6T7q$!ME zz$tErSm z?WZIRP=#J($(($Qga4V6U(1{*;GC^xrXD|bwJ>hO5uj8)p10t#xmvV&8U!ZD>h#rUw$!%J*P{49K|rKwKE-@`p!^JFI??Sxnt z>tK9BoNP~t(~$?qpFuW1P2|%=&JbzR$44)c&ll~Yo6lbsZP9yKDNJfv#?L-MJe=KZg>Hj>JjfriiwToS&kJX(G=Pk^c8ztFB00jL#rh!dnJNQ&bGD%J_`fX!*{> z3w7PB+O!IaQQbu2CCJ6HnAS$meRAKksH5X8JE+F^toWAp&Y6bSK$F+~cYm_$RZ)qL zp8VvlFQD5M@$c3F@t$^0q+4(Pe{L=Dp!LvGyzz_ZcD?D1U&J^c7tgkpo;udI#BbY% zpTaX0!Df@^`5&Kb|CBmH3CuE&tvt5tr!9SB+0bXcDR#Sl#M;HFZhnlqIHI3ZW}r`<~heB;+W7AM|zIa zG?hIcL6VK(Ibb>b8S!>vA?dG_f1YNgmqi@i7XM0YK6fDPG|}`rjXk=66BWGc`)vWE zpJK0z50lr<`|#*KP&>~>!Nlf`n5mVJ2XSJO(?*!72A1R@i>T{sbS`%Ci^Ax6-p}Gi z@=x`URs0RyOXDY2>$~Eko{h25@ylhyw8k^#;jeP$5;@#etPRn@J>K0o*c){DcRXNybNf8fNU-5xB zl3E&(O^q}T`iP*1>ty47@x9caudk8FXNgcp@FE4>vh-!klxMsbG|c77D#9n1d*Pag zY^|WBaYU=Qrj?>;8O@HwANrE)1MzX+g;)S3ZYb6Mj3lOMkj)oL-^xNhyMQL!d`W`+zc&NkI5eWiC1F@kGCS8@#MoB_N+^`fB zxkDL74YNd;13wjNEcrlKlyIIxAzhCEe-%~{IUue?AQ}P;D1}-fpn@2Je*<=^z7Yu$ zC5n+V(ul8uTD}TmRXJXd0-vgh;&%#(x(JR!;6}(a|6_e&;rd!|l{ig;_BE)QCZF4rP0^Zn~k~vag;bM2lZQZoI}KSc@3xiIKX53%|G8R~++1<`K(yLCLxz{y8*&U?iCy7E|f7 zr(_3`^{9BtiBlfq*bQjk`KhJ?eiWOwijIqLYIEjq;=Ab+)mDG2Ha5;UDaZ~fx0P(I z*OBL`Mceg)Ze$!U^XD5>PcIE!HyQ)j_r$mmTaxO(v`HDHJ$}KuqG{9s^z^LUrP` zVE7zo!*tim2Is^^R1W;hL>h6cHBVXyr}p{|-VTLEW1Z@(7SdF_w9aT}6u}D#cu_Q| zOWWCgzaxcp=dN8SmOZ8Hc!82rw!MH`+%S2!cy0J-HGx|G2aF7~EK@p)ypZ3OB}|iW ziO-TKAqYBD#D~|Y|F503vo2L@ VZws__v~_FYq?U{(gSG4Ae*ghb0(}4g delta 3941 zcmbVPU2Ggz6+U-ncfGrw_0QT~|2vzwZo1f{iD{FDBsQt+IBgmysRKzC)MdRh>#RNA zb?=N5Y@DoUBA`6*qx*n_)KXPEfRHQ%s1F6CB7qP{ec%O&c|{Z+Q6GaqeCO_;p8k}?)ka*oO93p=HvNa&W)!MiTGD9{N~#GBSe3rJ%165KZnPA^LyiWtB#=6cCy1{ zN9aD$JwaKEibQrB*-^TW*96sN1lcjN;%~zdfY_|Hr~7V1=Q)L zdnRR*;C7Rp)Z8RFNzLu4g55)QuV(i)*uCKPk)6`qRD;_GZa>)rnmf?orobH}dq{JK z8r*(xhshq%+!1mHw7WrYN68-3+%a;7C}|%cXAqMj3voe9nY4OWoDgd&5W8Yty=lBI zvg+SP(dt6T0%Ps=Pe=}^b#v};FBlfbaR7vjgc%b_{Nnn@BmT)=^%wJOwHp#L36e1a z(|g?wLV3C3N!F~9L5u>^t*ne;;29t!Br-<@lgIeuw6)_Y;PHM9;uG!QAIUIC_=4tb zqVwN*i|&}TW74WYK4^$jHDBeaJ0aQ$(Q25rRwKMw+hAQ-*tpCo$5`7CI|j*HTDXlc zW((Rtn9ALn9i@BJk!VLe$8`$+A;^22OQg`~5dGq?h=_ipTXbS94})LO z>A-+f&`;HR4&K3AEeF_RD*^ZEjzL?C9602l8K+uOKoR`VL&0x_9r+3qrwM~dQ&n6m zKSLqEjn?8Mze}QeCrn~HN^cNdyMa*RADp{kx?UD^9ocv&%;usT#X>pInP@AllIu(! zV3G#OMv;R;WwY$dgLn;M^Is`A8-A(sP*~+tEdSDkR>&8Nh@N8y!r52H+UzuhYGK8B z=n$sp76(O4^x#aSgqA1>b$PH?wMS>gsJalHdVb$&NEW1%_njP{l$__wQh8;TjYdHT zIqHE)c~pJSHK=|c-TgE>l%HYp9Fymn?6Vln`9(D#pE;-?Z3ILhN5KdZW}e^%ADOuX24?+OywsEEcyAeotO5!l<3ow>f^p=`lopM zC=>3lnK-(z>&a<#EVYoTtyEs(S?z_Zc0+wTwQ+J^+<9Wpc3L&chpd99QE%r^<%8la zb*2C6WhX|f@fJ2gbH;zRo$CAsPGP3iU;?jb$O4FRUtf4YJ>TG4Dk&G#NBw7NNnPOO z=(B9p>bW0`$5-(W)zyLZgXxPE+i}yCH53s?(mE8FjRO6URM2Scp?GZu>uTY(!CJPtN#r5i&s?N$lPn45Rn1|H+u7m z*B7z8$Ws@X=&CX$_ng4kSd&jPQ`bkcNPDg5|3WFj*FpkPQo8o5dVHCDt^jwhDY)utJp)5ddXfJw<+$zcTz-ot1*n8-joz z@!^4Q5-5Yi_!FCKQAMn#1%`rhPF8-@fTcCuplk+mXv#+c7;zFK?xT zuv=O$`5FSLe;gPyABeOHr%xPhmI?s5apY(qB+fBcQ!Rgd{2s(lyCu&rRMt0U{;u5g zk#Vb5fVwVpKm0tz0<%>1gRsB3fm3ow{W(4G+8WzA%!Jz@V3#)RF@p<5a@(kZRp3XG zn@pMo+*pV10Bu~tXI=M0hxVj?^VG9r7gGImM&}6_8|-MJ6|y zaB&Ci1vl?`>yCf3Vh3$`Z>wA=Rf1TdA}gDIsqCPZAS#(unY3b6$0>u1Gvos1-o~R* zo+Xl|6|qeGEK>}``eG5GC4v|n<+aDmNbNj-4N8Gg@q*B*S1AV}zqIbi9yM|3Q&nJE zlD$kunCKYlBga=s5UDj%4YMS}9m%*uG6Il%56d|wSD2h*vc!a!+1f%Yy+QQ!dd1#! pof+;mI=I%P0BEcKxL!S_!KyWu;=NaQ*k}{{Tk_))W8$ diff --git a/awesome-python3-webapp/www/app.py b/awesome-python3-webapp/www/app.py index 10d22e7..f9f8d5d 100644 --- a/awesome-python3-webapp/www/app.py +++ b/awesome-python3-webapp/www/app.py @@ -1,10 +1,9 @@ import logging -import asyncio -import json -import os -import time -from aiohttp import web +import asyncio, os, json, time from datetime import datetime + +from aiohttp import web +from urllib import parse from jinja2 import Environment, FileSystemLoader import orm @@ -12,13 +11,9 @@ logging.basicConfig(level=logging.INFO) -# def index(request): -# return web.Response(body='你好'.encode(encoding='utf-8'), -# headers={'Content-Type': 'text/html;charset=utf-8'}) - def init_jinja2(app, **kw): - logging.info('init jinja2....') + logging.info('init jinja2...') options = dict(autoescape=kw.get('autoescape', True), block_start_string=kw.get('block_start_string', '{%'), block_end_string=kw.get('block_end_string', '%}'), @@ -26,7 +21,6 @@ def init_jinja2(app, **kw): variable_end_string=kw.get('variable_end_string', '}}'), auto_reload=kw.get('auto_reload', True)) path = kw.get('path', None) - # logging.info('set jinja2 template path: %s' % path) if path is None: path = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'templates') @@ -36,41 +30,57 @@ def init_jinja2(app, **kw): if filters is not None: for name, f in filters.items(): env.filters[name] = f - app['__templates__'] = env + app['__templating__'] = env +# -------------------------工厂函数------------------------------------ +# 在每个响应之前打印日志 +async def logger_factory(app, handler): -@asyncio.coroutine -def logger_factory(app, handler): - def logger(request): - logging.info('Request: %s %s' % (request.method, request.path)) - # await asyncio.sleep(0.3) - return handler(request) + async def logger(request): + logging.info('Response: %s %s' % (request.method, request.path)) + return await handler(request) return logger -@asyncio.coroutine -def data_factory(app, handler): - def parse_data(request): +async def data_factory(app, handler): + + async def parse_data(request): + logging.info('data_factory...') if request.method == 'POST': - if request.content_type.startswith('application/json'): - request.__data__ = request.json() - logging.info('request json: %s' % str(request.__data__)) - elif request.content_type.startswith( - 'application/x-www-form-urlencoded'): - request.__data__ = request.post() - logging.info('request form: %s' % str(request.__data__)) - return handler(request) + if not request.content_type: + return web.HTTPBadRequest(text='Missing Content-Type.') + content_type = request.content_type.lower() + if content_type.startswith('application/json'): + request.__data__ = await request.json() + if not isinstance(request.__data__, dict): + return web.HTTPBadRequest(text='JSON body must be object.') + logging.info('request json: %s' % request.__data__) + elif content_type.startswith( + ('application/x-www-form-urlencoded', 'multipart/form-data')): + params = await request.json() + request.__data__ = dict(**params) + logging.info('request form: %s' % request.__data__) + else: + return web.HTTPBadRequest(text='Unsupported Content-Type: %s' % + content_type) + elif request.method == 'GET': + qs = request.query_string + request.__data__ = {k: v[0] for k, v in parse.parse_qs(qs, True).items()} + logging.info('request query: %s' % request.__data__) + else: + request.__data__ = dict() + return await handler(request) return parse_data +# 把任何返回值封装成浏览器可正确显示的Response对象 +async def response_factory(app, handler): -@asyncio.coroutine -def response_factory(app, handler): - def response(request): + async def response(request): logging.info('Response handler...') - r = handler(request) - logging.info(type(r)) + r = await handler(request) + logging.info('Method request -- done : %s' % request.method) if isinstance(r, web.StreamResponse): return r if isinstance(r, bytes): @@ -92,18 +102,20 @@ def response(request): resp.content_type = 'application/json;charset=utf-8' return resp else: + # 如果用jinja2渲染,绑定已验证过的用户 + r['__user__'] = request.__user__ resp = web.Response( body=app['__templating__'].get_template(template).render( **r).encode('utf-8')) resp.content_type = 'text/html;charset=utf-8' return resp - if isinstance(r, int) and r >= 100 and r < 600: - return web.Response(r) + if isinstance(r, int) and 100 <= r < 600: + return web.Response(status=r) if isinstance(r, tuple) and len(r) == 2: - t, m = r - if isinstance(t, int) and t >= 100 and t < 600: - return web.Response(t, str(m)) - # default: + status, message = r + if isinstance(status, int) and 100 <= status < 600: + return web.Response(status=status, text=str(message)) + # default resp = web.Response(body=str(r).encode('utf-8')) resp.content_type = 'text/plain;charset=utf-8' return resp @@ -125,24 +137,17 @@ def datetime_filter(t): return u'%s年%s月%s日' % (dt.year, dt.month, dt.day) -@asyncio.coroutine -def init(loop): - orm.create_pool(loop=loop, - host='localhost', - post=3306, - user='sa', - password='P@ssw0rd', - db='awesome') - app = web.Application(loop=loop, - middlewares=[ - logger_factory, response_factory - ]) +async def init(loop): + await orm.create_pool(loop=loop, + user='sa', + password='P@ssw0rd', + db='awesome') + app = web.Application(loop=loop, middlewares=[logger_factory, response_factory]) init_jinja2(app, filters=dict(datetime=datetime_filter)) add_routes(app, 'handlers') add_static(app) - # app.router.add_route("GET", "/", index) - srv = yield from loop.create_server(app.make_handler(), '127.0.0.1', 9003) - logging.info('Server started at http://127.0.0.1:9003') + srv = await loop.create_server(app.make_handler(), '127.0.0.1', 9000) + logging.info('server started at http://127.0.0.1:9000...') return srv diff --git a/awesome-python3-webapp/www/coroweb.py b/awesome-python3-webapp/www/coroweb.py index 4487ebf..d874994 100644 --- a/awesome-python3-webapp/www/coroweb.py +++ b/awesome-python3-webapp/www/coroweb.py @@ -10,6 +10,10 @@ def get(path): + ''' + Define decorator @get('/path') + ''' + def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): @@ -23,6 +27,10 @@ def wrapper(*args, **kw): def post(path): + ''' + Define decorator @post('/path') + ''' + def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): @@ -71,7 +79,6 @@ def has_request_arg(fn): sig = inspect.signature(fn) params = sig.parameters found = False - for name, param in params.items(): if name == 'request': found = True @@ -84,71 +91,9 @@ def has_request_arg(fn): % (fn.__name__, str(sig))) return found -# class RequestHandler(object): -# def __init__(self, app, fn): -# self._app = app -# self._func = fn -# self._has_request_arg = has_request_arg(fn) -# self._has_var_kw_arg = has_var_kw_arg(fn) -# self._has_named_kw_args = has_named_kw_args(fn) -# self._named_kw_args = get_named_kw_args(fn) -# self._required_kw_args = get_required_kw_args(fn) -# -# def __call__(self, request): -# kw = None -# if self._has_var_kw_arg or self._has_named_kw_args or self._required_kw_args: -# if request.method == 'POST': -# if not request.content_type: -# return web.HTTPBadRequest('Missing content-type') -# ct = request.content_type.lower() -# if ct.startswith('application/json'): -# params = request.json() -# if not isinstance(params, dict): -# return web.HTTPBadRequest('JSON body must be object.') -# kw = params -# elif ct.startswith( -# 'application/x-www-form-urlencoded') or ct.startswith( -# 'multipart/form-data'): -# params = request.post() -# kw = dict(**params) -# else: -# return web.HTTPBadRequest('Unsupported Content-Type:%s' % -# request.content_type) -# if request.method == 'GET': -# qs = request.quert_string -# if qs: -# kw = dict() -# for k, v in parse.parse_qs(qs, True).items(): -# kw[k] = v[0] -# if kw is None: -# kw = dict(**request.match_info) -# else: -# if not self._has_var_kw_arg and self._named_kw_args: -# copy = dict() -# for name in self._named_kw_args: -# if name in kw: -# copy[name] = name -# kw = copy -# for k, v in request.match_info.items(): -# if k in kw: -# logging.warning( -# 'Duplicate arg name in named arg and kw args: %s' % k) -# kw[k] = v -# if self._has_request_arg: -# kw['request'] = request -# if self._required_kw_args: -# for name in self._required_kw_args: -# if name not in kw: -# return web.HTTPBadRequest('Missing argument:%s' % name) -# logging.info('Call with args :%s ' % str(kw)) -# try: -# r = self._func(**kw) -# return r -# except Exception as e: -# return dict(error=e.error, data=e.data, message=e.message) - class RequestHandler(object): + logging.info('RequestHandler Start....') def __init__(self, app, fn): self._app = app self._func = fn @@ -157,8 +102,11 @@ def __init__(self, app, fn): self._has_named_kw_args = has_named_kw_args(fn) self._named_kw_args = get_named_kw_args(fn) self._required_kw_args = get_required_kw_args(fn) + logging.info('RequestHandler init .... ') + logging.info('object %s' % object) async def __call__(self, request): + logging.info('RequestHandler Method request: %s' % request.method) kw = None if self._has_var_kw_arg or self._has_named_kw_args or self._required_kw_args: if request.method == 'POST': @@ -205,44 +153,47 @@ async def __call__(self, request): # check required kw: if self._required_kw_args: for name in self._required_kw_args: - if not name in kw: + if name not in kw: return web.HTTPBadRequest('Missing argument: %s' % name) logging.info('call with args: %s' % str(kw)) + try: r = await self._func(**kw) return r - except APIError as e: + except Exception as e: return dict(error=e.error, data=e.data, message=e.message) def add_static(app): path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static') app.router.add_static('/static/', path) - logging.info('add static %s => %s ' % ('/static/', path)) + logging.info('add static %s => %s' % ('/static/', path)) def add_route(app, fn): method = getattr(fn, '__method__', None) path = getattr(fn, '__route__', None) + logging.info('path: %s,method: %s' % (path,method)) if path is None or method is None: raise ValueError('@get or @post not defined in %s.' % str(fn)) - if not asyncio.iscoroutinefunction(fn) and not inspect.signature(fn): + if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction( + fn): fn = asyncio.coroutine(fn) logging.info('add route %s %s => %s(%s)' % (method, path, fn.__name__, ', '.join(inspect.signature(fn).parameters.keys()))) + # logging.info('method: %s,fn: %s' % (method,fn)) app.router.add_route(method, path, RequestHandler(app, fn)) -def add_routes(app, moudle_name): - n = moudle_name.rfind('.') - # logging.info(' n %s ' % str(n)) +def add_routes(app, module_name): + n = module_name.rfind('.') if n == (-1): - mod = __import__(moudle_name, globals(), locals()) + mod = __import__(module_name, globals(), locals()) else: - name = moudle_name[n + 1:] + name = module_name[n + 1:] mod = getattr( - __import__(moudle_name[:n], globals(), locals(), [name]), name) + __import__(module_name[:n], globals(), locals(), [name]), name) for attr in dir(mod): if attr.startswith('_'): continue diff --git a/awesome-python3-webapp/www/handlers.py b/awesome-python3-webapp/www/handlers.py index 3ba13dd..f3f6833 100644 --- a/awesome-python3-webapp/www/handlers.py +++ b/awesome-python3-webapp/www/handlers.py @@ -1,18 +1,25 @@ -import re -import time -import json -import logging -import hashlib -import base64 -import asyncio +import re, time, json, logging, hashlib, base64, asyncio from coroweb import get, post from models import User, Comment, Blog, next_id +# @get('/') +# async def index(request): +# logging.info('users') +# users = await User.findAll() +# return {'__template__': 'test.html', 'users': users} +# +# +# @get('/test') +# async def index(request): +# logging.info('test') +# users = await User.findAll() +# return {'__template__': 'test.html', 'users': users} + +# 测试 @get('/') -def index(request): - logging.info('test User.findAll()') - users = User.findAll() +async def index(request): + users = await User.findAll() return {'__template__': 'test.html', 'users': users} diff --git a/awesome-python3-webapp/www/orm.py b/awesome-python3-webapp/www/orm.py index c5a54ff..8b33dd5 100644 --- a/awesome-python3-webapp/www/orm.py +++ b/awesome-python3-webapp/www/orm.py @@ -9,54 +9,60 @@ logging.basicConfig(level=logging.INFO) -@asyncio.coroutine -def create_pool(loop, **kw): +async def create_pool(loop, **kw): logging.info('create database connection pool...') global __pool - __pool = yield from aiomysql.create_pool( - host=kw.get('host', 'localhost'), - port=kw.get('port', 3306), - user=kw['user'], - password=kw['password'], - db=kw['db'], - charset=kw.get('charset', 'utf8'), - autocommit=kw.get('autocommit', True), - maxsize=kw.get('maxsize', 10), - minsize=kw.get('minsize', 1), - loop=loop) + __pool = await aiomysql.create_pool(host=kw.get('host', 'localhost'), + port=kw.get('port', 3306), + user=kw['user'], + password=kw['password'], + db=kw['db'], + charset=kw.get('charset', 'utf8'), + autocommit=kw.get('autocommit', True), + maxsize=kw.get('maxsize', 10), + minsize=kw.get('minsize', 1), + loop=loop) def log(sql, args=()): logging.info('SQL: %s' % sql) -@asyncio.coroutine -def select(sql, args, size=None): +async def select(sql, args, size=None): log(sql, args) - global __pool - with (yield from __pool) as conn: - cur = yield from conn.cursor(aiomysql.DictCursor) - yield from cur.execute(sql.replace('?', '%s'), args or ()) - if size: - rs = yield from cur.fetchmany(size) - else: - rs = yield from cur.fetchall() - yield from cur.close() - logging.info('rows returned %s' % len(rs)) - return rs - - -def execute(sql, args): - log(sql) - with (yield from __pool) as conn: + async with __pool.get() as conn: + # 等待连接对象返回DictCursor可以通过dict的方式获取数据库对象,需要通过游标对象执行SQL + async with conn.cursor(aiomysql.DictCursor) as cur: + await cur.execute( + sql.replace('?', '%s'), + args) #将sql中的'?'替换为'%s',因为mysql语句中的占位符为%s + #如果传入size' + if size: + resultset = await cur.fetchmany(size) # 从数据库获取指定的行数 + else: + resultset = await cur.fetchall() # 返回所有的结果集 + logging.info('rows returned: %s' % len(resultset)) + return resultset + + +async def execute(sql, args, autocommit=True): + log(sql, args) + async with __pool.get() as conn: + if not autocommit: # 若数据库的事务为非自动提交的,则调用协程启动连接 + await conn.begin() try: - cur = yield from conn.cursor() - yield from cur.execute(sql.replace('?', '%s'), args) - affected = cur.rowcount - yield from cur.close() - except Exception as e: - raise + async with conn.cursor( + aiomysql. + DictCursor) as cur: # 打开一个DictCursor,它与普通游标的不同在于,以dict形式返回结果 + await cur.execute(sql.replace('?', '%s'), args) + affected = cur.rowcount # 返回受影响的行数 + if not autocommit: # 同上, 事务非自动提交型的,手动调用协程提交增删改事务 + await conn.commit() + except BaseException as e: + if not autocommit: # 出错, 回滚事务到增删改之前 + await conn.rollback() + raise e return affected @@ -163,7 +169,7 @@ def __getattr__(self, key): try: return self[key] except KeyError: - raise AttributeError(r'Model object has no attribute %s' % key) + raise AttributeError(r"'Model' object has no attribute '%s'" % key) def __setattr__(self, key, value): self[key] = value @@ -184,27 +190,29 @@ def getValueOrDefault(self, key): return value @classmethod - @asyncio.coroutine - def find(cls, pk): + async def find(cls, pk): logging.info('find object by primary key') - rs = yield from select('%s where `%s`=?', - (cls.__select__, cls.__primary_key__), [pk], 1) + rs = await select('%s where `%s`=?' % + (cls.__select__, cls.__primary_key__), [pk], 1) if len(rs) == 0: return None return cls(**rs[0]) - @asyncio.coroutine - def save(self): + @classmethod + async def save(self): args = list(map(self.getValueOrDefault, self.__fields__)) args.append(self.getValueOrDefault(self.__primary_key__)) logging.info(args) - rows = yield from execute(self.__insert__, args) + rows = await execute(self.__insert__, args) if rows != 1: logging.warn('failed to insert record: affected rows: %s' % rows) - @asyncio.coroutine - def findAll(cls, where=None, args=None, **kw): + @classmethod + async def findAll(cls, where=None, args=None, **kw): + ' find objects by where clause. ' sql = [cls.__select__] + # logging.info(cls.__select__) + logging.info(select(' '.join(sql), args)) if where: sql.append('where') sql.append(where) @@ -225,5 +233,5 @@ def findAll(cls, where=None, args=None, **kw): args.extend(limit) else: raise ValueError('Invalid limit value: %s' % str(limit)) - rs = select(' '.join(sql), args) + rs = await select(' '.join(sql), args) return [cls(**r) for r in rs] diff --git a/awesome-python3-webapp/www/templates/test.html b/awesome-python3-webapp/www/templates/test.html index f23da43..939356a 100644 --- a/awesome-python3-webapp/www/templates/test.html +++ b/awesome-python3-webapp/www/templates/test.html @@ -6,9 +6,7 @@ -

All users

{% for u in users %} -

{{ u.name }} / {{ u.email }}

- {% endfor %} +

My name is chenshi2

diff --git a/awesome-python3-webapp/www/test.py b/awesome-python3-webapp/www/test.py index 2702e7f..01d6ce2 100644 --- a/awesome-python3-webapp/www/test.py +++ b/awesome-python3-webapp/www/test.py @@ -2,6 +2,8 @@ import asyncio import sys from models import User, Blog, Comment +import logging +# from confi_default import configs @asyncio.coroutine @@ -10,15 +12,17 @@ def test(loop): user='sa', password='P@ssw0rd', db='awesome') - u = User(name='chenshi2', - email='280580216@qq.com', - passwd='123456', - image='about:blank') - yield from u.save() + # u = User(name='chenshi2', + # email='280580216@qq.com', + # passwd='123456', + # image='about:blank') + # yield from u.save() + # users = User.find('0147201758559317d4ca7b200aa46caa9967cce9ae86107000') + # logging.info(users) + users = yield from User.findAll() + for x in users: + logging.info('name is %s , passwd is %s' % (x.name,x.passwd)) loop = asyncio.get_event_loop() loop.run_until_complete(test(loop)) -loop.close() -if loop.is_closed(): - sys.exit(0) From 7cbbc1006efe1c95946d6435c68d2e5daa770d1c Mon Sep 17 00:00:00 2001 From: ChenShi <280580216@qq.com> Date: Fri, 26 Aug 2016 09:53:42 +0800 Subject: [PATCH 2/2] fixed 405 method not allowed pip install aiohttp. --- .../www/__pycache__/coroweb.cpython-35.pyc | Bin 6638 -> 6580 bytes .../www/__pycache__/handlers.cpython-35.pyc | Bin 639 -> 639 bytes .../www/__pycache__/orm.cpython-35.pyc | Bin 8946 -> 8946 bytes awesome-python3-webapp/www/app.py | 105 ++++++------------ awesome-python3-webapp/www/coroweb.py | 20 ++-- 5 files changed, 40 insertions(+), 85 deletions(-) diff --git a/awesome-python3-webapp/www/__pycache__/coroweb.cpython-35.pyc b/awesome-python3-webapp/www/__pycache__/coroweb.cpython-35.pyc index 4cd0f4348a17f409b0fba0c3bc597df0a78cc7e2..99489d4dc7b074e48f10046f055534e4343e254e 100644 GIT binary patch delta 1036 zcmY+CO=uHQ5Xb-Xvf1qBqe(XDrXM1$A$VvJB-KI)TD7RHU!aF#tAq7K>^C#&}h4%h}jDdp?2S(fV1Wpva4W6Ek z^4c&>vC9oE8}JsDmKsVr0D9G#aopP_HEj#t`fgCsKz+!MTU=rQO%n}%1eSGpTcj$O zT*y$b^4b;`GSrCb4%e+lo@5SudmG47FQklIsL5v{_4WQQe|O3@@USh zu;Ufg7ur(g-m09nyyyyVtJ7>CzgxM|QA$%%WGP7|>AVVLQJgH15hkUSN4hw|?=*FB zG}<}srX0!9OrA`6Co_S%4q+Lp}cuEZ+TU1Hefi5L3+rhf!0v&A<=oc-E&rN cr^|zQM*iuE(Fdvbj?sj?)Vm$N5ZB|$zc$ClmH+?% delta 1071 zcmY*Y&ubG=5dLP9Y_i#G^Rr3XdPogz4@&)!meNw%2tCw8RhmPgsI;)L?Y5?Nchyif zrtV9L8%8XdJ)092j}f(q4IWzc{8)$eBZpc?<>D6N?z0A zuRniUdi+jVP~#y0Rer6SyP{r6<@X4r%h02E1T058AJi|@{w@JFU=VbILog)xg+NP! z!?n*F^bojRO%%y66znlv2u=t_9C}#f%(tRl z+fYUBst(Mz!mtx?*lO65V7&~mB0g4FFlsCYD6)uJN5MAgf&TI|^!$gZ3Cw4no<=Uf zjCqA}+f(cDl%Ok~7++fwtq2@Xs^H^&-W-FSf{_++JuXNZ8IhX1)sLGJS~6NuI8o>- z`W&8~jOm>!EwRh`He)ayVk|L~Y?n~G@w_|agn2|_+&Qq*?HEJzoR`jVixOH29DaD@ zGRy-K9TaZFQWS1Q*JM9sNwi-26^6gfHgJ|c-@Z}&pynalp6GxdP>38Qg74|7;z z!a{rc5!n zlr5<b%HZqD=PQs=Y3hocB3TmE3Q=*Mq{# z`F*Oohxs$bH;iT#*?=;<3RI*#uXyKA{sGaPyI!2-%66{c9u^by(LE|wX~xz14kGgj HIg$DYK$g|v diff --git a/awesome-python3-webapp/www/__pycache__/handlers.cpython-35.pyc b/awesome-python3-webapp/www/__pycache__/handlers.cpython-35.pyc index 88c8f152a17fd75ea25d6e74dbb2d220ca7db6b2..b73f8a6d8b6ddac032cdf9988ef6909539f01c63 100644 GIT binary patch delta 18 Zcmey*@}GrMjF*?ociR5&@{OEjOaMA#1?&I- delta 18 Zcmey*@}GrMjF*>d$<%$}aT__ym;gNH1}Fdk diff --git a/awesome-python3-webapp/www/__pycache__/orm.cpython-35.pyc b/awesome-python3-webapp/www/__pycache__/orm.cpython-35.pyc index 78851e303d831e475268d2e3b1eca4129c579748..576a622542ba793752a6ac3f74fa647dc36c05e7 100644 GIT binary patch delta 19 bcmez5`pK0`jF*>d>A`*B1xg#aUMK+oOl${* delta 19 acmez5`pK0`jF*>-W9z=~X2p$MFO&dAO9t)$ diff --git a/awesome-python3-webapp/www/app.py b/awesome-python3-webapp/www/app.py index f9f8d5d..92cae8b 100644 --- a/awesome-python3-webapp/www/app.py +++ b/awesome-python3-webapp/www/app.py @@ -1,29 +1,27 @@ -import logging +import logging; logging.basicConfig(level=logging.INFO) + import asyncio, os, json, time from datetime import datetime from aiohttp import web -from urllib import parse from jinja2 import Environment, FileSystemLoader import orm from coroweb import add_routes, add_static -logging.basicConfig(level=logging.INFO) - - def init_jinja2(app, **kw): logging.info('init jinja2...') - options = dict(autoescape=kw.get('autoescape', True), - block_start_string=kw.get('block_start_string', '{%'), - block_end_string=kw.get('block_end_string', '%}'), - variable_start_string=kw.get('variable_start_string', '{{'), - variable_end_string=kw.get('variable_end_string', '}}'), - auto_reload=kw.get('auto_reload', True)) + options = dict( + autoescape = kw.get('autoescape', True), + block_start_string = kw.get('block_start_string', '{%'), + block_end_string = kw.get('block_end_string', '%}'), + variable_start_string = kw.get('variable_start_string', '{{'), + variable_end_string = kw.get('variable_end_string', '}}'), + auto_reload = kw.get('auto_reload', True) + ) path = kw.get('path', None) if path is None: - path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), 'templates') + path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates') logging.info('set jinja2 template path: %s' % path) env = Environment(loader=FileSystemLoader(path), **options) filters = kw.get('filters', None) @@ -32,55 +30,29 @@ def init_jinja2(app, **kw): env.filters[name] = f app['__templating__'] = env -# -------------------------工厂函数------------------------------------ -# 在每个响应之前打印日志 async def logger_factory(app, handler): - async def logger(request): - logging.info('Response: %s %s' % (request.method, request.path)) - return await handler(request) - + logging.info('Request: %s %s' % (request.method, request.path)) + # await asyncio.sleep(0.3) + return (await handler(request)) return logger - async def data_factory(app, handler): - async def parse_data(request): - logging.info('data_factory...') if request.method == 'POST': - if not request.content_type: - return web.HTTPBadRequest(text='Missing Content-Type.') - content_type = request.content_type.lower() - if content_type.startswith('application/json'): + if request.content_type.startswith('application/json'): request.__data__ = await request.json() - if not isinstance(request.__data__, dict): - return web.HTTPBadRequest(text='JSON body must be object.') - logging.info('request json: %s' % request.__data__) - elif content_type.startswith( - ('application/x-www-form-urlencoded', 'multipart/form-data')): - params = await request.json() - request.__data__ = dict(**params) - logging.info('request form: %s' % request.__data__) - else: - return web.HTTPBadRequest(text='Unsupported Content-Type: %s' % - content_type) - elif request.method == 'GET': - qs = request.query_string - request.__data__ = {k: v[0] for k, v in parse.parse_qs(qs, True).items()} - logging.info('request query: %s' % request.__data__) - else: - request.__data__ = dict() - return await handler(request) - + logging.info('request json: %s' % str(request.__data__)) + elif request.content_type.startswith('application/x-www-form-urlencoded'): + request.__data__ = await request.post() + logging.info('request form: %s' % str(request.__data__)) + return (await handler(request)) return parse_data -# 把任何返回值封装成浏览器可正确显示的Response对象 async def response_factory(app, handler): - async def response(request): logging.info('Response handler...') r = await handler(request) - logging.info('Method request -- done : %s' % request.method) if isinstance(r, web.StreamResponse): return r if isinstance(r, bytes): @@ -96,33 +68,25 @@ async def response(request): if isinstance(r, dict): template = r.get('__template__') if template is None: - resp = web.Response(body=json.dumps( - r, ensure_ascii=False, - default=lambda o: o.__dict__).encode('utf-8')) + resp = web.Response(body=json.dumps(r, ensure_ascii=False, default=lambda o: o.__dict__).encode('utf-8')) resp.content_type = 'application/json;charset=utf-8' return resp else: - # 如果用jinja2渲染,绑定已验证过的用户 - r['__user__'] = request.__user__ - resp = web.Response( - body=app['__templating__'].get_template(template).render( - **r).encode('utf-8')) + resp = web.Response(body=app['__templating__'].get_template(template).render(**r).encode('utf-8')) resp.content_type = 'text/html;charset=utf-8' return resp - if isinstance(r, int) and 100 <= r < 600: - return web.Response(status=r) + if isinstance(r, int) and r >= 100 and r < 600: + return web.Response(r) if isinstance(r, tuple) and len(r) == 2: - status, message = r - if isinstance(status, int) and 100 <= status < 600: - return web.Response(status=status, text=str(message)) - # default + t, m = r + if isinstance(t, int) and t >= 100 and t < 600: + return web.Response(t, str(m)) + # default: resp = web.Response(body=str(r).encode('utf-8')) resp.content_type = 'text/plain;charset=utf-8' return resp - return response - def datetime_filter(t): delta = int(time.time() - t) if delta < 60: @@ -136,13 +100,11 @@ def datetime_filter(t): dt = datetime.fromtimestamp(t) return u'%s年%s月%s日' % (dt.year, dt.month, dt.day) - async def init(loop): - await orm.create_pool(loop=loop, - user='sa', - password='P@ssw0rd', - db='awesome') - app = web.Application(loop=loop, middlewares=[logger_factory, response_factory]) + await orm.create_pool(loop=loop, host='127.0.0.1', port=3306, user='sa', password='P@ssw0rd', db='awesome') + app = web.Application(loop=loop, middlewares=[ + logger_factory, response_factory + ]) init_jinja2(app, filters=dict(datetime=datetime_filter)) add_routes(app, 'handlers') add_static(app) @@ -150,7 +112,6 @@ async def init(loop): logging.info('server started at http://127.0.0.1:9000...') return srv - loop = asyncio.get_event_loop() loop.run_until_complete(init(loop)) -loop.run_forever() +loop.run_forever() \ No newline at end of file diff --git a/awesome-python3-webapp/www/coroweb.py b/awesome-python3-webapp/www/coroweb.py index d874994..dd54ed3 100644 --- a/awesome-python3-webapp/www/coroweb.py +++ b/awesome-python3-webapp/www/coroweb.py @@ -102,11 +102,11 @@ def __init__(self, app, fn): self._has_named_kw_args = has_named_kw_args(fn) self._named_kw_args = get_named_kw_args(fn) self._required_kw_args = get_required_kw_args(fn) + logging.info('RequestHandler init .... ') - logging.info('object %s' % object) + logging.info('object %s' % str(object)) async def __call__(self, request): - logging.info('RequestHandler Method request: %s' % request.method) kw = None if self._has_var_kw_arg or self._has_named_kw_args or self._required_kw_args: if request.method == 'POST': @@ -118,14 +118,11 @@ async def __call__(self, request): if not isinstance(params, dict): return web.HTTPBadRequest('JSON body must be object.') kw = params - elif ct.startswith( - 'application/x-www-form-urlencoded') or ct.startswith( - 'multipart/form-data'): + elif ct.startswith('application/x-www-form-urlencoded') or ct.startswith('multipart/form-data'): params = await request.post() kw = dict(**params) else: - return web.HTTPBadRequest('Unsupported Content-Type: %s' % - request.content_type) + return web.HTTPBadRequest('Unsupported Content-Type: %s' % request.content_type) if request.method == 'GET': qs = request.query_string if qs: @@ -145,8 +142,7 @@ async def __call__(self, request): # check named arg: for k, v in request.match_info.items(): if k in kw: - logging.warning( - 'Duplicate arg name in named arg and kw args: %s' % k) + logging.warning('Duplicate arg name in named arg and kw args: %s' % k) kw[k] = v if self._has_request_arg: kw['request'] = request @@ -156,7 +152,6 @@ async def __call__(self, request): if name not in kw: return web.HTTPBadRequest('Missing argument: %s' % name) logging.info('call with args: %s' % str(kw)) - try: r = await self._func(**kw) return r @@ -173,11 +168,10 @@ def add_static(app): def add_route(app, fn): method = getattr(fn, '__method__', None) path = getattr(fn, '__route__', None) - logging.info('path: %s,method: %s' % (path,method)) + logging.info('path:%s,method:%s' % (path,method)) if path is None or method is None: raise ValueError('@get or @post not defined in %s.' % str(fn)) - if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction( - fn): + if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction(fn): fn = asyncio.coroutine(fn) logging.info('add route %s %s => %s(%s)' % (method, path, fn.__name__,