Почему тайм-аут не всегда заканчивается ровно по часам
asyncio.TaskGroup владеет созданными в нём задачами и ждёт их завершения. Если одна падает с обычным исключением, группа запрашивает отмену остальных, дожидается очистки и собирает ошибки в ExceptionGroup.
В разборе отмены и тайм-аутов важна граница: cancel() отправляет запрос, а задача должна получить CancelledError и выполнить finally. Если она подавляет отмену или долго очищает ресурсы, завершение затянется.
wait_for() ждёт окончания отмены, поэтому фактическое время может превысить заданный timeout. Контекст asyncio.timeout() отменяет текущую задачу и преобразует свою отмену в TimeoutError снаружи блока. Для связанных операций помещайте TaskGroup внутрь timeout, чтобы дочерняя работа имела явного владельца.
#python #asyncio
asyncio.TaskGroup владеет созданными в нём задачами и ждёт их завершения. Если одна падает с обычным исключением, группа запрашивает отмену остальных, дожидается очистки и собирает ошибки в ExceptionGroup.
В разборе отмены и тайм-аутов важна граница: cancel() отправляет запрос, а задача должна получить CancelledError и выполнить finally. Если она подавляет отмену или долго очищает ресурсы, завершение затянется.
wait_for() ждёт окончания отмены, поэтому фактическое время может превысить заданный timeout. Контекст asyncio.timeout() отменяет текущую задачу и преобразует свою отмену в TimeoutError снаружи блока. Для связанных операций помещайте TaskGroup внутрь timeout, чтобы дочерняя работа имела явного владельца.
#python #asyncio
Что мешает запускать Python из снимка памяти
Импорты и инициализация повторяются при каждом старте интерпретатора. Снимок уже подготовленного процесса мог бы пропускать эту работу — особенно в WebAssembly и сервисах, которые часто запускают короткие задачи.
В обсуждении снимков CPython есть неожиданный барьер: случайное начальное значение для хеширования. Python выбирает его при запуске, чтобы затруднить атаки через коллизии. Снимок зафиксирует значение, и восстановленные процессы начнут использовать одно и то же.
Худ Чатем предлагает отдельную фазу инициализации с повторной настройкой состояния после восстановления. Потребуется учитывать и библиотеки, рассчитывающие на новый запуск. Это пока обсуждаемая архитектура; просто сохранить память процесса недостаточно для безопасного ускорения старта.
#python #cpython
Импорты и инициализация повторяются при каждом старте интерпретатора. Снимок уже подготовленного процесса мог бы пропускать эту работу — особенно в WebAssembly и сервисах, которые часто запускают короткие задачи.
В обсуждении снимков CPython есть неожиданный барьер: случайное начальное значение для хеширования. Python выбирает его при запуске, чтобы затруднить атаки через коллизии. Снимок зафиксирует значение, и восстановленные процессы начнут использовать одно и то же.
Худ Чатем предлагает отдельную фазу инициализации с повторной настройкой состояния после восстановления. Потребуется учитывать и библиотеки, рассчитывающие на новый запуск. Это пока обсуждаемая архитектура; просто сохранить память процесса недостаточно для безопасного ускорения старта.
#python #cpython
Как PEP 827 предлагает выводить тип выбранных полей
ORM-запрос выбирает name и email, но статический анализатор часто видит заранее заданную модель. Для отдельных операций приходится вручную поддерживать похожие типы: публичный ответ, создание записи и частичное обновление.
PEP 827 предлагает преобразования типов: условные выражения, перебор типов и доступ к членам модели. Библиотека могла бы вывести тип результата из выбранных полей или построить Update-модель с необязательными свойствами.
На Language Summit обсуждали и хранение аннотаций: Pydantic и FastAPI используют их во время выполнения, поэтому одного результата статической проверки недостаточно. Сохранение исходных выражений требует компромисса между памятью, скоростью и сложностью. Это предложение с прототипом, а не доступный синтаксис стабильного Python.
#python #типизация
ORM-запрос выбирает name и email, но статический анализатор часто видит заранее заданную модель. Для отдельных операций приходится вручную поддерживать похожие типы: публичный ответ, создание записи и частичное обновление.
PEP 827 предлагает преобразования типов: условные выражения, перебор типов и доступ к членам модели. Библиотека могла бы вывести тип результата из выбранных полей или построить Update-модель с необязательными свойствами.
На Language Summit обсуждали и хранение аннотаций: Pydantic и FastAPI используют их во время выполнения, поэтому одного результата статической проверки недостаточно. Сохранение исходных выражений требует компромисса между памятью, скоростью и сложностью. Это предложение с прототипом, а не доступный синтаксис стабильного Python.
#python #типизация
👍1
Python 3.10 больше не получает исправления безопасности
Версия 3.10.22 стала последней в своей ветке. После пяти лет поддержки Python 3.10 достиг end of life: новых security updates для него не будет.
В объявлении команды Python есть и другие изменения: 3.13.16 — последний полный maintenance-релиз ветки 3.13. Дальше она будет получать только исправления безопасности.
Перед миграцией проверьте интерпретатор в контейнерах, CI, виртуальных окружениях и заданиях по расписанию. Затем убедитесь, что для выбранной версии доступны совместимые зависимости и wheels, и прогоните тесты приложения.
Обновление пакетов внутри окружения само по себе не обновляет Python. Версию runtime нужно менять отдельно.
#python #обновления
Версия 3.10.22 стала последней в своей ветке. После пяти лет поддержки Python 3.10 достиг end of life: новых security updates для него не будет.
В объявлении команды Python есть и другие изменения: 3.13.16 — последний полный maintenance-релиз ветки 3.13. Дальше она будет получать только исправления безопасности.
Перед миграцией проверьте интерпретатор в контейнерах, CI, виртуальных окружениях и заданиях по расписанию. Затем убедитесь, что для выбранной версии доступны совместимые зависимости и wheels, и прогоните тесты приложения.
Обновление пакетов внутри окружения само по себе не обновляет Python. Версию runtime нужно менять отдельно.
#python #обновления
Почему lru_cache удерживает объекты в памяти
Декоратор
Есть и другие ловушки мемоизации. Каждый cache hit возвращает сохранённый объект: изменение закешированного списка увидят следующие вызовы. А
Для результатов выбирайте неизменяемые структуры, для внешних данных продумайте инвалидирование. Через
Потокобезопасность кеша тоже не гарантирует один запуск функции: при одновременных промахах вычисление может повториться.
#python #производительность
Декоратор
lru_cache хранит аргументы и результат функции. Если поставить его на метод экземпляра, self станет частью ключа — кеш может удерживать объект после того, как остальной код перестал им пользоваться.Есть и другие ловушки мемоизации. Каждый cache hit возвращает сохранённый объект: изменение закешированного списка увидят следующие вызовы. А
maxsize ограничивает число записей, но не задаёт срок их жизни.Для результатов выбирайте неизменяемые структуры, для внешних данных продумайте инвалидирование. Через
cache_info() проверьте, сколько попаданий кеш вообще даёт.Потокобезопасность кеша тоже не гарантирует один запуск функции: при одновременных промахах вычисление может повториться.
#python #производительность
👍2
Как менеджер паролей найдёт вашу форму Django
Менеджер паролей обнаружил утечку и предлагает заменить пароль. Чтобы открыть нужную страницу, он может обратиться к
В Django достаточно добавить RedirectView с pattern_name, указывающим на публичную форму смены пароля. URL стандарта не содержит завершающего слеша, а редирект должен быть временным.
Проверьте имя целевого маршрута тестом: Django разрешает его при запросе, поэтому опечатка может остаться незаметной до первого обращения.
Ещё одна проверка — неизвестный URL должен возвращать 404. Если catch-all выдаёт 200 на любой путь, менеджер паролей может проигнорировать этот механизм.
#python #django
Менеджер паролей обнаружил утечку и предлагает заменить пароль. Чтобы открыть нужную страницу, он может обратиться к
/.well-known/change-password.В Django достаточно добавить RedirectView с pattern_name, указывающим на публичную форму смены пароля. URL стандарта не содержит завершающего слеша, а редирект должен быть временным.
Проверьте имя целевого маршрута тестом: Django разрешает его при запросе, поэтому опечатка может остаться незаметной до первого обращения.
Ещё одна проверка — неизвестный URL должен возвращать 404. Если catch-all выдаёт 200 на любой путь, менеджер паролей может проигнорировать этот механизм.
#python #django
Когда Path.info экономит обращения к файловой системе
При обходе большого каталога проверки
У объектов, полученных через
Цена — актуальность. Если другой процесс заменил файл после обхода,
Кеш нельзя очистить на месте; новый
#python #файлы
При обходе большого каталога проверки
is_file() и is_dir() могут создавать множество запросов метаданных. В Python 3.14 появился кеш типов файлов Path.info.У объектов, полученных через
Path.iterdir(), он может уже содержать информацию из сканирования каталога. Несколько проверок типа используют эти данные повторно.Цена — актуальность. Если другой процесс заменил файл после обхода,
path.info может описывать прежнее состояние. Для свежей проверки используйте прямые методы Path.is_file() и Path.is_dir().Кеш нельзя очистить на месте; новый
Path(path) начинает с пустым кешем. Но даже свежая проверка не устраняет гонку между проверкой и открытием файла — ошибки операции всё равно нужно обрабатывать.#python #файлы
Почему mmap не всегда избавляет от копирования
Чтобы работать с данными через заимствованное представление, используйте
Отображение не означает, что весь файл сразу загружен в RAM, и не делает его неизменяемым снимком. Другой процесс всё ещё может менять исходный файл.
Для одного последовательного прохода обычное буферизованное чтение часто проще. Выбирайте mmap под характер доступа и измеряйте результат.
#python #память
mmap позволяет обращаться к содержимому файла по смещениям. Это удобно для бинарных форматов и повторного поиска, но срез mapped[start:end] всё равно создаёт новый объект bytes.Чтобы работать с данными через заимствованное представление, используйте
memoryview. Тогда нужно следить за временем жизни: пока представления существуют, закрытие mapping может вызвать BufferError. Освободите их до выхода из контекстного менеджера.Отображение не означает, что весь файл сразу загружен в RAM, и не делает его неизменяемым снимком. Другой процесс всё ещё может менять исходный файл.
Для одного последовательного прохода обычное буферизованное чтение часто проще. Выбирайте mmap под характер доступа и измеряйте результат.
#python #память
Почему Rust внутри CPython предлагают начать с zlib
На Python Language Summit обсудили постепенное внедрение Rust в CPython. Первый кандидат — модуль
Предлагается использовать
Перед расширением проекта нужно проверить поддержку платформ, влияние на производительность, сборку и сопровождение зависимостей.
Rust помогает исключить некоторые ошибки работы с памятью, но корректность алгоритмов по-прежнему требует тестирования. Поэтому в плане есть fuzzing и property-based tests.
#python #cpython
На Python Language Summit обсудили постепенное внедрение Rust в CPython. Первый кандидат — модуль
zlib: небольшой участок с заметным применением, в том числе при работе с пакетами.Предлагается использовать
zlib-rs, а существующую реализацию сохранить как fallback. В обсуждаемом плане Rust-бэкенд мог бы стать опциональным в Python 3.16. Это предложение, а не уже принятая возможность релиза.Перед расширением проекта нужно проверить поддержку платформ, влияние на производительность, сборку и сопровождение зависимостей.
Rust помогает исключить некоторые ошибки работы с памятью, но корректность алгоритмов по-прежнему требует тестирования. Поэтому в плане есть fuzzing и property-based tests.
#python #cpython
❤1
Почему тест проходит отдельно и падает в наборе
Один тест добавляет объект в общий список, другой рассчитывает, что список пуст. При привычном порядке запуска ошибка может долго оставаться незаметной.
В разборе плагинов pytest есть инструмент для таких случаев:
Плагин также управляет состоянием генераторов случайных чисел, поэтому сбой стоит проверить и на зависимость от случайных данных.
Ищите изменяемые атрибуты класса, глобальные кеши и фикстуры, которые оставляют состояние после себя. Исправление — изолировать данные и добавить очистку. Один успешный запуск в случайном порядке ещё не доказывает независимость тестов.
#python #тестирование
Один тест добавляет объект в общий список, другой рассчитывает, что список пуст. При привычном порядке запуска ошибка может долго оставаться незаметной.
В разборе плагинов pytest есть инструмент для таких случаев:
pytest-randomly перемешивает порядок тестов и печатает seed. С ним можно повторить проблемный запуск:pytest --randomly-seed=12345
Плагин также управляет состоянием генераторов случайных чисел, поэтому сбой стоит проверить и на зависимость от случайных данных.
Ищите изменяемые атрибуты класса, глобальные кеши и фикстуры, которые оставляют состояние после себя. Исправление — изолировать данные и добавить очистку. Один успешный запуск в случайном порядке ещё не доказывает независимость тестов.
#python #тестирование
Как запустить тесты самого Django через uv
Хотите исправить баг в Django? Сначала понадобится окружение для тестов фреймворка. Установки Django из PyPI для этого недостаточно: нужны исходники и тестовые зависимости.
Адам Джонсон показывает настройку через uv. После клонирования репозитория выполните из его корня:
Editable-установка позволяет тестам использовать ваш изменённый код. Для запуска можно указать конкретные тестовые модули вместо всего набора.
Одна из возможных проблем — сборка
#python #django
Хотите исправить баг в Django? Сначала понадобится окружение для тестов фреймворка. Установки Django из PyPI для этого недостаточно: нужны исходники и тестовые зависимости.
Адам Джонсон показывает настройку через uv. После клонирования репозитория выполните из его корня:
uv venv
uv pip install -e . -r tests/requirements/py3.txt
uv run python tests/runtests.py
Editable-установка позволяет тестам использовать ваш изменённый код. Для запуска можно указать конкретные тестовые модули вместо всего набора.
Одна из возможных проблем — сборка
pylibmc, которой нужны компилятор и заголовки libmemcached. Без этой зависимости остальные тесты можно запускать, но проверки, которым она нужна, будут пропущены. Учитывайте это, если правка затрагивает кеширование.#python #django
Почему subprocess с PIPE может зависнуть
Дочерний процесс пишет в stdout, родитель вызывает
В разборе взаимной блокировки показано, почему каналы нужно читать во время работы процесса. Для ограниченного вывода удобен
Он использует
У
#python #процессы
Дочерний процесс пишет в stdout, родитель вызывает
wait(). На небольшом выводе всё работает. На большом буфер канала заполняется: ребёнок ждёт чтения, родитель — завершения ребёнка.В разборе взаимной блокировки показано, почему каналы нужно читать во время работы процесса. Для ограниченного вывода удобен
run():import subprocess
result = subprocess.run(
["python", "--version"],
capture_output=True,
text=True,
timeout=10,
check=True,
)
Он использует
communicate(), который обслуживает оба потока. Вывод при этом собирается в памяти, поэтому для больших логов выбирайте файл или потоковое чтение.У
Popen.communicate(timeout=...) другая тонкость: истечение тайм-аута само не убивает процесс. Нужны завершение процесса и повторный communicate() для чтения остатка вывода.#python #процессы
⚡1