Kolben + AbhÀngigkeitsinjektor - Anleitung zur AbhÀngigkeitsinjektion

Hallo,



ich bin der Schöpfer von Dependency Injector . Dies ist ein AbhĂ€ngigkeitsinjektionsframework fĂŒr Python.



In diesem Tutorial möchte ich Ihnen zeigen, wie Sie mit dem AbhÀngigkeitsinjektor Flask-Anwendungen entwickeln.



Das Handbuch besteht aus folgenden Teilen:



  1. Was werden wir bauen?
  2. Bereiten Sie die Umgebung vor
  3. Projektstruktur
  4. Hallo Welt!
  5. Einschließlich Stile
  6. Github anschließen
  7. Suchdienst
  8. Suche verbinden
  9. Ein bisschen Refactoring
  10. Tests hinzufĂŒgen
  11. Fazit


Das abgeschlossene Projekt finden Sie auf Github .



Um zu beginnen, mĂŒssen Sie haben:



  • Python 3.5+
  • Virtuelle Umgebung


Und es ist wĂŒnschenswert zu haben:



  • Erste EntwicklungsfĂ€higkeiten mit Flask
  • Das Prinzip der AbhĂ€ngigkeitsinjektion verstehen


Was werden wir bauen?



Wir werden eine Anwendung erstellen, mit der Sie auf Github nach Repositorys suchen können. Nennen wir es Github Navigator.



Wie funktioniert Github Navigator?



  • Der Benutzer öffnet eine Webseite, auf der er aufgefordert wird, eine Suchabfrage einzugeben.
  • Der Benutzer gibt eine Abfrage ein und drĂŒckt die Eingabetaste.
  • Der Github Navigator sucht nach passenden Repositorys auf Github.
  • Nach Abschluss der Suche zeigt der Github Navigator dem Benutzer eine Webseite mit Ergebnissen an.
  • Die Ergebnisseite zeigt alle gefundenen Repositorys und die Suchabfrage.
  • FĂŒr jedes Repository sieht der Benutzer:

    • Repository-Name
    • Repository-EigentĂŒmer
    • Das letzte Commit fĂŒr das Repository
  • Der Benutzer kann auf eines der Elemente klicken, um seine Seite auf Github zu öffnen.






Bereiten Sie die Umgebung vor



ZunĂ€chst mĂŒssen wir einen Projektordner und eine virtuelle Umgebung erstellen:



mkdir ghnav-flask-tutorial
cd ghnav-flask-tutorial
python3 -m venv venv


Jetzt aktivieren wir die virtuelle Umgebung:



. venv/bin/activate


Die Umgebung ist fertig, jetzt beginnen wir mit der Projektstruktur.



Projektstruktur



Lassen Sie uns die folgende Struktur im aktuellen Ordner erstellen. Lassen Sie vorerst alle Dateien leer. Dies ist noch nicht kritisch.



Anfangsstruktur:



./
├── githubnavigator/
│   ├── __init__.py
│   ├── application.py
│   ├── containers.py
│   └── views.py
├── venv/
└── requirements.txt


Es ist Zeit, Flask und Dependency Injector zu installieren.



FĂŒgen wir der Datei die folgenden Zeilen hinzu requirements.txt:



dependency-injector
flask


Jetzt installieren wir sie:



pip install -r requirements.txt


Und ĂŒberprĂŒfen Sie, ob die Installation erfolgreich war:



python -c "import dependency_injector; print(dependency_injector.__version__)"
python -c "import flask; print(flask.__version__)"


Sie werden so etwas sehen wie:



(venv) $ python -c "import dependency_injector; print(dependency_injector.__version__)"
3.22.0
(venv) $ python -c "import flask; print(flask.__version__)"
1.1.2


Hallo Welt!



Lassen Sie uns eine minimale Hallo-Welt-App erstellen.



FĂŒgen wir der Datei die folgenden Zeilen hinzu views.py:



"""Views module."""


def index():
    return 'Hello, World!'


FĂŒgen wir nun einen Container fĂŒr AbhĂ€ngigkeiten hinzu (im Folgenden nur einen Container). Der Container enthĂ€lt alle Komponenten der Anwendung. FĂŒgen wir die ersten beiden Komponenten hinzu. Dies ist eine Kolbenanwendung und -ansicht index.



FĂŒgen wir der Datei Folgendes hinzu containers.py:



"""Application containers module."""

from dependency_injector import containers
from dependency_injector.ext import flask
from flask import Flask

