Как выстроить защиту цепочки поставок Python
Эшелонированная схема защиты начинается с собственного кода: Ruff находит секреты, слабую криптографию и запросы без тайм-аута до публикации пакета.
Зависимости и их криптографические хеши фиксируют через
Хеши не распознают изначально вредоносный пакет, а аудит пропускает неизвестные уязвимости. Поэтому начать стоит с Ruff и фиксации зависимостей, затем добавить аудит и SBOM.
Эшелонированная схема защиты начинается с собственного кода: Ruff находит секреты, слабую криптографию и запросы без тайм-аута до публикации пакета.
Зависимости и их криптографические хеши фиксируют через
uv lock или uv pip compile --generate-hashes. Затем pip-audit ищет в CI известные уязвимости, а SBOM помогает понять, затронул ли проект компрометированный пакет. Trusted Publishing с OIDC заменяет долгоживущие API-токены.Хеши не распознают изначально вредоносный пакет, а аудит пропускает неизвестные уязвимости. Поэтому начать стоит с Ruff и фиксации зависимостей, затем добавить аудит и SBOM.
🔥1
Как не сломать pickle собственным исключением Python
Если конструктор исключения принимает
Питоничный инвариант прост:
Пример с ValidationError показывает поломку и совместимый вариант класса.
Если конструктор исключения принимает
field и reason, не заменяйте их готовой строкой при вызове super().__init__(). Иначе в args останется один элемент, а при восстановлении BaseException.__reduce__ передаст его обратно конструктору. Тот ждёт два аргумента, поэтому распаковка завершится TypeError. Так же ломаются copy.copy() и передача исключения между процессами.Питоничный инвариант прост:
args должны оставаться корректным списком аргументов для вашего __init__. Передавайте в базовый класс исходные field и reason, храните структурированные данные в атрибутах, а читаемое сообщение формируйте в __str__.Пример с ValidationError показывает поломку и совместимый вариант класса.
Seroze’s blog
[Python] Exception Handling: The Parts I Got Wrong
Notes from working through an exception-handling quiz. Everything below was verified on CPython 3.12 rather than recalled — the sections marked trap are the ones I actually got wrong, and they cluster around one theme: the hierarchy and the unwind, not the…
🤪1
Охрана трубопровода длиной 400 километров
Камеры на столбах не заглянут за угол, дрон висит 30-40 минут и летит заряжаться, а охранник-человек — дорого, медленно и небезопасно на протяжённом объекте.
Технический разбор робопса изнутри: что скрыто под закрытым ядром биомеханики, какой стек сенсоров закрывает слепые пятна друг друга — лидар боится стекла, поэтому рядом ставят сонар.
Как рой из нескольких собак строит p2p-сеть, чтобы одна работала мостом для другой за горизонтом связи в техническом разборе робопса.
Камеры на столбах не заглянут за угол, дрон висит 30-40 минут и летит заряжаться, а охранник-человек — дорого, медленно и небезопасно на протяжённом объекте.
Технический разбор робопса изнутри: что скрыто под закрытым ядром биомеханики, какой стек сенсоров закрывает слепые пятна друг друга — лидар боится стекла, поэтому рядом ставят сонар.
Как рой из нескольких собак строит p2p-сеть, чтобы одна работала мостом для другой за горизонтом связи в техническом разборе робопса.
❤🔥2👍1
Как вернуть значение из всплывающего окна в форму Django Admin
Django Admin умеет создавать связанный объект во всплывающем окне и сразу подставлять его в исходную форму. Практический разбор этого механизма показывает, как переиспользовать его для собственного инструмента выбора значений.
Пример связывает
Питоничность здесь в композиции готовых частей: представление может вычислить значение любым способом, а JavaScript админки доставит результат в нужное поле. Цена переиспользования — зависимость от соглашений Django Admin: специального идентификатора ссылки и функций из
Django Admin умеет создавать связанный объект во всплывающем окне и сразу подставлять его в исходную форму. Практический разбор этого механизма показывает, как переиспользовать его для собственного инструмента выбора значений.
Пример связывает
ModelAdmin, отдельное представление, URL и шаблон. Ссылка вызывает showRelatedObjectLookupPopup, а кнопка во всплывающем окне через opener.dismissRelatedLookupPopup возвращает выбранную строку в поле формы и закрывает окно.Питоничность здесь в композиции готовых частей: представление может вычислить значение любым способом, а JavaScript админки доставит результат в нужное поле. Цена переиспользования — зависимость от соглашений Django Admin: специального идентификатора ссылки и функций из
RelatedObjectLookup.js.Как упаковать Python-проект в библиотеку и CLI
Копирование модулей и правки
Проект разделяет функцию обработки JSON и интерфейс на Typer. Поэтому одну логику можно импортировать как библиотеку или запускать командой
Editable-установка связывает окружение с исходным кодом: изменения становятся доступны без переустановки. Подход пригодится, когда внутренней утилите пора перестать быть набором файлов с относительными импортами.
Копирование модулей и правки
sys.path можно заменить устанавливаемым пакетом. В руководстве на примере JSON-флаттенера разобраны структура src, файл pyproject.toml с Hatchling, зависимости и точка входа для команды терминала.Проект разделяет функцию обработки JSON и интерфейс на Typer. Поэтому одну логику можно импортировать как библиотеку или запускать командой
json-flatten из любого каталога. Структура src не позволяет Python случайно импортировать исходники вместо установленного пакета.Editable-установка связывает окружение с исходным кодом: изменения становятся доступны без переустановки. Подход пригодится, когда внутренней утилите пора перестать быть набором файлов с относительными импортами.
Stay In The Loop
Packaging a Python Project Like a Pro
Stop copy-pasting scripts between projects. Learn how to structure and package your Python code so it's installable, importable, and reusable.
Как собрать Rust-проект с Python-модулем и отдельной программой
В пошаговом примере калькулятора одна функция сложения доступна из Python и из отдельной Rust-программы. PyO3 позволяет вызывать Rust-код из Python, maturin собирает расширение, а через uv устанавливают maturin и запускают сборку.
После установки модуля импорт в Python может работать, а
В примере это исправляют через
#python
В пошаговом примере калькулятора одна функция сложения доступна из Python и из отдельной Rust-программы. PyO3 позволяет вызывать Rust-код из Python, maturin собирает расширение, а через uv устанавливают maturin и запускают сборку.
После установки модуля импорт в Python может работать, а
cargo run — падать: PyO3 ищет Python, но глобальной установки нет или она настроена нестандартно.В примере это исправляют через
.cargo/config.toml: переменная PYO3_PYTHON указывает на .venv/bin/python. Так для запуска Rust-программы используется Python из виртуального окружения. В руководстве есть конфигурация сборки для обоих вариантов и проверки вызова функции.#python
Как открывать ссылки Django-сайта в приложениях Apple и Android
Для этого нужна двусторонняя связь: приложение объявляет домены, ссылки которых обрабатывает, а сайт подтверждает разрешённые приложения. Одного файла на сервере недостаточно.
Адам Джонсон показывает, как отдавать из Django файлы apple-app-site-association и assetlinks.json по адресам в
В разборе есть тесты заголовков, корректности JSON и идентификаторов приложений, а также проверки после развёртывания через сервисы Apple и Google. Ошибки здесь незаметны: ссылка просто открывается в браузере.
#django #тестирование
Для этого нужна двусторонняя связь: приложение объявляет домены, ссылки которых обрабатывает, а сайт подтверждает разрешённые приложения. Одного файла на сервере недостаточно.
Адам Джонсон показывает, как отдавать из Django файлы apple-app-site-association и assetlinks.json по адресам в
/.well-known/. Нужны HTTPS, ответ 200 без редиректов и тип содержимого application/json. Apple-файл хранится с расширением .json, чтобы FileResponse определил тип, но URL остаётся без расширения.В разборе есть тесты заголовков, корректности JSON и идентификаторов приложений, а также проверки после развёртывания через сервисы Apple и Google. Ошибки здесь незаметны: ссылка просто открывается в браузере.
#django #тестирование
security.txt в Django: контакт для сообщений об уязвимостях
Исследователь нашёл уязвимость на сайте. Куда ему писать? Файл
Адам Джонсон разбирает реализацию для Django: отдачу файла через
Для сопровождения пригодится отдельная проверка срока действия. Корректная дата в файле ещё не означает, что контакт актуален. Автор добавляет системную проверку Django: за 30 дней до истечения срока она начинает выдавать предупреждение, не прерывая команду. Это повод проверить контакты и обновить
#django #тестирование
Исследователь нашёл уязвимость на сайте. Куда ему писать? Файл
/.well-known/security.txt даёт публичный ответ: поле Contact указывает способ связи, а Expires — дату, после которой сведения считаются устаревшими.Адам Джонсон разбирает реализацию для Django: отдачу файла через
FileResponse, доступ без авторизации и тесты ответа. В примере проверяются тип содержимого, обязательные поля и разрешённые методы HTTP.Для сопровождения пригодится отдельная проверка срока действия. Корректная дата в файле ещё не означает, что контакт актуален. Автор добавляет системную проверку Django: за 30 дней до истечения срока она начинает выдавать предупреждение, не прерывая команду. Это повод проверить контакты и обновить
Expires.#django #тестирование
❤3
Как отличить отсутствие аргумента от None в Python
Если None — допустимое значение настройки, оно не подходит для обозначения «аргумент не передали». Маркер MISSING = object() решает эту задачу, но после deepcopy или pickle может превратиться в другой объект: проверка через is перестанет работать.
В Python 3.15 появляется встроенный sentinel. Объявление MISSING = sentinel("MISSING") даёт читаемую сигнатуру, позволяет использовать сам маркер в аннотации типа и сохраняет его идентичность при копировании.
Для pickle маркер должен быть доступен по имени в модуле: имя внутри sentinel обязано совпадать с именем переменной. Создавайте его один раз. Два вызова sentinel("MISSING") возвращают разные объекты, даже если строка одинакова.
#python #типизация
Если None — допустимое значение настройки, оно не подходит для обозначения «аргумент не передали». Маркер MISSING = object() решает эту задачу, но после deepcopy или pickle может превратиться в другой объект: проверка через is перестанет работать.
В Python 3.15 появляется встроенный sentinel. Объявление MISSING = sentinel("MISSING") даёт читаемую сигнатуру, позволяет использовать сам маркер в аннотации типа и сохраняет его идентичность при копировании.
Для pickle маркер должен быть доступен по имени в модуле: имя внутри sentinel обязано совпадать с именем переменной. Создавайте его один раз. Два вызова sentinel("MISSING") возвращают разные объекты, даже если строка одинакова.
#python #типизация
Как выполнять CPU-задачи в отдельных интерпретаторах Python
В Python 3.14 InterpreterPoolExecutor запускает потоки с отдельными интерпретаторами. У каждого свой GIL, поэтому вычисления на Python могут одновременно занимать несколько ядер в одном процессе.
У этой модели есть цена: между интерпретаторами передаются сериализованные функции, аргументы и результаты. Импорты и глобальные переменные изолированы. Кеш на уровне модуля станет кешем каждого работника; большая таблица данных может занять память несколько раз.
Подход подходит для достаточно крупных вычислительных задач с простыми входами и выходами. На мелких операциях передачу данных легко сделать дороже вычислений. Перед переносом проверьте совместимость C-расширений и сравните время и память с ProcessPoolExecutor на реальной нагрузке.
#python #производительность
В Python 3.14 InterpreterPoolExecutor запускает потоки с отдельными интерпретаторами. У каждого свой GIL, поэтому вычисления на Python могут одновременно занимать несколько ядер в одном процессе.
У этой модели есть цена: между интерпретаторами передаются сериализованные функции, аргументы и результаты. Импорты и глобальные переменные изолированы. Кеш на уровне модуля станет кешем каждого работника; большая таблица данных может занять память несколько раз.
Подход подходит для достаточно крупных вычислительных задач с простыми входами и выходами. На мелких операциях передачу данных легко сделать дороже вычислений. Перед переносом проверьте совместимость C-расширений и сравните время и память с ProcessPoolExecutor на реальной нагрузке.
#python #производительность
Почему цикл внутри теста скрывает часть ошибок
Тест перебирает десять входов и проверяет результат через assert. Если третий случай падает, оставшиеся семь до проверки не доходят. В отчёте появляется одна ошибка, а состояние остальных случаев неизвестно.
pytest.mark.parametrize превращает каждую пару «вход — ожидаемый результат» в отдельный тест. Без режима остановки на первой ошибке pytest проверит все случаи и покажет, какие именно сломались. Через ids им можно дать понятные имена.
Подготовку ресурсов удобно вынести в fixture с yield: код после yield выполнит очистку. Для ожидаемой ошибки используйте pytest.raises с конкретным типом и match, если важен текст сообщения. Иначе случайный ValueError из другой части функции может сделать тест зелёным.
#python #тестирование
Тест перебирает десять входов и проверяет результат через assert. Если третий случай падает, оставшиеся семь до проверки не доходят. В отчёте появляется одна ошибка, а состояние остальных случаев неизвестно.
pytest.mark.parametrize превращает каждую пару «вход — ожидаемый результат» в отдельный тест. Без режима остановки на первой ошибке pytest проверит все случаи и покажет, какие именно сломались. Через ids им можно дать понятные имена.
Подготовку ресурсов удобно вынести в fixture с yield: код после yield выполнит очистку. Для ожидаемой ошибки используйте pytest.raises с конкретным типом и match, если важен текст сообщения. Иначе случайный ValueError из другой части функции может сделать тест зелёным.
#python #тестирование