Файл: Методические указания по выполнению лабораторных работ для студентов, обучающихся с применением.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 05.12.2023

Просмотров: 133

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

63
"/version/?access_token=your_token"
conn request(
"GET"
, request) resp
=
conn getresponse()
#
берем json содержимой ответа
js_data
=
json load(resp)
print
(
"version "
,js_data[
0
][
'created'
]) ident_v
=
js_data[
0
][
'created'
]
# задаем строку запроса для получения структуры датасета
request
=
"https://data.gov.ru/api/json/dataset/"
request
=
request
+
dt[
'identifier'
]
iloc[i]
+
"/version/"
request
=
request
+
ident_v
+
"/structure?access_token=your_token"
conn request(
"GET"
, request) resp
=
conn getresponse() js_data
=
json load(resp)
# если при получении структуры данные не пустые, выводим данные о структуре
if
js_data:
print
(js_data)
# делаем запрос на получение данных в формате xml
request
=
"https://data.gov.ru/api/xml/dataset/"
request
=
request
+
dt[
'identifier'
]
iloc[i]
+
"/version/"
request
=
request
+
ident_v
+
"/content?access_token=your_token"
conn request(
"GET"
, request) resp
=
conn getresponse() data_content
=
resp read()
decode()
print
(data_content[
0
:
24
])
# попробуем обработать наши данные и парсить xml строку
import
pandas
as
pd
import
xml.etree.ElementTree
as
et
import
xml.dom.minidom
# используем стандартный парсер Python, есть и сторонние
# Два основных парсера DOM и sax. Почитайте, что это.
parser
=
et
XMLParser(encoding
=
"utf-8"
) xroot
=
et fromstring(data_content, parser
=
parser)
# ищем в xml теги, используя структуру, предлагаемую API
print
(xroot tag)
for
rows
in
xroot findall(
'rows'
):
print
(
"rows"
)
for
row
in
rows findall(
'row'
):

64
print
(
"row"
)
for
value
in
row findall(
'value'
):
print
(value text) conn close()
Как видите, приложение крашится при первом же запуске. Тем не менее, оно выводит некоторую полезную информацию. Во-первых, многие датасеты отсутствуют, формат некоторых датасетов оставляет желать лучшего. Тем не менее, некоторые даже содержат XML-данные и некоторые из них даже чи- таются. Таким образом, здесь полезной оказалась бы обработка исключений.
Для ознакомления с исключениями на Python обратитесь к ресурсу: https://pythonworld.ru/tipy-dannyx-v-python/isklyucheniya-v-python-konstrukciya- try-except-dlya-obrabotki-isklyuchenij.html .
Попробуйте переписать вышестоящий код с использованием функций, де- композируйте задачу, перепишите данные из xml в hdf формат. Учтите исклю- чения, отсутствующие данные отбрасывайте.

65
2
ЛАБОРАТОРНАЯ РАБОТА № 1
«РАЗРАБОТКА ВЕБ-ПРИЛОЖЕНИЯ НА PYTHON»
Целью данной лабораторной работы является изучение возможностей языка Python по обработке данных, создание веб-приложения с использованием фреймворка Flask, системы контроля версий GIT и системы непрерывной инте- грации Travis. Перед выполнением задания лабораторной работы необходимо выполнить задания из первой главы настоящих методических указаний.
2.1
Непрерывная интеграция для GitHub
Непрерывная интеграция (англ. Continuous Integration, CI) – способ разра- ботки программного обеспечения, который заключается в постоянном слиянии рабочих копий в общую основную ветвь разработки (до нескольких раз в день) и выполнении частых автоматизированных сборок проекта для скорейшего вы- явления потенциальных дефектов и решения интеграционных проблем.
В обычном проекте, где над разными частями системы разработчики трудятся независимо, стадия интеграции является заключительной. Она может непред- сказуемо задержать окончание работ. Переход к непрерывной интеграции поз- воляет снизить трудоёмкость интеграции и сделать её более предсказуемой за счёт наиболее раннего обнаружения и устранения ошибок и противоречий, но основным преимуществом является сокращение стоимости исправления де- фекта благодаря раннему его выявлению.
Непрерывная интеграция впервые концептуализирована и предложена
Гради Бучем в 1991 г. Является одним из основных элементов практики экс- тремального программирования.
Для применения практики необходимо выполнение ряда базовых требо- ваний к проекту разработки. В частности, исходный код и всё, что необходимо для сборки и тестирования проекта, должно храниться в репозитории системы управления версиями, а операции копирования из репозитория, сборки и тести- рования всего проекта должны быть автоматизированы и легко вызываться из внешних программ.


66
Для организации процесса непрерывной интеграции на выделенном сер- вере запускается служба, в задачи которой входят:

получение исходного кода из репозитория;

сборка проекта;

выполнение тестов;

развёртывание готового проекта;

отправка отчетов.
2.2
Примеры веб-сервисов для непрерывной интеграции
Существует ряд веб-сервисов, которые позволяют реализовать процесс непрерывной интеграции. Для операционной системы Windows это
AppVeyor https://www.appveyor.com/
, для Mac OS и Linux –
Travis CI https://travis-ci.org/
Мы будем работать под Linux с использованием Travis CI. Он имеет ряд особенностей, которые делают его хорошим выбором для начала работы с кон- вейерами сборки:

быстро интегрируется с любым общедоступным GitHub- репозиторием;

поддерживает все основные языки программирования;

развертывается на нескольких разных облачных платформах;

предлагает множество инструментов для обмена сообщениями и оповещения.
На высоком уровне он работает путем мониторинга github-репозитория на предмет новых коммитов (commit).
Когда создается новый коммит, Travis CI выполняет шаги конвейера сборки, как определено в файле конфигурации. Если какой-либо шаг не удался, конвейер завершается, и об этом создается уведомление.
Из коробки Travis CI требует незначительных настроек конфигурации.
Единственная необходимая конфигурация – это указание языка программирова- ния.

