{"id":482693,"date":"2026-06-07T11:25:52","date_gmt":"2026-06-07T11:25:52","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=482693"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=482693","title":{"rendered":"Python-\u043f\u0440\u043e\u0435\u043a\u0442 \u0432 2026: uv, ruff, pyproject.toml. \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u0437\u0430 5 \u043c\u0438\u043d\u0443\u0442"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>pip install, requirements.txt, virtualenv, black, isort, flake8, mypy, <a href=\"http:\/\/setup.py\" rel=\"noopener noreferrer nofollow\">setup.py<\/a>&#8230; \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0435 Python-\u043f\u0440\u043e\u0435\u043a\u0442 \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0432 2020 \u0433\u043e\u0434\u0443, \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043b\u044f \u0432\u0430\u0441. \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u0442\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0432\u0441\u0451 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435.<\/p>\n<p>\u0412 2026 \u0433\u043e\u0434\u0443 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 Python-\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0441\u043e\u0431\u0440\u0430\u043b\u0430\u0441\u044c \u0432 \u043d\u0435\u0447\u0442\u043e \u0446\u0435\u043b\u044c\u043d\u043e\u0435. \u0414\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 (<a href=\"https:\/\/github.com\/astral-sh\/uv\" rel=\"noopener noreferrer nofollow\">uv<\/a>\u00a0\u0438\u00a0<a href=\"https:\/\/github.com\/astral-sh\/ruff\" rel=\"noopener noreferrer nofollow\">ruff<\/a>) + \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b (<code>pyproject.toml<\/code>) \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442 7+ \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0443\u0442\u0438\u043b\u0438\u0442. \u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<h3>\u0427\u0442\u043e \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0438 \u043d\u0430 \u0447\u0442\u043e<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0411\u044b\u043b\u043e<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0421\u0442\u0430\u043b\u043e<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">pip + pip-tools<\/p>\n<\/td>\n<td>\n<p align=\"left\">uv<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">virtualenv \/ venv<\/p>\n<\/td>\n<td>\n<p align=\"left\">uv<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">pyenv<\/p>\n<\/td>\n<td>\n<p align=\"left\">uv<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">poetry \/ pipenv<\/p>\n<\/td>\n<td>\n<p align=\"left\">uv<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">black (\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435)<\/p>\n<\/td>\n<td>\n<p align=\"left\">ruff format<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">isort (\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u0432)<\/p>\n<\/td>\n<td>\n<p align=\"left\">ruff<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">flake8 (\u043b\u0438\u043d\u0442\u0438\u043d\u0433)<\/p>\n<\/td>\n<td>\n<p align=\"left\">ruff check<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><a href=\"http:\/\/setup.py\" rel=\"noopener noreferrer nofollow\">setup.py<\/a> \/ setup.cfg<\/p>\n<\/td>\n<td>\n<p align=\"left\">pyproject.toml<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">requirements.txt<\/p>\n<\/td>\n<td>\n<p align=\"left\">pyproject.toml + uv.lock<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0414\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u0434\u0435\u0432\u044f\u0442\u0438. \u041e\u0431\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 Rust, \u043e\u0431\u0430 \u043e\u0442\u00a0<a href=\"https:\/\/astral.sh\/\" rel=\"noopener noreferrer nofollow\">Astral<\/a>. \u0420\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 10-100 \u0440\u0430\u0437 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u043e\u0432 \u043d\u0430 Python.<\/p>\n<h3>\u0428\u0430\u0433 1. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 uv<\/h3>\n<p>\u041e\u0434\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430:<\/p>\n<pre><code class=\"python\"># macOS \/ Linuxcurl -LsSf https:\/\/astral.sh\/uv\/install.sh | sh# Windowspowershell -ExecutionPolicy ByPass -c \"irm https:\/\/astral.sh\/uv\/install.ps1 | iex\"# \u0418\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 pip (\u0435\u0441\u043b\u0438 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u043e-\u0441\u0442\u0430\u0440\u043e\u043c\u0443)pip install uv<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c:<\/p>\n<pre><code class=\"python\">$ uv --versionuv 0.7.x<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>ruff<\/code>\u00a0\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e. uv \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437\u00a0<code>uvx ruff<\/code>. \u041d\u043e \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e:<\/p>\n<pre><code class=\"python\">uv tool install ruff<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u0428\u0430\u0433 2. \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442<\/h3>\n<pre><code class=\"django\">$ uv init myprojectInitialized project `myproject` at `.\/myproject`$ cd myproject$ lspyproject.toml  src\/  README.md  .python-version<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>uv \u0441\u043e\u0437\u0434\u0430\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u00a0<code>pyproject.toml<\/code>, \u043f\u0430\u043f\u043a\u0443\u00a0<code>src\/<\/code>\u00a0\u0438 \u0444\u0430\u0439\u043b\u00a0<code>.python-version<\/code>. \u041d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0<a href=\"http:\/\/setup.py\" rel=\"noopener noreferrer nofollow\"><code>setup.py<\/code><\/a>,\u00a0<code>requirements.txt<\/code>,\u00a0<code>Makefile<\/code>.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u0435\u043d Python \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438:<\/p>\n<pre><code class=\"elixir\"># uv \u0441\u0430\u043c \u0441\u043a\u0430\u0447\u0430\u0435\u0442 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 \u043d\u0443\u0436\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e Pythonuv python install 3.13uv python pin 3.13<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0430,\u00a0<strong>uv \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 pyenv<\/strong>. \u041e\u043d \u0441\u0430\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 Python.<\/p>\n<h3>\u0428\u0430\u0433 3. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h3>\n<p>\u0417\u0430\u0431\u0443\u0434\u044c\u0442\u0435\u00a0<code>pip install<\/code>. \u0422\u0435\u043f\u0435\u0440\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"cmake\"># \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044cuv add requestsuv add pandas numpy# \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c dev-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044cuv add --dev pytest ruff# \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044cuv remove pandas<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>uv \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438:<\/p>\n<p>1. \u0421\u043e\u0437\u0434\u0430\u0451\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 (\u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442).<br \/>2. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0430\u043a\u0435\u0442 \u0432\u00a0<code>pyproject.toml<\/code>.<br \/>3. \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 lock-\u0444\u0430\u0439\u043b\u00a0<code>uv.lock<\/code>.<br \/>4. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442.<\/p>\n<p>\u0412\u0441\u0451 \u0437\u0430 \u043e\u0434\u043d\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443. \u041d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0<code>pip freeze &gt; requirements.txt<\/code>.<\/p>\n<h4>\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c<\/h4>\n<p>uv \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u044b \u0432 10-100 \u0440\u0430\u0437 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 pip. \u0425\u043e\u043b\u043e\u0434\u043d\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\u00a0<code>numpy + pandas + requests<\/code>:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0412\u0440\u0435\u043c\u044f<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">pip<\/p>\n<\/td>\n<td>\n<p align=\"left\">~12 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">poetry<\/p>\n<\/td>\n<td>\n<p align=\"left\">~8 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">uv<\/p>\n<\/td>\n<td>\n<p align=\"left\">~0.5 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0430. uv \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u044b \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0436\u0451\u0441\u0442\u043a\u0438\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432.<\/p>\n<h3>\u0428\u0430\u0433 4. pyproject.toml<\/h3>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439\u00a0<code>pyproject.toml<\/code>\u00a0\u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<pre><code class=\"python\">[project]name = \"myproject\"version = \"0.1.0\"description = \"My awesome project\"readme = \"README.md\"requires-python = \"&gt;=3.12\"dependencies = [    \"requests&gt;=2.32\",    \"numpy&gt;=2.0\",][dependency-groups]dev = [    \"pytest&gt;=8.0\",    \"ruff&gt;=0.9\",][tool.ruff]target-version = \"py312\"line-length = 88[tool.ruff.lint]select = [    \"E\",    # pycodestyle errors    \"W\",    # pycodestyle warnings    \"F\",    # pyflakes    \"I\",    # isort    \"UP\",   # pyupgrade    \"B\",    # flake8-bugbear    \"SIM\",  # flake8-simplify][tool.ruff.format]quote-style = \"double\"[tool.pytest.ini_options]testpaths = [\"tests\"]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0434\u0438\u043d \u0444\u0430\u0439\u043b. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u043b\u0438\u043d\u0442\u0435\u0440, \u0444\u043e\u0440\u043c\u0430\u0442\u0442\u0435\u0440, \u0442\u0435\u0441\u0442\u044b. \u0412\u0441\u0451 \u0437\u0434\u0435\u0441\u044c.<\/p>\n<h3>\u0428\u0430\u0433 5. \u041b\u0438\u043d\u0442\u0438\u043d\u0433 \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (ruff)<\/h3>\n<p><code>ruff<\/code>\u00a0\u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442\u00a0<code>flake8<\/code>\u00a0+\u00a0<code>black<\/code>\u00a0+\u00a0<code>isort<\/code>\u00a0+\u00a0<code>pyupgrade<\/code>. \u041e\u0434\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u0447\u0435\u0442\u044b\u0440\u0451\u0445.<\/p>\n<pre><code class=\"elixir\"># \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u0434uvx ruff check .# \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044cuvx ruff check --fix .# \u041e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 (\u0437\u0430\u043c\u0435\u043d\u0430 black)uvx ruff format .# \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439uvx ruff format --check .<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c ruff<\/h4>\n<p>ruff \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043a\u043e\u0434 \u0432 10-100 \u0440\u0430\u0437 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 flake8. \u041d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0437 1000 \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0412\u0440\u0435\u043c\u044f<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">flake8<\/p>\n<\/td>\n<td>\n<p align=\"left\">~12 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">flake8 + isort + black<\/p>\n<\/td>\n<td>\n<p align=\"left\">~25 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">ruff check + ruff format<\/p>\n<\/td>\n<td>\n<p align=\"left\">~0.3 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440: \u0447\u0442\u043e ruff \u043b\u043e\u0432\u0438\u0442<\/h4>\n<pre><code class=\"json\"># \u0414\u043eimport osimport sysfrom typing import Optional, List, Dictimport jsondef process(data: Optional[List[Dict[str, str]]] = None):    if data == None:        data = list()    for item in data:        if len(item.keys()) &gt; 0:            print(item)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"fsharp\"># \u041f\u043e\u0441\u043b\u0435 ruff check --fix + ruff formatimport jsondef process(data: list[dict[str, str]] | None = None):    if data is None:        data = []    for item in data:        if item:            print(item)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0427\u0442\u043e ruff \u0441\u0434\u0435\u043b\u0430\u043b:<\/p>\n<p>1. \u0423\u0431\u0440\u0430\u043b \u043d\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u044b (<code>os<\/code>,\u00a0<code>sys<\/code>).<br \/>2. \u041e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u044b.<br \/>3. \u0417\u0430\u043c\u0435\u043d\u0438\u043b\u00a0<code>Optional[List[Dict]]<\/code>\u00a0\u043d\u0430\u00a0<code>list[dict] | None<\/code>\u00a0(Python 3.10+).<br \/>4. \u0417\u0430\u043c\u0435\u043d\u0438\u043b\u00a0<code>== None<\/code>\u00a0\u043d\u0430\u00a0<code>is None<\/code>.<br \/>5. \u0417\u0430\u043c\u0435\u043d\u0438\u043b\u00a0<code>list()<\/code>\u00a0\u043d\u0430\u00a0<code>[]<\/code>.<br \/>6. \u0423\u043f\u0440\u043e\u0441\u0442\u0438\u043b\u00a0<code>len(item.keys()) &gt; 0<\/code>\u00a0\u0434\u043e\u00a0<code>item<\/code>.<\/p>\n<h3>\u0428\u0430\u0433 6. \u0417\u0430\u043f\u0443\u0441\u043a \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432<\/h3>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"javascript\"># \u0417\u0430\u043f\u0443\u0441\u043a \u0441\u043a\u0440\u0438\u043f\u0442\u0430uv run python src\/myproject\/main.py# \u0417\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432uv run pytest# \u0417\u0430\u043f\u0443\u0441\u043a \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438uv run mycommand<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>uv run<\/code>\u00a0\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u041d\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0<code>source .venv\/bin\/activate<\/code>.<\/p>\n<h4>\u041e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b<\/h4>\n<p>\u041d\u0443\u0436\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438, \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u044f \u043f\u0440\u043e\u0435\u043a\u0442?<\/p>\n<pre><code class=\"julia\"># \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 requests, \u0431\u0435\u0437 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438uv run --with requests python script.py# \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e (npx-\u0441\u0442\u0438\u043b\u044c)uvx black .uvx httpie https:\/\/api.github.com<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>uvx<\/code>\u00a0=\u00a0<code>npx<\/code>\u00a0\u0434\u043b\u044f Python. \u0421\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442, \u043d\u0435 \u0437\u0430\u0441\u043e\u0440\u044f\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0443.<\/p>\n<h3>\u0428\u0430\u0433 7. CI\/CD<\/h3>\n<p>\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 GitHub Actions workflow:<\/p>\n<pre><code class=\"json\"># .github\/workflows\/ci.ymlname: CIon: [push, pull_request]jobs:  check:    runs-on: ubuntu-latest    steps:      - uses: actions\/checkout@v4      - uses: astral-sh\/setup-uv@v5      - run: uv sync      - run: uvx ruff check .      - run: uvx ruff format --check .      - run: uv run pytest<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>4 \u0441\u0442\u0440\u043e\u043a\u0438. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u043b\u0438\u043d\u0442\u0438\u043d\u0433, \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0442\u0435\u0441\u0442\u044b. \u0412\u0441\u0451.<\/p>\n<p>\u0412\u0440\u0435\u043c\u044f CI \u043d\u0430 \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0421\u0442\u0435\u043a<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0412\u0440\u0435\u043c\u044f<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">pip + flake8 + black + pytest<\/p>\n<\/td>\n<td>\n<p align=\"left\">~45 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">poetry + flake8 + black + pytest<\/p>\n<\/td>\n<td>\n<p align=\"left\">~60 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">uv + ruff + pytest<\/p>\n<\/td>\n<td>\n<p align=\"left\">~12 \u0441\u0435\u043a<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h3>\u0428\u0430\u0433 8. Docker<\/h3>\n<p>\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 Dockerfile:<\/p>\n<pre><code class=\"python\">FROM python:3.13-slim# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c uvCOPY --from=ghcr.io\/astral-sh\/uv:latest \/uv \/usr\/local\/bin\/uv# \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430WORKDIR \/appCOPY pyproject.toml uv.lock .\/# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (\u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f Docker layer)RUN uv sync --no-dev --frozen# \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434COPY src\/ src\/CMD [\"uv\", \"run\", \"python\", \"-m\", \"myproject\"]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442:\u00a0<code>pyproject.toml<\/code>\u00a0\u0438\u00a0<code>uv.lock<\/code>\u00a0\u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 \u043a\u043e\u0434\u0430. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 Docker \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0439 \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438. \u0415\u0441\u043b\u0438 \u043a\u043e\u0434 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f, \u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0435\u0442, \u043f\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.<\/p>\n<h3>\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0441 pip\/poetry \u0437\u0430 2 \u043c\u0438\u043d\u0443\u0442\u044b<\/h3>\n<h4>\u0421 requirements.txt<\/h4>\n<pre><code class=\"python\"># \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442uv init# \u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 requirements.txtuv add $(cat requirements.txt)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0421 poetry<\/h4>\n<p>uv \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u00a0<code>pyproject.toml<\/code>\u00a0\u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Poetry. \u041f\u0440\u043e\u0441\u0442\u043e:<\/p>\n<pre><code class=\"python\"># \u0423\u0434\u0430\u043b\u0438\u0442\u044c poetry.lock, \u0441\u043e\u0437\u0434\u0430\u0442\u044c uv.lockrm poetry.lockuv lockuv sync<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0432\u00a0<code>pyproject.toml<\/code>\u00a0\u0435\u0441\u0442\u044c \u0441\u0435\u043a\u0446\u0438\u044f\u00a0<code>[tool.poetry]<\/code>, uv \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0435\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u0442\u0443\u0434\u0430.<\/p>\n<h3>\u041f\u043e\u043b\u043d\u044b\u0439 \u0447\u0435\u043a\u043b\u0438\u0441\u0442 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<pre><code class=\"python\"># 1. \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442uv init myproject &amp;&amp; cd myproject# 2. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438uv add requests pydantic# 3. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c dev-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438uv add --dev pytest ruff# 4. \u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434# ...# 5. \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0438 \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044cuvx ruff check --fix .uvx ruff format .# 6. \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044buv run pytest# 7. \u0413\u043e\u0442\u043e\u0432\u043e<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u044f\u0442\u044c \u043c\u0438\u043d\u0443\u0442. \u041d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0<a href=\"http:\/\/setup.py\" rel=\"noopener noreferrer nofollow\"><code>setup.py<\/code><\/a>,\u00a0<a href=\"http:\/\/MANIFEST.in\" rel=\"noopener noreferrer nofollow\"><code>MANIFEST.in<\/code><\/a>,\u00a0<code>requirements.txt<\/code>,\u00a0<code>tox.ini<\/code>,\u00a0<code>.flake8<\/code>,\u00a0<code>.isort.cfg<\/code>,\u00a0<code>pyproject.toml<\/code>\u00a0\u043d\u0430 200 \u0441\u0442\u0440\u043e\u043a.<\/p>\n<p>uv + ruff + pyproject.toml = \u0432\u0441\u0451, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f Python-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 2026 \u0433\u043e\u0434\u0443.<\/p>\n<h3>\u0421\u0441\u044b\u043b\u043a\u0438<\/h3>\n<p><a href=\"https:\/\/github.com\/astral-sh\/uv\" rel=\"noopener noreferrer nofollow\">uv \u043d\u0430 GitHub<\/a>\u00a0(80k+ \u0437\u0432\u0451\u0437\u0434)<br \/><a href=\"https:\/\/github.com\/astral-sh\/ruff\" rel=\"noopener noreferrer nofollow\">ruff \u043d\u0430 GitHub<\/a>\u00a0(40k+ \u0437\u0432\u0451\u0437\u0434)<br \/><a href=\"https:\/\/docs.astral.sh\/uv\/\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f uv<\/a><br \/><a href=\"https:\/\/docs.astral.sh\/ruff\/\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f ruff<\/a><br \/><a href=\"https:\/\/peps.python.org\/pep-0621\/\" rel=\"noopener noreferrer nofollow\">PEP 621<\/a>: \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 pyproject.toml<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1044550\/\">https:\/\/habr.com\/ru\/articles\/1044550\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>pip install, requirements.txt, virtualenv, black, isort, flake8, mypy, setup.py&#8230; \u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0435 Python-\u043f\u0440\u043e\u0435\u043a\u0442 \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0432 2020 \u0433\u043e\u0434\u0443, \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043b\u044f \u0432\u0430\u0441. \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u0442\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0432\u0441\u0451 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435.\u0412 2026 \u0433\u043e\u0434\u0443 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 Python-\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0441\u043e\u0431\u0440\u0430\u043b\u0430\u0441\u044c \u0432 \u043d\u0435\u0447\u0442\u043e \u0446\u0435\u043b\u044c\u043d\u043e\u0435. \u0414\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 (uv\u00a0\u0438\u00a0ruff) + \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b (pyproject.toml) \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442 7+ \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0443\u0442\u0438\u043b\u0438\u0442. \u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.\u0427\u0442\u043e \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c \u0438 \u043d\u0430 \u0447\u0442\u043e\u0411\u044b\u043b\u043e\u0421\u0442\u0430\u043b\u043epip + pip-toolsuvvirtualenv \/ venvuvpyenvuvpoetry \/ pipenvuvblack (\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435)ruff formatisort (\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u0432)ruffflake8 (\u043b\u0438\u043d\u0442\u0438\u043d\u0433)ruff checksetup.py \/ setup.cfgpyproject.tomlrequirements.txtpyproject.toml + uv.lock\u0414\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u0434\u0435\u0432\u044f\u0442\u0438. \u041e\u0431\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 Rust, \u043e\u0431\u0430 \u043e\u0442\u00a0Astral. \u0420\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 10-100 \u0440\u0430\u0437 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0430\u043d\u0430\u043b\u043e\u0433\u043e\u0432 \u043d\u0430 Python.\u0428\u0430\u0433 1. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 uv\u041e\u0434\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430:# macOS \/ Linuxcurl -LsSf https:\/\/astral.sh\/uv\/install.sh | sh# Windowspowershell -ExecutionPolicy ByPass -c &#171;irm https:\/\/astral.sh\/uv\/install.ps1 | iex&#187;# \u0418\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 pip (\u0435\u0441\u043b\u0438 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u043e-\u0441\u0442\u0430\u0440\u043e\u043c\u0443)pip install uv\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c:$ uv &#8212;versionuv 0.7.xruff\u00a0\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e. uv \u0443\u043c\u0435\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437\u00a0uvx ruff. \u041d\u043e \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e:uv tool install ruff\u0428\u0430\u0433 2. \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442$ uv init myprojectInitialized project `myproject` at `.\/myproject`$ cd myproject$ lspyproject.toml  src\/  README.md  .python-versionuv \u0441\u043e\u0437\u0434\u0430\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u00a0pyproject.toml, \u043f\u0430\u043f\u043a\u0443\u00a0src\/\u00a0\u0438 \u0444\u0430\u0439\u043b\u00a0.python-version. \u041d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0setup.py,\u00a0requirements.txt,\u00a0Makefile.\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u0435\u043d Python \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438:# uv \u0441\u0430\u043c \u0441\u043a\u0430\u0447\u0430\u0435\u0442 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 \u043d\u0443\u0436\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e Pythonuv python install 3.13uv python pin 3.13\u0414\u0430,\u00a0uv \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 pyenv. \u041e\u043d \u0441\u0430\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 Python.\u0428\u0430\u0433 3. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438\u0417\u0430\u0431\u0443\u0434\u044c\u0442\u0435\u00a0pip install. \u0422\u0435\u043f\u0435\u0440\u044c \u0442\u0430\u043a:# \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044cuv add requestsuv add pandas numpy# \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c dev-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044cuv add &#8212;dev pytest ruff# \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044cuv remove pandasuv \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438:1. \u0421\u043e\u0437\u0434\u0430\u0451\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 (\u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u043d\u0435\u0442).2. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0430\u043a\u0435\u0442 \u0432\u00a0pyproject.toml.3. \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 lock-\u0444\u0430\u0439\u043b\u00a0uv.lock.4. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442.\u0412\u0441\u0451 \u0437\u0430 \u043e\u0434\u043d\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443. \u041d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0pip freeze &gt; requirements.txt.\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044cuv \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u044b \u0432 10-100 \u0440\u0430\u0437 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 pip. \u0425\u043e\u043b\u043e\u0434\u043d\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430\u00a0numpy + pandas + requests:\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0412\u0440\u0435\u043c\u044fpip~12 \u0441\u0435\u043apoetry~8 \u0441\u0435\u043auv~0.5 \u0441\u0435\u043a\u042d\u0442\u043e \u043d\u0435 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0430. uv \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u043f\u0430\u043a\u0435\u0442\u044b \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0436\u0451\u0441\u0442\u043a\u0438\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432.\u0428\u0430\u0433 4. pyproject.toml\u0412\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439\u00a0pyproject.toml\u00a0\u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:[project]name = &#171;myproject&#187;version = &#171;0.1.0&#187;description = &#171;My awesome project&#187;readme = &#171;README.md&#187;requires-python = &#171;&gt;=3.12&#8243;dependencies = [    &#171;requests&gt;=2.32&#187;,    &#171;numpy&gt;=2.0&#187;,][dependency-groups]dev = [    &#171;pytest&gt;=8.0&#187;,    &#171;ruff&gt;=0.9&#187;,][tool.ruff]target-version = &#171;py312&#8243;line-length = 88[tool.ruff.lint]select = [    &#171;E&#187;,    # pycodestyle errors    &#171;W&#187;,    # pycodestyle warnings    &#171;F&#187;,    # pyflakes    &#171;I&#187;,    # isort    &#171;UP&#187;,   # pyupgrade    &#171;B&#187;,    # flake8-bugbear    &#171;SIM&#187;,  # flake8-simplify][tool.ruff.format]quote-style = &#171;double&#187;[tool.pytest.ini_options]testpaths = [&#171;tests&#187;]\u041e\u0434\u0438\u043d \u0444\u0430\u0439\u043b. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u043b\u0438\u043d\u0442\u0435\u0440, \u0444\u043e\u0440\u043c\u0430\u0442\u0442\u0435\u0440, \u0442\u0435\u0441\u0442\u044b. \u0412\u0441\u0451 \u0437\u0434\u0435\u0441\u044c.\u0428\u0430\u0433 5. \u041b\u0438\u043d\u0442\u0438\u043d\u0433 \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (ruff)ruff\u00a0\u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442\u00a0flake8\u00a0+\u00a0black\u00a0+\u00a0isort\u00a0+\u00a0pyupgrade. \u041e\u0434\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u043c\u0435\u0441\u0442\u043e \u0447\u0435\u0442\u044b\u0440\u0451\u0445.# \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u0434uvx ruff check .# \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044cuvx ruff check &#8212;fix .# \u041e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 (\u0437\u0430\u043c\u0435\u043d\u0430 black)uvx ruff format .# \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439uvx ruff format &#8212;check .\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c ruffruff \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043a\u043e\u0434 \u0432 10-100 \u0440\u0430\u0437 \u0431\u044b\u0441\u0442\u0440\u0435\u0435 flake8. \u041d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0437 1000 \u0444\u0430\u0439\u043b\u043e\u0432:\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0412\u0440\u0435\u043c\u044fflake8~12 \u0441\u0435\u043aflake8 + isort + black~25 \u0441\u0435\u043aruff check + ruff format~0.3 \u0441\u0435\u043a\u041f\u0440\u0438\u043c\u0435\u0440: \u0447\u0442\u043e ruff \u043b\u043e\u0432\u0438\u0442# \u0414\u043eimport osimport sysfrom typing import Optional, List, Dictimport jsondef process(data: Optional[List[Dict[str, str]]] = None):    if data == None:        data = list()    for item in data:        if len(item.keys()) &gt; 0:            print(item)# \u041f\u043e\u0441\u043b\u0435 ruff check &#8212;fix + ruff formatimport jsondef process(data: list[dict[str, str]] | None = None):    if data is None:        data = []    for item in data:        if item:            print(item)\u0427\u0442\u043e ruff \u0441\u0434\u0435\u043b\u0430\u043b:1. \u0423\u0431\u0440\u0430\u043b \u043d\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u044b (os,\u00a0sys).2. \u041e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043b \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u044b.3. \u0417\u0430\u043c\u0435\u043d\u0438\u043b\u00a0Optional[List[Dict]]\u00a0\u043d\u0430\u00a0list[dict] | None\u00a0(Python 3.10+).4. \u0417\u0430\u043c\u0435\u043d\u0438\u043b\u00a0== None\u00a0\u043d\u0430\u00a0is None.5. \u0417\u0430\u043c\u0435\u043d\u0438\u043b\u00a0list()\u00a0\u043d\u0430\u00a0[].6. \u0423\u043f\u0440\u043e\u0441\u0442\u0438\u043b\u00a0len(item.keys()) &gt; 0\u00a0\u0434\u043e\u00a0item.\u0428\u0430\u0433 6. \u0417\u0430\u043f\u0443\u0441\u043a \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f:# \u0417\u0430\u043f\u0443\u0441\u043a \u0441\u043a\u0440\u0438\u043f\u0442\u0430uv run python src\/myproject\/main.py# \u0417\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432uv run pytest# \u0417\u0430\u043f\u0443\u0441\u043a \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438uv run mycommanduv run\u00a0\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u041d\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0source .venv\/bin\/activate.\u041e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0435 \u0441\u043a\u0440\u0438\u043f\u0442\u044b\u041d\u0443\u0436\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438, \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u044f \u043f\u0440\u043e\u0435\u043a\u0442?# \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 requests, \u0431\u0435\u0437 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438uv run &#8212;with requests python script.py# \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e (npx-\u0441\u0442\u0438\u043b\u044c)uvx black .uvx httpie https:\/\/api.github.comuvx\u00a0=\u00a0npx\u00a0\u0434\u043b\u044f Python. \u0421\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442, \u043d\u0435 \u0437\u0430\u0441\u043e\u0440\u044f\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0443.\u0428\u0430\u0433 7. CI\/CD\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 GitHub Actions workflow:# .github\/workflows\/ci.ymlname: CIon: [push, pull_request]jobs:  check:    runs-on: ubuntu-latest    steps:      &#8212; uses: actions\/checkout@v4      &#8212; uses: astral-sh\/setup-uv@v5      &#8212; run: uv sync      &#8212; run: uvx ruff check .      &#8212; run: uvx ruff format &#8212;check .      &#8212; run: uv run pytest4 \u0441\u0442\u0440\u043e\u043a\u0438. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u043b\u0438\u043d\u0442\u0438\u043d\u0433, \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0442\u0435\u0441\u0442\u044b. \u0412\u0441\u0451.\u0412\u0440\u0435\u043c\u044f CI \u043d\u0430 \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435:\u0421\u0442\u0435\u043a\u0412\u0440\u0435\u043c\u044fpip + flake8 + black + pytest~45 \u0441\u0435\u043apoetry + flake8 + black + pytest~60 \u0441\u0435\u043auv + ruff + pytest~12 \u0441\u0435\u043a\u0428\u0430\u0433 8. Docker\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 Dockerfile:FROM python:3.13-slim# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c uvCOPY &#8212;from=ghcr.io\/astral-sh\/uv:latest \/uv \/usr\/local\/bin\/uv# \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430WORKDIR \/appCOPY pyproject.toml uv.lock .\/# \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (\u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f Docker layer)RUN uv sync &#8212;no-dev &#8212;frozen# \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434COPY src\/ src\/CMD [&#171;uv&#187;, &#171;run&#187;, &#171;python&#187;, &#171;-m&#187;, &#171;myproject&#187;]\u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442:\u00a0pyproject.toml\u00a0\u0438\u00a0uv.lock\u00a0\u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 \u043a\u043e\u0434\u0430. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 Docker \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0439 \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438. \u0415\u0441\u043b\u0438 \u043a\u043e\u0434 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f, \u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0435\u0442, \u043f\u0435\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442.\u041c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0441 pip\/poetry \u0437\u0430 2 \u043c\u0438\u043d\u0443\u0442\u044b\u0421 requirements.txt# \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442uv init# \u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0437 requirements.txtuv add $(cat requirements.txt)\u0421 poetryuv \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442\u00a0pyproject.toml\u00a0\u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Poetry. \u041f\u0440\u043e\u0441\u0442\u043e:# \u0423\u0434\u0430\u043b\u0438\u0442\u044c poetry.lock, \u0441\u043e\u0437\u0434\u0430\u0442\u044c uv.lockrm poetry.lockuv lockuv sync\u0415\u0441\u043b\u0438 \u0432\u00a0pyproject.toml\u00a0\u0435\u0441\u0442\u044c \u0441\u0435\u043a\u0446\u0438\u044f\u00a0[tool.poetry], uv \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0435\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u0442\u0443\u0434\u0430.\u041f\u043e\u043b\u043d\u044b\u0439 \u0447\u0435\u043a\u043b\u0438\u0441\u0442 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430# 1. \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442uv init myproject &amp;&amp; cd myproject# 2. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438uv add requests pydantic# 3. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c dev-\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438uv add &#8212;dev pytest ruff# 4. \u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434# &#8230;# 5. \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0438 \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044cuvx ruff check &#8212;fix .uvx ruff format .# 6. \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044buv run pytest# 7. \u0413\u043e\u0442\u043e\u0432\u043e\u041f\u044f\u0442\u044c \u043c\u0438\u043d\u0443\u0442. \u041d\u0438\u043a\u0430\u043a\u0438\u0445\u00a0setup.py,\u00a0MANIFEST.in,\u00a0requirements.txt,\u00a0tox.ini,\u00a0.flake8,\u00a0.isort.cfg,\u00a0pyproject.toml\u00a0\u043d\u0430 200 \u0441\u0442\u0440\u043e\u043a.uv + ruff + pyproject.toml = \u0432\u0441\u0451, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f Python-\u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432 2026 \u0433\u043e\u0434\u0443.\u0421\u0441\u044b\u043b\u043a\u0438uv \u043d\u0430 GitHub\u00a0(80k+ \u0437\u0432\u0451\u0437\u0434)ruff \u043d\u0430 GitHub\u00a0(40k+ \u0437\u0432\u0451\u0437\u0434)\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f uv\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f ruffPEP 621: \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 pyproject.toml\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 https:\/\/habr.com\/ru\/articles\/1044550\/<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-482693","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/482693","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=482693"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/482693\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=482693"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=482693"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=482693"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}