Python Quiz
Что выведет этот код? 💡🧠
Чему учит: f‑строки с динамической шириной — как подставлять спецификатор формата через { } и контролировать заполнение.
Зачем важно: полезно для аккуратного вывода чисел в логах/отчётах и на собеседованиях, где проверяют синтаксис. 😺
'0' перед шириной — символ заполнителя нулями; {w…
Зачем важно: полезно для аккуратного вывода чисел в логах/отчётах и на собеседованиях, где проверяют синтаксис. 😺
JIT в Python могут выпилить — и не потому что он глючит
Полгода никто не чесался — JIT спокойно жил в main с 3.13, разгонял x86-64/Linux в среднем на 8-9% и должен был стать одной из витрин 3.15 (тот уже во freeze, релиз в октябре). А 5 июня Steering Council внезапно нажал стоп.
Причина не техническая. Всё это держится на PEP 744, а он informational, не standards-track — то есть юридически никого ни к чему не обязывает: ни к поддержке, ни к метрикам успеха, ни к обещаниям совместимости. Совет сам признал: "мы не были достаточно строги к процессу для изменения такого масштаба".
Дали полгода: либо нормальный normative PEP с критериями принятия, либо код едет из main. Баги и security чинят как обычно, новые фичи — заморожены. Томас Воутерс из совета: "we're not unreasonable, but we do want this to be taken seriously" — не расстрельный дедлайн, но и не формальность для галочки.
Мне это скорее нравится, хоть и с опозданием. Три релиза фича жила без единого письменного обязательства на случай, если что-то пойдёт не так. Спохватились бы раньше — меньше народу сейчас зависело бы от undocumented behavior.
Полгода никто не чесался — JIT спокойно жил в main с 3.13, разгонял x86-64/Linux в среднем на 8-9% и должен был стать одной из витрин 3.15 (тот уже во freeze, релиз в октябре). А 5 июня Steering Council внезапно нажал стоп.
Причина не техническая. Всё это держится на PEP 744, а он informational, не standards-track — то есть юридически никого ни к чему не обязывает: ни к поддержке, ни к метрикам успеха, ни к обещаниям совместимости. Совет сам признал: "мы не были достаточно строги к процессу для изменения такого масштаба".
Дали полгода: либо нормальный normative PEP с критериями принятия, либо код едет из main. Баги и security чинят как обычно, новые фичи — заморожены. Томас Воутерс из совета: "we're not unreasonable, but we do want this to be taken seriously" — не расстрельный дедлайн, но и не формальность для галочки.
Мне это скорее нравится, хоть и с опозданием. Три релиза фича жила без единого письменного обязательства на случай, если что-то пойдёт не так. Спохватились бы раньше — меньше народу сейчас зависело бы от undocumented behavior.
👍1
В comprehension наконец завезли распаковку через *
Все путаются в
PEP 798 чинит это через
Забавная деталь из самого PEP: авторов натолкнул письменный экзамен по Python — студенты в ответах уже писали такую звёздочку, будучи уверены, что она существует. Не существовала — до сих пор.
Фича заморожена в 3.15.0b1, релиз в октябре. Двойной for никуда не денется, но хотя бы будет чем его заменить, когда не хочешь гадать про порядок циклов.
Все путаются в
[x for row in matrix for x in row] — кажется, что for идут как во вложенном цикле, а на деле наоборот, второй for относится к первому. Классический баг на собеседованиях.PEP 798 чинит это через
*: [*row for row in matrix] — то же самое, но без риска перепутать порядок. Работает и для {*row for row in matrix}, и для словарей через **.Забавная деталь из самого PEP: авторов натолкнул письменный экзамен по Python — студенты в ответах уже писали такую звёздочку, будучи уверены, что она существует. Не существовала — до сих пор.
Фича заморожена в 3.15.0b1, релиз в октябре. Двойной for никуда не денется, но хотя бы будет чем его заменить, когда не хочешь гадать про порядок циклов.
Ваш free-threaded питон может тихо врать про GIL
Поставил 3.14.0t (free-threaded сборку), жду параллелизма — а профиль как будто однопоточный.
Оказалось, это норм поведение, просто нигде не орёт об этом. Любое C-расширение, не помеченное как поддерживающее free-threading, при импорте тихо включает GIL обратно. Без варнинга, без ошибки — просто твой параллелизм молча схлопывается в обычный GIL-режим.
Проверяется одной строкой после всех импортов:
Есть ещё жёсткий вариант —
Перед тем как постить в чат бенчмарки с линейным ускорением на 3.14t — сначала эта проверка, потом бенчмарк.
Поставил 3.14.0t (free-threaded сборку), жду параллелизма — а профиль как будто однопоточный.
Оказалось, это норм поведение, просто нигде не орёт об этом. Любое C-расширение, не помеченное как поддерживающее free-threading, при импорте тихо включает GIL обратно. Без варнинга, без ошибки — просто твой параллелизм молча схлопывается в обычный GIL-режим.
Проверяется одной строкой после всех импортов:
python3.14 -c "import sys; print(sys._is_gil_enabled())"True после импорта нужных тебе либ — значит что-то из зависимостей откатило GIL обратно, и весь выигрыш от free-threaded сборки ты потерял, просто об этом не узнал.Есть ещё жёсткий вариант —
PYTHON_GIL=0 или -X gil=0: тогда откат запрещён, и несовместимое расширение уронит процесс вместо тихого отката. Для CI это честнее, чем молчаливая деградация.Перед тем как постить в чат бенчмарки с линейным ускорением на 3.14t — сначала эта проверка, потом бенчмарк.
Что выведет этот код с lazy import в Python 3.15?
В 3.15 beta 4 подвезли
Взял классику:
Прогони в голове, без REPL. Порядок печати — в опросе.
В 3.15 beta 4 подвезли
lazy import (PEP 810) — модуль реально не грузится, пока не тронешь его атрибут. Звучит как мелочь, а ломает интуицию с ходу.Взял классику:
import this печатает дзен прямо при загрузке модуля, это все знают. Обернул в lazy import и написал zen = this. Был уверен, что присваивание — это уже «использование». Не угадал.Прогони в голове, без REPL. Порядок печати — в опросе.
Python Quiz
Что выведет этот код с lazy import в Python 3.15? В 3.15 beta 4 подвезли lazy import (PEP 810) — модуль реально не грузится, пока не тронешь его атрибут. Звучит как мелочь, а ломает интуицию с ходу. Взял классику: import this печатает дзен прямо при загрузке…
В каком порядке напечатается вывод?
Final Results
100%
start → bound → zen → end
0%
zen → start → bound → end
0%
start → zen → bound → end
0%
start → bound → end, zen не печатается
В Django чужая сессия могла прилететь вам в общем кэше
Django тихо чинит баг, из-за которого чужая сессионная кука могла закэшироваться и уйти следующему юзеру.
Дальше классика cache poisoning: если перед Django стоит Redis, Memcached или CDN — следующий, кто попал в тот же ключ кэша, мог получить в ответе чужую сессию.
Бесит не сама дыра, а то, как она написана — условие «если у запроса нет X» почти всегда придумано под один тестовый сценарий, а не под реальный трафик, где у половины пользователей уже висит кука с языком интерфейса или темой.
Пофиксили в 6.0.7 и 5.2.16 (заодно и в 6.1-бете), CVE-2026-48588, severity формально low — нужны shared cache и
Если у вас
Django тихо чинит баг, из-за которого чужая сессионная кука могла закэшироваться и уйти следующему юзеру.
UpdateCacheMiddleware и cache_page() пропускали ответ с Set-Cookie в кэш, если проверяли только один случай: запрос пришёл вообще без кук. Логика была «нет кук на входе — значит и Set-Cookie можно смело кэшировать». Стоило браузеру принести любую левую куку — тему, язык, A/B-флаг — и проверка молча выключалась. Сессионный Set-Cookie улетал в общий кэш как ни в чём не бывало.Дальше классика cache poisoning: если перед Django стоит Redis, Memcached или CDN — следующий, кто попал в тот же ключ кэша, мог получить в ответе чужую сессию.
Бесит не сама дыра, а то, как она написана — условие «если у запроса нет X» почти всегда придумано под один тестовый сценарий, а не под реальный трафик, где у половины пользователей уже висит кука с языком интерфейса или темой.
Пофиксили в 6.0.7 и 5.2.16 (заодно и в 6.1-бете), CVE-2026-48588, severity формально low — нужны shared cache и
Vary: Cookie вместе. Но именно так у многих и настроено.Если у вас
cache_page или UpdateCacheMiddleware рядом с сессиями — это тот случай, когда апдейт не терпит «на следующем спринте».Python откатил архитектуру сборщика мусора прямо в патч-релизе
Python 3.14.0 в октябре сменил сборщик мусора — с generational на incremental, обещали паузы на больших кучах короче на порядок. В 3.14.5 в мае это просто откатили назад. Патч-релиз отменяет архитектурное решение целого мажора — в CPython такое почти не бывает.
Что пошло не так: на долгоживущих процессах (веб-серверы, пайплайны) резидентная память росла без остановки. По разбору pydevtools, счётчик инкрементальной работы мог уходить в минус — и полный проход сборщика попросту не запускался: в одном из кейсов первый full collection случился только на 20 000-й итерации, а в устойчивом состоянии в памяти висело больше 90 тысяч непрочищенных циклов.
Core team не стала ждать плановый 3.14.6 — ускорили релиз и откатили incremental GC сразу в 3.14 и 3.15, вернув generational из 3.13.
Смущает не сам баг — memory-менеджмент штука тонкая. Смущает то, что фичу пять месяцев гоняли через альфы, беты и rc — и всё равно поймали только когда реальный прод начал жаловаться на RSS. Если вы успели обновиться до 3.14.0–3.14.4 и мониторили память — вы только что бесплатно побетатестили GC для всего коммьюнити.
🔗 discuss.python.org, pydevtools.com
Python 3.14.0 в октябре сменил сборщик мусора — с generational на incremental, обещали паузы на больших кучах короче на порядок. В 3.14.5 в мае это просто откатили назад. Патч-релиз отменяет архитектурное решение целого мажора — в CPython такое почти не бывает.
Что пошло не так: на долгоживущих процессах (веб-серверы, пайплайны) резидентная память росла без остановки. По разбору pydevtools, счётчик инкрементальной работы мог уходить в минус — и полный проход сборщика попросту не запускался: в одном из кейсов первый full collection случился только на 20 000-й итерации, а в устойчивом состоянии в памяти висело больше 90 тысяч непрочищенных циклов.
Core team не стала ждать плановый 3.14.6 — ускорили релиз и откатили incremental GC сразу в 3.14 и 3.15, вернув generational из 3.13.
Смущает не сам баг — memory-менеджмент штука тонкая. Смущает то, что фичу пять месяцев гоняли через альфы, беты и rc — и всё равно поймали только когда реальный прод начал жаловаться на RSS. Если вы успели обновиться до 3.14.0–3.14.4 и мониторили память — вы только что бесплатно побетатестили GC для всего коммьюнити.
🔗 discuss.python.org, pydevtools.com
Discussions on Python.org
Reverting the incremental GC in Python 3.14 and 3.15
Python 3.14 shipped with a new incremental garbage collector. However, we’ve had a number of reports of significant memory pressure in production environments. We’ve decided to revert it in both 3.14 and 3.15, and go back to the generational GC from 3.13.…
Гитхаб был чистый. Пакет — нет
В mrmustard 0.7.4 — квантовой библиотеке Xanadu на PyPI — три дня назад нашли стилер. Тащит с диска SSH-ключи, AWS- и Kubernetes-креды и ставит три способа зацепиться в системе на будущее.
Но бесит не сам стилер, а то, как его спрятали.
У версии 0.7.4 нет ни тега, ни релиза, ни коммита в GitHub-репозитории. Открываешь исходники на гитхабе — там всё чисто, ревью ничего не найдёт. Вредонос добавили только в артефакт, который улетает через
Отдельная деталь для тех, кто вообще думает про такие атаки: пейлоад сначала проверяет, что он не в CI и не в контейнере, и только потом стартует. Целились именно в ноутбуки разрабов и исследователей, а не в одноразовые раннеры.
После такого фраза «да я гитхаб пролистал, там нормально» перестаёт что-либо значить. Гитхаб и то, что реально прилетает по
Нашёл всё не Xanadu, а сторонний исследователь из Aikido Security. PyPI пакет после этого отправил в карантин.
🔗 stepsecurity.io, safedep.io
В mrmustard 0.7.4 — квантовой библиотеке Xanadu на PyPI — три дня назад нашли стилер. Тащит с диска SSH-ключи, AWS- и Kubernetes-креды и ставит три способа зацепиться в системе на будущее.
Но бесит не сам стилер, а то, как его спрятали.
У версии 0.7.4 нет ни тега, ни релиза, ни коммита в GitHub-репозитории. Открываешь исходники на гитхабе — там всё чисто, ревью ничего не найдёт. Вредонос добавили только в артефакт, который улетает через
pip install: угнали токен CI из аккаунта мейнтейнера (это был ziofil, автор проекта) и залили пакет в PyPI напрямую, мимо обычного пайплайна.Отдельная деталь для тех, кто вообще думает про такие атаки: пейлоад сначала проверяет, что он не в CI и не в контейнере, и только потом стартует. Целились именно в ноутбуки разрабов и исследователей, а не в одноразовые раннеры.
После такого фраза «да я гитхаб пролистал, там нормально» перестаёт что-либо значить. Гитхаб и то, что реально прилетает по
pip install, — два разных артефакта, и связывает их только честность мейнтейнера в момент публикации. Если пиньте пакеты по хэшу wheel — вот ровно тот случай, когда это спасает, а не паранойя.Нашёл всё не Xanadu, а сторонний исследователь из Aikido Security. PyPI пакет после этого отправил в карантин.
🔗 stepsecurity.io, safedep.io
www.stepsecurity.io
Compromised PyPI Package: mrmustard 0.7.4 Steals SSH, Cloud, and Kubernetes Credentials - StepSecurity
mrmustard 0.7.4 on PyPI was a credential stealer that ran on import, exfiltrating SSH keys, AWS, and Kubernetes credentials. Here is the analysis, IOCs, and how to respond.
PyPI перестал пускать в старые релизы
Запушил докрутку — забытое wheel под 3.14, например — в релиз, которому две недели? С 22 июля PyPI такое просто не примет.
Правило простое: через 14 дней после публикации релиз закрывается для новых файлов насовсем, без исключений. Тема всплывала ещё в PEP 740 в 2024-м, но реально завелась в марте — после того как через скомпрометированные токены и воркфлоу закинули мусор в LiteLLM и Telnyx. Старые доверенные релизы — идеальная мишень: их качают привычно, без опаски.
Перед тем как включать, проверили, насколько больно это ударит по обычным майнтейнерам: из топ-15k пакетов только 56 хоть раз добавляли cp314-колесо релизу старше двух недель. Почти никто так не работает — а вот атакующему такая лазейка была подарком.
Шероховатость: официального способа проверить статус релиза («закрыт/не закрыт») пока нет — узнаёшь только по 403 при аплоаде. Мелочь, но для CI, который доливает артефакт постфактум, это неприятный сюрприз.
🔗 blog.pypi.org
Запушил докрутку — забытое wheel под 3.14, например — в релиз, которому две недели? С 22 июля PyPI такое просто не примет.
Правило простое: через 14 дней после публикации релиз закрывается для новых файлов насовсем, без исключений. Тема всплывала ещё в PEP 740 в 2024-м, но реально завелась в марте — после того как через скомпрометированные токены и воркфлоу закинули мусор в LiteLLM и Telnyx. Старые доверенные релизы — идеальная мишень: их качают привычно, без опаски.
Перед тем как включать, проверили, насколько больно это ударит по обычным майнтейнерам: из топ-15k пакетов только 56 хоть раз добавляли cp314-колесо релизу старше двух недель. Почти никто так не работает — а вот атакующему такая лазейка была подарком.
Шероховатость: официального способа проверить статус релиза («закрыт/не закрыт») пока нет — узнаёшь только по 403 при аплоаде. Мелочь, но для CI, который доливает артефакт постфактум, это неприятный сюрприз.
🔗 blog.pypi.org
blog.pypi.org
Releases now reject new files after 14 days - The Python Package Index Blog
PyPI no longer allows publishing new files to releases older than 14 days.
uv наконец умеет проверять типы точечно, а не всей монорепой разом
Пока весь техтвиттер спорит про JIT и Rust в CPython, Astral тихо прокачивает uv в сторону монорепо.
23 июля вышел uv 0.11.32 — добавили
До этого патча
Флаг мелкий, но по нему хорошо видно курс: после покупки Astral в марте OpenAI явно не делает из uv просто быстрый pip — это заявка на единый вход в lint/format/typecheck. Направление мне нравится: меньше
Минус один:
🔗 github.com, github.com
Пока весь техтвиттер спорит про JIT и Rust в CPython, Astral тихо прокачивает uv в сторону монорепо.
23 июля вышел uv 0.11.32 — добавили
--package и --all-packages для uv check. Сама команда check появилась только в июне: она гоняет ty, тайп-чекер Astral, прямо из uv, без отдельного pip install ty.До этого патча
uv check в воркспейсе с десятком пакетов проверял всё разом — падает один сервис, и непонятно, на что смотреть в первую очередь. Теперь можно натравить проверку на конкретный пакет флагом --package, а --all-packages явно просит пройтись по всем.Флаг мелкий, но по нему хорошо видно курс: после покупки Astral в марте OpenAI явно не делает из uv просто быстрый pip — это заявка на единый вход в lint/format/typecheck. Направление мне нравится: меньше
pip install ruff mypy black в каждом новом проекте.Минус один:
check всё ещё за preview-флагом, синтаксис может поменяться до стабильного релиза — тащить в CI прямо сейчас я бы не спешил.🔗 github.com, github.com
GitHub
Release 0.11.32 · astral-sh/uv
Release Notes
Released on 2026-07-23.
Preview features
Add --package and --all-packages selection to uv check (#20628)
Allow uv upgrade to update multiple marker-specific declarations of the same ...
Released on 2026-07-23.
Preview features
Add --package and --all-packages selection to uv check (#20628)
Allow uv upgrade to update multiple marker-specific declarations of the same ...
object() как сентинел годами тихо ломался в pickle — и почти никто не замечал
Сколько раз ты писал
В Python 3.15 завезли builtin
Мелочь, а сколько самодельных
🔗 peps.python.org
Сколько раз ты писал
MISSING = object() для дефолта, который надо отличить от None? Я — постоянно. И не знал, что если такой сентинел уедет через pickle (сессии, кэш, multiprocessing, Celery) — на другом конце restored is MISSING вернёт False. Тихий баг, всплывающий только в проде, когда объект пересекает границу процесса.В Python 3.15 завезли builtin
sentinel() (PEP 661). Он запоминает модуль и имя, поэтому pickle и copy.deepcopy восстанавливают тот же объект, а не подделку. Плюс вменяемый repr из коробки — никаких <object object at 0x7f...> в логах.Мелочь, а сколько самодельных
class _Missing: pass теперь можно выкинуть.🔗 peps.python.org
В Python 3.15 завезли нормальный сэмплирующий профайлер
Полгода таскал
Новый модуль
Частота по умолчанию 1кГц, можно гнать хоть до 1МГц. На выходе — flamegraph, pstats или html, на выбор. Профайлер и целевой процесс должны быть на одной минорной версии — из 3.14 к процессу на 3.15 не приаттачиться.
Заодно
🔗 peps.python.org, docs.python.org
Полгода таскал
py-spy в докер-образ, потому что сэмплирующего профайлера в stdlib не было — только cProfile, который считает каждый вызов и заметно тормозит прод. В 3.15 это закрыли.Новый модуль
profiling.sampling (кодовое имя Tachyon, PEP 799) цепляется к живому процессу по PID и читает стек снаружи — без инструментирования кода и без рестарта:python -m profiling.sampling attach 12345Частота по умолчанию 1кГц, можно гнать хоть до 1МГц. На выходе — flamegraph, pstats или html, на выбор. Профайлер и целевой процесс должны быть на одной минорной версии — из 3.14 к процессу на 3.15 не приаттачиться.
Заодно
cProfile переехал в profiling.tracing (алиас остался жить), а древний модуль profile объявили deprecated — выпилят в 3.17.py-spy из докерфайла выкидываю на следующем спринте: не вижу смысла тащить внешний бинарник, когда то же самое теперь есть из коробки.🔗 peps.python.org, docs.python.org
Python Enhancement Proposals (PEPs)
PEP 799 – A dedicated profiling package for organizing Python profiling tools | peps.python.org
This PEP proposes the creation of a new standard library module named profiling to organize Python’s built-in profiling tools under a single, coherent namespace.
До Python 3.15 осталось 66 дней
Открыл вчера changelog beta 4 — и это последняя бета. Дальше только релиз-кандидаты.
7 мая зафиксировали фичи (PEP 790) — с тех пор в 3.15 можно только чинить баги, нового уже не прилетит. 18 июля вышла b4: ~298 фиксов с прошлой беты, и всё, бета-цикл закрыт.
Сегодня мы ровно между b4 и rc1 — до октябрьского релиза 66 дней. Если у вас в проекте есть код под
🔗 blog.python.org, peps.python.org
Открыл вчера changelog beta 4 — и это последняя бета. Дальше только релиз-кандидаты.
7 мая зафиксировали фичи (PEP 790) — с тех пор в 3.15 можно только чинить баги, нового уже не прилетит. 18 июля вышла b4: ~298 фиксов с прошлой беты, и всё, бета-цикл закрыт.
Сегодня мы ровно между b4 и rc1 — до октябрьского релиза 66 дней. Если у вас в проекте есть код под
sys.version_info >= (3, 15) — самое время гонять его на бете, а не ждать октября: после rc1 (4 августа) ABI и API стараются больше не трогать.🔗 blog.python.org, peps.python.org
Последние дни ковырял тестирование AI-генерации в Vaulto Cards.
Само расширение довольно простое: выделяешь слово или фразу в браузере, и оно превращается в учебную карточку. Недавно я добавил библиотеку карточек и режим обучения, поэтому генератор стал заметно сложнее.
И появилась проблема: после каждой правки нужно было вручную открывать расширение, создавать карточки и смотреть, не стало ли хуже.
В итоге я вынес генерацию в отдельный Node.js-скрипт. Он запускает тот же пайплайн, что используется в расширении, только без интерфейса, а результат сохраняет в JSON и картинки.
Так довольно быстро нашлись странные ошибки. Например, целое предложение иногда обрабатывалось как одно случайное слово, а фраза
Пришлось явно разделить режимы
Ещё отдельно описал весь запуск в
Теперь, когда я открываю новую сессию Claude Code, мне не нужно каждый раз объяснять, как про
Само расширение довольно простое: выделяешь слово или фразу в браузере, и оно превращается в учебную карточку. Недавно я добавил библиотеку карточек и режим обучения, поэтому генератор стал заметно сложнее.
И появилась проблема: после каждой правки нужно было вручную открывать расширение, создавать карточки и смотреть, не стало ли хуже.
В итоге я вынес генерацию в отдельный Node.js-скрипт. Он запускает тот же пайплайн, что используется в расширении, только без интерфейса, а результат сохраняет в JSON и картинки.
Так довольно быстро нашлись странные ошибки. Например, целое предложение иногда обрабатывалось как одно случайное слово, а фраза
el gato определялась просто как артикль.Пришлось явно разделить режимы
WORD и SENTENCE и добавить очистку входных данных.Ещё отдельно описал весь запуск в
TESTING_AI_CARDS.md и добавил ссылку в CLAUDE.md.Теперь, когда я открываю новую сессию Claude Code, мне не нужно каждый раз объяснять, как про
У pip, uv и Poetry впервые будет общий выборный начальник
У pip, uv, Poetry и вообще всего Python-пакеджинга до сегодняшнего дня не было ни одного выборного органа — решения по интероп-спекам (wheel, PEP 440 и остальные) принимала неформальная PyPA, группа мейнтейнеров без единого мандата от комьюнити.
Как объявили в blog.python.org, сегодня в 14:00 UTC стартовали номинации сразу в новый Packaging Council (PEP 772, утверждён в апреле) и в PSF Board — окно до 11 августа, голосование 1–15 сентября.
Мест пять: топ-2 по голосам — два года (когорта A), следующие три — год (когорта B). Дальше когорты ротируются по очереди, чтобы совет не менялся весь разом.
Спорный PEP уровня будущего wheel v2 теперь будет решать голосование пятерых выборных, а не один решительный мейнтейнер, который раньше просто брал и делал. Медленнее, зато без личных вето — для стандартов, на которых держится весь пакеджинг, по-моему разумный обмен.
🔗 blog.python.org, blog.python.org, peps.python.org
У pip, uv, Poetry и вообще всего Python-пакеджинга до сегодняшнего дня не было ни одного выборного органа — решения по интероп-спекам (wheel, PEP 440 и остальные) принимала неформальная PyPA, группа мейнтейнеров без единого мандата от комьюнити.
Как объявили в blog.python.org, сегодня в 14:00 UTC стартовали номинации сразу в новый Packaging Council (PEP 772, утверждён в апреле) и в PSF Board — окно до 11 августа, голосование 1–15 сентября.
Мест пять: топ-2 по голосам — два года (когорта A), следующие три — год (когорта B). Дальше когорты ротируются по очереди, чтобы совет не менялся весь разом.
Спорный PEP уровня будущего wheel v2 теперь будет решать голосование пятерых выборных, а не один решительный мейнтейнер, который раньше просто брал и делал. Медленнее, зато без личных вето — для стандартов, на которых держится весь пакеджинг, по-моему разумный обмен.
🔗 blog.python.org, blog.python.org, peps.python.org
GIL уходит поэтапно — и по цифрам это заметно
Три фазы у free-threaded CPython, и по цифрам видно, что вторая — не косметика.
Phase I (3.13, октябрь 2024): экспериментальный билд, adaptive-интерпретатор выключен ради безопасности — минус 40% на single-thread коде. Многие тогда попробовали, увидели просадку и закрыли тему для себя.
Phase II (3.14, сейчас): PEP 779 приняли 16 июня 2025-го, статус — официально поддерживается, но не по умолчанию. Adaptive-интерпретатор вернули, просадка упала до 1% на macOS aarch64 и максимум 8% на x86-64 Linux.
Phase III — билд без GIL по умолчанию — пока просто пустая графа в PEP 779: критериев для неё авторы сознательно не написали. Ни PEP, ни даты — Steering Council решила сперва пожить с двумя билдами и посмотреть, что покажет прод.
🔗 peps.python.org, docs.python.org
Три фазы у free-threaded CPython, и по цифрам видно, что вторая — не косметика.
Phase I (3.13, октябрь 2024): экспериментальный билд, adaptive-интерпретатор выключен ради безопасности — минус 40% на single-thread коде. Многие тогда попробовали, увидели просадку и закрыли тему для себя.
Phase II (3.14, сейчас): PEP 779 приняли 16 июня 2025-го, статус — официально поддерживается, но не по умолчанию. Adaptive-интерпретатор вернули, просадка упала до 1% на macOS aarch64 и максимум 8% на x86-64 Linux.
Phase III — билд без GIL по умолчанию — пока просто пустая графа в PEP 779: критериев для неё авторы сознательно не написали. Ни PEP, ни даты — Steering Council решила сперва пожить с двумя билдами и посмотреть, что покажет прод.
🔗 peps.python.org, docs.python.org
Один Host-заголовок обходил защиту в каждом FastAPI
Пересчитал даты в advisory — между «нашли дыру» и «патч в релизе» прошло почти четыре месяца.
27 января X41 D-Sec наткнулись на баг, когда по заказу OSTIF гоняли аудит vLLM. Причина глубже: в Starlette
Мейнтейнеров уведомили 4 февраля, патч предложили 1 марта, а зашили в релиз только 21 мая — Starlette 1.0.1. Раскрыли на следующий день.
Starlette — подложка под FastAPI, vLLM, LiteLLM, 325 млн скачиваний в неделю. CVSS у мейнтейнера 6.5, у X41 — 7.0, и это не формальность: чем чаще access-контроль держится на пути запроса, а не на честной аутентификации, тем больнее такая дыра.
Если у вас FastAPI и Starlette не трогали с весны — гляньте версию.
🔗 github.com, ostif.org, badhost.org
Пересчитал даты в advisory — между «нашли дыру» и «патч в релизе» прошло почти четыре месяца.
27 января X41 D-Sec наткнулись на баг, когда по заказу OSTIF гоняли аудит vLLM. Причина глубже: в Starlette
request.url собирали из заголовка Host без проверки, а роутинг при этом смотрел на сырой путь из scope. Подсунул кривой Host — и request.url.path, на который завязаны миддлвари с проверками доступа, начинает врать.Мейнтейнеров уведомили 4 февраля, патч предложили 1 марта, а зашили в релиз только 21 мая — Starlette 1.0.1. Раскрыли на следующий день.
Starlette — подложка под FastAPI, vLLM, LiteLLM, 325 млн скачиваний в неделю. CVSS у мейнтейнера 6.5, у X41 — 7.0, и это не формальность: чем чаще access-контроль держится на пути запроса, а не на честной аутентификации, тем больнее такая дыра.
Если у вас FastAPI и Starlette не трогали с весны — гляньте версию.
🔗 github.com, ostif.org, badhost.org
Один релиз Pillow закрыл четыре дыры разом
Проверил
12.3.0 вышла ещё 1 июля, но CVE на самый неприятный баг из четырёх — EPS-парсер уходит в бесконечный цикл на отрицательном byte count в
В том же релизе тихо закрыли ещё три штуки: PDF без лимита на декомпрессию (классический zip bomb), shell-инъекцию через
Если Pillow где-то в проекте парсит файлы от пользователей — это апдейт на сегодня, а не «когда-нибудь занесу в спринт».
🔗 github.com, github.com
Проверил
pip show pillow в паре своих проектов — из них не все жили на актуальной версии.12.3.0 вышла ещё 1 июля, но CVE на самый неприятный баг из четырёх — EPS-парсер уходит в бесконечный цикл на отрицательном byte count в
%%BeginBinary — раскрыли только 14-го, и это до сих пор мало где обсуждали.В том же релизе тихо закрыли ещё три штуки: PDF без лимита на декомпрессию (классический zip bomb), shell-инъекцию через
ImageShow.WindowsViewer, если путь к файлу не свой, и утечку памяти на специально собранном JPEG2000.Если Pillow где-то в проекте парсит файлы от пользователей — это апдейт на сегодня, а не «когда-нибудь занесу в спринт».
🔗 github.com, github.com
Ruff одним патчем увеличил число правил в 7 раз
59 → 413. Именно так вырос дефолтный набор правил в Ruff 0.16.0, который вышел 23 июля.
С версии 0.1.0 в линтере накопилось 260+ новых правил — но по умолчанию их не включали, боялись сломать людям CI. Тут решились: заодно выпилили 18 самых холиварных pycodestyle/pyflakes-правил вроде E731 и F403 — слишком спорные, чтобы навязывать их всем.
Саймон Уиллисон прогнал релиз по своим проектам — и в sqlite-utils нашлось 1618 новых замечаний на коде, который днём раньше проходил линт чисто.
Откатить старое поведение:
🔗 astral.sh, simonwillison.net, github.com
59 → 413. Именно так вырос дефолтный набор правил в Ruff 0.16.0, который вышел 23 июля.
С версии 0.1.0 в линтере накопилось 260+ новых правил — но по умолчанию их не включали, боялись сломать людям CI. Тут решились: заодно выпилили 18 самых холиварных pycodestyle/pyflakes-правил вроде E731 и F403 — слишком спорные, чтобы навязывать их всем.
Саймон Уиллисон прогнал релиз по своим проектам — и в sqlite-utils нашлось 1618 новых замечаний на коде, который днём раньше проходил линт чисто.
Откатить старое поведение:
select = ["E4", "E7", "E9", "F"] в конфиге.🔗 astral.sh, simonwillison.net, github.com