package version section

This commit is contained in:
Jan Benda 2024-04-26 22:07:18 +02:00
parent 51b5c67e46
commit 8a9a50346d
6 changed files with 99 additions and 32 deletions

View File

@ -9,10 +9,11 @@ sites.
## Why packages? ## Why packages?
When working on your project, you typically end up with some scripts, When working on your project, you typically end up with some scripts,
functions and classes that are of more general interest. As a first functions and classes that could be of more general interest. For
step, you make some modules, i.e. separate python files, where you example, if you would use this code in some other projects as well.
collect this code. These modules can be easily imported from other As a first step, you make some modules, i.e. separate python files,
scripts in the very same directory. where you collect this code. These modules can be easily imported from
other scripts in the very same directory.
For example, consider a module `addition.py` and a script `analyze.py` For example, consider a module `addition.py` and a script `analyze.py`
both in the same directory: both in the same directory:
@ -46,7 +47,7 @@ people, you need to turn the modules into packages.
First we make a project directory for our new package. Usually the First we make a project directory for our new package. Usually the
name of the project directory is the same as the one of the name of the project directory is the same as the one of the
package. Here, however, we call the proejct directory `packagehowto` package. Here, however, we call the project directory `packagehowto`
and the name of the package `numerix`. and the name of the package `numerix`.
A package is a directory, and the name of the package is the name of A package is a directory, and the name of the package is the name of
@ -57,7 +58,9 @@ What makes this directory a package is the presence of a file named
`__init__.py`. This file is executed when the package is imported. For `__init__.py`. This file is executed when the package is imported. For
now we leave it empty. now we leave it empty.
The package directory resides in the `src/` directory of the project: The package directory resides in the `src/` directory of the
project. The layout of your package project then looks like this:
```txt ```txt
packagehowto/ packagehowto/
├── pyproject.toml ├── pyproject.toml
@ -100,7 +103,8 @@ is imported.
You would need to reinstall the package whenever you change your You would need to reinstall the package whenever you change your
package, for exmple when you add a new function or when you just fix package, for exmple when you add a new function or when you just fix
some package code. This is tedious, and that is why there is a `-e` some package code. This is tedious, and that is why there is a `-e`
option for `pip install`. So install your package with option ("editable install") for `pip install`. So install your package
with
```sh ```sh
pip3 install -e . pip3 install -e .
``` ```
@ -112,8 +116,8 @@ without the need to reinstall the package again.
This file is your package. In fact, you could write a package that This file is your package. In fact, you could write a package that
only has an `__init__.py` file in the package directory. All code you only has an `__init__.py` file in the package directory. All code you
want to make available in you package could be place in the want to make available in you package could be placed in the
`__init__.py` file. For example, if you define a `add_four()` function `__init__.py` file. For example, if you define an `add_four()` function
in `__init__.py` like this: in `__init__.py` like this:
``` ```
def add_four(x): def add_four(x):
@ -131,8 +135,8 @@ it available directly from the package. With this line in `__init__.py`
``` ```
from .addition import add_two from .addition import add_two
``` ```
(note the `.` in front of `addition`!) you can import `add_two()` (note the `.` in front of `addition` - this makes it a relative
without specifying the module: import) you can import `add_two()` without specifying the module:
``` ```
from numerix import add_two from numerix import add_two
``` ```
@ -164,6 +168,9 @@ Note, that the `numbers.py` module imports a function from the
`addition.py` module via a relative import with the `.` in front of `addition.py` module via a relative import with the `.` in front of
`addition`. `addition`.
And of course you can also import this function in `__init__.py` so
that it can be imported from the package directly.
## Distribute your package ## Distribute your package
@ -173,7 +180,7 @@ README.md
LICENSE LICENSE
pypi.org [PyPi](https://pypi.org/)
```sh ```sh
python3 -m build python3 -m build
@ -188,6 +195,66 @@ token
## Package version ## Package version
For uploading your package to [PyPi](https://pypi.org/) you need to
specify a version number in the `pyproject.toml` file. However, your
package should also provide a `__version__` variable. And some
scripts of your package might want to know about the version number
as well when you call them with a `--version' argument.
For the latter two cases, you can define a `__version__` variable in
one of the modules, or even in a dedicated module, that you then
import whereever you need it. Even better is to define it in the
`__init__.py` file:
```
__version__ = '1.4.2'
""" Current version of the numerix package as string 'x.y.z'. """
__year__ = '2024'
""" Year of the current numerix version as string. """
```
Then a script can easily check the package's version like this:
```
from numerix import __version__
print(__version__)
```
Other modules of the package need to import it from the `__init__.py`
file by a relative import to be able to use it:
```
from .__init__ import __version__
def about():
print(f'{__name__} {__version__}')
```
But how do you get the very same version into the `pyproject.toml`
file? It would be a very bad idea to write it there directly and
update it whenever you change it in the `__init__.py` file.
For this you need to specify the `version` field as `dynamic` in the
`[project]` section. This tells the package tool that the version will
be set dynamically by some code. There are several options to do
so. The simplest one is to add a `[tool.setuptools.dynamic]` section
where the version is read as an attribute from the `numerix` package,
that is its `__init__.py`file:
```txt
...
[project]
name = "numerix"
dynamic = ["version"]
...
[tool.setuptools.dynamic]
version = {attr = "numerix.__version__"}
```
## Unit tests ## Unit tests

View File

@ -43,7 +43,7 @@ Documentation = "https://whale.am28.uni-tuebingen.de/git/benda/packagehowto/src/
#numerix = "numerix.numerix:main" #numerix = "numerix.numerix:main"
[tool.setuptools.dynamic] [tool.setuptools.dynamic]
version = {attr = "numerix.version.__version__"} version = {attr = "numerix.__version__"}
#[tool.pytest.ini_options] #[tool.pytest.ini_options]
#pythonpath = "src" #pythonpath = "src"

View File

@ -4,6 +4,19 @@
Fancy numerics made easy. Fancy numerics made easy.
""" """
__version__ = '1.4.2'
""" Current version of the numerix package as string 'x.y.z'. """
__year__ = '2024'
""" Year of the current numerix version as string. """
# Add them to documentation:
__pdoc__ = {}
__pdoc__['__version__'] = True
__pdoc__['__year__'] = True
# Functions defined directly in __init__.py can be imported directly # Functions defined directly in __init__.py can be imported directly
# from the package (e.g. from numerix import add_four): # from the package (e.g. from numerix import add_four):
def add_four(x): def add_four(x):
@ -25,4 +38,3 @@ def add_four(x):
# Functions from the modules of the package can be imported into the # Functions from the modules of the package can be imported into the
# namespace of the package: # namespace of the package:
from .addition import add_two from .addition import add_two
from .version import __version__

View File

@ -1,6 +1,2 @@
def add_two(x): def add_two(x):
return x + 2 return x + 2

View File

@ -1,5 +1,11 @@
from .__init__ import __version__
from .addition import add_two from .addition import add_two
def three(): def three():
return add_two(1) return add_two(1)
def about():
print(f'{__name__} {__version__}')

View File

@ -1,14 +0,0 @@
""" Version and year of the numerix package.
"""
__version__ = '1.4.2'
""" Current version of the numerix package as string 'x.y.z'. """
__year__ = '2024'
""" Year of the current numerix version as string. """
# Add them to documentation:
__pdoc__ = {}
__pdoc__['__version__'] = True
__pdoc__['__year__'] = True