from . import views


class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__)

    index_view = flask.View(views.index)


Jetzt mĂŒssen wir eine Flask Application Factory erstellen. Es wird normalerweise genannt create_app(). Es wird ein Container erstellt. Der Container wird zum Erstellen der Flask-Anwendung verwendet. Der letzte Schritt besteht darin, das Routing einzurichten. Wir weisen die Ansicht index_viewaus dem Container zu, um Anforderungen an das Stammverzeichnis "/" unserer Anwendung zu verarbeiten.



Lassen Sie uns bearbeiten application.py:



"""Application module."""

from .containers import ApplicationContainer


def create_app():
    """Create and return Flask application."""
    container = ApplicationContainer()

    app = container.app()
    app.container = container

    app.add_url_rule('/', view_func=container.index_view.as_view())

    return app


Der Container ist das erste Objekt in der Anwendung. Es wird verwendet, um alle anderen Objekte abzurufen.


Unsere Anwendung ist jetzt bereit zu sagen "Hallo, Welt!"



In einem Terminal ausfĂŒhren:



export FLASK_APP=githubnavigator.application
export FLASK_ENV=development
flask run


Die Ausgabe sollte ungefĂ€hr so ​​aussehen:



* Serving Flask app "githubnavigator.application" (lazy loading)
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with fsevents reloader
* Debugger is active!
* Debugger PIN: 473-587-859


Öffnen Sie Ihren Browser und gehen Sie zu http://127.0.0.1:5000/ .



Sie sehen "Hallo Welt!"



Ausgezeichnet. Unsere minimale Anwendung startet und lÀuft erfolgreich.



Machen wir es etwas hĂŒbscher.



Einschließlich Stile



Wir werden Bootstrap 4 verwenden . Verwenden wir hierfĂŒr die Bootstrap-Flask- Erweiterung . Es wird uns helfen, alle notwendigen Dateien mit wenigen Klicks hinzuzufĂŒgen.



HinzufĂŒgen bootstrap-flaskzu requirements.txt:



dependency-injector
flask
bootstrap-flask


und im Terminal ausfĂŒhren:



pip install --upgrade -r requirements.txt


FĂŒgen wir nun die Erweiterung bootstrap-flaskzum Container hinzu.



Bearbeiten containers.py:



"""Application containers module."""

from dependency_injector import containers
from dependency_injector.ext import flask
from flask import Flask
from flask_bootstrap import Bootstrap

from . import views


class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__)

    bootstrap = flask.Extension(Bootstrap)

    index_view = flask.View(views.index)


Initialisieren wir die Erweiterung bootstrap-flask. Wir mĂŒssen uns Ă€ndern create_app().



Bearbeiten application.py:



"""Application module."""

from .containers import ApplicationContainer


def create_app():
    """Create and return Flask application."""
    container = ApplicationContainer()

    app = container.app()
    app.container = container

    bootstrap = container.bootstrap()
    bootstrap.init_app(app)

    app.add_url_rule('/', view_func=container.index_view.as_view())

    return app


Jetzt mĂŒssen wir Vorlagen hinzufĂŒgen. Dazu mĂŒssen wir templates/dem Paket einen Ordner hinzufĂŒgen githubnavigator. FĂŒgen Sie zwei Dateien im Vorlagenordner hinzu:



  • base.html - Grundvorlage
  • index.html - Hauptseitenvorlage


Erstellen Sie einen Ordner templatesund zwei leere Dateien base.htmlund index.html:



./
├── githubnavigator/
│   ├── templates/
│   │   ├── base.html
│   │   └── index.html
│   ├── __init__.py
│   ├── application.py
│   ├── containers.py
│   └── views.py
├── venv/
└── requirements.txt


FĂŒllen wir nun die Grundvorlage aus.



FĂŒgen wir der Datei die folgenden Zeilen hinzu base.html:



<!doctype html>
<html lang="en">
    <head>
        {% block head %}
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

        {% block styles %}
            <!-- Bootstrap CSS -->
            {{ bootstrap.load_css() }}
        {% endblock %}

        <title>{% block title %}{% endblock %}</title>
        {% endblock %}
    </head>
    <body>
        <!-- Your page content -->
        {% block content %}{% endblock %}

        {% block scripts %}
            <!-- Optional JavaScript -->
            {{ bootstrap.load_js() }}
        {% endblock %}
    </body>
</html>


