{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Python Package Index\n", "\n", "The Python Package Index is known as PyPi. \n", "\n", "This is where python packages are downloaded from when you use `pip install ` and the code installs (even though `` is not the name of a folder in your machine).\n", "\n", "## PyPi\n", "\n", "Navigate to https://pypi.org/ and search for `numpy`. On the [page](https://pypi.org/project/numpy/) you can see the current version of the package that is downloaded by default when you run `pip install numpy`.\n", "\n", "The webpage also gives you the `pip install` command you need to use, and on the left if you click on download files, you will see [things that look familiar](https://pypi.org/project/numpy/#files):\n", "\n", "- The source distribution (a tar.gz file) containing the source code of the package.\n", "- The wheel distribution (a .whl file) containing a binary version of the package.\n", "\n", "We saw both of these and how to build them in the previous parts of the course.\n", "\n", "In the case of `numpy` you see that there are many wheels. This is because `numpy` is a truly compiled pakage that is not just pure Python (it uses C extensions). We will see more of this later in the course, when we talk about multi-language programming and `cibuildwheel`.\n", "\n", "When you click on [release history](https://pypi.org/project/numpy/#history) you will see the many different versions of the package that have been released and the dates they were released.\n", "You can click on any of the version to see details and how to install that specific version. For instance, if you click on `numpy-1.26.4` you will see that the installation command is `pip install numpy==1.26.4`.\n", "\n", "\n", "## Installing a package from PyPi\n", "\n", "\n", "To install a package from PyPi do, in a terminal:\n", "\n", " ```bash\n", " pip install \n", " ```\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: numpy in /Users/boris/opt/miniconda3/lib/python3.9/site-packages (2.0.2)\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "pip install numpy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Above, you see that the package is already installed. and you see the version number in brackets at the end. \n", "\n", "To uninstall a package do:\n", "\n", "```bash\n", "pip uninstall \n", "```\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Found existing installation: numpy 2.0.2\n", "Uninstalling numpy-2.0.2:\n", " Would remove:\n", " /Users/boris/opt/miniconda3/bin/f2py\n", " /Users/boris/opt/miniconda3/bin/numpy-config\n", " /Users/boris/opt/miniconda3/lib/python3.9/site-packages/numpy-2.0.2.dist-info/*\n", " /Users/boris/opt/miniconda3/lib/python3.9/site-packages/numpy/*\n", "Proceed (Y/n)? " ] } ], "source": [ "pip uninstall numpy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and you are prompted with proceed, to which you can press `y` to confirm. After which, you would see:\n", "\n", "```\n", " Successfully uninstalled numpy-2.0.2\n", " ```\n", "\n", "\n", "To install a specific version of a package from PyPi do:\n", "\n", "```bash\n", "pip install ==\n", "```\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Collecting numpy==2.0.2\n", " Using cached numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl (5.3 MB)\n", "Installing collected packages: numpy\n", "Successfully installed numpy-2.0.2\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "pip install numpy==2.0.2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, it is always the wheel distribution that is downloaded and installed (or was downloaded, in which case it uses cache). PyPi automatically selects the wheel that is appropriate for your operating system.\n", "Only when no wheel is available for your OS or Python version, the source distribution is downloaded and installed (and this can take a while and risks failing).\n", "\n", "Good practice when you distribute a package is to provide all possible wheels for all major operating systems and Python versions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Installing multiple packages" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can install and uninstall multiple packages at the same time:\n", "\n", "```bash\n", "pip install \n", "```\n", "or\n", "\n", "```bash\n", "pip uninstall \n", "```\n", "\n", "### Package dependencies\n", "\n", "Package dependencies (as set in the configuration file of the package) are automatically installed when you install a package.\n", "\n", "For instance," ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: scikit-learn in /Users/boris/opt/miniconda3/lib/python3.9/site-packages (1.5.2)\n", "Requirement already satisfied: threadpoolctl>=3.1.0 in /Users/boris/opt/miniconda3/lib/python3.9/site-packages (from scikit-learn) (3.1.0)\n", "Requirement already satisfied: numpy>=1.19.5 in /Users/boris/opt/miniconda3/lib/python3.9/site-packages (from scikit-learn) (2.0.2)\n", "Collecting scipy>=1.6.0\n", " Using cached scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl (30.3 MB)\n", "Requirement already satisfied: joblib>=1.2.0 in /Users/boris/opt/miniconda3/lib/python3.9/site-packages (from scikit-learn) (1.2.0)\n", "Installing collected packages: scipy\n", "Successfully installed scipy-1.13.1\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "pip install scikit-learn" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "in this example, `scikit-learn` found all its dependencies (requirements) already installed and did not install them again, but it didn't find `scipy` and installed it.\n", "\n", "If for some reasons you don't want dependencies to be installed automatically, you can use the `--no-deps` flag:\n", "\n", "```bash\n", "pip install --no-deps\n", "```\n", "\n", "### Upgrading a package\n", "\n", "To upgrade a package that is already installed, you can use the `--upgrade` flag:\n", "\n", "```bash\n", "pip install --upgrade\n", "```\n", "\n", "\n", "\n", "\n", "### Sharing your Python environment\n", "\n", "A simple way to share a specific Python environment is to create a `requirements.txt` file, listing all the packages that should be installed.\n", "\n", "You can create this file manually or let Python do it for you by running\n", "\n", "```bash\n", "pip freeze > requirements.txt\n", "```\n", "\n", "from within your virtual environment.\n", "\n", "This will create a file with one package per line, in the format `package-name==version` (if the version is known).\n", "\n", "You can then share this file with someone else and they can install the same packages by running\n", "\n", "```bash\n", "pip install -r requirements.txt\n", "```\n", "\n", "from within their own fresh virtual environment and they will have the same Python environment as you.\n", "\n", "### Keeping track of packages\n", "\n", "Remember the command\n", "\n", "```bash\n", "pip list\n", "```\n", "\n", "which lists all the packages installed in the current environment.\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Uploading your package to PyPi\n", "\n", "\n", "Create a PyPi account if you don't have one already.\n", "\n", "Uploading your package to PyPi is simple. Follow [these](https://chatgpt.com/share/6729daf4-1610-800c-a2b0-933b1d638135) instructions.\n", "\n", "The essential steps are:\n", "\n", "- build your package with `python -m build`. This creates the `dist` folder with source and wheel distributions.\n", "- upload the package to PyPi with `twine upload dist/*`\n", "\n", "That's it. \n", "\n", "Note that local version segments are not allowed. If you have used `setuptools_scm` for versioning, you will need to remove the local version segment before uploading.\n", "A systematic way to do this is to add the following two lines to your `pyproject.toml` file:\n", "\n", "```toml\n", "[tool.setuptools_scm]\n", "version_scheme = \"post-release\"\n", "local_scheme = \"no-local-version\"\n", "```\n", "\n", "If the project name is already taken you will get an error and need to modify it.\n", "\n", "When successful, you will see something like:\n", "\n", "```\n", "Uploading distributions to https://upload.pypi.org/legacy/\n", "Uploading company_package-0.0.0b0.post12-py3-none-any.whl\n", "100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 19.5/19.5 kB • 00:00 • 14.9 MB/s\n", "Uploading company_package-0.0.0b0.post12.tar.gz\n", "100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.3/17.3 kB • 00:00 • 5.0 MB/s\n", "\n", "View at:\n", "https://pypi.org/project/company-package/0.0.0b0.post12/\n", "```\n", "\n", "and the package becomes available on [PyPi](https://pypi.org/).\n", "\n", "You can then test the installation by running\n", "\n", "```bash\n", "pip install company_package\n", "```\n", "\n", "from within a fresh virtual environment or on another machine.\n", "\n", "\n", "\n", "## Versioning\n", "\n", "\n", "Versioning for python packages is handled automatically. We do it with `setuptools_scm` and the version is automatically written \n", "to `/version.py`.\n", "\n", "Relevant configuration in the `pyproject.toml` file is:\n", "\n", "```toml\n", "[tool.setuptools_scm]\n", "version_scheme = \"post-release\"\n", "local_scheme = \"no-local-version\"\n", "write_to = \"/version.py\" # Where to write the dynamic version\n", "```\n", "\n", "With this configuration, when you make changes and build the package, the version is automatically updated\n", "and increments as `0.0.0.post1`, `0.0.0.post2`, etc. for each build that has changed compared to the previous one.\n", "\n", "To increment other parts of the version, you tag with a version number using `git`. \n", "\n", "For example, \n", "\n", "```bash\n", " git tag v0.0.1\n", "```\n", "\n", "will update the version to `0.0.1` (you dont need to worry about the `post` part).\n", "\n", "To push the tags to the remote repository, you run\n", "\n", "```bash\n", "git push --tags\n", "```\n", "\n", "and you can check they are there on the GitHub, like at [this page](https://github.com/borisbolliet/company_package/tags).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "**Exercise:** Upload the `pygmb` package you created in the example class to PyPi. You can deleted afterward if you want. To delete the project from PyPi,\n", "navigate to the PyPi page of your project, go to Settings, scroll down and click delete. \n", "
\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.9" } }, "nbformat": 4, "nbformat_minor": 4 }