[Python-ideas] Re: f-string code formatting

2020-09-18 Thread Joseph Perez
>  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

2020-09-18 Thread Joseph Perez
> 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

2020-09-18 Thread Joseph Perez
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

2020-09-18 Thread Joseph Perez
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

2020-09-17 Thread Joseph Perez
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

2020-09-17 Thread Joseph Perez
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

2020-09-17 Thread Joseph Perez
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

2020-03-30 Thread Joseph Perez
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

2020-03-30 Thread Joseph Perez
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

2020-03-30 Thread Joseph Perez
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/