diff --git a/.doctrees/documentation/repository-files/license-files.doctree b/.doctrees/documentation/repository-files/license-files.doctree index 42115bc3..39f2449b 100644 Binary files a/.doctrees/documentation/repository-files/license-files.doctree and b/.doctrees/documentation/repository-files/license-files.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle index de7d035d..31758557 100644 Binary files a/.doctrees/environment.pickle and b/.doctrees/environment.pickle differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree index d6a17e6a..7ead9ba9 100644 Binary files a/.doctrees/index.doctree and b/.doctrees/index.doctree differ diff --git a/.doctrees/tutorials/1-installable-code.doctree b/.doctrees/tutorials/1-installable-code.doctree index 5e2d98f8..d6f99d20 100644 Binary files a/.doctrees/tutorials/1-installable-code.doctree and b/.doctrees/tutorials/1-installable-code.doctree differ diff --git a/.doctrees/tutorials/add-license-coc.doctree b/.doctrees/tutorials/add-license-coc.doctree new file mode 100644 index 00000000..18719fcb Binary files /dev/null and b/.doctrees/tutorials/add-license-coc.doctree differ diff --git a/.doctrees/tutorials/add-readme.doctree b/.doctrees/tutorials/add-readme.doctree index ab38f71b..85e827ed 100644 Binary files a/.doctrees/tutorials/add-readme.doctree and b/.doctrees/tutorials/add-readme.doctree differ diff --git a/.doctrees/tutorials/intro.doctree b/.doctrees/tutorials/intro.doctree index d5ca191a..a3fc984d 100644 Binary files a/.doctrees/tutorials/intro.doctree and b/.doctrees/tutorials/intro.doctree differ diff --git a/.doctrees/tutorials/publish-pypi.doctree b/.doctrees/tutorials/publish-pypi.doctree index 0ee3eba6..c45af4d2 100644 Binary files a/.doctrees/tutorials/publish-pypi.doctree and b/.doctrees/tutorials/publish-pypi.doctree differ diff --git a/.doctrees/tutorials/pyproject-toml.doctree b/.doctrees/tutorials/pyproject-toml.doctree new file mode 100644 index 00000000..8a4afc24 Binary files /dev/null and b/.doctrees/tutorials/pyproject-toml.doctree differ diff --git a/_images/github-new-repo.png b/_images/github-new-repo.png new file mode 100644 index 00000000..fa1cca8b Binary files /dev/null and b/_images/github-new-repo.png differ diff --git a/_images/license-github-root-dir.png b/_images/license-github-root-dir.png new file mode 100644 index 00000000..7ce10e26 Binary files /dev/null and b/_images/license-github-root-dir.png differ diff --git a/_images/social_previews/summary_index_9e185de9.png b/_images/social_previews/summary_index_0393342e.png similarity index 66% rename from _images/social_previews/summary_index_9e185de9.png rename to _images/social_previews/summary_index_0393342e.png index 87719598..06c06871 100644 Binary files a/_images/social_previews/summary_index_9e185de9.png and b/_images/social_previews/summary_index_0393342e.png differ diff --git a/_images/social_previews/summary_tutorials_add-license-coc_24d43578.png b/_images/social_previews/summary_tutorials_add-license-coc_24d43578.png new file mode 100644 index 00000000..e6a97568 Binary files /dev/null and b/_images/social_previews/summary_tutorials_add-license-coc_24d43578.png differ diff --git a/_images/social_previews/summary_tutorials_add-readme_05ea09e7.png b/_images/social_previews/summary_tutorials_add-readme_cb98e8e2.png similarity index 65% rename from _images/social_previews/summary_tutorials_add-readme_05ea09e7.png rename to _images/social_previews/summary_tutorials_add-readme_cb98e8e2.png index d9bdc8cf..6c319235 100644 Binary files a/_images/social_previews/summary_tutorials_add-readme_05ea09e7.png and b/_images/social_previews/summary_tutorials_add-readme_cb98e8e2.png differ diff --git a/_images/social_previews/summary_tutorials_publish-pypi_177e2026.png b/_images/social_previews/summary_tutorials_publish-pypi_177e2026.png new file mode 100644 index 00000000..27e9ed3d Binary files /dev/null and b/_images/social_previews/summary_tutorials_publish-pypi_177e2026.png differ diff --git a/_images/social_previews/summary_tutorials_publish-pypi_a4a4bd2f.png b/_images/social_previews/summary_tutorials_publish-pypi_a4a4bd2f.png deleted file mode 100644 index d6b0105c..00000000 Binary files a/_images/social_previews/summary_tutorials_publish-pypi_a4a4bd2f.png and /dev/null differ diff --git a/_images/social_previews/summary_tutorials_pyproject-toml_1a4c4a0e.png b/_images/social_previews/summary_tutorials_pyproject-toml_1a4c4a0e.png new file mode 100644 index 00000000..ab9fd518 Binary files /dev/null and b/_images/social_previews/summary_tutorials_pyproject-toml_1a4c4a0e.png differ diff --git a/_images/view-license-github.png b/_images/view-license-github.png new file mode 100644 index 00000000..57dc8d2a Binary files /dev/null and b/_images/view-license-github.png differ diff --git a/_sources/documentation/repository-files/license-files.md.txt b/_sources/documentation/repository-files/license-files.md.txt index 37c797c5..e08a6f35 100644 --- a/_sources/documentation/repository-files/license-files.md.txt +++ b/_sources/documentation/repository-files/license-files.md.txt @@ -47,7 +47,7 @@ To select your license, we suggest that you use GitHub's [Choose a License tool ](https://choosealicense.com/). If you choose your license when creating a new GitHub repository, you can also -automatically get a text copy of the license file to add to your repo. However +automatically get a text copy of the license file to add to your repository. However in some cases the license that you want is not available through that online process. @@ -78,9 +78,9 @@ with the license that you selected for your package. :::{admonition} An example of how a license determine how code can be reused :class: note -Let's use stackOverflow as an example that highlights how a license determines how code can or can not be used. +Let's use StackOverflow as an example that highlights how a license determines how code can or can not be used. -[Stack overflow uses a Creative Commons Share Alike license.](https://stackoverflow.com/help/licensing). The sharealike license requires you to use the same sharealike license when you reuse any code from stackoverflow. +[Stack overflow uses a Creative Commons Share Alike license.](https://stackoverflow.com/help/licensing). The sharealike license requires you to use the same sharealike license when you reuse any code from StackOverflow. This means that technically, if you copy code from the Stack Overflow website, and use it in your package. And your packages uses a different license such as a MIT license, you are violating Stack Overflow's license requirements! @@ -92,7 +92,7 @@ This means that technically, if you copy code from the Stack Overflow website, a While many permissive licenses do not require citation we STRONG encourage that you cite all software that you use in papers, blogs and other publications. You tell your users how to cite your package by using a [citation.cff file](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files). We will cover this topic when we talk about creating DOI's for your package using zenodo. - -### Step 1. Add the name of your package as the README title +### Step 1: Add the name of your package as the README title At the top of the `README.md` file, add the name of your package. -If you are using markdown it should be a header 1 tag which is denoted with a single `#` sign. +If you are using markdown it should be a header 1 (H1) tag which is denoted with a single `#` sign. `# Package-title-here` -### Step 2 - add badges to the top of your README file +### Step 2: add badges to the top of your README file -It's common for maintainers to add badges to the top of their README files. Badges allow you and your package users to track things like +It's common for maintainers to add badges to the top of their README files. Badges allow you and your package users to track things like: * Broken documentation and test builds. -* Versions of your package that are on PyPI and Conda. +* Versions of your package that are on PyPI and conda. * Whether your package has been reviewed and vetted by an organization such as pyOpenSci and/or JOSS. If you have already published your package to pypi.org you can use [shields.io to create a package version badge](https://shields.io/badges/py-pi-version). This badge will dynamically update as you release new versions of your package to PyPI. -If not, you can leave the top empty for now and add badges to your README at a later point as they make sense for your package. +If not, you can leave the top empty for now and add badges to your README at a later point as they make sense. -### Step 3 - Add a description of what your package does +### Step 3: Add a description of what your package does Below the badges (if you have them), add a section of text that provides an easy-to-understand overview of what your @@ -81,7 +84,7 @@ package does. Remember that the more people understand what your package does, the more people will use it. -### Step 4 - Add package installation instructions +### Step 4: Add package installation instructions Next, add instructions that tell users how to install your package. @@ -96,7 +99,7 @@ If you haven't yet published your package to pypi.org then you can skip this section and come back and add these instructions later. -### Step 5 - Any additional setup +### Step 5: Any additional setup In some cases, your package users may need to manually install other tools in order to use your package. If that @@ -111,14 +114,14 @@ This might include: * additional tool installations, such as GDAL. :::{note} -Many packages won't need this section in their README. In that case you can always skip this section! +Many packages won't need an additional setup section in their README. +In that case you can always skip this section. ::: -### Step 6 - Add a get started section +### Step 6: Add a get started section -Next add a getting started section that shows how to use your package. This -section should include a small code snippet that demonstrates importing and using +Next add a get-started section. Within this section, add a small code example that demonstrates importing and using some of the functionality in your package. :::{admonition} Provide a fully functional code snippet if possible @@ -128,7 +131,7 @@ It is important to try to make the code examples that you provide your users as Be sure to provide a copy/paste code example that will work as-is when pasted into a Jupyter Notebook or .py file if that is possible. -If there are tokens and other steps needed to run your package, be sure to be clear about what those steps entail. +If there are tokens and other steps needed to run your package, be sure to be clear about what those steps are. ::: For the pyosPackage, a short get started demo might look like this: @@ -143,22 +146,28 @@ Or it could simply be a link to a getting started tutorial that you have created you don't have this yet, you can leave it empty for the time being. This would -also be a great place to add links to any tutorials that you have created that +also be a great place to add links to tutorials that help users understand how to use your package for common workflows. -### Step 7 - Community section +### Step 7: Community section The community section of your README file is a place to include information for users who may want to engage with your project. This engagement will likely happen on a platform like GitHub or GitLab. In the community section, you will add links to your contributing guide -and `CODE_OF_CONDUCT.md`. You will add a [`CODE_OF_CONDUCT.md` file in the next lesson](add-license-coc). +and `CODE_OF_CONDUCT.md`. You will create a [`CODE_OF_CONDUCT.md` file in the next lesson](add-license-coc). -As your package grows you may also have a link to a development guide that contributors and your maintainer team will follow. +As your package grows you may also have a link to a development guide that contributors and your maintainer team will follow. The development guide +outlines how to perform maintenance tasks such as: +* running tests +* making package releases +* building documentation +* and more. -### Step 8 - Citation information + +### Step 8: Citation information Finally it is important to let users know how to cite your package. You can communicate citation information in a few different ways. @@ -168,8 +177,8 @@ information for your package if it is hosted on a platform such as GitHub. [Check out this short tutorial that covers setting that up.](https://coderefinery.github.io/github-without-command-line/doi/) Alternatively if you send your package through a peer review process such -as the [one lead by pyOpenSci](https://www.pyopensci.org/about-peer-review/index.html), then you can get a cross-ref DOI through our partnership -with the Journal of Open Source Software. +as the [one lead by pyOpenSci](https://www.pyopensci.org/about-peer-review/index.html). After being accepted by pyOpenSci, if your package is in scope, you can be accepted by the Journal of Open Source Software and get a cross-ref DOI through [our partnership with the Journal of Open Source Software.](https://www.pyopensci.org/about-peer-review/index.html) + ## The finished README file diff --git a/_sources/tutorials/intro.md.txt b/_sources/tutorials/intro.md.txt index 35f2f171..29b728a8 100644 --- a/_sources/tutorials/intro.md.txt +++ b/_sources/tutorials/intro.md.txt @@ -33,7 +33,7 @@ Get to know Hatch :::{toctree} :hidden: -:caption: Create a Python package +:caption: Create and publish a Python Package What is a Python package? Make your code installable <1-installable-code> @@ -43,9 +43,11 @@ Publish to conda-forge :::{toctree} :hidden: -:caption: Project Metadata +:caption: Project information files & metadata Add README file +Add a license & code of conduct +Update metadata in pyproject.toml ::: :::{admonition} Learning Objectives @@ -96,7 +98,6 @@ to manage and reuse your code across different projects. Structuring your code as a package is the first step you need to take so you can share the tools in the toolbox you've created and let others build with it. (package-benefits)= - ## Why create a Python package? You might create a Python package because you want to: @@ -291,7 +292,7 @@ allows you to access it from any code run with that specific Python environment :::{figure-md} packages-environment -Diagram showing the steps associated with creating a package and then installing it. The first arrow says your package and the second says pip install package. The second arrow leads to a box that represents a Python environment that already has some packages installed such as pandas and NumPy. Your package will also get installed into that same environment when you pip install it. +Diagram showing the steps associated with creating a package and then installing it. The first arrow says your package and the second says pip install package. The second arrow leads to a box that represents a Python environment that already has some packages installed such as Pandas and NumPy. Your package will also get installed into that same environment when you pip install it. You don't have to publish to PyPI to make your code installable. With the correct file structure and project metadata you can make your code @@ -318,7 +319,7 @@ Then you can create a conda-forge recipe using the [Grayskull](https://github.co Graphic showing the high level packaging workflow. On the left you see a graphic with code, metadata and tests in it. Those items all go into your package. Documentation and data are below that box because they aren't normally published in your packaging wheel distribution. an arrow to the right takes you to a build distribution files box. that box leads you to either publishing to testPyPI or the real PyPI. From PyPI you can then connect to conda-forge for an automated build that sends distributions from PyPI to conda-forge. In the image above, you can see the steps associated with publishing -your package on PyPI and conda-forge. Note that the distribution files that PyPI requires are the [sdist](#python-source-distribution) and [wheel](#python-wheel) files. Once you are ready to make your code publicly installable, you can publish it on PyPI. Once your code is on PyPI it is straight forward to then publish to conda-forge. You create a recipe using the Grayskull package and then you open a pr in the conda-forge recipe repo. You will learn more about this process in the [conda-forge lesson](#). +your package on PyPI and conda-forge. Note that the distribution files that PyPI requires are the [sdist](#python-source-distribution) and [wheel](#python-wheel) files. Once you are ready to make your code publicly installable, you can publish it on PyPI. Once your code is on PyPI it is straight forward to then publish to conda-forge. You create a recipe using the Grayskull package and then you open a pr in the conda-forge recipe repository. You will learn more about this process in the [conda-forge lesson](#). ::: ## Yay, your package has users! Now what? diff --git a/_sources/tutorials/publish-pypi.md.txt b/_sources/tutorials/publish-pypi.md.txt index 6b622c26..931782ab 100644 --- a/_sources/tutorials/publish-pypi.md.txt +++ b/_sources/tutorials/publish-pypi.md.txt @@ -1,10 +1,11 @@ # Publish your Python package to PyPI :::{todo} -* emphasize that we recommended the trusted publisher GitHub action for most maintainers -* Make sure they add /dist to their .gitignore file. We have not discussed GitHub workflows anywhere yet. Where does that fit? -* https://hatch.pypa.io/latest/intro/#existing-project <- hatch will migrate from setup.py for you - if we go with hatch then we may want to add this to the installable code lesson -* Should we install hatch with pipx? +- emphasize that we recommended the trusted publisher GitHub action for most maintainers +- Make sure they add /dist to their .gitignore file. We have not discussed GitHub workflows anywhere yet. Where does that fit? +- https://hatch.pypa.io/latest/intro/#existing-project <- hatch will migrate from setup.py for you - if we go with hatch then we may want to add this to the installable code lesson +::: + ```bash pipx install hatch @@ -37,13 +38,8 @@ using [Grayskull](https://conda.github.io/grayskull/). You will learn how to publish to conda-forge in a future lesson. -:::{todo} -Fix this link once the lesson is published. - -You will learn how to publish to conda-forge in the [next lesson](7-publish-conda-forge.md). -::: +You will learn how to publish to conda-forge in the [next lesson](publish-conda-forge). -::: :::{figure-md} build-workflow-tutorial Graphic showing the high level packaging workflow. On the left you see a graphic with code, metadata and tests in it. Those items all go into your package. An arrow to the right takes you to a build distribution files box. Another arrow to the right takes you to a publish to PyPI box which has an arrow containing sdist and wheel that notes those files go to PyPI for hosting. From PyPI is an arrow containing sdist since you can then connect to conda-forge for an automated build that sends distributions from PyPI to conda-forge. @@ -51,7 +47,6 @@ You will learn how to publish to conda-forge in the [next lesson](7-publish-cond You need to build your Python package in order to publish it to PyPI (or Conda). The build process organizes your code and metadata into a distribution format that can be uploaded to PyPI and subsequently downloaded and installed by users. ::: - ## Test PyPI vs PyPI There are two "warehouses" that you can use to publish @@ -76,13 +71,13 @@ to PyPI. You need to: 1. **Create an account on (test) PyPI**: You will need to create a PyPI account and associated token which provides permissions for you to upload your package. 1. **Publish to PyPI using `hatch publish`** - In a future lesson, you will learn how to create an automated GitHub action workflow that publishes an updated version of your package to PyPI every time you create a GitHub release. :::{admonition} Learn more about building Python packages in our guide :class: tip + - [Learn more about what building a Python package is](../package-structure-code/python-package-distribution-files-sdist-wheel) - [Learn more about package distribution file that PyPI needs called the wheel](#python-wheel) - [Learn more about the package distribution file that conda-forge will need on PyPI called the sdist (source distribution)](#python-source-distribution) @@ -139,7 +134,6 @@ six 1.16.0 tzdata 2023.4 ``` - At any time you can exit the environment using `exit`. ```bash @@ -154,13 +148,13 @@ pyosPackage (☊ main) [✎ ×1 ] is 📦 v0.1.4 via 🐍 pyenv took 43s ➜ ``` - ### Hatch and environments Behind the scenes when hatch creates a new virtual environment, by default it uses venv[^venv] which is the default environment management tool that comes with Python installations. Hatch will: + 1. Create a new virtualenv (venv) that is located on your computer. 2. Install your package into the environment in editable mode (similar to `pip install -e`). This means it installs both your project and your project's dependencies as declared in your pyproject.toml file. @@ -192,10 +186,8 @@ You can learn more about building in the [build page of our packaging guide](../package-structure-code/python-package-distribution-files-sdist-wheel). ::: -:::{todo} The sdist is important if you wish to [publish -your package to conda-forge](7-publish-conda-forge) which you will learn about in a later lesson. -::: +your package to conda-forge](publish-conda-forge). You will learn about this in a later lesson. :::{todo} ➜ hatch build @@ -232,7 +224,7 @@ Example: `pyosPackage_yourNameHere`. Show them how to do this 1. update the project-name in the pyproject.toml file -2. update the module repo directory to be the same +2. update the module repository directory to be the same ::: :::{figure-md} build-workflow-tutorial @@ -242,7 +234,6 @@ Before you try to upload to test PyPI, check to see if the name of your package the search box at the top of the test PyPI website. ::: - :::{admonition} Setup 2-factor (2FA) authentication 2-factor authentication is a secure login process that allows you to @@ -268,12 +259,11 @@ It's ideal to create a package-specific token. When you create an account wide t ### Follow the steps below to create your token. -* Login to test PyPI and go to your account settings -* Scroll down to the **API tokens** section -* Click on the **Add API Token** button - * If you are new to using PyPI and don't have any packages there yet, OR if you have other packages on PyPI but are uploading a new package, you will need to create an account-wide token. -* When you create your token, be sure to copy the token value and store it in a secure place before closing that browser. - +- Login to test PyPI and go to your account settings +- Scroll down to the **API tokens** section +- Click on the **Add API Token** button + - If you are new to using PyPI and don't have any packages there yet, OR if you have other packages on PyPI but are uploading a new package, you will need to create an account-wide token. +- When you create your token, be sure to copy the token value and store it in a secure place before closing that browser. Your token should look something like this: @@ -286,12 +276,12 @@ It should start with `pypi` followed by a dash and a bunch of characters. Once you have your token, you are ready to publish to PyPI. -* Run `hatch publish -r test` +- Run `hatch publish -r test` `-r` stands for repository. In this case because you are publishing to test-PyPI you will use `-r test`. Hatch will then ask for a username and credentials. -* Add the word `__token__` for your username. This tells Test PyPI that you are using a token value rather than a username. -* Paste your PyPI token value in at the `Enter your credentials` prompt: +- Add the word `__token__` for your username. This tells Test PyPI that you are using a token value rather than a username. +- Paste your PyPI token value in at the `Enter your credentials` prompt: ```bash ❯ hatch publish -r test @@ -321,7 +311,6 @@ landing page for your newly uploaded package. This is an example landing page for the pyosPackage that was just uploaded. Notice at the top of the page there is instruction for how to install the package from test PyPI. You can simply copy that code and use it to install your package from testPyPi locally. ::: - As an example, [check out our pyOpenSci pyosPackage landing page on test PyPI](https://test.pypi.org/project/pyosPackage/). Notice that the page has information about the current package version and also installation instructions as follows: @@ -335,9 +324,9 @@ testPyPI as a permanent way to install your package. Test PyPi is a perfect plac ### Time to install your package -* On your computer, activate the development environment that -you wish to install your newly published package in. -* Run the installation instructions for your package from test PyPI. +- On your computer, activate the development environment that + you wish to install your newly published package in. +- Run the installation instructions for your package from test PyPI. ::::{tab-set} @@ -348,9 +337,11 @@ you wish to install your newly published package in. > pip install -i https://test.pypi.org/simple/ youPackageNameHere > conda list ``` + ::: :::{tab-item} venv mac / Linux + ```bash > hatch shell > pip install -i https://test.pypi.org/simple/ youPackageNameHere @@ -363,14 +354,12 @@ you wish to install your newly published package in. In this lesson you are using Hatch and hatchling to create, build and publish your Python Package. [Click here to learn about other packaging tools in the ecosystem.](../package-structure-code/python-package-build-tools.md) ::: - - - - +::: ## Package-specific token vs trusted publisher @@ -412,3 +401,4 @@ You will learn how to do that in the next lesson. ## Footnotes [^venv]: https://docs.python.org/3/library/venv.html +``` diff --git a/_sources/tutorials/pyproject-toml.md.txt b/_sources/tutorials/pyproject-toml.md.txt new file mode 100644 index 00000000..0434e413 --- /dev/null +++ b/_sources/tutorials/pyproject-toml.md.txt @@ -0,0 +1,597 @@ +# Make your Python package PyPI ready - pyproject.toml + +In [the installable code lesson](2-installable-code), you learned how to add the bare minimum information to a `pyproject.toml` file to make it installable. You then learned how to [publish a bare minimum version of your package to PyPI](publish-pypi.md). + +Following that you learned how to add a: +* [README.md](add-readme) +* [LICENSE](add-license-coc) and +* [CODE_OF_CONDUCT](add-coc) + +to the root of your project directory. + +To enhance the visibility of your package on PyPI and provide more information +about its compatibility with Python versions, project development status, and +project maintainers, you should add additional metadata to your `pyproject.toml` +file. This +lesson will guide you through the process. + + +:::{admonition} Learning Objectives +:class: tip + +In this lesson you will learn: + +1. More about the `pyproject.toml` file and how it's used to store different types of metadata about your package +1. How to declare information (metadata) about your project to help users find and understand it on PyPI. + +If you wish to learn more about the `pyproject.toml` format, [check out this page. ](../package-structure-code/pyproject-toml-python-package-metadata.md) +::: + +:::{dropdown} Click for lesson takeaways +:color: secondary +:icon: unlock + +When creating your pyproject.toml file, consider the following: + +1. There are only two required metadata tables that you need to install and publish your Python package: + * **[build-system]** + * **[project]**. +2. The **[project]** table stores your package's metadata. Within the **[project]** table, There are only two _required_ fields: + * **name=** + * **version=** +3. You should add more metadata to the `[project]` table as it will make it easier for users to find your project on PyPI. And it will also make it easier for installers to understand how to install your package. +3. When you are adding classifiers to the **[project]** table, only use valid values from [PyPI’s classifier page](https://PyPI.org/classifiers/). An invalid value here will raise an error when you build and publish your package on PyPI. +4. There is no specific order for tables in the `pyproject.toml` file. However, fields need to be placed within the correct tables. For example `requires =` always need to be in the **[build-system]** table. +5. We suggest that you include your **[build-system]** table at the top of your `pyproject.toml` file. +::: + +## What is a pyproject.toml file? + +The `pyproject.toml` file is a human and machine-readable file that serves as the primary configuration file for your Python package. + + +:::{tip} +[Building your package](build-package) is the step that created the distribution files that are required for you to publish to PyPI. +::: + + +### About the .toml format + +The **pyproject.toml** file is written in [TOML (Tom's Obvious, Minimal Language) format](https://toml.io/en/). TOML is an easy-to-read structure that is based on key/value pairs. Each section in the **pyproject.toml** file contains a `[table identifier]`. The TOML format can be compared to other structured formats such as`.json`. However, the TOML format was designed to be easier to read for humans. + +Below you can see the `[build-system]` table. Within +that table there are two required key/value pairs. + +`requires =` is the key and the value is `["hatchling"]` within the `[build-system]` array specified by square brackets `[]`. + +```toml +[build-system] # <- This is a table +requires = ["hatchling"] +# The build backend defines the tool that should be used to build your package distribution files. +build-backend = "hatchling.build" +``` + + +### What is the pyproject.toml used for? + +The pyproject.toml file tells your build tool: + +- What build backend to use to build your package (we are using `hatchling` in this tutorial but there are [many others to chose from](build-backend-options)). +- How and where to retrieve your package's version: + - **statically** where you declare the version `version = "0.1.0"` or + - **dynamically** where the tool looks to the most recent tag in your history to determine the current version. +- What dependencies your package needs +- What versions of Python your package supports (important for your users). + +The `pyproject.toml` file also makes it easy for anyone browsing your GitHub +repository to quickly understand your package's structure such as: + +- How your package is built, +- What Python versions and operating systems it supports +- What it does, +- Who maintains it + +Finally, the pyproject.toml file is also often used to configure tools such as static type checkers (e.g. mypy) and code formatters/linters (e.g. black, ruff). + +:::{tip} +Check out the [PyPA documentation](https://packaging.python.org/en/latest/tutorials/packaging-projects/#creating-pyproject-toml) if you are interested in setting build configurations for other tools. + +Note that some build tools may deviate in how they store project metadata. As such you may want to refer to their documentation if you decide to use a tool other than Hatch and hatchling. We have selected hatchling and hatch as our tool of choice for this tutorial as it adheres to PyPA rules and guidelines. + +::: + +### How is pyproject.toml metadata used? + +The pyproject.toml file is the file that your build tool uses to populate +a `METADATA` that is included in your Python distribution files that get published to PyPI. This `METADATA` file is then used by PyPI to populate your package's PyPI landing page and help users filter through the tens of thousands of packages published there. + +```{figure} ../images/python-build-package/pypi-metadata-classifiers.png +:scale: 50 % +:align: center +:alt: Image showing the left side bar of PyPI for the package xclim. The section at the top says Classifier. Below there is a list of items including Development status, intended audience, License, natural language, operating system, programming language and topic. Below each of those sections are various classifier options." width="300px"> + +When you add the classifier section to your pyproject.toml +and your package is built, the build tool organizes the metadata into a format that PyPI can understand and +represent on your PyPI landing page. These classifiers also allow users to sort through packages by version of python they support, categories and more. +``` + +:::{tip} A more in-depth overview of pyproject.toml files + +[Our guidebook page has a more in depth overview of this file](../package-structure-code/pyproject-toml-python-package-metadata/) +::: + + +## How to update your pyproject.toml file + +In the last lesson, you created a bare-bones pyproject.toml +file that contained the core elements needed to build your +package: + +1. A `[build-system]` table where you defined your project's backend build tool (`hatchling`) +2. A `[project]` table where you defined your project's version and name. + +The `pyproject.toml` file that you created, looked like this: + +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +``` + +Your next step is to add additional recommended metadata fields that will both +help users find your package on PyPI and also better describe the scope of your package. Once you add this metadata, you don't have to do it again. These metadata fields will only be updated periodically when you do something such as: + +- drop a package dependency +- modify what Python versions your package supports. + +:::{admonition} More on hatchling +:class: tip + +The documentation for the hatchling back-end is [here](https://hatch.pypa.io/latest/config/metadata/) +::: + +### Step 1: Populate the [project] table with author, maintainer and project description + +After completing the [installable code tutorial](1-installable-code), you should have a pyproject.toml file with a project name and a version in the `[project]` table. + +```toml +[project] +name = "pyospackage" +version = "0.1.0" +``` + +Add the following to your table: + +- A **description** of your package. This should be a single line and should briefly describe the goal of your package using non technical terms if as all possible! +- package **authors** +- package **maintainers** + +When you add authors and maintainers you need to use a format that will look like a Python list with a dictionary within it: + +`authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]` + +If you have two authors you can add them like this: + +`authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]` + +:::{admonition} Author names & emails +:class: note + +There is a quirk with PyPI for authors that have names but not emails in the pyproject.toml. If you are missing the email for one or more authors or maintainers, like this: + +```toml +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname" }] +``` + +Then we suggest that you only provide names in your list of names to ensure that everything renders properly on your PyPI page - like this: + +```toml +maintainers = [{ name = "Firstname lastname"}, { name = "Firstname lastname" }] +``` + +don't have emails for everyone, we suggest that you only add names. + +::: + +Your `pyproject.toml` file now should look like the example below. It is OK if you only have 1 author and the same author is also maintainer of your package: + +{emphasize-lines="8-10"} +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }] +``` + +:::{dropdown} Learn More: What's the difference between author and maintainer in open source? +:color: secondary + +When adding maintainers and authors, you may want to think about the difference between the two. + +Authors generally include people who: +* originally created / designed developed the package and +* people who add new functionality to the package. + +Whereas maintainers are the people that are currently, actively working on the project. It is often the case that there is overlap in authors and maintainers. As such these lists may be similar or the same. + +A good example of when the lists might diverge is sometimes you have a package where an initial author developed it and then stepped down as a maintainer to move on to other things. This person may continue to be considered an author but no longer actively maintains the package. + +It is important to note that there are many ways to define author vs maintainer and we don't prescribe a single approach in this tutorial. + +However, we encourage you to consider carefully, for PyPI publication, who +you want to have listed as authors and maintainers on your PyPI landing page. +::: + +### Step 2: Link your README and license in your pyproject.toml file + +In the previous lessons, you added both a [README.md](add-readme) file and a [LICENSE](add-license-coc) to your package repository. +Once you have those files, you can add them to your pyproject.toml file as +links following the example below. + +{emphasize-lines="11-12"} +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }] +readme = "README.md" +license = {file = 'LICENSE'} +``` +### Step 3: Add requires-python to your [project] table + +Finally, add the `requires-python` field to your `pyproject.toml` `[project]` table. The `requires-python` field, helps pip understand the lowest version of Python that you package supports when it's installed. It is thus a single value. + + +{emphasize-lines="13"} +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }] +readme = "README.md" +license = {file = 'LICENSE'} +requires-python = ">=3.10" +``` + +### Step 4: Add package dependencies to your [project] table + +Next add your dependencies table to the project table. +The `dependencies =` section contains a list (or array in the toml language) of the Python packages that your package requires to run properly in a Python environment. Similar to the requirements listed in the `[build-system]` table above: + +```toml +[build-system] # <- this is a table +requires = ["hatchling"] # this is an array (or list) of requirements +``` +dependencies are added in an array (similar to a Python list) structure. + + +{emphasize-lines="15"} +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }] +readme = "README.md" +license = {file = 'LICENSE'} +requires-python = ">=3.10" + +dependencies = ["numpy", "requests", "pandas", "pydantic"] +``` + +:::{admonition} Pin dependencies with caution +Pinning dependencies refers to specifying a specific version of a dependency like this `numpy == 1.0`. In some specific cases, you may chose to pin a package version for a specific package dependency. + +Declaring lower bounds involves ensuring that a user has at least a specific version (or greater) of a package installed. This is important as often your package is not backwards compatible with an older version of a tool - for example a version of Pandas that was released 5 years ago. + +You can declare a lower bound using syntax like this: + +`ruamel-yaml>=0.17.21` + +[Learn more about various ways to specify ranges of package versions here.](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) + +Note that unless you are building an application, you want to be cautious about pinning dependencies to precise versions. For example: + +`numpy == 1.0.2` + +This is because +users will be installing your package into various environments. +A dependency pinned to a single specific version can make +resolving a Python environment more challenging. As such only +pin dependencies to a specific version if you absolutely need to +do so. + +One build tool that you should be aware of that pins dependencies to an upper bound by default is Poetry. [Read more about how to safely add dependencies with Poetry, here.](../package-structure-code/python-package-build-tools.html#challenges-with-poetry) +::: + +### Step 5: Add PyPI classifiers to your pyproject.toml file + +Next you will add classifiers to your `pyproject.toml` file. The value for each classifier that you add to your `pyproject.toml` file must come from the list of [PyPI accepted classifier values found here](https://PyPI.org/classifiers/). Any deviations in spelling and format will cause issues when you publish to PyPI. + +:::{admonition} What happens when you use incorrect classifiers? +:class: tip + +If you do not [use standard classifier values](https://PyPI.org/classifiers/), when you try to publish your package on PyPI it will be rejected. 😔 Don't worry if PyPI rejects you on your first try! It has happened to all of us. +::: + +Review that list and add items below to your `pyproject.toml` file: + +- development status +- intended audiences +- topic +- license and +- programming language support + +The classifier key should look something like the example below. A few notes: + +- Your classifier values might be different depending upon the license you have selected for your package, your intended audience, development status of your package and the Python versions that you support +- You can add as many classifiers as you wish as long as you use the [designated PyPI classifier values](https://PyPI.org/classifiers/). + +{emphasize-lines="17-24"} +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }] +readme = "README.md" +license = {file = 'LICENSE'} +requires-python = ">=3.10" + +dependencies = ["numpy", "requests", "pandas", "pydantic"] + +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Build Tools", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11",] +``` + +Note that while classifiers are not required in your `pyproject.toml` file, they will help users find your package. As such we strongly recommend that you add them. + +### Step 6: Add the `[project.urls]` table + +Finally, add the project.urls table to your pyproject.toml file. + +`project.urls` contains links that are relevant for your project. You might want to include: + +- **Homepage:** A link to your published documentation for your project. If you are working through this tutorial, then you may not have this link yet. That's ok, you can skip it for the time being. +- **Bug reports:** a link to your issues / discussions or wherever you want users to report bugs. +- **Source:** the GitHub / GitLab link for your project. + +{emphasize-lines="27-30"} +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }] +readme = "README.md" +license = {file = 'LICENSE'} +requires-python = ">=3.10" + +dependencies = ["ruamel-yaml>=0.17.21", "requests", "python-dotenv", "pydantic"] + +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Build Tools", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + ] + +[project.urls] # Optional +"Homepage" = "https://www.pyopensci.org" +"Bug Reports" = "https://github.com/pyopensci/pyosmeta/issues" +"Source" = "https://github.com/pyopensci/pyosmeta/" +``` + +:::{tip} +There are many other urls that you can add here. Check out the [README file here for an overview](https://github.com/patrick91/links-demo). +::: + +## Putting it all together - your completed pyproject.toml file + +Below is an example of a complete `pyproject.toml` file that +is commented with all of the sections we discussed above. + +```toml +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.0" +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }] +readme = "README.md" +license = {file = 'LICENSE'} +requires-python = ">=3.10" + +dependencies = ["ruamel-yaml>=0.17.21", "requests", "python-dotenv", "pydantic"] + +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Topic :: Software Development :: Build Tools", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + ] + +[project.urls] # Optional +"Homepage" = "https://www.pyopensci.org" +"Bug Reports" = "https://github.com/pyopensci/pyosmeta/issues" +"Source" = "https://github.com/pyopensci/pyosmeta/" +``` + + +:::{dropdown} Appendix - Click for a fully commented pyproject.toml file +:color: secondary +:icon: unlock + +Below is a fully commented pyproject.toml file if you want to use it for reference. + +```toml +# You can delete all of the comments once you have created your own pyproject.toml file. + +# The build system table. Here we use hatchling as the build back end tool. +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +# The [project] section contains your package's metadata +# notice that the version is setup to be dynamically generated using dynamic=[“version”] + +[project] +name = "pyospackage" +# dynamic = ["version"] # you will learn how to dynamically set the version in a future lesson +version = "0.1.0" # manually assign version (not preferred) +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website" +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }] + +# maintainers section is optional but suggested. +maintainers = [ + { name = "firstname lastname", email = "admin@pyopensci.org" }, # Optional +] + +# Classifiers have set values - be sure to only use classifier values from the +# PyPI page here: https://PyPI.org/classifiers/ + +classifiers = [ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + "Development Status :: 4 - Beta", + + # Indicate who your project is intended for + "Intended Audience :: Developers", + "Topic :: Software Development :: Build Tools", + + # Pick your license (using syntax from the classifier page). We suggest MIT, BSD3 or Apache if you are corporate + "License :: OSI Approved :: MIT License", + + # Specify the Python versions ensuring that you indicate you support Python 3. + # this is only for PyPI and other metadata associated with your package - for your users to see + "Programming Language :: Python :: 3 :: Only", # BE sure to specify that you use python 3.x + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] + + +dependencies = ["xarray", "requests"] +# This is the metadata that pip reads to understand what versions your package supports +requires-python = ">=3.10" +readme = "README.md" +license = { file = "LICENSE" } + +# Add urls for your home page, issue tracker and source code +[project.urls] # Optional +"Homepage" = "https://www.pyopensci.org" +"Bug Reports" = "https://github.com/pyopensci/pyospackage/issues" +#"Funding" = "" +"Source" = "https://github.com/pyopensci/pyospackage" +``` +::: + +## Example `pyproject.toml` files + +Below are some examples of `pyproject.toml` files from various packages in the scientific and pyOpenSci ecosystem. +* [PyPA's fully documented example pyproject.toml file](https://github.com/pypa/sampleproject/blob/main/pyproject.toml) +* [taxpasta has a nicely organized pyproject.toml file and is a pyOpenSci approved package](https://github.com/taxprofiler/taxpasta/blob/f9f6eea2ae7dd08bb60a53dd49ad77e4cf143573/pyproject.toml) + + +## Wrap up + + +At this point you've created: + +* A [README.md](add-readme) file for your package +* A [CODE_OF_CONDUCT.md](add-coc) file to support your user community +* And a [LICENSE](add-license-coc) file which provides legal boundaries around how people can and can't use your software + +You also learned [how to publish your package to (test)PyPI](publish-pypi). + +## Publish a new version of your package to PyPI + +You are now ready to publish a new version of your Python package to (test) PyPI. When you do this you will see that the landing page for your package now contains a lot more information. + +Try to republish now. + +First, update the version of your package in your pyproject toml file. Below version is updated from +`0.1.0` to `0.1.1`. + +```TOML +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pyospackage" +version = "0.1.1" +``` + +Now use hatch to publish the new version of your package to test.PyPI.org. + +```bash +> hatch publish -r test + +``` + +### Next (optional) step - publishing to conda-forge + +You now have all of the skills that you need to publish +your package to PyPI. + +If you also want to publish your package on conda-forge (which is a channel within the conda ecosystem), you will learn how to do that in the next lesson. + + +:::{todo} +Really good resources from jeremiah https://daniel.feldroy.com/posts/2023-08-pypi-project-urls-cheatsheet useful (and the linked links-demo even more so) +::: diff --git a/documentation/index.html b/documentation/index.html index 1cba2c30..1dd9659d 100644 --- a/documentation/index.html +++ b/documentation/index.html @@ -62,7 +62,7 @@ - + @@ -649,12 +649,12 @@

