setuptools — правило для Cursor: что делает и как установить
Направляет ИИ-ассистента на сборку современных Python-пакетов через декларативный pyproject.toml и структуру src/.
.cursor/rules/setuptools.mdcЧто делает setuptools
Правило заставляет Cursor следовать современным стандартам упаковки Python-библиотек без устаревшего setup.py. Оно требует выносить весь исполняемый код в каталог src/ и настраивать метаданные в pyproject.toml по спецификациям PEP 517 и PEP 518.
Внутри зафиксированы инструкции по автоматическому управлению версиями через Git-теги с помощью setuptools-scm, разделению обычных зависимостей от опциональных блоков вроде dev и docs, а также регистрации консольных скриптов в [project.scripts].
Любые новые консольные команды или плагины станут доступны в терминале только после повторного запуска pip install -e ., даже в режиме редактируемой установки.
Какие задачи решает
- настроить структуру Python-пакета с каталогом src/
- перенести метаданные из setup.py в декларативный pyproject.toml
- настроить автовычисление версий из Git-тегов через setuptools-scm
- объявить зависимости и консольные команды в секции project.scripts
Примеры запросов агенту
- Сгенерируй pyproject.toml для новой утилиты с консольной командой и поддержкой setuptools-scm
- Реорганизуй текущий проект на структуру с каталогом src/ и опциональными зависимостями для тестов
- Добавь точку входа CLI в секцию project.scripts и покажи команду для переустановки в editable-режиме
Как установить setuptools
Вручную: положить файлы
.cursor/rules/setuptools.mdcВо frontmatter: description, globs, alwaysApply
Вручную: положить файлы
.claude/rules/setuptools.mdПоле paths во frontmatter ограничивает файлы: globs из источника → paths
AGENTS.md
Codex читает AGENTS.md: вставьте текст правила туда
Вручную: положить файлы
.github/instructions/setuptools.instructions.mdПоле applyTo задаёт, к каким файлам применять: globs из источника → applyTo
Вручную: положить файлы
.devin/rules/setuptools.mdВручную: положить файлы
.clinerules/setuptools.mdПо шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules
Вопросы о setuptools
Как установить setuptools в Cursor?
Сохраните файл правила в репозитории по пути .cursor/rules/setuptools.mdc.
Зачем это правило требует структуру каталогов src/?
Каталог src/ изолирует рабочий код пакета от корневых тестов и файлов проекта, предотвращая случайный импорт локальных модулей в обход установленной сборки.
Как настроить автоматическое обновление версий пакета?
Укажите dynamic = ["version"] в блоке [project] и подключите setuptools-scm в требованиях таблицы [build-system].
Исходный текст
setuptools.mdc · CC0-1.0
---
description: This guide defines best practices for configuring Python packages using setuptools, emphasizing modern, declarative `pyproject.toml` workflows for robust and maintainable projects.
globs: **/*.py
---
# setuptools Best Practices
`setuptools` is the de-facto standard for Python packaging. This guide outlines the definitive, modern approach to configuring your Python projects, prioritizing declarative `pyproject.toml` files, automated versioning, and clear dependency management. Adhere to these rules for consistent, maintainable, and standards-compliant package distributions.
## 1. Code Organization and Structure
Always use the `src/` layout for your package source code. This clearly separates your package's importable code from project-level files (like `pyproject.toml`, `README.md`, `tests/`).
❌ BAD: Flat layout
```
my_package/
├── __init__.py
├── module.py
├── pyproject.toml
└── tests/
```
✅ GOOD: `src/` layout
```
my_package/
├── src/
│ └── my_package/
│ ├── __init__.py
│ └── module.py
├── pyproject.toml
├── README.md
└── tests/
```
## 2. Declarative Configuration in `pyproject.toml`
Configure all project metadata and build settings declaratively in `pyproject.toml`. This aligns with PEP 517/518, enables isolated builds, and makes your package metadata machine-readable without executing code. Avoid `setup.py` for metadata.
**Always include `[build-system]` and `[project]` tables.**
```toml title="pyproject.toml"
[build-system]
requires = ["setuptools>=61", "setuptools-scm>=8"]
build-backend = "setuptools.build_meta"
[project]
name = "my-awesome-package"
dynamic = ["version"] # Managed by setuptools-scm
description = "A short description of my awesome package."
readme = "README.md"
requires-python = ">=3.8"
license = { file = "LICENSE" }
authors = [
{ name = "Your Name", email = "[email protected]" },
]
keywords = ["python", "utility", "example"]
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
[project.urls]
Homepage = "https://github.com/yourusername/my-awesome-package"
Documentation = "https://my-awesome-package.readthedocs.io/"
Repository = "https://github.com/yourusername/my-awesome-package"
[tool.setuptools]
package-dir = {"" = "src"} # Essential for src/ layout
[tool.setuptools_scm]
write_to = "src/my_package/_version.py" # Optional: writes version to a file
```
## 3. Version Management with `setuptools-scm`
Derive your package version directly from VCS (Git) tags using `setuptools-scm`. This eliminates manual version bumps and ensures your package version always reflects your repository state.
1. **Declare `setuptools-scm`** in `build-system.requires`.
2. **Set `dynamic = ["version"]`** in `[project]`.
3. **Configure `[tool.setuptools_scm]`** (optional, but recommended for `write_to`).
❌ BAD: Manual version in `pyproject.toml` or `__init__.py`
```toml
# pyproject.toml
[project]
version = "0.1.0" # ❌ BAD: Requires manual updates
```
✅ GOOD: Dynamic versioning with `setuptools-scm`
```toml title="pyproject.toml"
[build-system]
requires = ["setuptools>=61", "setuptools-scm>=8"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
dynamic = ["version"] # ✅ GOOD: Version derived from Git tags
[tool.setuptools_scm]
# Optional: write the version to a file for runtime access
write_to = "src/my_package/_version.py"
```
## 4. Dependency Declaration
Manage all dependencies declaratively in `pyproject.toml`.
* **`dependencies`**: For runtime dependencies.
* **`optional-dependencies`**: For optional dependencies (e.g., `dev`, `test`, `docs`).
❌ BAD: `dependency_links` or `requirements.txt` for runtime dependencies
```toml
# pyproject.toml
[project]
# ❌ BAD: dependency_links is deprecated.
# ❌ BAD: requirements.txt is for application environments, not libraries.
```
✅ GOOD: `dependencies` and `optional-dependencies`
```toml title="pyproject.toml"
[project]
dependencies = [ # ✅ GOOD: Runtime dependencies
"requests~=2.30",
"rich>=13.0.0",
]
[project.optional-dependencies] # ✅ GOOD: Optional dependencies
dev = [
"pytest>=7.0",
"pytest-cov",
"black",
"isort",
"mypy",
"setuptools-scm[toml]>=8", # Include setuptools-scm for dev installs
]
docs = [
"sphinx",
"furo",
]
```
## 5. Entry Points for Scripts and Plugins
Expose console scripts, GUI entry points, or plugin APIs using the `[project.scripts]` and `[project.entry-points]` tables. This is the standard way to create discoverable extensions and command-line tools.
```toml title="pyproject.toml"
[project.scripts] # ✅ GOOD: Console scripts
my-cli = "my_package.cli:main"
[project.gui-scripts] # ✅ GOOD: GUI scripts
my-gui = "my_package.gui:start_app"
[project.entry-points."my_package.plugins"] # ✅ GOOD: Custom plugin entry points
plugin_a = "my_package.plugins:PluginA"
plugin_b = "my_package.plugins:PluginB"
```
## 6. Resource Files and Namespace Packages
Bundle non-code assets (e.g., templates, data files) cleanly using `package_data`. For larger projects, use native namespace package support (PEP 420).
```toml title="pyproject.toml"
[tool.setuptools.package-data]
"my_package" = ["data/*.json", "templates/*.html"] # ✅ GOOD: Include specific data files
```
For namespace packages, simply omit `__init__.py` from the parent directory and ensure `setuptools` is configured to find them (e.g., via `package-dir` for `src/` layout).
```
src/
└── my_namespace/
├── my_package_a/
│ └── __init__.py
└── my_package_b/
└── __init__.py
```
## 7. Development Workflow
Always use a virtual environment. For local development, install your package in "editable" mode to reflect source changes instantly.
```bash
# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate # On Unix/macOS
# .venv\Scripts\activate # On Windows
# Install your package in editable mode with dev dependencies
pip install -e ".[dev]" # ✅ GOOD: Editable install for live code changes
```
**Pitfall**: Entry points (scripts, plugins) are only discoverable *after* the package is installed (even in editable mode). If you add a new entry point, you might need to re-run `pip install -e .` for it to register.
## 8. Building and Publishing
Generate standard distribution packages (wheels and source distributions) using `build`, and upload them securely with `twine`.
```bash
# Ensure build and twine are installed in your dev environment
pip install build twine
# Clean any previous builds
rm -rf dist/ build/ *.egg-info/
# Build distributions
python -m build # ✅ GOOD: Creates .whl and .tar.gz in dist/
# Upload to TestPyPI (always test here first!)
twine upload --repository testpypi dist/* # ✅ GOOD: Secure upload
# Upload to PyPI
twine upload dist/*
```
## 9. Type Hints
While not `setuptools`-specific, consistently apply type hints throughout your Python codebase. This improves code readability, maintainability, and enables static analysis tools to catch errors early. `setuptools` itself does not dictate type hint usage, but a well-packaged project is a well-typed project.
```python
# ✅ GOOD: Use type hints for clarity and static analysis
def calculate_sum(a: int, b: int) -> int:
return a + b
```
## 10. Custom Build Logic (When Absolutely Necessary)
If you *must* perform custom build steps (e.g., compiling C extensions, generating code), `setup.py` is still the place for imperative logic. However, keep it minimal and ensure it only handles build-time operations, not metadata.
```python title="setup.py"
# ❌ BAD: Defining metadata here. Use pyproject.toml instead.
# from setuptools import setup
# setup(name='my_package', version='0.1.0', ...)
# ✅ GOOD: Minimal setup.py for custom build logic (e.g., C extensions)
from setuptools import setup, Extension
my_extension = Extension(
'my_package.my_c_module',
sources=['src/my_package/my_c_module.c'],
)
setup(
ext_modules=[my_extension],
)
```
**Note**: Even for extensions, much can be configured in `pyproject.toml` directly with `setuptools`'s `[tool.setuptools.extensions]` table. Only resort to `setup.py` if truly complex, imperative logic is required.
© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc