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-commit
Here’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: flake8
GitHub 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 test
Conclusion
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!