What’s next in this Python package documentation section?

previous

-

Add a README file to your Python package

+

Make your Python package PyPI ready - pyproject.toml

How to choose a licenseTo select your license, we suggest that you use GitHub’s Choose a License tool .

If you choose your license when creating a new GitHub repository, you can also -automatically get a text copy of the license file to add to your repo. However +automatically get a text copy of the license file to add to your repository. However in some cases the license that you want is not available through that online process.

@@ -603,8 +603,8 @@

Important: make sure that you closely follow the guidelines outlines by the with the license that you selected for your package.

An example of how a license determine how code can be reused

-

Let’s use stackOverflow as an example that highlights how a license determines how code can or can not be used.

-

Stack overflow uses a Creative Commons Share Alike license.. The sharealike license requires you to use the same sharealike license when you reuse any code from stackoverflow.

+

Let’s use StackOverflow as an example that highlights how a license determines how code can or can not be used.

+

Stack overflow uses a Creative Commons Share Alike license.. The sharealike license requires you to use the same sharealike license when you reuse any code from StackOverflow.

This means that technically, if you copy code from the Stack Overflow website, and use it in your package. And your packages uses a different license such as a MIT license, you are violating Stack Overflow’s license requirements!

🚨 Proceed with caution! 🚨

@@ -612,7 +612,7 @@

