Hello, I also like the postponed annotation evaluation. Getting rid of most forward references is by itself a strong motivation for me, getting performance improvement on top of that is also great.
Regarding concerns about PEP 649 superseding PEP 543, I do also agree that this change would not be this complicated to make. The SC is even considering rewiring the `from __future__ import annotations` to enable pep 649 in case it's favored over 543. *isort* can enforce automatic imports addition or deletion via the *add_imports* and *remove_imports* options. (might be good to check if this can help achieve what we want): https://pycqa.github.io/isort/docs/configuration/options.html Best, Pierre Le lun. 4 juil. 2022 à 20:06, Jarek Potiuk <pot...@apache.org> a écrit : > Yeah. I certainly do not want to merge it now in the form it is (also TP > mentioned that in the comment that in this form it is impossible to > review). This is more POC but it can be done 'better' - for example the > empty __init__.py do not have to have the __tuture__ annotations added. I > think - if the feedback will be general "we like it" then we can also > introduce it in stages (folder-by-folder) to get it reviewable. > > J. > > On Mon, Jul 4, 2022 at 5:54 PM Ash Berlin-Taylor <a...@apache.org> wrote: > >> I certainly like the future-annotations and have idly thought about how >> to do this myself. >> >> The only downside I can think of is that it might makes cherry picks back >> to the 2.3 release branch more complicated in some cases (mostly because we >> generally try to avoid backporting things that aren't bug fixes.) >> >> So maybe we merge this in the prep stage for 2.4 instead of right now? >> >> -ash >> >> On Mon, Jul 4 2022 at 00:12:41 +0200, Jarek Potiuk <ja...@potiuk.com> >> wrote: >> >> Hey everyone, >> >> *TL;DR;* I wanted to discuss that maybe (not really sure- but I wanted >> to check with others) we could migrate the whole codebase of airflow to >> support PEP 563 - postponed evaluation of annotations. PEP 563 is nicely >> supported in our case (Python 3.7+) by `from __future__ import annotations` >> and pyupgrade automated pre-commit does the bulk of the work of converting >> our code automatically - both current and future. >> >> *Is there a POC?* >> >> Yeah. I have a PR that implements it. I actually implemented it today - >> literally in a few hours, in-between of other things. >> >> * On one hand it is huge= 3625 files (+16,459 −11,989 lines) >> * On the other hand it really only **really** changes type annotations >> (so no real code impact) and those changes are semi-automated. I >> literally got it "generated" in a couple of hours - and I can easily either >> rebase or reapply it on top of new changes. >> >> There are some spelling mistakes to fix and few tests to fix, but this >> should be easy. >> >> PR here: https://github.com/apache/airflow/pull/24816 >> >> *Why ?* >> >> Our code gets more and more type-annotated and it's cool. But it does not >> come for free (for now). The types for functions/classes are evaluated at >> import time and it takes some computational effort. Also we have a number >> of cases where we have "string" forward references. This is ugly and does >> not get as good support for auto-completions and IDEs in general. >> >> PEP 563 solves both problems. There is an alternative PEP 649 that could >> be chosen in the future, but I think we can get some benefits now without >> waiting for a decision (which even if it comes, will be only implemented in >> 3.11 or maybe in 3.12 and in the meantime we could get some benefits of PEP >> 563). >> >> 1) Runtime performance is improved in case we do not use type-hints at >> runtime (we don't) - static type checkers work as usual, but at runtime >> those annotations are placed in _annotations_ dictionary and evaluated only >> when runtime type-hint checking is used. >> >> 2) String forward references are not needed. >> No longer `-> 'Type' when you define the type a few lines above, simple >> `-> Type` will do. >> >> Those two on its own would be worth it IMHO, but there is more. >> >> 3) the new syntax of types from Python 3.10 is available and it's quite a >> bit nicer when it comes to Optional usage. Example: >> >> CLIENT_AUTH: Optional[Union[Tuple[str, str], Any]] = None >> >> turns into: >> >> CLIENT_AUTH: tuple[str, str] | Any | None = None >> >> 4) Interestingly enough - we do not need to do anything to use the new >> syntax. The pyupgrade which we have in our pre-commit will automatically >> convert the "old way" of using Optionals to the new one - as soon as you >> add `from __future__ import annotations`. This also means that if anyone >> uses the "old way" in the future, pre-commit will catch it and migrate - >> this is actually a cool learning experience for all contributors I think as >> they can learn and get usd to Python 3.10 syntax today. This conversion is >> done in my PR, you can take a look. >> >> 5) It is overwhelmingly mostly backwards-compatible for Python 3.7 except >> if you used runtime type annotation checking and analysis (which we did >> not) except inferring multiple outputs in decorators (literally single >> usage in the entire codebase). And the way we use it seems to be able to >> continue to work after we add some small fixes - I think just our tests >> need to be fixed (I think 9 of the failing tests to fix are falling into >> this camp). >> >> *Caveats* >> >> Almost none since we are already Python 3.7+. Basically each of our >> python files must start with: >> >> from __future__ import annotations >> >> Performance gets improved for imports. The PEP >> https://peps.python.org/pep-0563/ claims that the overhead for the >> runtime typing information needed is very small (memory wise) and since we >> are almost not using runtime type-hint evaluation memory usage will be >> lower because the type hints will not be evaluated at all during runtime. >> >> And similarly, like we do not care about licenses any more (because they >> are added automatically) by pre-commit, it could be the same with the >> __future__ import. >> >> PEP 649: >> >> The caveat is that https://peps.python.org/pep-0649/ - alternative >> approach to deferring annotation is still being discussed and PEP 563 is >> not confirmed.. PEP 649 is the reason why PEP 563 wasr removed from Python >> 3.10 - because there is no decision which one will go forward in the >> future. Discussion here: >> https://discuss.python.org/t/type-annotations-pep-649-and-pep-563/11363 >> >> However, one could think we are not really affected too much and even if >> we have to change for 3.11 it will be as simple. We do not use some heavy >> runtime type-hinting checks, and PEP 0649 `from __future__ import >> co_annotations' seems to be an easy switch. >> >> *How complex is it to migrate* >> >> It is simple. We Just merge https://github.com/apache/airflow/pull/24816 >> and maybe add a pre-commit to force the __future__ import in all our files. >> That's it. >> >> I did it in a couple of hours and I think it is all that we need - the PR >> I did could likely be merged today and it will be complete. Adding the >> "__future__" import is very easily automate-able and `pyupgrade` does all >> the rest. There is one exclusion that we have to make with >> pyupgrade (gcs.py has "list()" method that interferes with list Type). >> >> There were also a few type fixes that had to be done - but nothing major. >> >> That's about it. No drama. Some tests/docs need fixing but looking at the >> changes - very few. We can add pre-commits guarding it. >> >> *Options* >> >> In the PR I added the 'from __future__ import annotations` to all files >> (semi-automatically). But it does not have to be like that. One can think >> that this introduces some "noise". There are plenty of files that do not >> need it currently. >> >> On the other hand there is a nice "property" of having it in all the >> files: >> >> 1) We can even add it in the pre-commit to be injected automatically >> (should be simple). >> 2) Pyupgrade will automatically upgrade any future "forward" refs and >> optionals for us >> 3) we can keep consistent style of typing everywhere and remove >> __futures__ when we get to Python 3.10 >> >> But we can choose to do half-the way - for example do not add __future__ >> in empty __init__.py files. Or something similar. >> >> I am not 100% convinced myself, but maybe >> >> WDYT? Anyone has experience with it? bad/good one? >> >> J. >> >> >> >> >>