Enum ограничивает состояния, но не проверяет переходы
Статус
В разборе Enum отдельно рассматривают значения для сериализации и имена членов.
Но наличие статусов NEW и PAID не запрещает переход обратно. Разрешённые переходы нужно описать отдельно, например в методе объекта или таблице правил.
Если значения уходят в API или базу, выбирайте их явно. Переименование элемента перечисления и изменение внешнего строкового значения могут иметь разные последствия для совместимости.
#python #архитектура
Статус
"paied" — допустимая строка. Enum позволяет проверить значение на границе приложения:from enum import Enum
class Status(Enum):
NEW = "new"
PAID = "paid"
print(Status("paid") is Status.PAID) # True
# Status("paied") вызовет ValueError
В разборе Enum отдельно рассматривают значения для сериализации и имена членов.
Status("paid") ищет по значению, а Status["PAID"] — по имени.Но наличие статусов NEW и PAID не запрещает переход обратно. Разрешённые переходы нужно описать отдельно, например в методе объекта или таблице правил.
Если значения уходят в API или базу, выбирайте их явно. Переименование элемента перечисления и изменение внешнего строкового значения могут иметь разные последствия для совместимости.
#python #архитектура
❤2
После GIL: почему одних потоков недостаточно
Убрать общую блокировку — не значит убрать гонки данных. Если несколько потоков меняют общие объекты, приложению по-прежнему нужны правила доступа.
На Python Language Summit обсуждали модель BOC: задачи заранее объявляют, какие защищённые данные им нужны, а планировщик координирует выполнение. Идея — перенести часть работы с блокировками из прикладного кода в механизм запуска задач.
Прототип bocpy использует отдельные интерпретаторы. Его уже можно исследовать, но полноценное владение объектами потребует изменений среды выполнения. Авторы также отмечают цену обмена данными.
Это исследовательское предложение, а не новая гарантия стандартного Python. Для рабочего приложения пока нужно явно выбирать модель параллельности и проверять совместное использование изменяемых объектов.
#python #параллельность
Убрать общую блокировку — не значит убрать гонки данных. Если несколько потоков меняют общие объекты, приложению по-прежнему нужны правила доступа.
На Python Language Summit обсуждали модель BOC: задачи заранее объявляют, какие защищённые данные им нужны, а планировщик координирует выполнение. Идея — перенести часть работы с блокировками из прикладного кода в механизм запуска задач.
Прототип bocpy использует отдельные интерпретаторы. Его уже можно исследовать, но полноценное владение объектами потребует изменений среды выполнения. Авторы также отмечают цену обмена данными.
Это исследовательское предложение, а не новая гарантия стандартного Python. Для рабочего приложения пока нужно явно выбирать модель параллельности и проверять совместное использование изменяемых объектов.
#python #параллельность
Как дать помощнику контекст ошибки из Logfire
Помощник видит код репозитория, но не знает, какой запрос завершился ошибкой и сколько времени заняла база. Без телеметрии он может уверенно искать причину не в том месте.
В разборе Logfire MCP показывают, как передать клиенту MCP доступ к трассам, логам и метрикам. Помощник может запросить данные через SQL, сопоставить ошибку с обработчиком и проверить гипотезу на реальном выполнении.
Начать расследование лучше с конкретного сервиса, интервала времени и проблемного запроса. Так проще получить проверяемый ответ и ограничить объём данных.
Права нужно выбирать по задаче: сервер предоставляет инструменты не только для запросов, но и для управления объектами мониторинга. Доступ к просмотру телеметрии сам по себе не требует разрешать изменения алертов или настроек.
#python #отладка
Помощник видит код репозитория, но не знает, какой запрос завершился ошибкой и сколько времени заняла база. Без телеметрии он может уверенно искать причину не в том месте.
В разборе Logfire MCP показывают, как передать клиенту MCP доступ к трассам, логам и метрикам. Помощник может запросить данные через SQL, сопоставить ошибку с обработчиком и проверить гипотезу на реальном выполнении.
Начать расследование лучше с конкретного сервиса, интервала времени и проблемного запроса. Так проще получить проверяемый ответ и ограничить объём данных.
Права нужно выбирать по задаче: сервер предоставляет инструменты не только для запросов, но и для управления объектами мониторинга. Доступ к просмотру телеметрии сам по себе не требует разрешать изменения алертов или настроек.
#python #отладка
Python 3.16 alpha: что уже может проверить автор библиотеки
Первая альфа Python 3.16 вышла 13 октября. Набор возможностей ещё меняется, но ждать финального выпуска для первой проверки совместимости необязательно.
В анонсе разработчики предлагают запускать библиотеки и приложения на предварительной версии и сообщать об ошибках CPython.
Для библиотеки полезно проверить установку, импорт, тесты и сборку расширений. Если установка не удалась, отделите несовместимость своего кода от отсутствия готовых сборок зависимостей.
Такую проверку можно добавить отдельным заданием CI, сохранив основную матрицу поддерживаемых версий. Сбой предварительной версии нужно разобрать, а не автоматически считать регрессией библиотеки.
Это ранний выпуск для тестирования. Перенос рабочего сервиса на него не требуется; финальный Python 3.16 запланирован на октябрь 2027 года.
#python #тестирование
Первая альфа Python 3.16 вышла 13 октября. Набор возможностей ещё меняется, но ждать финального выпуска для первой проверки совместимости необязательно.
В анонсе разработчики предлагают запускать библиотеки и приложения на предварительной версии и сообщать об ошибках CPython.
Для библиотеки полезно проверить установку, импорт, тесты и сборку расширений. Если установка не удалась, отделите несовместимость своего кода от отсутствия готовых сборок зависимостей.
Такую проверку можно добавить отдельным заданием CI, сохранив основную матрицу поддерживаемых версий. Сбой предварительной версии нужно разобрать, а не автоматически считать регрессией библиотеки.
Это ранний выпуск для тестирования. Перенос рабочего сервиса на него не требуется; финальный Python 3.16 запланирован на октябрь 2027 года.
#python #тестирование
Как найти медленную функцию новым профилировщиком Tachyon
Приложение тормозит, но непонятно, где оно проводит время. В Python 3.15 появился статистический профилировщик
В разборе Astral показывают запуск через uv:
Профилировщик периодически снимает состояние выполнения. Граф помогает найти участки, которые часто попадают в выборку, и выбрать место для дальнейшего исследования.
Число выборок не равно точному числу вызовов. А изменение короткой функции не обязательно ускорит весь сценарий.
После правки повторите тот же замер с теми же данными и отдельно сравните полное время работы. Авторское ускорение на одном примере нельзя переносить на любое приложение.
#python #производительность
Приложение тормозит, но непонятно, где оно проводит время. В Python 3.15 появился статистический профилировщик
profiling.sampling, известный как Tachyon.В разборе Astral показывают запуск через uv:
uv run --python 3.15 -m profiling.sampling run --flamegraph --browser app.py
Профилировщик периодически снимает состояние выполнения. Граф помогает найти участки, которые часто попадают в выборку, и выбрать место для дальнейшего исследования.
Число выборок не равно точному числу вызовов. А изменение короткой функции не обязательно ускорит весь сценарий.
После правки повторите тот же замер с теми же данными и отдельно сравните полное время работы. Авторское ускорение на одном примере нельзя переносить на любое приложение.
#python #производительность
❤2
Почему обновления Django важны даже без SQL-инъекций
Запрос может вредить серверу, просто заставляя его тратить слишком много памяти или процессорного времени на разбор данных.
В обновлении безопасности Django от 6 октября исправили несколько таких сценариев. Один связан с кешированием множества длинных языковых кодов, другой — с квадратичной сложностью разбора параметров HTTP-заголовка.
Исправления вошли в 6.1.2, 6.0.9 и 5.2.18. Обновляться нужно до актуального исправленного выпуска своей поддерживаемой ветки.
После обновления проверьте обработку необычных заголовков: внутри парсера изменился механизм разбора, поэтому некоторые некорректные значения могут обрабатываться иначе.
Общий урок для своего кода: ограничивать размер входа до дорогой обработки и помещения в кеш. Даже полезный кеш становится проблемой, если ключи бесконтрольно задаёт внешний запрос.
#python #django
Запрос может вредить серверу, просто заставляя его тратить слишком много памяти или процессорного времени на разбор данных.
В обновлении безопасности Django от 6 октября исправили несколько таких сценариев. Один связан с кешированием множества длинных языковых кодов, другой — с квадратичной сложностью разбора параметров HTTP-заголовка.
Исправления вошли в 6.1.2, 6.0.9 и 5.2.18. Обновляться нужно до актуального исправленного выпуска своей поддерживаемой ветки.
После обновления проверьте обработку необычных заголовков: внутри парсера изменился механизм разбора, поэтому некоторые некорректные значения могут обрабатываться иначе.
Общий урок для своего кода: ограничивать размер входа до дорогой обработки и помещения в кеш. Даже полезный кеш становится проблемой, если ключи бесконтрольно задаёт внешний запрос.
#python #django
ExitStack: закрываем ресурсы в обратном порядке
Список файлов приходит из конфигурации. Их может быть два, а может двадцать. Вкладывать один
Для этого есть
В тот же стек можно добавить обычную функцию очистки через
Список файлов приходит из конфигурации. Их может быть два, а может двадцать. Вкладывать один
with в другой неудобно, а при ошибке на пятом файле первые четыре всё равно нужно закрыть.Для этого есть
contextlib.ExitStack. Внутри with ExitStack() as stack вызывайте stack.enter_context(open(path)) для каждого пути. Метод вернёт открытый файл и зарегистрирует его выход из контекста. Если следующий open завершится ошибкой, уже открытые файлы будут закрыты в обратном порядке.В тот же стек можно добавить обычную функцию очистки через
stack.callback. Она тоже выполнится при выходе, но подавить исключение не сможет. В документации ExitStack есть важная граница: сборка мусора сама по себе очистку не запускает. Управляйте сроком жизни стека через with или явно вызывайте close().Зелёный CI с устаревшим lock-файлом
Вы добавили зависимость в
Чтобы заметить такое расхождение, нужен
«Актуальный» здесь означает согласованный с метаданными проекта. Выход новой версии пакета на PyPI сам по себе не делает lock-файл устаревшим. А
Вы добавили зависимость в
pyproject.toml, а обновлённый uv.lock забыли закоммитить. Флаг --frozen может показаться строгой проверкой, но у него другой контракт: использовать существующий lock-файл, не проверяя его соответствие проекту.Чтобы заметить такое расхождение, нужен
--locked. По документации uv, команда завершится ошибкой, если lock-файл требует обновления. Например, uv sync --locked проверит его перед синхронизацией окружения. Отдельная проверка без установки зависимостей: uv lock --check.«Актуальный» здесь означает согласованный с метаданными проекта. Выход новой версии пакета на PyPI сам по себе не делает lock-файл устаревшим. А
--no-sync решает третью задачу: отключает проверку и обновление окружения перед запуском. Эти флаги отвечают за разные условия воспроизводимости.Forwarded from Нейроканал
На PyPI снова нашли заражённый LiteLLM, популярный шлюз к API разных LLM: версия 1.107.0 провисела около двух часов и ставила стилер. Он срабатывает при старте любого Python-процесса в окружении, даже если litellm никто не импортирует. Заражены были и Docker-образы с тегами latest, main-latest и main-stable. Сейчас версия снята с PyPI, а BerriAI подтвердила удаление образов.
Стилер забирает SSH-ключи, доступы к AWS, GCP, Azure и Kubernetes, пароли из браузеров, секреты CI, токены Claude Code, Cursor, Codex и других ИИ-инструментов, а при доступном
В марте проект уже взламывали через украденные учётки публикации, у нынешней атаки другие код и инфраструктура, связь между ними не установлена. Если ставились wheels 1.107.0 или запускались заражённые образы, доступные им секреты считаются скомпрометированными. До запуска pip из shell удаляют
@neuro_channel
Стилер забирает SSH-ключи, доступы к AWS, GCP, Azure и Kubernetes, пароли из браузеров, секреты CI, токены Claude Code, Cursor, Codex и других ИИ-инструментов, а при доступном
DATABASE_URL пытается выгрузить из базы LiteLLM-прокси ключи провайдеров. На Linux и macOS отдельный демон раз в час готов скачать и выполнить новый код, хотя вторая стадия так и не была замечена. По provenance образов исследователи Upwind нашли, что релиз собрал официальный конвейер BerriAI из репозитория-двойника Berri-AI/litellm. Как атакующий это провернул, пока неизвестно.В марте проект уже взламывали через украденные учётки публикации, у нынешней атаки другие код и инфраструктура, связь между ними не установлена. Если ставились wheels 1.107.0 или запускались заражённые образы, доступные им секреты считаются скомпрометированными. До запуска pip из shell удаляют
cook.pth, cook.py, sitecustomize.py и их файлы в __pycache__, останавливают фоновый Python-демон, пересобирают окружения с litellm==1.106.2 и меняют секреты. Индикаторы заражения собраны в issue проекта.@neuro_channel
🤯4
Decimal начинается до первого float
Две почти одинаковые записи дают разное округление. На Python 3.14.4 этот пример выводит сначала
Если вход изначально десятичный, сохраняйте строку до создания
Две почти одинаковые записи дают разное округление. На Python 3.14.4 этот пример выводит сначала
2.68, затем 2.67:from decimal import Decimal, ROUND_HALF_EVEN
cent = Decimal(".01")
print(Decimal("2.675").quantize(cent, rounding=ROUND_HALF_EVEN))
print(Decimal(2.675).quantize(cent, rounding=ROUND_HALF_EVEN))
Decimal из строки получает ровно заданную десятичную дробь. Из float он точно переносит уже существующее двоичное значение, которое чуть меньше 2.675. Конструктор не может восстановить исходное намерение по округлённому представлению числа.Если вход изначально десятичный, сохраняйте строку до создания
Decimal. Метод quantize задаёт нужный показатель степени, а режим округления выбирайте по правилам расчёта. ROUND_HALF_EVEN в примере округляет точную середину к чётной последней цифре. Это конкретная политика, а не универсальное правило для любых сумм.Задача в очереди, а строки в базе ещё нет
Внутри
В Django 5.2 для такого сценария есть transaction.on_commit. Зарегистрируйте функцию отправки задачи внутри
У этой границы есть предел: база уже закоммичена, когда callback обращается к брокеру. Ошибка отправки не откатит заказ и не гарантирует повторную доставку задачи.
Внутри
transaction.atomic() вы создаёте заказ и сразу отправляете его ID фоновому воркеру. Воркер может успеть обратиться к базе раньше коммита. Или транзакция откатится, а задача уже останется в очереди.В Django 5.2 для такого сценария есть transaction.on_commit. Зарегистрируйте функцию отправки задачи внутри
atomic. Она будет вызвана после успешного коммита, а при откате отброшена. Callback из вложенного блока ждёт внешнего коммита и не выполняется, если произошёл откат к его savepoint. В обычном режиме autocommit без открытой транзакции вызов происходит сразу.У этой границы есть предел: база уже закоммичена, когда callback обращается к брокеру. Ошибка отправки не откатит заказ и не гарантирует повторную доставку задачи.
on_commit устраняет преждевременный запуск, но надёжность передачи между базой и очередью нужно проектировать отдельно.В строке ABA у groupby три группы
Две буквы A не объединятся, потому что между ними стоит B.
Результат:
Есть и ловушка со сроком жизни: итераторы групп используют общий исходный итератор. Если группа понадобится позже, прочитайте её в список до перехода к следующей, как в примере. Эти детали описаны в контракте groupby. Сортировка и сохранённые списки требуют памяти, поэтому для подсчётов по несортированному потоку может лучше подойти словарь.
Две буквы A не объединятся, потому что между ними стоит B.
itertools.groupby начинает новую группу каждый раз, когда меняется ключ соседнего элемента:from itertools import groupby
print([(key, list(group)) for key, group in groupby("ABA")])
Результат:
[('A', ['A']), ('B', ['B']), ('A', ['A'])]. Это удобно для серий одинаковых событий в потоке. Для объединения всех записей с одним ключом данные обычно сначала сортируют по тому же key. Получить поведение SQL GROUP BY одним названием функции не выйдет.Есть и ловушка со сроком жизни: итераторы групп используют общий исходный итератор. Если группа понадобится позже, прочитайте её в список до перехода к следующей, как в примере. Эти детали описаны в контракте groupby. Сортировка и сохранённые списки требуют памяти, поэтому для подсчётов по несортированному потоку может лучше подойти словарь.
❤1
Pydantic может создать модель с неверными данными
Наличие объекта
Метод не отключает вообще всё: значения полей по умолчанию по-прежнему подставляются. Зато
В документации метода его предлагают для уже проверенных или заведомо доверенных данных. Выбирать этот путь только ради скорости тоже рано: в V2 разрыв сократился, а на простых моделях обычная валидация может оказаться быстрее. Прежде чем убрать проверку, измерьте свой сценарий и определите, кто теперь отвечает за корректность вложенных объектов.
Наличие объекта
BaseModel ещё не доказывает, что данные прошли проверку. В Pydantic V2 model_construct() создаёт модель без валидации. Если поле объявлено вложенной моделью, переданный туда словарь сам в неё не превратится.Метод не отключает вообще всё: значения полей по умолчанию по-прежнему подставляются. Зато
extra="forbid" при таком создании не даст привычной ошибки за лишнее поле. Оно будет проигнорировано. Поэтому контракт обычного конструктора нельзя механически переносить на model_construct.В документации метода его предлагают для уже проверенных или заведомо доверенных данных. Выбирать этот путь только ради скорости тоже рано: в V2 разрыв сократился, а на простых моделях обычная валидация может оказаться быстрее. Прежде чем убрать проверку, измерьте свой сценарий и определите, кто теперь отвечает за корректность вложенных объектов.
bind принимает строку в параметр int
Первый вывод:
Так можно разбирать вызовы в декораторе или диспетчере и получать
inspect.Signature.bind проверяет, можно ли разложить аргументы по параметрам функции. Аннотация int при этом не превращается в проверку типа:from inspect import signature
def ship(item: int, *, retries=2):
return item, retries
bound = signature(ship).bind("text")
print(bound.arguments)
bound.apply_defaults()
print(bound.arguments)
Первый вывод:
{'item': 'text'}. Второй добавляет 'retries': 2. bind не вставляет пропущенные значения по умолчанию в arguments, для этого нужен apply_defaults(). Саму ship этот код не вызывает.Так можно разбирать вызовы в декораторе или диспетчере и получать
TypeError при несовместимых аргументах. Но проверку значений нужно организовать отдельно. В документации bind есть и bind_partial, который разрешает пропустить обязательные параметры. Для проверки полного вызова это уже слишком мягкий контракт.