Important: make sure that you closely follow the guidelines outlines by the

What about software citation?#

While many permissive licenses do not require citation we STRONG encourage that you cite all software that you use in papers, blogs and other publications. You tell your users how to cite your package by using a citation.cff file. We will cover this topic when we talk about creating DOI’s for your package using zenodo.

- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+
+
+
+
+ + + + + + + +
+
+ +
+ + + + + + + + + + + + + +
+ +
+ + +
+
+ +
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ + + + + +
+ +
+

Add a LICENSE & CODE_OF_CONDUCT to your Python package#

+

In the previous lesson you:

+

Created a basic README.md file for your scientific Python package

+

Learned about the core components that are useful to have in a README file.

+
+

Learning objectives

+

In this lesson you will learn:

+
    +
  1. How to select and add a LICENSE file to your package repository with a focus on the GitHub interface.

  2. +
  3. How to add a CODE_OF_CONDUCT file to your package repository.

  4. +
  5. How you can use the Contributors Covenant website to add generic language as a starting place for your CODE_OF_CONDUCT.

  6. +
+
+
+

What is a license?#

+

A license contains legal language about how users can use and reuse your software. To set the LICENSE for your project, you:

+
    +
  1. create LICENSE file in your project directory that specifies the license that you choose for your package and

  2. +
  3. reference that file in your pyproject.toml data where metadata are set.

  4. +
