Skip to content

Reformat to use external runner #81

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

Merged
merged 2 commits into from
Dec 14, 2022
Merged

Reformat to use external runner #81

merged 2 commits into from
Dec 14, 2022

Conversation

jakkdl
Copy link
Member

@jakkdl jakkdl commented Dec 13, 2022

The PR is split into two commits, the first does the refactoring, the second splits up VisitorMiscChecks (turns out some comments were wrong in what visitors in it were necessary for which checks...) so most of those checks should be easier to read. So I'd recommend reading the diffs for those separately.

Was somewhat tricky to get this working with some of the very particular checks - and so it doesn't fully only iterate through the tree once. If a visit_ function calls self.visit() (either directly or through self.generic_visit()/self.visit_nodes()) it will set a flag self.novisit which tells the external runner to exclude that class when visiting subnodes so they're not visited twice.

To not have to do that too often I added Flake8TrioVisitor.save_state(node) which serves the same purpose as get_state/set_state did previously

outer = self.get_state(...)
# do stuff before visiting child nodes
...

# visit child nodes
self.generic_visit(node)
# restore state
self.set_state(outer)

so that can now be written

self.save_state(node, ...)
# do stuff before visiting child nodes
...
# generic_visit and set_state are both handled by external runner

get/set state are still used in a couple places when manually visiting, but should be possible to get rid of them completely and only have save_state().

I think I could get rid of nodes visiting their own subnodes entirely by adding

  1. exit_Xxx which is called for a node after it's subnodes have been visited (would clean up all cases of self.generic_visit(node) being used)
  2. visit functions for node parts that in the AST don't have dedicated nodes, e.g. visit_Finally or visit_WhileElse. This would split up several long functions and solve the last cases of revisits - only trouble child would be 107_108.visit_loop, which explicitly wants to visit the body twice atm, but I could probably rewrite that.

This would maybe give some performance gains, but should make the code simpler as well and can entirely remove Flake8TrioVisitor.visit() and .visit_nodes() - at the cost of adding some more "magic" method names or other construction (realizing as I'm writing I can have visitor classes implement a visit_Xxx as a pseudo-contextmanager, with enter and exit as magic names, and other names called as they match up with the _fields of the Xxx node. And the external runner handles a visit different depending on if it's isinstance function or class)

I'm not super happy about the current novisit solution with lots of set updating, and I have some alternative solutions, but getting rid of it entirely by implementing 1&2 above would ofc be even nicer.

Looking at runtime I'm not seeing much if any improvement in performance, not even just looking at --runfuzz -k site_code, so maybe reiterating through the tree multiple times wasn't that much of an issues, or my external runner adds enough overhead it's voided, but there could maybe be gains on code with large files and complicated functions - or at least when 1+2 are implemented.

I'm also starting to want to split up flake8_trio.py into different files, 1500 lines is starting to be quite inconvenient to navigate, and get any overview on, but not gonna do that in this PR as it would completely mess up any remaining diff logic - I also know you are hesitant to split given installation complications so would have to take care when doing that.

There's two TODO's in the code, probably not gonna touch them in this PR

  • Exclude subclasses for disabled checks - probably not a priority for Anthropic since you're always gonna use all checks (for now), but would help when debugging a single runner and could help to find out if any one visitor is eating a ton of time (and e.g. find out if 1+2 are worth it for performance reasons).
  • don't hard code unnecessary variables in get_state - elected not to touch this for now as it would most likely just mean renaming a lot of variables and that'd make a big diff even bigger. But is bound to introduce bugs in it's current state so plan to fix it soon after merge.

unless a check manually visits nodes in which case they will be visited
several times.
Copy link
Member

@Zac-HD Zac-HD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad I reviewed by commit, but this looks good to me!

As a follow-up, it'd be nice for each visitor class to have a docstring briefly explaining what they do - just copying the relevant line from the readme would be plenty. Also non-blocking comment on a comment below.

Merging this now because I want to avoid potential merge issues with future work 🙂


class Visitor100(Flake8TrioVisitor):
def visit_With(self, node: ast.With | ast.AsyncWith):
# Context manager with no `await trio.X` call within
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong comment; this is checking for with trio.{fail,move_on}_{at,after} contexts which do not contain a checkpoint.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in #82

@Zac-HD Zac-HD merged commit 7cdd918 into python-trio:main Dec 14, 2022
@jakkdl jakkdl mentioned this pull request Dec 16, 2022
5 tasks
@jakkdl jakkdl deleted the reformat branch December 31, 2022 13:06
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.

2 participants