Spec-Zone.ru › Flask 2.1

Обработка конфигурации

Приложениям необходима некая конфигурация. Существуют различные настройки, которые вы можете изменить в зависимости от среды приложения, например, включение режима отладки, установка секретного ключа и другие специфичные для среды параметры.

При разработке Flask конфигурация обычно должна быть доступна при запуске приложения. Вы можете жестко запрограммировать конфигурацию в коде, что для многих небольших приложений не так уж и плохо, но существуют лучшие способы.

Независимо от того, как вы загружаете свою конфигурацию, доступен объект конфигурации, содержащий загруженные значения конфигурации: атрибут config объекта Flask. Именно здесь Flask сам помещает определенные значения конфигурации, а также расширения могут помещать свои значения конфигурации. Но здесь также вы можете иметь свою собственную конфигурацию.

Основы конфигурации

Атрибут config фактически является подклассом словаря и может быть изменен, как и любой словарь:

app = Flask(__name__)
app.config['TESTING'] = True

Определенные значения конфигурации также передаются объекту Flask, так что вы можете читать и записывать их оттуда:

app.testing = True

Чтобы обновить несколько ключей одновременно, вы можете использовать метод dict.update():

app.config.update(
    TESTING=True,
    SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
)

Среда и функции отладки

Значения конфигурации ENV и DEBUG являются специальными, поскольку они могут вести себя непредсказуемо, если их изменить после того, как приложение начало настройку. Для надежной установки среды и режима отладки Flask использует переменные окружения.

Среда используется для указания Flask, расширениям и другим программам, например Sentry, в каком контексте Flask работает. Она контролируется переменной окружения FLASK_ENV и по умолчанию равна production.

Установка FLASK_ENV на development включит режим отладки. flask run по умолчанию будет использовать интерактивный отладчик и перезагрузчик в режиме отладки. Чтобы контролировать это отдельно от среды, используйте флаг FLASK_DEBUG.

Журнал изменений

Изменено в версии 1.0: Добавлен FLASK_ENV для отдельного управления средой от режима отладки. Среда разработки включает режим отладки.

Чтобы переключить Flask в среду разработки и включить режим отладки, установите FLASK_ENV:

$ export FLASK_ENV=development
$ flask run
$ set -x FLASK_ENV development
$ flask run
> set FLASK_ENV=development
> flask run
> $env:FLASK_ENV = "development"
> flask run

Рекомендуется использовать переменные окружения, как описано выше. Хотя возможно установить ENV и DEBUG в вашей конфигурации или коде, это настоятельно не рекомендуется. Их нельзя прочитать на ранней стадии командой flask , и некоторые системы или расширения, возможно, уже настроили себя на основе предыдущего значения.

Встроенные значения конфигурации

Следующие значения конфигурации используются внутри Flask:

ENV

Окружение, в котором запущено приложение. Flask и расширения могут включать поведение, основанное на окружении, например, включение отладочного режима. Атрибут env сопоставляется с этим ключом конфигурации. Он устанавливается переменной окружения FLASK_ENV и может работать не так, как ожидается, если установлен в коде.

Не включайте разработку при развертывании в продакшене.

По умолчанию: 'production'

Журнал изменений

Новое в версии 1.0.

DEBUG

Включен ли отладочный режим. При использовании flask run для запуска сервера разработки, будет показан интерактивный отладчик для необработанных исключений, и сервер будет перезагружаться при изменении кода. Атрибут debug сопоставляется с этим ключом конфигурации. Он включен, когда ENV равен 'development' и переопределяется переменной окружения FLASK_DEBUG. Он может работать не так, как ожидается, если установлен в коде.

Не включайте отладочный режим при развертывании в продакшене.

По умолчанию: True если ENV равен 'development', или False в противном случае.

TESTING

Включить тестовый режим. Исключения распространяются, а не обрабатываются обработчиками ошибок приложения. Расширения также могут изменить свое поведение для облегчения тестирования. Вы должны включить это в своих тестах.

По умолчанию: False

PROPAGATE_EXCEPTIONS

Исключения повторно генерируются, а не обрабатываются обработчиками ошибок приложения. Если не задано, это неявно истинно, если TESTING или DEBUG включены.

