Skip to content

Commit 4c2f58b

Browse files
author
lishuhuakai
committed
add python tutorial homework
1 parent 8bc46a8 commit 4c2f58b

File tree

254 files changed

+55076
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

254 files changed

+55076
-0
lines changed

Python_Tutorial/liaoxuefeng/.idea/.name

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python_Tutorial/liaoxuefeng/.idea/dictionaries/Administrator.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python_Tutorial/liaoxuefeng/.idea/encodings.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python_Tutorial/liaoxuefeng/.idea/liaoxuefeng.iml

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python_Tutorial/liaoxuefeng/.idea/misc.xml

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python_Tutorial/liaoxuefeng/.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python_Tutorial/liaoxuefeng/.idea/workspace.xml

+1,149
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import json, logging, inspect, functools
2+
3+
class APIError(Exception):
4+
'''
5+
the base APIError which contains error(required),
6+
data(optional) and message(optional).
7+
'''
8+
def __init__(self, error, data='', message=''):
9+
super().__init__(message)
10+
self.error = error
11+
self.data = data
12+
self.message = message
13+
14+
class APIValueError(APIError):
15+
'''
16+
Indicate the input value has error or invalid.
17+
The data specifies the error field of input form.
18+
'''
19+
def __init__(self, field, message=''):
20+
super().__init__('value : invalid', field, message)
21+
22+
class APIResourceNotFoundError(APIError):
23+
'''
24+
Indicate the resource was not found.
25+
The data specifies the resource name.
26+
'''
27+
def __init__(self, field, message=''):
28+
super().__init__('value:notfound', field, message)
29+
30+
class APIPermissionError(APIError):
31+
'''
32+
Indicate the api has no permission.
33+
'''
34+
def __init__(self, message=''):
35+
super().__init__('permission:forbidden', 'permission', message)
36+
37+
class Page(object):
38+
'''
39+
Page object for display pages.
40+
'''
41+
42+
def __init__(self, item_count, page_index=1, page_size=10):
43+
'''
44+
Init Pagination by item_count, page_index and page_size.
45+
46+
>>> p1 = Page(100, 1)
47+
>>> p1.page_count
48+
10
49+
>>> p1.offset
50+
0
51+
>>> p1.limit
52+
10
53+
>>> p2 = Page(90, 9, 10)
54+
>>> p2.page_count
55+
9
56+
>>> p2.offset
57+
80
58+
>>> p2.limit
59+
10
60+
>>> p3 = Page(91, 10, 10)
61+
>>> p3.page_count
62+
10
63+
>>> p3.offset
64+
90
65+
>>> p3.limit
66+
10
67+
'''
68+
self.item_count = item_count # 总的item的数目
69+
self.page_size = page_size # 每一页item的数目
70+
self.page_count = item_count // page_size + (1 if item_count % page_size > 0 else 0)
71+
if (item_count == 0) or (page_index > self.page_count):
72+
self.offset = 0
73+
self.limit = 0
74+
self.page_index = 1
75+
else:
76+
self.page_index = page_index
77+
self.offset = self.page_size * (page_index - 1)
78+
self.limit = self.page_size # 每一页的数目
79+
self.has_next = self.page_index < self.page_count # 之后是否还有
80+
self.has_previous = self.page_index > 1 # 之前是否还有
81+
82+
def __str__(self):
83+
return 'item_count:%s, page_count:%s,page_index:%s, page_size:%s,limit:%s'\
84+
% (self.item_count, self.page_count, self.page_index, self.page_size, self.limit)
85+
__repr__ = __str__
86+
+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import logging; logging.basicConfig(level=logging.INFO)
2+
3+
import asyncio, os, json, time
4+
from datetime import datetime
5+
6+
from aiohttp import web
7+
from jinja2 import Environment, FileSystemLoader
8+
9+
import orm
10+
from coroweb import add_routes, add_static
11+
from handlers import cookie2user, COOKIE_NAME
12+
'''
13+
async web application.
14+
'''
15+
16+
# 我这里有一点非常好奇的是,/api/这一类的函数究竟是如何被调用的。
17+
def init_jinja2(app, **kw):
18+
'''
19+
初始化jinja2
20+
'''
21+
logging.info('init jinja2...')
22+
options = dict(
23+
autoescape = kw.get('autoescape', True),
24+
block_start_string = kw.get('block_start_string', '{%'),
25+
block_end_string = kw.get('block_end_string', '%}'),
26+
variable_start_string = kw.get('variable_start_string', '{{'),
27+
variable_end_string = kw.get('variable_end_string', '}}'),
28+
auto_reload = kw.get('auto_reload', True)
29+
)
30+
path = kw.get('path', None)
31+
if path is None:
32+
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
33+
logging.info('set jinja2 template path: %s' % path)
34+
env = Environment(loader=FileSystemLoader(path), **options) # options是一些选项
35+
filters = kw.get('filters', None)
36+
if filters is not None:
37+
for name, f in filters.items(): # filter是一个字典类型喽!
38+
env.filters[name] = f # 添加过滤器
39+
app['__templating__'] = env # 模版
40+
41+
42+
async def logger_factory(app, handler):
43+
async def logger(request):
44+
logging.info('Request: %s %s' % (request.method, request.path))
45+
return (await handler(request))
46+
return logger # 返回一个装饰器
47+
48+
async def data_factory(app, handler):
49+
async def parse_data(request):
50+
if request.method == 'POST': # 需要提交数据
51+
if request.content_type.startswith('application/json'):
52+
request.__data__ = await request.json() # 记录下数据
53+
logging.info('request json: %s' % str(request.__data__))
54+
elif request.content_type.startswith('application/x-www-form-urlencoded'):
55+
request.__data__ = await request.post()
56+
logging.info('request form: %s' % str(request.__data__))
57+
return (await handler(request))
58+
return parse_data
59+
60+
async def response_factory(app, handler):
61+
'''
62+
中间件,我的感觉是handler会依次通过这些中间件函数,有中间件函数来对handler来做一些处理
63+
'''
64+
async def response(request):
65+
logging.info('Response handler...')
66+
r = await handler(request) # handler函数接收一个request,然后返回一个response对象
67+
# r是返回的response对象,事实上,这个函数是最后才调用
68+
if isinstance(r, web.StreamResponse):
69+
return r
70+
if isinstance(r, bytes):
71+
resp = web.Response(body=r)
72+
resp.content_type = 'application/octet-stream'
73+
return resp
74+
if isinstance(r, str): # 在这个程序中,重定向一般返回一段字符,以redirect:开头
75+
if r.startswith('redirect:'):
76+
return web.HTTPFound(r[9:]) # HTTPFound对应的状态码应该是302
77+
resp = web.Response(body=r.encode('utf-8')) # 如果不是以redirect:开头,那么,直接返回这段文本
78+
resp.content_type = 'text/html;charset=utf-8'
79+
return resp
80+
if isinstance(r, dict): # 如果返回了一个字典的话
81+
template = r.get('__template__')
82+
if template is None: # 并且r中并没有关于template的信息的话,就会将返回的dict数据以json的形式dump出去
83+
resp = web.Response(body=json.dumps(
84+
r,
85+
ensure_ascii=False,
86+
default=lambda o: o.__dict__).encode('utf-8')
87+
)
88+
resp.content_type = 'application/json;charset=utf-8'
89+
return resp
90+
else: # 渲染页面
91+
# 首先加入用户的信息
92+
r['__user__'] = request.__user__
93+
resp = web.Response(body=app['__templating__'].get_template(template).render(**r).encode('utf-8'))
94+
resp.content_type = 'text/html;charset=utf-8'
95+
return resp
96+
if isinstance(r, int) and r >= 100 and r < 600:
97+
return web.Response(status=r) # 返回状态码
98+
if isinstance(r, tuple) and len(r) == 2: # 如果返回了一个元组
99+
t, m = r # t代表状态码,然后m代表body的信息
100+
if isinstance(t, int) and t >= 100 and t < 600:
101+
return web.Response(status=t, body=str(m))
102+
# default:
103+
resp = web.Response(body=str(r).encode('utf-8'))
104+
resp.content_type = 'text/plain;charset=utf-8'
105+
return resp
106+
return response
107+
108+
async def auth_factory(app, handler):
109+
async def auth(request):
110+
logging.info('check user: %s %s' % (request.method, request.path))
111+
request.__user__ = None
112+
cookie_str = request.cookies.get(COOKIE_NAME) # 得到cookies的值
113+
if cookie_str:
114+
user = await cookie2user(cookie_str) # 得到cookies里面存储的用户的信息
115+
if user:
116+
logging.info('set current user:%s' % user.email)
117+
request.__user__ = user # 存储用户的信息
118+
if request.path.startswith('/manage/') and \
119+
(request.__user__ is None or not request.__user__.admin):
120+
return web.HTTPFound('/signin') # 重定向至登陆界面
121+
return (await handler(request))
122+
return auth
123+
124+
def datetime_filter(t):
125+
delta = int(time.time() - t)
126+
if delta < 60:
127+
return u'1分钟前'
128+
if delta < 3600:
129+
return u'%s分钟前' % (delta // 60)
130+
if delta < 86400:
131+
return u'%s小时前' % (delta // 3600)
132+
if delta < 604800:
133+
return u'%s天前' % (delta // 86400)
134+
dt = datetime.fromtimestamp(t)
135+
return u'%s年%s月%s日' % (dt.year, dt.month, dt.day)
136+
137+
async def init(loop):
138+
await orm.create_pool(
139+
loop=loop,
140+
host='127.0.0.1',
141+
port=3306,
142+
user='root',
143+
password='1234',
144+
db='awesome'
145+
)
146+
147+
app = web.Application(loop=loop,
148+
middlewares=[logger_factory, auth_factory, response_factory]
149+
) # 有一个疑问,那就是middlewares究竟是干什么用的?中间件,用于处理handle
150+
# 好似不是这样的。
151+
152+
init_jinja2(app, filters=dict(datetime=datetime_filter))
153+
from coroweb import add_routes, add_static
154+
add_routes(app, 'handlers')
155+
add_static(app)
156+
srv = await loop.create_server(app.make_handler(), '127.0.0.1', 9001)
157+
logging.info('server started at http://127.0.0.1:9001...')
158+
return srv
159+
160+
loop = asyncio.get_event_loop()
161+
loop.run_until_complete(init(loop))
162+
loop.run_forever()
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
'''
3+
Configuration
4+
'''
5+
6+
import config_default
7+
8+
class Dict(dict):
9+
'''
10+
Simple dict but support access as x.y style.
11+
'''
12+
def __init__(self, names=(), values=(), **kw):
13+
super().__init__(**kw)
14+
for k, v in zip(names, values):
15+
self[k] = v
16+
17+
def __getattr__(self, key):
18+
try:
19+
return self[key]
20+
except KeyError:
21+
raise AttributeError(r"'Dict' object has no attributes '%s" % key)
22+
23+
def __setattr__(self, key, value):
24+
self[key] = value
25+
26+
def merge(defaults, override):
27+
r = {}
28+
for k, v in defaults.items():
29+
if k in override:
30+
if isinstance(v, dict):
31+
r[k] = merge(v, override[k])
32+
else:
33+
r[k] = override[k]
34+
else:
35+
r[k] = v
36+
return r
37+
38+
def toDict(d):
39+
D = Dict()
40+
for k, v in d.items():
41+
D[k] = toDict(v) if isinstance(v, dict) else v
42+
return D
43+
44+
configs = config_default.configs
45+
46+
try:
47+
import config_override
48+
configs = merge(configs, config_override.configs)
49+
except ImportError:
50+
pass
51+
52+
configs = toDict(configs)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
configs = {
3+
'db' : {
4+
'host': '127.0.0.1',
5+
'port': 3306,
6+
'user': 'root',
7+
'password': '1234',
8+
'database': 'awesome'
9+
},
10+
'session' : {
11+
'secret': 'Awesome'
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
configs = {
3+
'db' : {
4+
'host':'127.0.0.1'
5+
}
6+
}

0 commit comments

Comments
 (0)