-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxweb_router.py
75 lines (60 loc) · 2.17 KB
/
xweb_router.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from collections import defaultdict
from functools import partial
from inspect import signature
import parse
__version__ = '0.1.1'
__author__ = 'Jiuli Gao'
__all__ = ('Router',)
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
class Router:
def __init__(self, prefix=''):
self.prefix = prefix
self.routes = defaultdict(list)
async def __call__(self, ctx, fn=None):
for path, handlers in self.routes.items():
parse_result = parse.parse(path, ctx.req.url)
if parse_result is None:
continue
ctx.params = AttributeDict()
ctx.params.update(parse_result.named)
next_fn = None
route_defined = False
for handler in handlers[::-1]:
if handler['method'] is not None and handler['method'] != ctx.req.method:
continue
if len(signature(handler['fn']).parameters) == 2:
if isinstance(handler['fn'], Router):
route_defined = True
next_fn = partial(handler['fn'], ctx=ctx, fn=next_fn)
else:
route_defined = True
next_fn = partial(handler['fn'], ctx=ctx)
if not route_defined:
ctx.abort(405)
await next_fn()
if fn:
await fn()
return
ctx.abort(404)
def use(self, path, method=None):
def callback(fn):
if isinstance(fn, Router):
fn.prefix = path
self.routes[self.prefix + path + '{}'].append({'fn': fn, 'method': method})
else:
self.routes[self.prefix + path].append({'fn': fn, 'method': method})
return callback
def get(self, path):
return self.use(path, 'GET')
def put(self, path):
return self.use(path, 'PUT')
def post(self, path):
return self.use(path, 'POST')
def patch(self, path):
return self.use(path, 'PATCH')
def delete(self, path):
return self.use(path, 'DELETE')