Introduction
Whenever I want to start a new Python project, I used to go for the standard venv included with Python. But, I easily got rid of it, since the folder it creates makes my editor too clumsy.
Afterwards, I discovered Pipenv and I was very happy with it, until I figured out that it doesn’t work well with some packages (e.g. colorama), since it specifies the platform type in the Pipfile.lock file, that I always add to my .gitignore file. Recently I looked for a solution to this cross-platform issue, that’s when I found out that people are suggesting using Poetry, a tool which I already heard about, but never took time to give it a chance.
I finally gave Poetry a chance that day, and from that point, Poetry became my best friend.
In my first blog post, I’ll take you through my Python Setup.
Poetry
Installing poetry
Poetry is a Python packaging and dependency management tool that assists you during the entire development process, from installing dependencies, code packaging, to publishing your code.
Powershell
(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -Bash
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -Verify that the installation was successful by running
poetry --version.
Poetry lifecycle
1. Project setup
poetry new blueprint
The above command will ask you for meta infos related to the project (version, authors, license…), then a new directory will be created with the following content:
blueprint
├── pyproject.toml # contains dependencies, project metadata and more
├── README.rst
├── blueprint
│ └── __init__.py
└── tests
├── __init__.py
└── test_blueprint.py
2. Add dependencies
In order to install a dependency, you need to run the following command:
poetry add <package>
If you’d like to add the dependency as a dev dependency, you can use the --dev (-D) flag:
poetry add -D <dev-package>
3. Export requirements.txt file
This command generates a requirements.txt file containing all the dependencies you’ve added to your project.
poetry export -f requirements.txt --output requirements.txt
If you want to export the dev dependencies too, you can use the --dev flag:
poetry export -f requirements.txt --dev --output requirements_dev.txt
Poe the Poet
Poe is a task runner plugin that runs with Poetry, allowing you to run tasks in Poetry’s virtual environment. It can be added to projects using different ways, but I prefer adding it a dev dependency.
poetry add --dev poethepoet
Tasks are defined withing the pyproject.toml file:
# pyproject.toml
[tool.poe.tasks]
[tool.poe.tasks.format]
help = "Run black on the code base"
cmd = "black ."And can be run using the following command:
poe format # or `poetry run poe format` if outside poetry shell
Code Editor
My editor of choice is Visual Studio Code and I use it to develop all my projects.
This is a list of the Python related extensions I use in my editor:
- Python’s official extension: Includes IntelliSense using Pylance, Linting, Jupyter Notebooks, code formatting, refactoring, unit tests …
- Python Test Explorer: I’ve been struggling with unit tests discovery on Windows, and this extension helps me to run them.
- Python Environment Manager: This extension gives a full overview on Python environments.
- autoDocstring: This extension helps me to generate docstrings for my code, all I have to do is type
"""and the extension will generate the docstring for me. - Sourcery: An awesome Python refactoring tool.
- Tabnine and GitHub Copilot: Cause who doesn’t like AI writing code for them?
Code formatting and linting
For code formatting, I use black and for linting, I use flake8 or pylint.
Unit testing
I admit it, I rarely write tests for my code (cause my code never fails 😎), but on serious projects I use pytest with pytest-cov for code coverage, plus pytest-mock mocking fixtures.
With poe, I can run tests with coverage using the following command:
poe test
# pyproject.toml
[tool.poe.tasks]
[tool.poe.tasks.test]
help = "Run pytest on the code base"
cmd = "pytest -v --cov=src --cov-report=term"Pre-commit hooks
Before publishing my code to GitHub, I always have to re-check my code for linting, formatting, security issues… and I use pre-commit to do that.
It can be installed using the following command:
poetry add --dev pre-commitHere’s a sample of the .pre-commit-config.yaml configuration file:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-added-large-files
- id: detect-private-key
- repo: https://github.com/psf/black
rev: 22.1.0
hooks:
- id: black
language_version: python3.8
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.9
hooks:
- id: flake8GitHub actions
The entire pipeline of my projects is managed by GitHub Actions, here’s the CI configuration for my projects:
name: Check Code
on:
push:
branches: [ main ] # on push to main
paths-ignore:
- '*.md' # ignore .md files changes
pull_request:
branches: [ main ] # on pull requests to main
paths-ignore:
- '*.md' # ignore .md files changes
jobs:
ci:
strategy:
max-parallel: 2
matrix:
python-version: [3.8, 3.9]
poetry-version: [1.1.13]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
steps:
- name: Check out repository code
uses: actions/checkout@v2
# Setup Python (faster than using Python container)
- name: Setup Python ${{ matrix.python-version }} on ${{ matrix.os }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install wheel
run: python -m pip install wheel
- name: Install poetry ${{ matrix.poetry-version }}
uses: abatilo/actions-poetry@v2.0.0
with:
poetry-version: ${{ matrix.poetry-version }}
- name: Cache Poetry virtualenv
uses: actions/cache@v2
id: cache
with:
path: ~/.virtualenvs
key: poetry-${{ hashFiles('**/poetry.lock') }}-py${{ matrix.python-version }}-os${{ matrix.os }}
restore-keys: |
poetry-${{ hashFiles('**/poetry.lock') }}-py${{ matrix.python-version }}-os${{ matrix.os }}
- name: Config Poetry
run: |
poetry config virtualenvs.in-project false
poetry config virtualenvs.path ~/.virtualenvs
- name: Install Dependencies using Poetry
run: poetry install
if: steps.cache.outputs.cache-hit != 'true'
- name: Check for security issues
run: poetry run poe bandit
- name: Run test suite
run: poetry run poe testConclusion
There are many libraries and tools that can be added to the list such as bandit, autoflake, make, Docker, etc. But I’ll let those for another day.
I made a GitHub repo that I use as a template for my Python projects, give it a try and let me know what you think!
Finally, I’d like to wish you all Ramadan Mubarak! Hope you liked my first blog post!