| |
|
|
| |
|
|
| - Understand modern Python project layouts |
| - Learn about `pyproject.toml` and `pixi.toml` configuration files |
| - Set up proper directory structure for CLI applications |
| - Implement version control best practices |
|
|
| |
|
|
| There are two main approaches to organizing Python projects: |
|
|
| |
|
|
| ``` |
| my-cli/ |
| βββ my_cli/ |
| β βββ __init__.py |
| β βββ cli.py |
| β βββ utils.py |
| βββ tests/ |
| βββ pyproject.toml |
| βββ README.md |
| ``` |
|
|
| |
|
|
| ``` |
| my-cli/ |
| βββ src/ |
| β βββ my_cli/ |
| β βββ __init__.py |
| β βββ cli.py |
| β βββ utils.py |
| βββ tests/ |
| βββ pyproject.toml |
| βββ pixi.toml |
| βββ README.md |
| ``` |
|
|
| **Why src layout?** |
| - Prevents accidental imports from development directory |
| - Clearer separation between source and other files |
| - Better for testing and packaging |
|
|
| |
|
|
| |
|
|
| The modern standard for Python project metadata: |
|
|
| ```toml |
| [build-system] |
| requires = ["hatchling"] |
| build-backend = "hatchling.build" |
|
|
| [project] |
| name = "my-cli-tool" |
| version = "0.1.0" |
| description = "An AI-powered CLI tool" |
| authors = [{name = "Your Name", email = "you@example.com"}] |
| readme = "README.md" |
| requires-python = ">=3.11" |
| dependencies = [ |
| "typer>=0.9", |
| "rich>=13.0", |
| ] |
|
|
| [project.scripts] |
| my-cli = "my_cli.cli:app" |
|
|
| [tool.ruff] |
| line-length = 100 |
| target-version = "py311" |
|
|
| [tool.mypy] |
| python_version = "3.11" |
| strict = true |
| ``` |
|
|
| |
|
|
| Pixi-specific configuration for environment management: |
|
|
| ```toml |
| [project] |
| name = "my-cli-tool" |
| version = "0.1.0" |
| description = "An AI-powered CLI tool" |
| channels = ["conda-forge"] |
| platforms = ["linux-64", "osx-64", "win-64"] |
|
|
| [dependencies] |
| python = ">=3.11" |
| typer = ">=0.9" |
| rich = ">=13.0" |
|
|
| [feature.dev.dependencies] |
| pytest = "*" |
| ruff = "*" |
| mypy = "*" |
| black = "*" |
|
|
| [environments] |
| default = [] |
| dev = ["dev"] |
|
|
| [tasks] |
| start = "python -m my_cli.cli" |
| test = "pytest tests/" |
| lint = "ruff check src/" |
| format = "black src/ tests/" |
| ``` |
|
|
| |
|
|
| Here's a complete, production-ready project structure: |
|
|
| ``` |
| my-cli-tool/ |
| βββ .git/ |
| βββ .gitignore |
| βββ .vscode/ |
| β βββ settings.json |
| βββ src/ |
| β βββ my_cli/ |
| β βββ __init__.py |
| β βββ cli.py |
| β βββ commands/ |
| β β βββ __init__.py |
| β β βββ organize.py |
| β β βββ stats.py |
| β βββ core/ |
| β β βββ __init__.py |
| β β βββ processor.py |
| β βββ utils/ |
| β βββ __init__.py |
| β βββ helpers.py |
| βββ tests/ |
| β βββ __init__.py |
| β βββ conftest.py |
| β βββ test_cli.py |
| β βββ test_core.py |
| βββ docs/ |
| β βββ README.md |
| βββ .gitignore |
| βββ pyproject.toml |
| βββ pixi.toml |
| βββ pixi.lock |
| βββ LICENSE |
| βββ README.md |
| ``` |
|
|
| |
|
|
| Use this script to create the structure: |
|
|
| ```bash |
| |
| |
|
|
| PROJECT_NAME="my-cli-tool" |
| PACKAGE_NAME="my_cli" |
|
|
| |
| mkdir -p $PROJECT_NAME/{src/$PACKAGE_NAME/{commands,core,utils},tests,docs,.vscode} |
|
|
| |
| touch $PROJECT_NAME/src/$PACKAGE_NAME/__init__.py |
| touch $PROJECT_NAME/src/$PACKAGE_NAME/commands/__init__.py |
| touch $PROJECT_NAME/src/$PACKAGE_NAME/core/__init__.py |
| touch $PROJECT_NAME/src/$PACKAGE_NAME/utils/__init__.py |
| touch $PROJECT_NAME/tests/__init__.py |
|
|
| |
| touch $PROJECT_NAME/src/$PACKAGE_NAME/cli.py |
| touch $PROJECT_NAME/README.md |
| touch $PROJECT_NAME/LICENSE |
|
|
| echo "Project structure created!" |
| ``` |
|
|
| Or use pixi to create it: |
|
|
| ```bash |
| |
| pixi init my-cli-tool |
| cd my-cli-tool |
|
|
| |
| pixi add python typer rich |
|
|
| |
| mkdir -p src/my_cli/{commands,core,utils} |
| touch src/my_cli/__init__.py |
| touch src/my_cli/cli.py |
|
|
| |
| mkdir tests |
| touch tests/__init__.py |
| ``` |
|
|
| |
|
|
| Essential patterns for Python projects: |
|
|
| ```gitignore |
| |
| __pycache__/ |
| *.py[cod] |
| *$py.class |
| *.so |
| .Python |
| build/ |
| develop-eggs/ |
| dist/ |
| downloads/ |
| eggs/ |
| .eggs/ |
| lib/ |
| lib64/ |
| parts/ |
| sdist/ |
| var/ |
| wheels/ |
| *.egg-info/ |
| .installed.cfg |
| *.egg |
|
|
| |
| .env |
| .venv |
| env/ |
| venv/ |
| ENV/ |
| env.bak/ |
| venv.bak/ |
|
|
| |
| .pixi/ |
| pixi.lock |
|
|
| |
| .vscode/ |
| .idea/ |
| *.swp |
| *.swo |
| *~ |
|
|
| |
| .pytest_cache/ |
| .coverage |
| htmlcov/ |
|
|
| |
| .DS_Store |
| Thumbs.db |
| ``` |
|
|
| |
|
|
| Initialize Git and make your first commit: |
|
|
| ```bash |
| |
| git init |
|
|
| |
| |
|
|
| |
| git add . |
|
|
| |
| git commit -m "Initial project structure" |
|
|
| |
| gh repo create my-cli-tool --public --source=. --remote=origin |
| git push -u origin main |
| ``` |
|
|
| |
|
|
| |
|
|
| ```python |
| """My CLI Tool - An AI-powered command-line application.""" |
|
|
| __version__ = "0.1.0" |
| __author__ = "Your Name" |
| __email__ = "you@example.com" |
|
|
| |
| from .cli import app |
|
|
| __all__ = ["app"] |
| ``` |
|
|
| |
|
|
| 1. **Use src layout**: Prevents import issues and improves testing |
| 2. **Lock dependencies**: Commit `pixi.lock` for reproducibility |
| 3. **Separate concerns**: Use subdirectories for commands, core logic, and utilities |
| 4. **Write tests early**: Create test files alongside implementation |
| 5. **Document as you go**: Update README with each feature |
| 6. **Use type hints**: Enable better IDE support and catch errors early |
|
|
| |
|
|
| Ask Copilot to help with: |
|
|
| ```python |
| |
| |
| |
| |
| ``` |
|
|
| |
|
|
| With your project structure in place, you're ready to start building your CLI application. In the next chapter, we'll use Typer to create powerful command-line interfaces. |
|
|
| |
|
|
| - [Python Packaging Guide](https://packaging.python.org/) |
| - [Pixi Project Configuration](https://pixi.sh/latest/reference/project_configuration/) |
| - [PEP 518 - pyproject.toml](https://peps.python.org/pep-0518/) |
|
|