English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Detailed Explanation of Packaging and Publishing Python Modules

Introduction

Yesterday, I packaged and uploaded my VASP file processing library to PyPI, and now you can install VASPy directly through pip and easy_install (and welcome VASP users who do computational chemistry to star and participate in it),

VASPy's GotHub address:https://github.com/PytLab/VASPy
VASPy's PyPI address:https://pypi.python.org/pypi/vaspy/

Since my memory is not very good, I am afraid that I will forget it after a long time, so I am taking advantage of the momentum to summarize the packaging and uploading of Python with my own VASPy program as an example.

File structure of VASPy package

Firstly, write the entire file structure of the VASPy package, and the subsequent content is explained by example:

VASPy/
├── LICENSE
├── MANIFEST
├── MANIFEST.in
├── README.rst
├── requirements.txt
├── scripts
│  ├── change_incar_parameters.py
│  ├── create_inputs.py
│  └── ...
├── setup.cfg
├── setup.py
├── tests
│  ├── incar_test.py
│  ├── __init__.py
│  ├── oszicar_test.py
│  ├── outcar_test.py
│  ├── testdata
│  │  ├── CONTCAR
│  │  ├── DOS_SUM
│  │  ├── ELFCAR
│  │  └── ...
│  └── ...
└── vaspy
  ├── __init__.py
  ├── iter.py
  ├── matstudio.py
  └── ...
4 directories, 54 files

Tools for packaging and installing third-party packages

Here we need to use tools like setuptools and pip to package and publish our own packages, and if we need to build a wheel, we also need to install the wheel module. If the Python version is >=2.7.9or >=3.4setuptools and pip are already installed, and may need to be updated to the latest version

pip install -U pip setuptools

You can use package management tools, such as

yum install pip
sudo apt-get install pip

Through get-Installation of pip.py script, if wheel and setuptools are not installed, they will also be automatically installed

python get-pip.py

Specific tool installation and introduction will not be elaborated here, please refer to 'requirements for installing packages'.

The role of different files in the package

setup.py

This file is the most important file for packaging the entire project, providing two main functions:

The setup() function, which specifies how to configure your own project.
Command-line tools, including packaging, testing, and publishing. You can view them with the following command;

python setup.py --help-commands

setup.cfg

This file includes some default parameters for the build process, such as when building bdist_wheel:--The 'universal' parameter

[bdist_wheel]
universal=1

This will default to using it every time the package is packaged--With the 'universal' parameter, the effect is similar:

python setup.py bdist_wheel --universal

README.rst

This was originally written in markdown, but after packaging and releasing it on PyPI, I found that PyPI does not support markdown rendering, and the page was in chaos. Therefore, I re-wrote it using reStructuredText syntax. After all, the syntax of markup languages is generally easy to master, and if not, you can always find a template to copy and paste.
The syntax rules of reStructuredText can be referred to in the official documentation: Quick reStructuredText

In fact, there is another method, which is to use pandoc to convert markdown to rst format. An easier way is to use the pyandoc module to automatically convert it during publication.
You can refer to the specific method: Use Markdown README's in Python modules

MANIFEST.in

This file tells setuptools which additional files need to be packaged during packaging, for example, I use this file to include the test data files of the unit test in VASPy. Of course, README, LICENSE, etc., can also be packaged together using it.
Below is the content of my own MANIFEST.in:

include README.rst
include requirements.txt
include LICENSE
recursive-include scripts *
recursive-include tests *

Specific syntax rules can be referred to: The MANIFEST.in template

vaspy/

This folder is the package where the vaspy source code is located.

tests/

This folder is also a subpackage that contains unit test scripts. To be able to use python setup.py test for unit testing, I specifically added __init__.py to make it a package.

Parameters of setup()

Here, I only introduce several parameters I use, for the specific usage of other parameters, please refer to:https://docs.python.org/3/distutils/setupscript.html

name

versions = "vaspy"

It is the name of the entire project, and it will be used with the version number after packaging.

version

from vaspy import __version__
version = __version__

description

It is a brief description of the project, usually just one sentence, which will be displayed at the bottom of the name on PyPI.

long_description

It is a long description, which is a concise summary of the project. If this string is in rst format, PyPI will automatically render it as HTML for display. You can directly read the content from README.rst.

url

Link to the package, usually a link on GitHub or a link on readthedocs.

packages

List of subpackages to include, setuptools provides find_packages() to help us find packages under the root path, which is a function that distutil does not have.

setup_requires

This parameter defines the other dependencies required for the installation and smooth operation of VASPy (the most basic ones), and these dependencies will be installed when using pip.
For the difference between this parameter and requirements.txt, refer to: install_requires vs Requirements files

classifier

This parameter provides a series of classifications, which will be placed in different directories on PyPI to classify projects.
For the specific names and rules of categories, refer to:https://pypi.python.org/pypi#63;%3Aaction=list_classifiers

test_suite

This parameter can help us use

python setup.py test

No longer need to write a separate script like run_tests.py to run unit tests.
The official explanation of this parameter:

A string naming a unittest.TestCase subclass (or a package or module containing one or more of them, or a method of such a subclass), or naming a function that can be called with no arguments and returns a unittest.TestSuite. If the named suite is a module, and the module has an additional_tests() function, it is called and the results are added to the tests to be run. If the named suite is a package, any submodules and subpackages are recursively added to the overall test suite.

That is to say, this parameter can accept various types of parameters:

Accepts a subclass of unittest.TestCase, we can put all unit tests into a single test case, then import it and pass it to the test_suite.
Accepts a function object, this function object has no parameters and returns a unittest.TestSuite. This allows us to write a single function, merge multiple test cases into a suite, and then return it. After that, we can import the function and pass it to the test_suite.

Module and package names, I use this method. Before, my tests were all separate scripts. By adding a __init__.py, I can turn it into a package. Pass the package name to the test_suite, and setuptools will magically run all tests under this package. In the future, when I add test scripts, I can directly add new scripts without any changes.

Running effect:

zjshao@SHAO-PC:/mnt/d/Dropbox/Code/CentOS_code/VASPy$ python setup.py test
running test
running egg_info
creating vaspy.egg-info
writing vaspy.egg-info/PKG-INFO
writing top-level names to vaspy.egg-info/top_level.txt
writing dependency_links to vaspy.egg-info/dependency_links.txt
writing manifest file 'vaspy.egg'-info/SOURCES.txt'
reading manifest file 'vaspy.egg'-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'vaspy.egg'-info/SOURCES.txt'
running build_ext
test_compare (tests.incar_test.InCarTest)
Make sure we can compare two InCar objects correctly. ... ok
test_eq (tests.incar_test.InCarTest)
Test __eq__() function. ... ok
...
Some outputs are omitted here
----------------------------------------------------------------------
Ran 22 tests in 3.574s
OK

Publish your own Python package

1. First, go to PyPI to register an account

2. Configuration~/.pypirc as follows:

[distutils]
index-servers =
  pypi
  pypitest
[pypi]
username:ShaoZhengjiang
password:mypassword
[pypitest]
username:ShaoZhengjiang
password:mypassword

3Then register and upload your own package to the test server

PyPI provides a test server where we can do tests.

python setup.py register -r pypitest

Then

python setup.py sdist upload -r pypitest

If there are no problems, we should not get any errors.

4Upload to PyPI

If the above test is successful, we can register and upload the package following the same steps.

python setup.py register -r pypi
python setup.py sdist upload -r pypi

Ok, after that we can access PyPI,https://pypi.python.org/pypi/vaspy/On the page we see our own packages.

You May Also Like