@sourcery-ai summary
in your review. You can also add this in to your
summary template and we'll insert it in-place.@sourcery-ai
in your title.We've made significant improvements to our code reviews, IDE plugins, and GitHub integration. These include UX enhancements, more customization options, and new features for better code management and collaboration.
You can now customize your reviews with your own style guides, conventions, migration rules, and review rules for specific files or directories.
You can also chat with the Sourcery bot in the review comments to continue a conversation. Understand the issue better, get advice, and generate code in real time.
Reviews
IDE plugins:
We've now brought our instant AI code review functionality into your IDE. The new 'Review' tab in the Sourcery sidebar lets you get a review straight away, keeping you in flow and letting you address issues without context switching.
On GitHub we've revamped our dashboard to make it easier to add and remove team members, and we've added configuration - you can now get your reviews in any language (within reason). Install it here. It is free for open source repos, and has a 2-week trial otherwise.
We'd love to hear your feedback! Reach out at Reviews@sourcery.ai. For general inquiries, contact us at hello@sourcery.ai. Ask for help or suggest improvements on GitHub.
Our Code Review functionality is generally available for GitHub! Install it here. It is free for open source repos, and has a 2-week trial otherwise.
We'd love to hear your feedback! Reach out at Reviews@sourcery.ai. For general inquiries, contact us at hello@sourcery.ai. Ask for help or suggest improvements on GitHub.
suggestion
type (where applicable) to help you improve your code.@sourcery-ai review
in a pull
request comment.
@sourcery-ai review
can be used both to request a first review and
to re-request a review after making changes;@sourcery-ai review
for
the review to be triggered - any additional text will cause Sourcery to
ignore the comment;@author
.use-fstring-for-formatting
that caused Sourcery to suggest using f-strings with starred expressions.We made a mistake during our release process and v1.17.0 is not available. Please upgrade to v1.18.0 instead.
Our Code Review functionality is now generally available for GitHub! Install it here. It is free for open source repos, and has a 2 week trial otherwise. As part of this we have moved our legacy GitHub bot functionality over to the new system - instead of opening a new pull request with the Sourcery rules, these are shown as inline comments on your PR.
temp
directory to fix issue when running in remote SSH
session.This release introduces a number of fixes and stability improvements mainly focused on the Sourcery Coding Assistant.
Our Code Review functionality is in active development in a closed beta. To request access, please email tim@sourcery.ai.
We made a mistake during our release process and v1.14.0 is not available. Please upgrade to v1.15.0 instead.
This release significantly improves the code review assistant. Several stability improvements and bug fixes are also included.
Our Code Review functionality is still in a closed Alpha. To request access, please email tim@sourcery.ai.
This release introduces a number of fixes and stability improvements mainly focused on the Sourcery Coding Assistant.
Our Code Review functionality is still in a closed Alpha. To request access, please email tim@sourcery.ai.
bin-op-identity
.This release introduces a number of fixes and small features to improve the stability of the IntelliJ plugin, especially on Windows, as well as improvements to our model prompts.
The Sourcery Coding Assistant is now available in all JetBrains IDEs including Intellij and PyCharm!
Get it here:
AccessDeniedException
in the Intellij plugin along with other
Windows issuesAsk Sourcery
Command Palette error/
Release 1.10 fixed a number of bugs in our coding assistant from version 1.9.0 and added in support for the coding assistant for JetBrains IDEs. It's currently available in a closed beta for JetBrains users, but will be more broadly available shortly.
dict-assign-update-to-union
refactoring to suggestionWe've reworked our Jetbrains plugin, making lots of under-the-hood changes. These will enable us to deliver a more consistent experience between Jetbrains IDEs and VS Code. In particular we will soon be making the Sourcery Coding Assistant available for JetBrains IDEs.
This means quite a few changes will be apparent in the new version:
We have also continued to make improvements for the Sourcery Coding Assistant in VS Code. We improved both the output for some recipes and the code search used in the background. Also, the chat history is now stored in your local sqlite database.
The assistant is currently only available in closed beta. If you want to get early access to it, please sign up to the waitlist.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community. Ask for help or suggest improvements on GitHub.
use-getitem-for-re-match-groups
to a suggestionSome more improvements for the Sourcery Coding Assistant. We improved both the output for some recipes and the code search used in the background. Also, the chat history is now stored in your local sqlite database.
The assistant is currently only available in closed alpha. If you want to get early access to it, please sign up to the waitlist.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community. Ask for help or suggest improvements on GitHub.
This release considerably improves the Sourcery coding assistant recipes and chat. Basic support for non-Python languages has been added. We are also introducing two new modes: Troubleshooting and Code Review.
The assistant is currently only available in closed alpha. If you want to get early access to it, please sign up to the waitlist.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community. Ask for help or suggest improvements on GitHub.
This new version of Sourcery includes more features and improvements to our coding assistant:
coding_assistant.project_description
field to the Sourcery
configuration file (.sourcery.yaml
). This field is used to inform the
Sourcery coding assistant about the project and improve the quality of the
suggestions. For instance, an appropriate .sourcery.yaml
file for the
sourcery-analytics
project would contain
coding_assistant:
project_description: |-
Sourcery Analytics is a command line tool and library for statically analyzing
Python code quality.
TypeError
s when retrieving the currently active fileThis release adds more features to our coding assistant, including two new
recipes: Simplify Code
and Generate Docstring
. We also improved the way you
can interact with the assistant by using code lens. The Debug Code
recipe has
been renamed as Troubleshoot
and is now more powerful.
The assistant is currently only available in closed alpha. If you want to get early access to it, please sign up to the waitlist.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community. Ask for help or suggest improvements on GitHub.
Simplify Code
recipeGenerate Docstring
recipeTroubleshoot
and improve its functionalitytsx
and jsx
files via language IDThis release continued to add features to our pair programming coding assistant,
in particular a new Ask Sourcery
command that lets you easily request
assistance from within the code editor. This can be triggered from the command
palette, selecting some code and right-clicking, or from a code lens above
Python classes and functions.
The assistant is currently only available in closed alpha. If you want to get early access to it, please sign up to the waitlist.
We also addressed the slow activation times that users were seeing with our VS Code extension.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community. Ask for help or suggest improvements on GitHub.
Ask Sourcery
command to let you trigger recipes or ask questionsReview Code
recipe - allowing you to get code reviews of
the selected codeThis release includes the first version of our pair programming coding assistant that allows you to:
The assistant is currently only available in closed alpha. If you want to get early access to it, please sign up to the waitlist.
This release also re-adds the ability to log in by inserting your Sourcery token, fixed a few bugs and improved some error messages.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community. Ask for help or suggest improvements on GitHub.
Implemented the first version of our closed-alpha coding assistant
Re-added the ability to log in by inserting your Sourcery token
Improved cross-file type inference for several Sourcery rules
We now show the rule ID to be skipped in the skip commands
New Sourcery rules:
iloc
for indexing in Pandas
(use_iloc)Path.exists
checks
(remove-redundant-path-exists)paths
configuration of custom rulesgetattr
based on its default
argument.
Fixes #349bytes
and str
s compare differently in Sourcery rule conditionsFor this release we've added some new rules, improved validation when creating custom rules, and squished some pesky bugs.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community.
Add method-chaining pandas rule
enable rule saving in interactive scan
no complex tests rules: dont-import-test-modules, no-loop-in-tests, no-conditionals-in-tests
rule config validation errors in PyCharm
show url on hub command in CLI
surface rule config validation errors in the language server
validate node kinds in the rules config
Rule
encoding issue for rules rendering on WindowsWe've now moved our multi-language support into public beta. This means that everyone will now start seeing Sourcery suggestions for JavaScript and TypeScript files - you no longer need to request a sign-up.
We'd love to hear your feedback! Reach out at hello@sourcery.ai or on Twitter @SourceryAI. Join the Sourcery Discord Community.
.sourcery.yaml
file in VS CodeOn the Python side, we focused on data science in this release. Now, you'll get
suggestions related to some Pandas best practices, like the apply
function or
the inplace
argument.
We've continued working on multi-language support. Now, you'll get suggestions for JavaScript code in PyCharm as well. We've also introduced several tweaks to the multi-language engine and the rule syntax.
Python
dataframe-append-to-concat
Pandas rulepandas-avoid-inplace
ruleDataFrame
objectsJavaScript
There are fewer updates in this alpha release as we've been focused on research and development of our core engine.
As well as a couple of new JavaScript rules and a fix for an edge case in the
Python rule simplify-fstring-formatting
, we've released reference
documentation for every JavaScript rule that ships with Sourcery - see for
instance documentation for the new rule dont-reassign-caught-exceptions
at
https://docs.sourcery.ai/Reference/Default-Rules/javascript-rules/dont-reassign-caught-exceptions/
Also new in this release is a command in VSCode for Sourcery called "Search and Replace across workspace" - this will open a panel where you can use our pattern matching and replacing syntax to apply a one-off rule. This feature is in early stages of development - please reach out at hello@sourcery.ai if you are interested in learning more.
dont-reassign-caught-exceptions
javascript ruledont-reassign-foreach-variables
javascript ruledont-use-wrappers-for-builtins
javascript rulesimplify-fstring-formatting
will no longer trigger where constant "{" and
"}" are being used, to avoid creating invalid code.This release adds many new JavaScript and TypeScript rules using Sourcery's (alpha-stage) multi-language functionality.
If you are interested in getting access to the Beta for Sourcery for JavaScript and Typescript, please sign up here.
no-eval
JavaScript ruleremove-redundant-boolean
JavaScript ruleuse-braces
JavaScript ruledont-negate-is-instanceof-operands
JavaScript ruleremove-unreachable-code
JavaScript rulemisplaced-break-or-continue
JavaScript ruledont-shadow-arguments
JavaScript ruleremove-redundant-if-statement
JavaScript ruledont-reassign-parameters
JavaScript ruleinline-immediately-returned-variable
JavaScript ruleavoid-function-declarations-in-blocks
JavaScript rulesimplify-boolean-comparison
will now trigger in
match-case guard clausespossible-incorrect-bitwise-operator
JavaScript ruledont-self-assign-variables
JavaScript rulegenerators-should-yield
JavaScript rulethrow-new-errors
JavaScript ruleremove-redundant-slice-index
JavaScript ruleonly-delete-object-properties
JavaScript ruledont-use-with
JavaScript ruledont-concatenate-string-literals
JavaScript ruleno-new-symbol
JavaScript rulereturn-outside-function
JavaScript ruleyield-outside-generator
JavaScript ruleavoid-infinite-loops
JavaScript ruleuse-array-literal
to handle argumentsuse-object-destructuring
and combine-object-destructure
extended to also
work for let
statementsuse-braces
refactoringremove-dict-keys
no longer proposed when the target has multiple valuesmerge_assign_and_aug_assign
can no longer incorrectly lead to access to a
variable not assigned yetdict-literal
, list-literal
and remove-unnecessary-cast
from
incorrectly triggering in match-case patternsThis release adds support for Sourcery's (alpha-stage) multi-language functionality in its Language Server implementation. Alpha testers may begin to see refactorings suggested for JavaScript and TypeScript files in their Language-Server compatible IDEs, such as VSCode.
If you are interested in getting access to the Beta for Sourcery for Javascript and Typescript, please sign up here.
assignment-operator
javascript ruleavoid-using-var
javascript rulebinary-operator-identity
javascript rulede-morgan
javascript ruleflatten-nested-try
javascript ruleflip-comparison
javascript ruleinvert-ternary
javascript rulemax-min
javascript rulemerge-assign-operators
javascript rulemerge-else-if
javascript rulemerge_nested_ifs
javascript ruleno-new-function
javascript ruleprefer-arrow-callback
javascript rulesimplify-ternary
javascript ruleuse-array-literal
javascript ruleuse-object-destructuring
javascript ruleuse-ternary-operator
javascript rulewhile-guard-to-condition
javascript rulewrap-immediately-invoked-function-expressions
javascript ruleswap-if-expression
will no longer trigger where there are nested if
expressions.docstrings-for-packages
out from the docstrings-for-modules
GPSG
rule.0/0
in js binary-operator-identity
rule.sourcery hub
command in the CLI
and a status bar icon in PyCharm. This lets you easily enable and disable
rules for your projects.This Sourcery release includes a brand-new billing dashboard for team administrators to view and manage their payment settings.
include
setting from old version of config now treats an empty
list as including the "default" rule set, so that Sourcery's default rules
still run.instance-method-first-arg-name
by not triggering if there
are any decorators present.replace-interpolation-with-fstring
failing for strings with
quotes.You can now configure Sourcery directly from VS Code. Just click the Sourcery button in the VS Code status bar at the bottom.
Then you can login, read the Getting Started instructions or select Sourcery rules to enable and disable
Sourcery now parses and understands Python 3.10 code including the all important
match
syntax.
You can now easily run the Google Python Style Guide.
Enable it directly from config with:
rule_settings:
enable:
- default # Continue to run the default rules
- google-python-style-guide # Add in the additional
Or run it directly from CLI with
sourcery review --enable google-python-style-guide PATH
rule_settings:
enable:
- default # Continue to run the default rules
- google-python-style-guide # Add in the additional
sourcery review --enable google-python-style-guide PATH
match
statements.with
statements containing multiple bracketed context
managers..sourcery.yaml
keys:
refactor
-> rule_settings
rule_settings.include
-> rule_settings.enable
rule_settings.skip
-> rule_settings.disable
^\[A-Za-z\]\[A-Za-z0-9-\_/:\]\*$
refactor
-> rule_settings
and other config keys when
adding disable
rule ids from IDEsIn this update, Sourcery takes the tedium out of signing in in your IDE.
Previously, we asked you to enter a token from your Sourcery dashboard into your
IDE settings. Now, we are able to handle the full login flow automatically. Use
the Sourcery: Login
command from VSCode, or the Login
button in the Sourcery
window in Pycharm, then follow the instructions in your browser.
--summary
and --no-summary
rule_tags
to define additional rule tags--no-summary
optiongoogle-python-style-guide
tag to the Google Python Style Guide rules.Sourcery: Login
command from the command paletteconvert-any-to-in
inline-immediately-returned-variable
doesn't trigger where the
variable has a return annotation.python_version
specified as a stringRules can now be tagged by adding a tags key. Then you can include these tags from the CLI to choose a subset of rules to run.
This makes it easy to specify which rules you want to run in CI. First add a tag to the rules you want:
rules:
- id: important-rule
tags:
- ci
pattern: '...'
Then run the ci
tag with sourcery review --include ci .
It is now much easier to configure Sourcery to run in pre-commit or CI. Run:
sourcery init pre-commit
sourcery init ci
include
and exclude
/skip
config and
CLI options. Sourcery's built-in rules carry the built-in
tag.sourcery init
command in CLI - you can now use it to add
pre-commit
config, as well as view instructions to add Sourcery to CI.We continued improving the
Command Line Interface:
With the new --diff
option, you can now run Sourcery only for the code in your
current PR.
sourcery review --diff "git diff main" .
We had an issue with the release 0.12.10 This changelog contains the changes of both 0.12.10 and 0.12.11
sourcery review --diff="git diff HEAD" .
--config
contains
sourcery login
from CLI..sourcery.yaml
file present.invert-any-all
from inverting chains of comparisons like 0 <= value <= 255
. Fixes
Issue # 286test_*.py
and *_test.py
instead of the test.sourcery.yaml
file in the current
directory or any of its ancestors, rather than just the current directory..sourcery.yaml
match paths relative to the config file. This applies to
ignore
,
rules.paths.include
and rules.paths.exclude
This time around we've been hard at work in the background - making the Command Line Interface quicker and more responsive, and fixing some pesky issues.
Flag Hard-Coded Values
.sourcery.yaml
match paths relative to the config file. This applies to
ignore
, rules.paths.include
and rules.paths.exclude
for-append-to-extend
.
Fixes Issue # 279stderr
use-itertools-product
will now only trigger when we can infer that the types being iterated over are
finite sequences. This addresses
Issue #281snake-case-arguments
rule now correctly excludes argument separators
and "_"We've been hard at work on documenting all of the awesome things that you can do with our custom rules. We've reworked our documentation and written up how you can start enforcing the Google Python Style Guide in your team right now.
Our other notable improvement this time round is a new summary view when you run
the review
command using our
Command Line Interface.
review
command / overview: summary view.review
default output: 1 line per issue, with standard format links to
issue locations. You can use the --verbose
flag to get a detailed output
with each issue's description and diff.merge-isinstance
refactoring will now apply to chains of or
operators.review
command now validates that include
and exclude
rules
exist in either the core ruleset or the config file being used.Ellipsis
as ...
, fixing
Issue #273False
in an if
test
was followed by elif branchesset-comprehension
.
Fixes Issue #271.ignore
directories in the docssourcery init
: Use new syntax in the
no-print-statements
ruleWe've continued to make our custom rules more powerful!
This includes:
A new ...
syntax
for matching anything in a position. Say you want to write a rule that
matches any print
statement. You can now write pattern: print(...)
and
this will find all print statements with any number of positional or keyword
arguments.
Fully qualified name recognition.
Say you want to transform typing.List
into list
in line with
PEP 585. You can define the following
rule:
rules:
- id: convert-typing-list
pattern: typing.List
replacement: list
description: Use `list` rather than `typing.List`
This will find all occurrences of typing.List
and replace them with list
,
even if they have been imported using from typing import List
.
...
or nothing !!!
in patternsis_identifier
public condition to match variables that are valid identifiersstatement_count
custom rule condition - this lets you count how many
statements you matched.${target} = ${value}
will now match assignments such as i: int = 0
.os.path.join
will match join
if it is imported as
from os.path import join
(and all of the possible variations).pattern
name.pattern
from being used as a regular capture name.default-mutable-arg
if the arg name is shadowed in the default argument. e.g. def f(arg=[arg])
dict-assign-update-to-union
when the update accesses the dict variableremove-redundant-except-handler
for non-built-in exceptionsLast time we introduced custom rules into Sourcery.
This time they're becoming even more powerful as you can filter pattern matches with a condition.
Let's say we want to stop global variables being declared. First let's write down what a global variable is:
DAYS_IN_WEEK = 7
_
Here's a rule to identify global variables:
rules:
- id: no-global-variables
pattern: ${var} = ${value}
condition: |
var.in_module_scope()
and not var.is_upper_case()
and not var.starts_with("_")
description: Don't declare `${var}` as a global variable
Check out the conditions reference to see what conditions are available.
condition
field that means the rule only matches
when the condition is satisfieduse-file-iterator
refactoringreintroduce-else
will now trigger more oftenlist-literal
and dict-literal
will now trigger in every
instance of list()
and dict()
, instead of only in assignmentsreview
command instead of refactor
dict-assign-update-to-union
doesn't trigger for global variablesWe've focused on improving our documentation for custom rules. Check out these how-to guides:
--exclude
to exclude some rules for the commands review
and
refactor
--include
option has now been sped up, as it now runs only the proposers
necessary for the included proposals.explanation
in VSCode, PyCharm and the CLI for Sourcery custom rulesWe've added a walkthrough to our VS Code extension to make it easier to get started with Sourcery. Go to the Help > Get Started menu to check it out.
We've added two new refactorings for pandas
! These aim to improve performance
by streamlining apply
operations. If you have any feedback or more ideas for
rules you'd like to see in pandas
please
let us know!
Custom rules are now even more powerful!
sourcery init
command to produce a default .sourcery.yaml
configuration
filereplace-apply-with-method-call
refactoring for Pandas Series
and DataFrame
replace-apply-with-numpy-operation
refactoring for Pandas Series
and DataFrame
paths
that
they include
/exclude
from running ontests
in custom rule configuration.sourcery.yaml
file is now validated when it is opened in PyCharmversion
to config file and removed recommendation_level
from outputfor-index-replacement
could remove indices that were accessed later.sum-comprehension
:
Do not apply if the name sum
has already been used.remove-redundant-fstring
won't remove the content of multi-line fstrings.You can now build your own rules into Sourcery!
Are there issues that keep popping up in your projects, nuances around libraries you use, or feedback you want to make sure your whole team gets? Just create a Sourcery rule and we'll automatically find and fix those issues for you.
To get started, we've put together a tutorial for you to create your first rule.
And we've added a section to our docs with more details about what types of rules you can currently create.
Anyone can create up to 3 rules for free - or you can sign up for a Team plan to create unlimited rules.
function-quality
proposal in the Sourcery configuration file.avoid-builtin-shadow
no longer triggers for class variableshoist-similar-statement-from-if
to consider if-statements containing
elifs as different from each other (fixes issue
#241).sourcery.yaml
formatting and comments when updated from IDEsWe've been busy working under the hood on a new feature which we'll be unveiling soon! In the meantime we have:
# sourcery skip: low-code-quality
comment. It can now also be completely
switched off by adding low-code-quality
to the skip
section in the
Sourcery configuration file. This
does mean that existing # sourcery no-metrics
comments must be changed into
the skip
format as above.convert-to-enumerate
in async for loopsmerge-duplicate-blocks
will no longer duplicate conditions that may have side-effectsremove-assert-true
refactoringtoken
and missing ruleType
settings which
resolves issues in Vimequality-identity
from triggering with float or complex numbers since NaN == NaN
is falsehoist-statement-from-loop
from triggering when the assignment value writes variablesuse-fstring-for-concatenation
now keeps the correct string quote for both sides of the concatenationinstance-method-first-arg-name
from firing for built-in class methods __new__
, __init_subclass__
, and
__class_getitem__
, which instead will trigger
class-method-first-arg-name
.use-fstring-for-concatenation
to trigger on long lines if this results in shorter lines (fixes issue
#222)request_review
: Fix so that a single value can be used again.The Sourcery CLI now
includes a review
command. Use this to get Sourcery to give suggestions and
comments in addition to standard refactorings. Commented lines will be
highlighted in red.
break-or-continue-outside-loop
refactoring
class-method-first-arg-name
refactoring
collection-to-bool
refactoring
compare-via-equals
suggestion
dict-assign-update-to-union
refactoring
do-no-use-bare-except
suggestion
hoist-repeated-if-condition
refactoring
simplify-single-exception-tuple
refactoring
remove-redundant-boolean
refactoring
remove-redundant-constructor-in-dict-union
refactoring
remove-redundant-exception
refactoring
return-or-yield-outside-function
refactoring
use-getitem-for-re-match-groups
refactoring
use-dictionary-union
refactoring
while-guard-to-condition
refactoring
Add removal of bools to
remove-unnecessary-cast
The remove-duplicate-key refactoring was split into a refactoring
remove-duplicate-set-key
and a suggestion
remove-duplicate-dict-key
remove-duplicate-dict-key
was enhanced to handle unpacked dictionaries
remove-duplicate-dict-key
and
remove-duplicate-set-key
were enhanced to refactor dicts and sets in any context (previously they were
only applied in assignments).
simplify-len-comparison
will now also simplify len(s) < 0 as False and len(s) >= 0 as True
raise-specific-error
will now also cover raising BaseException and raising from other exceptions
Comments will now show on the correct line where there are functions with docstrings. Addresses issue #211
F-strings containing escaped characters will not be refactored into constant strings. Addresses issue #213.
str-prefix-suffix
now triggers in the correct way for applying endswith
use-assigned-var
:
Do not apply if the variable is overwritten in a loop
use-itertools-product
will now combine nested products. Fixes
issue #214.
We now assume any
and all
write to their arguments, since they exhaust
iterators. This fixes
issue #210
Comments: Sourcery will now spot issues in your code that don't have an
automated code fix. Instead we will give a detailed explanation of the issue
along with a guide on how to fix them. Just hover for more info. The first
comment that we have introduced is
raise-specific-error
- here we can identify that a base Exception
is being raised (and explain
how it is better to raise a specific exception), but we can't automatically
detect which exception should be raised in this case.
There is now a new config option to specify which rule types to display in the plugins - you can choose to any combination of refactorings, suggestions and comments.
Sourcery refactorings can now add imports where necessary. This means that we
can suggest using standard library functions such as contextlib.suppress
.
aware-datetime-for-utc
suggestion
remove-unnecessary-cast
refactoring
replace-interpolation-with-fstring
refactoring
swap-if-expression
refactoring
use-contextlib-suppress
refactoring
use-fstring-for-formatting
refactoring
use-itertools-product
refactoring
use-or-for-fallback
refactoring
avoid-builtin-shadow
comment
unwrap-iterable-construction
refactoring
path-read
will now
suggest importing pathlib
if it is not already imported.raise-from-previous-error
where raise e from e
was suggested.path-read
and
aware-datetime-for-utc
that caused them to never be triggeredremove-redundant-fstring
:
Do not trigger if the f-string contains escaped curly bracesuse-datetime-now-not-today
refactoringremove-str-from-fstring
refactoring (split out from
simplify-fstring-formatting
)--include
option to
command-line interface and
config files. This allows you to specify Sourcery to only apply certain
refactoring rules.simplify-fstring-formatting
will no longer remove calls to str
in formatted values. This is not valid
for classes which override __repr__
.use-named-expression
will now only trigger where the variable being assigned to is used in the body
of the if
chain-compares
will
now trigger when comparing to constants, and will avoid mixing different types
of comparisonremove-str-from-print
refactoring to deal with multiple argumentsuse-next
refactoring when statements have side-effectsfor-append-to-extend
refactoring with tuple loop variablesuse-any
refactoringuseless-else-on-loop
when there is a break
in an inner loop's elsedefault-get
doesnt trigger where the default has side effectschain-compares
refactoringmax-min-default
refactoringremove-dict-items
refactoringremove-redundant-condition
refactoringuse-string-remove-affix
refactoringuse-fstring-for-concatenation
refactoringskip-sorted-list-construction
refactoringmissing-dict-items
suggestionuse-next
refactoringfor-append-to-extend
refactoringmerge-list-appends-into-extend
refactoringraise-from-previous-error
suggestionuse-named-expression
refactoring so that it also triggers on appropriate while loops.remove-redundant-slice-index
extended to cover steps and removal of end indexcomprehension-to-generator
use-fstring-for-concatenation
Toggle Sourcery Recommendation Level
, and through a toggle button in the
Sourcery panel in PyCharm. The toggle can also be made directly in the user
configuration file.default-mutable-arg
suggestion - this is the first suggestion, and triggers when you use a
dictionary, set or list as a default argument to a function.simplify-empty-collection-comparison
proposalnon-equal-comparison
proposaluse-named-expression
proposalpath-read
proposalmerge-nested-ifs
will no longer trigger if either condition contains a named
expression.for-index-underscore
will now also trigger on comprehensions and generators.remove-unused-enumerate
to handle comprehensionsuse-any
and comprehension proposers will no longer incorrectly suggest
incorporating code containing named expressions.square-identity
introduce-default-else
proposalmove-assign-in-block
proposalswitch
refactoringreplace-dict-items-with-values
suggestions for unstructured keys -
https://github.com/sourcery-ai/sourcery/issues/181use-any
, dict-literal
and list-literal
proposals will now trigger where
there is an annotation present.return-identity
proposal as now superceded.You can now use Sourcery straight away on installation, with no need to create an account or enter a token. This gives you access to our Free tier. To try out our Pro features you can create an account to get a 30 day free trial.
equality-identity
Simplify equality comparisons that are always True
or False
if 1 == 1:
always_do_this()
if 1 != 1:
never_do_this()
if True:
always_do_this()
if False:
never_do_this()
When comparing a value to itself, the outcome will always be True
, as long as
the equality operator has not been overridden, and this also holds for the
opposite comparison and False
. It is more readable to use a direct comparison
to the boolean value.
identity-comprehension
Convert list/set/tuple comprehensions that do not change the input elements into
# List comprehensions
[item for item in coll]
[item for item in friends.names()]
# Dict comprehensions
{k: v for k, v in coll}
{k: v for k, v in coll.items()} # Only if we know coll is a `dict`
# Unneeded call to `.items()`
dict(coll.items()) # Only if we know coll is a `dict`
# Set comprehensions
{item for item in coll}
# List comprehensions
list(iter(coll))
list(iter(friends.names()))
# Dict comprehensions
dict(coll)
dict(coll)
# Unneeded call to `.items()`
dict(coll)
# Set comprehensions
set(coll)
All these comprehensions are just creating a copy of the original collection. They can all be simplified by simply constructing a new collection directly. The resulting code is easier to read and shows the intent more clearly.
merge-assign-and-aug-assign
Replaces an assignment and an augmented assignment with a single assignment.
other_value = 33
number = 42
number += other_value
other_value = 33
number = 42 + other_value
When we mutate a variable multiple times without reading or writing its value in between, it's more readable and more efficient to change its value only once. This way, it's clearer which values this variable can have at various points.
This refactoring works with all 4 augmented assignment operators:
+=
-=
*=
/=
remove-str-from-print
Removes unnecessary calls to str()
from within print()
print(str(1))
print(1)
Objects passed into calls to the print()
function already have str()
called
on them, so it is not required to do so yourself.
simplify-division
Use Python's built-in feature for succinct division syntax.
result = int(42 / 10)
result = 42 // 10
result = 42 // 10
remainder = 42 % 10
result, remainder = divmod(42, 10)
Python has some great features to simplify division expressions. If you're
interested only in the whole number component of the quotient, you can use the
//
integer division operator. If you want to have the whole number component
and the remainder in separate variables, the built-in divmod
function comes
handy.
simplify-substring-search
Simplify finding if substrings are present in strings by using in
my_str = "Hello world"
if my_str.find("ello") == -1:
print("Not Found!")
my_str = "Hello world"
if "ello" not in my_str:
print("Not Found!")
my_str = "Hello world"
if my_str.count("ello") > 0:
print("Found!")
my_str = "Hello world"
if "ello" in my_str:
print("Found!")
Making use of Python's in
operator for detecting if a substring is present in
a string is more readable than using the find
or count
methods, and is also
suggested in the
documentation. These
methods are more suitable for cases where you need more information about the
substring's location or the number of times it appears.
if
conditions with named expresssions could
change behaviour due to missing brackets.hoist-if-from-if
proposal from hoisting ifs that would then be
incorrectly enteredremove-redundant-slice-index
Removes unnecessary explicit 0
when slicing the beginning of a sequence.
With an end index:
numbers[0:5]
Without an end index:
numbers[0:]
With an end index:
numbers[:5]
Without an end index:
numbers[:]
The default starting value for a slice is 0, so it is unnecessary to explicitly define it. This refactoring removes such zeros, slightly shortening the code.
remove-unused-enumerate
Remove unnecessary calls to
enumerate
when
the index variable is not used.
for index, hat in enumerate(hats):
print("I like this hat: ", hat)
for i, (key, value) in enumerate(my_dictionary.items(), start=100):
do_something(key)
do_something_else(value)
for hat in hats:
print("I like this hat: ", hat)
for key, value in my_dictionary.items():
do_something(key)
do_something_else(value)
Enumerating iterables with
enumerate
is a
good practice for having access to both the values and their respective indices.
However, when the indices are not necessary, it is cleaner to simply iterate
over the original iterable and remove the call to enumerate
.
simplify-string-len-comparison
Changes an indirect comparison of a string's length to 0
into a direct
comparison of the string to the empty string.
if len(s) == 0:
...
if len(r) > 0:
...
if s == "":
...
if r != "":
...
This refactoring avoids an unnecessary calculation and keeps the logic in the domain of string types. It tends to unlock further improvements to string comparisons.
useless-else-on-loop
Moves code in else
blocks that is always executed to the main body
evens = []
for n in numbers:
if n % 2:
evens.append(n)
else:
print("Done!")
evens = []
for n in numbers:
if n % 2:
evens.append(n)
print("Done!")
Loops should only have an else
clause if they can exit early with a break
statement. If there is no break
then the code in the else
is always
executed. In this case the else
statements can be moved to the same scope as
the loop itself, making the code slightly easier to understand (no need to look
up what the else
does).
simplify-len-comparison
proposal has been extended to cover cases such
as len(seq) != 0
remove-redundant-if
was incorrectly suggested in situations
with nested changes to condition variablesuse-any
could be incorrectly suggested in cases where the
for
loop being replaced unpacked and used multiple variablesremove-empty-nested-block
Remove nested block which has no effect
for i in range(3):
pass
Here the code has been removed:
An if
or for
which is empty and has no effect should not be present in the
code. It clutters things up and makes it harder to see what the code is really
doing.
simplify-dictionary-update
Add single value to dictionary directly rather than using update()
def foo(d: dict) -> None:
d.update({"request": HttpRequest()})
frobnicate(d)
def foo(d: dict) -> None:
d["request"] = HttpRequest()
frobnicate(d)
When we are just adding one entry to a dictionary it is simpler to do it
directly rather than via the update()
method. This also eliminates the
overhead of constructing another dictionary and calling a method, so should
slightly improve performance.
str.join
remove-redundant-if
if global
state had changed.de-morgan
inequality refactoring to numerical typesuse-count
refactoring to only apply on lists and strings
You can now sign up on the website to get access to Sourcery's beta updates. Just log in, go to your profile page and check the box under the 'Nightly builds' heading.
This will let you try out our latest refactorings and fixes the day they become available, rather than waiting for our plugin releases. Each morning when a build is available it will get automatically downloaded, then will prompt you to restart your IDE to get the new features.
remove-redundant-fstring
Replace f-string with no interpolated values with string.
description = f"This is a totally normal string"
description = "This is a totally normal string"
This refactoring spots cases where use of an f-string is unnecessary since there
are no interpolated values. It's easy to forget to remove the f
if you have
such a value and then remove it later.
simplify-fstring-formatting
Simplify unnecessary nesting, casting and constant values in f-strings
description = f'This {1} thing is {f"{str(adjective)}"}'
description = f"This 1 thing is {adjective}"
When writing an f-string it is not necessary to interpolate the values of constants or cast variables to strings - these will be done automatically. It is also not necessary to nest f-strings when adding the contents of the nested string directly achieves the same result.
ternary-to-if-expression
Replace boolean ternary with inline if expression
protocol_type = uses_ssl() and "https" or "http"
protocol_type = "https" if uses_ssl() else "http"
In some cases, especially in old codebases that were written in Python 2, boolean expressions are used as ternary operators. However, replacing boolean ternary expressions with inline ifs where appropriate better portrays the code's intention and therefore makes it easier for others to read it.
# TODO Rename this here and in [first_usage] and [second_usage]
assign-if-exp
to cover the case where the default value is assigned
firstBefore:
x = 2
if condition:
x = 1
After:
x = 1 if condition else 2
default-get
refactorings now work for if expressionsuse-any
will no longer trigger if it introduces a short-circuit where global
state is writtenmerge-repeated-if
will no longer trigger if the first if
writes global
state that could affect the seconduse-any
will no longer trigger if the for loop target is used later on
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
It is now possible to configure the detect clones functionality for finding duplicate code.
This configuration must be added at the project level in the .sourcery.yaml
file, under the clone_detection
heading. See
here for more details on the Sourcery
configuration file.
min_lines
: The minimum number of lines each code section must have to be
picked up. The minimum value for this is 3.min_duplicates
: The minimum number of duplicate code sections there must be.
The minimum value for this is 2.identical_clones_only
: When this is set only exactly identical sections of
duplicate code will be picked up.clone_detection:
min_lines: 3
min_duplicates: 2
identical_clones_only: false
The working memory metric will now only consider the most complex element within collections or call arguments, rather than incrementing for each element.
This means that when declaring a list like this one:
hats = ["BOWLER", "TOP" + "HAT", "TRILBY"]
The working memory for this statement will now be 3 (incrementing for hats
,
TOP
and HAT
) whereas before it would have been 5. This will prevent the
phenomenon where creating dictionaries, lists or data classes would give
functions unreasonably high working memory scores. For a full discussion of the
working memory metric see our blog post
here.
swap-variable
Swap variable values with tuple assignment
temp = a
a = b
b = temp
a, b = b, a
When trying to swap the values held by two variables, we may avoid using an extra temporary variable unnecessarily by employing Python's tuple assignment. As a consequence of this refactoring, the code is not only more concise but also reflects its intention more clearly.
merge-else-if-into-elif
Merge else clause's nested if statement into elif
def interpret_response(response):
if response.status == "200":
return response.data
else:
if response.status == "404":
return "Not Found"
else:
return "Error"
def interpret_response(response):
if response.status == "200":
return response.data
elif response.status == "404":
return "Not Found"
else:
return "Error"
Flattening if statements nested within else clauses generates code that is easier to read and expand upon.
inline-variable
Inline variable that is only used once
thelist = []
for i in range(10):
k = i**2
thelist.append(k)
thelist = []
for i in range(10):
thelist.append(i**2)
Inlining variable can help to streamline the code, but can also make it less readable. Sourcery will only inline variables where doing so allows further readability changes to be made, such as converting a loop into a list comprehension.
remove-redundant-continue
Remove redundant continue
statement
mylist2 = []
for i in mylist:
if i != 2:
mylist2.append(i)
else:
continue
mylist2 = []
for i in mylist:
if i != 2:
mylist2.append(i)
If a continue
is not followed by any other statements in a for
or while
loop then it is not necessary, so can be removed. Removing unnecessary lines
declutters the code and makes it easier to understand. This refactoring will
only be triggered if it unlocks further improvements.
reintroduce-else
Lift code into else
after break in control flow
summer_hats = []
for hat in hats:
if hat in WINTER_HATS:
continue
summer_hats.append(hat)
summer_hats = []
for hat in hats:
if hat in WINTER_HATS:
continue
else:
summer_hats.append(hat)
Where the body of an if
statement ends with a break in the control flow, such
as a continue
, return
or raise
, the subsequent statements can be lifted
into the else
clause. On its own this change does not improve the code, so
Sourcery will only suggest it where it unlocks furher improvements. In the
example above once the code has been lifted into the else
the conditional can
be inverted and the continue
removed, which then lets the for
loop be
converted into a list comprehension.
remove-duplicate-key
Remove duplicate keys in declaration of sets and dicts
addresses = {*address_list1, *address_list2, *address_list1}
addresses = {*address_list2, *address_list1}
Keys of Sets and Dictionaries must be unique. Hence, repeated keys are redundant and can be removed from the declaration to increase the conciseness and clarity of the code.
For dictionaries that have repeated keys with differing values (i.e.
{key1: 'some_value', key1: 'another_value'}
), Sourcery will only remove the
key-value pairs that would be removed at run time.
flatten-nested-try
Merge nested try-statement into a single try
def testConnection(db, credentials):
try:
try:
db.connect(credentials)
except InvalidCredentials:
return "Check your credentials"
except ConnectionError:
return "Error while trying to connect"
finally:
print("Connection attempt finished")
return "Connection Successful"
def testConnection(db, credentials):
try:
db.connect(credentials)
except InvalidCredentials:
return "Check your credentials"
except ConnectionError:
return "Error while trying to connect"
finally:
print("Connection attempt finished")
return "Connection Successful"
Flattening try-except statements nested within a try-finally generates equivalent code that is easier to read and expand upon.
collection-into-set
Use set when checking membership of a collection of literals
if currency in ["EUR", "USD"]:
take_payment()
if currency in {"EUR", "USD"}:
take_payment()
When checking if a variable is one of a collection of literals it is both more
natural and more performant to use a set
rather than a list
or tuple
to
define that collection. Note that this can only be done where Sourcery can
ascertain that the value being checked is of a hashable type.
bytes
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
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:
The metrics are now enabled by default both in VSCode and PyCharm.
The config option metrics.enabled
has been removed.
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.