Skip to content

Commit 82215aa

Browse files
committed
Update to pyansys-template
1 parent 822ca74 commit 82215aa

File tree

1 file changed

+183
-39
lines changed

1 file changed

+183
-39
lines changed

doc/source/library_description/packaging.rst

Lines changed: 183 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,178 @@
22

33
Packaging
44
#########
5-
A Python package organizes and structures a Python library, which contains several
6-
modules and assets such as examples or binary extensions. A Python package
7-
offers an easy, reliable, and comprehensive way to distribute and install
8-
a Python library on a variety of platforms and environments.
5+
6+
A Python package organizes and structures a Python library, which contains
7+
several modules and assets such as examples or binary extensions. A Python
8+
package offers an easy, reliable, and comprehensive way to distribute and
9+
install a Python library on a variety of platforms and environments.
10+
11+
.. note::
12+
13+
If you want to create a new PyAnsys project according to the guidelines
14+
presented in the following lines, consider using the `pyansys template`_.
15+
16+
17+
Python scripts, modules, sub-packages and packages
18+
--------------------------------------------------
19+
20+
It is important to understand the difference between Python scripts, modules,
21+
sub-packages and packages:
22+
23+
* ``Script``: any Python file holding logic source code.
24+
* ``Module``: any Python script hosted next to an ``__init__.py`` file.
25+
* ``Sub-package``: any directory holding various Python modules.
26+
* ``Package``: any directory which contains Python modules and sub-packages.
27+
28+
The following structure is shown to better explain previous concepts:
29+
30+
.. code:: bash
31+
32+
.
33+
├── src
34+
│   └── package
35+
│   ├── subpackage_a
36+
│   │   ├── __init__.py
37+
│   │   └── module_c.py
38+
│   ├── __init__.py
39+
│   ├── module_a.py
40+
│   └── module_b.py
41+
├── LICENSE
42+
├── README.rst
43+
└── pyproject.toml
44+
945
1046
Namespace Packaging
1147
-------------------
12-
A PyAnsys library uses `namespace packaging`_.
13-
Namespace packages allow a user to easily split subpackages from a package into
14-
single, independent distributions.
48+
A PyAnsys library uses `namespace packaging`_. Namespace packages allow a user
49+
to easily split sub-packages from a package into single, independent
50+
distributions.
51+
52+
There are different approaches available for creating a namespace package. For
53+
the ``ansys`` namespace, we use the `PEP 420`_ `native namespace packages`_
54+
approach.
55+
56+
Following previous namespace, the source directory of any `PyAnsys library`
57+
should look like this:
58+
59+
.. code:: bash
60+
61+
.
62+
└── src
63+
└── ansys
64+
└── product
65+
└── library
66+
└── __init__.py
1567
16-
There are different approaches available for creating a namespace package. For the
17-
``ansys`` namespace, we use the `PEP 420`_ `native namespace packages`_ approach.
1868
1969
Required Files
2070
--------------
2171

22-
* README.rst file: Describes the purpose of the package.
72+
* ``README.rst`` file: Describes the purpose of the package.
2373
*The format of this file must be reStructuredText.*
2474

25-
* LICENSE file: Specifies copyrights and required authorization.
75+
* ``LICENSE`` file: Specifies copyrights and required authorization.
2676

27-
* pyproject.toml file: Provides package information.
77+
* ``pyproject.toml`` file: Provides package information.
2878
This file provides the package metadata, and defines how it is built.
2979
There are different build backends available, such as `setuptools`_,
3080
`poetry`_ and `flit`_.
3181

82+
* ``src/ansys/product/library/__init__.py`` file: This file usually holds the
83+
version of the package in a variable named ``__version__``. The value of this
84+
variable can be parsed from the `pyproject.toml` file, so it is only specified
85+
in one location.
3286

33-
Project Configuration File
34-
--------------------------
87+
88+
Additional Directories
89+
----------------------
90+
91+
The following directories may be specified at the same level of ``src/`` one:
92+
93+
* ``tests/``: This directory holds all unitary tests of the package. It is
94+
likely that those take advantage of the `pytest`_ framework.
95+
96+
* ``doc/``: A directory devoted to hold all documentation files and examples on
97+
how to use the package.
98+
99+
100+
Project File and Build System
101+
------------------------------
35102

