Refurb

Latest version: v2.0.0

Safety actively analyzes 624093 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 1 of 6

2.0.0

This new release greatly improves the type checking capabilities of Refurb. You might find that you are getting a lot more errors in your projects, as well as a few false positives. Please report any incorrect changes you might find!

Add better type deduction

Refurb now makes better use of Mypy's type deduction system, allowing Refurb to find more errors and with better accuracy.

For example, the following is not detected in older versions of Refurb:

python
nums = [[]]

if len(nums[0]):
print("nums[0] is not empty")


With this new version of Refurb, the type of `nums[0]` is inferred as a `list`:


$ refurb file.py
file.py:3:4 [FURB115]: Replace `len(nums[0])` with `nums[0]`


While this new type deduction is a great improvement on what existed before, there is still a lot of room for improvement. If you find any typing related bugs, please report it!

Add `use-isinstance-bool` check (FURB191)

Don't check if a value is `True` or `False` using `in`, use an `isinstance()` call.

Bad:

python
if value in {True, False}:
pass


Good:

python
if isinstance(value, bool):
pass


Add `use-str-method` check (FURB190)

Don't use a lambda function to call a no-arg method on a string, use the name of the string method directly. It is faster, and often times improves readability.

Bad:

python
def normalize_phone_number(phone_number: str) -> int:
digits = filter(lambda x: x.isdigit(), phone_number)

return int("".join(digits))


Good:

python
def normalize_phone_number(phone_number: str) -> int:
digits = filter(str.isdigit, phone_number)

return int("".join(digits))


Add `no-subclass-builtin` check (FURB189)

> Note: this check is disabled by default, see below.

Subclassing `dict`, `list`, or `str` objects can be error prone, use the `UserDict`, `UserList`, and `UserStr` objects from the `collections` module instead.

Bad:

python
class CaseInsensitiveDict(dict):
...


Good:

python
from collections import UserDict

class CaseInsensitiveDict(UserDict):
...


Note: `isinstance()` checks for `dict`, `list`, and `str` types will fail when using the corresponding User class. If you need to pass custom `dict` or `list` objects to code you don't control, ignore this check. If you do control the code, consider using the following type checks instead:

* `dict` -> `collections.abc.MutableMapping`
* `list` -> `collections.abc.MutableSequence`
* `str` -> No such conversion exists

Rename `no-del` to `use-clear` (FURB131)

Read dbe31262aa873690724b6c01db704228fe48f9e2 for more info. In short, FURB131 will now detect both of the following snippets:

python
nums = [[1, 2, 3], [4, 5, 6]]

nums[0][:] = []
del nums[0][:]


Running Refurb:


$ refurb file.py
file.py:3:1 [FURB131]: Replace `nums[0][:] = []` with `nums[0].clear()`
file.py:4:1 [FURB131]: Replace `del nums[0][:]` with `nums[0].clear()`


What's Changed
* Add `no-subclass-builtin` check by dosisod in https://github.com/dosisod/refurb/pull/324
* Add better detection and error messages for len compatible types in FURB115 by dosisod in https://github.com/dosisod/refurb/pull/331

**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.28.0...v2.0.0

1.28.0

This release adds improved error messages, more suggestions for existing checks, and 2 brand new checks!

Add `remove-prefix-or-suffix` check (FURB188)

Don't explicitly check a string prefix/suffix if you're only going to remove it, use `.removeprefix()` or `.removesuffix()` instead.

Bad:

python
def strip_txt_extension(filename: str) -> str:
return filename[:-4] if filename.endswith(".txt") else filename


Good:

python
def strip_txt_extension(filename: str) -> str:
return filename.removesuffix(".txt")


Add `use-reverse` check (FURB187)

Don't use `x[::-1]` or `reversed(x)` to reverse a list and reassign it to itself, use the faster in-place `.reverse()` method instead.

Bad:

python
names = ["Bob", "Alice", "Charlie"]

names = reversed(names)
or
names = list(reversed(names))
or
names = names[::-1]


Good:

python
names = ["Bob", "Alice", "Charlie"]

names.reverse()


Detect `itemgetter()` in FURB118 (`use-operator`)

The `operator.itemgetter()` function can be used to get one or more items from an object, removing the need to create a lambda just to extract values from an object:

Bad:

python
row = (1, "Some text", True)

transform = lambda x: (x[2], x[0])


Good:

python
from operator import itemgetter

row = (1, "Some text", True)

transform = itemgetter(2, 0)


Detect no-arg lambdas returning default literals in FURB111 (`use-func-name`)

Don't use lambdas when you want a default value for a literal type:

Bad:

python
counter = defaultdict(lambda: 0)
multimap = defaultdict(lambda: [])


Good:

python
counter = defaultdict(int)
multimap = defaultdict(list)


