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

Commit

Permalink
feat!: use exception groups for composite errors
Browse files Browse the repository at this point in the history
Closes: #28
  • Loading branch information
LeeeeT committed Nov 17, 2022
1 parent d39ac60 commit be8e419
Show file tree
Hide file tree
Showing 132 changed files with 2,439 additions and 1,000 deletions.
150 changes: 92 additions & 58 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 }}
- 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 }}
12 changes: 6 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
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
5 changes: 5 additions & 0 deletions docs/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit be8e419

Please sign in to comment.