Skip to main content

Deadcode Logo

Find and Fix Unused Python Code

pre-commit PyPI Downloads License: AGPLv3
Buy Me a Coffee at ko-fi.com

Installation

pip install deadcode

Usage

To see unused code findings:

deadcode .

To see suggested fixes for all files:

deadcode . --fix --dry

To see suggested fixes only for foo.py file:

deadcode . --fix --dry --only foo.py

To fix:

deadcode . --fix

Tune out some of the false positives, e.g.:

deadcode . --exclude=venv,tests --ignore-names=BaseTestCase,*Mixin --ignore-names-in-files=migrations

The same options can be provided in pyproject.toml settings file:

[tool.deadcode]
exclude = ["venv", "tests"]
ignore-names = ["BaseTestCase", "*Mixin"]
ignore-names-in-files = ["migrations"]

If your project uses Tach to declare module boundaries, deadcode can read one or more tach.toml files and treat names exposed through [[interfaces]] as intentional public API (never reported as unused, the same way __all__ is treated), and skip files that belong to a module marked unchecked = true:

deadcode . --tach-config tach.toml

Pre-commit hook

Create a .pre-commit-config.yaml file in the root of your project directory, if it doesn't exist, and add the following to the file:

# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
  - repo: https://github.com/albertas/deadcode
    rev: 2.6.0
    hooks:
      - id: deadcode

Command line options

Option                                    Type Meaning
--fix - Automatically remove detected unused code expressions from the code base.
--dry - Show changes which would be made in files.
--only list Filenames (or path expressions), that will be reflected in the output (and modified if needed).
--exclude list Filenames (or path expressions), which will be completely skipped without being analysed.
--ignore-names list Removes provided list of names from the output. Regexp expressions to match multiple names can also be provided, e.g. *Mixin will match all classes ending with Mixin.
--ignore-names-in-files list Ignores unused names in files, which filenames match provided path expressions.
--ignore-names-if-inherits-from list Ignores names of classes, which inherit from provided class names.
--ignore-names-if-decorated-with list Ignores names of an expression, which is decorated with one of the provided decorator names.
--ignore-bodies-of list Ignores body of an expression if its name matches any of the provided names.
--ignore-bodies-if-decorated-with list Ignores body of an expression if its decorated with one of the provided decorator names.
--ignore-bodies-if-inherits-from list Ignores body of a class if it inherits from any of the provided class names.
--ignore-definitions list Ignores definition (including name and body) if a name of an expression matches any of the provided ones.
--ignore-definitions-if-inherits-from list Ignores definition (including name and body) of a class if it inherits from any of the provided class names.
--ignore-definitions-if-decorated-with list Ignores definition (including name and body) of an expression, which is decorated with any of the provided decorator names.
--ignore-non-self-attributes - Does not report unused attributes assigned on objects other than self, e.g. foo.bar = 1. Such assignments may have side effects or be consumed by code outside of the analysed files, so they cannot safely be assumed dead.
--ignore-class-attributes - Does not report unused attributes assigned directly in a class body, e.g. THING = "blah" inside a class Foo: block. Such attributes may control behaviour of inherited/overridden methods, external frameworks, or metaclasses, so they cannot safely be assumed dead.
--tach-config list Paths to tach.toml files (see Tach). Names exposed via [[interfaces]] are treated as public API and never reported as unused; files in unchecked = true modules are skipped entirely.
--no-color - Removes colors from the output.
--count - Provides the count of the detected unused names instead of printing them all out.
--quiet - Does not output anything. Makefile still fails with exit code 1 if unused names are found.
Glossory
  • name - variable, function or class name.
  • body - code block which follows after : in function or class definition.
  • definition - whole class or function definition expression including its name and body.

Rules

