Skip to content
New issue

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

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

Already on GitHub? # 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))
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant