Выбрать главу

(venv)$ cd examples/flaskr/

(venv)$ py.test test_flaskr.py # Тесты должны проходить

(venv)$ export FLASK_APP=flaskr

(venv)$ flask initdb

(venv)$ flask run

Читаем код Flask

Итоговой целью Flask является создание веб-приложения, поэтому он не особо отличается от приложений командной строки Diamond и HowDoI. Вместо того чтобы привести еще одну схему, иллюстрирующую прохождение потока выполнения по функциям, мы пройдемся с помощью отладчика по приложению-примеру flaskr. Для этого нам нужен pdb — отладчик Python (находится в стандартной библиотеке).

Для начала добавьте точку останова в файле Flaskr.py, которая будет активизирована, когда поток выполнения ее достигнет, что заставит интерактивную сессию войти в отладчик:

@app.route('/')

def show_entries():

····import pdb; pdb.set_trace() ## Здесь поставьте точку останова.

····db = get_db()

····cur = db.execute('select title, text from entries order by id desc')

····entries = cur.fetchall()

····return render_template('show_entries.html', entries=entries)

Закройте файл и введите python в командной строке, дабы войти в интерактивную сессию. Чтобы не запускать сервер, используйте внутренние вспомогательные программы для тестирования Flask — для симуляции запроса HTTP GET к каталогу /, куда мы только что поместили отладчик:

>>> import flaskr

>>> client = flaskr.app.test_client()

>>> client.get('/')

> /[… truncated path…]/flask/examples/flaskr/flaskr.py(74)show_entries()

-> db = get_db()

(Pdb)

Последние три строки мы получили от pdb: мы видим путь (к Flaskr.py), номер строки (74) и имя метода (show_entries()), где мы остановились. Строка (-> db = get_db()) показывает выражение, которое будет выполнено следующим, если сделаем в еще один шаг в отладчике. Приглашение (Pdb) указывает на то, что мы используем отладчик pdb.

Мы можем подняться или опуститься по стеку[73], введя в командной строке u или d соответственно. Просмотрите документацию к pdb (https://docs.python.org/library/pdb.html) под заголовком «Команды отладчика», чтобы получить полный список команд, с которыми можно работать. Мы также можем ввести имена переменных, чтобы увидеть их значения, и любую другую команду Python; мы даже можем указать переменным другие значения до того, как продолжим выполнение кода.

Если мы поднимемся по стеку на один шаг, то увидим, что вызвало функцию show_entries() (с помощью точки останова, которую мы только что установили): это объект flask.app.Flask, имеющий словарь с именем view_functions, который соотносит строковые имена (вроде 'show_entries') с функциями. Мы также увидим, что функция show_entries() была вызвана с **req.view_args.

Мы можем узнать, чем является req.view_args, в интерактивной командной строке отладчика, просто введя нужное имя (это пустой словарь — {}, то есть аргументов нет):

(Pdb) u

> /[… truncated path…]/flask/flask/app.py(1610)dispatch_request()

-> return self.view_functions[rule.endpoint](**req.view_args)

(Pdb) type(self)

<class 'flask.app.Flask'>

(Pdb) type(self.view_functions)

<type 'dict'>

(Pdb) self.view_functions

{'add_entry': <function add_entry at 0x1081 98230>,

'show_entries': <function show_entries at 0x1081981b8>, [… truncated…]

'login': <function login at 0x1081982a8>}

(Pdb) rule.endpoint

'show_entries'

(Pdb) req.view_args

{}

Одновременно с отладкой мы можем открыть файл исходного кода и следовать по нему. Если мы продолжим подниматься по стеку, то увидим, где вызвано приложение WSGI:

(Pdb) u

> /[… truncated path…]/flask/flask/app.py(1624)full_dispatch_request()

-> rv = self.dispatch_request()

(Pdb) u

> /[… truncated path…]/flask/flask/app.py(1973)wsgi_app()

-> response = self.full_dispatch_request()

(Pdb) u

> /[… truncated path…]/flask/flask/app.py(1985)__call__()

-> return self.wsgi_app(environ, start_response)

Если мы продолжим вводить u, то окажемся в модуле тестирования, который был использован для создания фальшивого клиента без запуска сервера, — мы достигли конца стека. Мы узнали, что приложение flaskr отправляется изнутри объекта класса flask.app.Flask, строка 1985 файла Flask/Flask/app.py. Перед вами эта функция:

Это строка 1973, определенная в отладчике.

Это строка 1985, также определенная в отладчике. Сервер WSGI получит объект Flask как приложение и будет вызывать его всякий раз, когда приходит соответствующий запрос (с помощью отладчика мы нашли точку входа в код).

Мы используем отладчик точно так же, как граф вызовов для HowDoI: следуем вызовам функций (это в принципе не отличается от чтения самого кода). Ценность отладчика заключается в том, что мы не видим лишнего кода, который может отвлечь нас или запутать. Используйте тот подход, который наиболее эффективен для вас.

вернуться

73

В Python стек вызовов содержит исполняемые инструкции, запущенные интерпретатором Python. Поэтому если функция f() вызовет функцию g(), то f() пойдет на стек первой, а g() при вызове будет помещена выше f(). Когда функция g() возвращает значение, она удаляется из стека, и функция f() продолжает работу с того места, где прервалась. Стек называется так потому, что он работает точно так же, как посудомойка, которой требуется вымыть стопку тарелок: новые тарелки помещаются наверх, и вам всегда нужно начинать работу с верхних.