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
|
import threading
from zope.component import getGlobalSiteManager
class ThreadLocalManager(threading.local):
def __init__(self, default=None):
# http://code.google.com/p/google-app-engine-django/issues/detail?id=119
# we *must* use a keword argument for ``default`` here instead
# of a positional argument to work around a bug in the
# implementation of _threading_local.local in Python, which is
# used by GAE instead of _thread.local
self.stack = []
self.default = default
def push(self, info):
self.stack.append(info)
set = push # b/c
def pop(self):
if self.stack:
return self.stack.pop()
def get(self):
try:
return self.stack[-1]
except IndexError:
return self.default()
def clear(self):
self.stack[:] = []
def defaults():
reg = getGlobalSiteManager()
return {'request':None, 'registry':reg}
manager = ThreadLocalManager(default=defaults)
## **The below function ``get_current*`` functions are special. They
## are not part of the official BFG API, however, they're guaranteed
## to live here "forever", so they may be relied on in emergencies.
## However, they should be used extremely sparingly** (read: almost
## never).
## In particular, it's almost always usually a mistake to use
## ``get_current_request`` because its usage makes it possible to
## write code that can be neither easily tested nor scripted. The
## author of this function reserves the right to point and laugh at
## code which uses this function inappropriately. Inappropriate usage
## is defined as follows:
## - ``get_current_request`` should never be called within
## :term:`view` code, or code called by view code. View code
## already has access to the request (it's passed in).
## - ``get_current_request`` should never be called in :term:`model`
## code. Model code should never require any access to the
## request; if your model code requires access to a request object,
## you've almost certainly factored something wrong, and you should
## change your code rather than using this function.
## - The ``get_current_request`` function should never be called
## because it's 'easier' or 'more elegant' to think about calling
## it than to pass a request through a series of function calls
## when creating some API design. Your application should instead
## almost certainly pass data derived from the request around
## rather than relying on being able to call this function to
## obtain the request in places that actually have no business
## knowing about it. Parameters are meant to be passed around as
## function arguments, not obtained from some pseudo-global. Don't
## try to 'save typing' or create 'nicer APIs' by using this
## function in the place where a request is required; this will
## only lead to sadness later.
## - Neither ``get_current_request`` nor ``get_current_registry``
## should never be called within application-specific forks of
## third-party library code. The library you've forked almost
## certainly has nothing to do with repoze.bfg, and making it
## dependent on repoze.bfg (rather than making your repoze.bfg
## application depend upon it) means you're forming a dependency in
## the wrong direction.
## The ``get_current_request`` function *is* still useful in very
## limited circumstances. As a rule of thumb, usage of
## ``get_current_request`` is useful **within code which is meant to
## eventually be removed**. For instance, you may find yourself
## wanting to deprecate some API that expects to be passed a request
## object in favor of one that does not expect to be passed a request
## object. But you need to keep implementations of the old API
## working for some period of time while you deprecate the older API.
## So you write a 'facade' implementation of the new API which calls
## into the code which implements the older API. Since the new API
## does not require the request, your facade implementation doesn't
## have local access to the request when it needs to pass it into the
## older API implementaton. After some period of time, the older
## implementation code is disused and the hack that uses
## ``get_current_request`` is removed. This would be an appropriate
## place to use the ``get_current_request`` function.
## ``get_current_request`` retrieves a request object from a
## thread-local stack that is managed by a :term:`Router` object.
## Therefore the very definition of 'current request' is defined
## entirely by the behavior of a repoze.bfg Router. Scripts which
## use :mod:`repoze.bfg` machinery but never actually start a WSGI
## server or receive requests via HTTP (such as scripts which use the
## :mod:`repoze.bfg.scripting`` API) will never cause any Router code
## to be executed. Such scripts should expect this function to
## always return ``None``.
## ``get_current_registry`` is mostly non-useful if you use the ZCA
## API zope.component.getSiteManager will call it for you.
def get_current_request():
"""Return the currently active request or ``None`` if no request
is currently active. This is *not* an official API.
"""
return manager.get()['request']
def get_current_registry(context=None): # context required by getSiteManager API
"""Return the currently active component registry or the global
component registry if no request is currently active. This is
*not* an official API.
"""
return manager.get()['registry']
|