Installation and usage#
Packaging and distribution are key aspects of any Python project, and two that
underwent a significant evolution over the last few years.
The bottomline is: you should ship a pyproject.toml
file with your project.
For reference, the one we are distributing with this repository looks like
# See the Python packaging user guide for the ultimate reference on
# pyproject.toml, and more specifically
# https://packaging.python.org/en/latest/specifications/pyproject-toml/
# This section is mandatory in pyproject.toml for any buildable project.
# It specifies what tool(s) are needed to build your package and what
# backend to call for the actual build. hatchling
# https://github.com/pypa/hatch/tree/master/backend
# is a pretty popular choice.
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# This is probably the most important section, and the fields should
# be pretty much self-explaining. A couple of things:
# - declaring "version" as a dynamic field is handy because minimized
# the places where the version string is hard-coded---we shall tell
# hatch a few lines below which file we want to read to the version
# string from;
# - you should list in this section all the dependencies your package
# relies on, so they get automatically installed (if necessary) when
# the package is pip-installed.
[project]
name = "metarep"
dynamic = ["version"]
description = "A repository about making repositories"
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.7"
authors = [
{ name = "Luca Baldini", email = "luca.baldini@unipi.it" }
]
dependencies = [
"numpy",
]
# Optional dependencies are listed here, grouped into logical sections.
# By default (e.g. upon "pip install .") optional dependencies are not
# installed, but they are when you do, e.g., "pip install .[dev]"
[project.optional-dependencies]
dev = [
"pytest",
"ruff",
"pylint",
]
docs = [
"sphinx",
"sphinxawesome-theme",
]
# A few more useful fields...
[project.urls]
Homepage = "https://github.com/lucabaldini/metarep"
Issues = "https://github.com/lucabaldini/metarep/issues"
# Specify the python file that hatchling should read the version string from.
[tool.hatch.version]
path = "src/metarep/_version.py"
# ruff configuration, see
# https://docs.astral.sh/ruff/configuration/
# for the ultimate reference.
# Note we target the oldest Python version that we support, which helps
# in avoiding features that are only available in newer versions.
[tool.ruff]
target-version = "py37"
line-length = 100
src = ["src"]
exclude = ["docs"]
# By default the ruff configuration is fairly minimal, and you might
# want to specifically enable specific useful rules.
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes
"I", # isort (imports)
"B", # flake8-bugbear
"UP", # pyupgrade (kept safe for py37)
"SIM", # flake8-simplify
"C4", # flake8-comprehensions
"NPY", # NumPy-specific best practices
"PERF" # performance gotchas
]
# And, of course, sometimes you want to disable rules that are enabled
# by default.
ignore = [
"C408" # I sometimes like dict() calls better than literal dicts
]
# On the other hand, pylint is fairly noisy by default, and you might
# want to disable some rules.
[tool.pylint.'MESSAGES CONTROL']
disable = [
"missing-docstring",
"too-few-public-methods",
"too-many-arguments",
"too-many-positional-arguments",
"too-many-instance-attributes",
"too-many-locals",
"use-dict-literal",
]
[tool.pylint.'BASIC']
good-names = ["i", "j", "k", "x", "y", "z"]
[tool.pylint.'FORMAT']
max-line-length = 100
pyproject files can be arbitrarily complex, and encompass any sort of meta
information that goes along with your project, but, at the very basic level,
they make your project installable. This means that including a properly
formatted pyproject.toml
file will allow a user to, e.g., pip install
your
package transprently—directly from PyPI, if you have added your package there,
pip install package
or locally at the very minimum
pip install .
This is it. All the files get copied into a place where they can be imported from,
and it is the pyproject.toml
file that makes that possible.
Note
If you have never heard about pip, the pip repo is a good starting point, and also a good example of a non-trivial Python package that you can take as an inspiration for your own endeavors.
Editable installation#
When you develop (as opposed to use) a package, you want to install it in editable mode.
pip install -e .
Invoking pip
with the -e
command-line switch will place a special
link in the proper folder pointing back to you local version of the source
files (instead of copying the source tree) so that you will always see the
last version of the code as you modify it, e.g., in the local copy of your
git repository. Needless to say, it is still the pyproject.toml
file that
makes all the magic.
Note
You can achieve the same result by just making sure that the
PYTHONPATH
environmental variable is pointing to the folder where
your Python modules live, and in fact you might as well do that. That is
not necessarily considered a good practice, as it departs completely
from the installation path of a typical Python package that you use as
a library, but you should still make sure you understand the basic internals
of the Python import system.