Skip to content

Commit

Permalink
Merge pull request #14 from johnnymillergh/feature/poetry-refactoring…
Browse files Browse the repository at this point in the history
…-dec-29-2024

feat(Poetry): build with Poetry
  • Loading branch information
johnnymillergh authored Jan 5, 2025
2 parents 92e0995 + cbc7701 commit 32e9910
Show file tree
Hide file tree
Showing 96 changed files with 2,790 additions and 2,469 deletions.
7 changes: 3 additions & 4 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
**

# ... except for dependencies and source
!Pipfile
!Pipfile.lock
!python_boilerplate
!setup.cfg
!pyproject.toml
!poetry.lock
!src/
20 changes: 11 additions & 9 deletions .github/actions/project-environment-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@ description: Setup project environment
runs:
using: "composite"
steps:
- name: Install Poetry
shell: bash
run: pipx install poetry==1.8.5
# The actions/cache step below uses this id to get the exact python version
- id: setup-python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.12"
python-version: "3.12.2"
architecture: x64
# https://github.com/actions/setup-python/blob/main/docs/advanced-usage.md#caching-packages
cache: "pipenv"
cache: "poetry"
# https://github.com/actions/cache/blob/main/examples.md#python---pipenv
- uses: actions/cache@v3
- id: cache-pipenv
uses: actions/cache@v3
with:
path: ~/.local/share/virtualenvs
key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }}
- name: Install Dependencies with pipenv
key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-poetry-${{ hashFiles('poetry.lock') }}
- name: Install Dependencies with Poetry
if: steps.cache-pipenv.outputs.cache-hit != 'true'
shell: bash
run: |
pip install pipenv
pipenv install --quiet --deploy --dev
run: poetry install --with test
2 changes: 1 addition & 1 deletion .github/workflows/publish-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Publish docker image

on:
push:
tags: "*"
tags: ["*"]

jobs:
docker:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: Python CI with pipenv
name: Python CI with Poetry

on:
pull_request: {}
pull_request:
types: [opened, reopened]
push:
branches:
- 'main'
Expand Down Expand Up @@ -32,37 +33,37 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/project-environment-setup
- run: pipenv run isort --recursive --diff .
- run: pipenv run black --check .
- run: pipenv run flake8
- run: poetry run ruff check .
- name: Install mypy types
run: |
yes | pipenv run mypy --install-types \
yes | poetry run mypy --install-types \
|| test $? -eq 2 && echo "Installed mypy types successfully" \
|| echo "Failed to install mypy types"
- run: pipenv run mypy
- run: poetry run mypy
- name: Python Tests with pytest
run: env LOG_LEVEL=INFO pipenv run pytest --quiet --cov --cov-report term -n auto --benchmark-disable
run: env LOG_LEVEL=INFO poetry run pytest --quiet --cov --cov-report term -n auto --benchmark-disable
- name: Python Benchmark with pytest
run: env LOG_LEVEL=ERROR pipenv run pytest --capture=no --log-cli-level=ERROR -n 0 --benchmark-only
run: env LOG_LEVEL=ERROR poetry run pytest --capture=no --log-cli-level=ERROR -n 0 --benchmark-only
pyinstaller-smoke-test:
needs: static-code-analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ./.github/actions/project-environment-setup
- name: Build Application Executable Package with PyInstaller
run: |
pipenv run pyinstaller --windowed --noconsole \
--add-data "setup.cfg:." \
--add-data "python_boilerplate/resources/*:python_boilerplate/resources" \
poetry run pyinstaller --windowed --noconsole \
--add-data "pyproject.toml:." \
--add-data "src/python_boilerplate/resources/*:python_boilerplate/resources" \
--name multithread_and_thread_pool_usage \
--clean --noconfirm python_boilerplate/demo/multithread_and_thread_pool_usage.py
--clean --noconfirm src/python_boilerplate/demo/multithread_and_thread_pool_usage.py
- name: Display Built Artifacts
run: |
du -s -h *
- name: Smoke Test PyInstaller Application
run: ./dist/multithread_and_thread_pool_usage/multithread_and_thread_pool_usage
docker-smoke-test:
needs: static-code-analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -82,13 +83,13 @@ jobs:
- uses: ./.github/actions/project-environment-setup
- name: Check Versions of Python Packages
run: |
output=$(pipenv run pip list --outdated)
output=$(poetry run pip list --outdated)
if [ -z "$output" ]
then
echo "🎉 Congrats! Everything is up-to-date"
else
echo "⚠️ Attention! Outdated dependencies detected"
echo "$output"
fi
echo "Pipfile"
cat Pipfile
echo "pyproject.toml"
cat pyproject.toml
30 changes: 0 additions & 30 deletions .github/workflows/twitter-together.yml

This file was deleted.