67
Всегда можно предоставить больше настроек конфигурации для адапта- ции нашего конвейера, если это необходимо. Например, мы можем ограничить ветви, для которых запускаются сборки, добавить дополнительные шаги в кон- вейер и многое другое.
Travis умеет работать как из полновесной виртуальной машины, так и из Docker-контейнера. В теории, это позволяет сократить время между git push и началом сборки приблизительно на одну минуту. К сожалению, на прак- тике за это ускорение придётся заплатить потерей возможности делать sudo, а это, в свою очередь, ведёт к ограничениям при установке нужных зависимо- стей.
Как именно собирать, тестировать и развёртывать проект, описывается в специальном конфигурационном файле на языке YAML. Этот файл должен лежать в корне репозитория и иметь имя .travis.yml или appveyor.yml (допуска- ется .appveyor.yml) – для Travis CI и AppVeyor соответственно.
2.3
Что такое YAML
YAML – это язык с синтаксическим структурированием с помощью от- ступов (как и, например, Python), но при этом не разрешается использование табуляции.
После того как YAML-файлы добавлены в репозиторий, нужно включить непрерывную интеграцию для заданного проекта на сайтах Travis и AppVeyor.
Нужно зайти на https://travis-ci.org
, авторизовавшись через свой github-аккаунт.
Затем соглашаемся с доступом, который запрашивает Travis CI (ему нужно бу- дет получать уведомления о новых коммитах), синхронизуем список своих про- ектов, выбираем нужный и щёлкаем на включатель. Можно повторить анало- гичный процесс на сайте https://ci.appveyor.com, если вы все-таки решили ис- пользовать Windows.
Начиная с этого момента каждый git push в ваш репозиторий будет запус- кать процесс непрерывной интеграции: сервисы Travis поднимут виртуальную машину, настроят среду, установят зависимости, скачают ваш проект, соберут


68 и протестируют его, а также, при желании, выложат инсталляторы, архивы с исходниками и документацию – всё согласно спецификации в YAML-файлах.
В создании YAML-файлов и заключается основная работа.
Когда вы зайдете на сайт travis-ci, вас попросят о входе через GitHub или
B
itbucket. Выбираем GitHub. Возможно, произойдет переключение на travis- ci.com, если вы заходите использовать приватные репозитории GitHub, но мож- но указать org и работать с org.
2.4
Создание проекта веб-приложения на Flask
Создадим на сайте GitHub новый проект. Можете заполнить файл readme.md.
Если будете использовать git client на своей машине, то лучше не делать этого сразу. Дальнейшие указания будут связаны с непосредственной работой через сайт GitHub. Создадим каталог, в котором будет храниться наш проект, flaskapp. Для этого выбираем Create New File (рис. 2.1).
Рис. 2.1 – Создание файла в проекте
Поставим слеш после имени каталога flaskapp и имя файла .gitkeep
(
рис. 2.2). В указанном файле можем написать, что угодно, например, для чего данный каталог. Нажимаем кнопку commit снизу.
Рис. 2.2 – Создание папки проекта и неиспользуемого файла

69
Теперь создадим файлы, в которых будут указаны библиотеки и иниции- рующие данные для реализации нашего веб-сервера. Перед разработкой веб-сервера желательно разработать модель будущего сайта, провести анализ требований пользователей, оценить возможную нагрузку на ваш сайт. Но мы пишем достаточно простое приложение, и поэтому пока изучим возможности
CI и создание простого веб-сервиса. В нашем каталоге на сайте создадим файл some_app.py, в котором содержится следующий код:
print
(
"Hello world"
)
Можно создать пустой файл и туда скопировать код, можно скопировать созданный файл с локального диска, затем реализовать commit.
После того как вы привязали свой проект на GitHub с непрерывной инте- грацией travis-ci, можно создать файл .travis.yml в проекте GitHub и после commit будет запущен build (рис. 2.3).
language
: python
install
:
- pip3 install flask
script
:
- python3 ./flaskapp/some_app.py
В данном случае наш проект пуст, и инсталляция Flask тут, по сути, тоже не нужна.
Рис. 2.3 – Пример подтверждения commit
Здесь мы просто запускаем скрипт, который напечатает "Hello world".

70
2.5
Продолжение простейшего эксперимента с проектом Flask
Продолжим дальше наши эксперименты уже непосредственно с простей- шим сайтом с использованием фреймворка Flask. С точки зрения непрерывной интеграции необходимо создать работающий веб-сайт, протестировать его и разместить на каком-либо хостинге. Система непрерывной интеграции позво- ляет это сделать, в частности, на Heroku. Пока попробуем просто запустить сайт в фоновом режиме. Для этого нам понадобится создать небольшой скрипт под Linux и изменить файл YAML. Удобнее всего это делать, используя git- клиент, но, если у вас его нет, можно воспользоваться непосредственно интер- фейсом сайта GitHub. Если создавать файлы из меню, это всякий раз будет вы- зывать процесс build на travis-ci при нажатии commit, очевидно, некоторые из этих build не сработают вовсе. Потому лучше создать у себя на диске от- дельную директорию и потом сделать upload содержимого директории на GitHub через интерфейс и подтвердить commit.
Рис. 2.4 – Папка проекта
Итак, какие файлы нам понадобятся в каталоге flaskapp. Файл, содержа- щий приложение Flask, назовем some_app.py. Можно создавать свой проект непосредственно в среде PyCharm, а затем скопировать весь проект на сайт
GitHub.
print
(
"Hello world"
)
from
flask
import
Flask app
=
Flask(
__name__
)
#декоратор для вывода страницы по умолчанию
@app.route
(
"/"
)
def
hello
():
return
"
1   2   3   4   5   6   7

Hello World!

71
2.5.1
Что такое WSGI
WSGI (Web Server Gateway Interface) – это стандарт взаимодействия меж- ду Python-программой, выполняющейся на стороне сервера, и самим веб- сервером, например Apache. WSGI является потомком CGI (Common Gateway
Interface).
Когда Веб начал развиваться, CGI разрастался из-за поддержки огромного количества языков и отсутствия других решений. Однако такое ре- шение было медленным и ограниченным. WSGI был разработан как интерфейс для маршрутизации запросов от веб-серверов (Apache, Nginx и т. д.) на веб- приложения.
В простейшем случае WSGI состоит из двух основных компонентов:

веб-сервер (Nginx, Apache и т. д.);

веб-приложение, написанное на языке Python.
Веб-сервер исполняет код и отправляет связанную с http-запросом ин- формацию и callback-функцию в веб-приложение. Затем запрос на стороне при- ложения обрабатывается и высылается ответ на веб-сервер. Периодически меж- ду веб-сервером и веб-приложением существуют одна или несколько промежу- точных прослоек. Такие прослойки позволяют осуществить, например, балан- сировку между несколькими веб-приложениями или предпроцессинг (предоб- работку) отдаваемого контента.
Файл wsgi.py.
from
some_app
import
app
if
__name__
==
"__main__"
: app run()
2.5.2
Примеры WSGI-серверов и Gunicorn
В качестве веб-сервера будем использовать Gunicorn, хотя есть и множе- ство других (Bjoern, uWSGI, mod_wsgi, Meinheld, CherryPy). Gunicorn – это
WSGI- сервер, созданный для использования в UNIX-системах. Название – сокра- щенная и комбинированная версия слов «Green Unicorn». Он относительно быст- рый, легко запускается и работает с широким спектром веб-фреймворков. Ко- манда разработчиков рекомендует использовать Gunicorn в связке с Nginx, где
Nginx используется в качестве прокси-сервера.

