Installation¶
There are two things necessary for a good Python package installation. First,
the setup.cfg
and/or setup.py
files which control the installation of the package itself.
This is needed, if you want to create your package and use it like a pip
installed package. The other thing is the environment.yml
which is used to
set up the environment for the installation. For this small project, the
environment.yml
is using a sledgehammer to crack a nut. We will still want to
keep it here for completeness.
Actual installation¶
Having all these corner stones in place, we simply need to install it. This is simply done by the following line of code.
# Install your package
pip install -e .
The -e
simply let’s you modify the package without having to reinstall it
all the time. So, testing of the package can be done with every change of the
source files even though there is no re-installation. Note that this is only
necessary for packages that you install from the source code and plan on
modifying!
setup.cfg
¶
In newer installations, the setup.cfg
replaces parts of the setup.py
or, in many cases, even the whole file. Here, we define all the options that
we want setuptools.setup()
to use when executing:
pip install -e .
First, let’s have a look at the file in our project:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | [metadata]
# replace with your username:
name = htmapp
version = 0.0.4
author = Lucas Sawade, Peter Makus
author_email = lsawade@princeton.edu
description = How to make a Python package.
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/lsawade/how_to_make_a_python_package
project_urls =
Documentation = https://how-to-make-a-python-package.readthedocs.io/en/latest/
TravisCI = https://travis-ci.com/github/lsawade/how_to_make_a_python_package
classifiers =
Programming Language :: Python :: 3
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Operating System :: OS Independent
keywords = Fun, Education, Learning, Programming
[options]
package_dir =
= src
packages = find:
python_requires = >=3.6
install_requires = numpy
tests_require = pytest
zip_safe = False
[options.extras_require]
docs =
sphinx
sphinx-rtd-theme
tests = pytest; py
[options.entry_points]
console_scripts =
sample-bin = matpy.bins.sample_bin:main
[options.packages.find]
where = src
|
Most of the defined options are quite self-explanatory.
[options.packages.find]
where = src
defines where the package is located. Typically, we have a src
folder that
contains the whole package. This line changes the import structure so that we
can later run import matpy
instead of import src.matpy
. For a list of
all available parameters and their correct syntax check out the
setuptools documentation.
Scripts argument¶
The scripts argument lets you create executables that are installed upon
running the installation. For example, in the directory bins
(binaries,
which are not technically binaries in this case, but used in the same way as
traditional binary files), there is the executable sample-bin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #!/usr/bin/env python
from matpy import MatrixMultiplication
import numpy as np
import logging
# Use this to set the logger to different levels.
logger = logging.getLogger("matpy")
def main():
# Set up tests arrays
a = np.array([[1, 2],
[3, 4]])
b = np.array([[2, 3, 5],
[4, 5, 6]])
# Use class and function call
M = MatrixMultiplication(a, b, method='matmul')
c = M()
print("C:")
print(c)
if __name__ == "__main__":
main()
|
It is normal Python code, but after installation
pip install -e .
you can simply run
sample-bin
from anywhere on your computer, which will run the python command sample_bin()
. Do make sure that this filenames do not
conflict with your traditional command line tools such as ls
, cd
, etc.
Otherwise you won’t be able to use your created executables.
setup.py
¶
In some cases, you might still want to include a setup.py
which used
to be the old standard way. One of those cases is if you would like to be
able to use the -e
(editable) pip install
command. Then, you would
just include a minimal setup.py
containing the following:
from setuptools import setup
# configuration is done in setup.cfg
setup()
A second use-case of the setup.py
is illustrated in our sample file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | """ :noindex:
Setup.py file that governs the installatino process of
`how_to_make_a_python_package` it is used by
`conda install -f environment.yml` which will install the package in an
environment specified in that file.
"""
from setuptools import setup
from setuptools.command.test import test as testcommand
# This installs the pytest command. Meaning that you can simply type pytest
# anywhere and "pytest" will look for all available tests in the current
# directory and subdirectories recursively (not yet supported in the setup.cfg)
class PyTest(testcommand):
user_options = [('pytest-args=', 'a', "Arguments to pass to py.tests")]
def initialize_options(self):
testcommand.initialize_options(self)
self.pytest_args = []
def run_tests(self):
import pytest
import sys
errno = pytest.main(self.pytest_args)
sys.exit(errno)
setup(cmdclass={'tests': PyTest})
|
Here, we add the cmdclass
keyword, which is not supported by the
setup.cfg
(at least, at the time of writing). After package installation,
when you in the repository, a simple
pytest
will check all subdirectories for tests and run them subsequently. It is amazing for debugging your code. A third case is for more advanced dynamic installs, in which we wish to compile our module differenly depending upon which machine it is installed on (e.g., different OS or architecture).
environment.yml
¶
This one is mainly to set up an environment and install dependencies there, so that you main Python installation stays untouched and cannot be broken. The general structure looks as follows:
1 2 3 4 5 6 7 8 9 10 | name: htmapp
dependencies:
- python=3.8
- numpy
- pip
- pip:
- sphinx
- sphinx-rtd-theme
- pytest
- -e .
|
name
specifies the name of the environment to be created, and pip
defines extra packages that possibly aren’t available from the conda package
manager. And additional setting that is often used, but we are skipping here are
channels
, which are online locations from where to grab the dependencies
when they are installed with conda (a typical example is conda-forge).
The file is pretty straightforward, so I’m gonna stop talking about it now.
To create an environment from the environment.yml
file simply execute the following:
conda env create -f environment.yml