diff --git a/README.md b/README.md index ad67e49..464af7e 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ to install them, how to upload them, how to maintain them, how to work with them. For details consult https://packaging.python.org, or https://py-pkgs.org, or other sites. +Before you create a package please consider building a [virtual +environment](./venv.md) for your project. ## Why packages? @@ -17,12 +19,14 @@ other scripts in the very same directory. For example, consider a module `addition.py` and a script `analyze.py` both in the same directory: + ```txt ├── addition.py └── analyze.py ``` In `addition.py` we define a function `add_two()`: + ``` def add_two(x): return x + 2 @@ -30,6 +34,7 @@ def add_two(x): We can use this function in `analyze.py` by importing it from `addition.py`: + ``` from addition import add_two @@ -42,7 +47,6 @@ directory (or if modules are in sub-directories). To make modules available in other places of your file system or even for other people, you need to turn the modules into packages. - ## Minimal package First we make a project directory for our new package. Usually the @@ -87,16 +91,20 @@ on your machine and import it from wherever you want. To install the project, go to the project root, here `packagehowto/` and run from your shell + ```sh pip3 install . ``` + This installs the package of the current project folder `.` somewhere in your home directory. From anywhere in your home file system you now can import this package. The import line of our `analyze.py` file needs to look like this: + ``` from numerix.addition import add_two ``` + From the addition module of the numerix package the function add_two is imported. @@ -105,13 +113,14 @@ 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 ("editable install") for `pip install`. So install your package with + ```sh pip3 install -e . ``` + Then all future changes on your package are immediately available without the need to reinstall the package again. - ## The `__init__.py` file This file is your package. In fact, you could write a package that @@ -119,11 +128,14 @@ only has an `__init__.py` file in the package directory. All code you 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): return x + 4 ``` + then it can be imported directly from the package: + ``` from numerix import add_four ``` @@ -132,34 +144,41 @@ Alternatively, you can define all your functions in module files, like we did with the function `add_two()` in the `addition.py` module. In the `__init__.py` file you can import this function and this way make it available directly from the package. With this line in `__init__.py` + ``` from .addition import add_two ``` + (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 ``` - ## Multiple modules within a package You can have as many modules as you need in your package. Let's add a module `numbers.py` to the `numerix` package + ```txt └── numerix ├── __init__.py ├── addition.py └── numbers.py ``` + with the following content: + ``` from .addition import add_two def three(): return add_two(1) ``` + This makes a function `three()` available that can be imported via + ``` from numerix.numbers import three ``` @@ -171,7 +190,6 @@ Note, that the `numbers.py` module imports a function from the And of course you can also import this function in `__init__.py` so that it can be imported from the package directly. - ## Versioning Your package needs a version number (for details see below). But how to @@ -187,7 +205,6 @@ by a dot. These numbers are incremented in the following way: - `minor`, when functionality is added in a backwards-compatible manner, and - `patch`, for backwards-compatible bug fixes. - ## Package version For uploading your package to [PyPi](https://pypi.org/) you need to @@ -233,7 +250,7 @@ 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. The version number should be set only in one place. -This is possible, of course. You need to specify the `version` field +This is possible, of course. 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 @@ -272,18 +289,21 @@ python3 -m twine upload dist/* token +## Using `poetry` + +You have now seen how you can do everything "from scratch". This is of course +good to know. But there are tools to significantly simplify package creation +and management, such as [`poetry`](https://python-poetry.org/). Its worth +checking it out. Heres a nice demo: https://python-poetry.org/docs/basic-usage/ ## Unit tests pytest coverage + ```sh pytest -v --cov-report html --cov numerix tests/ ``` ## Documentation - - - - diff --git a/venv.md b/venv.md new file mode 100644 index 0000000..1d7e584 --- /dev/null +++ b/venv.md @@ -0,0 +1,111 @@ +# Why and how to use virtual environments? + +## What is a virtual environment? + +- A venv is **seperated** from your system packages / software, such as + firefox, thunderbird, etc. +- Packages that are installed cannot talk to system packages and vice versa -> + you know what you use because you have to explicitly install **all** packages + that your project requires. +- They can be build and destroyed easily and quickly to test different versions + of packages (or even python itself!). + +## How to build a `venv`? + +- PEP405 (=python style guide) virtual environments should be named "venv" or ".venv". + +To create one, run: + +```sh +python -m venv # e.g. venv or .venv +``` + +You should now see a new directory in your current working directory called "venv" or ".venv". + +To activate it, run this on linux or macos: + +```sh +source /bin/activate +``` + +On windows, you can run + +```sh +.//Scripts/Activate.ps1 +``` + +You should now see an indicator in your shell prompt such as: + +```sh +(venv) user@host:~/path/to/your/project +``` + +It is active as long as you do not explicitly deactivate it or close the shell. +You can now `pip install ` as you normally would. +To check which python version it uses, you can run this on linux/macos: + +```sh +which python3 && which pip +``` + +Both paths should point to your virtual environment in the project directory. + +To deactivate, simply run on linux/macos/windows: + +```sh +deactivate +``` + +What we have now seen all comes with python but there are tools that make this +more convenient: What if you also want to try another pyhton version? Or use +the same venv in multiple projects? For this, there is `pyenv`: + +### `venv` pitfalls + +- You cannot move or rename **any** directory inside the path to your project + directory or the `venv` breaks. You can rename a folder _inside_ the project + directory as long as you dont change the path to the venv. +- You cannot use the venv for multiple projects + +`pyenv` fixes this: + +## Using [`pyenv`](https://github.com/pyenv/pyenv.git) / [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv.git) + +Use pyenv for managing python versions and pyenv-virtualenv for a slightly +easier way of interacting with venvs. + +To download another python version (without destroying your system), simply run: + +```sh +pyenv install python3.12 +``` + +To see which versions are installed, you can run + +```sh +pyenv versions +``` + +To set this version as the default in a specific directory (and all its subdirectories), run: + +```sh +pyenv local 3.12 +``` + +Now you can either use the tutorial above to create a standard venv or use `pyenv-virtualenv` like this: + +```sh +pyenv virtualenv 3.12 +``` + +Now you can activate it by `pyenv activate ` or use it as the standard in the current and subdirectories with + +```sh +pyenv local +``` + +The convenient thing is, that this venv will always be automatically activated +when you enter the directory. If you do this in multiple directories, you can +have the same venv for multiple projects. + +There are some alternatives to `pyenv` such as