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
Upgrade python syntax to 3.9 and newer #6376
Conversation
3a66914
to
7c6c4e8
Compare
It will be easier to resolve merge conflicts in this PR if #6375 is merged first. |
7c6c4e8
to
1582298
Compare
5a24763
to
a737f53
Compare
524e91f
to
d8ad3aa
Compare
I've rebased this PR to fix merge conflicts from the recent whitespace updates. |
d8ad3aa
to
d8477f0
Compare
d8477f0
to
e1fb601
Compare
e1fb601
to
ce67c0a
Compare
I'm following up on some of my old PRs. @jcfr Do you think we can go ahead and proceed with this one? Let me know if |
ce67c0a
to
9ed2c47
Compare
9ed2c47
to
8e8d175
Compare
8e8d175
to
9f7b811
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, looks all good, just added two small comments.
@@ -2707,7 +2707,7 @@ def _messageDisplay(logLevel, text, testingReturnValue, mainWindowNeeded=False, | |||
if not windowTitle: | |||
windowTitle = slicer.app.applicationName + " " + logLevelString | |||
if slicer.app.testingEnabled(): | |||
logging.info("Testing mode is enabled: Returning %s and skipping message box [%s]." % (testingReturnValue, windowTitle)) | |||
logging.info(f"Testing mode is enabled: Returning {testingReturnValue} and skipping message box [{windowTitle}].") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer not to introduce usage of f-strings in logging functions, because using f-strings results in performing expensive string manipulations even if the message does not end up being printed due to the current log level.
Has pyupgrade recommended this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes pyupgrade
changes it to .format() and then re-running changes it again to an f-string. The maintainer points to asottile/pyupgrade#503 (comment) in that f-string usage here is not a performance drop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's a performance concern fstrings and format statements should be avoided in logging calls since the arguments will be evaluated before the logging method is invoked, so the computation will always happen regardless of log level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not going to argue with the maintainer of pyupgrade
on this one, so since there are no exceptions to keep % formatting only for logging statements with pyupgrade
that means I would need to remove pyupgrade
from the pre-commit-config.yaml in this PR and we would have to apply all the changes in a manual review basis and every so often update the Slicer code base to get back into the compliance that we believe in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the link @jamesobutler, it led to some very interesting discussions. There seems to be a very strong disagreement between various Python developers on this topic and probably the correct answer depends on the use case. The insignificant performance drop was a measurement error, in the same issue further along the discussion, the actual performance drop was shown to be about 20%. So, this is a real problem. There are additional potential issues with exceptions during string conversion.
However, in our specific these cases here, there is no performance or exception-safety problems, so it should be fine to use f-strings.
My only concern is that using f-strings in logging would make this the default choice everywhere, even where performance matters. But maybe keeping the classic formatting in our log messages is not a very effective way of educating/reminding developers anyway, and if the cost is not to use pyupgrade at all or spend a lot of time with fighting with various lint tools, then it may just not worth it.
So, I'm OK with keeping the suggested changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at https://pylint.pycqa.org/en/latest/user_guide/messages/warning/logging-format-interpolation.html, the following is indicated:
Another reasonable option is to use f-string. If you want to do that, you need to enable logging-format-interpolation and disable logging-fstring-interpolation.
Given the fact there is no significant performance impact 1, enforcing f-string everywhere is reasonable.
That said, I think we should explicitly configure pylint with:
logging-fstring-interpolation
->disabled
logging-format-interpolation
->enabled
Footnotes
@@ -2730,7 +2730,7 @@ def messageBox(text, parent=None, **kwargs): | |||
import logging, qt, slicer | |||
if slicer.app.testingEnabled(): | |||
testingReturnValue = qt.QMessageBox.Ok | |||
logging.info("Testing mode is enabled: Returning %s (qt.QMessageBox.Ok) and displaying an auto-closing message box [%s]." % (testingReturnValue, text)) | |||
logging.info(f"Testing mode is enabled: Returning {testingReturnValue} (qt.QMessageBox.Ok) and displaying an auto-closing message box [{text}].") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, I would not use f-strings in logging.
9f7b811
to
1c51830
Compare
1c51830
to
ae06131
Compare
Following the integration of #6573, this should be rebased against the current |
ae06131
to
b7536a3
Compare
I've rebased to fix the merge conflict. |
b7536a3
to
0baa88d
Compare
I've rebased to update to the latest version of |
@@ -18,7 +18,7 @@ def writeFile(path, content): | |||
pass | |||
|
|||
# Write file | |||
with open(path, "wt") as f: | |||
with open(path, "w") as f: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since text mode (t
) is the default 1, this makes sense ✔️
Footnotes
@@ -2707,7 +2707,7 @@ def _messageDisplay(logLevel, text, testingReturnValue, mainWindowNeeded=False, | |||
if not windowTitle: | |||
windowTitle = slicer.app.applicationName + " " + logLevelString | |||
if slicer.app.testingEnabled(): | |||
logging.info("Testing mode is enabled: Returning %s and skipping message box [%s]." % (testingReturnValue, windowTitle)) | |||
logging.info(f"Testing mode is enabled: Returning {testingReturnValue} and skipping message box [{windowTitle}].") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at https://pylint.pycqa.org/en/latest/user_guide/messages/warning/logging-format-interpolation.html, the following is indicated:
Another reasonable option is to use f-string. If you want to do that, you need to enable logging-format-interpolation and disable logging-fstring-interpolation.
Given the fact there is no significant performance impact 1, enforcing f-string everywhere is reasonable.
That said, I think we should explicitly configure pylint with:
logging-fstring-interpolation
->disabled
logging-format-interpolation
->enabled
Footnotes
@jcfr I've included W1203 in the ignore of .flake8 configuration which I believe utilizes the pylint codes. |
After looking at this in more details, I realized that
Strictly speaking, running pyupgrade in the GitHub workflow does not really make sense because (1) we do not yet push back the changes to the open pull-request (this could be done enabling and (2) rewriting details are not reported back in the output. Using pre-commit to run against all files may indeed be convenient and may avoid the following:
and only require the following
Source: https://discourse.slicer.org/t/locally-execute-pre-commit-linting-locally/22837 This means that the update of the workflow without enabling service like For these reasons, I will:
Footnotes |
1124f40
to
c63215c
Compare
@jamesobutler Comparing with the version I obtained with |
There was indeed some re-runs of pyupgrade as when you run it once and then immediately run it a second time, it will change more things the second time around. Yes, I might’ve additionally changed some things as well but I don’t remember. Adding pyupgrade to the pre-commit run enforces the updated syntax for new PRs, but I wasn’t planning for it to be auto fixed by a bot. It would be up to the developer to see the reported issues just like if they had incorrect tab counts reported by pylint which they would manually fix and push. I would treat this as a developer responsibility similar to when someone has a commit that doesn’t pass the commit message check in a multi commit PR and it requires fixing up to pass required status checks.
Re (1) I suggest not to auto-fix PRs with pre-commit.ci to push changes back as mentioned in Re (2) rewriting details are indeed reported back in the GitHub action workflow results (or in pre-commit.ci results) and also locally as you’ve shown in your screenshot above. This provides developers clear instructions about what something should be changed or that they can run pyupgrade locally to apply the changes and commit and squash into their appropriate commit. |
Thanks for the detailed answer, this is very helpful 🙏 I will integrate the change and publish pull-requests respectively adding (1) execution of
👍
The screenshot I provided was obtained after running the tool locally, I will investigate further to see how rewritten changed are displayed within the GitHub workflow as I couldn't find an example (yet) Footnotes |
Changes were applied automatically by running: PythonSlicer -m pip install pyupgrade followed by the following command executed twice PythonSlicer -m pyupgrade --py39-plus MyPythonFile.py for every python file in the Slicer repository. Notes: * Running the command twice is needed to ensure that string associated with `logging` package are updated to use f-string. * Changes have been manually reviewed to revisit some of the changes automatically proposed: - removed remaining parenthesis after class definition in WebServer - removed remaining occurences of `socker.error` from WebServer - updated CLISerializationTest to use f-string Co-authored-by: Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
c63215c
to
aeb569c
Compare
Thanks for sharing the example, I will follow up with a PR including your original commit updating the |
See #6605 |
This continually enforces changes made in 4483cc0 and 1a85eba.Changes were applied automatically by running:pre_commit run --all-files
EDIT
Similarly to 1a85eba (introduced through PR #6132) and 4483cc0 (introduced through PR #5625), this PR uses
pyupgrade
to also automatically upgrade python syntax.Using pyupgrade
PythonSlicer -m pip install pyupgrade
PythonSlicer -m pyupgrade --py39-plus MyPythonFile.py
pyupgrade-script.py
written to automate running pyupgrade across all python files in the Slicer repo. It was run byPythonSlicer pyupgrade-script.py
.