+

By adding the LICENSE file to your pyproject.toml file, the LICENSE will be included in your package’s metadata which is used to populate your package’s PyPI landing page. The LICENSE is also used in your GitHub repository’s landing page interface.

+
+

What license should you use?#

+

We suggest that you use a permissive license that accommodates the other most commonly used licenses in the scientific Python ecosystem (MIT[1] and BSD-3[2]). If you are unsure, use MIT given it’s the generally recommended +license on choosealicense.com.

+ +
+
+

Where should the LICENSE file live#

+

Your LICENSE file should be placed at the root of your package’s repository. +When you add the LICENSE at the root, GitHub will automagically discover it and +provide users with a direct link to your license file within your GitHub +repository.

+
+Image showing the GitHub repository for SunPy an accepted pyOpenSci package. +
+

Notice at the top of the +README portion of the GitHub landing page, there are three tabs directly linking to the README file which is visible, the CODE_OF_CONDUCT file and one that specifies +the license that SunPy uses. These files are discovered by GitHub because they +are placed in the root of the project directory using standard naming conventions.#

+
+
+
+
+

How to add a LICENSE file to your package directory#

+

There are several ways to add a LICENSE file:

+
    +
  1. When you create a new repository on GitHub, it will ask you if you wish to add a LICENSE file at that time. If you select yes, it will create the file for you.

  2. +
  3. You can add a license through the GitHub gui following the instructions here.

  4. +
  5. You can add the file manually like we are doing in this lesson.

  6. +
