Writing Your Packages - Part 2
In the last episode we explained why we might want to make our own packages. We selected Python
as a language for this series as we will be writing software to facilitated FEniCS
simulations. In this episode we will take a look at the outline of the acoupy_meshutil
and acoupy_helmholtz
packages. We will not go into the details of creating Python
packages. For more information about that you can see Hosting Python Packages on Git Repositories. Instead, we will explain the basic outline of the packages.
What to Package?
How do we decide what to put in a package? Why some sets of Python
modules should be in a package and others not? Whilst meant for the design of operating systems the Unix Philosophy offers good guidelines on this. For our goals we can summarise as follows:
- Write packages that do one thing and do it well;
- Write packages to work together;
In this series we are aiming to write a set of packages to handle the Helmholtz equation. We could have had all the code to import meshes into the acoupy_helmholtz
package. But maybe one day we will write a package for the Linearized Navier-Stokes equation. If we put the mesh input-output code into the acoupy_helmholtz
package we will have to write it again. Or use acoupy_helmholtz
as a dependency, which will result in loads of unnecessary code being a dependency too.
Since handling meshes is a well defined substep of any FEM problem it is best to put it into its own package. Then, we will be able to write any other solver to take as input meshes as transformed by our mesh reading utility. That is: we will write our packages to split the task in parts and work together.
Sometimes it is hard to predict which segments of your problem are not tightly coupled to the problem itself. You can always split a package into more packages as you progress into the development. In general, if some code deals with a part of a problem that is general enough to apply to other problems, then it most likely deserves a package.
Anatomy of a Python
Package
We will give only a brief outline, mainly with the information you need to quickstart. For more information refer to Hosting Python Packages on Git Repositories.
A Python
package, as a bare minimum, has some source code and a setup.py
file. By taking acoupy_meshutil
as an example, we could organise the minimum package as follows:
acoupy_meshutil/
├── acoupy_meshutil/
└── setup.py
The acoupy_meshutil
subfolder (under the root folder which is also called acoupy_meshutil
) contains the source code. The source code consists of one or more Python
modules and a (eventually blank) __init__.py
file. setup.py
contains the package definition. Below it is a snapshot of it at the time of writing to act as an example:
import setuptools
# Read the README.md file to add it to the long_description attribute below
with open('README.md', 'r', encoding='utf-8') as fh:
long_description = fh.read()
setuptools.setup(
name='acoupy_meshutil',
version='0.0.1',
author='Stefano Tronci',
author_email='stefano.tronci@protonmail.com',
description='Utilities for meshes.',
long_description=long_description,
long_description_content_type='text/markdown',
url='https://gitlab.com/acoupy/acoupy_meshutil',
packages=setuptools.find_packages(),
classifiers=[
'Programming Language :: Python :: 3',
'Operating System :: OS Independent',
],
python_requires='>=3.6',
install_requires=[
'numpy',
'meshio',
'h5py'
],
extras_require={
'doc': ['Sphinx!=5.2.0.post0', 'sphinx-rtd-theme']
},
package_data={
'acoupy_meshutil': [
'data/meshes/med/mid_spherecut_m.med'
]
},
)
Most of it should be self explanatory: the file defines basic properties about the package. Perhaps, the most important arguments are:
name
: to specify the name of your package. Make sure it is unique (no other package anywhere, especially on PyPI has the same name);python_requires
: to specify thePython
version our package needs;install_requires
: to specify which packages our package depends on;extras_require
: to specify optional additional dependencies for our package.
In addition, our package can contain data, listed under package_data
.
If you look into acoupy_meshutil
you will see that the package has some more goodies in it, such as a doc
folder for Sphinx
documentation, a README
, a LICENSE
and a .gitlab-ci.yml
file for Continuous Integration. The .gitlab-ci.yml
file in particular could be interesting as it shows how to setup a FEniCS
equipped Ubuntu
virtual machine for GitLab CI/CD. In this example the .gitlab-ci.yml
file builds and serves the Sphinx
documentation. All of these elements are optional: to get started you only need a subfolder and a setup.py
file. However, it is much better to provide at least a README
and a LICENSE
to your software, so that it is clear how your code can be used. This both from a legal standpoint (LICENSE
) and a practical one by providing some minimal documentation in README
.
Installing the Package
Every time a setup.py
is provided, and the package is hosted on a git
repository, installation is very easy with pip
. In your python environment just do:
pip install git+<clone_with_https_url>
Where <clone_with_https_url>
is the URL shown in the Clone
tab of GitLab (any other git
host will have a similar option to display the URL):

Figure 1
The Clone URL in GitLab.
pip install git+https://gitlab.com/acoupy/acoupy_meshutil.git
It is also possible to install by using the Clone with SSH
option. See Hosting Python Packages on Git Repositories | Installing Your Package for more information.
Sometimes the installation of your package will have some caveats. This is the case for both acoupy_meshutil
and acoupy_helmholtz
, which need some preparation of your Python
environment before you can successfully pip install
them. This is why having a README
is very good: you can document these steps for yourself as well as others in there.
Most of your packages will probably have a very similar structure. In fact, this is also the structure of acoupy_helmholtz
. However, more complex things are possible, such as packages written in some other language (for example C++
) with Python
wrappers.
Conclusion
In this episode we discussed the basic outline of a Python
package. We also discussed how we should go around packaging our tools. In the next episodes we will show how these packages operate, starting from acoupy_meshutil
.
License Information

This work is licensed under a Creative Commons Attribution 4.0 International License.