%%file app.py
from flask import Flask, jsonify
= Flask(__name__)
app
@app.route('/')
def home():
return jsonify({"message": "Hello, World!"})
if __name__ == '__main__':
app.run()
Writing app.py
Celem laboratorium jest zapoznanie studentów z tworzeniem aplikacji REST API w Pythonie z wykorzystaniem biblioteki Flask oraz jej konteneryzacją w Dockerze. Nauczysz się: - Tworzenia prostego REST API, - Obsługi zapytań HTTP i obsługi błędów w API, - Testowania API z wykorzystaniem pytest
, - Przenoszenia aplikacji do kontenera Docker.
Naszym zadaniem jest wystawienie aplikacji w Pythonie, która na żądanie klienta udzieli odpowiedzi na podstawie predykcji wygenerowanej przez model.
Aplikację napiszemy w Pythonie z wykorzystaniem Flask 3.0.3.
Naszą aplikację chcemy uruchomić lokalnie, a następnie w prosty sposób przenieść i uruchomić na dowolnym komputerze. Dlatego naturalnym rozwiązaniem jest zapisanie kodu w pliku z rozszerzeniem .py.
Aby automatycznie zapisać kod aplikacji do pliku app.py, wykorzystamy magiczną komendę %%file plik.py
.
%%file app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return jsonify({"message": "Hello, World!"})
if __name__ == '__main__':
app.run()
Writing app.py
Uwaga! W dokumentacji Flask w kodzie podstawowej aplikacji nie występują dwie ostatnie linie odpowiedzialne za uruchomienie serwera.
Wyjaśnijmy co zawiera przykładowy kod.
from flask import Flask
Załadowanie bibliotekiapp = Flask(__name__)
utworzenie interfejsu serwera APIDekoratory w Pythonie pozwalają modyfikować zachowanie funkcji bez zmiany jej kodu. Flask wykorzystuje dekoratory do tworzenia tras (@app.route), ale można je także stosować w analizie danych – np. do logowania czasu wykonania funkcji lub obsługi błędów.
Załóżmy, że mamy funkcję, która pobiera dane z pliku CSV i zwraca listę wartości. Dodamy dekorator, który automatycznie przeskaluje dane do zakresu 0-1, co często jest wymagane przed analizą statystyczną lub trenowaniem modeli ML.
import numpy as np
# Dekorator do normalizacji danych
def normalize_data(func):
def wrapper(*args, **kwargs):
data = func(*args, **kwargs) # Pobranie oryginalnych danych
min_val, max_val = min(data), max(data)
normalized = [(x - min_val) / (max_val - min_val) for x in data]
print("Dane po normalizacji:", normalized)
return normalized
return wrapper
@normalize_data
def get_data():
return [10, 15, 20, 30, 50]
get_data()
Dane po normalizacji: [0.0, 0.125, 0.25, 0.5, 1.0]
[0.0, 0.125, 0.25, 0.5, 1.0]
Ćwiczenie: „Napisz dekorator, który zaokrągla wartości do 2 miejsc po przecinku.”
Dodajmy obsługę błędów, np. kiedy klient poda niepoprawne dane:
Uruchomienie serwera moze odbyć się na przynajmniej na dwa sposoby.
Otwórz termianal w lokalizacji gdzie znajduje się plik aplikacji
lub (jeśli nie ma fragmentu app.run()
)
Powinna pojawić się informacja podobna do ponizszej:
* Serving Flask app 'app'
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
W celu weryfikacji działania możesz otworzyć nowe okno terminalu wpisując:
Bezpośrenie uruchomienia kodu w notatniku spowoduje uruchomienie serwera i zatrzymanie jakiejkolwiek mozliwości realizacji kodu. Aby tego uniknąć mozesz wykorzystać bibliotekę subprocess.
Jeśli potrzebujemy zamknąć subprocess wykonaj:
Do testowania API wykorzystamy pytest
oraz bibliotekę requests
. ### Instalacja pytest:
%%file test_app.py
import pytest
import requests
def test_home():
response = requests.get("http://127.0.0.1:5000/")
assert response.status_code == 200
assert response.json()["message"] == "Hello, World!"
Writing test_app.py
============================= test session starts ==============================
platform linux -- Python 3.11.6, pytest-8.3.5, pluggy-1.5.0
rootdir: /home/jovyan/notebooks
plugins: anyio-4.0.0
collected 1 item
test_app.py . [100%]
============================== 1 passed in 0.03s ===============================
Aby uruchomić kod aplikacji app.py, potrzebujemy interpretera języka Python zainstalowanego na naszym komputerze. Jednak samo posiadanie interpretera nie jest wystarczające – aby aplikacja działała poprawnie, należy utworzyć środowisko (najlepiej wirtualne), w którym będą dostępne wszystkie wymagane biblioteki, takie jak Flask.
uwaga: wszystkie polecenia terminala dotyczyć będą wersji linux/mac os
W pierwszej kolejności sprawdź czy dostępne są polecenia pozwalające realizować kod pythonowy.
Wszystkie te polecenia powinny wskazyać na folder z domyślnym środowiskiem Pythona.
Wygeneruj i uruchom środowisko wirtualne lokalnie wpisując w terminalu:
Dobra praktyka: środowisko python to nic innego jak katalog. W naszej wersji to katalog ukryty o nazwie .venv. Jeśli skopiujesz ten katalog gdzie indziej przestanie pełnić on swoją funkcję środowiska python. Dlatego jego odtworzenie nie polega na jego kopiowaniu. Jeśli Twój projekt jest powiązany ze środowiskiem kontroli wersji GIT zadbaj aby katalog środowiska nie był dodawany do repozytorium. Mozesz wykonać to działanie dodając odpowiedni wpis do pliki .gitignore
Posiadając utworzone nowe środowisko sprawdź jakie biblioteki się w nim znajdują.
Mozemy ponownie sprawdzić polecenia python i pip:
Domyślnie powinny pojawić się biblioteki pip oraz setuptools.
Doinstaluj bibliotekę flask.
pip install flask==3.0.3
pip list
Package Version
------------ -------
blinker 1.7.0
click 8.1.7
Flask 3.0.3
itsdangerous 2.1.2
Jinja2 3.1.3
MarkupSafe 2.1.5
pip 23.2.1
setuptools 65.5.0
Werkzeug 3.0.2
Jak widać instalacja biblioteki flask wymusiła doinstalowanie równiez innych pakietów.
Jedyną mozliwością przeniesienia środowiska python jest jego ponowna instalacja na nowej maszynie i instalacja wszystkich pakietów. Aby jednak nie instalować kazdego pakietu osobno mozemy wykorzystać plik konfiguracyjny requirements.txt zawierający listę pakietów.
Pamiętaj - kazdy pakiet powinien zawierać nr wersji pakietu. W innym przypadku moze okazać się, ze nowe werjse pakietów spowodują brak obsługi twojego kodu.
Aby utworzyć plik konfiguracyjny uzyj polecenia w terminalu:
Tak wygenerowany plik mozesz uzywać na dowolnej maszynie do instalacji i odtworzenia potrzebnego środowiska wykonawczego python.
Dygresja. W momencie przygotowywania materiałów Flask był w wersji 3.0.1 - dziś juz realizowany jest w wersji 3.0.3. Zmiany następują szybciej niz się wydaje. Instalacja pakietów z pliku odbywa się z wykorzystaniem polecenia:
Mamy teraz dwa pliki: app.py, i requirements.txt. Przenosząc je do dowolnego projektu na serwerach github jesteśmy w stanie uruchomić naszą aplikację wszędzie tam gdzie dostępny będzie interpreter python na którym mozemy utworzyć nowe wirtualne środowisko i zainstalować biblioteki z pliku requirements.txt.
Do pełnej automatyzacji przydałaby się jeszcze mozliwość uruchomienia środowiska python na dowolnej maszynie.
W tym celu utwórz plik Dockerfile:
Powyzszy plik pozwala w docker desktop uruchomić obraz wykorzystujący podstawowy system operacyjny (tutaj linux) wraz z podstawowym środowiskiem python3.11.
Ponadto plik ten kopiuje potrzebne pliki (app.py, requirements.txt) na obraz dockera.
Polecenie RUN pozwala uruchomić dowolne polecenie bash wewnątrz obrazu dockera.
Polecenie CMD pozwala uruchomić polecenie uruchamiające serwer w trybie tak by nie zamknąć tego polecenia.
Ostatnią informacją jest ustalenie portu na 8000.
utworzenie kontenera na podstawie pliku Dockerfile
uruchomienie kontenera