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
Что проверить перед переходом на SQLAlchemy 2.1
Обновление зависимости может поменять драйвер подключения, даже если строка подключения осталась прежней.
В SQLAlchemy 2.1 адрес
Есть ещё два изменения: минимальная версия Python — 3.11, а
Перед обновлением прогоните сценарии подключения, транзакций и загрузки связей. Проверьте окружение CI: старая установленная зависимость может скрыть то, что сломается при чистой установке.
#python #sqlalchemy
Обновление зависимости может поменять драйвер подключения, даже если строка подключения осталась прежней.
В SQLAlchemy 2.1 адрес
postgresql:// по умолчанию выбирает psycopg, а oracle:// — oracledb. Если проект рассчитывает на конкретный DBAPI, укажите его явно и проверьте совместимость.Есть ещё два изменения: минимальная версия Python — 3.11, а
greenlet больше не устанавливается автоматически. Для асинхронных возможностей используйте:pip install "sqlalchemy[asyncio]"
Перед обновлением прогоните сценарии подключения, транзакций и загрузки связей. Проверьте окружение CI: старая установленная зависимость может скрыть то, что сломается при чистой установке.
#python #sqlalchemy
Как сделать бэкап работающей SQLite через Python
Просто скопировать файл активной базы рискованно. Во время копирования страницы могут изменяться, а при WAL часть данных находится в отдельном журнале.
Python предоставляет доступ к SQLite Online Backup API через
SQLite согласует копирование с работой базы. Получившаяся копия самостоятельна: следующие записи в исходник в неё не попадут.
Здесь
#python #sqlite
Просто скопировать файл активной базы рискованно. Во время копирования страницы могут изменяться, а при WAL часть данных находится в отдельном журнале.
Python предоставляет доступ к SQLite Online Backup API через
Connection.backup(). Метод вызывают у источника и передают ему соединение с приёмником:import sqlite3
from contextlib import closing
with closing(sqlite3.connect("app.db")) as src:
with closing(sqlite3.connect("backup.db")) as dst:
src.backup(dst)
SQLite согласует копирование с работой базы. Получившаяся копия самостоятельна: следующие записи в исходник в неё не попадут.
Здесь
closing нужен для закрытия соединений: обычный with connection управляет транзакцией, но не закрывает соединение. После бэкапа проверьте восстановление и чтение данных.#python #sqlite
❤1
UTF-8 по умолчанию не перекодирует старые файлы
В Python 3.15 текстовый ввод-вывод по умолчанию использует UTF-8. Это убирает часть различий между платформами, но файл в CP1251 остаётся файлом в CP1251.
В руководстве по переходу предлагают сначала найти операции с неявной кодировкой:
Предупреждения покажут выполненные вызовы, где кодировка не указана. Для остальных путей пригодится статическая проверка.
Указывайте
Не добавляйте
#python #файлы
В Python 3.15 текстовый ввод-вывод по умолчанию использует UTF-8. Это убирает часть различий между платформами, но файл в CP1251 остаётся файлом в CP1251.
В руководстве по переходу предлагают сначала найти операции с неявной кодировкой:
python -X warn_default_encoding app.py
Предупреждения покажут выполненные вызовы, где кодировка не указана. Для остальных путей пригодится статическая проверка.
Указывайте
encoding="utf-8" для UTF-8 и encoding="cp1251" для известных старых файлов. Если нужна именно кодировка локали пользователя, используйте encoding="locale".Не добавляйте
errors="ignore" ради исчезновения ошибки: так можно незаметно потерять символы. Перед обновлением проверьте реальные входные файлы, включая выгрузки из старых систем.#python #файлы