72
2.5.3
Запуск проекта с использованием Gunicorn
В файле YAML наряду с Flask мы установим Gunicorn, а в скрипте ниже реализуется вызов веб-сервера с нашим веб-приложением.
Файл st.sh для вызова в скрипте yaml: gunicorn --bind 127.0.0.1:5000 wsgi:app & APP_PID
=
$!
sleep 5 echo $APP_PID kill -TERM $APP_PID echo process gunicorns kills exit 0
Предварительно можно протестировать ваш проект на локальной машине путем запуска из командной строки вашего проекта. gunicorn --bind 127.0.0.1:5000 wsgi:app
Затем в браузере наберите адрес 127.0.0.1:5000.
Что здесь делается (в скрипте st.sh)? Сначала мы запускаем веб-сервер в фоновом режиме, на это указывает символ & в конце команды, при этом в пе- ременной APP_PID мы сохраняем PID последнего фонового процесса, этот но- мер хранится в переменной $!. Затем делаем приостановку на 5 секунд, это сде- лано заранее, чтобы потом можно было запустить какие-то проверочные скрип- ты, возможно, этого будет и недостаточно. Наше приложение выполняется в так называемых worker-ах, можно указать их количество. После этого мы останавливаем master процесс веб-сервера kill -TERM. Можно посмотреть дру- гие ключи для команды kill. Например, -HUP, перезапуск.
Запуск сервера в фоновом режиме реализуется, чтобы освободить кон- соль для дальнейших команд, иначе travis-ci будет ждать бесконечно заверше- ние процесса (порядка часа).
Файл .travis.yml, который хранится вне папки flaskapp.
language
: python
before_install
:
- chmod +x ./flaskapp/st.sh
install
:
- pip3 install flask

73
- pip3 install gunicorn
script
:
- cd flaskapp
- ./st.sh
Здесь мы указываем, что будет запускаться в виртуальной машине. Как видим, указывается язык программирования. До инсталляции назначается ат- рибут файла скрипта – исполнимый. Устанавливается Flask, Gunicorn, в испол- нимых скриптах происходит переход в папку и запуск нашего скрипта.
В данном случае произойдет успешный build коммитa.
Попробуем запустить некоторый тест. Создадим файл client.py.
import
requests
r
=
requests get(
'http://localhost:5000/'
)
print
(r status_code)
print
(r text)
Изменим файл st.sh на следующий: gunicorn --bind 127.0.0.1:5000 wsgi:app & APP_PID
=
$!
sleep 5 echo start client python3 client.py sleep 5 echo $APP_PID kill -TERM $APP_PID exit 0
Изменим наш файл .travis.yml, загрузим файлы на github и закоммитим
(commit).
language
: python
before_install
:
- chmod +x ./flaskapp/st.sh
install
:
- pip3 install flask
- pip3 install gunicorn
- pip3 install requests
script
:
- cd flaskapp
- ./st.sh

74
Ниже в job log выводится консольная информация при запуске виртуаль- ной машины с инициирующими командами из YAML-файла.
2.5.4
Ремарка о тестировании
Очевидно, build пройдет независимо от того, проработает ли наш импро- визированный тест или нет, учитывая, что мы в любом случае завершаем наш исполнимый файл с успехом. Возможна только проблема с «зависанием». Так как мы вызываем скрипт, который в любом случае возвращает успешное ис- полнение, такое использование travis-ci и системы контроля версий не совсем обоснованно и не имеет особого смысла, кроме того, что, допустим, у вас нет возможностей проверки работы на локальной машине. То есть в этом случае практически любой коммит будет подтвержден, несмотря на, казалось бы, от- сутствие каких-то библиотек и ошибок сборки проекта. Тем не менее, пока по- пытаемся использовать travis-ci для разворачивания нашего проекта. А потом посмотрим, как на самом деле нужно было запускать тестовую проверку.
Естественно, хотелось бы потом добавить возможности автоматизиро- ванного тестирования и деплоя нашего проекта на какой-либо сервер. Для этого есть соответствующие средства, для тестирования веб-сервера можно исполь- зовать selenium.webdriver, для тестирования приложения подходит pytest, тесты можно указать в качестве блока YAML-файла в поле script.
2.6
Краткое знакомство с шаблонами Flask
Для начала изучим возможности Flask для нашего будущего проекта. Нам понадобятся шаблоны. Импортируем в наш файл some_app.py модуль и доба- вим новую функцию.
from
flask
import
render_template
#
наша новая функция сайта
@app.route
(
"/data_to"
)
def
data_to
():
#создаем переменные с данными для передачи в шаблон
some_pars
=
{
'user'
:
'Ivan'
,
'color'
:
'red'
}

75 some_str
=
'Hello my dear friends!'
some_value
=
10
#передаем данные в шаблон и вызываем его
return
render_template(
'simple.html'
,some_str
=
some_str, some_value
=
some_value,some_pars
=
some_pars)
Здесь мы передаем словарь, строку и просто целое значение. Для удоб- ства можно все передать в одном словаре.
Создадим также сам шаблон, для этого сначала создадим каталог templates в нашем каталоге приложения. И запишем туда файл simple.html.
<
html
>
<
head
>
{% if some_str %}
<
title
>{{ some_str }}
title
>
{% else %}
<
title
>Hm, there is no string!
title
>
{% endif %}

head
>
<
body
>
<
h1
style
=
"color:{{ some_pars.color }};"
>Hello, {{ some_pars.user }}!
h1
>
<
h2
>some_value {{ some_value }}!
h2
>

body
>

html
>
В шаблон {{}} можно передавать не только переменные, но и функции, т. к. в Python функция также является объектом. В данному случае функция render_template вызывает шаблонизатор Jinja2, который является частью фреймворка Flask. Jinja2 заменяет блоки {{...}} на соответствующие им значе- ния, переданные как аргументы шаблона. А в {% %} можно указывать специ- альные управляющие операторы, в данном случае if else endif. Можно также, например,
{
%
for
x
in
mylist
|
reverse
%
}
{
%
endfor
%
} и многие другие.
У себя на локальной машине запустите ваш проект через Gunicorn и про- верьте 127.0.0.1:5000/data_to.