48 changes: 17 additions & 31 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,58 +19,44 @@ repos:
- id: check-case-conflict
- repo: local
hooks:
- id: autoflake
name: autoflake
- id: poetry-check
name: Poetry Check
stages: [ commit ]
language: system
entry: pipenv run autoflake
types: [ python ]
args:
- "--in-place"
- "--expand-star-imports"
- "--remove-duplicate-keys"
- "--remove-unused-variables"
- id: isort
name: isort
stages: [ commit ]
language: system
entry: pipenv run isort
types: [ python ]
- id: black
name: black
stages: [ commit ]
language: system
entry: pipenv run black
types: [ python ]
- id: flake8
name: flake8
language: python
entry: poetry check
pass_filenames: false
files: ^(.*/)?(poetry\.lock|pyproject\.toml)$
- id: ruff-format
name: Ruff Check and Fix
stages: [ commit ]
language: system
entry: pipenv run flake8
# Ruff checks and fixes Python code for both /src and /tests directories
entry: poetry run ruff check .
types: [ python ]
exclude: setup.py
args:
- "--fix"
- id: mypy
name: mypy
stages: [ commit ]
language: system
entry: pipenv run mypy
entry: poetry run mypy
types: [ python ]
require_serial: true
- id: pytest
name: pytest
name: Pytest Unit Tests
stages: [ commit ]
language: system
# https://github.com/pytest-dev/pytest/issues/5502#issuecomment-1020761655
# Prevent Pytest logging error like: ValueError: I/O operation on closed file.
entry: env LOG_LEVEL=DEBUG pipenv run pytest --cov --cov-report html --html=./build/.pytest_report/report.html --self-contained-html --log-cli-level=DEBUG -n auto --benchmark-disable
entry: env LOG_LEVEL=DEBUG poetry run pytest --cov --cov-report html --html=./build/.pytest_report/report.html --self-contained-html --log-cli-level=DEBUG -n auto --benchmark-disable
types: [ python ]
pass_filenames: false
- id: pytest-cov
name: pytest
name: Pytest with Coverage
stages: [ push ]
language: system
# https://github.com/pytest-dev/pytest/issues/5502#issuecomment-1020761655
# Prevent Pytest logging error like: ValueError: I/O operation on closed file.
entry: env LOG_LEVEL=ERROR pipenv run pytest --cov --cov-fail-under=90 --capture=no --log-cli-level=ERROR -n auto
entry: env LOG_LEVEL=ERROR poetry run pytest --cov --cov-fail-under=90 --capture=no --log-cli-level=ERROR -n auto
types: [ python ]
pass_filenames: false
114 changes: 89 additions & 25 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,40 +1,104 @@
FROM python:3.12-slim AS base
# syntax=docker/dockerfile:1
# Keep this syntax directive! It's used to enable Docker BuildKit

# Setup env
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONFAULTHANDLER 1
# Based on https://github.com/python-poetry/poetry/discussions/1879?sort=top#discussioncomment-216865
# Inpired by https://gist.github.com/usr-ein/c42d98abca3cb4632ab0c2c6aff8c88a
# but I try to keep it updated (see history)

FROM base AS python-deps
################################
# PYTHON-BASE
# Sets up all our shared environment variables
################################
FROM python:3.12.2-slim AS python-base

# Install pipenv and compilation dependencies
RUN pip install pipenv
# Setup env for Python
ENV PYTHONUNBUFFERED=1 \
# prevents python creating .pyc files
PYTHONDONTWRITEBYTECODE=1 \
\
# pip
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \
\
# poetry
# https://python-poetry.org/docs/configuration/#using-environment-variables
POETRY_VERSION=1.8.5 \
# make poetry install to this location
POETRY_HOME="/opt/poetry" \
# make poetry create the virtual environment in the project's root
# it gets named `.venv`
POETRY_VIRTUALENVS_IN_PROJECT=true \
# do not ask any interactive question
POETRY_NO_INTERACTION=1 \
\
# paths
# this is where our requirements + virtual environment will live
PYSETUP_PATH="/opt/pysetup" \
VENV_PATH="/opt/pysetup/.venv"

# prepend poetry and venv to path
ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"

################################
# BUILDER-BASE
# Used to build deps + create our virtual environment
################################
FROM python-base AS builder-base
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc \
&& apt-get clean
&& apt-get install --no-install-recommends -y \
# deps for installing poetry
curl \
# deps for building python deps
build-essential

# install poetry - respects $POETRY_VERSION & $POETRY_HOME
# The --mount will mount the buildx cache directory to where
# Poetry and Pip store their cache so that they can re-use it
RUN --mount=type=cache,target=/root/.cache \
curl -sSL https://install.python-poetry.org | python3 -

RUN poetry --version

# copy project requirement files here to ensure they will be cached.
WORKDIR $PYSETUP_PATH
COPY poetry.lock pyproject.toml ./

# install runtime deps - uses $POETRY_VIRTUALENVS_IN_PROJECT internally
RUN --mount=type=cache,target=/root/.cache \
poetry install --no-interaction --no-root --without test

# Install python dependencies in /.venv
COPY Pipfile .
COPY Pipfile.lock .
RUN PIPENV_VENV_IN_PROJECT=1 pipenv install --quiet --deploy
################################
# DEVELOPMENT
# Image used during development / testing
################################
FROM python-base AS development
WORKDIR $PYSETUP_PATH

FROM base AS runtime
# copy in our built poetry + venv
COPY --from=builder-base $POETRY_HOME $POETRY_HOME
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH

# Copy virtual env from python-deps stage
COPY --from=python-deps /.venv /.venv
ENV PATH="/.venv/bin:$PATH"
# quicker install as runtime deps are already installed
RUN poetry install

# Create and switch to a new user
# RUN useradd --create-home appuser
# will become mountpoint of our code
WORKDIR /app
# USER appuser

# Install application into container
COPY . .
################################
# PRODUCTION
# Final image used for runtime
################################
FROM python-base AS production
COPY --from=builder-base $PYSETUP_PATH $PYSETUP_PATH
COPY . /app/
WORKDIR /app/src

RUN pwd
RUN ls -l -h
# Show the project module in the current directory. e.g.
# total 4.0K
# drwxr-xr-x 11 root root 4.0K Jan 1 12:59 python_boilerplate
RUN ls -lh

# Run the executable
ENTRYPOINT ["python", "-m", "python_boilerplate"]
Expand Down
Loading

0 comments on commit 32e9910

Please sign in to comment.