Refurb

Latest version: v2.0.0

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

Scan your dependencies

Page 4 of 6

1.13.0

This check includes a few bug fixes, as well as many new checks!

The `--python-version` setting defaults to currently installed version now

Previously Refurb would be completely unaware of what version of Python you where checking unless you set the `--python-version 3.x` flag. Now, unless you override it with that flag, Refurb will default to whatever the currently installed version of Python on your machine is.

Add `simplify-strip` check (FURB159)

In some situations the `.lstrip()`, `.rstrip()` and `.strip()` string methods can be written more succinctly: `strip()` is the same thing as calling both `lstrip()` and `rstrip()` together, and all the strip functions take an iterable argument of the characters to strip, meaning you don't need to call a strip function multiple times with different arguments, you can just concatenate them and call it once.

Bad:

python
name = input().lstrip().rstrip()

num = " -123".lstrip(" ").lstrip("-")


Good:

python
name = input().strip()

num = " -123".lstrip(" -")


Add `no-redundant-assignment` check (FURB160)

Sometimes when you are debugging (or copy-pasting code) you will end up with a variable that is assigning itself to itself. These lines can be removed.

Bad:

python
name = input("What is your name? ")
name = name


Good:

python
name = input("What is your name? ")


Add `use-bit-count` check (FURB161)

Python 3.10 adds a very helpful `bit_count()` function for integers which counts the number of set bits. This new function is more descriptive and faster compared to converting/counting characters in a string.

Bad:

python
x = bin(0b1010).count("1")

assert x == 2


Good:

python
x = 0b1010.bit_count()

assert x == 2


Add `simplify-fromisoformat` check (FURB162)

Python 3.11 adds support for parsing UTC timestamps that end with `Z`, thus removing the need to strip and append the `+00:00` timezone.

Bad:

python
date = "2023-02-21T02:23:15Z"

start_date = datetime.fromisoformat(date.replace("Z", "+00:00"))


Good:

python
date = "2023-02-21T02:23:15Z"

start_date = datetime.fromisoformat(date)


What's Changed
* Add `simplify-strip` check by dosisod in https://github.com/dosisod/refurb/pull/202
* Add more flake8 plugins by dosisod in https://github.com/dosisod/refurb/pull/204
* Add `no-redundant-assignment` check by dosisod in https://github.com/dosisod/refurb/pull/205
* Add `use-bit-count` check by dosisod in https://github.com/dosisod/refurb/pull/208
* Emit error for empty string in `Path()` constructor by dosisod in https://github.com/dosisod/refurb/pull/209
* Add `simplify-fromisoformat` check by dosisod in https://github.com/dosisod/refurb/pull/210
* Set `python_version` to currently installed Python version by dosisod in https://github.com/dosisod/refurb/pull/211
* Replace `flake8` with `ruff`, bump version by dosisod in https://github.com/dosisod/refurb/pull/212


**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.12.0...v1.13.0

1.12.0

Important Mypy Update Info

