-
Notifications
You must be signed in to change notification settings - Fork 2k
/
common.py
151 lines (115 loc) · 3.87 KB
/
common.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# encoding: utf-8
# This file contains commonly used parts of external libraries. The idea is
# to help in removing helpers from being used as a dependency by many files
# but at the same time making it easy to change for example the json lib
# used.
#
# NOTE: This file is specificaly created for
# from ckan.common import x, y, z to be allowed
from collections import MutableMapping
import flask
import pylons
from werkzeug.local import Local, LocalProxy
from pylons.i18n import _, ungettext
from pylons import g, c, session, response
import simplejson as json
try:
from collections import OrderedDict # from python 2.7
except ImportError:
from sqlalchemy.util import OrderedDict
def is_flask_request():
u'''
A centralized way to determine whether we are in the context of a
request being served by Flask or Pylons
'''
try:
pylons.request.environ
pylons_request_available = True
except TypeError:
pylons_request_available = False
return (flask.request and
(flask.request.environ.get(u'ckan.app') == u'flask_app' or
not pylons_request_available))
class CKANConfig(MutableMapping):
u'''Main CKAN configuration object
This is a dict-like object that also proxies any changes to the
Flask and Pylons configuration objects.
The actual `config` instance in this module is initialized in the
`load_environment` method with the values of the ini file or env vars.
'''
def __init__(self, *args, **kwargs):
self.store = dict()
self.update(dict(*args, **kwargs))
def __getitem__(self, key):
return self.store[key]
def __iter__(self):
return iter(self.store)
def __len__(self):
return len(self.store)
def __repr__(self):
return self.store.__repr__()
def copy(self):
return self.store.copy()
def clear(self):
self.store.clear()
try:
flask.current_app.config.clear()
except RuntimeError:
pass
try:
pylons.config.clear()
# Pylons set this default itself
pylons.config[u'lang'] = None
except TypeError:
pass
def __setitem__(self, key, value):
self.store[key] = value
try:
flask.current_app.config[key] = value
except RuntimeError:
pass
try:
pylons.config[key] = value
except TypeError:
pass
def __delitem__(self, key):
del self.store[key]
try:
del flask.current_app.config[key]
except RuntimeError:
pass
try:
del pylons.config[key]
except TypeError:
pass
def _get_request():
if is_flask_request():
return flask.request
else:
return pylons.request
class CKANRequest(LocalProxy):
u'''Common request object
This is just a wrapper around LocalProxy so we can handle some special
cases for backwards compatibility.
LocalProxy will forward to Flask or Pylons own request objects depending
on the output of `_get_request` (which essentially calls
`is_flask_request`) and at the same time provide all objects methods to be
able to interact with them transparently.
'''
@property
def params(self):
u''' Special case as Pylons' request.params is used all over the place.
All new code meant to be run just in Flask (eg views) should always
use request.args
'''
try:
return super(CKANRequest, self).__getattr__(u'params')
except AttributeError:
return super(CKANRequest, self).__getattr__(u'args')
local = Local()
# This a proxy to the bounded config object
local(u'config')
# Thread-local safe objects
config = local.config = CKANConfig()
# Proxies to already thread-local safe objects
request = CKANRequest(_get_request)