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 `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 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+ 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.
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 `_.
77+ * ``pyproject.toml `` file: Provides package metadata and defines how the package
78+ is built. There are different build backends available, such as `setuptools `_,
79+ `poetry `_, and `flit `_.
3180
81+ * ``src/ansys/product/library/__init__.py `` file: Usually contains the
82+ version of the package in a variable named ``__version__ ``. The value of this
83+ variable can be parsed from the ``pyproject.toml `` file so that the version
84+ is only specified in one location.
3285
33- Project Configuration File
34- --------------------------
86+
87+ Additional Directories
88+ ----------------------
89+
90+ The following directories may be specified at the same level as the ``src/ `` one:
91+
92+ * ``tests/ ``: Contains all unit tests for the package. It is
93+ likely that these tests take advantage of the `pytest `_ framework.
94+
95+ * ``doc/ ``: Contain all documentation files and examples on
96+ how to use the package.
97+
98+
99+ Project File and Build System
100+ ------------------------------
35101
36102The ``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
103+ projects. It must contain at least a ``[build-system] `` section, which determines
38104how the project is built. Some commonly used packaging tools are `setuptools `_,
39- `poetry `_, or `flit `_.
105+ `poetry `_, and `flit `_. All three of these packaging tools are currently supported by
106+ the `pyansys template `_.
107+
108+
109+ Flit
110+ ^^^^
40111
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
112+ Flit is a modern and lightweight build system that requires developers
113+ to manage virtual environments on their own. Developers must:
45114
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.
115+ * Create a virtual environment and activate it.
116+ * Install the package in editable mode.
49117
50- To use `poetry `_ as a packaging tool, the ``pyproject.toml `` should contain
118+ Flit is the default tool for creating a new project when using the
119+ `pyansys template `_.
51120
52- .. code :: toml
121+ The ``[project] `` section specifies the project's metadata and required
122+ dependencies. For more information, see the `flit pyproject.toml
123+ guidelines `_.
53124
54- [build-system]
55- requires = ["poetry-core>=1.0.0"]
56- build-backend = "poetry.core.masonry.api"
57125
58- The ``[tool.poetry] `` section contains metadata, and defines the project's dependencies. Refer to the
59- `poetry pyproject.toml documentation `_ for details.
126+ Poetry
127+ ^^^^^^
128+
129+ Poetry is known because of its strong dependency pinning thanks to the
130+ ``poetry.lock `` file. When installing a package, poetry creates a virtual
131+ environment, thus ensuring an isolated package development environment.
132+
133+ It is possible to avoid previous behavior by executing the following command:
134+
135+ .. code :: bash
136+
137+ poetry config virtualenvs.create false --local
138+
139+ Therefore, `poetry `_ may be chosen due to the following reasons:
140+
141+ * It supports pinning dependency versions via a ``poetry.lock `` file, which we
142+ use for testing / CI.
143+ * Downstream packages can still consume a loose dependency specification.
144+ * It integrates with `dependabot `_ to update the pinned version.
145+
146+ The ``[tool.poetry] `` section contains metadata, and defines the project's
147+ dependencies. Refer to the `poetry pyproject.toml documentation `_ for details.
148+
149+
150+ Setuptools
151+ ^^^^^^^^^^
152+
153+ Setuptools is a very well known build system in the Python ecosystem. It is used
154+ in projects requiring a ``setup.py ``. Setuptools can be used with projects using
155+ the ``pyproject.toml `` too, although not all metadata is fully supported yet.
156+
157+ The main advantage of this build system is the ability of creating 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 ``. 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 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,14 +184,26 @@ 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 which enable developers to
191+ write clean code according to different coding style guidelines. Some of these
192+ tools are `black `_, `isort `_, `flake8 `_, `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 `` reducing thus the
196+ amount 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+ ``pyproject.toml `` is not yet fully supported. Instead, it also requires a
202+ ``setup.cfg `` and / or ``setup.py `` file.
203+
204+ In the `pyansys template `, all these configurations are included by default in
205+ the `.pre-commit-config.yaml `, as `pre-commit ` is not able to parse the
206+ ``pyproject.toml `` file neither the ``setup.py `` one.
82207
83208
84209Generate the Package and Upload It on PyPI
@@ -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+ 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+ .. _ pyansys template : https://github.com/pyansys/pyansys- template
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