Skip to main content

Validate and extract JSON-sourced data into type-safe dataclasses

Project description

plucker

Build Status codecov Python Version

Validate and extract JSON-sourced data into type-safe dataclasses

wut

  • Tired of relying on vendor-provided, untyped Python libraries to interface with external APIs?
  • Want to just make a few simple HTTP requests without the weight of extra dependencies?
  • Do you only use a small subset of the data you get from external sources, picking out five fields when you are given thirty?
  • Are you more than slightly worried that the API might change under you and you wouldn't know?
  • Want to avoid just reaching into dictionaries to get the data you want?
  • Do you want to parse the JSON you get into something type-safe so that mypy will complain when you do wrong things?
  • Is writing fakes a bit too heavyweight for the APIs you're calling? Would producing an error on unexpected input work OK for now?

Enter plucker.

plucker is designed to validate, map and reduce regularly structured data into dataclasses. That data would typically be JSON from APIs but could be anything that mostly consists of Python dicts and lists when parsed.

plucker will either give you type-verified data, or it will fail with helpful error messages:

Data not in expected format; expected fred to be 'list' but it was 'dict':
.fred[].v
 ^^^^

Just pick the data you want using jq-style paths, map it so that it's the right type if you need to, and you have well-typed validated data to feed into the rest of your system.

Installation (soon...)

pip install plucker

Example

from typing import List
from dataclasses import dataclass
from enum import Enum, auto
from datetime import date

from plucker import pluck, Path


class Status(Enum):
    """A cintact's status."""
    CURRENT = auto()
    EXPIRED = auto()


@dataclass
class Contact:
    """A contact record."""
    name: str
    email: str


@dataclass
class Struct:
    """The typed dataclass we want our data collected into."""
    date: date
    id: int
    state: Status
    affected_records: List[int]
    contacts: List[Contact]


TO_STATUS = {"CUR": Status.CURRENT, "EXP": Status.EXPIRED}

input_ = {
    "date": "2021-01-01",
    "id": "1242",
    "payload": {
        "from": "CURRENT",
        "who": [
            {"name": "DM", "id": 1, "email": "dangermouse@example.com"},
            {"name": "Stiletto", "id": 23, "email": "baroni@example.com"},
        ]
    }
}

plucked = pluck(
    input_,
    Struct,
    date=Path(".date"),
    id=Path(".id").map(int),
    state=Path(".payload.from").map(TO_STATUS),
    affected_records=Path(".payload.who[].id"),
    people=Path(".payload.who[]").into(
        Contact,
        name=Path(".name"),
        email=Path(".email"),
    ),
)

expected = Struct(
    date=date(2021, 1, 1),
    id=1242,
    state=Status.CURRENT,
    affected_records=[1, 23],
    contacts=[
        Contact("DM", "dangermouse@example.com"),
        Contact("Stiletto", "baroni@example.com")
    ]
)

assert plucked == expected
# ^ it's True

Prior art

  1. dataclasses_json -> require the same structure between JSON and serialization, which means you have to specify an intermediate structure
  2. DRF serializers -> heavyweight and not type safe, destructure into dictionaries
  3. Elm's JSON decoders -> this design isn't really based on anything in there but ever since using them I wanted similar functionality in Python
  4. jq, an amazing commandline tool for querying JSON data
  5. Parse, don't validate
  6. Elm's error messages

License

MIT

Credits

A bunch of the tooling was taken from wemake-python-package but then heavily modified.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

plucker-0.1.0.tar.gz (10.2 kB view details)

Uploaded Source

Built Distribution

plucker-0.1.0-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file plucker-0.1.0.tar.gz.

File metadata

  • Download URL: plucker-0.1.0.tar.gz
  • Upload date:
  • Size: 10.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.5 CPython/3.9.0 Darwin/18.7.0

File hashes

Hashes for plucker-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5064cf08a333bf637706117516101f50819f410aa64d50856811446744330071
MD5 8ccda4effb1e8357e1f030b0ed1f05e8
BLAKE2b-256 3b4c06a00dff95acd59fcbb57350423984ccf969c48935aaf0f376bf0e178c92

See more details on using hashes here.

File details

Details for the file plucker-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: plucker-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 9.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.5 CPython/3.9.0 Darwin/18.7.0

File hashes

Hashes for plucker-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3272ac2e6601df8519c73261b8bb05eb11c9bc29e6f17c840743e1c3b74daf70
MD5 f4c4bb8b93645bf901c703fab242cb6f
BLAKE2b-256 c2c1f9c3085c7b5d12db0c66a8c3cff298178d1defa6349519c9d18e42fba8de

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page