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

Compute TokenList.value dynamically #623

Closed

Conversation

living180
Copy link
Contributor

Partial fix for #621:

To avoid quadratic behavior, make TokenList.value a dynamically-computed property rather than an attribute so that it does not need to be recomputed each time TokenList.group_tokens() is called with extend=True.

The first three commits in this PR are supporting work: I found that making TokenList.value a property caused test failures due to line endings not being correctly preserved when stripping comments. This is due to the fact that before making TokenList.value a property, the StripCommentsFilter was changing the underlying tokens without updating the value attribute of the parent TokenList. After making TokenList.value a property, those changes did get reflected in the parent TokenList's value and as a result the desired line endings were being lost.

The most straightforward way I found to address this was to make comment stripping happen before grouping is performed, which required a small amount of hackery to make grouping happen via a filter. I am open to suggestions to better ways to handle this.

I am also a little concerned about the possibility for slowdowns if a particular TokenList's value is accessed, and thus computed, multiple times, but I didn't actually observe any. This might still be an issue via a codepath I didn't look at. I have some ideas on how to address it if a performance problem comes up, but it would clutter up the code somewhat so I didn't want to implement it unless a need could be demonstrated.

This will allow moving some filters to run before the tokens are
grouped.
Rename Token to TokenBase and make it a superclass for TokenList and a
new Token class.  Move some of the functionality of TokenBase into Token
and TokenList.
The fact that a new value was being computed each time
TokenList.group_tokens() is called caused supra-linear runtime when
token grouping was enabled.

Address by making TokenList.value a dynamically-computed property rather
than a static attribute.
@codecov
Copy link

codecov bot commented May 19, 2021

Codecov Report

Merging #623 (0e187cd) into master (23d2993) will increase coverage by 0.03%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #623      +/-   ##
==========================================
+ Coverage   96.82%   96.86%   +0.03%     
==========================================
  Files          20       20              
  Lines        1514     1532      +18     
==========================================
+ Hits         1466     1484      +18     
  Misses         48       48              
Impacted Files Coverage Δ
sqlparse/__init__.py 100.00% <100.00%> (ø)
sqlparse/engine/filter_stack.py 100.00% <100.00%> (ø)
sqlparse/filters/__init__.py 100.00% <100.00%> (ø)
sqlparse/filters/others.py 98.90% <100.00%> (+0.10%) ⬆️
sqlparse/formatter.py 95.12% <100.00%> (ø)
sqlparse/sql.py 97.67% <100.00%> (+0.06%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 23d2993...0e187cd. Read the comment docs.


def enable_grouping(self):
self._grouping = True
self.grouping_filter.enable()

Choose a reason for hiding this comment

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

I was working off of this change today and found myself wanting to initialize it to None on line 20, then build the GroupingFilter and append it it to stmtprocess here if it is None.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason I went with the approach that I did is that I wanted to ensure that grouping continued to happen before the other filters were run. Looking at the usages within sqlparse, implementing your approach would keep the existing behavior. I also know that Django Debug Toolbar calls .enable_grouping() manually, but it shouldn't be affected by your approach either.

The only concern would be if some other code appends a filter that requires grouping and then calls .enable_grouping() after appending that filter, things would break.

@adamantike
Copy link

This PR will potentially fix django-commons/django-debug-toolbar#1402. I would really appreciate if it can be reviewed and considered for being merged!

@living180
Copy link
Contributor Author

Closing in favor of #710.

@living180 living180 closed this Mar 28, 2023
@living180 living180 deleted the dynamic_tokenlist_value branch March 28, 2023 13:30
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.

3 participants