Всем привет, вот и заканчивается лето :(

Мой прошлый дайджест неожиданным образом зашел, а значит - людям такое интересно. В августе было много новых интересных PEP’ов (например, PEP 805: Safe Parallel Python), которые я поревьюил, было много новых релизов, было много новых опенсорс проектов чуваков из нашего сообщества, пару интересных подкастов и множество другого интересного!

С меня как всегда статья без нейрослопа и ИИ, с вас как всегда интересные комментарии и лайки! Но немного нейрослопа я все же добавил в некоторые свои проекты. Но осторожно и с пользой для всех.

Погнали смотреть, что у нас в питоне происходило!


CPython

После долгих споров и обсуждений про наш PEP-841 и синтаксис f{1: 2} для frozendict, я решил сделать небольшую паузу от питона. В опенсорсе важно уметь переключать свое внимение, чтобы не ловить усталось и выгорание.

Потому, единственное, чем я занимался в CPython: ревью и обсуждение PEPов.

PEP 805

Я хочу показать самый интересный из них: PEP 805: Safe Parallel Python. Марк Шенон предлагает сделать ОЧЕНЬ много всего для того, чтобы Free-Threading в CPython наконец начал нормально работать. Он буквально пишет: если мы оставим все как есть сейчас, то Free-Threading будет очень сложно использовать.

В чем суть предложения?

  1. Главная идея PEP’а, что VM питона должна контролировать доступ к объектам из разных потоков. И контролировать корректность такого доступа. Чтобы такого добиться, предлагается добавить довольно много новых частей Python

  2. Как? Самое главное - добавить каждому объекту __shareable__ атрибут: Immutable - которые нельзя менять и можно шарить в рамках ThreadGroup, Local - существующие только в рамках одной ThreadGroup (можно смело мутировать), Protected - можно мутировать с мьютексом, Synchronized - специальный маркер для билтинов (им ненужна внешняя синхронизация, они умеют сами)

  3. Добавить threading.ThreadGroup объекты, по сути - группа тредов, которые вместе работают над какими-то общими данными. Что позволит упростить синхронизацию общих объектов для них

  4. Добавить функции для управления стейтом объектов: freeze(), syncronize()

Пример:

class State:
       def __init__(self, value):
           self.value = value

class Counter:
    def __init__(self):
        self.mutex = Lock() 
        with self.mutex:
            self.number = self.mutex.protect(State(0))
        self.__freeze__()

    def value(self):
        with self.mutex:
            return self.number.value

    def increment(self):
        with self.mutex:
            self.number.value += 1

Как оно работает? Да ктож его знает ?️️

И хоть я оставил всего два мелких замечания, было очень интересно почитать. Скажу честно, что сесть и проанализировать каждый нюанс предложения у меня не было ни времени, ни сил. Но у нас в сообществе есть замечательный @zzzzzzerg, который уделил ПЕПу куда больше внимания. Очень жду его развернутого мнения в комментариях под данной статьей.

Обсуждение: Что вы думаете про PEP-805? Сложно? Или наоборот?

Самый короткий crash в питоне

Попробуйте запустить такое в Python 3.14.0:

__conditional_annotations__ = 0
a: 1

Все упадет. Не с исключением, а с core-dumped. Почему?

Когда в CPython добавляли поддержку ленивых аннотаций в PEP-649, то нужно было как-то поддержать такой код:

>>> import dis
>>> dis.dis('''
... if int():
...     x: int = 0
... else:
...     x: str = ''
... ''')
  --           MAKE_CELL                0 (__conditional_annotations__)

   0           RESUME                   0

   2           LOAD_CONST               1 (<code object __annotate__ at 0x10cfe2710, file "<dis>", line 2>)
               MAKE_FUNCTION
               STORE_NAME               3 (__annotate__)
               BUILD_SET                0
               STORE_NAME               0 (__conditional_annotations__)
               LOAD_NAME                1 (int)
               PUSH_NULL
               CALL                     0
               TO_BOOL
               POP_JUMP_IF_FALSE        9 (to L1)
               NOT_TAKEN

   3           LOAD_SMALL_INT           0
               STORE_NAME               2 (x)
               LOAD_NAME                0 (__conditional_annotations__)
               LOAD_SMALL_INT           0
               SET_ADD                  1
               POP_TOP
               LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE

   5   L1:     LOAD_COMMON_CONSTANT     8 ('')
               STORE_NAME               2 (x)
               LOAD_NAME                0 (__conditional_annotations__)
               LOAD_SMALL_INT           1
               SET_ADD                  1
               POP_TOP
               LOAD_COMMON_CONSTANT     7 (None)
               RETURN_VALUE

Disassembly of <code object __annotate__ at 0x10cfe2710, file "<dis>", line 2>:
  2           RESUME                   0
              LOAD_FAST_BORROW         0 (format)
              LOAD_SMALL_INT           2
              COMPARE_OP             132 (>)
              POP_JUMP_IF_FALSE        3 (to L1)
              NOT_TAKEN
              LOAD_COMMON_CONSTANT     1 (NotImplementedError)
              RAISE_VARARGS            1
      L1:     BUILD_MAP                0

  3           LOAD_SMALL_INT           0
              LOAD_GLOBAL              0 (__conditional_annotations__)
              CONTAINS_OP              0 (in)
              POP_JUMP_IF_FALSE       10 (to L2)
              NOT_TAKEN
              LOAD_GLOBAL              2 (int)
              COPY                     2
              LOAD_CONST               1 ('x')

  2           STORE_SUBSCR

  5   L2:     LOAD_SMALL_INT           1
              LOAD_GLOBAL              0 (__conditional_annotations__)
              CONTAINS_OP              0 (in)
              POP_JUMP_IF_FALSE       10 (to L3)
              NOT_TAKEN
              LOAD_GLOBAL              4 (str)
              COPY                     2
              LOAD_CONST               1 ('x')

  2           STORE_SUBSCR
      L3:     RETURN_VALUE

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

  3           LOAD_SMALL_INT           0
              LOAD_GLOBAL              0 (__conditional_annotations__)
              CONTAINS_OP              0 (in)
              POP_JUMP_IF_FALSE       10 (to L2)
              NOT_TAKEN
              LOAD_GLOBAL              2 (int)
              COPY                     2
              LOAD_CONST               1 ('x')

{'x': int} если if int() будет True,


  5   L2:     LOAD_SMALL_INT           1
              LOAD_GLOBAL              0 (__conditional_annotations__)
              CONTAINS_OP              0 (in)
              POP_JUMP_IF_FALSE       10 (to L3)
              NOT_TAKEN
              LOAD_GLOBAL              4 (str)
              COPY                     2
              LOAD_CONST               1 ('x')

и {'x': str} если False. Проверим на чуть другом примере:

>>> if int():
...     x: int = 0
... else:
...     x: str = ''
...     
>>> __annotate__(1)
{'x': <class 'str'>}

и

>>> if int() == 0:
...     x: int = 0
... else:
...     x: str = ''
...     
>>> __annotate__(1)
{'x': <class 'int'>}

Я проревьюил фикс, очень забавно получилось!

Обсуждение: Знали ли вы про __conditional_annotations__? Не кажется ли вам, что такая фича - уже прям сильно сложно?

А еще поговорили про CPython и его будущее в подкасте у Монтаны:

wemake-python-styleguide

репозиторий | зеркало

Лучший тул для качества кода на питоне: для вас и ваших агентов!

Выпустил wemake-python-styleguide@1.8.0!

Что в новом релизе?

  1. Поддержка Python3.15 и запрещены lazy import конструкции

  2. Улучшена поддержка t строк, теперь мы считаем их сложность (как в f строках). Например, строка t'Hello, {user.profile.get_name()}' теперь будет запрещена, а t'Hello, {user}' - нет

  3. Добавлена поддержка ИИ: мы сделали скилл /wps для написания кода агентами так, чтобы агент сразу писал код с контекстом будущих проверок и не тратил лишние токены на исправления

  4. Добавили локальный MCP, теперь агент может сам его стартануть, может его спрашивать про коды ошибок, как их исправлять. Меньше токенов жжется!

Установка  в Claude
Пример установки плагина в Claude

Обсуждение: Пробовали ли вы использовать wemake-python-styleguide с агентами? Довольны ли вы результатом?

Немного стыдного нейрослопа

Как и обещал в начале статьи.

Пока я делал MCP и прочее, мне конечно требовалось поставить агент локально. А как его можно безопасно локально запустить? А никак! Пришлось костылить запуск агента в докере:

claude () {
  # How it works:
  # 1. First run: the native installer drops the binary into ~/.local
  #    (volume `claude-bin`), then you go through the normal login /
  #    onboarding flow in the CLI.
  # 2. Everything Claude Code writes — auth, settings, .claude.json,
  #    session history, memory — lands in `claude-settings`, because
  #    CLAUDE_CONFIG_DIR redirects all of it there.
  # 3. Later runs: binary and config are already in the volumes, so no
  #    reinstall and no re-auth. `claude update` inside the container
  #    also persists, since it writes to ~/.local/share/claude.
  # 4. The project is mounted at its host path (not /workspace), so
  #    each repo keeps its own per-project sessions and memory.

  local project="$(readlink -f '.')"
  local image='buildpack-deps:bookworm-scm'  # has curl, git, bash

  docker run -it --rm \
    -e CLAUDE_CONFIG_DIR=/claude-config \
    -e PATH="/root/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
    -v claude-settings:/claude-config \
    -v claude-bin:/root/.local \
    -v "$project":"$project" \
    -w "$project" \
    "$image" \
    bash -c '
      if [ ! -x "$HOME/.local/bin/claude" ]; then
        curl -fsSL https://claude.ai/install.sh | bash
      fi
      exec claude "$@"
    ' _ "$@"
}

Можно посмотреть все мои дотфайлы: https://github.com/sobolevn/dotfiles Там много полезного.

Обсуждение: А как вы запускаете агентов локально? Что еще можно обезопасить?

Кстати про нейрослоп. Провели стрим с @Propan671, пытались решить задачки из django-modern-rest полностью при помощи агентов. Только вайбкодом. И очень сложные. И security-related.

Получилось ли? Посмотрите стрим или прочитайте итоговый пост!

django-modern-rest

репозиторий | зеркало

Выпустили релиз django-modern-rest@0.14.0!

Что добавили?

  • Официальную поддержку нового тайпчекера ty

  • Добавили полезностей для Router, теперь можно включать Router в urlpatterns просто как router.to_urlpatterns(), сильно меньше кода

  • Добавили поддержку @validate для создания переиспользуемых контроллеров

Сейчас работаем над релизом 0.15.0, там будет очень много изменений. А еще завтра начнется событие в нашем сообществе: #opensource_september, следить за ним можно будет у меня в тг.

А еще я записал подкаст про django-modern-rest с уважаемым @PyLounge

Обсуждение: Появилось желание попробовать после подкаста?

django-stubs

репозиторий | зеркало

Выпустили django-stubs@6.1.0! Релиз с поддержкой django@6.1.

А еще мы теперь поддерживаем pyrefly и ty в качестве официальных тайпчекеров. Конечно, силы плагинов mypy там нет, но базовые вещи - работают. Мы теперь гоняем тесты и проверяем.

Обсуждение: а каким тайпчекером пользуетесь вы?

Проекты сообщества

  • https://github.com/dshein-alt/rusty - Result как в Rust, но только для питона

  • https://github.com/dshein-alt/serde - Библиотека для сериализации моделей на базе NamedTuple

  • https://github.com/dshein-alt/ropds - Быстрый и лёгкий сервер персональной электронной библиотеки с каталогом OPDS 1.2 / 2.0 и веб-интерфейсом.

  • https://github.com/th0r3nt/JAWL (Just A While Loop) - ИИ-фреймворк для автономных ИИ-агентов через ReAct-циклы.

  • https://github.com/fomenko-ai/pytest-hardware-template - шаблон автоматизации тестирования оборудования на основе pytest. Основная идея - сделать как можно более общий универсальный шаблон и развивать его как библиотеку, адаптируя будущие обновления шаблона во внутренние проекты компании с помощью AI скиллов.

  • https://github.com/brilliance-admin/backend-python - админ панели на vue под sqlalchemy/django/любой источник данных с backend

  • https://github.com/goduni/unissh - современный, опенсорсный SSH клиент с selfhosted zero-knowledge сервером для синхронизации данных

  • https://github.com/kap-sh/capo - нормальный Python SDK для Amazon, поверх zapros, вместо ужасного boto. Про него на канале вышел пост

  • https://github.com/pomponchik/incontext - плагин для Hermes agent, который делает переменную max_tokens динамической, зависящей от остатка эффективного контекстного окна (т.е. с учетом запаса на сжатие)

  • https://github.com/rtugov/agentcontext - В общем история такая - неделю назад угорел по ИИшкам и локальным инференсам. В итоге понял что нет тулинга чтобы посмотреть контекст того же codex в риалтайме. В итоге я сделал свой proxy который встает между codex, claude, opencode, pi, etc. и просто показывает контекст запуска по шагам

  • https://github.com/mutating/skelet - Работа с несколькими источниками конфига, в разных форматах (в т.ч. перечисленные переменные окружения, YAML-файлы и другие), типизация (как на рантайме, так и в статик тайп чек тайме), и работа с секретами

  • https://github.com/pomponchik/autofission - По сути управляет одной настройкой - MaxScale в кластере Куба при использовании lambda функций. Теперь она не хардкодится, а определяется по реальной загрузке кластера, которая информация о которой регулярно обновляется

  • https://github.com/OlegYurchik/metaorm - Асинхронный слой работы с БД поверх SQLModel

  • https://github.com/Khabib73/open-source-playbook - Гайд для корректно, вежливого и продуктивного общения в опенсорсе. Многим бы пригодилось!

Хотите оказаться в списке? Пишите про свой проект с тегом #opensource к нам в чат.

Одной строкой

Выводы

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

Я там ничего не продаю, просто делаю свою работу, если считаете, что я делаю полезное - можно поддержать. Если нет, то я все равно продолжу ее делать.

Подписывайтесь на главный канал сообщества, если вам нравится такое читать. И возможно даже захочется поучаствовать! Буду рад видеть вас частью нашего опенсорс сообщеста :)

