Блог Евгения Морозова

python

Написал перед отпуском статью о часто возникающей проблеме при контейнеризациии приложений со статикой:

Как организовать отдачу статических файлов в контейнеризованном Django

Написано на примере Django, но сам принцип довольно общий и подойдёт для многих других фреймворков, языков и технологий.

У меня нет действующего аккаунта на Хабре, поэтому опубликовано от имени Яндекс.Практикума.

#django #python #docker

Для поиска утечек памяти в приложениях на Python существует масса различных модулей, в том числе, уже встроенный в Python 3 модуль tracemalloc. Недостаток всех этих инструментов в том, что утечку надо воспроизвести в локальном окружении, а потом уже, используя pdb или ipdb, ковыряться в куче (heap), в поисках утекших объектов. Однако если у нас есть огромный проект, посещаемый миллионами пользователей, то воспроизвести утечку может оказаться невозможно, так как к ней приводит какое-то сочетание взаимодействия пользователей с проектом, которое не воспроизвести наугад.

К счастью, нашёл проект meliae, позволяющий сделать дамп кучи в произвольный момент, с тем, чтобы проанализировать ее в оффлайне, уже не на боевом сервере.

Однако, в проекте оказался досадный баг: целые числа Python он пытается сериализовать как тип C long. Но в Python целое число может быть произвольной разрядности, а в C long имеет разрядность 32 или 64 бит. Где-то в нашем проекте (или одной из его зависимостей) используются большие числа, поэтому создать дамп не удавалось, потому что этот процесс очень быстро обрывался с ошибкой OverflowError.

Делать нечего, все другие варианты поиска утечки я уже попробовал без малейшего успеха. Скомпилировал Python из исходников с отладочной информацией, скомпилировал meliae, и стал вспоминать полузабытые навыки программирования на C и использования отладчика gdb. Довольно быстро нашел место возникновения ошибки, проблема была только в том, что времени на поиски у меня немного, а изучение того, как сдампить из модуля на C полноценное представление целого числа Python, потребовало бы длительного изучения устройства интерпретатора Python.

В итоге воспользовался быстро найденной функцией PyLong_AsLongLongAndOverflow, которая возвращает -1, в случае, если число Python не помещается в long long. Сомневаюсь, что в нашем приложении утекают long, поэтому точное их значение меня не интересует.

Свои правки положил здесь: https://github.com/emorozov/meliae

Если удастся найти утечку памяти, постараюсь написать об этом тоже.

#python #разработка

В больших и старых проектах на Django бывает непросто найти ошибки из-за большого количества сигналов. Сигналы затрудняют анализ кода, так как обработчик может быть создан в любом модуле проекта, например, не в том, где определена модель, и вызывается неявно.

Для облегчения поиска обработчиков нашел когда-то команду для Django, выводящую список всех обработчиков в проекте. Но она выводила только список обработчиков, без указания к какой модели они относятся. Чуть позже нашлась усовершенствованная версия, а затем я тоже приложил руки в процессе создания pull request для проекта django-extensions. Пришлось попотеть, так как django-extensions должен работать на большом количестве различных версий Python и Django (включая, например, PyPy). Но все препятствия удалось преодолеть, надеюсь, что мой код окажется в django-extensions, а пока оставляю ссылку на сам код команды, чтобы можно было пользоваться, пока рассматривается pull request: list_signals.py

#python #разработка

Закончился PyCon. Кратко опишу свои впечатления. Было интересно, на некоторых докладах чувстовал, что делаю велосипеды, тогда как многие другие — космические корабли.

Попытался участвовать в трех конкурсах: 1. Был смешной автоматик от Positive Technologies с вопросами по Python, некоторые весьма непростые. Выиграл мячик. 2. Была викторина в стиле «Что? Где? Когда?» от Яндекса, в которой играли командами. Наша команда заняла 8-е место из 12 (но мы были самой маленькой командой, поэтому нам пришлось вчетвером думать за десятерых). 3. Попытался поучаствовать в конкурсе от Positive Technologies, в котором надо было исправить несколько уязвимостей в Python приложениях.

На первый взгляд, конкурс от PT был простой, но первый час я бился с тем, что мои решения не проходили, подошел к Ивану Цыганову, он выяснил, что на сервере проверки решений закончилось место. Затем хотелось прослушать почти все доклады, так что урывками пытался в перерывах копаться в коде, но все уязвимости исправить так и не успел. Тем более, мне показалось, что две исправленные уязвимости проверяльщик упорно не хотел засчитать.

Но так как несколько человек этот этап прошли, то не уверен, проблема с моими исправлениями или проверяльщик все же ожидал какой-то шаблон, под который не подошло мое исправление. Иван обещал выложить исходники проверяльщика на GitHub, возможно, позже проверю.

Из понравившихся докладов запомнились больше всего: доклад Ивана Цыганова об уязвимостях, доклад Златы Обуховской о проблемах с асинхронностью в Python, доклад Александра Кошелева о сборке образов Docker без build зависимостей (не rocket science, но очень жизненно), доклад Артёма Малышева о DDD, доклад Бориса Цема об уменьшении сложности проектов Wargaming. И доклад Бобука до кучи, потому что он вызвал самое бурное обсуждение и массу шуток.

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

Лично мои ощущения. После более, чем 10 лет работы в удаленном режиме, мне завидно смотреть на ребят, которые приезжают вместе, общаются, обсуждают происходящее. Я этого всего лишен, и начинаю понимать, как этого не хватает. Поскольку по одиночке никто не приехал, кроме меня, втесаться в чью-то компанию очень сложно, мне это не удалось, к сожалению. Люди приехали из одной компании, давно друг-друга знают, у них свои шуточки о своих рабочих проблемах, и так далее. Вклиниться в такой разговор очень непросто, моих социальных навыков для этого, увы, не хватило.

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

По итогам начал думать, что во-первых, хочу в офис. Мне надоела жизнь перекати поля и надоел вакуум вокруг, минимум общения, в том числе, общения на профессиональные темы.

#pycon #python #работа

Если вы разрабатываете сайт на языке не поддерживаемом Django, то можете столкнуться с подобной ошибкой:

  File "/home/user/.virtualenvs/laos/lib/python3.7/site-packages/django/utils/translation/trans_real.py", line 102, in __init__
    raise IOError("No translation files found for default language %s." % settings.LANGUAGE_CODE)
OSError: No translation files found for default language lo.

Язык в settings.py определён правильно, ошибка довольно загадочная, и поиск не даёт разумных результатов.

Если попытаться скомпилировать переводы командой compilemessages, то она естественно не выполняется с той же самой ошибкой.

Самый простой способ обхода: перейти в каталог с переводами для данного языка и скомпилировать переводы вручную:

cd locale/lo/LC_MESSAGES
msgfmt -o django.mo django.po
msgfmt -o djangojs.mo djangojs.po

Более простой и быстрый вариант: временно поменять язык по умолчанию на en, выполнить compilemessages, поменять язык обратно.

Наверное надо создать соответствующий баг в трекере Django, если дойдут руки, дополню пост.

#django #python #gettext