Skip to content

Setting Up Python in a Workflow


Every workflow you write from here on starts with the same two moves: get the code onto the runner, then get an interpreter ready to run it. You already know how to do the first part. This chapter covers the second — turning a bare GitHub-hosted runner into a machine that actually has Python on it.

Why The Runner Doesn’t Already Have The Python You Want

GitHub-hosted runners ship with a handful of Python versions pre-installed, but you can’t rely on “whatever happens to be there” for two reasons. First, the default python3 on the runner image can change between GitHub’s image updates without warning. Second, your project may need a specific version — maybe you’re testing against 3.13 specifically, or you need to guarantee the same version your teammates run locally.

actions/setup-python solves this by downloading and installing the exact version you ask for, then pointing python and pip at it for every step that follows.

Adding setup-python To A Workflow

Here’s the minimum shape:

- name: Setup Python
  uses: actions/setup-python@v7
  with:
    python-version: "3.13"

That’s it — one action, one required input. After this step runs, every subsequent run: step in the same job has python and pip available at version 3.13, no matter what the runner image shipped with by default.

Note

setup-python has to run after actions/checkout, but it doesn’t actually depend on your code being present — it just installs an interpreter. The ordering matters more for later steps (installing dependencies, running tests) that assume both the code and the interpreter are ready.

Verifying What Landed On The Runner

Don’t take the version string on faith — print it. A cheap sanity-check step saves you from debugging a mismatch three steps later:

- name: Confirm Python Version
  run: python --version

Run this once while you’re setting a workflow up for the first time, then you can leave it in permanently — it’s nearly free and it shows up right in the log, which is useful the day someone changes the python-version input and forgets to check the result.

Pinning Exact Versions Vs Minor Versions

The python-version input accepts more than one format:

ValueWhat You Get
"3.13"Latest patch release of 3.13 available at run time (e.g. 3.13.7)
"3.13.2"That exact patch version, if available
"3.x"Latest 3.x release overall

For most projects, pinning to a minor version ("3.13") is the right default — you get bug fixes and security patches automatically, without your CI silently jumping to Python 4 someday. Pin the exact patch version only when you have a specific reason to freeze it (reproducing a bug tied to a patch release, for example).

Tip

Whatever you choose here, use the same version locally. A workflow that passes on 3.13 in CI but was written and tested against 3.11 on your machine is a trap waiting to spring.

Hands-On: Adding The Workflow

From the previous lesson, you’ve got the project to learn Building Real CI Pipelines checked out locally, with the send_file.py / receive_file.py pair and its tests/ folder. Time to give it a real CI workflow.

Create the workflow file:

mkdir -p .github/workflows
cat > .github/workflows/ci.yml << 'EOF'
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v7

      - name: Setup Python
        uses: actions/setup-python@v7
        with:
          python-version: "3.13"

      - name: Confirm Python Version
        run: python --version
EOF

Commit and push it:

git add .github/workflows/ci.yml
git commit -m "Add CI workflow: checkout and setup Python"
git push

Open the Actions tab for your repo. You should see the workflow run, and the “Confirm Python Version” step’s log should print something like Python 3.13.7. That confirms the whole chain worked: the runner spun up, checked out your code, installed the interpreter you asked for, and ran a command against it.

This workflow doesn’t do anything useful with your project yet — it just proves the ground floor is solid. The next chapter builds on this exact file, adding the step that installs the project’s real dependency: pytest.

Last updated on