По умолчанию: None

PRESERVE_CONTEXT_ON_EXCEPTION

Не удалять контекст запроса при возникновении исключения. Если не задано, это истинно, если DEBUG истинно. Это позволяет отладчикам инспектировать данные запроса при ошибках, и обычно его не нужно устанавливать напрямую.

По умолчанию: None

TRAP_HTTP_EXCEPTIONS

Если нет обработчика для исключения типа HTTPException, повторно генерировать его для обработки интерактивным отладчиком вместо возврата его как простого ответа об ошибке.

По умолчанию: False

TRAP_BAD_REQUEST_ERRORS

Попытка доступа к несуществующему ключу из словарей запроса, таких как args и form, вернёт страницу ошибки 400 Bad Request. Включите это, чтобы рассматривать ошибку как необработанное исключение, чтобы получить интерактивный отладчик. Это более конкретная версия TRAP_HTTP_EXCEPTIONS Если не установлено, то включено в отладочном режиме.

По умолчанию: None

SECRET_KEY

Секретный ключ, который будет использоваться для безопасного шифрования cookie сессии и может использоваться для любых других задач безопасности расширениями или вашим приложением. Это должна быть длинная случайная bytes или str. Например, скопируйте вывод этого в вашу конфигурацию:

$ python -c 'import secrets; print(secrets.token_hex())'
'192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'

Не раскрывайте секретный ключ при публикации вопросов или коммитах кода.

По умолчанию: None

SESSION_COOKIE_NAME

Имя cookie сессии. Может быть изменено, если у вас уже есть cookie с таким же именем.

По умолчанию: 'session'

SESSION_COOKIE_DOMAIN

Правило соответствия домена, для которого cookie сессии будет действительным. Если не задано, cookie будет действительным для всех поддоменов SERVER_NAME. Если False, домен cookie не будет установлен.

По умолчанию: None

SESSION_COOKIE_PATH

Путь, для которого cookie сессии будет действительным. Если не задано, cookie будет действительным в APPLICATION_ROOT или /, если это не задано.

По умолчанию: None

SESSION_COOKIE_HTTPONLY

Браузеры не позволят JavaScript получить доступ к cookies, помеченным как «только HTTP», для обеспечения безопасности.

По умолчанию: True

SESSION_COOKIE_SECURE

Браузеры будут отправлять cookies только с запросами по HTTPS, если cookie помечен как «безопасный». Приложение должно быть доступно по HTTPS для того, чтобы это имело смысл.

По умолчанию: False

SESSION_COOKIE_SAMESITE

Ограничить способ отправки cookies с запросами с внешних сайтов. Может быть установлено в 'Lax' (рекомендуется) или 'Strict'. См. Параметры Set-Cookie.

По умолчанию: None

Журнал изменений

Новое в версии 1.0.

PERMANENT_SESSION_LIFETIME

Если session.permanent истинно, срок действия cookie будет установлен на это количество секунд в будущем. Может быть datetime.timedelta или int.

Встроенная реализация cookie Flask проверяет, что криптографическая подпись не старше этого значения.

По умолчанию: timedelta(days=31) (2678400 секунд)

SESSION_REFRESH_EACH_REQUEST

Управляет тем, отправляется ли cookie с каждым ответом, когда session.permanent истинно. Отправка cookie каждый раз (по умолчанию) может более надёжно предотвратить истечение сессии, но использует больше полосы пропускания. Непостоянные сессии не затрагиваются.

По умолчанию: True

USE_X_SENDFILE

При передаче файлов установить заголовок X-Sendfile вместо отправки данных с Flask. Некоторые веб-серверы, такие как Apache, распознают это и отправляют данные более эффективно. Это имеет смысл только при использовании такого сервера.

По умолчанию: False

SEND_FILE_MAX_AGE_DEFAULT

При отправке файлов установите максимальную длительность кэширования на это количество секунд. Может быть datetime.timedelta или int. Переопределите это значение на основе файла, используя get_send_file_max_age() в приложении или шаблоне.

