Skip to main content

pilo

https://travis-ci.org/bninja/pilo.png https://coveralls.io/repos/bninja/pilo/badge.png

Yet another form parser.

dev

$ git clone git@github.com:bninja/pilo.git
$ cd pilo
$ mkvirtualenv pilo
(pilo)$ pip install -e .[tests]
(pilo)$ py.test tests/ --cov=pilo --cov-report term-missing

release

All is well:

(pilo)$ py.test tests/ --cov=pilo --cov-report term-missing

so update __version__ in:

  • pilo/__init__.py

then commit and tag it (travis will publish it to pypi):

$ git commit -am "release v{version}"
$ git tag -a v{version} -m "release v{version}"
$ git push --tags

usage

Validation

Here we validate that a message has acceptable headers and body.

from pilo import Form
from pilo.fields import Dict, String


class Message(Form):
    headers = Dict(String(choices=['to', 'from', 'content-type']), String())
    body = String(max_length=20)


>>> print Message(headers={'to': 'William III'}, body='ha'*10)
{'body': 'hahahahahahahahahaha', 'headers': {'to': 'William III'}}

>>> print Message(headers={'send-to': 'William III'}, body='ha'*10)
Invalid: headers - "send-to" is not one of "to", "from", "content-type"

>>> print Message(headers={'to': 'William III'}, body='ha'*11)
Invalid: body - "hahahahahahahahahahaha" must have length <= 20

Hooks

Override-able mechanism allowing users to inject functions to customize these behaviors:

  • compute

  • resolve

  • parse

  • default

  • munge

  • filter

  • validate

e.g.:

import pilo


class ExtraCurricular(pilo.Form):

   category = pilo.fields.String(
       choices=['athletics', 'academics', 'social', 'service']
   )

   name = pilo.fields.String(max_length=40)

   description = pilo.fields.String(max_length=140)

   role = pilo.fields.String(choices=['member', 'leader'])


class CollegeApplication(pilo.Form):

    high_school_name = pilo.fields.String()

    sat_score = pilo.fields.Integer()

    gpa = pilo.fields.Float()

    extra_curriculars = pilo.fields.List(pilo.fields.SubForm(ExtraCurricular))

    score = pilo.fields.Float(default=pilo.NONE)

    accepted = pilo.fields.Bool(default=False)

    @score.compute
    def score(self):
        leadership_roles = [
            ec for ec in self.extra_curriculars if ec.role == 'leader'
        ]
        relevant_extra_curriculars =[
            ec for ec in self.extra_curriculars
            if ec.category in ['academics', 'service']
        ]
        score = (
            10 * (self.sat_score / 1600.0) +
            10 * (self.gpa / 4.0) +
             5 * len(leadership_roles) +
             5 * len(relevant_extra_curriculars)
        )
        return score

    @accepted.compute
    def accepted(self):
        if self.score > 30:
            return True
        return False

    @high_school_name.munge
    def high_school_name(self, value):
        return value.upper()


application = CollegeApplication(
    high_school_name='Bodega High',
    sat_score=1400,
    gpa=4.0,
    extra_curriculars=[
        dict(category='athletics', role='leader', name='hockey', description=''),
        dict(category='academics', role='member', name='chess club', description=''),
    ]
)


>>> print application.high_school_name
BODEGA HIGH

>>> print application.score
28.75

>>> print application.accepted
False

Form polymorphism and type downcasting

In the following example, a user has an address, but the address schema is polymorphic on the country abbreviation.

import pilo
import uuid


class Address(pilo.Form):

    guid = pilo.fields.UUID(default=uuid.uuid4)
    country = pilo.fields.Type.abstract()


class UnitedKingdomAddress(Address):

    country = pilo.fields.Type.constant('UK')
    name = pilo.fields.String()
    street = pilo.fields.String()
    locality = pilo.fields.String()
    post_town = pilo.fields.String()
    postcode = pilo.fields.String()


class UnitedStatesAddress(Address):

    country = pilo.fields.Type.constant('USA')
    name = pilo.fields.String()
    street = pilo.fields.String()
    unit = pilo.fields.String(default=None)
    city = pilo.fields.String()
    state = pilo.fields.String()
    zip = pilo.fields.String(length=5)


class User(pilo.Form):

     guid = pilo.fields.UUID(default=uuid.uuid4)
     name = pilo.fields.String()
     address = pilo.fields.PolymorphicSubForm(Address.country)


mikey_representation = dict(
    name='Michael Pikey',
    address=dict(
        country='UK',
        name='Mikey Pikey',
        street='351 Meagre Lane',
        locality='Hedge End',
        post_town='Southampton',
        postcode='SO31 4NG',
    )
)


bart_representation = dict(
    name='Bartholomew Simpson',
    address=dict(
        country='USA',
        name='Bite Me',
        street='742 Evergreen Terrace',
        city='Springfield',
        state='???',
        zip='12345',
    )
)


mikey = User(**mikey_representation)


bart = User(**bart_representation)


>>> print dict(mikey)
{
    'address': {
        'country': 'UK',
        'guid': UUID('8c73752c-69a2-4832-99f8-c5354cbeec59'),
        'locality': 'Hedge End',
        'name': 'Mikey Pikey',
        'post_town': 'Southampton',
        'postcode': 'SO31 4NG',
        'street': '351 Meagre Lane'
    },
    'guid': UUID('eee0953c-1b5a-4bd0-893d-f513b1cf24f4'),
    'name': 'Michael Pikey'
}

>>> print dict(bart)
{
    'address': {
        'city': 'Springfield',
        'country': 'USA',
        'guid': UUID('a321bedd-8b94-46b8-830e-ea137b08a608'),
        'name': 'Bite Me',
        'state': '???',
        'street': '742 Evergreen Terrace',
        'unit': None,
        'zip': '12345'
    },
    'guid': UUID('3155a3dd-4b5a-4990-aaea-439359bb36a9'),
    'name': 'Bartholomew Simpson'
}

>>> print mikey.address.postcode
SO31 4NG

>>> print bart.address.zip
12345

>>> print type(mikey.address).__name__
UnitedKingdomAddress

>>> print type(bart.address).__name__
UnitedStatesAddress

Metadata

Release files for pilo 0.6.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pilo 0.6.2
File Size Uploaded Provenance
pilo-0.6.2.tar.gz 22.5 kB Without provenance Details

Release files / pilo-0.6.2.tar.gz

Download URL pilo-0.6.2.tar.gz
Size 22.5 kB
Tags Source
SHA-256 checksum
How to use checksums
845878be066ea675327e569e608d45e06f51025ff2dae39e7642fbeaf53f2c12
BLAKE2b-256 checksum
How to use checksums
8896eb3161000cc8d7b35a054291cd4d257f1b5d122316307507a8eb8c091bf3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Security for pilo 0.6.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page