+
+

Tip

+

If you completed the past lessons including

+
    +
  1. Making your code installable and

  2. +
  3. publishing your package to PyPI

  4. +
+

then you already have a LICENSE file containing text for the MIT license in your Python package. Thus you can skip to the next section of this tutorial which walks you through adding a CODE_OF_CONDUCT.

+

If you don’t yet have a LICENSE file in your directory, then continue reading.

+
+
+
+

How to add a LICENSE to your package - the manual way#

+

If you don’t already have a LICENSE file, and you are not yet using a platform such as GitHub or GitLab, then you can create a license file by

+
    +
  1. Create a new file called LICENSE. If you are using shell you can type:

  2. +
+
# Create a license file in your shell
+> touch LICENSE
+
+
+
    +
  1. Go to choosealicense.com

  2. +
  3. Select permissive license

  4. +
  5. It will suggest that you use the MIT license.

  6. +
  7. Copy the license text that it provides into your LICENSE file that you created above.

  8. +
  9. Save your file. You’re all done!

  10. +
+
+

An overview of LICENSES in the scientific Python ecosystem

+

In the pyOpenSci packaging guidebook, we provide an overview of license in the scientific Python ecosystem. We review why license files are important, which ones are most commonly used for scientific software and how to select the correct license.

+

If you want a broad overview of why licenses are important for protecting open source software, check out this blog post that overviews the legal side of things.

+
+
+ +Instructions for adding a license files within the GitHub interface
+
+
+
+
+
+ +
+

When you create a new GitHub repository you can add a license +through the GitHub interface.

+
+Screenshot of the create new repository interface that GitHub provides. The elements of this are the owner and repository name for the new repo. Below that you can add a description of the repository. Below that you can set it to be public or private. At the bottom of the interface there is an Add a README checkbox where it will add a blank readme file for you. At the very bottom there is a line to add a .gitignore file and another to choose a license. +
+

Image showing the GitHub interface that allows you to add a LICENSE and README file when you create a new repository.#

+
+
+
+ +
+

If you already have a GitHub repository for your package, then you can add a LICENSE using the GitHub interface by adding a new file to the repository.

+
    +
  • Follow the instructions to select and add a license to your repository on the GitHub LICENSE page .

  • +
  • Once you have added your LICENSE file, be sure to sync your git local repository with the repository on GitHub.com. This means running git pull to update your local branch.

  • +
+
+Image showing what the LICENSE file looks like in the GItHub interface. At the top you can see the actual license which in this image is BSD 3-clause New or revised license. Then there is some text describing both what the license is and the associated permissions for that specific license. At the bottom of the image, the actual text for the license is shown in the LICENSE file. +
+

You can view a summary of the LICENSE chosen on your project’s +GitHub landing page.#

+
+
+
+
+
+

Now you know how to add a LICENSE to your project. Next, you’ll learn +about the CODE_OF_CONDUCT.md file and how to add it to your +package directory.

+
+
+
+

What is a code of conduct file?#

+

A CODE_OF_CONDUCT file is used to establish guidelines for how people in your community interact.

+

This file is critical to supporting your community as it +grows. The CODE_OF_CONDUCT:

+
    +
  1. Establishes guidelines for how users and contributors interact with each other and you in your software repository.

  2. +
  3. Identifies negative behaviors that you don’t want in your interactions.

  4. +
+

You can use your code of conduct as a tool that can be referenced when moderating challenging conversations.

+
+

What to put in your code of conduct file#

+

If you are unsure of what language to add to your CODE_OF_CONDUCT +file, we suggest that you adopt the contributor covenant language as a starting place.

+

Contributor Covenant

+

The CODE_OF_CONDUCT.md should be placed at the root of your project directory, similar to the LICENSE file.

+
+
+

How to add a CODE_OF_CONDUCT file to your package directory#

+
    +
  • Add a CODE_OF_CONDUCT.md file to the root of your repository if it doesn’t already exist.

  • +
+
> touch CODE_OF_CONDUCT.md
+
+
+ +

That’s it - you’ve now added a code of conduct to your package directory.

+ +
+
+
+

Wrap up#

+

In this lesson and the last lesson, you have added a:

+
    +
  • README file;

  • +
  • LICENSE file and a

  • +
  • CODE_OF_CONDUCT file.

  • +
+

These are fundamental files needed for every scientific Python package +repository. These files help users understand how to use your package and +interact with package maintainers.

+

In the upcoming lessons, you will:

+ +
+
+
+

Footnotes#

+
+ +
+
+ + +
+ + + + + + + +
+ + + + + + +
+
+ +
+ +
+
+
+ + + + + +
+ + +
+ + \ No newline at end of file diff --git a/tutorials/add-readme.html b/tutorials/add-readme.html index 2901b21c..4c1ced0a 100644 --- a/tutorials/add-readme.html +++ b/tutorials/add-readme.html @@ -11,12 +11,12 @@ - + - - - + + + Add a README file to your Python package — Python Packaging Guide @@ -61,7 +61,7 @@ - + @@ -455,16 +455,18 @@ -

Create a Python package

+

Create and publish a Python Package

-

Project Metadata

+

Project information files & metadata

@@ -526,9 +528,10 @@

Add a README file to your Python package#

In the previous lessons you learned:

    -
  1. What a Python package is

  2. -
  3. How to make your code installable

  4. -
  5. How to publish your package to (test) PyPI

  6. +
  7. What a Python package is

  8. +
  9. How to make your code installable

  10. +
  11. How to publish your package to (test) PyPI

  12. +
  13. How to publish your package to conda-forge

Learning objectives

@@ -550,14 +553,16 @@

What is a README file?