FĂŒllen wir nun die Masterseitenvorlage aus.



FĂŒgen wir der Datei die folgenden Zeilen hinzu index.html:



{% extends "base.html" %}

{% block title %}Github Navigator{% endblock %}

{% block content %}
<div class="container">
    <h1 class="mb-4">Github Navigator</h1>

    <form>
        <div class="form-group form-row">
            <div class="col-10">
                <label for="search_query" class="col-form-label">
                    Search for:
                </label>
                <input class="form-control" type="text" id="search_query"
                       placeholder="Type something to search on the GitHub"
                       name="query"
                       value="{{ query if query }}">
            </div>
            <div class="col">
                <label for="search_limit" class="col-form-label">
                    Limit:
                </label>
                <select class="form-control" id="search_limit" name="limit">
                    {% for value in [5, 10, 20] %}
                    <option {% if value == limit %}selected{% endif %}>
                        {{ value }}
                    </option>
                    {% endfor %}
                </select>
            </div>
        </div>
    </form>

    <p><small>Results found: {{ repositories|length }}</small></p>

    <table class="table table-striped">
        <thead>
            <tr>
                <th>#</th>
                <th>Repository</th>
                <th class="text-nowrap">Repository owner</th>
                <th class="text-nowrap">Last commit</th>
            </tr>
        </thead>
        <tbody>
        {% for repository in repositories %} {{n}}
            <tr>
              <th>{{ loop.index }}</th>
              <td><a href="{{ repository.url }}">
                  {{ repository.name }}</a>
              </td>
              <td><a href="{{ repository.owner.url }}">
                  <img src="{{ repository.owner.avatar_url }}"
                       alt="avatar" height="24" width="24"/></a>
                  <a href="{{ repository.owner.url }}">
                      {{ repository.owner.login }}</a>
              </td>
              <td><a href="{{ repository.latest_commit.url }}">
                  {{ repository.latest_commit.sha }}</a>
                  {{ repository.latest_commit.message }}
                  {{ repository.latest_commit.author_name }}
              </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
</div>

{% endblock %}


Großartig, fast fertig. Der letzte Schritt besteht indexdarin , die Ansicht zu Ă€ndern , um die Vorlage zu verwenden index.html.



Lassen Sie uns bearbeiten views.py:



"""Views module."""

from flask import request, render_template


def index():
    query = request.args.get('query', 'Dependency Injector')
    limit = request.args.get('limit', 10, int)

    repositories = []

    return render_template(
        'index.html',
        query=query,
        limit=limit,
        repositories=repositories,
    )


Erledigt.



Stellen Sie sicher, dass die Anwendung ausgefĂŒhrt wird, flask runund öffnen Sie http://127.0.0.1:5000/ .



Das solltest du sehen:







Github anschließen



In diesem Abschnitt werden wir unsere Anwendung in die Github-API integrieren.

Wir werden die PyGithub- Bibliothek verwenden .



FĂŒgen wir es hinzu zu requirements.txt:



dependency-injector
flask
bootstrap-flask
pygithub


und im Terminal ausfĂŒhren:



pip install --upgrade -r requirements.txt


Jetzt mĂŒssen wir den Github-API-Client zum Container hinzufĂŒgen. Dazu mĂŒssen wir zwei neue Anbieter aus dem Modul verwenden dependency_injector.providers:



  • Der Anbieter Factoryerstellt den Github-Client.
  • Der Anbieter ConfigurationĂŒbergibt das API-Token und das Github-Timeout an den Client.


Machen wir das.



Lassen Sie uns bearbeiten containers.py:



"""Application containers module."""

from dependency_injector import containers, providers
from dependency_injector.ext import flask
from flask import Flask
from flask_bootstrap import Bootstrap
from github import Github

from . import views


class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__)

    bootstrap = flask.Extension(Bootstrap)

    config = providers.Configuration()

    github_client = providers.Factory(
        Github,
        login_or_token=config.github.auth_token,
        timeout=config.github.request_timeout,
    )

    index_view = flask.View(views.index)


Wir haben die Konfigurationsparameter verwendet, bevor wir ihre Werte eingestellt haben. Dies ist das Prinzip, nach dem der Anbieter arbeitet Configuration.



Zuerst verwenden wir, dann setzen wir die Werte.



FĂŒgen wir nun die Konfigurationsdatei hinzu.

Wir werden YAML verwenden.



Erstellen Sie eine leere Datei config.ymlim Stammverzeichnis des Projekts:



