-
-
Notifications
You must be signed in to change notification settings - Fork 374
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
Using Annotated in attrs #775
Comments
Full disclosure I haven't had a chance to use Annotated yet, though I'm excited about it for my own projects. Are you thinking of something like:
My big concerns of doing it for validators are:
We'd probably not just want to stick Reading the Pep a little more it looks like one idea is to have a series of classes rather than one class for the Annotations. So you could do something like this But it could be nice to stick the
I can't decide if that's worse or better though. |
Just wanted to chime-in that I have a use-case for adding field configuration in from typing import Annotated, TypeVar
import attr
T = TypeVar("T", bound="Driver")
Parent = Annotated[T, "parent"]
@attr.s
class Driver:
@property
def parents(self) -> list[Driver]:
def _is_parent_type(field: attr.Attribute, value: Any) -> bool:
return type(field.type) is type(Parent) and "parent" in getattr(field.type, "__metadata__")
return list(attr.asdict(self, recurse=False, filter=_is_parent_type).values())
@attr.s
class Bus(Driver):
pass
@attr.s
class Device(Driver):
bus: Parent[Bus] = attr.ib()
bus = Bus()
dev = Device(bus)
assert dev.parents == [bus] What would be nice is to be able to add extra metadata into Parent = Annotated[T, "parent", Field(repr=False)] |
That said, it could even be improved to allow insertion of field metadata via Parent = Annotated[T, Field(repr=False, metadata={"parent": True})]
@attr.s
class Driver:
@property
def parents(self) -> list[Driver]:
def _is_parent_type(field: attr.Attribute, value: Any) -> bool:
return field.metadata.get("parent", False)
return list(attr.asdict(self, recurse=False, filter=_is_parent_type).values()) |
I just also wanted to briefly express my interest in the possibility of using |
Skimming the comments, do I see it correctly that there's somewhat a consensus to get rid of the special-cased Generally speaking, that seems like a good way to make the typing situation less about lying to the type checker. Open questions for me are:
cc @Tinche |
Hi @hynek, just to make my point clear: I'm not suggesting to get rid of the good old Concrete exampleIdeally, I would like to capture the semantics of a So instead if having to repeat the following field assignment @define
class NeedsPrimeNumber:
prime: int = field(default=3, validator=is_prime, converter=le_converter)
@define
class AlsoNeedsPrimeNumber:
prime: int = field(default=5, validator=is_prime, converter=le_converter) I'd rather want to write PrimeNumber = Annotated[int, Field(validator=is_prime, converter=le_converter)]
@define
class UsingAnnotated:
prime: PrimeNumber = field(default=3)
@define
class AlsoUsingAnnotated:
prime: PrimeNumber = field(default=5) where in this case only the default (which is class specific) remains part of the regular assignment. Perhaps this was already clear to you, just thought a specific example could help 🙃 |
@AdrianSosic, in your example, I believe the right-side PrimeNumber = Annotated[int, Field(validator=is_prime, converter=le_converter)]
@define
class UsingAnnotated:
prime: PrimeNumber = 3 because, otherwise, the library has to tell type checkers that
IMHO, yes! |
Hi @dlax 👋🏼 Probably, setting a default was not the best example from my side. But what I meant is that there could be other field-related setting that do not belong the the concept of a For example: PrimeNumber = Annotated[int, Field(validator=is_prime, converter=le_converter)]
@define
class RequiresPrimeLargerThanFive:
prime: PrimeNumber = field(default=7, validator=gt(5)) So the specific class here needs a prime larger than five, but primes in general don't have this requirement. Or are you suggesting you use a second layer of PrimeNumber = Annotated[int, Field(validator=is_prime, converter=le_converter)]
@define
class RequiresPrimeLargerThanFive:
prime: Annotated[PrimeNumber, validator=gt(5)] = 7 with the general idea of moving every functionality of |
Yes, one key aspect of PrimeNumber = Annotated[int, Validator(is_prime), Converter(le_converter)]
@define
class RequiresPrimeLargerThanFive:
prime: Annotated[PrimeNumber, Validator(gt(5))] = 7 and keep the |
I have been playing with Annotated recently, and was wondering whether this is something that might be used within attrs. My first instinct was "maybe this could be used for validators?". Maybe even
field()
?The text was updated successfully, but these errors were encountered: