Skip to content
Merged
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
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/nationalarchives/python-utilities/compare/v1.7.0...HEAD)
## [Unreleased](https://github.com/nationalarchives/python-utilities/compare/v1.8.0...HEAD)

### Added
### Changed
Expand All @@ -14,6 +14,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
### Security

## [1.8.0](https://github.com/nationalarchives/python-utilities/compare/v1.7.0...v1.8.0) - 2026-08-19

### Added

- Added `tna_frontend_pagination()` to `tna_utilities.component` to generate the entire content block required for [TNA Frontend pagination components](https://design-system.nationalarchives.gov.uk/components/pagination/)

### Changed

- `QueryStringTransformer` is now read-only - to modify query strings, create a new editable object with `new()`

## [1.7.0](https://github.com/nationalarchives/python-utilities/compare/v1.6.0...v1.7.0) - 2026-08-19

### Added
Expand Down
51 changes: 49 additions & 2 deletions docs/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,56 @@ print(paginate(42, 7, around=2))
# [1, "...", 5, 6, 7, 8, 9, "...", 42]
```

## `tna_frontend_pagination()`

> Added in `v1.8.0`.

Creates an object that be used directly in a [National Archives pagination component](https://design-system.nationalarchives.gov.uk/components/pagination/) using [`tna_frontend_pagination_items()`](#tna_frontend_pagination_items).

### Arguments

| Argument | Description | Default |
| -------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `pages` | The total number of pages to paginate | [none] |
| `current_page` | The number of the current page | [none] |
| `base_url` | The base URL including the blank query string for the page | [none] |
| `custom_properties` | A dictionary of custom properties for the pagination component | [none] |
| `around` | The number of items to always show around the current page | `1` |
| `transformer` | A function to create the item given a number and whether it is the current page | `tna_utilities.component.tna_frontend_pagination_item_transformer` |
| `ellipsis` | A dictionary to use in place of an ellipsis | `{"ellipsis": True}` |
| `previous_page_properties` | Properties to use for the previous page button | [none] |
| `next_page_properties` | Properties to use for the next page button | [none] |

### Example

```python
from tna_utilities.component import tna_frontend_pagination

print(tna_frontend_pagination(42, 7, "?page=", {"landmarkLabel": "Pages of results"}, next_page_properties={"text": "Go on..."}))
# {
# "landmarkLabel": "Pages of results",
# "items": [
# {"number": 1, "current": False, "href": "?page=1"},
# {"ellipsis": True},
# {"number": 6, "current": False, "href": "?page=6"},
# {"number": 7, "current": True, "href": "?page=7"},
# {"number": 8, "current": False, "href": "?page=8"},
# {"ellipsis": True},
# {"number": 42, "current": False, "href": "?page=42"},
# ],
# "previous": {
# "href": "?page=6",
# },
# "next": {
# "text": "Go on...",
# "href": "?page=8",
# },
# }
```

## `tna_frontend_pagination_items()`

Creates an object that be used directly in a [National Archives pagination component](https://design-system.nationalarchives.gov.uk/components/pagination/).
Creates a list of items that be used directly in a [National Archives pagination component](https://design-system.nationalarchives.gov.uk/components/pagination/).

### Arguments

Expand All @@ -44,7 +91,7 @@ Creates an object that be used directly in a [National Archives pagination compo
### Example

```python
from tna_utilities.component import paginate
from tna_utilities.component import tna_frontend_pagination_items

print(tna_frontend_pagination_items(42, 7, "?page="))
# [
Expand Down
28 changes: 28 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,31 @@ This is a library of common Python functions, some specific to The National Arch
- [Flask](./flask.md)

[Read the changelog](https://github.com/nationalarchives/python-utilities/blob/main/CHANGELOG.md).

## Root-level functions

### `strtobool()`

Converts a string to boolean based on a number of predefined truthy and falsy values.

#### Arguments

| Argument | Description | Default |
| -------- | -------------------- | ------- |
| `value` | The value to convert | [none] |

#### Example

```python
from tna_utilities import strtobool

print(strtobool("yes"))
# True

print(strtobool("0"))
# False

print(strtobool("maybe")) # Raises ValueError: Invalid truth value

print(strtobool(True)) # Raises TypeError: Invalid truth value
```
63 changes: 26 additions & 37 deletions docs/url.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,56 +76,43 @@ qs.is_value_in_parameter("b", "4")
# False
```

### Add and remove parameters
### Add, update and remove parameters

Here, we are creating a new query string using `.new()` which creates a modifyable object which allows us to add, update and remove parameters and their values.

```python
from tna_utilities.url import QueryStringTransformer

# ?a=1&b=2&b=3
qs = QueryStringTransformer([("a", ["1"]), ("b", ["2", "3"])])

qs.add_parameter("c", "4")
qs.update_parameter("b", ["5", "6"])
qs.remove_parameter("a")
new_qs = qs.new()

print(qs.get_query_string())
# ?b=5&b=6&c=4
new_qs.add_parameter("c", "4")
new_qs.update_parameter("b", ["5", "6"])
new_qs.add_parameter_value("b", "7")
new_qs.toggle_parameter_value("b", "1")
new_qs.remove_parameter_value("b", "5")
new_qs.remove_parameter("a")
print(new_qs.get_query_string())
# ?b=1&b=6&b=7&c=4

# Chainable (as of v1.1.0)
print(qs.add_parameter(
print(new_qs.add_parameter(
"c", "4"
).update_parameter(
"b", ["5", "6"]
).add_parameter_value(
"b", "7"
).toggle_parameter_value(
"b", "1"
).remove_parameter_value(
"b", "5"
).remove_parameter(
"a"
).get_query_string())
```

### Update parameter values

```python
from tna_utilities.url import QueryStringTransformer

# ?a=1&b=2&b=3
qs = QueryStringTransformer([("a", ["1"]), ("b", ["2", "3"])])

qs.add_parameter_value("a", "4")
qs.toggle_parameter_value("b", "3")
qs.remove_parameter_value("a", "1")

print(qs.get_query_string())
# ?a=4&b=2

# Chainable (as of v1.1.0)
new_query_string = qs.add_parameter_value(
"a", "4"
).toggle_parameter_value(
"b", "3"
).remove_parameter_value(
"a", "1"
).get_query_string()
```

### Tolerant mode

> Added in `v1.7.0`.
Expand All @@ -135,12 +122,14 @@ from tna_utilities.url import QueryStringTransformer

# ?a=1
qs = QueryStringTransformer([("a", ["1"])])
qs.remove_parameter_value("b", "2") # Raises KeyError: Parameter 'b' does not exist
qs.is_value_in_parameter("c", "3") # Raises KeyError: Parameter 'c' does not exist
new_qs = qs.new()
new_qs.remove_parameter_value("b", "2") # Raises KeyError: Parameter 'b' does not exist
print(new_qs.is_value_in_parameter("c", "3")) # Raises KeyError: Parameter 'c' does not exist

# ?a=1
qs_tolerant = QueryStringTransformer([("a", ["1"])], tolerant=True)
qs_tolerant.remove_parameter_value("b", "2") # No exception raised
print(qs_tolerant.is_value_in_parameter("c", "3"))
tolerant_qs = QueryStringTransformer([("a", ["1"])], tolerant=True)
new_tolerant_qs = tolerant_qs.new()
new_tolerant_qs.remove_parameter_value("b", "2") # No exception raised
print(new_tolerant_qs.is_value_in_parameter("c", "3"))
# False
```
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "tna-utilities"
version = "1.7.0"
version = "1.8.0"
requires-python = ">=3.10"
authors = [
{name = "Andrew Hosgood", email = "andrew.hosgood@nationalarchives.gov.uk"},
Expand Down
Loading