How to contribute to your package

  • How to cite your package

  • -

    Your README.md file is important as it is often the first thing that someone sees before they install your package. The README file also will be used to populate your PyPI landing page.

    -

    Note that there is no required format for README files. This page simply outlines sections that we suggest you have in your README file.

    +

    Your README.md file is important as it is often the first thing that someone sees before they install your package. The README file is also used to populate your PyPI landing page.

    +

    Note that there is no specific content structure for README files. +However, this tutorial outlines the sections that we suggest that you +include in your README file.

    Create a README.md file for your package#

    It’s time to add a README.md file to your project directory.

    -

    Step 0. Create a README file#

    +

    Step 0: Create a README file#

    To get started, if you don’t already have a README.md file in your project directory, create one.

    Tip

    @@ -572,24 +577,24 @@

    Step 0. Create a README file -

    Step 1. Add the name of your package as the README title#

    +

    Step 1: Add the name of your package as the README title#

    At the top of the README.md file, add the name of your package.

    -

    If you are using markdown it should be a header 1 tag which is denoted with a single # sign.

    +

    If you are using markdown it should be a header 1 (H1) tag which is denoted with a single # sign.

    # Package-title-here

    -

    Step 2 - add badges to the top of your README file#

    -

    It’s common for maintainers to add badges to the top of their README files. Badges allow you and your package users to track things like

    +

    Step 2: add badges to the top of your README file#

    +

    It’s common for maintainers to add badges to the top of their README files. Badges allow you and your package users to track things like:

    • Broken documentation and test builds.

    • -
    • Versions of your package that are on PyPI and Conda.

    • +
    • Versions of your package that are on PyPI and conda.

    • Whether your package has been reviewed and vetted by an organization such as pyOpenSci and/or JOSS.

    If you have already published your package to pypi.org you can use shields.io to create a package version badge. This badge will dynamically update as you release new versions of your package to PyPI.

    -

    If not, you can leave the top empty for now and add badges to your README at a later point as they make sense for your package.

    +

    If not, you can leave the top empty for now and add badges to your README at a later point as they make sense.

    -

    Step 3 - Add a description of what your package does#

    +

    Step 3: Add a description of what your package does#

    Below the badges (if you have them), add a section of text that provides an easy-to-understand overview of what your package does.

    @@ -601,7 +606,7 @@

    Step 3 - Add a description of what your package doesRemember that the more people understand what your package does, the more people will use it.

    -

    Step 4 - Add package installation instructions#

    +

    Step 4: Add package installation instructions#

    Next, add instructions that tell users how to install your package.

    For example, can they use pip to install your package? pip install packagename

    @@ -612,7 +617,7 @@

    Step 4 - Add package installation instructions -

    Step 5 - Any additional setup#

    +

    Step 5: Any additional setup#

    In some cases, your package users may need to manually install other tools in order to use your package. If that is the case, be sure to add a section on additional setup @@ -626,19 +631,19 @@

    Step 5 - Any additional setup

    Note

    -

    Many packages won’t need this section in their README. In that case you can always skip this section!

    +

    Many packages won’t need an additional setup section in their README. +In that case you can always skip this section.

    -

    Step 6 - Add a get started section#

    -

    Next add a getting started section that shows how to use your package. This -section should include a small code snippet that demonstrates importing and using +

    Step 6: Add a get started section#

    +

    Next add a get-started section. Within this section, add a small code example that demonstrates importing and using some of the functionality in your package.

    Provide a fully functional code snippet if possible

    It is important to try to make the code examples that you provide your users as useful as possible.

    Be sure to provide a copy/paste code example that will work as-is when pasted into a Jupyter Notebook or .py file if that is possible.

    -

    If there are tokens and other steps needed to run your package, be sure to be clear about what those steps entail.

    +

    If there are tokens and other steps needed to run your package, be sure to be clear about what those steps are.

    For the pyosPackage, a short get started demo might look like this:

    >>> from pyospackage.add_numbers import add_num
    @@ -649,26 +654,32 @@ 

    Step 6 - Add a get started section -

    Step 7 - Community section#

    +

    Step 7: Community section#

    The community section of your README file is a place to include information for users who may want to engage with your project. This engagement will likely happen on a platform like GitHub or GitLab.

    In the community section, you will add links to your contributing guide -and CODE_OF_CONDUCT.md. You will add a CODE_OF_CONDUCT.md file in the next lesson.

    -

    As your package grows you may also have a link to a development guide that contributors and your maintainer team will follow.

    +and CODE_OF_CONDUCT.md. You will create a CODE_OF_CONDUCT.md file in the next lesson.

    +

    As your package grows you may also have a link to a development guide that contributors and your maintainer team will follow. The development guide +outlines how to perform maintenance tasks such as:

    +
      +
    • running tests

    • +
    • making package releases

    • +
    • building documentation

    • +
    • and more.

    • +
    -

    Step 8 - Citation information#

    +

    Step 8: Citation information#

    Finally it is important to let users know how to cite your package. You can communicate citation information in a few different ways.

    You can use a tool such as zenodo to create a DOI and associated citation information for your package if it is hosted on a platform such as GitHub. Check out this short tutorial that covers setting that up.

    Alternatively if you send your package through a peer review process such -as the one lead by pyOpenSci, then you can get a cross-ref DOI through our partnership -with the Journal of Open Source Software.

    +as the one lead by pyOpenSci. After being accepted by pyOpenSci, if your package is in scope, you can be accepted by the Journal of Open Source Software and get a cross-ref DOI through our partnership with the Journal of Open Source Software.

    @@ -751,11 +762,11 @@

    The finished README file

    next

    -

    Documentation for your Open Source Python Package

    +

    Add a LICENSE & CODE_OF_CONDUCT to your Python package

    @@ -777,15 +788,15 @@

    The finished README file
  • What is a README file?
  • Create a README.md file for your package
  • The finished README file
  • diff --git a/tutorials/get-to-know-hatch.html b/tutorials/get-to-know-hatch.html index 15c337a2..2ffb9960 100644 --- a/tutorials/get-to-know-hatch.html +++ b/tutorials/get-to-know-hatch.html @@ -455,16 +455,18 @@ -

    Create a Python package

    +

    Create and publish a Python Package

    -

    Project Metadata

    +

    Project information files & metadata

    diff --git a/tutorials/intro.html b/tutorials/intro.html index c29cbaa8..c82648ad 100644 --- a/tutorials/intro.html +++ b/tutorials/intro.html @@ -455,16 +455,18 @@ -

    Create a Python package

    +

    Create and publish a Python Package

    -

    Project Metadata

    +

    Project information files & metadata

    @@ -768,7 +770,7 @@

    Python packages and environments -Diagram showing the steps associated with creating a package and then installing it. The first arrow says your package and the second says pip install package. The second arrow leads to a box that represents a Python environment that already has some packages installed such as pandas and NumPy. Your package will also get installed into that same environment when you pip install it. +Diagram showing the steps associated with creating a package and then installing it. The first arrow says your package and the second says pip install package. The second arrow leads to a box that represents a Python environment that already has some packages installed such as Pandas and NumPy. Your package will also get installed into that same environment when you pip install it.

    You don’t have to publish to PyPI to make your code installable. With the correct file structure and project metadata you can make your code @@ -791,7 +793,7 @@

    Publishing a package to PyPI / Conda-ForgeGraphic showing the high level packaging workflow. On the left you see a graphic with code, metadata and tests in it. Those items all go into your package. Documentation and data are below that box because they aren't normally published in your packaging wheel distribution. an arrow to the right takes you to a build distribution files box. that box leads you to either publishing to testPyPI or the real PyPI. From PyPI you can then connect to conda-forge for an automated build that sends distributions from PyPI to conda-forge.

    In the image above, you can see the steps associated with publishing -your package on PyPI and conda-forge. Note that the distribution files that PyPI requires are the sdist and wheel files. Once you are ready to make your code publicly installable, you can publish it on PyPI. Once your code is on PyPI it is straight forward to then publish to conda-forge. You create a recipe using the Grayskull package and then you open a pr in the conda-forge recipe repo. You will learn more about this process in the conda-forge lesson.#

    +your package on PyPI and conda-forge. Note that the distribution files that PyPI requires are the sdist and wheel files. Once you are ready to make your code publicly installable, you can publish it on PyPI. Once your code is on PyPI it is straight forward to then publish to conda-forge. You create a recipe using the Grayskull package and then you open a pr in the conda-forge recipe repository. You will learn more about this process in the conda-forge lesson.#

    diff --git a/tutorials/publish-conda-forge.html b/tutorials/publish-conda-forge.html index 4925b3ef..74f370f1 100644 --- a/tutorials/publish-conda-forge.html +++ b/tutorials/publish-conda-forge.html @@ -455,16 +455,18 @@ -

    Create a Python package

    +

    Create and publish a Python Package

    -

    Project Metadata

    +

    Project information files & metadata

    diff --git a/tutorials/publish-pypi.html b/tutorials/publish-pypi.html index 942c1b2b..7ca3439a 100644 --- a/tutorials/publish-pypi.html +++ b/tutorials/publish-pypi.html @@ -11,12 +11,12 @@ - + - - - + + + Publish your Python package to PyPI — Python Packaging Guide @@ -455,16 +455,18 @@ -

    Create a Python package

    +

    Create and publish a Python Package

    -

    Project Metadata

    +

    Project information files & metadata

    @@ -524,6 +526,14 @@

    Publish your Python package to PyPI#

    +
    pipx install hatch
    +  installed package hatch 1.9.1, installed using Python 3.12.1
    +  These apps are now globally available
    +    - hatch
    +done!  🌟 ✨
    +
    +
    +

    In the previous Python packaging lessons, you’ve learned:

    1. What a Python package is

    2. @@ -541,8 +551,7 @@

      Publish your Python package to PyPIGrayskull.

      You will learn how to publish to conda-forge in a future lesson.

      -

    -
    +

    You will learn how to publish to conda-forge in the next lesson.

    Graphic showing the high level packaging workflow. On the left you see a graphic with code, metadata and tests in it. Those items all go into your package. An arrow to the right takes you to a build distribution files box. Another arrow to the right takes you to a publish to PyPI box which has an arrow containing sdist and wheel that notes those files go to PyPI for hosting. From PyPI is an arrow containing sdist since you can then connect to conda-forge for an automated build that sends distributions from PyPI to conda-forge.
    @@ -550,6 +559,7 @@

    Publish your Python package to PyPI

    Test PyPI vs PyPI#

    There are two “warehouses” that you can use to publish @@ -642,7 +652,7 @@

    Step 1: Create a Python package development environment

    Hatch and environments#

    Behind the scenes when hatch creates a new virtual environment, -by default it uses venv[1] which is the default environment management tool that comes with Python installations.

    +by default it uses venv[1] which is the default environment management tool that comes with Python installations.

    Hatch will:

    1. Create a new virtualenv (venv) that is located on your computer.

    2. @@ -673,6 +683,8 @@

      Step 2: Build your package’s sdist and wheel distributionsbuild page of our packaging guide.

    +

    The sdist is important if you wish to publish +your package to conda-forge. You will learn about this in a later lesson.

    Congratulations - you’ve created your Python package distribution files #

    You’ve now built your Python package and created your package distribution files. The next step is to setup @@ -696,11 +708,11 @@

    Step 3. Setup your test PyPI accounthttps://test.pypi.org/ to ensure that the package name that you have selected doesn’t already exist. If you are using our test pyosPackage, then we suggest that you add your name or GitHub username to the end of the package name to ensure it’s unique.

    Example: pyosPackage_yourNameHere.

    -
    +
    This is a screenshot of the test PyPI website. At the top in the search bar, you can see the search for pyosPackage. The search return says there were no results for pyosPackage Did you mean probpackage

    Before you try to upload to test PyPI, check to see if the name of your package is already taken. You can do that using -the search box at the top of the test PyPI website.#

    +the search box at the top of the test PyPI website.#

    - -

    @@ -856,10 +862,13 @@

    You have published your package to (test) PyPI!

    Footnotes#

    +
    
    +
    +

    diff --git a/tutorials/pyproject-toml.html b/tutorials/pyproject-toml.html new file mode 100644 index 00000000..3b46ace7 --- /dev/null +++ b/tutorials/pyproject-toml.html @@ -0,0 +1,1202 @@ + + + + + + + + + + + + + + + + + + + + + + Make your Python package PyPI ready - pyproject.toml — Python Packaging Guide + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    +
    +
    +
    +
    + + + + + + + +
    +
    + +
    + + + + + + + + + + + + + +
    + +
    + + +
    +
    + +
    +
    + +
    + +
    + + + + +
    + +
    + + +
    +
    + + + + + +
    + +
    +

    Make your Python package PyPI ready - pyproject.toml#

    +

    In the installable code lesson, you learned how to add the bare minimum information to a pyproject.toml file to make it installable. You then learned how to publish a bare minimum version of your package to PyPI.

    +

    Following that you learned how to add a:

    + +

    to the root of your project directory.

    +

    To enhance the visibility of your package on PyPI and provide more information +about its compatibility with Python versions, project development status, and +project maintainers, you should add additional metadata to your pyproject.toml +file. This +lesson will guide you through the process.

    +
    +

    Learning Objectives

    +

    In this lesson you will learn:

    +
      +
    1. More about the pyproject.toml file and how it’s used to store different types of metadata about your package

    2. +
    3. How to declare information (metadata) about your project to help users find and understand it on PyPI.

    4. +
    +

    If you wish to learn more about the pyproject.toml format, check out this page.

    +
    +
    + +Click for lesson takeaways
    +
    +
    +
    +
    +

    When creating your pyproject.toml file, consider the following:

    +
      +
    1. There are only two required metadata tables that you need to install and publish your Python package:

      +
        +
      • [build-system]

      • +
      • [project].

      • +
      +
    2. +
    3. The [project] table stores your package’s metadata. Within the [project] table, There are only two required fields:

      +
        +
      • name=

      • +
      • version=

      • +
      +
    4. +
    5. You should add more metadata to the [project] table as it will make it easier for users to find your project on PyPI. And it will also make it easier for installers to understand how to install your package.

    6. +
    7. When you are adding classifiers to the [project] table, only use valid values from PyPI’s classifier page. An invalid value here will raise an error when you build and publish your package on PyPI.

    8. +
    9. There is no specific order for tables in the pyproject.toml file. However, fields need to be placed within the correct tables. For example requires = always need to be in the [build-system] table.

    10. +
    11. We suggest that you include your [build-system] table at the top of your pyproject.toml file.

    12. +
    +
    +
    +

    What is a pyproject.toml file?#

    +

    The pyproject.toml file is a human and machine-readable file that serves as the primary configuration file for your Python package.

    +
    +

    Tip

    +

    Building your package is the step that created the distribution files that are required for you to publish to PyPI.

    +
    +
    +

    About the .toml format#

    +

    The pyproject.toml file is written in TOML (Tom’s Obvious, Minimal Language) format. TOML is an easy-to-read structure that is based on key/value pairs. Each section in the pyproject.toml file contains a [table identifier]. The TOML format can be compared to other structured formats such as.json. However, the TOML format was designed to be easier to read for humans.

    +

    Below you can see the [build-system] table. Within +that table there are two required key/value pairs.

    +

    requires = is the key and the value is ["hatchling"] within the [build-system] array specified by square brackets [].

    +
    [build-system] # <- This is a table
    +requires = ["hatchling"]
    +# The build backend defines the tool that should be used to build your package distribution files.
    +build-backend = "hatchling.build"
    +
    +
    +
    +
    +

    What is the pyproject.toml used for?#

    +

    The pyproject.toml file tells your build tool:

    +
      +
    • What build backend to use to build your package (we are using hatchling in this tutorial but there are many others to chose from).

    • +
    • How and where to retrieve your package’s version:

      +
        +
      • statically where you declare the version version = "0.1.0" or

      • +
      • dynamically where the tool looks to the most recent tag in your history to determine the current version.

      • +
      +
    • +
    • What dependencies your package needs

    • +
    • What versions of Python your package supports (important for your users).

    • +
    +

    The pyproject.toml file also makes it easy for anyone browsing your GitHub +repository to quickly understand your package’s structure such as:

    +
      +
    • How your package is built,

    • +
    • What Python versions and operating systems it supports

    • +
    • What it does,

    • +
    • Who maintains it

    • +
    +

    Finally, the pyproject.toml file is also often used to configure tools such as static type checkers (e.g. mypy) and code formatters/linters (e.g. black, ruff).

    +
    +

    Tip

    +

    Check out the PyPA documentation if you are interested in setting build configurations for other tools.

    +

    Note that some build tools may deviate in how they store project metadata. As such you may want to refer to their documentation if you decide to use a tool other than Hatch and hatchling. We have selected hatchling and hatch as our tool of choice for this tutorial as it adheres to PyPA rules and guidelines.

    +
    +
    +
    +

    How is pyproject.toml metadata used?#

    +

    The pyproject.toml file is the file that your build tool uses to populate +a METADATA that is included in your Python distribution files that get published to PyPI. This METADATA file is then used by PyPI to populate your package’s PyPI landing page and help users filter through the tens of thousands of packages published there.

    +
    +Image showing the left side bar of PyPI for the package xclim. The section at the top says Classifier. Below there is a list of items including Development status, intended audience, License, natural language, operating system, programming language and topic. Below each of those sections are various classifier options." width="300px"> +
    +

    When you add the classifier section to your pyproject.toml +and your package is built, the build tool organizes the metadata into a format that PyPI can understand and +represent on your PyPI landing page. These classifiers also allow users to sort through packages by version of python they support, categories and more.#

    +
    +
    +
    +

    Tip

    +

    A more in-depth overview of pyproject.toml files

    +

    Our guidebook page has a more in depth overview of this file

    +
    +
    +
    +
    +

    How to update your pyproject.toml file#

    +

    In the last lesson, you created a bare-bones pyproject.toml +file that contained the core elements needed to build your +package:

    +
      +
    1. A [build-system] table where you defined your project’s backend build tool (hatchling)

    2. +
    3. A [project] table where you defined your project’s version and name.

    4. +
    +

    The pyproject.toml file that you created, looked like this:

    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.0"
    +
    +
    +

    Your next step is to add additional recommended metadata fields that will both +help users find your package on PyPI and also better describe the scope of your package. Once you add this metadata, you don’t have to do it again. These metadata fields will only be updated periodically when you do something such as:

    +
      +
    • drop a package dependency

    • +
    • modify what Python versions your package supports.

    • +
    +
    +

    More on hatchling

    +

    The documentation for the hatchling back-end is here

    +
    +
    +

    Step 1: Populate the [project] table with author, maintainer and project description#

    +

    After completing the installable code tutorial, you should have a pyproject.toml file with a project name and a version in the [project] table.

    +
    [project]
    +name = "pyospackage"
    +version = "0.1.0"
    +
    +
    +

    Add the following to your table:

    +
      +
    • A description of your package. This should be a single line and should briefly describe the goal of your package using non technical terms if as all possible!

    • +
    • package authors

    • +
    • package maintainers

    • +
    +

    When you add authors and maintainers you need to use a format that will look like a Python list with a dictionary within it:

    +

    authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]

    +

    If you have two authors you can add them like this:

    +

    authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]

    +
    +

    Author names & emails

    +

    There is a quirk with PyPI for authors that have names but not emails in the pyproject.toml. If you are missing the email for one or more authors or maintainers, like this:

    +
    maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname" }]
    +
    +
    +

    Then we suggest that you only provide names in your list of names to ensure that everything renders properly on your PyPI page - like this:

    +
    maintainers = [{ name = "Firstname lastname"}, { name = "Firstname lastname" }]
    +
    +
    +

    don’t have emails for everyone, we suggest that you only add names.

    +
    +

    Your pyproject.toml file now should look like the example below. It is OK if you only have 1 author and the same author is also maintainer of your package:

    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.0"
    +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website"
    +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]
    +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]
    +
    +
    +
    + +Learn More: What’s the difference between author and maintainer in open source?
    +
    +
    +
    +
    +

    When adding maintainers and authors, you may want to think about the difference between the two.

    +

    Authors generally include people who:

    +
      +
    • originally created / designed developed the package and

    • +
    • people who add new functionality to the package.

    • +
    +

    Whereas maintainers are the people that are currently, actively working on the project. It is often the case that there is overlap in authors and maintainers. As such these lists may be similar or the same.

    +

    A good example of when the lists might diverge is sometimes you have a package where an initial author developed it and then stepped down as a maintainer to move on to other things. This person may continue to be considered an author but no longer actively maintains the package.

    +

    It is important to note that there are many ways to define author vs maintainer and we don’t prescribe a single approach in this tutorial.

    +

    However, we encourage you to consider carefully, for PyPI publication, who +you want to have listed as authors and maintainers on your PyPI landing page.

    +
    +
    + +
    +

    Step 3: Add requires-python to your [project] table#

    +

    Finally, add the requires-python field to your pyproject.toml [project] table. The requires-python field, helps pip understand the lowest version of Python that you package supports when it’s installed. It is thus a single value.

    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.0"
    +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website"
    +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]
    +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]
    +readme = "README.md"
    +license = {file = 'LICENSE'}
    +requires-python = ">=3.10"
    +
    +
    +
    +
    +

    Step 4: Add package dependencies to your [project] table#

    +

    Next add your dependencies table to the project table. +The dependencies = section contains a list (or array in the toml language) of the Python packages that your package requires to run properly in a Python environment. Similar to the requirements listed in the [build-system] table above:

    +
    [build-system] # <- this is a table
    +requires = ["hatchling"] # this is an array (or list) of requirements
    +
    +
    +

    dependencies are added in an array (similar to a Python list) structure.

    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.0"
    +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website"
    +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]
    +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]
    +readme = "README.md"
    +license = {file = 'LICENSE'}
    +requires-python = ">=3.10"
    +
    +dependencies = ["numpy", "requests", "pandas", "pydantic"]
    +
    +
    +
    +

    Pin dependencies with caution

    +

    Pinning dependencies refers to specifying a specific version of a dependency like this numpy == 1.0. In some specific cases, you may chose to pin a package version for a specific package dependency.

    +

    Declaring lower bounds involves ensuring that a user has at least a specific version (or greater) of a package installed. This is important as often your package is not backwards compatible with an older version of a tool - for example a version of Pandas that was released 5 years ago.

    +

    You can declare a lower bound using syntax like this:

    +

    ruamel-yaml>=0.17.21

    +

    Learn more about various ways to specify ranges of package versions here.

    +

    Note that unless you are building an application, you want to be cautious about pinning dependencies to precise versions. For example:

    +

    numpy == 1.0.2

    +

    This is because +users will be installing your package into various environments. +A dependency pinned to a single specific version can make +resolving a Python environment more challenging. As such only +pin dependencies to a specific version if you absolutely need to +do so.

    +

    One build tool that you should be aware of that pins dependencies to an upper bound by default is Poetry. Read more about how to safely add dependencies with Poetry, here.

    +
    +
    +
    +

    Step 5: Add PyPI classifiers to your pyproject.toml file#

    +

    Next you will add classifiers to your pyproject.toml file. The value for each classifier that you add to your pyproject.toml file must come from the list of PyPI accepted classifier values found here. Any deviations in spelling and format will cause issues when you publish to PyPI.

    +
    +

    What happens when you use incorrect classifiers?

    +

    If you do not use standard classifier values, when you try to publish your package on PyPI it will be rejected. 😔 Don’t worry if PyPI rejects you on your first try! It has happened to all of us.

    +
    +

    Review that list and add items below to your pyproject.toml file:

    +
      +
    • development status

    • +
    • intended audiences

    • +
    • topic

    • +
    • license and

    • +
    • programming language support

    • +
    +

    The classifier key should look something like the example below. A few notes:

    +
      +
    • Your classifier values might be different depending upon the license you have selected for your package, your intended audience, development status of your package and the Python versions that you support

    • +
    • You can add as many classifiers as you wish as long as you use the designated PyPI classifier values.

    • +
    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.0"
    +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website"
    +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]
    +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]
    +readme = "README.md"
    +license = {file = 'LICENSE'}
    +requires-python = ">=3.10"
    +
    +dependencies = ["numpy", "requests", "pandas", "pydantic"]
    +
    +classifiers = [
    +    "Development Status :: 4 - Beta",
    +    "Intended Audience :: Developers",
    +    "Topic :: Software Development :: Build Tools",
    +    "License :: OSI Approved :: MIT License",
    +    "Programming Language :: Python :: 3 :: Only",
    +    "Programming Language :: Python :: 3.10",
    +    "Programming Language :: Python :: 3.11",]
    +
    +
    +

    Note that while classifiers are not required in your pyproject.toml file, they will help users find your package. As such we strongly recommend that you add them.

    +
    +
    +

    Step 6: Add the [project.urls] table#

    +

    Finally, add the project.urls table to your pyproject.toml file.

    +

    project.urls contains links that are relevant for your project. You might want to include:

    +
      +
    • Homepage: A link to your published documentation for your project. If you are working through this tutorial, then you may not have this link yet. That’s ok, you can skip it for the time being.

    • +
    • Bug reports: a link to your issues / discussions or wherever you want users to report bugs.

    • +
    • Source: the GitHub / GitLab link for your project.

    • +
    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.0"
    +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website"
    +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]
    +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]
    +readme = "README.md"
    +license = {file = 'LICENSE'}
    +requires-python = ">=3.10"
    +
    +dependencies = ["ruamel-yaml>=0.17.21", "requests", "python-dotenv", "pydantic"]
    +
    +classifiers = [
    +    "Development Status :: 4 - Beta",
    +    "Intended Audience :: Developers",
    +    "Topic :: Software Development :: Build Tools",
    +    "License :: OSI Approved :: MIT License",
    +    "Programming Language :: Python :: 3 :: Only",
    +    "Programming Language :: Python :: 3.10",
    +    "Programming Language :: Python :: 3.11",
    +    ]
    +
    +[project.urls] # Optional
    +"Homepage" = "https://www.pyopensci.org"
    +"Bug Reports" = "https://github.com/pyopensci/pyosmeta/issues"
    +"Source" = "https://github.com/pyopensci/pyosmeta/"
    +
    +
    +
    +

    Tip

    +

    There are many other urls that you can add here. Check out the README file here for an overview.

    +
    +
    +
    +
    +

    Putting it all together - your completed pyproject.toml file#

    +

    Below is an example of a complete pyproject.toml file that +is commented with all of the sections we discussed above.

    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.0"
    +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website"
    +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]
    +maintainers = [{ name = "Firstname lastname", email = "email@pyopensci.org" }, { name = "Firstname lastname", email = "email@pyopensci.org" }]
    +readme = "README.md"
    +license = {file = 'LICENSE'}
    +requires-python = ">=3.10"
    +
    +dependencies = ["ruamel-yaml>=0.17.21", "requests", "python-dotenv", "pydantic"]
    +
    +classifiers = [
    +    "Development Status :: 4 - Beta",
    +    "Intended Audience :: Developers",
    +    "Topic :: Software Development :: Build Tools",
    +    "License :: OSI Approved :: MIT License",
    +    "Programming Language :: Python :: 3 :: Only",
    +    "Programming Language :: Python :: 3.10",
    +    "Programming Language :: Python :: 3.11",
    +    ]
    +
    +[project.urls] # Optional
    +"Homepage" = "https://www.pyopensci.org"
    +"Bug Reports" = "https://github.com/pyopensci/pyosmeta/issues"
    +"Source" = "https://github.com/pyopensci/pyosmeta/"
    +
    +
    +
    + +Appendix - Click for a fully commented pyproject.toml file
    +
    +
    +
    +
    +

    Below is a fully commented pyproject.toml file if you want to use it for reference.

    +
    # You can delete all of the comments once you have created your own pyproject.toml file.
    +
    +# The build system table. Here we use hatchling as the build back end tool.
    +[build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +# The [project] section contains your package's metadata
    +# notice that the version is setup to be dynamically generated using dynamic=[“version”]
    +
    +[project]
    +name = "pyospackage"
    +# dynamic = ["version"] # you will learn how to dynamically set the version in a future lesson
    +version = "0.1.0" # manually assign version (not preferred)
    +description = "Tools that update the pyOpenSci contributor and review metadata that is posted on our website"
    +authors = [{ name = "Firstname lastname", email = "email@pyopensci.org" }]
    +
    +# maintainers section is optional but suggested.
    +maintainers = [
    +    { name = "firstname lastname", email = "admin@pyopensci.org" }, # Optional
    +]
    +
    +# Classifiers have set values - be sure to only use classifier values from the
    +# PyPI page here: https://PyPI.org/classifiers/
    +
    +classifiers = [
    +    # How mature is this project? Common values are
    +    #   3 - Alpha
    +    #   4 - Beta
    +    #   5 - Production/Stable
    +    "Development Status :: 4 - Beta",
    +
    +    # Indicate who your project is intended for
    +    "Intended Audience :: Developers",
    +    "Topic :: Software Development :: Build Tools",
    +
    +    # Pick your license (using syntax from the classifier page). We suggest MIT, BSD3 or Apache if you are corporate
    +    "License :: OSI Approved :: MIT License",
    +
    +    # Specify the Python versions ensuring that you indicate you support Python 3.
    +    # this is only for PyPI and other metadata associated with your package - for your users to see
    +    "Programming Language :: Python :: 3 :: Only", # BE sure to specify that you use python 3.x
    +    "Programming Language :: Python :: 3.10",
    +    "Programming Language :: Python :: 3.11",
    +]
    +
    +
    +dependencies = ["xarray", "requests"]
    +# This is the metadata that pip reads to understand what versions your package supports
    +requires-python = ">=3.10"
    +readme = "README.md"
    +license = { file = "LICENSE" }
    +
    +# Add urls for your home page, issue tracker and source code
    +[project.urls] # Optional
    +"Homepage" = "https://www.pyopensci.org"
    +"Bug Reports" = "https://github.com/pyopensci/pyospackage/issues"
    +#"Funding" = ""
    +"Source" = "https://github.com/pyopensci/pyospackage"
    +
    +
    +
    +
    +
    +

    Example pyproject.toml files#

    +

    Below are some examples of pyproject.toml files from various packages in the scientific and pyOpenSci ecosystem.

    + +
    +
    +

    Wrap up#

    +

    At this point you’ve created:

    +
      +
    • A README.md file for your package

    • +
    • A CODE_OF_CONDUCT.md file to support your user community

    • +
    • And a LICENSE file which provides legal boundaries around how people can and can’t use your software

    • +
    +

    You also learned how to publish your package to (test)PyPI.

    +
    +
    +

    Publish a new version of your package to PyPI#

    +

    You are now ready to publish a new version of your Python package to (test) PyPI. When you do this you will see that the landing page for your package now contains a lot more information.

    +

    Try to republish now.

    +

    First, update the version of your package in your pyproject toml file. Below version is updated from +0.1.0 to 0.1.1.

    +
    [build-system]
    +requires = ["hatchling"]
    +build-backend = "hatchling.build"
    +
    +[project]
    +name = "pyospackage"
    +version = "0.1.1"
    +
    +
    +

    Now use hatch to publish the new version of your package to test.PyPI.org.

    +
    > hatch publish -r test
    +
    +
    +
    +

    Next (optional) step - publishing to conda-forge#

    +

    You now have all of the skills that you need to publish +your package to PyPI.

    +

    If you also want to publish your package on conda-forge (which is a channel within the conda ecosystem), you will learn how to do that in the next lesson.

    +
    +
    +
    + + +
    + + + + + + + +
    + + + + + + +
    +
    + +
    + +
    +
    +
    + + + + + + + + \ No newline at end of file