76
При этом мы видим, как динамически сформировалась страница, с пере- данным заголовком страницы, строкой с именем пользователя красного цвета.
Используя GitHub или Git client, загрузите файлы в проект. Можно снача- ла создать папку templates и в нее поместить файл simple.html. Затем обновить файл some_app.py, затем – client.py.
import
requests
r
=
requests get(
'http://localhost:5000/'
)
print
(r status_code)
print
(r text) r
=
requests get(
'http://localhost:5000/data_to'
)
print
(r status_code)
print
(r text)
Тревис должен успешно обработать наш коммит, как и было сказано вы- ше, практически в любом случае. Если хотите, можете сразу перенести тести- рование в YAML-файле в соответствующий блок либо изменить возврат ошиб- ки в файле st.sh не на exit 0. То, как у вас это получилось, можете включить в отчет.
2.7 Изучение шаблонов, форм
Использование шаблонов не всегда удобно. В силу того что нам так или иначе придется описывать нашу страницу целиком на HTML, нам бы хотелось ускорить этот процесс, используя заготовки, для этого можно воспользоваться удобными библиотеками bootstrap и WTForms. Кроме того, добавим в наш про- ект нейронную сеть, которая будет классифицировать изображения.
Добавление в проект форм
В файл some_app добавим наши формы. Формы, конечно, можно описать непосредственно в шаблоне файла HTML с помощью forms input, но зачем нам это делать, если мы, допустим, не мастера дизайна, пусть все будет делаться за нас гораздо быстрее и желательно в несколько строк.
Общая суть задачи. Добавим обработку запроса GET и POST в наш API: some_app.py, в функции обработки запроса будет рендериться форма, которая

77 также добавлена как класс в файл some_app.py. В шаблоне template/net.html, ко- торый у нас рендерится, мы добавим вызов обработки формы, передаваемой при обработке запроса пользователя с помощью одной функции: wtf.quick_form(form, method='post',enctype="multipart/form-data", action="net").
Данная функция сама сформирует HTML-код с формой. Так как на форме есть кнопка submit (для submit указан обработчик POST), то, естественно, будет вызван метод POST, который мы обрабатываем в методе net-файла some_app.py. Кроме того, на форме есть капча, проверяющая наличие человека во взаимодействии (как установить капчу, показано ниже, после листингов), за- грузка файла с изображением, которое классифицируется нейронной сетью, прописанной в файле net.py, функции НС вызываются тоже из нашего же обра- ботчика. Данные формы автоматически валидируются на введение и правиль- ность.
Дальше изучаем код по комментариям.
Создадим папку во flaskapp/static, поместим туда файл с изображением image0008.png
Например, md static
Установим нужные библиотеки Python.
- pip3 install flask-bootstrap
- pip3 install flask-wtf
- pip3 install pillow
- pip3 install tensorflow==2.0.0-alpha0
- pip3 install keras
Если хотите запускать нейронную сеть с использованием gpu, можно установить tensorflow-gpu==2.0.0-alpha0. Но тогда вам придется устанавливать дополнительно cuda, cudnn, иметь соответствующую видеокарту. Потому в нашем случае достаточно tensorflow для CPU.
Добавим код в some_app.py
Можем этот код добавить непосредственно после того кода, который у нас уже есть, и реализует метод data_to. В коде присутствуют ключи для кап- чи, которые нужно сформировать на сайте Google.

78
# модули работы с формами и полями в формах
from
flask_wtf
import
FlaskForm,RecaptchaField
from
wtforms
import
StringField, SubmitField, TextAreaField
#
модули валидации полей формы
from
wtforms.validators
import
DataRequired
from
flask_wtf.file
import
FileField, FileAllowed, FileRequired
# используем csrf токен, можете генерировать его сами
SECRET_KEY
=
'secret'
app config[
'SECRET_KEY'
]
=
SECRET_KEY
# используем капчу и полученные секретные ключи с сайта Google
app config[
'RECAPTCHA_USE_SSL'
]
=
False app config[
'RECAPTCHA_PUBLIC_KEY'
]
=
'
сюда поместить ключ из google'
app config[
'RECAPTCHA_PRIVATE_KEY'
]
=
'
сюда поместить секретный ключ из google'
app config[
'RECAPTCHA_OPTIONS'
]
=
{
'theme'
:
'white'
}
# обязательно добавить для работы со стандартными шаблонами
from
flask_bootstrap
import
Bootstrap bootstrap
=
Bootstrap(app)
#
создаем форму для загрузки файла
class
NetForm
(FlaskForm):
# поле для введения строки, валидируется наличием данных
# валидатор проверяет введение данных после нажатия кнопки submit
# и указывает пользователю ввести данные, если они не введены
#
или неверны
openid
=
StringField(
'openid'
, validators
=
[DataRequired()])
# поле загрузки файла
# здесь валидатор укажет ввести правильные файлы
upload
=
FileField(
'Load image'
, validators
=
[
FileRequired(),
FileAllowed([
'jpg'
,
'png'
,
'jpeg'
],
'Images only!'
)])
#
поле формы с capture
recaptcha
=
RecaptchaField()
#кнопка submit, для пользователя отображена как send
submit
=
SubmitField(
'send'
)
# функция обработки запросов на адрес 127.0.0.1:5000/net
# модуль проверки и преобразование имени файла
# для устранения в имени символов типа / и т.д.
from
werkzeug.utils
import
secure_filename
import
os

79
# подключаем наш модуль и переименовываем
# для исключения конфликта имен
import
net
as
neuronet
# метод обработки запроса GET и POST от клиента
@app.route
(
"/net"
,methods
=
[
'GET'
,
'POST'
])
def
net
():
# создаем объект формы
form
=
NetForm()
# обнуляем переменные, передаваемые в форму
filename
=
None neurodic
=
{}
# проверяем нажатие сабмит и валидацию введенных данных
if
form validate_on_submit():
# файлы с изображениями читаются из каталога static
filename
=
os path join(
'./static'
, secure_filename(form upload data filename)) fcount, fimage
=
neuronet read_image_files(
10
,
'./static'
)
# передаем все изображения в каталоге на классификацию
# можете изменить немного код и передать только загруженный файл
decode
=
neuronet getresult(fimage)
# записываем в словарь данные классификации
for
elem
in
decode: neurodic[elem[
0
][
1
]]
=
elem[
0
][
2
]
#
сохраняем загруженный файл
form upload data save(filename)
# передаем форму в шаблон, так же передаем имя файла и результат работы нейронной
# сети, если был нажат сабмит, либо передадим falsy значения
return
render_template(
'net.html'
,form
=
form,image_name
=
filename,neurodic
=
neurodic)
Здесь используется класс формы, которая реализует размещение полей ввода строки, капчи и загрузки файла, кроме того, шаблон выводит содержимое изображения. Автоматически благодаря bootstrap реализуется отображение формы. Для работы шаблона не забудьте в some_app.py добавить строчку кода: bootstrap
=
Bootstrap(app)
Также не забудьте добавить секретный токен для защиты от CSRF-атаки.
Можете его генерировать как случайную строку при запуске сервера.
SECRET_KEY
=
'secret'
app config[
'SECRET_KEY'
]
=
SECRET_KEY

