https://github.com/drivendataorg/sortedcontainers-pydantic
Adds Pydantic support to sortedcontainers.
https://github.com/drivendataorg/sortedcontainers-pydantic
pydantic python sorted-lists sorted-map sorted-sets sortedcontainers
Last synced: 4 months ago
JSON representation
Adds Pydantic support to sortedcontainers.
- Host: GitHub
- URL: https://github.com/drivendataorg/sortedcontainers-pydantic
- Owner: drivendataorg
- License: mit
- Created: 2024-03-05T17:51:49.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2025-04-19T00:38:28.000Z (8 months ago)
- Last Synced: 2025-06-20T17:50:22.406Z (6 months ago)
- Topics: pydantic, python, sorted-lists, sorted-map, sorted-sets, sortedcontainers
- Language: Python
- Homepage:
- Size: 108 KB
- Stars: 7
- Watchers: 6
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# sortedcontainers-pydantic
[](https://pypi.org/project/sortedcontainers-pydantic/)
[](https://github.com/conda-forge/sortedcontainers-pydantic-feedstock)
[](https://pypi.org/project/sortedcontainers-pydantic/)
[](https://github.com/drivendataorg/sortedcontainers-pydantic/actions/workflows/tests.yml?query=branch%3Amain)
[](https://codecov.io/gh/drivendataorg/sortedcontainers-pydantic)
This package extends [sortedcontainers](https://github.com/grantjenks/python-sortedcontainers/), a fast pure-Python library for sorted mutable collections, to work with [Pydantic](https://docs.pydantic.dev/latest/)'s models, validation, and serialization.
The easiest way to get started is to simply import `SortedDict`, `SortedList`, or `SortedSet` from `sortedcontainers_pydantic` instead of from `sortedcontainers`.
```python
from pydantic import BaseModel, TypeAdapter
from sortedcontainers_pydantic import SortedList
class MyModel(BaseModel):
sorted_list: SortedList[int]
MyModel(sorted_list=[3.0, 1.0, 2.0])
#> MyModel(sorted_list=SortedList([1, 2, 3]))
MyModel.model_validate_json('{"sorted_list": [3, 1, 2]}')
#> MyModel(sorted_list=SortedList([1, 2, 3]))
MyModel(sorted_list=[3, 1, 2]).model_dump_json()
#> '{"sorted_list":[1,2,3]}'
TypeAdapter(SortedList).validate_python([3, 1, 2])
#> SortedList([1, 2, 3])
TypeAdapter(SortedList).validate_json("[3, 1, 2]")
#> SortedList([1, 2, 3])
```
Reproducible example created by [reprexlite](https://github.com/jayqi/reprexlite) v1.0.0
For additional alternative ways to declare types from this library, see the ["Usage approaches"](#usage-approaches) section below.
This library also supports key functions to customize sorting behavior. See the ["Specifying a key function with `Key`"](#specifying-a-key-function-with-key) section for further details.
## Installation
sortedcontainers-pydantic is available on [PyPI](https://pypi.org/project/sortedcontainers-pydantic/). You can install it with
```bash
pip install sortedcontainers-pydantic
```
It is also available on [conda-forge](https://github.com/conda-forge/sortedcontainers-pydantic-feedstock). You can install it with
```bash
conda install sortedcontainers-pydantic --channel conda-forge
```
## Usage approaches
There are three different ways you can use `sortedcontainers-pydantic`.
### 1. Import from sortedcontainers_pydantic
The library has subclasses of sortedcontainers's `SortedDict`, `SortedList`, and `SortedSet` with [Pydantic's special methods](https://docs.pydantic.dev/latest/concepts/types/#customizing-validation-with-__get_pydantic_core_schema__) that enable validation and serialization. To use them, simply import classes of the same name from `sortedcontainers_pydantic`.
```python
from pydantic import BaseModel
from sortedcontainers_pydantic import SortedList
class MyModel(BaseModel):
sorted_list: SortedList[int]
MyModel(sorted_list=[3.0, 1.0, 2.0])
#> MyModel(sorted_list=SortedList([1, 2, 3]))
MyModel.model_validate_json('{"sorted_list": [3, 1, 2]}')
#> MyModel(sorted_list=SortedList([1, 2, 3]))
```
### 2. Use the annotation pattern
_New in sortedcontainers-pydantic v2.0.0_
The library has special annotation objects `SortedDictPydanticAnnotation`, `SortedListPydanticAnnotation`, and `SortedSetPydanticAnnotation` that can be attached to sortedcontainers's `SortedDict`, `SortedList`, and `SortedSet`, respectively, using `typing.Annotated`. This implements the [annotated pattern](https://docs.pydantic.dev/latest/concepts/types/#handling-third-party-types) supported by Pydantic.
```python
from typing import Annotated
from pydantic import BaseModel
from sortedcontainers import SortedList
from sortedcontainers_pydantic import SortedListPydanticAnnotation
class MyModel(BaseModel):
sorted_list: Annotated[SortedList[int], SortedListPydanticAnnotation]
MyModel(sorted_list=[3.0, 1.0, 2.0])
#> MyModel(sorted_list=SortedList([1, 2, 3]))
```
Unlike approach 1, the type being used is the original class from sortedcontainers and not a subclass.
### 3. Use the wrapper type aliases
_New in sortedcontainers-pydantic v2.0.0_
You can also use the wrapper types `AnnotatedSortedDict`, `AnnotatedSortedList`, or `AnnotatedSortedSet`. These are simply type aliases implementing approach 2.
```python
from pydantic import BaseModel
from sortedcontainers_pydantic import AnnotatedSortedList
AnnotatedSortedList
#> typing.Annotated[sortedcontainers.sortedlist.SortedList[~_T], ]
class MyModel(BaseModel):
sorted_list: AnnotatedSortedList[int]
MyModel(sorted_list=[3.0, 1.0, 2.0])
#> MyModel(sorted_list=SortedList([1, 2, 3]))
```
## Specifying a key function with `Key`
_New in sortedcontainers-pydantic v2.0.0_
You can specify a key function to control sorting. The key should be a callable that takes a single argument. It will be run on every element to generate a key for making comparisons. To specify a key, instantiate the `Key` special annotation object wrapping it, and attach it with `typing.Annotated`. This works with any of the three approaches.
### Example using `Key` with approach 1
```python
from typing import Annotated
from pydantic import BaseModel
from sortedcontainers_pydantic import Key, SortedList
class MyModel(BaseModel):
sorted_list: Annotated[SortedList[int], Key(lambda x: -x)]
MyModel(sorted_list=[3.0, 1.0, 2.0])
#> MyModel(sorted_list=SortedKeyList([3, 2, 1], key= at 0x10ae058a0>))
```
### Example using `Key` with approach 2
```python
from typing import Annotated
from pydantic import BaseModel
from sortedcontainers import SortedList
from sortedcontainers_pydantic import Key, SortedListPydanticAnnotation
class MyModel(BaseModel):
sorted_list: Annotated[SortedList[int], SortedListPydanticAnnotation, Key(lambda x: -x)]
MyModel(sorted_list=[3.0, 1.0, 2.0])
#> MyModel(sorted_list=SortedKeyList([3, 2, 1], key= at 0x10aa4a520>))
```
### Example using `Key` with approach 3
```python
from typing import Annotated
from pydantic import BaseModel
from sortedcontainers_pydantic import AnnotatedSortedList, Key
class MyModel(BaseModel):
sorted_list: Annotated[AnnotatedSortedList[int], Key(lambda x: -x)]
MyModel(sorted_list=[3.0, 1.0, 2.0])
#> MyModel(sorted_list=SortedKeyList([3, 2, 1], key= at 0x10ca65080>))
```
---
Reproducible examples created by [reprexlite](https://github.com/jayqi/reprexlite) v1.0.0