Dieser Artikel ist eine Fortsetzung von Letztes Mal, aber Sie sollten ihn problemlos alleine lesen können. Nun, es ist ein Artikel für meine eigene Organisation ...
Schließlich die "Flaschen" -Klasse des Burgturms.
Zuallererst vom letzten Mal mit der Methode __call__
.
bottle.py
class Bottle(object):
def __call__(self, environ, start_response):
""" Each instance of :class:'Bottle' is a WSGI application. """
return self.wsgi(environ, start_response)
def wsgi(self, environ, start_response):
""" The bottle WSGI-interface. """
try:
out = self._cast(self._handle(environ))
# rfc2616 section 4.3
if response._status_code in (100, 101, 204, 304) or environ['REQUEST_METHOD'] == 'HEAD':
if hasattr(out, 'close'): out.close()
out = []
start_response(response._status_line, response.headerlist)
return out
Mit anderen Worten, der Nachrichtentextteil der Antwort wird aus "self._cast (self._handle (environ))" generiert. Da "self.cast ()" ein Prozess zum Codieren von Daten in ein für eine HTTP-Nachricht geeignetes Format ist, wird der Antwortinhalt tatsächlich von "self._handle (environ)" erstellt.
Das ist etwas lang. Also werde ich versuchen, es bis auf den Ausnahmeblock zu aktualisieren.
bottle.py
#: A thread-safe instance of :class:`LocalResponse`. It is used to change the
#: HTTP response for the *current* request.
response = LocalResponse()
class Bottle(object):
def _handle(self, environ):
path = environ['bottle.raw_path'] = environ['PATH_INFO']
if py3k:
environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore')
environ['bottle.app'] = self
request.bind(environ)
response.bind()
try:
while True: # Remove in 0.14 together with RouteReset
out = None
try:
self.trigger_hook('before_request')
route, args = self.router.match(environ)
environ['route.handle'] = route
environ['bottle.route'] = route
environ['route.url_args'] = args
out = route.call(**args)
break
finally:
if isinstance(out, HTTPResponse):
out.apply(response)
try:
self.trigger_hook('after_request')
return out
Response = LocalResponse ()
erschien plötzlich hier, aber die übergeordnete Klasse BaseResponse
der LocalResponse
-Klasse ist unten definiert.
bottle.py
class BaseResponse(object):
""" Storage class for a response body as well as headers and cookies.
This class does support dict-like case-insensitive item-access to
headers, but is NOT a dict. Most notably, iterating over a response
yields parts of the body and not the headers. #Die folgenden Kommentare werden weggelassen
"""
default_status = 200
default_content_type = 'text/html; charset=UTF-8'
def __init__(self, body='', status=None, headers=None, **more_headers):
self._cookies = None
self._headers = {}
self.body = body
Es scheint Informationen wie Cookies, Header und Textkörper zu enthalten. Ich werde vorerst nicht weiter jagen.
Nun ist "Bottle () ._ handler ()"
route, args = self.router.match(environ)
out = route.call(**args)
return out
Dieser Teil ist der Schlüssel, und es scheint, dass der Routing-Prozess hier ausgeführt wird. Hier bedeutet "self.router" "Router ()" (definiert in "Bottle .__ init__"). Schauen wir uns also diese Klasse an.
bottle.py
class Router(object):
""" A Router is an ordered collection of route->target pairs. It is used to
efficiently match WSGI requests against a number of routes and return
the first target that satisfies the request. The target may be anything,
usually a string, ID or callable object. A route consists of a path-rule
and a HTTP method.
The path-rule is either a static path (e.g. `/contact`) or a dynamic
path that contains wildcards (e.g. `/wiki/<page>`). The wildcard syntax
and details on the matching order are described in docs:`routing`.
"""
def __init__(self, strict=False):
self.rules = [] # All rules in order
self._groups = {} # index of regexes to find them in dyna_routes
self.builder = {} # Data structure for the url builder
self.static = {} # Search structure for static routes
self.dyna_routes = {}
self.dyna_regexes = {} # Search structure for dynamic routes
#: If true, static routes are no longer checked first.
self.strict_order = strict
self.filters = {
're': lambda conf: (_re_flatten(conf or self.default_pattern),
None, None),
'int': lambda conf: (r'-?\d+', int, lambda x: str(int(x))),
'float': lambda conf: (r'-?[\d.]+', float, lambda x: str(float(x))),
'path': lambda conf: (r'.+?', None, None)
}
def match(self, environ):
""" Return a (target, url_args) tuple or raise HTTPError(400/404/405). """
verb = environ['REQUEST_METHOD'].upper()
path = environ['PATH_INFO'] or '/'
if verb == 'HEAD':
methods = ['PROXY', verb, 'GET', 'ANY']
else:
methods = ['PROXY', verb, 'ANY']
for method in methods:
if method in self.static and path in self.static[method]:
target, getargs = self.static[method][path]
return target, getargs(path) if getargs else {}
elif method in self.dyna_regexes:
for combined, rules in self.dyna_regexes[method]:
match = combined(path)
if match:
target, getargs = rules[match.lastindex - 1]
return target, getargs(path) if getargs else {}
Es ist ein wenig chaotisch hier und es ist schwer zu verstehen, was das "Ziel" von "Rückgabeziel, get args (path)" ist, aber wie Sie sehen können, wenn Sie sich "route" ansehen, ist args = self.router.match (environ) " , Die Route
-Instanz wird zurückgegeben, nicht wahr?
Mit anderen Worten, bevor Sie es wissen, wird "Route ()" als "self.static [method] [path]" registriert.
Bevor Sie es wissen! ?? </ b>
Wenn Sie sich die Quellen unten ansehen, sehen Sie nach und nach das große Ganze!
bottle.py
class Bottle(object):
def route(self,
path=None,
method='GET',
callback=None,
name=None,
apply=None,
skip=None, **config):
""" A decorator to bind a function to a request URL. Example::
@app.route('/hello/<name>')
def hello(name):
return 'Hello %s' % name
The ``<name>`` part is a wildcard. See :class:`Router` for syntax
details.
"""
if callable(path): path, callback = None, path
plugins = makelist(apply)
skiplist = makelist(skip)
def decorator(callback):
if isinstance(callback, basestring): callback = load(callback)
for rule in makelist(path) or yieldroutes(callback):
for verb in makelist(method):
verb = verb.upper()
route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config)
self.add_route(route)
return callback
return decorator(callback) if callback else decorator
def add_route(self, route):
""" Add a route object, but do not change the :data:`Route.app`
attribute."""
self.routes.append(route)
self.router.add(route.rule, route.method, route, name=route.name)
if DEBUG: route.prepare()
Also wir
@app.route('/hello/<name>')
def hello(name):
return 'Hello %s' % name
Durch Anbringen eines Dekorateurs, wenn eine Anfrage fliegt
route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config)
self.add_route(route)
Und Sie haben der Instanz "Router" Informationen über die Instanz "Route" gegeben.
Irgendwie wurde mein Kopf wütend ...
Was ich daraus gelernt habe
route, args = self.router.match(environ)
out = route.call(**args)
return out #Antwortdaten sind enthalten!
Die "Route" in ist eine Instanz der "Route" (obwohl dies offensichtlich erscheint), und die "Route (). Call ()" enthält die gewünschten Antwortdaten!
Wenn Sie sich also die Definition der Klasse "Route" ansehen
bottle.py
class Route(object):
""" This class wraps a route callback along with route specific metadata and
configuration and applies Plugins on demand. It is also responsible for
turing an URL path rule into a regular expression usable by the Router.
"""
def __init__(self, app, rule, method, callback,
name=None,
plugins=None,
skiplist=None, **config):
#: The application this route is installed to.
self.app = app
self.callback = callback
#: A list of route-specific plugins (see :meth:`Bottle.route`).
self.plugins = plugins or []
@cached_property
def call(self):
""" The route callback with all plugins applied. This property is
created on demand and then cached to speed up subsequent requests."""
return self._make_callback()
def _make_callback(self):
callback = self.callback
for plugin in self.all_plugins():
try:
if hasattr(plugin, 'apply'):
callback = plugin.apply(callback, self)
else:
callback = plugin(callback)
except RouteReset: # Try again with changed configuration.
return self._make_callback()
if not callback is self.callback:
update_wrapper(callback, self.callback)
return callback
Mit anderen Worten, das Plug-In ist eingeklemmt, und der wichtige Teil ist "self.callback", aber dieser befindet sich in erster Linie in "Bottle.route"
bottle.py
def decorator(callback):
if isinstance(callback, basestring): callback = load(callback)
for rule in makelist(path) or yieldroutes(callback):
for verb in makelist(method):
verb = verb.upper()
route = Route(self, rule, verb, callback, name=name, plugins=plugins, skiplist=skiplist, **config)
self.add_route(route)
return callback
return decorator(callback) if callback else decorator
Sie haben gerade den Rückruf bestanden, der eingegangen ist. das ist
@app.route('/hello/<name>')
def hello(name):
return 'Hello %s' % name
Es entspricht der "Hallo" -Funktion in, was ebenfalls ganz natürlich ist, aber die Antwortdaten werden gemäß der hier definierten Funktion generiert.
Chan-Chan.
So habe ich endlich das ganze Bild bekommen (obwohl ich die Teile der Protokollierung und Fehlerbehandlung ignoriert habe).
Aber die Frage ist
from bottle import route
Ich habe keine Ahnung, warum der "Route" -Dekorator geladen ist. Es fühlt sich so an, als ob die in der Klasse "Route" definierte Dekorationsfunktion in der Umgebung unter dem Namen "Route" registriert ist.
Wenn jemand versteht, lass es mich wissen ... weinen
Recommended Posts