**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.27.0...v1.28.0

1.27.0

This release adds 2 new checks and adds improved detection and error messages for a few other checks!

Add `no-copy-with-merge` Check (FURB185)

You don't need to call `.copy()` on a dict/set when using it in a union since the original dict/set is not modified.

Bad:

python
d = {"a": 1}

merged = d.copy() | {"b": 2}


Good:

python
d = {"a": 1}

merged = d | {"b": 2}


Add `use-sort` Check (FURB186)

Don't use `sorted()` to sort a list and reassign it to itself, use the faster in-place `.sort()` method instead.

Bad:

python
names = ["Bob", "Alice", "Charlie"]

names = sorted(names)


Good:

python
names = ["Bob", "Alice", "Charlie"]

names.sort()


Color is now disabled when piping output

Previously Refurb would always emit color unless you turned it off. Now it will check if the output is a TTY, and if so, disable the color.

Improve `use-chain-from-iterable` (FURB179)

FURB179 now detects the following snippets:

python
functools.reduce(operator.add, rows)
functools.reduce(operator.add, rows, [])
functools.reduce(operator.concat, rows)
functools.reduce(operator.concat, rows, [])


These snippets are slow because they use the `add`/`concat` operator. This will create a new list for each iteration instead of doing it in-place.

Improve `use-dict-union` (FURB173)

FURB173 now detects the following snippets:

python
_ = dict(**x)
_ = dict(x, **y)
_ = dict(**x, **y)
_ = dict(x, a=1)
_ = dict(**x, a=1, b=2)
_ = dict(**x, **y, a=1, b=2)


These can be re-written using dictionary unions:

python
_ = {**x}
_ = x | y
_ = x | y
_ = x | {"a": 1}
_ = x | {"a": 1, "b": 2}
_ = x | y | {"a": 1, "b": 2}

1.26.0

This release adds one new check and a bunch of bug fixes!

Add `use-fluent-interface` (FURB184)

When an API has a Fluent Interface (the ability to chain multiple calls together), you should chain those calls instead of repeatedly assigning and using the value. Sometimes a return statement can be written more succinctly:

Bad:

python
def get_tensors(device: str) -> torch.Tensor:
t1 = torch.ones(2, 1)
t2 = t1.long()
t3 = t2.to(device)
return t3

def process(file_name: str):
common_columns = ["col1_renamed", "col2_renamed", "custom_col"]
df = spark.read.parquet(file_name)
df = df \
.withColumnRenamed('col1', 'col1_renamed') \
.withColumnRenamed('col2', 'col2_renamed')
df = df \
.select(common_columns) \
.withColumn('service_type', F.lit('green'))
return df


Good:

python
def get_tensors(device: str) -> torch.Tensor:
t3 = (
torch.ones(2, 1)
.long()
.to(device)
)
return t3

def process(file_name: str):
common_columns = ["col1_renamed", "col2_renamed", "custom_col"]
df = (
spark.read.parquet(file_name)
.withColumnRenamed('col1', 'col1_renamed')
.withColumnRenamed('col2', 'col2_renamed')
.select(common_columns)
.withColumn('service_type', F.lit('green'))
)
return df


Thank you to sbrugman for implementing this new check!

What's Changed
* Fix FURB183 false positive when using custom formatter by dosisod in https://github.com/dosisod/refurb/pull/315
* Fix FURB118 `operator.contains` false positive, improve error messages by dosisod in https://github.com/dosisod/refurb/pull/317
* Initial implementation for fluid interface check by sbrugman in https://github.com/dosisod/refurb/pull/287
* Fix: false negative in FURB111 by sbrugman in https://github.com/dosisod/refurb/pull/313
* Fix FURB115 being emitted when using `len(x)` with non-boolean operators by dosisod in https://github.com/dosisod/refurb/pull/319

New Contributors
* sbrugman made their first contribution in https://github.com/dosisod/refurb/pull/287

**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.25.0...v1.26.0

1.25.0

This release adds colorized output to Refurb, as well as some bugfixes!

![image](https://github.com/dosisod/refurb/assets/39638017/1fa75635-d25d-4822-9f19-0f037eac4945)

Color output is enabled by default. If you don't like it you can disable it using any of the following methods:

* Use the `--no-color` CLI arg
* Use `color = false` in the config file
* Set the `NO_COLOR` env var

What's Changed
* Don't emit FURB135/FURB148 when using `_` in comprehensions by dosisod in https://github.com/dosisod/refurb/pull/312

**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.24.0...v1.25.0

1.24.0

This release adds 2 new checks, some documentation updates, and allows for using Refurb with the new 1.7.0 release of Mypy. Thank you bzoracler for fixing this!

Page 1 of 6

© 2024 Safety CLI Cybersecurity Inc. All Rights Reserved.