Все еще работаем над llm-based FastAPI сервисом. Создал сам себе issue: нужна возможность периодически выполнять какие-то задачи, в народе именуемых cronjobами. Поскольку fastapi - это современный веб фреймворк тупо роутер запросов, такой функционал нам не завезли из коробки. Но задача довольно классическая, проблем быть не должно.
Кроме того,бох девопс дал нам кубернетис с его встроенными CronJobs. Поэтому изечно можем раз в минуту дергать какой-то сервис по ендпоинту /run-cron. Нам лишь нужно
* хранить и отслеживать статус джоб
* парсить cronexpr и решать, какие джобы щас запустить
* определять, если джоба зависла и сбрасывать статус
Это такой bare minimum, который бы меня устроил.
Гугл и ллмки выдали мне решение: билиотека apscheduler. Куча звезд на гитхабе, делает все то, что описано выше и даже больше. Короче, царский подгодон.
Начал интегрироваться и вместо cronjobов сделал blowjobы. Потому что этот apscheduler сам себе экзекутор задач. Он ни в какую не хотел привязываться к внешнему тригеру, потому что он сам знает, когда ему запускать задачи. А мне зачем экзекутор джобов в каждом поде приложения??
Потратив целый день на попытки скрестить жопу сужом питоном, я понял, что за этот день я бы уже написал свое решение. Единственное, что мне нужно, это либа для парсинга cronexpr. Ну уж с этим то проблем быть не должно? Не должно ведь, python?
Самая популярная либа для парсинга cron экспрешнов называется croniter. И она официально не поддерживается с конца 2024 года 🤡 На стэковерфлоу в связи с этим советуют воспользоваться новой либой cron-converter, у которой невероятные 46 звезд на гитхабе (кстати, поставил 47ю) 🤩 Ну тут особо выбора нет, ибо писать парсер с нуля - это задача для пет проектов.
И вот получается, что в 2к25 я все еще занимаюсь тем, что было сделано во многих фреймворках и цмсках в нулевые. Странно это как-то... Может я неправильно это готовлю.
Кто-то может подумать, что я тут опять накидываю на питон. На самом деле уже 4 года в проде на Symfony также крутится собственное решение с кронджобами, которое делает все тоже самое. Ибо Scheduler компонент завезли только в версии 6.3. И я его даже не пробовал 😔 Но хотя бы в пхп у либы dragonmantank/cron-expression, которая парсит cron expression, 4.7к звезд, а у питоновсокого croniter 485 🤷 вообще нет уверенности, что кому-то это надо.
Поделитесь, как сами решаете проблему с кроном? сразу ставите celery? запускаете отдельный сервис с тем же кодом, но чисто повыполнять таски? или целиком на кубовых джобах живете?
Кроме того,
* хранить и отслеживать статус джоб
* парсить cronexpr и решать, какие джобы щас запустить
* определять, если джоба зависла и сбрасывать статус
Это такой bare minimum, который бы меня устроил.
Гугл и ллмки выдали мне решение: билиотека apscheduler. Куча звезд на гитхабе, делает все то, что описано выше и даже больше. Короче, царский подгодон.
Начал интегрироваться и вместо cronjobов сделал blowjobы. Потому что этот apscheduler сам себе экзекутор задач. Он ни в какую не хотел привязываться к внешнему тригеру, потому что он сам знает, когда ему запускать задачи. А мне зачем экзекутор джобов в каждом поде приложения??
Потратив целый день на попытки скрестить жопу с
Самая популярная либа для парсинга cron экспрешнов называется croniter. И она официально не поддерживается с конца 2024 года 🤡 На стэковерфлоу в связи с этим советуют воспользоваться новой либой cron-converter, у которой невероятные 46 звезд на гитхабе (кстати, поставил 47ю) 🤩 Ну тут особо выбора нет, ибо писать парсер с нуля - это задача для пет проектов.
И вот получается, что в 2к25 я все еще занимаюсь тем, что было сделано во многих фреймворках и цмсках в нулевые. Странно это как-то... Может я неправильно это готовлю.
Кто-то может подумать, что я тут опять накидываю на питон. На самом деле уже 4 года в проде на Symfony также крутится собственное решение с кронджобами, которое делает все тоже самое. Ибо Scheduler компонент завезли только в версии 6.3. И я его даже не пробовал 😔 Но хотя бы в пхп у либы dragonmantank/cron-expression, которая парсит cron expression, 4.7к звезд, а у питоновсокого croniter 485 🤷 вообще нет уверенности, что кому-то это надо.
Поделитесь, как сами решаете проблему с кроном? сразу ставите celery? запускаете отдельный сервис с тем же кодом, но чисто повыполнять таски? или целиком на кубовых джобах живете?
🔥1
Итак, настал момент истины. На сколько же php быстрее golang?
И нет, я не ошибся. Дмитрий Кириллов в своем шикарном докладе показал, что php с jit может быть быстрее Си (базового). Это на столько меня вдохновило, что я решил поиграться с этим сам. Пришлось даже виртуалочку для этого арендовать.
Я использовал ту же самую задачу о рюкзаке из доклада. Вот код на golang.
Код на пхп взял прям отсюда.
Итак, вот, что нам выдал perf для 10 запусков golang(1.25.2)
А вот для php(8.4.13)
Таким образом, мы видим, что php реально очень быстр, когда дело касается CPU-bound задач. Ну и конечно, когда вы поприседали с ним, чтоб убрать все ненужные опкоды. Мы получили, что пхп быстрее почти на 20%.
Изначально я тестировал этот код на версии php 8.3. И там результат был таков
Что конечно все еще быстрее голэнг, но не так впечатляюще. То есть разрабы php действительно хорошо поработали над jit в 8.4!👍
А еще я поставил nodejs и python, раз уж пошла такая пляска. И я вынужден признать, что ребята, которые пилят V8, рил настоящие гении. Для ноды результат получился
Что медленее php8.4, но быстрее и 8.3 и golang. Но при этом, в отличии от php, мне не нужно было делать ничего специального. Я просто написал
и оно уже быстрее голэнг!
Что касается питона (3.12), то тут все выглядит как-то так 😂
Лан, нет смысла сравнивать язык с jit и без jit. Понятно, что это будет избиение младенца.
Поэтому я решил отключить jit в php. Более того, я решил использовать версию кода на пхп без всяких извращений с проверками на out of bound conditions. Таким образом, код стал выглядеть, как обычный код на пыхе. Итого имеем
То есть питон более, чем в 5 раз медленее пхп.
А что в итоге? Понятно, что это все синтетика. Понятно, что, когда мы начнем писать бизнес логику, начнем вызывать методы у объектов, начнем массивами всячески оперировать, то картина будет немного другой. Конечно статически типизированный и компилируемый голэнг все таки в другой лиге играет. Особенно в плане потребления памяти.
Но если вдруг перед вами стоит задача, где надо тупо дробить числа, а у вас пхп - не бегите переписывать этот кусок на голэнг, шоб было побыстрее! Лучше вместо создания нового микросервиса посмотрите доклад Дмитрия, охуейте, а затем примените новые знания на практике 👆
P.S. Мечтаю стать Дмитрием, когда вырасту
И нет, я не ошибся. Дмитрий Кириллов в своем шикарном докладе показал, что php с jit может быть быстрее Си (базового). Это на столько меня вдохновило, что я решил поиграться с этим сам. Пришлось даже виртуалочку для этого арендовать.
Я использовал ту же самую задачу о рюкзаке из доклада. Вот код на golang.
package main
import "fmt"
const w = 700
const h = 700
const l = 700
const target = 1500
func main() {
ans := 0
for i := 0; i < w; i++ {
for j := 0; j < h; j++ {
for k := 0; k < l; k++ {
vol := (i + 3) * (j + 4) * (k + 5)
if vol == target {
ans += 2
}
}
}
}
fmt.Println(ans)
}
Код на пхп взял прям отсюда.
Итак, вот, что нам выдал perf для 10 запусков golang(1.25.2)
0.353181 +- 0.000158 seconds
А вот для php(8.4.13)
0.2895 +- 0.0119 seconds
Таким образом, мы видим, что php реально очень быстр, когда дело касается CPU-bound задач. Ну и конечно, когда вы поприседали с ним, чтоб убрать все ненужные опкоды. Мы получили, что пхп быстрее почти на 20%.
Изначально я тестировал этот код на версии php 8.3. И там результат был таков
0.33962 +- 0.00224
Что конечно все еще быстрее голэнг, но не так впечатляюще. То есть разрабы php действительно хорошо поработали над jit в 8.4!👍
А еще я поставил nodejs и python, раз уж пошла такая пляска. И я вынужден признать, что ребята, которые пилят V8, рил настоящие гении. Для ноды результат получился
0.32645 +- 0.00288
Что медленее php8.4, но быстрее и 8.3 и golang. Но при этом, в отличии от php, мне не нужно было делать ничего специального. Я просто написал
const calc = (w, h, l, target) => {
let ans = 0;
for (let i = 0; i < w; i++) {
for (let j = 0; j < h; j++) {
for (let k = 0; k < l; k++) {
const vol = (i + 3) * (j + 4) * (k + 5);
if (vol === target) {
ans += 2;
}
}
}
}
return ans;
};
console.log(calc(700, 700, 700, 1500));и оно уже быстрее голэнг!
Что касается питона (3.12), то тут все выглядит как-то так 😂
25.958 +- 0.235 seconds
Лан, нет смысла сравнивать язык с jit и без jit. Понятно, что это будет избиение младенца.
Поэтому я решил отключить jit в php. Более того, я решил использовать версию кода на пхп без всяких извращений с проверками на out of bound conditions. Таким образом, код стал выглядеть, как обычный код на пыхе. Итого имеем
4.9320 +- 0.0439 seconds
То есть питон более, чем в 5 раз медленее пхп.
А что в итоге? Понятно, что это все синтетика. Понятно, что, когда мы начнем писать бизнес логику, начнем вызывать методы у объектов, начнем массивами всячески оперировать, то картина будет немного другой. Конечно статически типизированный и компилируемый голэнг все таки в другой лиге играет. Особенно в плане потребления памяти.
Но если вдруг перед вами стоит задача, где надо тупо дробить числа, а у вас пхп - не бегите переписывать этот кусок на голэнг, шоб было побыстрее! Лучше вместо создания нового микросервиса посмотрите доклад Дмитрия, охуейте, а затем примените новые знания на практике 👆
P.S. Мечтаю стать Дмитрием, когда вырасту
👏11👍5🔥3
В догонку к предыдущему посту. Поставил еще bun, pypy (python реализация с jit) и ruby!
Ну что могу сказать. Bun очень удивил! 🤩
У ноды, напомню, было 0.32645. Так что это наш новый чемпион!
Окей, я подумал, что может рил влияние запуска самой ноды на столько велико. Ведь я мерию perfом, а он измеряет выполнение команды. Добавил в сам скрипт временные метки. И нихрена подобного. У bun это в среднем около 0.20 секунд. У ноды 0.30 секунд. То есть, и там, и там на запуск и всякое остальное тратится +/- одно и тоже время.
Так шо bun рил топ! 👍
А что там с pypy? А наконец-то все как у людей
Но тут я подумал все-таки, что это ж питон. И там чертешо творится на старте. Поэтому померил само выполнение скрипта. И тут я не ошибся. Действительно, само выполнение заняло в среднем 0.29. Причем разброс прям маленький, работает стабильно.
Ну и чисто по фану, запустил Ruby (3.2.3).
Чуток быстрее питона -- уже хорошо. Ожидаемо.
Рубисты сорри. Я вообще не рубист. Я пытался поставить yjit и у меня он не собрался чет с первого раза. А по скольку "собрать из исходников" -- единственый варик у них в доке, топошли они нахуй я забил.
Кароче, первый вывод. Если у вас jit, то че то вычислять числами будет плюс-минус одинаково везде. Но только если это не bun. Bun -- мое почтение! 🫡 А если у вас не jit, то пхп вам напихает за обе щеки (привет python и ruby).
Второй вывод: первый вывод -- это вывод из жопы. Не надо воспринимать его серьезно. Мы тут чуток в циклах числа посчитали. Это мягко говоря не все вычислительные задачи. Так шо похер. Все чисто for fun.
И последнее. У пхп с jit просто отвратительный разброс по таймингам
от Bun до nodejs. Нигде больше такого нет, у всех все стабильно с точностью до 2го знака.
Ну что могу сказать. Bun очень удивил! 🤩
0.22418 +- 0.00369 seconds
У ноды, напомню, было 0.32645. Так что это наш новый чемпион!
Окей, я подумал, что может рил влияние запуска самой ноды на столько велико. Ведь я мерию perfом, а он измеряет выполнение команды. Добавил в сам скрипт временные метки. И нихрена подобного. У bun это в среднем около 0.20 секунд. У ноды 0.30 секунд. То есть, и там, и там на запуск и всякое остальное тратится +/- одно и тоже время.
Так шо bun рил топ! 👍
А что там с pypy? А наконец-то все как у людей
0.346620 +- 0.000672
Но тут я подумал все-таки, что это ж питон. И там чертешо творится на старте. Поэтому померил само выполнение скрипта. И тут я не ошибся. Действительно, само выполнение заняло в среднем 0.29. Причем разброс прям маленький, работает стабильно.
Ну и чисто по фану, запустил Ruby (3.2.3).
20.0148 +- 0.0176 seconds
Чуток быстрее питона -- уже хорошо. Ожидаемо.
Рубисты сорри. Я вообще не рубист. Я пытался поставить yjit и у меня он не собрался чет с первого раза. А по скольку "собрать из исходников" -- единственый варик у них в доке, то
Кароче, первый вывод. Если у вас jit, то че то вычислять числами будет плюс-минус одинаково везде. Но только если это не bun. Bun -- мое почтение! 🫡 А если у вас не jit, то пхп вам напихает за обе щеки (привет python и ruby).
Второй вывод: первый вывод -- это вывод из жопы. Не надо воспринимать его серьезно. Мы тут чуток в циклах числа посчитали. Это мягко говоря не все вычислительные задачи. Так шо похер. Все чисто for fun.
И последнее. У пхп с jit просто отвратительный разброс по таймингам
0.2980 seconds
0.2284 seconds
0.3182 seconds
0.2904 seconds
0.2707 seconds
0.3137 seconds
0.2628 seconds
0.2971 seconds
0.2144 seconds
0.2786 seconds
от Bun до nodejs. Нигде больше такого нет, у всех все стабильно с точностью до 2го знака.
❤2
Любой пхпшник знает, что топовая IDE это джетбрейнсовский phpstorm. Сорри любители Vim с LSP, но это горькая правда🥲 И недавнее исследование от джетбрейнс 🤡 это подтверждает. Кстати, ставьте лоис, если хотите обзор на возможности сторонней lsp (phpactor) для пхп. Или не ставьте. Как хотите, кароч, я все равно сделаю.
Но сегодняшний пост не о восхвалении пхпшторма, а скорее наоборот. Ядром любой IDE я считаю вот эту часть, связанную с lsp и статическим анализом кода. Все остальное - это просто приятные присрачки, без которых жить сложно, но можно. Без стат анализа же ide превращается в обычный блокнот.
Проблема в том, что я уже несколько раз натыкался на баги, связанные с некорректным анализом кода. И тут вы мне скажете "да ты охуел! у всех есть баги!" Но прикол в том, что эти баги не вчера зарепортили люди. И создается впечатление, что никто их не торопится фиксить. Например, как вам вот такой баг из 2023 года. Если вкратце, то в этом коде
шторм будет считать, что у $c тип string[][], хотя должно быть string[]. Это в дальнейшнем приводит к false-positive ошибке в редакторе, что очень бесит. И вот в конце 2025го я вынужден использовать array_merge при работе со списками😡
Поэтому я решил проверить свое ощущение и узнать, а как вообще у джетбрейнс обстоит дело с фиксом багов, которые им пользователи приносят. Благо, что у них вполне себе открытые release notes и трекер. В youtrack надо поставить фильтр Subsystem: PHP Inspections, чтоб получить тикеты связанные с анализом пхп. Вот для 2023 года (178 штук), а вот для 2022 (286 штук).
Чекнул релиз ноуты за 2025 год. На момент написания поста, актуальная версия 2025.2.4. Получилось, что в этом году они не исправили ни одной проблемы из 2023 года, исправили 1 тикет из 2021 и 1 тикет из 2022. Это было все в одном релизе 2025.2. И это довольно печально😢
Конечно я не продакт в джетбрейнс, и не мне приоритеты выставлять, чем занять разрабов завтра. Но как минимум мне кажется странным, что почти все тикеты имеют приоритет Normal (процентов 90), либо Nice to have. И только два (тикета, а не процента) имеют приоритет Major. Но, сука, и их никто не торопится фиксить 🤡
Мне странно видеть у всех багов пользователей приоритет Normal. Баги же разные бывают. Некоторые чисто косметические и на них можно забить, а некоторые куда серьезнее. Например, вот этот тикет влияет на возможности рефакторинга. Люди в комментах бампают его, но как-то всем насрать. Проприетарная безысходность...
Есть ощущение, что в джетбрейнс считают (не безосновательно), что их анализ кода и так уже достаточно хорош, поэтому в этом направлении можно подзабить. И это тот самый случай, когда прям не хватает хорошей опенсорсной альтернативы, шоб как то расшевелить это все.
Вот такая осенняя грустняшка сегодня😰
Но сегодняшний пост не о восхвалении пхпшторма, а скорее наоборот. Ядром любой IDE я считаю вот эту часть, связанную с lsp и статическим анализом кода. Все остальное - это просто приятные присрачки, без которых жить сложно, но можно. Без стат анализа же ide превращается в обычный блокнот.
Проблема в том, что я уже несколько раз натыкался на баги, связанные с некорректным анализом кода. И тут вы мне скажете "да ты охуел! у всех есть баги!" Но прикол в том, что эти баги не вчера зарепортили люди. И создается впечатление, что никто их не торопится фиксить. Например, как вам вот такой баг из 2023 года. Если вкратце, то в этом коде
$a = ['a'];
$b = ['b'];
$c = [...$a, ...$b];
шторм будет считать, что у $c тип string[][], хотя должно быть string[]. Это в дальнейшнем приводит к false-positive ошибке в редакторе, что очень бесит. И вот в конце 2025го я вынужден использовать array_merge при работе со списками😡
Поэтому я решил проверить свое ощущение и узнать, а как вообще у джетбрейнс обстоит дело с фиксом багов, которые им пользователи приносят. Благо, что у них вполне себе открытые release notes и трекер. В youtrack надо поставить фильтр Subsystem: PHP Inspections, чтоб получить тикеты связанные с анализом пхп. Вот для 2023 года (178 штук), а вот для 2022 (286 штук).
Чекнул релиз ноуты за 2025 год. На момент написания поста, актуальная версия 2025.2.4. Получилось, что в этом году они не исправили ни одной проблемы из 2023 года, исправили 1 тикет из 2021 и 1 тикет из 2022. Это было все в одном релизе 2025.2. И это довольно печально😢
Конечно я не продакт в джетбрейнс, и не мне приоритеты выставлять, чем занять разрабов завтра. Но как минимум мне кажется странным, что почти все тикеты имеют приоритет Normal (процентов 90), либо Nice to have. И только два (тикета, а не процента) имеют приоритет Major. Но, сука, и их никто не торопится фиксить 🤡
Мне странно видеть у всех багов пользователей приоритет Normal. Баги же разные бывают. Некоторые чисто косметические и на них можно забить, а некоторые куда серьезнее. Например, вот этот тикет влияет на возможности рефакторинга. Люди в комментах бампают его, но как-то всем насрать. Проприетарная безысходность...
Есть ощущение, что в джетбрейнс считают (не безосновательно), что их анализ кода и так уже достаточно хорош, поэтому в этом направлении можно подзабить. И это тот самый случай, когда прям не хватает хорошей опенсорсной альтернативы, шоб как то расшевелить это все.
Вот такая осенняя грустняшка сегодня😰
❤6👍5
Сегодня жители Санкт-Петербурга могли видеть ярко красное зарево. Это полыхала моя срака после попыток стать pro python девелопером😡
В чем суть. Потребовалось разработать новый сервис. К сожалению его специфика вновь заставила использовать python вместо любимого пхп 😢
Очень часто можно услышать мнение что стандартный пакетный менеджер pip - говно из жопы. Типа он медленный, всратый, не позволяет разделять зависимости на группы, нет лок файла и прочее. Короче говоря, устаревший инструмент. И это не безосновательно.
И вот комьюнити напряглось и родило новый пакетный менеджер uv, который blazingly fast (написан на rust 😍), в котором куча всяких фич, который за тебя готовит виртуальные енвайронменты и прочее. Короче, слышал про него только хорошее.
Подумал, что говорят про него достаточно долго и много, поэтому можно его попробовать затащить в прод. Покурил доку. Вроде бы все выглядит как нормальный пакетный менеджер. Есть pyproject.toml файл, в котором описываются зависимости с требованиями к их версиями, аналог composer.json и package.json. Есть uv.lock, в котором прям точные версии пакетов описываются. Есть команды для установки, удаления, обновления пакетов. Короче, все как мы любим, и все работает реально быстро. Так что же тогда могло так сильно поджарить жепу?
Давайте вспомним, как мы готовим наши проекты для прода. Обычно одним из этапов билда является команда вроде
А дальше вопрос, как запускать наше приложение? Дла этого используется команда uv run. Она сама активирует текущий venv со всеми зависимостями и запустит ваш скрипт. Так, например, рекомендуют запускать uvicorn в докере.
И вот разработчики решили, что будет АХУЕННО крутой идеей при запуске uv run
* проверять, что лок файл соответствует toml, и если нет то обновлять его
* проверять, что venv соответствует лок файлу, и если нет то обновлять venv
Блять, я готов ставить свое сгоревшее очко на то, что когда вы запускаете
И такое "ожидаемое" не только меня сбивает с толку. Считаю, что делать такое было мега тупой идеей. Ибо ни в одном другом пакетном менеджере я не припомню такого поведения. Сук, ты выдай лучше ошибку! Че ты бесиш то! 😡
А так в целом конечно blazingly fast и очень круто 👍
Ну давайте, питонисты, напихайте мне в комментах, что я неправ и команда запуска - отличное место, чтоб обновить venv 😢
В чем суть. Потребовалось разработать новый сервис. К сожалению его специфика вновь заставила использовать python вместо любимого пхп 😢
Очень часто можно услышать мнение что стандартный пакетный менеджер pip - говно из жопы. Типа он медленный, всратый, не позволяет разделять зависимости на группы, нет лок файла и прочее. Короче говоря, устаревший инструмент. И это не безосновательно.
И вот комьюнити напряглось и родило новый пакетный менеджер uv, который blazingly fast (написан на rust 😍), в котором куча всяких фич, который за тебя готовит виртуальные енвайронменты и прочее. Короче, слышал про него только хорошее.
Подумал, что говорят про него достаточно долго и много, поэтому можно его попробовать затащить в прод. Покурил доку. Вроде бы все выглядит как нормальный пакетный менеджер. Есть pyproject.toml файл, в котором описываются зависимости с требованиями к их версиями, аналог composer.json и package.json. Есть uv.lock, в котором прям точные версии пакетов описываются. Есть команды для установки, удаления, обновления пакетов. Короче, все как мы любим, и все работает реально быстро. Так что же тогда могло так сильно поджарить жепу?
Давайте вспомним, как мы готовим наши проекты для прода. Обычно одним из этапов билда является команда вроде
yarn install --frozen-lockfile --production, которая ставит все зависимости из лок файла без development. И вот аналогом такой команды в uv является команда uv sync --frozen --no-dev. Это команда создает venv со всеми зависимостями из лок файла, кроме дев зависимостей.А дальше вопрос, как запускать наше приложение? Дла этого используется команда uv run. Она сама активирует текущий venv со всеми зависимостями и запустит ваш скрипт. Так, например, рекомендуют запускать uvicorn в докере.
И вот разработчики решили, что будет АХУЕННО крутой идеей при запуске uv run
* проверять, что лок файл соответствует toml, и если нет то обновлять его
* проверять, что venv соответствует лок файлу, и если нет то обновлять venv
Блять, я готов ставить свое сгоревшее очко на то, что когда вы запускаете
uv run app.py вы не ожидаете, что у вас че-то будет меняться в лок файле или в venv. Ибо это команда для ЗАПУСКА. Окей, мы поставили все прод зависимости с помощью uv sync --frozen --no-dev, затем выполнили uv run на старте контейнера, и у нас подтянулись все дев зависимости🤡збс! и чтоб этого не случилось, нужно добавлять флаг --no-sync. И такое "ожидаемое" не только меня сбивает с толку. Считаю, что делать такое было мега тупой идеей. Ибо ни в одном другом пакетном менеджере я не припомню такого поведения. Сук, ты выдай лучше ошибку! Че ты бесиш то! 😡
А так в целом конечно blazingly fast и очень круто 👍
Ну давайте, питонисты, напихайте мне в комментах, что я неправ и команда запуска - отличное место, чтоб обновить venv 😢
😁7🔥2🤡1