This is the 3rd release in the past 3 days, sorry for the spam! This version is pretty important though, since it removes the version cap on Mypy: They just released [Mypy version 1.0](https://mypy-lang.blogspot.com/2023/02/mypy-10-released.html) a few days ago, the same day that v1.11.1 (the lastest version) of Refurb came out. Since a lot of people will be upgrading Mypy in the coming days, it is important to remove this cap so that people don't get version conflicts. Now that Mypy has reached 1.0, a "stable" release, there should be less of a concern when it comes to spontaneous breakage.

With that in mind, this newest version does include one new check!

Add `simplify-as-pattern-with-builtin` check (FURB158)

This check looks for instances where builtin types such as `int()`, `float()`, etc. are used in `as` patterns (such as `int() as x`). Although this is totally valid, it can be more succinctly written as `int(x)`.

Here is what that looks like side-by-side:

python
match data:
case str() as name:
print(f"Hello {name}")


Compare that to the simpler version:

python
match data:
case str(name):
print(f"Hello {name}")


**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.11.1...v1.12.0

1.11.1

This minor version fixes a typo in FURB156 (`use-string-charsets`) which incorrectly said to use the `strings` module instead of the `string` module.

What's Changed
* Fix typo in FURB156 by bbkgh in https://github.com/dosisod/refurb/pull/197

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

**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.11.0...v1.11.1

1.11.0

This version includes a couple of new checks, including a new check from first-time contributor doomedraven!

Add `simplify-global-and-nonlocal` check (FURB154)

The `global` and `nonlocal` statements can take multiple variables, meaning you don't need to have a separate line for each variable:

python
def f():
nonlocal x
nonlocal y

...


The above code can be written like this instead:

python
def f():
nonlocal x, y

...


Add `use-pathlib-stat` check (FURB155)

This check suggests that you use the [`pathlib`](https://docs.python.org/3/library/pathlib.html) module for doing `stat()` file operations, such as getting the file size, date modified, etc.

For example, the following code:

python
if os.path.getsize("file.txt"):
pass


Can be written like this:

python
if Path("file.txt").stat().st_size:
pass


Add `use-string-charsets` check (FURB156)

The [`string`](https://docs.python.org/3/library/string.html) library offers some common charsets such as digits, upper/lower case alpha characters, and more. This improves readability, and cuts down on line length as well.

For example:

python
digits = "0123456789"

if c in digits:
pass

if c in "0123456789abcdefABCDEF":
pass


The above code can be written like this using the `string` module:

python
if c in string.digits:
pass

if c in string.hexdigits:
pass


Add `simplify-decimal-ctor` check (FURB157)

The `Decimal()` constructor can take many different types such as `str`, `int`, and `float`. Often times you can simplify the construction of `Decimal` objects, especially when using plain literals such as `"0"`.

python
if x == Decimal("0"):
pass

if y == Decimal(float("Infinity")):
pass


Good:

python
if x == Decimal(0):
pass

if y == Decimal("Infinity"):
pass


What's Changed
* Add more info to the explaination output by dosisod in https://github.com/dosisod/refurb/pull/185
* Add "simplify-global-and-nonlocal" check by dosisod in https://github.com/dosisod/refurb/pull/186
* Fix FURB123 (no-redundant-cast) suggesting to use `.copy()` for literals by dosisod in https://github.com/dosisod/refurb/pull/188
* replace os.path.getsize with Path("file.txt").stat().st_size by doomedraven in https://github.com/dosisod/refurb/pull/189
* Add `normalize_os_path` helper function by dosisod in https://github.com/dosisod/refurb/pull/193
* Add `use-string-charsets` check by dosisod in https://github.com/dosisod/refurb/pull/194
* Add `simplify-decimal-ctor` check by dosisod in https://github.com/dosisod/refurb/pull/195
* Bump packages, bump version to 1.11.0 by dosisod in https://github.com/dosisod/refurb/pull/196

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

**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.10.0...v1.11.0

1.10.0

Add ability to ignore checks on a per-file/folder basis

You can now ignore errors for a given path! Just add the following to your `pyproject.toml`:

toml
[[tool.refurb.amend]]
path = "your/path/here" <-- can be a file or folder
ignore = ["FURB123"]


Read [the docs](https://github.com/dosisod/refurb#ignore-checks-per-filefolder) for more info on how to use this new feature!

Add `use-pathlib-mkdir` check (FURB150)

Use the `mkdir` function from the `pathlib` library instead of using the `mkdir` and `makedirs` functions from the `os` library.

The following code:

python
import os

os.mkdir("new_folder")


Can be written like:

python
from pathlib import Path

Path("new_folder").mkdir()


Add `use-pathlib-touch` check (FURB151)

Don't use `open(x, "w").close()` if you just want to create an empty file, use the less confusing `Path.touch()` method instead.

<details>
<summary>Note that this check is disabled by default (expand this for a full explanation).</summary>
<br>
This check is disabled by default because `touch()` will throw a `FileExistsError` if the file already exists, and (at least on Linux) it sets different file permissions, meaning it is not a drop-in replacement. If you don't care about the file permissions or know that the file doesn't exist beforehand this check may be for you.
</details>

For example, this code:

python
open("file.txt", "w").close()


Can be written like this:

python
from pathlib import Path

Path("file.txt").touch()


Add `use-math-constant` check (FURB152)

Don't hardcode math constants like pi, tau, or e, use the `math.pi`, `math.tau`, or `math.e` constants respectively instead.

For example, this code:

python
def area(r: float) -> float:
return 3.1415 * r * r


Should be written like this:

python
import math

def area(r: float) -> float:
return math.pi * r * r


Add `simplify-path-constructor` check (FURB153)

The `Path()` constructor defaults to the current directory, so don't pass the current directory (`"."`) explicitly.

This:

python
file = Path(".")


Can be written like this:

python
file = Path()


Add names to checks

All checks now contain a `name` field which makes them easier to refer to. Although the name isn't actually used for anything, you will eventually be able to use the name field as a replacement for `FURBxxx` on the CLI, in config files, and in `noqa` comments. In addition, the name (along with the categories) will be printed at the top of the "explainer" for the check when using `--explain`.

What's Changed
* Add `--namespace-packages` flag to mypy by dosisod in https://github.com/dosisod/refurb/pull/170
* Add ability to parse path expressions resulting from `/` operator by dosisod in https://github.com/dosisod/refurb/pull/171
* Add "pathlib touch" check by dosisod in https://github.com/dosisod/refurb/pull/172
* Add missing categories to checks by dosisod in https://github.com/dosisod/refurb/pull/175
* Add "no math constants" check by dosisod in https://github.com/dosisod/refurb/pull/176
* Add "no explicit cwd" check by dosisod in https://github.com/dosisod/refurb/pull/178
* Add `name` field to checks by dosisod in https://github.com/dosisod/refurb/pull/179
* Add ability to ignore errors on a per file/folder basis by dosisod in https://github.com/dosisod/refurb/pull/183
* Fix integers not working in amend sections, bump packages by dosisod in https://github.com/dosisod/refurb/pull/184


**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.9.1...v1.10.0

1.9.1

This release contains a couple bug fixes:

Folders without an `__init__.py` or `py.typed` file no longer cause errors

Mypy requires an `__init__.py` file to tell it where the root of the project is, which can cause issues if your project doesn't have any of these files. A flag has been added when calling Mypy which fixes this.

Fix "list extend" (FURB113) false positive

Previously this check did not ensure that the `.append()` function was called on a `list`, meaning the following code would cause an error:

python
class Queue:
_queue: list

def __init__(self) -> None:
self._queue = []

def append(self, item) -> None:
self._queue.append(item)


q = Queue()
q.append(1) Use `x.extend(...)` instead of repeatedly calling `x.append()`
q.append(2)


This has now been fixed.

What's Changed
* Add makefile recepie to update `.txt` file output by dosisod in https://github.com/dosisod/refurb/pull/164
* Fix duplicate module error when running by dosisod in https://github.com/dosisod/refurb/pull/165
* Fix FURB113 emitting error on any `append()` function call by dosisod in https://github.com/dosisod/refurb/pull/166
* Bump packages, make bug fix release by dosisod in https://github.com/dosisod/refurb/pull/167


**Full Changelog**: https://github.com/dosisod/refurb/compare/v1.9.0...v1.9.1

Page 4 of 6

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.