Manage Python dependencies with Poetry and Github Actions

Learn how to clean up your Python code

Alt text

General

As I'm digging deeper into the python stack I came across some awesome tools like PyRight for static type checking, Ruff for Linting and Formating, Poetry for Dependency Management and Github Actions as CI/CD Pipeline to validate my Github Repository. So in this blog article I build a very simply Python Game with the Ursina Engine and use Poetry and Github Actions to clean up my Code.

Ursina Engine

First I will create a virtual environment and install Ursina Engine. Then I create my game and run it. It's just a FirstPersonController that walks on a plane.

virtualenv -p python3 .venv #I prefer virtualenv over python3 -m venv .
source .venv/bin/activate
pip install ursina
code main.py
python main.py

Notice how I purposely put a wrong indentation behind ground that pyright will recognise.

main.py

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController

app = Ursina()

player = FirstPersonController()
    ground = Entity(model="plane", collider="box", scale=64, texture="grass", texture_scale=(4, 4))

app.run()

Poetry

Now we install Poetry, Ruff and Pyright to manage our Python project. Poetry is very useful cause you can use the config file not only to validate that the project uses the right packet version but also to create linting rules and so on.


We will create a Poetry config file called pyproject.toml and add our packages to the file. You can also ignore some warnings. We also create a file called poetry.toml to tell Poetry that we are using a venv. Here are the commands that I used:

pip install ruff
pip install pyright #pylint but opensource
pip install poetry
code pyproject.toml
code poetry.toml
python --version #to manually add the version to your pyproject.toml
poetry add ursina #automatically adds the current version to your pyproject.toml
poetry add pyright --group dev #developer tool dependancy
poetry run pyright #check syntax errors
poetry add ruff --group dev #formatter and linter
poetry run ruff format #formatter
poetry run ruff check --fix #linter

The name main comes from our main.py file.

pyproject.toml

[tool.poetry]
name = "main"
version = "0.1.0"
description = "My first game"
authors = [
"arvednet",
"someone",
]

readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10.12"
ursina = "^7.0.0"

[tool.poetry.group.dev.dependencies]
pyright = "^1.1.388"
ruff = "^0.7.3"

[tool.pyright]
venvPath = "."
venv = ".venv"

reportWildcardImportFromLibrary = false
ignore = ["assets/test.py"]

[tool.ruff]
line-length = 120

[tool.ruff.format]
indent-style = "tab"
line-ending = "lf"

[tool.ruff.lint]
ignore = ["E402", "F405", "F403"]

poetry.toml

[virtualenvs]
in-project = true

If everything worked poetry run ruff check --fix should show All checks passed! after you fixed the indentation error.

Github Actions

Github Actions is a CI/CD Pipeline to continously test your code. We will create a Ruff and Poetry pipeline.


We have to create a .github/workflows directory in our github repository and create two files called ruff.yml and poetry.yml.


Here we will declare which official github actions repositories we want to use to test our code.


.github/workflows/ruff.yml

name: Check formatting and linting

on: push

jobs:
  check_formatting:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/ruff-action@v1
        with:
          args: 'format --check'

  check_linting:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/ruff-action@v1

.github/workflows/poetry.yml

name: main

on: push

jobs:
  ci:
    runs-on: ubuntu-20.04
    env:
      POETRY_VIRTUALENVS_IN_PROJECT: true
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - uses: abatilo/actions-poetry@v2
      - name: Install dependencies and build Cython extension
        run: poetry install --no-root
      - name: Rebuild the project
        run: poetry build
      - name: Cache venv created by poetry (configured to be in '.venv')
        uses: actions/cache@v3
        with:
          path: ./.venv
          key: venv-${{ runner.os }}-${{ hashFiles('poetry.lock') }}
      - name: Run pyright
        run: poetry run pyright

Last we create a nice README.md and push our repository to github. Put the third ' behind console in this README.md if you copy/paste it.

README.md

# My first game

A preview of the game:

[<img alt = "My first game" src = "https://i.imgur.com/rZpWJV9.png" width = 25% />](https://i.imgur.com/rZpWJV9.png)

This is my first game:

- Its main purpose is to show how we configure Poetry and the `pyproject.toml` file for better dependency management, and add a formatter and a linter as well as a CI setup to check all this.
- But of course the game is playable. You can walk around in a 3D world :).

## Installing dependencies

Using [Poetry](https://python-poetry.org/):

``console
poetry install
``

If you ever need to rebuild them, you can do:

``console
poetry build
``

## Running

Using Poetry:

``console
poetry run python main.py
``


Great if everything worked you will have a green mark now with successful tests!

Alt text

Here is the Repository. You can clone it and use poetry install to install the dependencies of the game. Check out this video which basically sums up this blog article.