./
├── githubnavigator/
│   ├── templates/
│   │   ├── base.html
│   │   └── index.html
│   ├── __init__.py
│   ├── application.py
│   ├── containers.py
│   └── views.py
├── venv/
├── config.yml
└── requirements.txt


Und fĂŒllen Sie es mit den folgenden Zeilen aus:



github:
  request_timeout: 10


Um mit der Konfigurationsdatei zu arbeiten, verwenden wir die PyYAML- Bibliothek . FĂŒgen wir es der Datei mit AbhĂ€ngigkeiten hinzu.



Bearbeiten requirements.txt:



dependency-injector
flask
bootstrap-flask
pygithub
pyyaml


und installieren Sie die AbhÀngigkeit:



pip install --upgrade -r requirements.txt


Wir werden eine Umgebungsvariable verwenden, um das API-Token zu ĂŒbergeben GITHUB_TOKEN.



Jetzt mĂŒssen wir bearbeiten create_app(), um 2 Aktionen auszufĂŒhren, wenn die Anwendung gestartet wird:



  • Konfiguration laden von config.yml
  • Laden Sie das API-Token aus der Umgebungsvariablen GITHUB_TOKEN


Bearbeiten application.py:



"""Application module."""

from .containers import ApplicationContainer


def create_app():
    """Create and return Flask application."""
    container = ApplicationContainer()
    container.config.from_yaml('config.yml')
    container.config.github.auth_token.from_env('GITHUB_TOKEN')

    app = container.app()
    app.container = container

    bootstrap = container.bootstrap()
    bootstrap.init_app(app)

    app.add_url_rule('/', view_func=container.index_view.as_view())

    return app


Jetzt mĂŒssen wir ein API-Token erstellen.



DafĂŒr benötigen Sie:



  • Folgen Sie diesem Tutorial auf Github
  • Token auf Umgebungsvariable setzen:



    export GITHUB_TOKEN=<your token>


Dieser Artikel kann vorĂŒbergehend ĂŒbersprungen werden.



Die App wird ohne Token ausgefĂŒhrt, jedoch mit begrenzter Bandbreite. Limit fĂŒr nicht authentifizierte Clients: 60 Anfragen pro Stunde. Das Token wird benötigt, um dieses Kontingent auf 5000 pro Stunde zu erhöhen.


Erledigt.



Die Installation der Client-Github-API ist abgeschlossen.



Suchdienst



Es ist Zeit, einen Suchdienst hinzuzufĂŒgen SearchService. Er wird:



  • Suche auf Github
  • Erhalten Sie zusĂ€tzliche Daten zu Commits
  • Formatergebnis konvertieren


SearchServiceverwendet den Github-API-Client.



Erstellen Sie eine leere Datei services.pyim Paket githubnavigator:



./
├── githubnavigator/
│   ├── templates/
│   │   ├── base.html
│   │   └── index.html
│   ├── __init__.py
│   ├── application.py
│   ├── containers.py
│   ├── services.py
│   └── views.py
├── venv/
├── config.yml
└── requirements.txt


und fĂŒgen Sie die folgenden Zeilen hinzu:



"""Services module."""

from github import Github
from github.Repository import Repository
from github.Commit import Commit


class SearchService:
    """Search service performs search on Github."""

    def __init__(self, github_client: Github):
        self._github_client = github_client

    def search_repositories(self, query, limit):
        """Search for repositories and return formatted data."""
        repositories = self._github_client.search_repositories(
            query=query,
            **{'in': 'name'},
        )
        return [
            self._format_repo(repository)
            for repository in repositories[:limit]
        ]

    def _format_repo(self, repository: Repository):
        commits = repository.get_commits()
        return {
            'url': repository.html_url,
            'name': repository.name,
            'owner': {
                'login': repository.owner.login,
                'url': repository.owner.html_url,
                'avatar_url': repository.owner.avatar_url,
            },
            'latest_commit': self._format_commit(commits[0]) if commits else {},
        }

    def _format_commit(self, commit: Commit):
        return {
            'sha': commit.sha,
            'url': commit.html_url,
            'message': commit.commit.message,
            'author_name': commit.commit.author.name,
        }


FĂŒgen wir SearchServicenun den Container hinzu.



Bearbeiten containers.py:



"""Application containers module."""

from dependency_injector import containers, providers
from dependency_injector.ext import flask
from flask import Flask
from flask_bootstrap import Bootstrap
from github import Github

