Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

feat!: use exception groups for composite errors #49

Merged
merged 1 commit into from
Nov 17, 2022
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
152 changes: 93 additions & 59 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
push:
branches: [main]
branches: [ main ]
pull_request:
types: [opened, synchronize]
types: [ opened, synchronize ]

jobs:
flake8:
Expand All @@ -13,82 +13,101 @@ jobs:
matrix:
python-version: [ '3.11' ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- id: cache
- name: Restore cache and venv
id: cache
uses: actions/cache@v3
with:
path: |
~/.cache
.venv
key: ${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install Poetry
if: steps.cache.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1.3.3
with:
virtualenvs-in-project: true
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: poetry install --with dev
- run: |
- name: Run flake8
run: |
source .venv/bin/activate
pre-commit run --all-files flake8

mypy:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.11' ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- id: cache
uses: actions/cache@v3
with:
path: |
~/.cache
.venv
key: ${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
- uses: actions/cache@v3
with:
path: .mypy_cache
key: ${{ matrix.python-version }}
- if: steps.cache.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1.3.3
with:
virtualenvs-in-project: true
- if: steps.cache.outputs.cache-hit != 'true'
run: poetry install --with dev
- run: |
source .venv/bin/activate
pre-commit run --all-files mypy
# mypy:
# runs-on: ubuntu-latest
# strategy:
# matrix:
# python-version: [ '3.11' ]
# steps:
# - name: Checkout
# uses: actions/checkout@v3
# - name: Setup Python
# uses: actions/setup-python@v4
# with:
# python-version: ${{ matrix.python-version }}
# - name: Restore cache and venv
# id: cache
# uses: actions/cache@v3
# with:
# path: |
# ~/.cache
# .venv
# key: ${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
# - name: Restore mypy cache
# uses: actions/cache@v3
# with:
# path: .mypy_cache
# key: ${{ matrix.python-version }}
# - name: Install Poetry
# if: steps.cache.outputs.cache-hit != 'true'
# uses: snok/install-poetry@v1.3.3
# with:
# virtualenvs-in-project: true
# - name: Install dependencies
# if: steps.cache.outputs.cache-hit != 'true'
# run: poetry install --with dev
# - name: Run mypy
# run: |
# source .venv/bin/activate
# pre-commit run --all-files mypy

pyright:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.11' ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- id: cache
- name: Restore cache and venv
id: cache
uses: actions/cache@v3
with:
path: |
~/.cache
.venv
key: ${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install Poetry
if: steps.cache.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1.3.3
with:
virtualenvs-in-project: true
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: poetry install --with dev
- run: |
- name: Run pyright
run: |
source .venv/bin/activate
pre-commit run --all-files pyright

Expand All @@ -98,24 +117,30 @@ jobs:
matrix:
python-version: [ '3.11' ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- id: cache
- name: Restore cache and venv
id: cache
uses: actions/cache@v3
with:
path: |
~/.cache
.venv
key: ${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install Poetry
if: steps.cache.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1.3.3
with:
virtualenvs-in-project: true
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: poetry install --with dev
- run: |
- name: Run pyright-verify
run: |
source .venv/bin/activate
pre-commit run --all-files pyright-verify

Expand All @@ -129,36 +154,45 @@ jobs:
os: [ ubuntu-latest, windows-latest, macos-latest ]
python-version: [ '3.11' ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- id: cache
- name: Restore cache and venv
id: cache
uses: actions/cache@v3
with:
path: |
~/.cache
.venv
key: ${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
- uses: actions/cache@v3
- name: Restore pytest cache
uses: actions/cache@v3
with:
path: .pytest_cache
key: ${{ runner.os }}-${{ matrix.python-version }}
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install Poetry
if: steps.cache.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1.3.3
with:
virtualenvs-in-project: true
- if: steps.cache.outputs.cache-hit != 'true'
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: poetry install --with dev
- if: runner.os == 'Windows'
- name: Run pytest on Windows
if: runner.os == 'Windows'
run: |
source .venv/scripts/activate
pre-commit run --all-files pytest
- if: runner.os != 'Windows'
- name: Run pytest on normal OS
if: runner.os != 'Windows'
run: |
source .venv/bin/activate
pre-commit run --all-files pytest
- uses: codecov/codecov-action@v3
- name: Upload coverage report to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: coverage.xml
Expand Down
18 changes: 12 additions & 6 deletions .github/workflows/publish-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,26 @@ name: Publish release

on:
release:
types: [created]
types: [ created ]

jobs:
publish-release:
name: Publish release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: Checkout
uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- uses: snok/install-poetry@v1.3.3
- name: Install Poetry
uses: snok/install-poetry@v1.3.3
with:
virtualenvs-create: false
- run: poetry build
- uses: pypa/gh-action-pypi-publish@master
- name: Build the package
run: poetry build
- name: Publish the package to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{ secrets.PYPI_API_TOKEN }}
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ci:
autofix_commit_msg: 'refactor: auto fixes from pre-commit hooks'
autoupdate_commit_msg: 'build(deps): update pre-commit hooks'
skip: [ pyproject-flake8, mypy, pyright, pyright-verify, pytest ]
skip: [ pyproject-flake8, pyright, pyright-verify, pytest ]

repos:
- repo: https://github.com/pycqa/isort
Expand Down Expand Up @@ -33,12 +33,12 @@ repos:

- repo: local
hooks:
- id: mypy
name: mypy
entry: bash -c "pip install poetry && poetry install --with mypy && mypy"
language: system
pass_filenames: false
stages: [ commit ]
# - id: mypy
# name: mypy
# entry: bash -c "pip install poetry && poetry install --with mypy && mypy"
# language: system
# pass_filenames: false
# stages: [ commit ]

- id: pyright
name: pyright
Expand Down
49 changes: 41 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@

---

**Documentation**: [valtypes.readthedocs.io][docs]

**Source code**: [github.com/LeeeeT/valtypes][source]

---

## What is valtypes

**Valtypes** is a flexible data parsing library which will help you make illegal states unrepresentable and enable you to practice ["Parse, don’t validate"][parse-dont-validate] in Python. It has many features that might interest you, so let's dive into some examples.
**Valtypes** is a flexible data parsing library which will help you make illegal states unrepresentable and enable you to practice ["Parse, don’t validate"](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate) in Python. It has many features that might interest you, so let's dive into some examples.

## Examples

Expand Down Expand Up @@ -58,8 +64,7 @@ Parse complex data structures:
```python
from dataclasses import dataclass


from valtypes import parse
from valtypes import parse_json
from valtypes.type import int, list, str


Expand All @@ -69,16 +74,44 @@ class User:
name: Name
hobbies: list.NonEmpty[str.NonEmpty]


raw = {"id": 1, "name": "Fred", "hobbies": ["origami", "curling", "programming"]}

print(parse(User, raw))
print(parse_json(User, raw))
```

```
User(id=1, name='Fred', hobbies=['origami', 'curling', 'programming'])
```

Get a nice error message if something went wrong (traceback omitted):

```python
raw = {"id": 0, "hobbies": [""]}

parse_json(User, raw)
```

```
| valtypes.error.parsing.dataclass.Composite: dataclass parsing error (3 sub-exceptions)
+-+---------------- 1 ----------------
| valtypes.error.parsing.dataclass.WrongFieldValue: can't parse field 'id' (1 sub-exception)
+-+---------------- 1 ----------------
| valtypes.error.parsing.type.numeric.Minimum: the value must be greater than or equal to 1, got: 0
+------------------------------------
+---------------- 2 ----------------
| valtypes.error.parsing.dataclass.MissingField: required field 'name' is missing
+---------------- 3 ----------------
| valtypes.error.parsing.dataclass.WrongFieldValue: can't parse field 'hobbies' (1 sub-exception)
+-+---------------- 1 ----------------
| valtypes.error.parsing.sequence.Composite: sequence parsing error (1 sub-exception)
+-+---------------- 1 ----------------
| valtypes.error.parsing.sequence.WrongItem: can't parse item at index 0 (1 sub-exception)
+-+---------------- 1 ----------------
| valtypes.error.parsing.type.sized.MinimumLength: length 0 is less than the allowed minimum of 1
+------------------------------------
```

## Installation

Install from [PyPI]:
Expand All @@ -93,8 +126,8 @@ Build the latest version from [source]:
pip install git+https://github.com/LeeeeT/valtypes
```

[parse-dont-validate]: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate

[pypi]: https://pypi.org/project/valtypes
[docs]: https://valtypes.readthedocs.io

[source]: https://github.com/LeeeeT/valtypes

[PyPI]: https://pypi.org/project/valtypes
Loading