Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 44 additions & 7 deletions examples/pure-hatch/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pyproject.toml example build setup to use hatchling and hatch_vcs
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
Expand All @@ -15,28 +16,49 @@ keywords = ["pyOpenSci", "python packaging"]
readme = "README.md"
license = "BSD-3-Clause"
classifiers = [
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
# How mature is this project? Common values are
"Development Status :: 4 - Beta",

# Indicate who your project is intended for
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
dependencies = [
"dependency-package-name-1",
"dependency-package-name-2",
"pandas",
"xarray",
"geopandas",
"matplotlib"
]

[project.optional-dependencies]
tests = [
[dependency-groups]
test = [
"pytest",
"pytest-cov"
]

lint = [
"black",
"flake8"
"ruff"
]

docs = [
"sphinx",
"pydata-sphinx-theme"
]

dev = [
{include-group = "test"},
{include-group = "lint"}
]

[project.optional-dependencies]
plot = ["bokeh"]
test = ["pytest", "pytest-cov"]
docs = ["sphinx", "pydata-sphinx-theme"]

[tool.ruff]
select = [
"E", # pycodestyle errors
Expand All @@ -50,3 +72,18 @@ known-first-party = ["examplePy"]

[tool.pytest.ini_options]
pythonpath = "src"

# Example hatch vcs setup in the pyproject.toml file
[tool.hatch.build.hooks.vcs]
version-file = "_version.py"

[tool.hatch.envs.test]
development-group= [
"tests",
]

[tool.hatch.envs.test.scripts]
run = "pytest {args:--cov=test --cov-report=term-missing --cov-report=xml}"

[[tool.hatch.envs.test.matrix]]
python = ["3.10", "3.11", "3.12"]
18 changes: 18 additions & 0 deletions examples/pure-hatch/src/examplePy/numbers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# src/examplePy/numbers.py
def add_numbers(a: float, b: float) -> float:
"""
Add two numbers together and return the result.
Parameters
----------
a : float
The first number to add.
b : float
The second number to add.
Returns
-------
float
The sum of the two numbers.
"""
return a + b
42 changes: 40 additions & 2 deletions examples/pure-hatch/src/examplePy/temperature.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
def celsius_to_fahrenheit(celsius):
# src/examplePy/temperature.py
def celsius_to_fahrenheit(celsius: float) -> float:
"""
Convert temperature from Celsius to Fahrenheit.

Expand All @@ -12,7 +13,7 @@ def celsius_to_fahrenheit(celsius):
return fahrenheit


def fahrenheit_to_celsius(fahrenheit):
def fahrenheit_to_celsius(fahrenheit: float) -> float:
"""
Convert temperature from Fahrenheit to Celsius.

Expand All @@ -24,3 +25,40 @@ def fahrenheit_to_celsius(fahrenheit):
"""
celsius = (fahrenheit - 32) * 5 / 9
return celsius


def average_temperature(temps: list[float]) -> float:
"""
Calculate average temperature from a list.

Parameters
----------
temps : list
List of temperatures.

Returns
-------
float
Average temperature.
"""
return sum(temps) / len(temps)


def convert_and_average(temps_celsius: list[float]) -> float:
"""
Convert list of Celsius temps to Fahrenheit and
calculate the average.

Parameters
----------
temps_celsius : list
List of Celsius temperatures.

Returns
-------
float
Average temperature in Fahrenheit.
"""
temps_fahrenheit = [celsius_to_fahrenheit(t)
for t in temps_celsius]
return average_temperature(temps_fahrenheit)
17 changes: 17 additions & 0 deletions examples/pure-hatch/tests/examplePy/test_numbers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# tests/examplePy/test_numbers.py
from examplePy.numbers import add_numbers


def test_add_numbers():
"""Test the add_numbers function."""
# test with positive numbers
result = add_numbers(2, 3)
assert result == 5, f"Expected 5, but got {result}"

# test with negative numbers
result2 = add_numbers(-1, 4)
assert result2 == 3, f"Expected 3, but got {result2}"

# test with zero
result3 = add_numbers(0, 5)
assert result3 == 5, f"Expected 5, but got {result3}"
38 changes: 38 additions & 0 deletions examples/pure-hatch/tests/examplePy/test_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,44 @@
from examplePy import temperature


def test_convert_and_average():
"""
Test that convert_and_average correctly combines conversion
and averaging.
"""
# Test with known values: [0, 10, 20] Celsius
# Should average to 10 Celsius = 50 Fahrenheit
temps_celsius = [0, 10, 20]
result = temperature.convert_and_average(temps_celsius)
assert abs(result - 50.0) < 0.01

# Test with different values
temps_celsius = [0, 100]
result = temperature.convert_and_average(temps_celsius)
# Average of 32 and 212 Fahrenheit = 122
assert abs(result - 122.0) < 0.01


def test_temperature_workflow():
"""
Test the complete temperature processing workflow.

This end-to-end test provides sample temperature data in
Celsius, processes it through the full workflow
(conversion and averaging), and verifies the output is
correct.
"""
# Sample temperature data in Celsius
temps_celsius = [0, 10, 20]

# Run the complete workflow
result = temperature.convert_and_average(temps_celsius)

# Verify the output
# Average of 32, 50, and 68 Fahrenheit = 50 Fahrenheit
assert abs(result - 50.0) < 0.01


def test_fahrenheit_to_celsius_positive():
"""Test F to C calculation for positive values"""
value = 95
Expand Down
91 changes: 41 additions & 50 deletions package-structure-code/declare-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,28 @@ While `pyproject.toml` is now the standard, you may sometimes encounter older ap
Specifying dependencies in the [project.dependency] array of your `pyproject.toml` file ensures that libraries needed to run your package are correctly installed into a user's environment.
For instance, if your package requires Pandas to run properly, and you add Pandas to the `project.dependency` array, Pandas will be installed into the users' environment when they install your package using uv, pip, or conda.

```toml
[project]
...
...
...
dependencies = [
"pandas",
]
```

:::{literalinclude} ../examples/pure-hatch/pyproject.toml
:language: toml
:prepend: "[project]\n...\n...\n..."
:start-at: dependencies = [
:end-at: ]
:::

Development dependencies make it easier for contributors to work on your package. You can set up instructions for running specific workflows, such as tests, linting, and even typing, that automatically install groups of development dependencies. These dependencies can be stored in arrays (lists of dependencies) within a `[development-group]` table.

```toml
[development-group]
tests = [
"pytest",
"pytest-cov"
]
```
:::{literalinclude} ../examples/pure-hatch/pyproject.toml
:language: toml
:start-at: [development-group]
:end-before: lint
:::

### Types of dependencies

There are three different types of dependencies that you will learn about on this page:

1. **Required dependencies:** These are dependencies that need to be installed for your package to work correctly in a user's environment. You add these dependencies to the `[project.dependencies]` table in your pyproject.toml file.
2. **Feature Dependencies:** These are dependencies that are required if a user wants to access additional functionality (that is not core) to your package. Store these in the `[project.optional.dependencies]` table or your pyproject.toml file.
2. **Feature Dependencies:** These are dependencies that are required if a user wants to access additional functionality (that is not core) to your package. Store these in the `[project.optional-dependencies]` table or your pyproject.toml file.
3. **Development Dependencies:** These dependencies are required if someone wants to develop or work on your package. These include instance linters, testing tools like pytest and mypy are examples of development dependencies. Store these in the `[project.dependency.groups]` table or your pyproject.toml file.

:::{tip}
Expand All @@ -76,17 +72,13 @@ You can add your required dependencies to the `dependencies` array in the
your package with uv, pip, or conda, these dependencies will be
automatically installed alongside your package in their environment.

```toml
[project]
name = "examplePy"
authors = [
{name = "Some Maintainer", email = "some-email@pyopensci.org"},
]
dependencies = [
"pandas",
"matplotlib",
]
```

:::{literalinclude} ../examples/pure-hatch/pyproject.toml
:language: toml
:prepend: "[project]\n...\n...\n..."
:start-at: dependencies = [
:end-at: ]
:::

:::{tip}
Try your best to minimize dependencies whenever possible. Remember that
Expand Down Expand Up @@ -143,18 +135,17 @@ Optional (also referred to as feature) dependencies can be installed by users as

Place these dependencies in the `[project.optional-dependencies]` table.

```toml
[project]
...
...
...
[optional.dependencies]
plot = ["bokeh"]
```

:::{literalinclude} ../examples/pure-hatch/pyproject.toml
:language: toml
:prepend: "[project]\n...\n...\n..."
:start-at: [project.optional-dependencies]
:end-at: plot = ["bokeh"]
:::

When a user installs your package, uv, pip, or conda automatically installs all required dependencies. Optional dependencies are only installed if the user explicitly requests them.

:::{dropdown} How to Add optional.dependencies using UV
:::{dropdown} How to Add project.optional-dependencies using UV
:icon: eye
:color: primary

Expand All @@ -169,7 +160,7 @@ uv add --optional feature pandas
Will add this to your pyproject.toml file:

```toml
[optional.dependencies]
[project.optional-dependencies]
feature = [
"pandas>=2.3.3",
]
Expand Down Expand Up @@ -208,12 +199,12 @@ within a `[development-groups]` table.

Similar to optional-dependencies, you can create separate subgroups or arrays with names using the syntax: `group-name = ["dep1", "dep2"]`

```toml
[development-groups]
tests = ["pytest", "pytest-cov"]
docs = ["sphinx", "pydata-sphinx-theme"]
lint = ["ruff", "black"]
```
:::{literalinclude} ../examples/pure-hatch/pyproject.toml
:language: toml
:start-at: [development-group]
:end-before: [project.optional-dependencies]
:::


:::{dropdown} How to Add [development.group] using UV
:icon: eye
Expand Down Expand Up @@ -361,12 +352,12 @@ installation conflicts.

You can also create combined groups that reference other groups:

```toml
[project.optional-dependencies]
test = ["pytest", "pytest-cov"]
docs = ["sphinx", "pydata-sphinx-theme"]
dev = ["your-package[test,docs]", "build", "twine"]
```

:::{literalinclude} ../examples/pure-hatch/pyproject.toml
:language: toml
:start-at: [project.optional-dependencies]
:end-before: [tool.ruff]
:::

Then install everything with pip install or uv sync as needed:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Once you have published both package distributions (the source distribution and
(publish-pypi-conda)=
## What is PyPI

[PyPI](https://pypi.org/) is an online Python package repository that
[PyPI](https://pypi.org/) (p/aɪ/.pi/aɪ/ or p/aɪ/p/aɪ/) is an online Python package repository that
you can use to both find and install and publish your Python package. There is
also a test PyPI repository where you can test publishing your package
prior to the final publication on PyPI.
Expand Down
Loading