[Python-ideas] Re: f-string code formatting
> As Ricky and Wes have pointed out, IDE refactoring tools are already able to > look inside not just f-strings but regular strings too. Ricky has written the opposite : "As far as I know, none of these tools know how to do the renaming of the FIRST bar to bar_new:", and i can confirm > If your point is a practical problem, it is already a practical problem for > refactoring tools. How do they deal with this? They don't do it automatically, so they give the burden to the user which has to review all the potential changes in strings literal (with a lot of false-positive, and some missing occurrences); and that's when they do, because mostly they don't. > That is why I am suggesting that tool users should start cooperating on a > standard for directives. Even if I agree with you on this point (for example, I'm happy that new versions of Pycharm support `# noqa` directive to disable some checks), this features makes it irrelevant IMO as I already stated that it would imply user repeating himself. ___ 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/HAWCBWYLLQ4TO6UJ7ALIJT6JIQMZO5BK/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Magic attribute for attribute names retrieving
> Dunder names are reserved for use by the Python interpreter. That's convenient, because my suggestion is to add a magic attribute into the Python specifications ;) It would be a `type` attribute, like `__mro__` or others. > So here we have `__attrs__` is not just a dunder attribute, but also a dunder > built-in name. It hasn't to be a built-in name in global scope but only in the scope of class declaration (and could then be interpreted by type checkers has being owned by the class being declared). Using it outside a class declaration should raise a `NameError`. By the way, I think you did not understand my suggestion, so maybe it was not enough clear — that's maybe related too to the fact you precise in an other post that your are "not aware of many refactoring tools for Python at all". So I will develop my point by talking about an other pseudo-static (but completely dynamic under the hood) standard Python feature; let's talk about dataclasses. Dataclasses are a dynamic thing, a decorator which rewrite class methods; this is so dynamic that the method code is first written as a string and then compiled with `exec`, and that it use regex parsing under the hood to check types in stringified annotations. That's under the hood. However, for the user, thanks to IDEs, type checkers, linters, etc. this is handled as a static feature. Attribute access can be type checked, and `__init__` method parameters are checked too. Don't believe that IDEs and other tools execute the `dataclass` code for each class in order to retrieve the signature of the generated method. No, they just compute it themselves statically, because they **know that it will be generated this way**. How do they know ? Because it's written in Python specifications, so they have to handle it. And if you write code reassigning an attribute of a frozen dataclass, linter will warn you, while the real check is dynamic and realized in class generated `__setattr__`. (To prove you that's purely static, try to do `dataclass2 = dataclass` and execute mypy with a class decorated by `dataclass2`) So, if tools are able to statically compute a signature of dataclass `__init__` by using its fields annotations (even if it's dynamic like hell behind), I hope you begin to understand how they could be able to interpret `__attrs__.bar` in a different manner than raw `"bar"`; it's not "one more step" as you said, it's a different processing, and because it's a different processing, type checking can be added, using for example my suggested `_SpecialForm` `Attribute[Owner, T]` > So linters that cannot cope with `@validate('email')` will be able to cope > with `@validate(__attrs__.email)`, because ... why? Because it would be written in Python specification that this has a special meaning for type checking, as it is for dataclasses methods. That's why I dare use a dunder name, because it's a suggestion for the Python specification. > Presumably these would work too: > `assert getattr(foo, None.__attrs__.bar) == 0` > `assert getattr(foo, foo.__attrs__.baz, 999) == 999` It will works, yes, but the same way that passing a `str` to a function annotated with an `int` parameter: type checker will shout at you. Python static checks are never enforced dynamically, this suggestion does not aim to change this behavior. But in Python, dynamics things can be interpreted in a static way by tools, they needs a specification to follow, dataclasses being again the best example. > Apart from typing 15 chars to avoid 2 quotation marks, and making a runtime > attribute lookup plus method call to avoid a literal, how will this help > reduce dynamicism? I hope that you've understood now with this complementary explanation (and yes, there is more chars typed, but is that an issue when meanings are different?) ___ 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/MNGFPIWUHH6C2UEO6BVTARMDLDNUX3XT/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: f-string code formatting
Ricky Teachey wrote: > But if you really want it or need it in a situation where find and replace > isn't a great option The example i've given is a good example where find and replace isn't a great option. In fact, you don't want to use find and replace to change a function parameter, because it will be tedious to change all function calls with named parameter accross your call. That's why refactoring tools exist. I agree, that Pycharm find and replace is very nice (especially using regex), but I use it only for modify copy-pasted things with regex, never for refactoring. By the way, I like your "hack", but as you say it's not very fantastic; maybe it deserve an official simplification. ___ 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/2FXDQHXSNSTNPEQYM3SCLPDBW6JFQVTY/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: f-string code formatting
Steven D'Aprano wrote: > I'm not aware of many refactoring tools for Python at all, [...] I don't know > how well IDEs like VisualStudio and PyCharm do refactoring. This help me to understand your point of view. But if I consider your proposition, it's evident that a simple comment `# IDE:refactor` would not be enough for IDE. Because a string is full of words and several of them could matchs the symbols of your code; by the way, the IDE would not be able to delimitate expression. So you would have to put redondant information into your comment, and redundancy is not cool for the user; if the shortcut `f"{foo=}"` has been introduced in 3.8, that's to avoid "to repeat yourself" (word taken from feature author). By the way, there is (as far as I know) no comment standardisation in Python, they are specific to the tools which use them. See how many docstring standard we have; Both Pycharm and Black have their own comment directive to toggle formatting on/off; when mypy and flake8 find an issue in your code, you have to put # type: ignore # noqa… How could an approach using comment be promising? And as you can see in other responses to your post, when the Python language introduce a feature, IDEs adapt to fully support it. That's the case for f-string where refactoring, linting, type-checking, reformatting, etc. are handled inside. This is the difference between a literal string and a "not-evaluated" string. ___ 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/J3RH4IMECCIWI7GQ65G6OX6EGNJ6JTRC/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] f-string code formatting
Note: this suggestion should echo https://mail.python.org/archives/list/python-ideas@python.org/thread/UUFFAI3FZMQRVPDCUPZEOAZCRNXKWFDE/ but has a bigger scope and completely differs in the way to proceed. Currently, Python lacks a way to integrate code parts into string; when I say code, I don't talk only about identifiers (on which is focusing `nameof` suggestion) but also about expression. Actually, this feature exists in Python but is hidden in a 3.8 [f-string feature](https://docs.python.org/3.8/whatsnew/3.8.html#f-strings-support-for-self-documenting-expressions-and-debugging). Expression string should be made accessible for itself. It could be done by adding a leading token `:` to the expression. Thus `f"{:a + b}" == "a + b"`. Like "normal" formatted expression, it would be handled by IDEs, especially for refactoring. The difference with "normal" formatted expression is that the expression would not be evaluated. A use case example: ```python def foo(bar: int): if bar != 42: # If `bar` is renamed, error message will be renamed too by the IDE raise ValueError(f"{:bar} is not 42") ``` By the way, there will be the following equivalence: `f"{a + b=}" == f"{:a + b}={a + b}"`. The idea is to reuse existing mechanisms. (Of course the syntax suggestion is arbitrary and can be discussed. I have considered a leading token because there are already a lot of modifiers at the end of the expression; I have thought about `:` and `!` and my preferences has gone to `:`.) 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/7VAII3CWQ7TCINRIMLYVZXN36S7Z3RZB/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Magic attribute for attribute names retrieving
Alex Hall wrote: > This sounds a lot like this suggestion to add a nameof function/operator: > https://mail.python.org/archives/list/python-ideas@python.org/thread/UUFFAI3... Indeed, it sounds like the `nameof` operator; I had not heard of this suggestion before your message. However, there is at least two important differences between both suggestions which may matter: - `nameof` should be implemented as a new operator with a dedicated implementation using AST and raising SyntaxError; `__attrs__` is simpler and dynamic (pythonic?), just a `type` object attribute, and cannot fail. (I don't mention implementation using CPython `current_frame` specificity, as it is unavailable in Pypy, IronPython, etc.) - `nameof` is only about variable/attribute name; `__attrs__` has a dual use: attribute name and `getattr` typing (i don't see how the second could be considered with `nameof`) 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/CDLYJ4EW5BX6PLIIU5K7UHI4BRCL2ZDR/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Magic attribute for attribute names retrieving
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] Re: Limit 'import as' syntax
As spotted by response, I did not mature enough my point to see that they could have a slight difference between both statements. This thread is no longer relevant. Thank you ___ 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/K7CX6HOQYT2HZQH3WYHXXEQYTJ4WTTDF/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Limit 'import as' syntax
You are right, I did not envisage the case where you could have name mangling between submodule and variable inside package __init__.py, which could lead to different behavior. So my statement is erroneous and this thread is no longer relevant. Thank you ___ 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/O25CKD6WEVFWIMHJEITJ7BAUVUTG7ZCE/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Limit 'import as' syntax
There is no other advantage than respect of the Zen of Python (and I don't know how much it counts). Maybe it can simplify interpreter code, but I don't know about it and I doubt it. With that, it could help newcomers to Python to choose between the two syntaxes. (And I've already experienced team conflict about syntax) By the way, I think this issue is not fundamental, that's why a removal would actually maybe be too strong. ___ 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/FD5PIOEUFEQQWY475TYZPZF5SOKDQW3S/ Code of Conduct: http://python.org/psf/codeofconduct/