from . import services, views


class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__)

    bootstrap = flask.Extension(Bootstrap)

    config = providers.Configuration()

    github_client = providers.Factory(
        Github,
        login_or_token=config.github.auth_token,
        timeout=config.github.request_timeout,
    )

    search_service = providers.Factory(
        services.SearchService,
        github_client=github_client,
    )

    index_view = flask.View(views.index)


Suche verbinden



Wir sind jetzt bereit fĂŒr die Suche. Lassen Sie uns SearchServicein indexSicht verwenden.



Bearbeiten views.py:



"""Views module."""

from flask import request, render_template

from .services import SearchService


def index(search_service: SearchService):
    query = request.args.get('query', 'Dependency Injector')
    limit = request.args.get('limit', 10, int)

    repositories = search_service.search_repositories(query, limit)

    return render_template(
        'index.html',
        query=query,
        limit=limit,
        repositories=repositories,
    )


Ändern wir nun den Container, um die AbhĂ€ngigkeit beim Aufruf SearchServicean die Ansicht zu ĂŒbergeben index.



Bearbeiten containers.py:



"""Application containers module."""

from dependency_injector import containers, providers
from dependency_injector.ext import flask
from flask import Flask
from flask_bootstrap import Bootstrap
from github import Github

from . import services, views


class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__)

    bootstrap = flask.Extension(Bootstrap)

    config = providers.Configuration()

    github_client = providers.Factory(
        Github,
        login_or_token=config.github.auth_token,
        timeout=config.github.request_timeout,
    )

    search_service = providers.Factory(
        services.SearchService,
        github_client=github_client,
    )

    index_view = flask.View(
        views.index,
        search_service=search_service,
    )


Stellen Sie sicher, dass die Anwendung ausgefĂŒhrt wird, flask runund öffnen Sie http://127.0.0.1:5000/ .



Du wirst sehen:







Ein bisschen Refactoring



Unsere Ansicht indexenthÀlt zwei fest codierte Werte:



  • Standard-Suchbegriff
  • Begrenzen Sie die Anzahl der Ergebnisse


Lassen Sie uns ein wenig umgestalten. Wir werden diese Werte in die Konfiguration ĂŒbertragen.



Bearbeiten views.py:



"""Views module."""

from flask import request, render_template

from .services import SearchService


def index(
        search_service: SearchService,
        default_query: str,
        default_limit: int,
):
    query = request.args.get('query', default_query)
    limit = request.args.get('limit', default_limit, int)

    repositories = search_service.search_repositories(query, limit)

    return render_template(
        'index.html',
        query=query,
        limit=limit,
        repositories=repositories,
    )


Jetzt mĂŒssen diese Werte auf Abruf ĂŒbergeben werden. Lassen Sie uns den Container aktualisieren.



Bearbeiten containers.py:



"""Application containers module."""

from dependency_injector import containers, providers
from dependency_injector.ext import flask
from flask import Flask
from flask_bootstrap import Bootstrap
from github import Github

from . import services, views


class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__)

    bootstrap = flask.Extension(Bootstrap)

    config = providers.Configuration()

    github_client = providers.Factory(
        Github,
        login_or_token=config.github.auth_token,
        timeout=config.github.request_timeout,
    )

    search_service = providers.Factory(
        services.SearchService,
        github_client=github_client,
    )

    index_view = flask.View(
        views.index,
        search_service=search_service,
        default_query=config.search.default_query,
        default_limit=config.search.default_limit,
    )


Jetzt aktualisieren wir die Konfigurationsdatei.



Bearbeiten config.yml:



github:
  request_timeout: 10
search:
  default_query: "Dependency Injector"
  default_limit: 10


Erledigt.



Das Refactoring ist abgeschlossen. Mu machte den Code sauberer.



Tests hinzufĂŒgen



Es wĂ€re schön, einige Tests hinzuzufĂŒgen. Machen wir das.



Wir werden Pytest und Coverage verwenden .



Bearbeiten requirements.txt:



dependency-injector
flask
bootstrap-flask
pygithub
pyyaml
pytest-flask
pytest-cov


und installieren Sie neue Pakete:



pip install -r requirements.txt


Erstellen Sie eine leere Datei tests.pyim Paket githubnavigator:



./
├── githubnavigator/
│   ├── templates/
│   │   ├── base.html
│   │   └── index.html
│   ├── __init__.py
│   ├── application.py
│   ├── containers.py
│   ├── services.py
│   ├── tests.py
│   └── views.py
├── venv/
├── config.yml
└── requirements.txt


