diff --git a/README.md b/README.md index 18f17c6..901d6a4 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,11 @@ sites. ## Why packages? When working on your project, you typically end up with some scripts, -functions and classes that are of more general interest. As a first -step, you make some modules, i.e. separate python files, where you -collect this code. These modules can be easily imported from other -scripts in the very same directory. +functions and classes that could be of more general interest. For +example, if you would use this code in some other projects as well. +As a first step, you make some modules, i.e. separate python files, +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` 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 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`. 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 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 packagehowto/ ├── pyproject.toml @@ -100,7 +103,8 @@ is imported. 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 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 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 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 -`__init__.py` file. For example, if you define a `add_four()` function +want to make available in you package could be placed in the +`__init__.py` file. For example, if you define an `add_four()` function in `__init__.py` like this: ``` 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 ``` -(note the `.` in front of `addition`!) you can import `add_two()` -without specifying the module: +(note the `.` in front of `addition` - this makes it a relative +import) you can import `add_two()` without specifying the module: ``` 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`. +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 @@ -173,7 +180,7 @@ README.md LICENSE -pypi.org +[PyPi](https://pypi.org/) ```sh python3 -m build @@ -188,6 +195,66 @@ token ## 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 diff --git a/pyproject.toml b/pyproject.toml index 6a5e295..bb7ef34 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ Documentation = "https://whale.am28.uni-tuebingen.de/git/benda/packagehowto/src/ #numerix = "numerix.numerix:main" [tool.setuptools.dynamic] -version = {attr = "numerix.version.__version__"} +version = {attr = "numerix.__version__"} #[tool.pytest.ini_options] #pythonpath = "src" diff --git a/src/numerix/__init__.py b/src/numerix/__init__.py index cb9977e..170f5db 100644 --- a/src/numerix/__init__.py +++ b/src/numerix/__init__.py @@ -4,6 +4,19 @@ 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 # from the package (e.g. from numerix import add_four): def add_four(x): @@ -25,4 +38,3 @@ def add_four(x): # Functions from the modules of the package can be imported into the # namespace of the package: from .addition import add_two -from .version import __version__ diff --git a/src/numerix/addition.py b/src/numerix/addition.py index 91dcf28..f9530eb 100644 --- a/src/numerix/addition.py +++ b/src/numerix/addition.py @@ -1,6 +1,2 @@ def add_two(x): return x + 2 - - - - diff --git a/src/numerix/numbers.py b/src/numerix/numbers.py index c460463..243a4e0 100644 --- a/src/numerix/numbers.py +++ b/src/numerix/numbers.py @@ -1,5 +1,11 @@ +from .__init__ import __version__ from .addition import add_two + def three(): return add_two(1) + +def about(): + print(f'{__name__} {__version__}') + diff --git a/src/numerix/version.py b/src/numerix/version.py deleted file mode 100644 index 1fbcbc2..0000000 --- a/src/numerix/version.py +++ /dev/null @@ -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 -