36103
The ``pyproject.toml`` file is the standardized build configuration file for Python
37104
projects. It needs to at least contain a ``[build-system]`` section, which determines
38105
how the project is built. Some commonly used packaging tools are `setuptools`_,
39-
`poetry`_, or `flit`_.
106+
`poetry`_, or `flit`_. All these three build systems are currently supported by
107+
the `pyansys template`_.
108+
109+
110+
Flit
111+
^^^^
40112

41-
We use `poetry`_ as a default choice in the `PyAnsys template`_, for the following reasons:
42-
* it supports pinning dependency versions, which we use for testing / CI
43-
* downstream packages can still consume a loose dependency specification
44-
* it integrates with `dependabot`_ to update the pinned version
113+
It is a modern and lightweight build system. Using this tool requires
114+
developers to manage virtual environments by their own, that is:
45115

46-
Feel free to use any one of the packaging tools mentioned above that best suits
47-
your needs. The advantage of `flit`_ is its simplicity, while `setuptools`_ is most useful
48-
when custom build steps need to be implemented as Python code.
116+
* Creating a virtual environment and activating it.
117+
* Installing the package in editable mode.
49118

50-
To use `poetry`_ as a packaging tool, the ``pyproject.toml`` should contain
119+
This tool is the default one for creating a new project when using the
120+
`pyansys template`_.
51121

52-
.. code:: toml
122+
The ``[project]`` section is used for specifying project's metadata and required
123+
dependencies. More information can be found in the `flit pyproject.toml
124+
guidelines`_.
53125

54-
[build-system]
55-
requires = ["poetry-core>=1.0.0"]
56-
build-backend = "poetry.core.masonry.api"
57126

58-
The ``[tool.poetry]`` section contains metadata, and defines the project's dependencies. Refer to the
59-
`poetry pyproject.toml documentation`_ for details.
127+
Poetry
128+
^^^^^^
129+
130+
Poetry is known because of its strong dependency pinning thanks to the
131+
``poetry.lock`` file. When installing a package, poetry creates a virtual
132+
environment, thus ensuring an isolated package development environment.
133+
134+
It is possible to avoid previous behavior by executing the following command:
135+
136+
.. code:: bash
137+
138+
poetry config virtualenvs.create false --local
139+
140+
Therefore, `poetry`_ may be chosen due to the following reasons:
141+
142+
* It supports pinning dependency versions via a ``poetry.lock`` file, which we
143+
use for testing / CI.
144+
* Downstream packages can still consume a loose dependency specification.
145+
* It integrates with `dependabot`_ to update the pinned version.
146+
147+
The ``[tool.poetry]`` section contains metadata, and defines the project's
148+
dependencies. Refer to the `poetry pyproject.toml documentation`_ for details.
149+
150+
151+
Setuptools
152+
^^^^^^^^^^
153+
154+
Setuptools is a very well known build system in the Python ecosystem. It is used
155+
in projects requiring a ``setup.py``. Setuptools can be used with projects using
156+
the ``pyproject.toml`` too, although not all metadata is fully supported yet.
157+
158+
The main advantage of this build system is the ability of creating custom build
159+
steps in the form of Python code.
160+
161+
162+
Specifying Package Version
163+
--------------------------
164+
165+
It is very common for packages to specify their current version in the
166+
``__version__`` variable. This variable is usually declared in the
167+
``__init__.py`` file included in the ``library`` directory.
168+
169+
However, it is also required to specify the version in the ``pyproject.toml`` or
170+
``setup.py``. This leads to a duplicate declaration of the project's version,
171+
which could lead to a potential mismatch between both.
172+
173+
Therefore, a good practice is to take advantage of the `importlib.metadata package`_,
174+
for parsing the version from package metadata. This guarantees no mismatch
175+
between both version declarations.
60176

61-
Since poetry cannot automatically determine a package's version, we instead specify it in the ``[tool.poetry]``
62-
section, and add code to ``__init__.py`` which obtains the version from the installation metadata:
63177