Если None, send_file указывает браузеру использовать условные запросы вместо кэширования по времени, что обычно предпочтительнее.

По умолчанию: None

SERVER_NAME

Уведомить приложение о том, к какому хосту и порту оно подключено. Требуется для поддержки соответствия маршрутов по поддоменам.

Если установлено, будет использоваться для домена cookie сессии, если SESSION_COOKIE_DOMAIN не установлен. Современные браузеры не позволят устанавливать cookies для доменов без точки. Чтобы использовать домен локально, добавьте все имена, которые должны быть перенаправлены на приложение, в свой файл hosts.

127.0.0.1 localhost.dev

Если установлено, url_for может генерировать внешние URL-адреса только с контекстом приложения вместо контекста запроса.

По умолчанию: None

APPLICATION_ROOT

Уведомить приложение о пути, под которым оно смонтировано приложением/веб-сервером. Это используется для генерации URL-адресов за пределами контекста запроса (внутри запроса, диспетчер отвечает за установку SCRIPT_NAME вместо; см. Передача управления приложением для примеров конфигурации диспетчеризации).

Будет использоваться для пути cookie сессии, если SESSION_COOKIE_PATH не установлен.

По умолчанию: '/'

PREFERRED_URL_SCHEME

Использовать эту схему для генерации внешних URL-адресов, когда контекст запроса отсутствует.

По умолчанию: 'http'

MAX_CONTENT_LENGTH

Не читать больше этого количества байт из данных входящего запроса. Если не установлено и запрос не указывает CONTENT_LENGTH, данные не будут читаться для обеспечения безопасности.

По умолчанию: None

JSON_AS_ASCII

Сериализовать объекты в ASCII-кодированный JSON. Если это отключено, возвращаемый из jsonify JSON будет содержать символы Unicode. Это имеет последствия для безопасности при отображении JSON в JavaScript в шаблонах и обычно должно оставаться включённым.

По умолчанию: True

JSON_SORT_KEYS

Сортировать ключи JSON-объектов в алфавитном порядке. Это полезно для кэширования, так как гарантирует, что данные сериализуются одинаково независимо от того, какое используется значение семени хэша Python. Хотя не рекомендуется, вы можете отключить эту функцию для возможного повышения производительности за счет кэширования.

Значение по умолчанию: True

JSONIFY_PRETTYPRINT_REGULAR

jsonify ответы будут выводиться с новыми строками, пробелами и отступами для лучшей читаемости человеком. Всегда включено в режиме отладки.

Значение по умолчанию: False

JSONIFY_MIMETYPE

MIME-тип jsonify ответов.

Значение по умолчанию: 'application/json'

TEMPLATES_AUTO_RELOAD

Перезагружать шаблоны при их изменении. Если не установлено, будет включено в режиме отладки.

Значение по умолчанию: None

EXPLAIN_TEMPLATE_LOADING

Вести журнал отладочной информации, отслеживая, как загружался файл шаблона. Это может быть полезно, чтобы понять, почему шаблон не был загружен или загружен неправильный файл.

Значение по умолчанию: False

MAX_COOKIE_SIZE

Выводить предупреждение, если заголовки cookie превышают это количество байтов. Значение по умолчанию 4093. Браузеры могут игнорировать большие cookie. Установите в 0 чтобы отключить предупреждение.

Журнал изменений

Изменено в версии 1.0: LOGGER_NAME и LOGGER_HANDLER_POLICY были удалены. Смотрите Ведение журнала для получения информации о конфигурации.

Добавлен ENV для отражения переменной окружения FLASK_ENV.

Добавлен SESSION_COOKIE_SAMESITE для управления параметром SameSite cookie сессии.

Добавлен MAX_COOKIE_SIZE для управления предупреждением от Werkzeug.

Новое в версии 0.11: SESSION_REFRESH_EACH_REQUEST, TEMPLATES_AUTO_RELOAD, LOGGER_HANDLER_POLICY, EXPLAIN_TEMPLATE_LOADING

Новое в версии 0.10: JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_PRETTYPRINT_REGULAR

Новое в версии 0.9: PREFERRED_URL_SCHEME

