Skip to main content
Knowing Python syntax is only half the picture. The other half is knowing how to actually run a project day to day: how to start a new one cleanly, how to add packages without breaking other projects, how to debug when things go wrong, and how to keep your configuration files honest. This page gives you the practical workflow you will use every single day.

Initialising a new project

Managing multiple Python versions

Different projects often need different Python versions. uv handles this transparently:
uv writes the pinned version to .python-version. Commit this file so every contributor uses the same interpreter. If you work with many Python versions regularly, pyenv is an alternative that works independently of uv.

Running scripts

Always run scripts from the project root directory using the -m flag. This guarantees that your package is on sys.path and that relative paths in your code resolve correctly.
If you double-click a .py file or run python src/weather_analysis/main.py from the wrong directory, your imports will likely fail. The -m flag plus running from the project root is the single habit that prevents 90% of path errors.

Adding a new feature — end-to-end workflow

Here is the workflow you will follow every time you add a new capability to your project:
1

Create a new module

Add a new file for the feature’s logic. Keep it focused — one clear responsibility per file.
2

Write the functions and add a test

Create the corresponding test file immediately — not after everything is working.
Run the tests:
3

Import the new module in main.py

Wire the new feature into your entry point once you are satisfied with the tests.
4

Update pyproject.toml if you added a dependency

If the new feature uses a third-party package, record it properly:
Never assume a package is “already there”. Document every dependency you use.

Updating dependencies

Always run your test suite after updating dependencies. A minor version bump in a library can introduce breaking changes. Run pytest before committing updated lock files.

Reading error tracebacks effectively

Python tracebacks look intimidating but follow a consistent pattern. Read them from the bottom up — the last line is the actual error, and the lines above it are the call stack that led there.
Your reading checklist:
  1. What is the error type? (ZeroDivisionError, KeyError, TypeError …)
  2. What is the error message? (often tells you exactly what went wrong)
  3. Which file and line number is at the bottom of the stack? (that is where to fix it)
  4. Work upward through the call stack to understand why the bad value arrived there

Debugging workflow

Quick debugging with print statements

For simple problems, print is fast and requires no setup:
Remove print debugging before committing. Use the logging module for persistent diagnostic output instead:

VS Code debugger

For harder bugs, the VS Code debugger lets you pause execution and inspect any variable without modifying your code.
1

Set a breakpoint

Click in the gutter (left of the line numbers) on the line where you want execution to pause. A red dot appears.
2

Start the debugger

Press F5, or open the Run & Debug panel (Ctrl+Shift+D / ⇧⌘D) and click Run and Debug. Choose Python File.
3

Inspect variables

When execution pauses at your breakpoint, hover over any variable to see its value, or expand the Variables panel on the left. Use the toolbar buttons to step over, step into, or continue.
Create a .vscode/launch.json to configure the debugger for your project:

Keeping pyproject.toml tidy

Your pyproject.toml is the source of truth for your project. Keep it honest:
Install dev dependencies separately so they do not ship in your production environment:

Weather Data Analysis Project

Apply everything you have learned by building a real weather analysis tool