Note for PyCharm users - version 2020.2 or later is required for Sourcery 0.9.3 and above.
Sourcery can now perform class-level refactorings! It scans your classes for duplicate code and will suggest extracting it into methods.
Normally Sourcery scans for refactorings on every code change. Class-level scans need to do more analysis, so this will only run on file open and save to improve performance.
class-extract-method
Extract duplicate code from different methods in a class into a new one.
Available to all users while in alpha, then will move to Pro/Team
class TestClass:
def extraction_example(self):
self.speed_slider = Scale(
self.parent, from_=1, to=10, orient=HORIZONTAL, label="Speed"
)
self.speed_slider.pack()
self.speed_slider.set(DEFAULT_SPEED)
self.speed_slider.configure(background="white")
def intervening_function(self):
return 1
def next_example(self):
self.force_slider = Scale(
self.parent, from_=1, to=10, orient=HORIZONTAL, label="Force"
)
self.force_slider.pack()
self.force_slider.set(DEFAULT_FORCE)
self.force_slider.configure(background="white")
class TestClass:
def extraction_example(self):
self.speed_slider = self._extracted_from_next_example_2("Speed", DEFAULT_SPEED)
def intervening_function(self):
return 1
def next_example(self):
self.force_slider = self._extracted_from_next_example_2("Force", DEFAULT_FORCE)
def _extracted_from_next_example_2(self, label, arg1):
result = Scale(self.parent, from_=1, to=10, orient=HORIZONTAL, label=label)
result.pack()
result.set(arg1)
result.configure(background="white")
return result
Do not Repeat Yourself (DRY) is an important tenet of writing clean, maintainable code. Duplicated code bloats the code base, making it harder to read and understand. It often also leads to bugs. Where changes are made in only some of the duplicated areas unintended behaviour will often arise.
One of the main ways to remove duplication is to extract the common areas into
another method and call that. Sourcery can detect areas of duplicate code that
are in different methods in the same class and extract them. It is recommended
that you then rename the extracted function and any arguments that have not been
automatically named. In the above example a suitable method name would be
create_slider
, and arg1
would be default_value
.
In VS Code each location to be extracted from is shown as a sub-heading in the Problems pane so you can keep track of what is happening.
Class-level refactorings such as this one run on file open and file save, rather than on every change to the code.
When a refactoring only uses one proposal, there will now be a menu option in VS
Code and PyCharm to 'Never show me this refactoring', or 'Turn off this
refactoring permanently'. This will permanently disable this proposal, and it
will not be displayed to the user again on that machine. This configuration is
stored in a sourcery.yaml
file in the user's config location. Other
configuration can also be set up in this file, for example to configure the
clone detection parameters.
When this option is taken a notification is displayed to the user asking for feedback and giving them the location of this config file if they wish to edit it and undo the action.
As part of these changes the 'Skip all' menu option has been removed, to avoid
having too many Sourcery options. Adding # sourcery: skip
to a function
definition will still work as before.
merge-except-handler
Merge except handlers with identical code blocks
try:
connect(credentials)
except ConnectionError as e:
log_error(e)
except RuntimeError as e:
log_error(e)
try:
connect(credentials)
except (ConnectionError, RuntimeError) as e:
log_error(e)
This reduces repetition across equivalent exception handlers by combining them into one.
min-max-identity
refactoring will now trigger on appropriate if
expressionsawait
or yield