Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dataclasses support #409

Open
benjaminweb opened this issue Oct 3, 2019 · 0 comments
Open

dataclasses support #409

benjaminweb opened this issue Oct 3, 2019 · 0 comments

Comments

@benjaminweb
Copy link

benjaminweb commented Oct 3, 2019

Is this in or out of scope?

# requires Python 3.7
from dataclasses import dataclass

from voluptuous import Schema, Object, All, Range
from voluptuous.schema_builder import PREVENT_EXTRA


@dataclass
class InventoryItem:
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand


class DataClassSchema(Schema):
    @staticmethod
    def dataClassSchema(x):
        return {
            fieldName: fieldValues.type
            for fieldName, fieldValues in (x.__dataclass_fields__).items()
        }

    @staticmethod
    def merge_constraints_of_key(a, b):
        return All(a, b)

    def merge_constraints_of_schema(self, dclsSchema, addSchema):
        result = dict()
        for k, v in dclsSchema.items():
            if k in addSchema:
                result[k] = self.merge_constraints_of_key(v, addSchema[k])
            else:
                result[k] = v
        return result

    def __init__(self, dcls, schema, required=False, extra=PREVENT_EXTRA):
        return super(DataClassSchema, self).__init__(
            Object(
                self.merge_constraints_of_schema(self.dataClassSchema(dcls), schema),
                cls=dcls,
            ),
            required,
            extra,
        )


s1 = Schema(
    Object(
        {"name": str, "unit_price": All(float, Range(min=5)), "quantity_on_hand": int}
    ),
    InventoryItem,
)

s2 = DataClassSchema(InventoryItem, {"unit_price": Range(min=5)})

# assert s1 == s2 # fails due to bug: Schema({'a': All(float)}) == Schema({'a': All(float)})

# however, s1 and s2 operate equivalently:

# s1(InventoryItem('nails', 3.33, 4))
# s2(InventoryItem('nails', 3.33, 4))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant