This sounds a lot like this suggestion to add a nameof function/operator:
https://mail.python.org/archives/list/python-ideas@python.org/thread/UUFFAI3FZMQRVPDCUPZEOAZCRNXKWFDE/#IHXME3F5XEQZAN6JSK2PMC4UOWV7AVSF

On Thu, Sep 17, 2020 at 10:37 PM Joseph Perez <jope...@hotmail.fr> wrote:

> A lot of libraries use string for attribute names to do some "dynamic"
> things. A typical example are SQLAlchemy [validators](
> https://docs.sqlalchemy.org/en/13/orm/mapped_attributes.html#simple-validators
> ):
> ```python
> from sqlalchemy.orm import validates
>
> class EmailAddress(Base):
>     __tablename__ = 'address'
>
>     id = Column(Integer, primary_key=True)
>     email = Column(String)
>
>     @validates('email')  # Here
>     def validate_email(self, key, address):
>         assert '@' in address
>         return address
>
> ```
> In this example of SQLAlchemy documentation, email validator use `"email"`
> string in order to associate the validator to the `email` column.
>
> However this dynamic things don't play well with all static tools like
> linters, but especially IDE (for usages finding, navigation, refactoring,
> etc.), and of course type checkers.
>
> This issue could be solved with a "magic attribute" `__attrs__` (name can
> be discussed), used the following way:
> ```python
> @dataclass
> class Foo:
>     bar: int
>
> foo = Foo(0)
> assert getattr(foo, Foo.__attrs__.bar) == 0
> assert getattr(foo, foo.__attrs__.bar) == 0
> ```
> To make it usable in class declaration, the `__attrs__` symbol should be
> added to class declaration namespace:
> ```python
> class Foo:
>     bar: int
>     @validator(__attrs__.bar)
>     def validate(self):
>         ...
> ```
> No check would be done by `__attrs__`, they are let to linters which would
> integrate this language feature and check for the presence of the attribute
> in the class/instance.
>
> And that becomes more interesting because type checkers could use this
> feature to check dynamic attribute retrieving.
> A special type `Attribute[Owner, T]` could be defined to be used by type
> checkers such as `getattr` signature become:
> ```
> # default parameter omitted for concision
> def getattr(obj: Owner, attr: Attribute[Owner, T], /) -> T:
>     ...
> ```
> (of course, `getattr` can still be used with strings, as the relation
> between `Attribute` and `str` is explained later)
>
> It could allow to add typing to function like the following:
> ```python
> Key = TypeVar("Key", bound=Hashable)
> def dict_by_attr(elts: Collection[T], key_attr: Attribute[T, Key]) ->
> Mapping[Key, T]:
>     return {getattr(elt, key_attr): elt for elt in elts}
> ```
>
> Concerning the implementation of this feature would be very
> straightforward, `__attrs__` being defined as a instance of a class:
> ```python
> class Attrs:
>     __slots__ = []
>     def __getattribute__(self, name):
>         return name
> ```
> Thus, `Foo.__attrs__.bar` would be simply equal to `"bar"`; `Attribute`
> would be a special type, but backed by a `str`. hence there is no need to
> modify `getattr` implementation or existing code using it. `Attribute` type
> should then be a kind of `_SpecialForm`, compatible with string by the
> "relation" `str` <=> `Attribute[Any, Any]`
> The only modifications in the langage would be to add the `Attrs` class,
> an `__attrs__` field to `type` and in class definition namespace when it is
> evaluated.
> The rest of the work (checking the attribute presence, type checking with
> `Attribute[Owner, T]`) should be done by external tools (Pycharm, Mypy,
> etc.) to handle the feature.
>
> To sum up, `__attrs__` would be a pseudo-static wrapper to attribute name
> retrieving in order to benefit of static tools (refactoring, usages
> finding, navigation, type checking), with a straightforward and backward
> compatible implementation.
>
> And I don't see that as a "niche" feature, because a lot of libraries
> could actually benefit from it (and SQLAlchemy, Pydantic, etc. are not a
> small libraries).
>
> Joseph
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-le...@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-ideas@python.org/message/UMPALRK3E2BL525V4C6KTTN5QV2NW3JY/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/MKDUOTXKXAFR75QTWPVB6ZX53W6RQTGH/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to