До встречи в сентябре!

Комментарии (14)


  1. PyLounge
    31.08.2026 12:15

    Братан, хорош, давай, давай, вперёд! Контент в кайф, можно ещё? Вообще красавчик! Можно вот этого вот почаще?


  1. Gaxeliy
    31.08.2026 12:15

    Батька Python на русском вещает! Спасибо, будем теперь в курсе всего :-)


  1. Sibnum
    31.08.2026 12:15

    Недавно пришёл к тому, что дайджесты лучше, чем бесконечный поток новых постов. Спасибо, за дайджест!


  1. Khabib73
    31.08.2026 12:15

    Класс!


    1. sobolevn Автор
      31.08.2026 12:15

      Спасибо за вклад в статью и опенсорс!


  1. thorent
    31.08.2026 12:15

    Ух ты, мой JAWL упомянули, занятно


    1. sobolevn Автор
      31.08.2026 12:15

      Спасибо, что опубликовал!


  1. getorigin
    31.08.2026 12:15

    А каким AI-агентом вы сейчас чаще всего пользуетесь для работы с Python?


    1. sobolevn Автор
      31.08.2026 12:15

      Никаким :) Я весь код руками пишу.


  1. vldmrmlkv
    31.08.2026 12:15

    del


  1. zzzzzzerg
    31.08.2026 12:15

    Привет!

    После такого интро даже страшно что-то писать :)

    Идея в ПЕПе выглядит очень интересно, ждем когда появится референсная реализация, чтобы можно было ее предметно посмотреть. На DPO многие высказывают опасения, что предложение не решит все проблемы, но вроде сейчас такая цель и не ставится.

    Для меня были интересны изменения, связанные со сборкой мусора. К ней можно отнести два изменения. Во-первых, стандартная версия должна получить deferred refcounting, который реализован для free-threading версии, насколько я понимаю нельзя просто так перенести эту реализацию, т.к. она требует изменения в memory-layout для PyObject (впрочем Марк предлагает эти изменения тоже внести). Подробностей пока нет, хотя Марк обещал добавить их в ПЕП. Тоже будет интересно посмотреть, как он планирует изменить сборщик мусора в этой связи. В целом, унификация сборки мусора для обоих версий идея хорошая, т.к. снизит нагрузку на майнтейнеров.

    Второе изменение не такое радикальное, но тоже интересное - изменится поведение оператора del, ему разрешат возвращать значения, таким образом можно будет передавать владение объектом, например, в другой канал или метод (foo(del bar)). Связано это с тем, что некоторые оптимизации планировалось делать только для объектов, которые имеют единственную ссылку. Насколько я понимаю, сейчас Марк немного ослабил это требование, так что может это изменение не приживется, хотя на мой взгляд тоже интересное.


    1. efimov-mikhail
      31.08.2026 12:15

      После такого интро придется изучать идею Марка сильно детальнее и писать лонгрид)))


      1. zzzzzzerg
        31.08.2026 12:15

        Рад тебя видеть и тут и там :)


  1. Fedyaration
    31.08.2026 12:15

    PEP 805 давно пора