dict.get(x, None)
with dict.get(x)
hats = {"bowler": Bowler(), "sombrero": Sombrero()}
fedora = hats.get("fedora", None)
hats = {"bowler": Bowler(), "sombrero": Sombrero()}
fedora = hats.get("fedora")
When using a dictionary's get
method you can specify a default to return if
the key is not found. This defaults to None
, so it is unnecessary to specify
None
if this is the required behaviour. Removing the unnecessary argument
makes the code slightly shorter and clearer.
remove-unit-step-from-range
Replace range(x, y, 1)
with range(x, y)
for i in range(y, len(x), 1):
do_t()
for i in range(y, len(x)):
do_t()
The default step
value for a call to range()
is 1
, so it is unnecessary
to explicitly define it. This refactoring removes this argument, slightly
shortening the code.
Our new duplicate code detection feature is now available for PyCharm!
You can now select multiple files or folders and choose 'Sourcery - Detect Clones' to scan for duplicated code within them. This will find sections of code that are 3 lines long or greater that are duplicated in multiple places. It will also find near-duplicate code where variable names have been changed but the code structure remains the same. The duplicate code found will appear in the Sourcery tool window.
This feature is available in our Pro subscription. It is in active development so we would love your feedback.
Have a piece of code that you don't want to touch that is giving a low quality warning?
You can now disable these warnings in VS Code and PyCharm. Add # sourcery no-metrics
at
the end of the line with the function definition to do so. There's also a new quick-fix
action on the warnings to disable them.
async for
loops.You can now purchase a Sourcery Pro subscription.
With Sourcery Pro you can:
Get more details here.
You can now select multiple files or folders and scan for duplicated code within them. This will find sections of code that are 3 lines long or greater that are duplicated in multiple places. It will also find near-duplicate code where variable names have been changed but the code structure remains the same.
This feature is available in our Pro subscription, for VS Code users only initially. It is in active development so we would love your feedback.
Sourcery is now available in Sublime.
Get more details and setup instructions here.
This will convert code like this:
result = ""
for text in long_list_of_text():
result = result + text
return result
into:
result = "".join(long_list_of_text())
return result
Changes this:
results = sum(1 for token in source.split() if token == 1)
to this:
results = sum(token == 1 for token in source.split())
simplify-boolean-comparison
suggest more oftenuse-count
now triggers on the result of simplify-constant-sum
rather than directlyremove-redundant-if
now slightly more powerfulif..elif
chains with repeated coderemove-redundant-if
when invalidated by a context managerswitch
refactoring could produce incorrect result
This message now displays the name of the function where we have detected low code quality. This lets you easily see at a glance where the problems in your code are.
Sourcery can now propose refactorings to extract blocks of code into new functions. This currently proposes in two circumstances:
This feature will be available in the upcoming Pro subscription.
Select the project or a folder within a project in the IDE plugins, and then have Sourcery scan every file within it. All refactoring suggestions will be displayed as they are found in the Problems window.
This makes it easy to refactor a large portion of the codebase quickly without manually having to visit every file to see the Sourcery suggestions.
This feature will be available in the upcoming Pro subscription.
Previously when aggregating metrics we simply calculated metrics for each function and then averaged them. This did not account for the differing size of functions - a 100 line function has more impact on quality than a 10 line one.
We now weight each metric (apart from method length) by the number of lines in each method when averaging them. This gives a better view of the actual file and project-level quality.
Hoist code from an else
after a guard clause. This will happen where the main body of an if
contains only a raise or return statement, and there are multiple statements in the else
.
def f(a=None):
if a is None:
return 42
else:
# some long statement
var = (i ** 2 for i in range(a))
return sum(var)
is converted into:
def f(a=None):
if a is None:
return 42
# some long statement
var = (i ** 2 for i in range(a))
return sum(var)
Where a value is set on each branch of an if
and then immediately returned, instead return it directly from each branch.
def f():
if condition:
val = 42
else:
val = 0
return val
is converted into:
def f():
if condition:
return 42
else:
return 0
Use with sourcery refactor --in-place
to backup changed files with given suffix:
sourcery refactor --in-place --backup .bak main.py
If any refactorings are found in main.py
a copy will be made
at main.py.bak
before it is updated in place.
for-index-replacement
for lists, as it's possible __len__
and __getitem__
are implemented but __iter__
is not.swap-if-else refactoring
. This will now also be triggered where it can enable the above remove-else-after-guard
refactoring. The description has also changed to reflect this.
This refactoring uses the fact that Python allows negative list indices to be accessed directly.
It converts this:
last_element = a[len(a) - 1]
into this:
last_element = a[-1]
The merge-comparison proposal will now apply in this case:
if x != a and x != b:
do_stuff()
This will be converted to:
if x not in [a, b]:
do_stuff()
pass
statements at class level
Sourcery is now available as a command line interface. This enables several new use cases:
This functionality is only available with Pro/Team subscriptions. If you'd like to try it out for your team please contact us.
The Sourcery command line interface can be installed by running:
pip install sourcery-cli
Once installed you can interactively login with:
sourcery login
which will open up a browser tab and ask for confirmation.
To display suggested refactorings as a diff:
sourcery refactor {file_or_directory}
And to apply those changes to the files:
sourcery refactor --in-place {file_or_directory}
Full documentation is available here.
You can now hover over a method definition to see a quick view of its code quality. The metrics available are:
This can be switched off in the Sourcery section of the plugin settings.
with
context manager to ensure file closureA common way of opening and using files is:
file = open("welcome.txt")
data = file.read()
print(data)
file.close()
However if an exception is thrown in between the file being opened and closed the call to file.close()
may end up being skipped.
By using Python's with
context manager the file is closed for you as soon as the block is exited.
with open("welcome.txt") as file:
data = file.read()
print(data)
list-comprehension
refactoringWe have now extended this refactoring to include an additional case, where augmented assignment is used to add to the list rather than append
.
The following code:
files = []
for x in file_iterator:
if x[-4:] == ".csv":
files += [x]
will now be refactored as:
files = [x for x in file_iterator if x[-4:] == ".csv"]
if
expression by using or
Often we find ourselves setting a value if it evaluates to True, and otherwise using a default.
currency = args['currency'] if args['currency'] else DEFAULT_CURRENCY
This can be simplified to the following, which is a bit easier to read and avoids the duplication of args['currency']
.
currency = args['currency'] or DEFAULT_CURRENCY
use-assigned-variable
from re-using properties
We've been making some changes to how our code quality metrics are displayed.
When hovering over a method definition you now get more explanation of the code metrics. This means that you can see if the metric scores are good or bad at a glance.
In VS Code this is an emoji as shown above, whereas in PyCharm it is shown in writing. For each metric if the score is below average we also give a tip on how to improve it.
Right now these metrics are hidden by default in PyCharm and VS Code, but they're very easy to enable.
To set them up just add the following setting to your Sourcery config file:
metrics:
enabled: True
Loop counters that are incremented on each iteration of the loop like so:
i = 0
for animal in animals:
i += 1
print(i, animal)
can be replaced with a call to enumerate
with a suitable start index:
for i, animal in enumerate(animals, start=1):
print(i, animal)
The following simple but overly verbose code:
return True if some_boolean_expression else False
is refactored to:
return bool(some_boolean_expression)
The negated version:
return False if some_boolean_expression else True
is refactored to:
return not some_boolean_expression
Instructions for how to write a code editor plugin are now available here. As the Sourcery binary implements the Language Server Protocol it is very easy to write a plugin for a new code editor.
We wanted to make it easier for you to bring Sourcery into your workplace so you can improve your codebase. Starting today you can now use Sourcery for free with up to 3 team members! This is for both public and private repos.
Sourcery will review and refactor all new pull requests for these team members and give you insight to code quality. The only limitation is that refactoring whole private repos is still disabled on the free tier.
Public repos, as always, get access to all of Sourcery's features for free.
One of the big takeaways from some of our conversations with you is that teams != full GitHub organisations.
Now you can pick and choose individual team members within your organisation who should have Sourcery access.
All organisation members still get full Sourcery functionality for public repositories.
Our code quality tools are now available outside of GitHub! Right now they're hidden by default in PyCharm and VS Code, but they're very easy to enable.
To set them up just add the following setting to your Sourcery config file:
metrics:
enabled: True
We're still in the alpha stage of our code quality tools within IDEs, so we'd love to get your feedback and thoughts as we continue to make improvements.