/
route.py
110 lines (82 loc) · 2.97 KB
/
route.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
""" Utilities for traversal """
from pyramid.httpexceptions import HTTPNotFound
class ISmartLookupResource(object):
"""
Resource base class that allows hierarchical lookup of attributes
Potential use case: /user/1234/post/5678
At the /user/1234 point in traversal you can set a 'user' attribute on the
resource. At the 'post/5678' point in traversal you can set a 'post'
attribute on *that* resource. Then the request can access both of them from
the context directly:
.. code-block:: python
def get_user_post(context, request):
user = context.user
if user.is_cool():
return context.post
"""
__name__ = ''
__parent__ = None
def __getattr__(self, name):
if name.startswith('_'):
raise AttributeError()
current = self.__parent__
while current is not None:
try:
return getattr(current, name)
except AttributeError:
# If this node was doing smart lookup, we don't need to
if isinstance(current, ISmartLookupResource):
break
current = current.__parent__
raise AttributeError("'%s' not found on any parents of %s" %
(name, self))
class IStaticResource(ISmartLookupResource):
""" Simple resource base class for static-mapping of paths """
subobjects = {}
def __getitem__(self, name):
child = self.subobjects[name]()
child.__parent__ = self
child.__name__ = name
return child
class IModelResource(ISmartLookupResource):
"""
Resource base class for wrapping models in a sqlalchemy database
Notes
-----
Requires any parent node to set the 'request' attribute
"""
__model__ = None
__modelname__ = 'model'
def __init__(self, model=None):
setattr(self, self.__modelname__, model)
@property
def db(self):
"""
Access the SQLAlchemy session on the request
Override this if your session is named something other than 'db'
"""
return self.request.db
def get_model(self, name):
"""
Retrieve a model from the database
Override this for custom queries
"""
return self.db.query(self.__model__).filter_by(id=name).first()
def create_model(self, name):
"""
Override this if you wish to allow 'PUT' request to create a model
"""
raise KeyError
def __getitem__(self, name):
if getattr(self, self.__modelname__) is None:
model = self.get_model(name)
if model is None and self.request.method == 'PUT':
model = self.create_model(name)
if model is not None:
child = self.__class__(model)
child.__parent__ = self
child.__name__ = name
return child
else:
raise HTTPNotFound()
raise KeyError