[Python] Lesen Sie den Quellcode von Flasche Teil 1

Lesen Sie Flasche.py

Ich habe versucht, den Code von Bottle, einem Webframework von Python, zu lesen. Der Quellcode für Bottle ist in Bottle.py zusammengefasst, daher sollten Sie diese Datei lesen.

Klicken Sie hier für GitHub. https://github.com/bottlepy/bottle

Der unten angegebene Code stammt von Bottle.py und enthält nur die erforderlichen Teile. Außerdem füge ich an einigen Stellen Kommentare hinzu.

Es ist schwierig, den Details von Anfang an zu folgen, daher möchte ich zuerst den Gesamtfluss erfassen.

Erster Eingang: run ()

Ich möchte der Quelle in der Reihenfolge vom Start folgen. Starten Sie die Flasche beispielsweise wie folgt gemäß der Dokumentation.

from bottle import route, run, template

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

run(host='localhost', port=8080)

Beginnen wir mit run (). Auch für alle Fälle ist der Quellcode (meistens) kaputt und in Anführungszeichen gesetzt.

bottle.py


def run(app=None,
        server='wsgiref',
        host='127.0.0.1',
        port=8080,
        interval=1,
        reloader=False,
        quiet=False,
        plugins=None,
        debug=None,
        config=None, **kargs):

    app = app or default_app()

    if server in server_names:
            server = server_names.get(server)
        if isinstance(server, basestring):
            server = load(server)
        if isinstance(server, type):
            server = server(host=host, port=port, **kargs)
        if not isinstance(server, ServerAdapter):
            raise ValueError("Unknown or unsupported server: %r" % server)

    if reloader:
            lockfile = os.environ.get('BOTTLE_LOCKFILE')
            bgcheck = FileCheckerThread(lockfile, interval)
            with bgcheck:
                server.run(app)
            if bgcheck.status == 'reload':
                sys.exit(3)
        else:
            server.run(app)

Zusamenfassend

app = app or default_app()  #Der Standardwert ist App=None
server = server_names.get(server)  #Der Standardwert ist Server='wsgiref'
server.run(app)

Korrekt. Schauen wir uns zunächst die Definition von default_app () in der ersten Zeile an.

Was ist die AppStack-Klasse?

Der Definitionsteil ist

apps = app = default_app = AppStack()

damit,

bottle.py



class AppStack(list):
    """ A stack-like list. Calling it returns the head of the stack. """

    def __call__(self):
        """ Return the current default application. """
        return self.default

    def push(self, value=None):
        """ Add a new :class:`Bottle` instance to the stack """
        if not isinstance(value, Bottle):
            value = Bottle()
        self.append(value)
        return value
    new_app = push

    @property
    def default(self):
        try:
            return self[-1]
        except IndexError:
            return self.push()

Aha. AppStack erbt von der Liste. Von der Seite, die "AppStack ()" ("Server") verwendet, ist die Methode "call" wichtig.

Um die Überprüfung der Aufrufmethode zusammenzufassen:

app = AppStack()
app()

Es scheint, dass eine "Bottle" -Instanz zurückgegeben wird (wenn dies das Standardargument ist). Gleichzeitig ist es ein Mechanismus, um es als Liste zu akkumulieren.

Ich würde gerne die Quelle der "Flasche" -Klasse zusammenstellen, aber wie der Name schon sagt, ist dies der Kern von "Flasche" und lang. Erstens ist die AppStack-Instanz


server.run(app)

Es wird als Argument an die run-Methode des Servers übergeben und sollte danach "app ()" heißen. Überprüfen wir also zuerst "server".

Serverklasse

Ein wenig zurückblicken,


app = app or default_app()  #Der Standardwert ist App=None
server = server_names.get(server)  #Der Standardwert ist Server='wsgiref'
server.run(app)

Die Geschichte des Versuchs herauszufinden, wer der "Server" in dem Teil von definiert hat.

bottle.py



server_names = {
    'cgi': CGIServer,
    'flup': FlupFCGIServer,
    'wsgiref': WSGIRefServer,  #Dies ist die Standardeinstellung
    'waitress': WaitressServer,
    #Folgendes wird weggelassen
}

Es ist ein Wörterbuch, und jeder Wert erbt die Klasse "ServerAdapter". Da dies ein "nur übergeordnetes Formular" ist, gehe ich plötzlich zur Klasse "WSGIRefServer".

bottle.py


class WSGIRefServer(ServerAdapter):
    def run(self, app):  # pragma: no cover
        from wsgiref.simple_server import make_server
        from wsgiref.simple_server import WSGIRequestHandler, WSGIServer
        import socket

        server_cls = self.options.get('server_class', WSGIServer)
        self.srv = make_server(self.host, self.port, app, server_cls,
                               handler_cls)
        self.port = self.srv.server_port  # update port actual port (0 means random)
        try:
            self.srv.serve_forever()
        except KeyboardInterrupt:
            self.srv.server_close()  # Prevent ResourceWarning: unclosed socket
            raise

Das an app.ser.run () übergebene app = AppStack () wird an die Funktion make_server übergeben. Die Funktion make_server selbst stammt aus der Python-Standardbibliothek wsgiref.

https://docs.python.org/ja/3/library/wsgiref.html

Die Webserver-Gateway-Schnittstelle (WSGI) ist eine Standardschnittstelle zwischen Webserver-Software und in Python geschriebenen Webanwendungen. Mit einer Standardschnittstelle können Anwendungen, die WSGI unterstützen, auf verschiedenen Webservern problemlos verwendet werden.

Schauen wir uns also das Beispiel in der wsgiref-Dokumentation an.


from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server

def simple_app(environ, start_response):
    setup_testing_defaults(environ)

    status = '200 OK'
    headers = [('Content-type', 'text/plain')]

    start_response(status, headers)

    ret = ["%s: %s\n" % (key, value)
           for key, value in environ.iteritems()]
    return ret

httpd = make_server('', 8000, simple_app)
print "Serving on port 8000..."
httpd.serve_forever()

Korrekt.

Rückblickend auf die bisherigen Quellen war diese Funktion (simple_app im Beispiel ) Bottle ().

Es ist eine Instanz, keine Funktion! aber es ist okay! Wenn Sie eine __call__ Instanz haben, können Sie sie wie eine Funktion aufrufen!

Es scheint langweilig zu sein, aber wenn Sie es organisieren, ist es ein Beispiel


simple_app(environ, start_response)

Die auszuführende Handlung ist

Bottle()(environ, start_response)

Entspricht der Ausführung.

Das ist </ b>

Es scheint offensichtlich, aber die Flascheninstanz ist für die eigentliche Verarbeitung verantwortlich </ b>

Ich fand heraus.

Tatsächlich

bottle.py



class Bottle(object):

    def __call__(self, environ, start_response):

Ist definiert.

Es war so lange.

Die Klasse "Flasche" sollte [Weiter] sein (https://qiita.com/nyancook/items/1181597a10f8c4481a56).

Zusammenfassung bisher

"Bottle ()" wird als Argument an die Funktion "make_server" der Bibliothek "wsgiref" übergeben und ist für die eigentliche Verarbeitung verantwortlich.

Recommended Posts