64178
.. code:: python
65179
@@ -71,14 +185,26 @@ section, and add code to ``__init__.py`` which obtains the version from the inst
71185
__version__ = importlib_metadata.version(__name__.replace(".", "-"))
72186
73187
74-
Where supported, we aim to put all tooling-related configuration into ``pyproject.toml``.
75-
For example, it can also be used to configure the code formatter `black`_ or the static
76-
type checker `mypy`_.
188+
Extra Tools Configuration
189+
-------------------------
190+
191+
There are plenty of tools in the Python ecosystem which enable developers to
192+
write clean code according to different coding style guidelines. Some of these
193+
tools are `black`_, `isort`_, `flake8`_, `mypy`_...
194+
195+
Some of these tools can be configured. This configuration might be specified in
196+
custom files required by the tool or in the ``pyproject.toml`` reducing thus the
197+
amount of files in the project directory.
77198

78199
.. note::
79200

80-
When using `setuptools`_ as a build backend, providing the metadata in ``pyproject.toml`` is not yet fully supported.
81-
Instead, it also requires a ``setup.cfg`` and / or ``setup.py`` file.
201+
When using `setuptools`_ as a build backend, providing the metadata in
202+
``pyproject.toml`` is not yet fully supported. Instead, it also requires a
203+
``setup.cfg`` and / or ``setup.py`` file.
204+
205+
In the `pyansys template`, all these configurations are included by default in
206+
the `.pre-commit-config.yaml`, as `pre-commit` is not able to parse the
207+
``pyproject.toml`` file neither the ``setup.py`` one.
82208

83209

84210
Generate the Package and Upload It on PyPI
@@ -94,15 +220,28 @@ Create the python package.
94220
pip install build
95221
python -m build
96222
223+
If using flit or poetry, you can also run:
224+
225+
.. code::
226+
227+
flit build
228+
poetry build
229+
97230
Verify the distribution's long description rendering with ``twine``.
98231

99232
.. code::
100233
101234
pip install twine
102235
twine check dist/*
103236
104-
Upload the package to PyPI using ``twine`` and the upload token generated for the ``ansys`` PyPI account.
105-
Contact [email protected] for the token.
237+
238+
Upload the package to PyPI using ``twine`` and the upload token generated for
239+
the ``ansys`` PyPI account. As soon as the package has been released for the
240+
first time, it is possible to create an independent token dedicated to this
241+
package. This way the token stored in the GitHub secrets and used in the
242+
release's workflow is only related to that specific package. This limits the
243+
exposure to any potential token security flaws. Contact
244+
[email protected] for the token.
106245

107246
.. code::
108247
@@ -169,12 +308,17 @@ To create a package complying with the above standards, here is the minimal cont
169308
.. _PEP 420: https://www.python.org/dev/peps/pep-0420/
170309
.. _setuptools: https://setuptools.pypa.io
171310
.. _poetry: https://python-poetry.org/docs/
311+
.. _flit pyproject.toml guidelines: https://flit.readthedocs.io/en/latest/pyproject_toml.html
172312
.. _flit: https://flit.readthedocs.io
173313
.. _dependabot: https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/about-dependabot-version-updates
174-
.. _PyAnsys template: https://github.com/pyansys/template
314+
.. _pyansys template: https://github.com/pyansys/pyansys-template
175315
.. _poetry pyproject.toml documentation: https://python-poetry.org/docs/pyproject/
176316
.. _black: https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file
177317
.. _mypy: https://mypy.readthedocs.io/en/stable/config_file.html#the-mypy-configuration-file
178318
.. _trunk-based development: https://trunkbaseddevelopment.com/
179319
.. _secret: https://docs.github.com/en/actions/reference/encrypted-secrets
180320
.. _setup.py: https://packaging.python.org/tutorials/packaging-projects/#configuring-metadata
321+
.. _importlib.metadata package: https://docs.python.org/3/library/importlib.metadata.html
322+
.. _isort: https://github.com/PyCQA/isort
323+
.. _flake8: https://flake8.pycqa.org/en/latest/
324+
.. _pytest: https://docs.pytest.org/en/latest/

0 commit comments

Comments
 (0)