und fĂŒgen Sie die folgenden Zeilen hinzu:



"""Tests module."""

from unittest import mock

import pytest
from github import Github
from flask import url_for

from .application import create_app


@pytest.fixture
def app():
    return create_app()


def test_index(client, app):
    github_client_mock = mock.Mock(spec=Github)
    github_client_mock.search_repositories.return_value = [
        mock.Mock(
            html_url='repo1-url',
            name='repo1-name',
            owner=mock.Mock(
                login='owner1-login',
                html_url='owner1-url',
                avatar_url='owner1-avatar-url',
            ),
            get_commits=mock.Mock(return_value=[mock.Mock()]),
        ),
        mock.Mock(
            html_url='repo2-url',
            name='repo2-name',
            owner=mock.Mock(
                login='owner2-login',
                html_url='owner2-url',
                avatar_url='owner2-avatar-url',
            ),
            get_commits=mock.Mock(return_value=[mock.Mock()]),
        ),
    ]

    with app.container.github_client.override(github_client_mock):
        response = client.get(url_for('index'))

    assert response.status_code == 200
    assert b'Results found: 2' in response.data

    assert b'repo1-url' in response.data
    assert b'repo1-name' in response.data
    assert b'owner1-login' in response.data
    assert b'owner1-url' in response.data
    assert b'owner1-avatar-url' in response.data

    assert b'repo2-url' in response.data
    assert b'repo2-name' in response.data
    assert b'owner2-login' in response.data
    assert b'owner2-url' in response.data
    assert b'owner2-avatar-url' in response.data


def test_index_no_results(client, app):
    github_client_mock = mock.Mock(spec=Github)
    github_client_mock.search_repositories.return_value = []

    with app.container.github_client.override(github_client_mock):
        response = client.get(url_for('index'))

    assert response.status_code == 200
    assert b'Results found: 0' in response.data


Beginnen wir nun mit dem Testen und ĂŒberprĂŒfen Sie die Abdeckung:



py.test githubnavigator/tests.py --cov=githubnavigator


Du wirst sehen:



platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
plugins: flask-1.0.0, cov-2.10.0
collected 2 items

githubnavigator/tests.py ..                                     [100%]

---------- coverage: platform darwin, python 3.8.3-final-0 -----------
Name                             Stmts   Miss  Cover
----------------------------------------------------
githubnavigator/__init__.py          0      0   100%
githubnavigator/application.py      11      0   100%
githubnavigator/containers.py       13      0   100%
githubnavigator/services.py         14      0   100%
githubnavigator/tests.py            32      0   100%
githubnavigator/views.py             7      0   100%
----------------------------------------------------
TOTAL                               77      0   100%


Beachten Sie, wie wir github_clientmit der Methode durch Mock ersetzen .override(). Auf diese Weise können Sie den RĂŒckgabewert eines beliebigen Anbieters ĂŒberschreiben.



Fazit



Wir haben unsere Flask-Anwendung mithilfe der AbhÀngigkeitsinjektion erstellt. Wir haben Dependency Injector als AbhÀngigkeitsinjektions-Framework verwendet.



Der Hauptteil unserer Anwendung ist der Container. Es enthĂ€lt alle Komponenten der Anwendung und ihre AbhĂ€ngigkeiten an einem Ort. Dies bietet Kontrolle ĂŒber die Struktur der Anwendung. Es ist leicht zu verstehen und zu Ă€ndern:



"""Application containers module."""

from dependency_injector import containers, providers
from dependency_injector.ext import flask
from flask import Flask
from flask_bootstrap import Bootstrap
from github import Github

from . import services, views


class ApplicationContainer(containers.DeclarativeContainer):
    """Application container."""

    app = flask.Application(Flask, __name__)

    bootstrap = flask.Extension(Bootstrap)

    config = providers.Configuration()

    github_client = providers.Factory(
        Github,
        login_or_token=config.github.auth_token,
        timeout=config.github.request_timeout,
    )

    search_service = providers.Factory(
        services.SearchService,
        github_client=github_client,
    )

    index_view = flask.View(
        views.index,
        search_service=search_service,
        default_query=config.search.default_query,
        default_limit=config.search.default_limit,
    )




Ein Container als Karte Ihrer Anwendung. Sie wissen immer, was von was abhÀngt.



Was weiter?






All Articles