80
В папке templates создадим шаблон net.html для обработки форм.
{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

задаем заголовок страницы -->
{% block title %}This is an page{% endblock %}

блок body -->
{% block content %}
{{ wtf.quick_form(form, method='post',enctype="multipart/form-data", action="net") }}

один из стандартных тегов html – заголовок второго уровня -->
<
h2
>Classes:
h2
>

проверяем, есть ли данные классификации -->
{% if neurodic %}

запускаем цикл прохода по словарю и отображаем ключ-значение -->

классифицированных файлов -->
{% for key, value in neurodic.items() %}
<
h3
>{{key}}: {{value}}
h3
>
{% endfor %}
{% else %}
<
h3
> There is no classes
h3
>
{% endif %}
<
h2
>Image is here:
h2
>

отображаем загруженное изображение с закругленными углами -->

если оно есть (после submit) -->
{% if image_name %}
<
p
>{{image_name}}
<
p
><
img
src
=
{{image_name}}
class
=
"img-rounded"
alt
=
"My Image"
width
=
224
height
=
224
/>
{% else %}
<
p
> There is no image yet
p
>
{% endif %}
{% endblock %}
2.8 Добавление нейронной сети для классификации
Создадим в основной папке файл net.py.
import
random
#
библиотека keras для НС
import
keras
# входной слой сети и модель сети

81
from
keras.layers
import
Input
from
keras.models
import
Model
#
одна из предобученных сетей
from
keras.applications.resnet50
import
preprocess_input, decode_predictions
import
os
# модуль работы с изображениями
from
PIL
import
Image
import
numpy
as
np
#
для конфигурации gpu
from
tensorflow.compat.v1
import
ConfigProto
from
tensorflow.compat.v1
import
InteractiveSession
# настраиваем работу с GPU, для CPU эта часть не нужна
config
=
ConfigProto() config gpu_options per_process_gpu_memory_fraction
=
0.7
config gpu_options allow_growth
=
True session
=
InteractiveSession(config
=
config) height
=
224
width
=
224
nh
=224
nw
=224
ncol
=3
# загружаем и создаем стандартную уже обученную сеть keras
visible2
=
Input(shape
=
(nh,nw,ncol),name
=
'imginp'
) resnet
=
keras applications resnet_v2
ResNet50V2(include_top
=
True
, weights
=
'imagenet'
, input_tensor
=
visible2, input_shape
=
None
, pooling
=
None
, classes
=1000
)
# чтение изображений из каталога
# учтите, если там есть файлы, не соответствующие изображениям, или каталоги
#
возникнет ошибка
def
read_image_files
(files_max_count,dir_name): files
=
os listdir(dir_name) files_count
=
files_max_count
if
(files_max_count
>
len
(files)):
#
определяем количество файлов не больше max
files_count
=
len
(files) image_box
=
[[]]
*
files_count
for
file_i
in
range
(files_count):
#
читаем изображения в список
image_box[file_i]
=
Image open(dir_name
+
'/'
+
files[file_i])
# / ??
return
files_count, image_box

82
# возвращаем результаты работы нейронной сети
def
getresult
(image_box): files_count
=
len
(image_box) images_resized
=
[[]]
*
files_count
# нормализуем изображения и преобразуем в numpy
for
i
in
range
(files_count): images_resized[i]
=
np array(image_box[i]
resize((height,width)))
/255.0
images_resized
=
np array(images_resized)
# подаем на вход сети изображение в виде numpy массивов
out_net
=
resnet predict(images_resized)
# декодируем ответ сети в один распознанный класс top=1 (можно больше классов)
decode
=
decode_predictions(out_net, top
=1
)
return
decode
# заранее вызываем работу сети, так как работа с gpu требует времени
# из-за инициализации библиотек
# возможно, лучше убрать и закомментировать эти строки
# fcount, fimage = read_image_files(1,'./static')
# decode = getresult(fimage)
2.9
Добавление капчи
Создаем проверку google-капчи. Для этого заходим по адресу https://www.google.com/recaptcha
, затем выбираем admin console. Создаем клю- чи для капчи, label – localhost, выбираем капчу второй версии, добавляем два домена localhost и 127.0.0.1. Копируем ключи (Copy site key, Copy secret key) в app config[
'RECAPTCHA_PUBLIC_KEY'
]
=
'______________________'
app config[
'RECAPTCHA_PRIVATE_KEY'
]
=
'______________________'
2.10
Добавление возможности классификации изображения
Расширим функциональность нашего проекта, добавив обработку запроса от клиента в json-формате. Общая идея заключается в передаче от клиента в json-запросе файла изображения, закодированного строкой base64, и затем сервер возвращает класс объекта, изображенного на картинке.
Добавим в наш some_app.py следующий код:
from
flask
import
request
from
flask
import
Response

83
import
base64
from
PIL
import
Image
from
io
import
BytesIO
import
json
# метод для обработки запроса от пользователя
@app.route
(
"/apinet"
,methods
=
[
'GET'
,
'POST'
])
def
apinet
(): neurodic
=
{}
# проверяем, что в запросе json данные
if
request mimetype
==
'application/json'
:
#
получаем json данные
data
=
request get_json()
# берем содержимое по ключу, где хранится файл
# закодированный строкой base64
# декодируем строку в массив байт, используя кодировку utf-8
# первые 128 байт ascii и utf-8 совпадают, потому можно
filebytes
=
data[
'imagebin'
]
encode(
'utf-8'
)
# декодируем массив байт base64 в исходный файл изображение
cfile
=
base64
b64decode(filebytes)
# чтобы считать изображение как файл из памяти, используем BytesIO
img
=
Image open(BytesIO(cfile)) decode
=
neuronet getresult([img]) neurodic
=
{}
for
elem
in
decode: neurodic[elem[
0
][
1
]]
=
str
(elem[
0
][
2
])
print
(elem)
# пример сохранения переданного файла
# handle = open('./static/f.png','wb')
# handle.write(cfile)
# handle.close()
#
преобразуем словарь в json-строку
ret
=
json dumps(neurodic)
#
готовим ответ пользователю
resp
=
Response(response
=
ret, status
=200
, mimetype
=
"application/json"
)
#
возвращаем ответ
return
resp

84
Здесь мы не проверяем ошибки в самом json-запросе. Кроме того, если это не json-запрос, вернется пустой словарь. Желательно, конечно, добавить все необходимые проверки, чтобы у вас не возникала ошибка на стороне серве- ра 500.
Итоговый client.py, запрашивающий сервис, который мы создали
#
импортируем нужные модули
import
os
from
io
import
BytesIO
import
base64
img_data
=
None
# создаем путь к файлу (для кросс-платформенности, например)
path
=
os path join(
'./static'
,
'image0008.png'
)
# читаем файл и енкодируем его в строку base64
with
open
(path,
'rb'
)
as
fh: img_data
=
fh read() b64
=
base64
b64encode(img_data)
# создаем json словарь, который
# отправляется на сервер в виде json-строки
# преобразование делает сама функция отправки запроса post
jsondata
=
{
'imagebin'
:b64
decode(
'utf-8'
)} res
=
requests post(
'http://localhost:5000/apinet'
, json
=
jsondata)
if
res ok:
print
(res json())
Можем все это теперь закоммитить на github. И подкрепить проверку на travis. Что должно быть у нас в итоге в папке flaskapp:
/flaskapp
/static image0008.png
/templates net.html simple.html some_app.py client.py net.py st.sh

85
Реализуем коммит и изменим содержимое YAML-файла.
language
: python
before_install
:
- chmod +x ./flaskapp/st.sh
install
:
- pip3 install flask
- pip3 install gunicorn
- pip3 install requests
- pip3 install flask-bootstrap
- pip3 install flask-wtf
- pip3 install pillow
- pip3 install tensorflow==2.0.0-alpha0
- pip3 install keras
script
:
- cd flaskapp
- ./st.sh
Если все нормально, то на travis-ci в конце будут такие строчки:
[(
'n06359193'
,
'web_site'
,
0.9643341
)]
{
'web_site'
:
'0.9643341'
}
3620
[
2020-04-30 07
:
39
:
08
+0000
] [
3620
] [INFO] Handling signal: term
[
2020-04-30 07
:
39
:
08
+0000
] [
3624
] [INFO] Worker exiting (pid:
3624
)
The command
"./st.sh"
exited
with
0.
Либо вместо web_site распознанный класс, переданный вами в файле скрипта client.py.
Вообще говоря, тут мы используем travis-ci как удаленное средство за- пуска проекта. Обычно предполагается, что есть множество разработчиков и частое слияние рабочих копий в общий проект. Если бы мы сразу пошли пу- тем размещения теста в соответствующем блоке или следили за правильностью срабатывания скрипта, то коммитов нерабочих проектов и не происходило бы.

86
2.11 Дополнительная возможность по возвращению
разных документов в зависимости от шаблона
Добавим дополнительную функциональность в наш проект, в данном случае обработку xml-документа с помощью шаблона обработки xsl. В папке static добавим папку xml и туда запишем два файла: file.xml и file.xslt. Как вари- ант, предлагается взять различные прикладные области и возвращать данные в виде таблицы, списка, простого текста. Мы здесь рассмотрим только один шаблон как пример.





id=
"1"
>

John


30


Driver



id =
"2"
>

Lisa


20


Programmist




Шаблон выглядит следующим образом:


version =
"1.0"
xmlns:xsl=
"http://www.w3.org/1999/XSL/Transform"
>
1   2   3   4   5   6   7





border =
"1"
>


select=
"people/man"
>


87









select=
"@id"
/>


select=
"name"
/>


select=
"age"
/>


select=
"work"
/>


88
try
: r
=
requests get(
'http://localhost:5000/apixml'
)
print
(r status_code)
if
(r status_code
!=200
): exit
(
1
)
print
(r text)
except
: exit
(
1
)
Файл st.sh изменим так, чтобы он возвращал нам ошибку в случае, если процесс не будет выполнен. gunicorn --bind 127.0.0.1:5000 wsgi:app & APP_PID
=
$!
sleep 25 echo start client python3 client.py
APP_CODE
=
$?
sleep 5 echo $APP_PID kill -TERM $APP_PID echo app code $APP_CODE exit $APP_CODE
Теперь у нас при выполнении данного скрипта в случае ошибок исполне- ния будет возвращаться код ошибки и коммит не будет фиксироваться на github.
Загрузим новый проект на github.
Давайте проверим. Изменим YAML-файл, добавив туда
- pip3 install lxml
При коммите у нас возникает ошибка, которая обусловлена тем, что мы использовали не очень хорошо спроектированную функцию в net.py, которая считывает все подряд, включая каталоги, кроме того, мы не обрабатываем ни- как try except на сервере. Заменим в файле net.py функцию:
def
read_image_files
(files_max_count,dir_name): files
=
[item name
for
item
in
os scandir(dir_name)
if
item is_file()] files_count
=
files_max_count
if
(files_max_count
>
len
(files)):
#
определяем количество файлов не больше max
files_count
=
len
(files)

89 image_box
=
[[]]
*
files_count
for
file_i
in
range
(files_count):
#
читаем изображения в список
image_box[file_i]
=
Image open(dir_name
+
'/'
+
files[file_i])
# / ??
return
files_count, image_box
Загрузим на GitHub новую версию net.py. Теперь все должно получиться, если нет, смотрим ошибки и пытаемся их исправить, пока коммит не подтвер- дится.
2.12
Деплой на Heroku
Можно реализовать деплой непосредственно на Heroku:
deploy
:
provider
: heroku
api_key
:
secure
:
"YOUR
ENCRYPTED
API
KEY"
Правда, необходимо получить heroku auth:token, это можно сделать, например, через командную строку и команду: heroku auth:token, но для этого необходимо установить Command Line Interface Heroku https://devcenter.heroku.com/categories/command-line или по адресу https://dashboard.heroku.com/account
(
рис. 2.5).
Рис. 2.5 – Пример генерации ключа на Heroku
Чтобы реализовать деплой на Heroku, желательно получить encrypt ключа с помощью консоли travis-ci, чтобы никто не увидел вашего секретного ключа
H
eroku. Если вам не страшны возможности доступа со стороны к вашему акка- унту, можете добавить ключ непосредственно в открытом виде в YAML-файл на github в поле api_key. Но предварительно придется установить travis-cli.

90
$
travis encrypt YOUR_API_HEROKU_SECRET --org
-r
YOUR_GIT_ACCOUNT/YOUR_WEBPROJECT
При разработке желательно использовать стандартный buildpack для ка- кого-то языка, клонировав его с официального репозитория. Для Python это, например:
$
git clone https://github.com/heroku/python-getting-started.git
Затем можно настроить свой проект на базе созданного, правда, тут ис- пользуется django.
Но мы пойдем другим путем. Зарегистрируемся на сайте Heroku и созда- дим приложение. В нашем приложении на GitHub сделаем изменения. Heroku определяет наличие какого-либо типа приложения и поддержку языка на осно- ве наличия определенных специализированный файлов. Например, для Python это requirements.txt, setup.py или pipfile в корне нашего проекта вместе с YAML- файлом. Добавим requirements.txt следующего содержания: gunicorn
=
=20.0.4
Flask
=
=1.1.2
requests
=
=2.23.0
Flask-Bootstrap
=
=3.3.7.1
Flask-WTF
=
=0.14.3
Pillow
=
=6.2.2
tensorflow
=
=2.0.1
Keras
=
=2.3.1
lxml
=
=4.3.3
Как видите, это те библиотеки, которые нам понадобятся при работе нашего приложения. Heroku будет считывать данный файл при попытке build нашего приложения.
Кроме того, мы должны добавить Procfile, где укажем запуск воркеров через Gunicorn. web: gunicorn wsgi:app -b 0.0.0.0:$PORT --chdir flaskapp
Порт указывается Heroku.
Добавим runtime.txt, где укажем, например, версию Python. Можете ука- зать другую версию. python-3.7.6

91
Слегка перепишем YAML-файл.
language
: python
python
:
-
"3.7.6"
before_install
:
- chmod +x ./flaskapp/st.sh
install
:
- pip install -r requirements.txt
script
:
- cd flaskapp
- ./st.sh
Удалим в нашем файле net.py строки вызова нейронной сети в конце скрипта. Или закомментируем
# fcount, fimage = read_image_files(1,'./static')
# decode = getresult(fimage)
В нашем созданном приложении на Heroku выберем вкладку деплой.
Выберете деплой-метод Github (рис. 2.6).
Рис. 2.6 – Пример выбора деплоя
После этого реализуйте подключение к вашему аккаунту и присоедине- ние к вашему проекту с Flask.
Во вкладке Automatic deploys укажете галочкой поле Wait for CI to pass before deploy
, чтобы деплоймент разрешался системой интеграции travis-ci.
По идее все, после того как вы сделаете коммит всех изменений проекта, он должен загрузиться в качестве вашего приложения на Heroku. Приложение получилось тяжелым и медленным, возможно, потребует дополнительного времени ожидания или перезагрузки на странице браузера.

92
Подумайте, как решить проблему постоянного сохранения и накопления файлов в папке static.
Как ускорить загрузку приложения в связи c постоянной загрузкой нейронной сети.
Тестирование pytest остается на самостоятельное изучение.
Если вам хочется просмотреть структуру папок на Heroku, нужно устано- вить себе консольный клиент.
$ sudo snap install --classic heroku или
$ curl https://cli-assets.heroku.com/install-ubuntu.sh | sh
$ sudo apt-get install heroku
Воспользуйтесь командой.
$ heroku run bash --app YOUR_HEROKU_APP
Для просмотра логов можно воспользоваться командой:
$ heroku logs --tail --app YOUR_HEROKU_APP
2.
13 Задание на лабораторную работу № 1
Внимательно изучите материал методических указаний, последовательно выполняя представленные задания. После изучения и выполнения предложен- ных заданий реализуйте в соответствии со своим вариантом веб-приложение с использованием фреймворка Flask. Каждое приложение должно обеспечивать проверку на робота с помощью капчи или любой другой технологии. Размести- те объекты отображения и ввода удобно для пользователя.
Варианты для выполнения задания
Вариант 1
Веб-приложение должно обеспечивать преобразование подаваемой на вход картинки путем устранения шума в соответствии с переданным параметром сглаживания или любого другого параметра (метод фильтрации можно выбрать самостоятельно). Должна быть возможность вывода графика распределения цветов на картинке и графика распределения шума.

93
Вариант 2
Веб-приложение должно изменять контраст картинки по указанному зна- чению уровня контраста и показывать результат пользователю, выдавать гра- фики распределения цветов исходной и полученной картинки.
Вариант 3
Веб-приложение должно изменять яркость картинки по указанному зна- чению уровня яркости и показывать результат пользователю, выдавать графики распределения цветов исходной и полученной картинки.
Вариант 4
Веб-приложение должно смешивать две картинки по указанному значе- нию уровня смешения от 0 до 1 и показывать результат пользователю, выдавать графики распределения цветов исходных и полученной картинки.
Вариант 5
Веб-приложение должно изменять размер картинки по указанному значе- нию масштаба и показывать результат пользователю, выдавать графики рас- пределения цветов исходной и полученной картинки.
Вариант 6
Веб-приложение должно поворачивать картинку по указанному значению угла поворота и показывать результат пользователю, выдавать графики распре- деления цветов исходной и полученной картинки.
Вариант 7
Веб-приложение должно менять цветовые карты изображения r, g, b в со- ответствии с заданным пользователем порядком, выдавать графики распреде- ления цветов исходной картинки и графики среднего значения цвета по верти- кали и горизонтали.

94
Вариант 8
Веб-приложение должно поменять местами правую и левую часть кар- тинки либо верхнюю и нижнюю, в зависимости от желания пользователя, нари- совать график распределения цветов исходной картинки.
Вариант 9
Веб-приложение должно изменить интенсивность любой цветовой карты изображения или сразу нескольких, выдавать графики распределения цветов исходной картинки и новой картинки.
Вариант 10
Веб-приложение должно рисовать на картинке вертикальный или гори- зонтальный крест заданного цвета в зависимости от желания пользователя, вы- давать графики распределения цветов исходной картинки и новой картинки.
Вариант 11
Веб-приложение должно склеить две картинки в одну по вертикали или горизонтали в зависимости от желания пользователя, выдавать графики распре- деления цветов исходных картинок и новой картинки.
Вариант 12
Веб-приложение должно зашумлять картинку с уровнем шума заданным пользователем, выдавать графики распределения цветов исходной и новой кар- тинки.
Вариант 13
Веб-приложение должно разбить изображение на четыре части по верти- кали и горизонтали и создать четыре отдельных изображения, для каждого но- вого и исходного изображения нарисовать графики распределения цветов.

95
Вариант 14
Веб-приложение должно разбить изображение на четыре части по верти- кали и горизонтали и реализовать сдвиг по часовой стрелке данных частей, со- здав новое изображение. Нарисовать график распределения цветов для исход- ного изображения.
Вариант 15
Веб-приложение должно закрасить части изображения в шахматном по- рядке, размер шахматной клетки задает пользователь в процентах от размера исходного изображения. Нарисовать график распределения цветов для исход- ного и нового изображения.
Вариант 16
Веб-приложение должно добавить рамку для изображения, размер рамки задает пользователь. Нарисовать график распределения цветов для исходного изображения.
Вариант 17
Веб-приложение должно изменить изображением путем обмена местами чередующихся полос либо по вертикали, либо по горизонтали в зависимости от данных пользователя, так же пользователь может задать ширину полосы. Нари- совать график распределения цветов для исходного изображения.
Вариант 18
Веб-приложение должно формировать новое изображение на основе ис- ходного путем умножения изображения на периодическую функцию sin или cos с нормировкой, период изменения задает пользователь, аргумент функции определяется вертикальной или горизонтальной составляющей. Нарисовать график распределения цветов для нового и исходного изображения.

96
Вариант 19
Веб-приложение должно формировать новое изображение на основе ис- ходного путем умножения изображения на периодическую функцию sin или cos с нормировкой, период изменения задает пользователь, аргумент функции определяется и вертикальной, и горизонтальной составляющей. Нарисовать график распределения цветов для нового и исходного изображения.
Вариант 20
Веб-приложение должно формировать новое изображение на основе ис- ходного путем сдвига по замкнутым прямоугольным составляющим на опреде- ленное число пикселов, которое задает пользователь. Например, сдвигается внешняя рамка, затем вторая и так до внутренней части. Учесть, что размер сдвига внутренней части зависит от размера внутренней части и не должен пре- вышать максимального циклического сдвига по условному кругу. Нарисовать график распределения цветов для исходного изображения.

97
3
ЛАБОРАТОРНАЯ РАБОТА № 2 «РАЗРАБОТКА ВЕБ-СЕРВИСА»
Целью данной лабораторной работы является изучение создания веб- сервиса с использованием фреймворка Flask и его документирование с исполь- зование Swagger.
3.1 Создание отдельной среды окружения для проекта
Flasgger
и документирования Swagger
Создадим отдельный проект, в котором рассмотрим кратко использова- ние одной из библиотек, позволяющих вести автоматическую документацию
API с применением Swagger. Без документации ваш API бесполезен для других людей, впрочем, и для вас через какое-то время, когда вы забудете, что делали ранее, потому необходимо вести документацию, а еще проще ее вести, если это будет делаться автоматически.
Папки, которые созданы в данном проекте, не используются, и даны всего лишь для наглядности и понимания структуры проекта на Flask. В данном слу- чае используется некоторая отдельная часть сайта, сделанная с помощью
B
lueprint (sitepart), которая содержит свои шаблоны и свои статичные файлы, это и есть основная концепция использования Blueprint. Когда проект разраста- ется и в одной папке или файле сложно хранить все элементы и части веб- приложения, то можно использовать Blueprint, который позволяет создавать от- дельную часть сайта с использованием отдельного каталога, более того, можно вести независимую разработку и потом подключить кусок такого Blueprint к основному сервису просто со своим URL.
Кроме того, в примере будет приведена возможность описания сайта с использованием Swagger, благодаря библиотеке Flasgger. Создадим следую- щую структуру файлов и папок.
Создав среду, установим необходимые библиотеки.
(proj1)$ pip install flask=1.1.2
(proj1)$pip install flask-blueprint=1.3.0
(proj1)$pip install flasgger=0.9.5

98 sitepart sitepart/static sitepart/templates sitepart/sitepart.py static templates main.py
Содержимое main.py.
# Подключение библиотек для работы с Flask и Blueprint from flask import
Flask
, jsonify
,
Blueprint
# Подключение библиотеки для создания автоматической документации API
from flasgger import
Swagger
# Подключение части нашего веб-сервиса с использованием Blueprint from sitepart sitepart import sitepart
#
Приложение Flask app
=
Flask
(
__name__
)
# Инициализация для нашего API сервиса документации Swagger swagger
=
Swagger
(
app
)
#
Создаем основной Blueprint сайта main
=
Blueprint
(
"/"
,
__name__
, template_folder
=
'templates'
,
static_folder
=
'static'
)
# объявляем декоратор для метода http get
# Информация, которая будет выдаваться по URL/info/something
# Параметр в <> при вводе URL будет передан в переменную about функции info
@main.route
(
'/info//'
)
def info
(
about
)
:
"""Example endpoint returning about info
This is using docstrings for specifications.
--- parameters:
- name: about in: path type: string enum: ['all','version', 'author', 'year']
required: true

99 default: all definitions:
About:
type: string responses:
200:
description: A string schema:
$ref: '#/definitions/About'
examples:
version: '1.0'
"""
all_info
=
{
'all'
:
'main_author 1.0 2020'
,
'version'
:
'1.0'
,
'author'
:
'main_author'
,
'year'
:
'2020'
}
result
=
{
about
:
all_info
[
about
]}
return jsonify
(
result
)
#
Регистрируем основной Blueprint и Blueprint другой части сайта app register_blueprint
(
main
,
url_prefix
=
'/'
)
# url_prefix указывает URL в контексте которого будет доступна часть данного Blueprint app register_blueprint
(
sitepart
,
url_prefix
=
'/sitepart'
)
# Запуск приложения Flask в режиме debug app run
(
debug
=True
)
Debug = True означает, что отладчик Flask работает. Эта функция полезна при разработке, так как при возникновении проблем она выдает детализирован- ные сообщения об ошибке, что упрощает работу по их устранению.
Большинство функций здесь имеют комментарии, но, наверное, следует уделить внимание следующей части:

100
"""Example endpoint returning about info
This is using docstrings for specifications.
--- parameters:
- name: about in: path type: string enum: ['all','version', 'author', 'year']
required: true default: all definitions:
About:
type: string responses:
200:
description: A string schema:
$ref: '#/definitions/About'
examples:
version: '1.0'
"""
Как видите, указанная часть, использующаяся для описания и документи- рования функций в Python, здесь описывает наш API. Здесь указан входной па- раметр (parameters), фактически часть имени в пути URL, он имеет тип string и может быть значением all, version, author или year (например,
127.0.0.1:5000/info/all). Более того, по адресу http://127.0.0.1:5000/apidocs можно получить документацию на API. Мы определяем тип About string в definitions и затем используем это определение в ответах responses. Тип ответа 200 OK, имеет описание и схему, говорящую о том, что в ответе json возвращается стро- ка и даже приводится пример ответа на запрос version.
То же самое можно сделать, сославшись в документации к функции на файл, содержащий - - -, и далее содержимое, приводимое выше или в деко- раторе. На официальном сайте библиотеки приводится следующие примеры:

101 1. from flasgger import swag_from
@app.route('/colors/
/')
@swag_from('colors.yml') def colors(palette):
2.
@app.route('/colors/
/') def colors(palette):
""" file: colors.yml
"""
Кроме того, приводятся и другие варианты использования определений
S
wagger, в том числе через словарь Python и др.
В файле sitepart.py в каталоге part содержится следующий код: from flask import
Blueprint
,
jsonify
# Создаем Blueprint для отдельной части веб API
sitepart
=
Blueprint
(
1   2   3   4   5   6   7