Code Name Message
DC01 unused-variable Variable {name} is never used
DC02 unused-function Function {name} is never used
DC03 unused-class Class {name} is never used
DC04 unused-method Method {name} is never used
DC05 unused-attribute Attribute {name} is never used
DC06 unused-name Name {name} is never used
DC07 unused-import Import {name} is never used
DC08 unused-property Property {name} is never used
DC09 unreachable-if-block Unreachable conditional statement block
DC11 empty-file Empty Python file
DC12 commented-out-code Commented out code
DC13 unreachable-code Code after terminal statement, e.g. return, raise, continue, break
DC ignore-expression Do not show any findings for an expression, which starts on current line (this code can only be used in # noqa: DC comments)

Ignoring checks with noqa comments

Inline # noqa comments can be used to ignore deadcode checks. E.g. unused Foo class wont be detected/fixed because # noqa: DC03 comment is used:

class Foo:  # noqa: DC03
    pass

Contributing

  • make check - runs unit tests and other checks using virtual environment.

Rationale

ruff and flake8 - don't have rules for unused global code detection, only for local ones F823, F841, F842. deadcode package tries to add new DCXXX checks for detecting variables/functions/classes/files which are not used in a whole code base.

deadcode - is supposed to be used inline with other static code checkers like ruff.

There is an alternative vulture package.

Known limitations

In case there are several definitions using the same name - they all wont be reported if at least one usage of that name is being detected.

Files with syntax errors will be ignored, because deadcode uses ast to build abstract syntax tree for name usage detection.

It is assumed that deadcode will be run using the same or higher Python version as the code base is implemented in.

Feature requests

  • Replace .* with only * in regexp matching.
  • Add unused class method detection DC04 check.
  • Add --fix option to automatically remove detected dead code occourencies
  • Add a check for empty python files.
  • Split error codes into DC01, DC02, DC03 for variables, functions, class.
    • Should have different codes for ignoring name and ignoring whole definition (reserved DCxx0 - ignore name, DCxx1 - ignore definition).
    • Allow to disable each check separately using:
      • inline comment.
      • pyproject.toml file
  • Add a check for code in comments.
  • Add target python version option, if specified it will be used for code base check.
  • Add a --depth parameter to ignore nested code.. (To only check global scope use 0).
  • Add options:
    • --ignore-definitions
    • --ignore-definitions-if-inherits-from
    • --ignore-definitions-if-decorated-with
    • --ignore-names-if-inherits-from
    • --ignore-names-if-decorated-with
    • --ignore-bodies-of
    • --ignore-bodies-if-decorated-with
    • --ignore-bodies-if-inherits-from
    • --ignore-definitions
    • --ignore-definitions-if-inherits-from
    • --ignore-definitions-if-decorated-with
      • Question: would it be possible to ignore only certain types of checks for a body, e.g. only variable attributes of TypedDict and still check usage of methods and properties?
      • What expression would allow this type of precission?
  • Distinguish between definitions with same name, but different files.
  • Repeated application of deadcode till the output stops changing.
  • Unreachable code detection and fixing: this should only be scoped for if statements and only limited to primitive variables.
  • Benchmarking performance with larger projects (time, CPU and memory consumption) in order to optimize.
  • --fix could accept a list of filenames as well (only those files would be changed, but the summary could would be full). (This might be confusing, because filenames, which have to be considered are provided without any flag, --fix is expected to not accept arguments)
  • pre-commit-hook.
  • language server.
  • DC10: remove code after terminal statements like raise, return, break, continue and comes in the same scope.
  • Add ignore and per-file-ignores command line and pyproject.toml options, which allows to skip some rules.
  • Make sure that all rules are being skipped by noqa comment and all rules react to noqa: rule_id comments.
  • Include package names into code item scope (dot-separated path), e.g. "package1.package2.module.class.method.variable".
  • All options should be able to accept dot-separated path or a generic name, e.g. "marshmallow.Schema" vs "Schema", documentation should cleary demonstrate the behaviour/example that "Schema" means "*.Schema".
  • Redefinition of an existing name makes previous name unreachable, unless it is assigned somehow.
  • Check if file is still valid/parsable after automatic fixing, if not: halt the change and report error.
  • Investigate ways of extracting and backporting Python3.10+ ast implementation to lower Python versions.

Release notes

  • v2.6.0:
    • Add --ignore-class-attributes option to not report unused attributes assigned directly in a class body (e.g. THING = "blah" inside class Foo:), since such attributes may control behaviour of inherited/overridden methods, external frameworks, or metaclasses.
  • v2.5.0:
    • Add --ignore-non-self-attributes option to not report unused attributes assigned on objects other than self (e.g. foo.bar = 1), since such assignments may have side effects or be consumed by code outside of the analysed files.
  • v2.4.2:
    • Add --tach-config option to read tach.toml file(s) and treat names exposed via [[interfaces]] as public API, and skip unchecked = true modules entirely.
  • v2.4.1:
    • Add --version option to show deadcode version.
    • Use stdout for deadcode output.
  • v2.4.0:
    • Add --only option that accepts filenames only which will be reflected in the output and modified. This option can be used with --fix and --fix --dry options as well as for simple unused code detection without fixing.
  • v2.3.2:
    • Add pre-commit hook support.
    • Drop support for Python 3.8 and 3.9 versions, since their ast implementation is lacking features.
  • v2.3.1:
    • Started analysing files in bytes instead of trying to convert them into UTF-8 encoded strings.
    • Improved automatic removal of unused imports.
  • v2.3.0:
    • Add --dry option.
    • Update error codes to use DCXX format instead of DCXXX.

Metadata

Release files for lapsed 3.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for lapsed 3.2.0
File
lapsed-3.2.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
lapsed-3.2.0-py3-none-win32.whl Python 3 none Windows x86-32 Details
lapsed-3.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
lapsed-3.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
lapsed-3.2.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
lapsed-3.2.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 10.9 MB

Release files / lapsed-3.2.0-py3-none-win_amd64.whl

Download URL lapsed-3.2.0-py3-none-win_amd64.whl
Size 1.9 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
963f80d5ea8bc382a3c55028464b6f1f429d1742c79db0902ea61aaa9d7629b7
BLAKE2b-256 checksum
How to use checksums
e9bdb76848df216184cbc712e70ce0ab0e47f804cdd76c02ca90c18a33f5f933
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / lapsed-3.2.0-py3-none-win32.whl

Download URL lapsed-3.2.0-py3-none-win32.whl
Size 1.7 MB
Tags Python 3 Windows x86-32
SHA-256 checksum
How to use checksums
b28c819c2a92f79d9ef641675e6ab8427b314f2c9f1665de8c1710ecd480a472
BLAKE2b-256 checksum
How to use checksums
4ec0d69614098751d61e7d0b64e6781a2252b1a7cfbf9ba734398c51ad1ecd31
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / lapsed-3.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL lapsed-3.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.9 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
e8662b8b6c46b4c4ea67ac70c150ab3c5c52871d6c850e5fb9e69c6078517dc6
BLAKE2b-256 checksum
How to use checksums
768b207268e6e71c323b3d370c52d0627df466fbbbbdeda288d95531e9974967
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / lapsed-3.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL lapsed-3.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.8 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
ef533e8250e130ce513ce6d7e4064a279c987690a0b26e65745203838056df6f
BLAKE2b-256 checksum
How to use checksums
9529e9d9c9f8aca0559a5c53c6ef9a9b4b8da7a818a203817102c348b412c070
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / lapsed-3.2.0-py3-none-macosx_11_0_arm64.whl

Download URL lapsed-3.2.0-py3-none-macosx_11_0_arm64.whl
Size 1.8 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
056cf374209e7c7e023b7ed4b4a5cd52b054df3fc9d26568fb33ecd50b4ba4c5
BLAKE2b-256 checksum
How to use checksums
9f0eff41be04e0ee61d5a23093557f785630a8951a10222f0a6006b5f9ffe2f5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / lapsed-3.2.0-py3-none-macosx_10_12_x86_64.whl

Download URL lapsed-3.2.0-py3-none-macosx_10_12_x86_64.whl
Size 1.8 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
681f0c37fcbc747d52f259f297b5c5ef0aa874b92cb636a55fd96585cf5363f2
BLAKE2b-256 checksum
How to use checksums
92d27e1d5598c1a43277b7342b09c3fddb9b179ed50e442973a9c43986d42741
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

3.2.0 This release

6 release files

3.0.0

2 release files

2.9.0

2 release files

2.8.0

2 release files

2.7.2

2 release files

2.7.1

2 release files

2.7.0

2 release files

2.6.1

2 release files

2.6.0

2 release files

2.5.0

2 release files

2.4.2

2 release files

2.4.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page