From a832d9b937df7d2c36b9e8e5966fea512fe4fbf6 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Fri, 1 Mar 2024 14:50:33 -0800 Subject: [PATCH 1/9] More description on version specification in main text, model version specifications throughout, specific poetry example --- tutorials/pyproject-toml.md | 72 +++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index 324d8b9e..ace75625 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -255,8 +255,11 @@ 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. - +Add the `requires-python` field to your `pyproject.toml` `[project]` table. +The `requires-python` field, helps pip understand which versions of Python that you package supports when it's installed. +It is thus a single value. +`requires-python` supports the dependency specification syntax discussed in the next section - typically this will be +a lower bound specifying the oldest version of python that can run your package, but you may also need to specify an upper bound in some more advanced cases. {emphasize-lines="13"} ```toml @@ -284,8 +287,40 @@ The `dependencies =` section contains a list (or array in the toml language) of [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. +```toml +dependencies = ["numpy", "requests", "pandas", "pydantic"] +``` + +Dependencies can, and usually should come with a **version specifier.** +A plain dependency says that your package can work with any version of that dependent package. +Code changes over time, bugs are fixed, APIs change, and so it's good to be clear about which version of the dependency you wrote your code to be compatible with - a package you wrote this year probably isn't compatible with numpy v0.0.1! + +[Learn more about various ways to specify ranges of package versions here.](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) + +The most common version specifier is a **lower bound,** allowing any version higher than the specified version. +Ideally you should set this to the lowest version that is still compatible with your package, but in practice for new packages this is often set at the version that was current at the time the package was written. + +Lower bounds look like this: + +```toml +dependencies = [ "numpy>=1.0" ] +``` + +You can combine specifiers with commas, and use different kinds of specifiers for each package in your `dependencies` section: + +```toml +dependencies = [ + "numpy>=1.0", # Greater than or equal to 1.0 + "requests==10.1", # Exactly 10.1 + "pandas", # Any version + "pydantic>=1.7,<2" # Greater than or equal to 1.7, but less than 2 +] +``` + +Your `pyproject.toml` file will now look like this: {emphasize-lines="15"} ```toml @@ -303,24 +338,15 @@ readme = "README.md" license = {file = 'LICENSE'} requires-python = ">=3.10" -dependencies = ["numpy", "requests", "pandas", "pydantic"] +dependencies = ["numpy>=1.0", "requests==10.1", "pandas", "pydantic>=1.7,<2"] ``` :::{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. +"Pinning" dependencies refers to specifying a specific version of a dependency like this: -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` +`numpy == 1.0`. +Unless you are building an application, you want to be cautious about pinning dependencies to precise versions. This is because users will be installing your package into various environments. A dependency pinned to a single specific version can make @@ -328,6 +354,14 @@ resolving a Python environment more challenging. As such only pin dependencies to a specific version if you absolutely need to do so. +Similarly, you should be cautious when specifying an upper bound on a package. +These two specifications are equivalent: + +``` +pydantic>=1.10,<2 +pydantic^1.10 +``` + 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) ::: @@ -370,7 +404,7 @@ readme = "README.md" license = {file = 'LICENSE'} requires-python = ">=3.10" -dependencies = ["numpy", "requests", "pandas", "pydantic"] +dependencies = ["numpy>=1.0", "requests==10.1", "pandas", "pydantic>=1.7,<2"] classifiers = [ "Development Status :: 4 - Beta", @@ -410,7 +444,7 @@ readme = "README.md" license = {file = 'LICENSE'} requires-python = ">=3.10" -dependencies = ["ruamel-yaml>=0.17.21", "requests", "python-dotenv", "pydantic"] +dependencies = ["numpy>=1.0", "requests==10.1", "pandas", "pydantic>=1.7,<2"] classifiers = [ "Development Status :: 4 - Beta", @@ -452,7 +486,7 @@ readme = "README.md" license = {file = 'LICENSE'} requires-python = ">=3.10" -dependencies = ["ruamel-yaml>=0.17.21", "requests", "python-dotenv", "pydantic"] +dependencies = ["numpy>=1.0", "requests==10.1", "pandas", "pydantic>=1.7,<2"] classifiers = [ "Development Status :: 4 - Beta", @@ -525,7 +559,7 @@ classifiers = [ ] -dependencies = ["xarray", "requests"] +dependencies = ["numpy>=1.0", "requests==10.1", "pandas", "pydantic>=1.7,<2"] # This is the metadata that pip reads to understand what versions your package supports requires-python = ">=3.10" readme = "README.md" From 10fb76a927c70dbba938607cf026cb680cadaa2d Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Fri, 1 Mar 2024 14:55:01 -0800 Subject: [PATCH 2/9] dummy commit because github is not receiving my pushes? --- tutorials/pyproject-toml.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index ace75625..bda80b3e 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -360,7 +360,7 @@ These two specifications are equivalent: ``` pydantic>=1.10,<2 pydantic^1.10 -``` +``` 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) ::: From 2b1cd51ddb131741c1210600bd80a6221e06f5bb Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Fri, 1 Mar 2024 14:55:30 -0800 Subject: [PATCH 3/9] undo dummy commit, github received --- tutorials/pyproject-toml.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index bda80b3e..ace75625 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -360,7 +360,7 @@ These two specifications are equivalent: ``` pydantic>=1.10,<2 pydantic^1.10 -``` +``` 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) ::: From 15f60408ba9a563d736932f1aefd5d7d14a66fef Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Mon, 4 Mar 2024 12:20:20 -0800 Subject: [PATCH 4/9] run precommit --- tutorials/pyproject-toml.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index 97b1fa70..f63dee40 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -255,9 +255,9 @@ license = {file = 'LICENSE'} ``` ### Step 3: Add requires-python to your [project] table -Add the `requires-python` field to your `pyproject.toml` `[project]` table. -The `requires-python` field, helps pip understand which versions of Python that you package supports when it's installed. -It is thus a single value. +Add the `requires-python` field to your `pyproject.toml` `[project]` table. +The `requires-python` field, helps pip understand which versions of Python that you package supports when it's installed. +It is thus a single value. `requires-python` supports the dependency specification syntax discussed in the next section - typically this will be a lower bound specifying the oldest version of python that can run your package, but you may also need to specify an upper bound in some more advanced cases. @@ -294,13 +294,13 @@ dependencies are added in an array (similar to a Python list) structure. dependencies = ["numpy", "requests", "pandas", "pydantic"] ``` -Dependencies can, and usually should come with a **version specifier.** +Dependencies can, and usually should come with a **version specifier.** A plain dependency says that your package can work with any version of that dependent package. Code changes over time, bugs are fixed, APIs change, and so it's good to be clear about which version of the dependency you wrote your code to be compatible with - a package you wrote this year probably isn't compatible with numpy v0.0.1! [Learn more about various ways to specify ranges of package versions here.](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) -The most common version specifier is a **lower bound,** allowing any version higher than the specified version. +The most common version specifier is a **lower bound,** allowing any version higher than the specified version. Ideally you should set this to the lowest version that is still compatible with your package, but in practice for new packages this is often set at the version that was current at the time the package was written. Lower bounds look like this: From 972dbf2e869ae9a111d14790caae22afa0d896da Mon Sep 17 00:00:00 2001 From: Jonny Saunders Date: Tue, 19 Mar 2024 14:45:18 -0700 Subject: [PATCH 5/9] Apply suggestions from code review thank you @willingc! Co-authored-by: Carol Willing --- tutorials/pyproject-toml.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index c550106d..35bc35e9 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -297,10 +297,10 @@ license = {file = "LICENSE"} ### Step 3: Specify Python version with `requires-python` Add the `requires-python` field to your `pyproject.toml` `[project]` table. -The `requires-python` field, helps pip understand which versions of Python that you package supports when it's installed. -It is thus a single value. -`requires-python` supports the dependency specification syntax discussed in the next section - typically this will be -a lower bound specifying the oldest version of python that can run your package, but you may also need to specify an upper bound in some more advanced cases. +The `requires-python` field helps pip identify which Python versions that your package supports. +It is set to a single value. +The [packaging specification](https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata-requires-python) defines`requires-python` as a string that uses version specifiers. Most projects will specify the oldest Python version supported by the package. In some advanced cases, an upper bound is set to indicate which future Python versions, if any, will be supported. + {emphasize-lines="22"} ```toml @@ -344,8 +344,8 @@ dependencies are added in an array (similar to a Python list) structure. dependencies = ["numpy", "requests", "pandas", "pydantic"] ``` -Dependencies can, and usually should come with a **version specifier.** -A plain dependency says that your package can work with any version of that dependent package. +A dependency can be limited to specific versions using a **version specifier.** +If the dependency has no version specifier after the dependency name, your package can use any version of the dependent package. Code changes over time, bugs are fixed, APIs change, and so it's good to be clear about which version of the dependency you wrote your code to be compatible with - a package you wrote this year probably isn't compatible with numpy v0.0.1! [Learn more about various ways to specify ranges of package versions here.](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) @@ -359,7 +359,7 @@ Lower bounds look like this: dependencies = [ "numpy>=1.0" ] ``` -You can combine specifiers with commas, and use different kinds of specifiers for each package in your `dependencies` section: +Commas are used to separate individual dependencies, and each package in your `dependencies` section can use different types of version specifiers: ```toml dependencies = [ @@ -401,7 +401,7 @@ dependencies = ["numpy>=1.0", "requests==10.1", "pandas", "pydantic>=1.7,<2"] ``` :::{admonition} Pin dependencies with caution -"Pinning" dependencies refers to specifying a specific version of a dependency like this: +"Pinning" a dependency means setting it to a specific version, like this: `numpy == 1.0`. From ba9f79c7c85518a637b4fce136316620f6cf0d4d Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Tue, 19 Mar 2024 14:50:11 -0700 Subject: [PATCH 6/9] fix poetry link --- tutorials/pyproject-toml.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index 35bc35e9..19529425 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -351,7 +351,9 @@ Code changes over time, bugs are fixed, APIs change, and so it's good to be clea [Learn more about various ways to specify ranges of package versions here.](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) The most common version specifier is a **lower bound,** allowing any version higher than the specified version. -Ideally you should set this to the lowest version that is still compatible with your package, but in practice for new packages this is often set at the version that was current at the time the package was written. +Ideally you should set this to the lowest version that is still compatible with your package, but in practice for new packages this is often set at the version that was current at the time the package was written[^lowerbound]. + +[^lowerbound]: Lower bounds look like this: @@ -421,7 +423,7 @@ pydantic>=1.10,<2 pydantic^1.10 ``` -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) +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.](challenges-with-poetry) ::: ### Step 5: Add PyPI classifiers From 713ac6acca7560880f412326939532ed29158539 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Tue, 19 Mar 2024 14:54:19 -0700 Subject: [PATCH 7/9] lint --- tutorials/pyproject-toml.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index 19529425..780c0a85 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -353,7 +353,7 @@ Code changes over time, bugs are fixed, APIs change, and so it's good to be clea The most common version specifier is a **lower bound,** allowing any version higher than the specified version. Ideally you should set this to the lowest version that is still compatible with your package, but in practice for new packages this is often set at the version that was current at the time the package was written[^lowerbound]. -[^lowerbound]: +[^lowerbound]: Lower bounds look like this: From 20f4bef73392039a79a0f388a76dfa638902bf71 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Tue, 19 Mar 2024 16:03:50 -0700 Subject: [PATCH 8/9] finish footnote --- tutorials/pyproject-toml.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index 780c0a85..cd0cb516 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -353,7 +353,7 @@ Code changes over time, bugs are fixed, APIs change, and so it's good to be clea The most common version specifier is a **lower bound,** allowing any version higher than the specified version. Ideally you should set this to the lowest version that is still compatible with your package, but in practice for new packages this is often set at the version that was current at the time the package was written[^lowerbound]. -[^lowerbound]: +[^lowerbound]: Some packaging tools will do this for you when you add a dependency using their cli interface. For example [`poetry add`](https://python-poetry.org/docs/cli/#add) will add the most recent version with a `^` specifier, and [`pdm add`](https://pdm-project.org/latest/reference/cli/#add) will add the most recent version with `>=`. Lower bounds look like this: From 6bb0f9da98f829be754fc00c347045bd7bf951df Mon Sep 17 00:00:00 2001 From: Jonny Saunders Date: Wed, 20 Mar 2024 13:57:52 -0700 Subject: [PATCH 9/9] Update tutorials/pyproject-toml.md Co-authored-by: Carol Willing --- tutorials/pyproject-toml.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/pyproject-toml.md b/tutorials/pyproject-toml.md index cd0cb516..0cc45363 100644 --- a/tutorials/pyproject-toml.md +++ b/tutorials/pyproject-toml.md @@ -407,7 +407,7 @@ dependencies = ["numpy>=1.0", "requests==10.1", "pandas", "pydantic>=1.7,<2"] `numpy == 1.0`. -Unless you are building an application, you want to be cautious about pinning dependencies to precise versions. +If you are building a library package that other developers will depend upon, you must be cautious before pinning to a precise dependency version. Applications, such as production websites, will often pin their dependencies since other packages will not depend on their project. This is because users will be installing your package into various environments. A dependency pinned to a single specific version can make