-
-
Notifications
You must be signed in to change notification settings - Fork 302
Add tree_rev
attribute to TreeRebuilder
#1388
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
Conversation
You have probably thought about this, but:
|
Yes and not. The idea was to do After your comment I again thought about if there are options to do these changes backwards compatible. This would certainly be better. We'll have to see what's possible, but I'm already planing to do some initial PRs with this change before moving forward. As for |
👍 Agreed.
What about adding an option/global variable to |
Not sure how practical that would be. I've created the first PR for the Next up will be the |
I reverted passing I'll leave this PR as draft for now. Will probably come back it it once I have much more time (in 2-3 months). |
Pull Request Test Coverage Report for Build 2319748031
💛 - Coveralls |
Sorry I'm a little late to this discussion. This seems like something really impactful in term of maintenance required. As far as I know astroid is not used in any major lib except pylint. For a small script or a pre-commit hooks the astroid version can be set to an old one easily, or upgraded easily because there isn't that much code. So we're not making anyone life miserable by making breaking change in astroid without handling retro-compatibility, unless I'm mistaken. If we would actually make someone life miserable, and if adding rev_tree in astroid is easier than upgrading their library, then the persons affected could do this rev_tree change themself directly in astroid with their own requirements in mind so it would probably fit their need better than what we imagine they would need. As for us we control the astroid version in pylint so we can use astroid > 3 and upgrade pylint's code when we do upgrade ? Basically my argument is that YAGNI. I broke the |
@Pierre-Sassoulas You're right the proposal would complicate maintenance and doesn't even solve all issues. I'm a bit glad we didn't do it 😅 The big issue with the proposal is that even for pylint it wouldn't be all that useful. Yes we could have revisions for the ast tree, but every update we do needs to be complete form the start since we can only select distinct versions. Incremental updates would be better. If I think back, the change from This is what I was thinking of now for the
There might be some edge cases especially around What do you think? |
The deprecation cycle sounds about right, we already have a lot of deprecation like this going on for pylint 3 and astroid 3. We're going to have to release 3.0 at some point, and 4.0 seems very far at this point but if there's no easy way to make it in one step we don't have much of a choice. |
Superseded by #1867 |
Description
First step for pylint-dev/pylint#5466 (comment)
Although it should work like I describe below, I'm certainly open for ideas how to make it better. Especially with regards to the "global" state for
tree_rev
. Let me know what you think @Pierre-Sassoulas @DanielNoord.Important changes
tree_rev
attribute is added toTreeRebuilder
. Usually a value should be passed with__init__
, but it defaults toTREE_REV
defined inconst.py
.TreeRebuilder.visit
requires one more attribute ->tree_rev
. This might seem redundant, since the value is already stored as instance variableself.tree_rev
. Unfortunately, it isn't possible to defined overloads based on instance variables though. The goal is to be able say:"For tree_rev = 1, visit of AST node x returns instance of A, for tree_rev = 2, it returns instance of B."
Fortunately for us, to archive that it is not necessary to add the argument to eachvisit_xxx
function.tree_rev
class variable is added toAstroidManager
. It's basically used to store a "global" state for the selected revision. See below on how it should be use.tree_rev
attribute has been added toparse
. Passing it would temporarily overrideAstroidManager.parse
.Note: This is only intended for experimenting. In production the whole tree should be generated with only one revision.
Rational
We are at a point were multiple issues require updates to the
TreeRebuilder
. At the moment, it isn't really possible to do them in a backwards compatible manner. With this change, libraries likepylint
which useastroid
can choose how they would want the Python AST to be parsed byastroid
. Thus we will enable a more granular upgrade path. In the end that allows us to iterate on tree changes before bundling them all together into a new major version.Intended use
Libraries may either choose to stick with the default revision provided by astroid or override the class variable
AstroidManager.tree_rev
. Changing the revision should be done before any astroid AST is build. For pylint the required change would be right after the imports inpylinter.py
.Impact for plugins
Each update to the tree should essentially be consider a breaking change for all plugins.
pylint
probably more so thanastroid
once. That's just the nature of it, unfortunately. The stability policy this PR uses only extends to libraries which generate the AST themselves (eg. pylint).After a new revision is release, each plugin should be updated to make sure it's compatible. It's important to remember that plugins don't choose the revision themselves. Meaning if they support a large enough version range with multiple revisions, they need to make sure all work as expected. That can, for example, be done with revision guards by accessing
AstroidManager.tree_rev
. (Only important to remember not to do that on import as the version might not have been set yet. (?) )That section also applies to astroids builtin brain modules and as a whole. We need to make sure
astroid
works with all currently supported revisions, regardless of the tree output.Open Challenges
AstroidManager
and thus before the global revision is set, almost all actions are only done later during inference. All, except for one which needs to be fixed separately.https://github.com/PyCQA/astroid/blob/1cf4bf7f3f4491ddda76662a6c57206d10d990b0/astroid/brain/brain_builtin_inference.py#L142-L147
Instead of on import, the method should be run as part of
_post_build
before any transforms are called.https://github.com/PyCQA/astroid/blob/1cf4bf7f3f4491ddda76662a6c57206d10d990b0/astroid/builder.py#L173-L175
The are existing testes for that, so it should be fairly easy to make sure it still works as intended.
astroid
will end up supporting multiple revision at the same time, we also need to make sure to test the whole test suite against each one. That will end up multiplying the time spend on these. In cases where different revisions change unrelated parts, it might be possible to do one tests for the before and after instead of each individually.The good new, that doesn't apply to pylint as it should only ever support one at a time.
Open Questions
Increasing the major version feels wrong, since this isn't directly a user facing change. However as written currently, some things might as well break. So just a minor version bump might be misleading as well.
Just an idea, we could require plugins to specific their supported revisions (lower / upper bound). If the one used by pylint is outside the supported range, the plugin is disabled with a warning. If no bounds are set we would assume the current revision 1. With that in place, updates wouldn't be breaking once any longer and thus it could be possible to include them in
minor
releases as long as we make sure to highlight them in the release notes.The downside here is that we'll probably end up introducing fragmentation into the plugin ecosystem.
Todos
TreeRebuilder
using that change. Test impact on pylint.Type of Changes