22
33Packaging
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- a single, independent distribution.
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
1559
16- Three different approaches are currently available for creating a namespace package:
60+ .
61+ └── src
62+ └── ansys
63+ └── product
64+ └── library
65+ └── __init__.py
1766
18- * `native namespace packages `_
19- * pkgutil-style namespace packages
20- * pkg_resources-style namespace packages
2167
2268 Required Files
2369--------------
2470
25- * README.rst file: Describes the purpose of the package.
71+ * `` README.rst `` file: Describes the purpose of the package.
2672 *The format of this file must be reStructuredText. *
2773
28- * LICENSE file: Specifies copyrights and required authorization.
74+ * `` LICENSE `` file: Specifies copyrights and required authorization.
2975
30- * setup.py file: Provides package information.
31- The presence of this file indicate that the package was likely created using `` disutils `` ,
32- which is the Python standard for building and distributing a Python package .
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 `_ .
3379
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.
3484
35- Setup File
36- ----------
37- The `setup.py `_ file is the build script for ``setuptools ``. It exposes dynamic metadata and contains
38- package information, such as a description, author, and version.
39- In this file, the ``setuptools `` module is used to configure the metadata (as opposed to ``distutils ``).
4085
41- .. code :: python
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+ ------------------------------
100+
101+ The ``pyproject.toml `` file is the standardized build configuration file for Python
102+ projects. It must contain at least a ``[build-system] `` section, which determines
103+ how the project is built. Some commonly used packaging tools are `setuptools `_,
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+ ^^^^
110+
111+ Flit is a modern and lightweight build system that requires developers
112+ to manage virtual environments on their own. Developers must:
113+
114+ * Create a virtual environment and activate it.
115+ * Install the package in editable mode.
116+
117+ Flit is the default tool for creating a new ``pyansys `` project when using the
118+ `ansys-templates tool `_.
119+
120+ The ``[project] `` section specifies the project's metadata and required
121+ dependencies. For more information, see `flit pyproject.toml
122+ guidelines `_.
123+
42124
43- import setuptools
44- setuptools.setup(... )
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.
45175
46- This file gathers all namespace packages and files that must be included in the distributed
47- package.
48176
49177.. code :: python
50178
51- packages = []
52- for package in setuptools.find_namespace_packages(include = ' ansys*' ):
53- if package.startswith(' ansys.tools.example_coverage' ):
54- packages.append(package)
179+ try :
180+ import importlib.metadata as importlib_metadata
181+ except ModuleNotFoundError :
182+ import importlib_metadata
183+
184+ __version__ = importlib_metadata.version(__name__ .replace(" ." , " -" ))
185+
186+
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.
55197
198+ .. note ::
56199
57- It also extracts the version number from the ``_version.py `` file located in the
58- ``ansys/<product>/library `` directory of the source code.
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.
59207
60208
61209Generate the Package and Upload It on PyPI
62210------------------------------------------
63211
64- 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/ >`_
65213account, you must perform the following process manually.
66214
67215Create the python package.
68216
69217.. code ::
70218
71- python setup.py sdist
219+ pip install build
220+ python -m build
221+
222+ If using flit or poetry, you can also run:
223+
224+ .. code ::
225+
226+ flit build
227+ poetry build
72228
73229 Verify the distribution's long description rendering with ``twine ``.
74230
@@ -77,8 +233,14 @@ Verify the distribution's long description rendering with ``twine``.
77233 pip install twine
78234 twine check dist/*
79235
80- Upload the package to PyPI using ``twine `` and the upload token generated for the ``ansys `` PyPI account.
81- 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+ 82244
83245.. code ::
84246
@@ -127,7 +289,7 @@ Install a package with:
127289
128290.. code ::
129291
130- pip install ansys. <product>. <library>
292+ pip install ansys- <product>- <library>
131293
132294 To create a package complying with the above standards, here is the minimal content of your PyAnsys library:
133295
@@ -136,12 +298,26 @@ To create a package complying with the above standards, here is the minimal cont
136298 ansys/<product>/<library>/__init__.py
137299 LICENSE
138300 README.rst
139- setup.py
301+ pyproject.toml
140302 tests/
141303
142304
143305 .. _namespace packaging : https://packaging.python.org/guides/packaging-namespace-packages/
144306.. _native namespace packages : https://packaging.python.org/guides/packaging-namespace-packages/#native-namespace-packages
307+ .. _PEP 420 : https://www.python.org/dev/peps/pep-0420/
308+ .. _setuptools : https://setuptools.pypa.io
309+ .. _poetry : https://python-poetry.org/docs/
310+ .. _flit pyproject.toml guidelines : https://flit.readthedocs.io/en/latest/pyproject_toml.html
311+ .. _flit : https://flit.readthedocs.io
312+ .. _dependabot : https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/about-dependabot-version-updates
313+ .. _ansys-templates tool : https://github.com/pyansys/pyansys-templates
314+ .. _poetry pyproject.toml documentation : https://python-poetry.org/docs/pyproject/
315+ .. _black : https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file
316+ .. _mypy : https://mypy.readthedocs.io/en/stable/config_file.html#the-mypy-configuration-file
145317.. _trunk-based development : https://trunkbaseddevelopment.com/
146318.. _secret : https://docs.github.com/en/actions/reference/encrypted-secrets
147319.. _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