"Set up and structure Python apps and scripts on Windows: virtual environments, requirements.txt or pyproject.toml, src layout, type hints, logging, CLIs with argparse or Typer, config from env, and running and testing with pytest. Use when the user asks for a Python script, tool, CLI, bot, automation or Python project setup."
Install
npx skillscat add v-groups-foundations/freetoken/python-project Install via the SkillsCat registry.
Python project
Every project gets its own virtual environment, pinned dependencies and a single obvious way to run it.
1. Environment (PowerShell)
python --version # need 3.10+; use `py -3.12` if several are installed
python -m venv .venv
.\.venv\Scripts\Activate.ps1 # if blocked: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
python -m pip install --upgrade pip
python -m pip install requests- Always
python -m pip, so packages go into the active interpreter. - Without activating, call
.\.venv\Scripts\python.exedirectly (reliable for run_app commands). - Add
.venv/,__pycache__/,.env,*.pycto.gitignore. - If the project uses uv (
uv.lockexists):uv sync,uv run python -m app,uv add <pkg>.
2. Dependencies
- Scripts/small apps:
requirements.txtwith versions (requests==2.32.3), created bypython -m pip freeze > requirements.txt(then trim to direct dependencies), installed withpython -m pip install -r requirements.txt. Dev tools inrequirements-dev.txt. - Packages/larger apps:
pyproject.toml:
[project]
name = "invoicer"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = ["typer>=0.12", "httpx>=0.27"]
[project.optional-dependencies]
dev = ["pytest>=8", "ruff>=0.6"]
[project.scripts]
invoicer = "invoicer.cli:app"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build" Install for development: python -m pip install -e ".[dev]".
3. Layout
- Single script:
tool.pywith amain()andif __name__ == "__main__": main(). - App:
src/invoicer/__init__.py,cli.py,core.py(logic, no I/O),config.py,tests/test_core.py.
Run withpython -m invoicer(add__main__.py). Avoidsys.pathhacks.
4. Code quality defaults
- Type hints on function signatures;
from __future__ import annotationsfor older syntax support.
Data containers:@dataclass(or pydantic models when validating external input). pathlib.Pathfor files;encoding="utf-8"on everyopen()(Windows defaults to cp1252).- Format and lint:
python -m pip install ruff, thenruff format .andruff check . --fix. - Handle expected errors with specific exceptions and clear messages; let unexpected ones crash
with a traceback during development. Exit withsys.exit(1)on failure in CLIs.
5. Logging, not print
import logging
log = logging.getLogger(__name__)
def main() -> None:
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s")
log.info("processing %d files", len(files))print only for the CLI's actual output. --verbose flag switches to DEBUG.
6. CLIs
- Standard library:
argparse(no dependency). - Nicer: Typer (
python -m pip install typer):
import typer
app = typer.Typer()
@app.command()
def convert(src: Path, out: Path = Path("out.csv"), dry_run: bool = False) -> None:
"""Convert SRC invoice export to CSV."""
...
if __name__ == "__main__":
app()Help text for every command; sensible defaults; confirm before destructive actions.
7. Config via environment
- Read secrets and settings from env, loaded from
.envwithpython-dotenv(load_dotenv()) orpydantic-settings(class Settings(BaseSettings)). Provide.env.example. - Fail early with a clear message if a required variable is missing.
- PowerShell: set for a session with
$env:API_KEY = "...".
8. Testing
python -m pip install pytest, tests in tests/test_*.py, functions test_*, plain assert.
Use tmp_path for files, monkeypatch for env vars, fixtures for shared setup. Run python -m pytest -q.
Keep logic in pure functions so most tests need no I/O. See the testing skill for more.
Check before you finish
- Fresh install works: new venv,
python -m pip install -r requirements.txt(or-e .), then run. - Run the program on a real example (run_app or the shell) and quote the output.
python -m pytest -qpasses;ruff check .clean if ruff is used.- README or reply states the exact commands to install and run.
Common mistakes
- Installing into the global Python; forgetting to activate the venv in a new shell.
- Unpinned requirements; mixing
pipandpython -m pipfor different interpreters. - Hard-coded absolute Windows paths; files opened without
encoding. - Business logic inside the CLI function, so it cannot be tested.