Skip to content

Commit 38a1ae9

Browse files
committed
Update to pyansys-templates
1 parent 3a7b5cb commit 38a1ae9

File tree

1 file changed

+187
-44
lines changed

1 file changed

+187
-44
lines changed

doc/source/library_description/packaging.rst

Lines changed: 187 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,177 @@
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 `ansys-templates tool`_.
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 with logic source code.
24+
* ``Module``: Any Python script hosted next to an ``__init__.py`` file.
25+
* ``Sub-package``: Any directory containing various Python modules.
26+
* ``Package``: Any directory containing 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 you
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+
Therefore, the source directory of any `PyAnsys library` should look like this:
57+
58+
.. code:: bash
59+
60+
.
61+
└── src
62+
└── ansys
63+
└── product
64+
└── library
65+
└── __init__.py
1566
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.
1867
1968
Required Files
2069
--------------
2170

22-
* README.rst file: Describes the purpose of the package.
71+
* ``README.rst`` file: Describes the purpose of the package.
2372
*The format of this file must be reStructuredText.*
2473

25-
* LICENSE file: Specifies copyrights and required authorization.
74+
* ``LICENSE`` file: Specifies copyrights and required authorization.
2675

27-
* pyproject.toml file: Provides package information.
28-
This file provides the package metadata, and defines how it is built.
29-
There are different build backends available, such as `setuptools`_,
30-
`poetry`_ and `flit`_.
76+
* ``pyproject.toml`` file: Provides package metadata and defines how the package
77+
is built. There are different build backends available, such as `setuptools`_,
78+
`poetry`_, and `flit`_.
3179

80+
* ``src/ansys/product/library/__init__.py`` file: Usually contains the
81+
version of the package in a variable named ``__version__``. The value of this
82+
variable can be parsed from the ``pyproject.toml`` file so that the version
83+
is only specified in one location.
3284

33-
Project Configuration File
34-
--------------------------
85+
86+
Additional Directories
87+
----------------------
88+
89+
The following directories may be specified at the same level as the ``src/`` one:
90+
91+
* ``tests/``: Contains all unit tests for the package. It is
92+
likely that these tests take advantage of the `pytest`_ framework.
93+
94+
* ``doc/``: Contain all documentation files and examples on
95+
how to use the package.
96+
97+
98+
Project File and Build System
99+
------------------------------
35100

36101
The ``pyproject.toml`` file is the standardized build configuration file for Python
37-
projects. It needs to at least contain a ``[build-system]`` section, which determines
102+
projects. It must contain at least a ``[build-system]`` section, which determines
38103
how the project is built. Some commonly used packaging tools are `setuptools`_,
39-
`poetry`_, or `flit`_.
104+
`poetry`_, and `flit`_. All three of these packaging tools are currently supported by
105+
the ``pyansys-advanced`` template, which is included in the `ansys-templates tool`_.
106+
107+
108+
Flit
109+
^^^^
40110

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
111+
Flit is a modern and lightweight build system that requires developers
112+
to manage virtual environments on their own. Developers must:
45113

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.
114+
* Create a virtual environment and activate it.
115+
* Install the package in editable mode.
49116

50-
To use `poetry`_ as a packaging tool, the ``pyproject.toml`` should contain
117+
Flit is the default tool for creating a new ``pyansys`` project when using the
118+
`ansys-templates tool`_.
51119

52-
.. code:: toml
120+
The ``[project]`` section specifies the project's metadata and required
121+
dependencies. For more information, see `flit pyproject.toml
122+
guidelines`_.
53123

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

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

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:
63176

64177
.. code:: python
65178
@@ -71,20 +184,32 @@ section, and add code to ``__init__.py`` which obtains the version from the inst
71184
__version__ = importlib_metadata.version(__name__.replace(".", "-"))
72185
73186
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`_.
187+
Extra Tools Configuration
188+
-------------------------
189+
190+
There are plenty of tools in the Python ecosystem that enable developers to
191+
write clean code according to different coding style guidelines. Some of these
192+
tools are `black`_, `isort`_, `flake8`_, and `mypy`_.
193+
194+
Some of these tools can be configured. This configuration might be specified in
195+
custom files required by the tool or in the ``pyproject.toml`` file, thus reducing the
196+
number of files in the project directory.
77197

78198
.. note::
79199

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.
200+
When using `setuptools`_ as a build backend, providing the metadata in
201+
the ``pyproject.toml`` file is not yet fully supported. Instead, it also
202+
requires a ``setup.cfg`` file, ``setup.py`` file, or both files.
203+
204+
In the `pyansys template`, all these configurations are included by default in
205+
the ``.pre-commit-config.yaml`` file because ``pre-commit`` is not able to parse the
206+
``pyproject.toml`` file nor the ``setup.py`` file.
82207

83208

84209
Generate the Package and Upload It on PyPI
85210
------------------------------------------
86211

87-
The first time that you want to upload a package on PyPI under the `ansys <https://pypi.org/user/ansys/>`_
212+
The first time that you want to upload a package on PyPI under `ansys <https://pypi.org/user/ansys/>`_
88213
account, you must perform the following process manually.
89214

90215
Create the python package.
@@ -94,15 +219,28 @@ Create the python package.
94219
pip install build
95220
python -m build
96221
222+
If using flit or poetry, you can also run:
223+
224+
.. code::
225+
226+
flit build
227+
poetry build
228+
97229
Verify the distribution's long description rendering with ``twine``.
98230

99231
.. code::
100232
101233
pip install twine
102234
twine check dist/*
103235
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.
236+
237+
Upload the package to PyPI using ``twine`` and the upload token generated for
238+
the ``ansys`` PyPI account. As soon as the package has been released for the
239+
first time, it is possible to create an independent token dedicated to this
240+
package. This way the token stored in the GitHub secrets and used in the
241+
release's workflow is only related to that specific package. This limits the
242+
exposure to any potential token security flaws. Contact
243+
[email protected] for the token.
106244

107245
.. code::
108246
@@ -169,12 +307,17 @@ To create a package complying with the above standards, here is the minimal cont
169307
.. _PEP 420: https://www.python.org/dev/peps/pep-0420/
170308
.. _setuptools: https://setuptools.pypa.io
171309
.. _poetry: https://python-poetry.org/docs/
310+
.. _flit pyproject.toml guidelines: https://flit.readthedocs.io/en/latest/pyproject_toml.html
172311
.. _flit: https://flit.readthedocs.io
173312
.. _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
313+
.. _ansys-templates tool: https://github.com/pyansys/pyansys-templates
175314
.. _poetry pyproject.toml documentation: https://python-poetry.org/docs/pyproject/
176315
.. _black: https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file
177316
.. _mypy: https://mypy.readthedocs.io/en/stable/config_file.html#the-mypy-configuration-file
178317
.. _trunk-based development: https://trunkbaseddevelopment.com/
179318
.. _secret: https://docs.github.com/en/actions/reference/encrypted-secrets
180319
.. _setup.py: https://packaging.python.org/tutorials/packaging-projects/#configuring-metadata
320+
.. _importlib.metadata package: https://docs.python.org/3/library/importlib.metadata.html
321+
.. _isort: https://github.com/PyCQA/isort
322+
.. _flake8: https://flake8.pycqa.org/en/latest/
323+
.. _pytest: https://docs.pytest.org/en/latest/

0 commit comments

Comments
 (0)