Новое в версии 0.8: TRAP_BAD_REQUEST_ERRORS, TRAP_HTTP_EXCEPTIONS, APPLICATION_ROOT, SESSION_COOKIE_DOMAIN, SESSION_COOKIE_PATH, SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE

Новое в версии 0.7: PROPAGATE_EXCEPTIONS, PRESERVE_CONTEXT_ON_EXCEPTION

Новое в версии 0.6: MAX_CONTENT_LENGTH

Новое в версии 0.5: SERVER_NAME

Новое в версии 0.4: LOGGER_NAME

Настройка из файлов Python

Конфигурация становится более полезной, если вы можете хранить её в отдельном файле, предпочтительно расположенном вне самого пакета приложения. Это позволяет упаковывать и распространять ваше приложение с помощью различных инструментов обработки пакетов (Развертывание с помощью Setuptools) и, наконец, изменять файл конфигурации после этого.

Поэтому распространённым шаблоном является:

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

Сначала загружается конфигурация из модуля yourapplication.default_settings, а затем значения перезаписываются содержимым файла, на который указывает переменная окружения YOURAPPLICATION_SETTINGS. Эту переменную окружения можно установить в оболочке перед запуском сервера:

$ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg
$ flask run
 * Running on http://127.0.0.1:5000/
$ set -x YOURAPPLICATION_SETTINGS /path/to/settings.cfg
$ flask run
 * Running on http://127.0.0.1:5000/
> set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg
> flask run
 * Running on http://127.0.0.1:5000/
> $env:YOURAPPLICATION_SETTINGS = "\path\to\settings.cfg"
> flask run
 * Running on http://127.0.0.1:5000/

Сами файлы конфигурации — это фактические файлы Python. Только значения с заглавными буквами фактически хранятся в объекте config позже. Поэтому убедитесь, что для ваших ключей конфигурации используются заглавные буквы.

Вот пример файла конфигурации:

# Example configuration
SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'

Убедитесь, что конфигурация загружается очень рано, чтобы расширения могли получить доступ к конфигурации при запуске. В объекте config также есть другие методы для загрузки из отдельных файлов. Для получения полной справки, прочитайте документацию по объекту Config.

Настройка из файлов данных

Также возможно загрузить конфигурацию из файла в формате по вашему выбору, используя from_file(). Например, для загрузки из файла TOML:

import toml
app.config.from_file("config.toml", load=toml.load)

Или из файла JSON:

import json
app.config.from_file("config.json", load=json.load)

Настройка из переменных окружения

Помимо указания на файлы конфигурации с помощью переменных окружения, вам может быть полезно (или необходимо) управлять значениями конфигурации непосредственно из окружения. Flask можно настроить на загрузку всех переменных окружения, начинающихся со специфического префикса, в config с помощью from_prefixed_env().

Переменные окружения могут быть установлены в оболочке перед запуском сервера:

$ export FLASK_SECRET_KEY="5f352379324c22463451387a0aec5d2f"
$ export FLASK_MAIL_ENABLED=false
$ flask run
 * Running on http://127.0.0.1:5000/
$ set -x FLASK_SECRET_KEY "5f352379324c22463451387a0aec5d2f"
$ set -x FLASK_MAIL_ENABLED false
$ flask run
 * Running on http://127.0.0.1:5000/
> set FLASK_SECRET_KEY="5f352379324c22463451387a0aec5d2f"
> set FLASK_MAIL_ENABLED=false
> flask run
 * Running on http://127.0.0.1:5000/
> $env:FLASK_SECRET_KEY = "5f352379324c22463451387a0aec5d2f"
> $env:FLASK_MAIL_ENABLED = "false"
> flask run
 * Running on http://127.0.0.1:5000/

Переменные затем можно загрузить и получить доступ к ним в config с ключом, равным имени переменной окружения без префикса, т.е.

app.config.from_prefixed_env()
app.config["SECRET_KEY"]  # Is "5f352379324c22463451387a0aec5d2f"

Префикс по умолчанию FLASK_. Это настраивается с помощью аргумента prefix from_prefixed_env().

