Skip to content
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

Supports standard library nodes #46

Conversation

tristanlatr
Copy link
Contributor

@tristanlatr tristanlatr commented Mar 8, 2023

Fix #45.

It's still works with gast of course. But starting at Pyhton 3.6 beniget provides a beniget.standard module which has the same public interface as the main module except it works with standard library nodes.

All test classes have been adjusted to allow changing the reference ast module, standard library test are implemented as a subclass fo the original test case.

@tristanlatr tristanlatr changed the title Supports standard library ndoes Supports standard library nodes Mar 8, 2023
@serge-sans-paille
Copy link
Owner

Hey Tristan. The only reason for not using gast would be to speedup processing, and that would need to be backed with numbers. We currently don't need to think about ast representation thanks to gast, and I consider this a good point. So my question would be: what motivates this PR? (And by the way, thanks for your interest in beniget, are you using it for some specific project / purpose?)

@tristanlatr
Copy link
Contributor Author

The main motivation to use standard library ast nodes is to be compatible with all the code that already exist that is using the standard library. It's not about performance really to me, but I agree it should improve it a little.

More specifically, I'm looking at beginet to be the core of a new library which will aim at analyzing the code structure of entire packages and the relationship between them for documentation purposes. My plan it to use beniget to solve these issues twisted/pydoctor#295 twisted/pydoctor#348, by creating a code model which will be used by pydoctor to do the name resolution. One of the challenges is to find the canonical name for each symbols (because one symbol can be imported and accessible in several modules). Another challenge is the handling of __all__ variable, etc...

Hope this answer your question

@serge-sans-paille
Copy link
Owner

gast has a ast_to_gast and a gast_to_ast functions. Your change here is being too intrusive for the benefit, I'm going to decline... Sorry for being conservative, but keeping many projects manageable in my small brain is of primary importance to me :-)

And thanks for sharing your plan. I'll try to support this by making beniget more robust, as in fixing #44 !

@tristanlatr
Copy link
Contributor Author

I get it... But it's too bad because making beniget compatible with the standard library is probably much less work that making pydoctor compatible with gast.

But I'll see what I can do about this...

@tristanlatr
Copy link
Contributor Author

I’m reopening this pull request (and I’ll update it as well) because I think it’s highly relevant in terms of performance gain. Generating the def use chains takes about a third of the time taken to produce the gast…

beniget/beniget.py Outdated Show resolved Hide resolved
@tristanlatr tristanlatr marked this pull request as ready for review November 15, 2023 21:16
@tristanlatr
Copy link
Contributor Author

We could use a subclass for the standard library nodes, It might be even more clean and do not require to change all the isinstance calls.

@tristanlatr tristanlatr marked this pull request as draft April 9, 2024 16:01
@tristanlatr
Copy link
Contributor Author

I'm marking this PR as draft until I implement a much less intrusive diff

@tristanlatr tristanlatr marked this pull request as ready for review April 12, 2024 01:59
beniget/beniget.py Outdated Show resolved Hide resolved
beniget/beniget.py Outdated Show resolved Hide resolved
beniget/standard.py Outdated Show resolved Hide resolved
tests/test_attributes.py Outdated Show resolved Hide resolved
tests/test_capture.py Outdated Show resolved Hide resolved
@tristanlatr
Copy link
Contributor Author

tristanlatr commented Apr 12, 2024

Salut @serge-sans-paille,

J'espère que tu vas bien.

Je me permet de te relancer quant à ces changements. L'idée c'est ne plus utiliser isisntance pour determiner le type des noeuds, mais de comparer type(x).__name__ à la place. Je pense même que ça améliore les performances un chouya puisque qu'on ne vas pas chercher la MRO des classes.

Le reste du code spécifique à la librairie standard est dans un nouveau module: beniget.standard, qui offre la même interface publique que le module beniget. L'idée est d'être de moins invasif possible tout en offrant le support pour les noeuds standards, qui ne sont pas si différents au final.

La suggestion initiale d'utiliser un mapping ast -> gast ne semble pas viable, en plus d'être tres inefficace, j'ai pas réussi a faire passer les tests de beniget avec la version modifiée.

C'est pour ça que j'espère vraiment que tu vas considérer ces changements,

Merci,

@serge-sans-paille
Copy link
Owner

serge-sans-paille commented Apr 15, 2024

Hey @tristanlatr . I'm not a big fan of the name based-check, and the additional checks for two different kind of nodes.
Do you think it would work to pass the ast module in the constructor and have it just be a member of the analysis, so that we would write:

if isinstance(self.node, self.ast.Name):

instead of

if isinstance(self.node, ast.Name):

?

@tristanlatr
Copy link
Contributor Author

Yes that could work! But Def and _CollectFutureImports will need to be changed as well.
Let me try to refactor this PR.

@tristanlatr
Copy link
Contributor Author

tristanlatr commented Apr 15, 2024

Après quelques analyses, Le but ici est de rendre la classe DefUseChains assez flexible et auto-dépendante afin de pouvoir implementer tous les changement pour la librairie standard en créant une classe dérivée.

Donc ça implique créer les attributs de classes suivant:

  • DefUseChains.ast: Le module ast de référence
  • DefUseChains.Def: La classe Def de référence
  • DefUseChains.collect_future_imports et _CollectFutureImports
  • DefUseChains.collect_locals et CollectLocals
  • DefUseChains._validate_comprehension et autres
  • DefUseChains.lookup_annotation_name_defs et autres

Pour UseDefChains y'a rien a faire.
Pour Ancestors y'a rien a faire.

Ensuite:

  • Changer toutes les occurrences de ast dans DefUseChains par self.ast.
  • Changer toutes les occurrences de Def(...) par self.Def(...)
  • Ajuster standard.DefUseChains utiliser le module ast standard et utiliser la version adaptée de Def

Je ne suis pas certain que passer le module ast de reference par le constructeur est le plus simple: pourquoi pas une classe dérivée et assigner le module ast en tant que variable de classe ? (Comme je fais dans les tests d’ailleurs)

Merci,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make it work with the standard library
2 participants