attrs – how to validate an instance of a Literal or None

Question:

This is what I have. I believe there are two problems here – the Literal and the None.

from attrs import frozen, field
from attrs.validators import instance_of

OK_ARGS = ['a', 'b']

@field
class MyClass:
    my_field: Literal[OK_ARGS] | None = field(validator=instance_of((Literal[OK_ARGS], None)))

Error:

TypeError: Subscripted generics cannot be used with class and instance checks

Edit: I’ve made a workaround with a custom validator. Not that pretty however:

def _validator_literal_or_none(literal_type):
    def inner(instance, attribute, value):
        if (isinstance(value, str) and (value in literal_type)) or (value is None):
            pass
        else:
            raise ValueError(f'You need to provide a None, or a string in this list: {literal_type}')
    return inner
Asked By: GlaceCelery

||

Answers:

You can’t do isinstance() checks on Literals/Nones and that’s what the is_instance Validator is using internally (it predates those typing features by far).

While we’ve resisted adding a complete implementation of the typing language due to its complexity, having one dedicated to such cases mind be worth exploring if you’d like to open an issue.

Answered By: hynek
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.