Значения будут распарсены для попытки преобразования в тип, более специфичный, чем строки. По умолчанию используется json.loads(), поэтому возможны любые допустимые JSON-значения, включая списки и словари. Это настраивается с помощью аргумента loads from_prefixed_env().

При добавлении булевого значения с помощью стандартного парсинга JSON, только “true” и “false”, строчные, являются допустимыми значениями. Имейте в виду, что любая непустая строка рассматривается как True в Python.

Можно задавать ключи во вложенных словарях, разделяя ключи двойным подчёркиванием (__). Любые промежуточные ключи, которые не существуют в родительском словаре, будут инициализированы пустым словарем.

$ export FLASK_MYAPI__credentials__username=user123
app.config["MYAPI"]["credentials"]["username"]  # Is "user123"

В Windows ключи переменных окружения всегда заглавные, поэтому вышеприведённый пример превратится в MYAPI__CREDENTIALS__USERNAME.

Для ещё более продвинутых функций загрузки конфигурации, включая слияние и регистронезависимую поддержку Windows, попробуйте специализированную библиотеку, такую как Dynaconf, которая включает интеграцию с Flask.

Рекомендации по конфигурированию

Недостатком подхода, упомянутого ранее, является то, что он усложняет тестирование. В общем случае нет единственного решения на 100%, но есть несколько моментов, которые можно учитывать для улучшения этого опыта:

  1. Создайте свое приложение в функции и зарегистрируйте схемы на нем. Таким образом, вы можете создавать несколько экземпляров приложения с различными прикрепленными конфигурациями, что значительно упрощает тестирование отдельных модулей. Вы можете использовать это для передачи конфигурации по мере необходимости.
  2. Не пишите код, которому требуется конфигурация во время импорта. Если вы ограничитесь доступом к конфигурации только по запросу, вы сможете переконфигурировать объект позже по мере необходимости.
  3. Убедитесь, что конфигурация загружается очень рано, чтобы расширения могли получить доступ к конфигурации при вызове init_app.

Разработка/Производство

Большинству приложений требуется более одной конфигурации. Должны быть отдельные конфигурации для сервера производства и конфигурации, используемой во время разработки. Самый простой способ справиться с этим — использовать стандартную конфигурацию, которая всегда загружается и является частью контроля версий, и отдельную конфигурацию, которая переопределяет значения по мере необходимости, как показано в примере выше:

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

Затем вам просто нужно добавить отдельный config.py файл и экспортировать YOURAPPLICATION_SETTINGS=/path/to/config.py, и все готово. Однако существуют и альтернативные способы. Например, вы можете использовать импорты или наследование.

Очень популярный метод в мире Django — сделать импорт явным в файле конфигурации, добавив from yourapplication.default_settings import * в начало файла, а затем вручную переопределить изменения. Вы также можете проверить переменную среды, такую как YOURAPPLICATION_MODE, и установить ее в production, development и т. д., и импортировать различные жестко закодированные файлы в зависимости от этого.

Интересный паттерн также заключается в использовании классов и наследования для конфигурации:

class Config(object):
    TESTING = False

class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
    DATABASE_URI = "sqlite:////tmp/foo.db"

class TestingConfig(Config):
    DATABASE_URI = 'sqlite:///:memory:'
    TESTING = True

Для активации такой конфигурации необходимо вызвать from_object():

app.config.from_object('configmodule.ProductionConfig')

Обратите внимание, что from_object() не создает экземпляр объекта класса. Если вам нужно создать экземпляр класса, например, для доступа к свойству, необходимо сделать это до вызова from_object():

from configmodule import ProductionConfig
app.config.from_object(ProductionConfig())

# Alternatively, import via string:
from werkzeug.utils import import_string
cfg = import_string('configmodule.ProductionConfig')()
app.config.from_object(cfg)

Создание экземпляра объекта конфигурации позволяет использовать @property в ваших классах конфигурации:

class Config(object):
    """Base config, uses staging database server."""
    TESTING = False
    DB_SERVER = '192.168.1.56'

    @property
    def DATABASE_URI(self):  # Note: all caps
        return f"mysql://user@{self.DB_SERVER}/foo"

class ProductionConfig(Config):
    """Uses production database server."""
    DB_SERVER = '192.168.19.32'

class DevelopmentConfig(Config):
    DB_SERVER = 'localhost'

class TestingConfig(Config):
    DB_SERVER = 'localhost'
    DATABASE_URI = 'sqlite:///:memory:'

Существует множество различных способов, и как вы хотите управлять своими файлами конфигурации — решать вам. Однако вот список полезных рекомендаций:

  • Сохраняйте стандартную конфигурацию в системе управления версиями. Заполните конфигурацию этой стандартной конфигурацией или импортируйте ее в свои собственные файлы конфигурации перед переопределением значений.
  • Используйте переменную среды для переключения между конфигурациями. Это можно сделать вне интерпретатора Python и значительно упрощает разработку и развертывание, так как позволяет быстро и легко переключаться между различными конфигурациями, не изменяя код. Если вы часто работаете над разными проектами, вы можете даже создать свою собственную скрипт для задания, которая активирует virtualenv и экспортирует для вас конфигурацию разработки.
  • Используйте инструмент, такой как fabric для развертывания, чтобы отдельно распространять код и конфигурации на серверы производства. Более подробную информацию об этом вы найдете в шаблоне Развертывание с Fabric.

Папки экземпляров

Журнал изменений

В версии 0.8.

Flask 0.8 вводит папки экземпляров. Flask долгое время позволял ссылаться на пути, относящиеся непосредственно к папке приложения (через Flask.root_path). Таким же образом многие разработчики загружали конфигурации, хранящиеся рядом с приложением. Однако, к сожалению, это хорошо работает только если приложения не являются пакетами, в этом случае корневой путь относится к содержимому пакета.

В Flask 0.8 была добавлена новая атрибут: Flask.instance_path. Он относится к новому понятию — «папка экземпляра». Папка экземпляра предназначена для того, чтобы не находиться под управлением контроля версий и быть специфичной для развертывания. Это идеальное место для хранения данных, которые меняются во время выполнения, или конфигурационных файлов.

Вы можете либо явно указать путь к папке экземпляра при создании приложения Flask, либо позволить Flask автоматически определить папку экземпляра. Для явного конфигурирования используйте параметр instance_path:

app = Flask(__name__, instance_path='/path/to/instance/folder')

Пожалуйста, имейте в виду, что этот путь должен быть абсолютным при указании.

Если параметр instance_path не указан, используются следующие значения по умолчанию:

  • Модуль, не установленный:

    /myapp.py
    /instance
    
  • Пакет, не установленный:

    /myapp
        /__init__.py
    /instance
    
  • Модуль или пакет, установленный:

    $PREFIX/lib/pythonX.Y/site-packages/myapp
    $PREFIX/var/myapp-instance
    

    $PREFIX — это префикс вашей установки Python. Это может быть /usr или путь к вашему virtualenv. Вы можете вывести значение sys.prefix, чтобы увидеть, чему оно установлено.

Поскольку объект конфигурации обеспечивал загрузку файлов конфигурации из относительных имен файлов, мы сделали возможным изменение загрузки с использованием имен файлов, относительных к пути экземпляра, при необходимости. Поведение относительных путей в файлах конфигурации можно переключать между «относительно корня приложения» (по умолчанию) и «относительно папки экземпляра» с помощью переключателя instance_relative_config в конструктор приложения:

app = Flask(__name__, instance_relative_config=True)

Вот полный пример того, как настроить Flask для предварительной загрузки конфигурации из модуля, а затем переопределить конфигурацию из файла в папке экземпляра, если он существует:

app = Flask(__name__, instance_relative_config=True)
app.config.from_object('yourapplication.default_settings')
app.config.from_pyfile('application.cfg', silent=True)

Путь к папке экземпляра можно найти в Flask.instance_path. Flask также предоставляет сокращение для открытия файла из папки экземпляра с помощью Flask.open_instance_resource().

Пример использования обоих:

filename = os.path.join(app.instance_path, 'application.cfg')
with open(filename) as f:
    config = f.read()

# or via open_instance_resource:
with app.open_instance_resource('application.cfg') as f:
    config = f.read()

© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.1.x/config/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API