Various code metrics for Python code

Overview

Radon

Codacy badge Travis-CI badge Coveralls badge PyPI latest version badge Radon license

Radon is a Python tool that computes various metrics from the source code. Radon can compute:

  • McCabe's complexity, i.e. cyclomatic complexity
  • raw metrics (these include SLOC, comment lines, blank lines, &c.)
  • Halstead metrics (all of them)
  • Maintainability Index (the one used in Visual Studio)

Requirements

Radon will run from Python 2.7 to Python 3.8 (except Python versions from 3.0 to 3.3) with a single code base and without the need of tools like 2to3 or six. It can also run on PyPy without any problems (currently PyPy 3.5 v7.3.1 is used in tests).

Radon depends on as few packages as possible. Currently only mando is strictly required (for the CLI interface). colorama is also listed as a dependency but if Radon cannot import it, the output simply will not be colored.

Note: Python 2.6 was supported until version 1.5.0. Starting from version 2.0, it is not supported anymore.

Installation

With Pip:

$ pip install radon

Or download the source and run the setup file:

$ python setup.py install

Usage

Radon can be used either from the command line or programmatically. Documentation is at https://radon.readthedocs.org/.

Cyclomatic Complexity Example

Quick example:

$ radon cc sympy/solvers/solvers.py -a -nc
sympy/solvers/solvers.py
    F 346:0 solve - F
    F 1093:0 _solve - F
    F 1434:0 _solve_system - F
    F 2647:0 unrad - F
    F 110:0 checksol - F
    F 2238:0 _tsolve - F
    F 2482:0 _invert - F
    F 1862:0 solve_linear_system - E
    F 1781:0 minsolve_linear_system - D
    F 1636:0 solve_linear - D
    F 2382:0 nsolve - C

11 blocks (classes, functions, methods) analyzed.
Average complexity: F (61.0)

Explanation:

  • cc is the radon command to compute Cyclomatic Complexity
  • -a tells radon to calculate the average complexity at the end. Note that the average is computed among the shown blocks. If you want the total average, among all the blocks, regardless of what is being shown, you should use --total-average.
  • -nc tells radon to print only results with a complexity rank of C or worse. Other examples: -na (from A to F), or -nd (from D to F).
  • The letter in front of the line numbers represents the type of the block (F means function, M method and C class).

Actually it's even better: it's got colors!

A screen of Radon's cc command

Note about file encoding

On some systems, such as Windows, the default encoding is not UTF-8. If you are using Unicode characters in your Python file and want to analyze it with Radon, you'll have to set the RADONFILESENCODING environment variable to UTF-8.

On a Continuous Integration server

If you are looking to use radon on a CI server you may be better off with xenon. Although still experimental, it will fail (that means exiting with a non-zero exit code) when various thresholds are surpassed. radon is more of a reporting tool, while xenon is a monitoring one.

If you are looking for more complete solutions, read the following sections.

Codacy

Codacy uses Radon by default to calculate metrics from the source code.

Code Climate

Radon is available as a Code Climate Engine. To understand how to add Radon's checks to your Code Climate Platform, head over to their documentation: https://docs.codeclimate.com/v1.0/docs/radon

coala Analyzer

Radon is also supported in coala. To add Radon's checks to coala, simply add the RadonBear to one of the sections in your .coafile.

CodeFactor

CodeFactor uses Radon out-of-the-box to calculate Cyclomatic Complexity.

Usage with Jupyter Notebooks

Radon can be used with .ipynb files to inspect code metrics for Python cells. Any % macros will be ignored in the metrics.

Note

Jupyter Notebook support requires the optional nbformat package. To install, run pip install nbformat.

To enable scanning of Jupyter notebooks, add the --include-ipynb flag.

To enable reporting of individual cells, add the --ipynb-cells flag.

Quick example:

$ radon raw --include-ipynb --ipynb-cells .
example.ipynb
    LOC: 63
    LLOC: 37
    SLOC: 37
    Comments: 3
    Single comments: 2
    Multi: 10
    Blank: 14
    - Comment Stats
        (C % L): 5%
        (C % S): 8%
        (C + M % L): 21%
example.ipynb:[0]
    LOC: 0
    LLOC: 0
    SLOC: 0
    Comments: 0
    Single comments: 0
    Multi: 0
    Blank: 0
    - Comment Stats
        (C % L): 0%
        (C % S): 0%
        (C + M % L): 0%
example.ipynb:[1]
    LOC: 2
    LLOC: 2
    SLOC: 2
    Comments: 0
    Single comments: 0
    Multi: 0
    Blank: 0
    - Comment Stats
        (C % L): 0%
        (C % S): 0%
        (C + M % L): 0%

Links

Issues
  • Use python tokenizer to identify single-line comments and docstrings.

    Use python tokenizer to identify single-line comments and docstrings.

    Perform the raw analysis using a single iterator. Add test cases that cover line continuations and unusual docstrings.

    opened by ashanbrown 16
  • ERROR: invalid syntax (<unknown>, line 1404)

    ERROR: invalid syntax (, line 1404)

    Cloned the repository. Did sudo python radon/setup.py install with apparent success. Installed Baker module.

    [21:48 ~/Documents/Dprojects/Python/CoBro] radon cc cobro.py
    cobro.py
        ERROR: invalid syntax (<unknown>, line 1404)
    [21:48 ~/Documents/Dprojects/Python/CoBro] radon mi cobro.py
    cobro.py
        ERROR: invalid syntax (<unknown>, line 1404)
    [21:49 ~/Documents/Dprojects/Python/CoBro] radon raw  cobro.py
    cobro.py
        LOC: 1404
        LLOC: 688
        SLOC: 1323
        Comments: 491
        Multi: 82
        Blank: 81
        - Comment Stats
            (C % L): 35%
            (C % S): 37%
            (C + M % L): 41%
    

    Noting "1404" as size of input -- that line of cobro.py was: # c'est tout! a comment indented 4 ending in ! -- deleted that line and appropriate output appeared. Restoring line 1404 as #! returned the error.

    opened by tallforasmurf 15
  • CC for lambda functions (and, more generally, nested functions)

    CC for lambda functions (and, more generally, nested functions)

    In the documentation on ReadTheDocs (https://radon.readthedocs.org/en/latest/intro.html#cyclomatic-complexity), the reasoning behind increasing CC by one when encountering a lambda function is that it is a regular function. This raises a couple of questions:

    1. Why should a lambda function in itself increase the cyclomatic complexity? Surely, it does not in itself add any linearly independent paths.
    2. Why should it make a difference in the CC of a function if the lambda function is defined inside the function or not? The lambda function could be replaced by a regular function which would either be nested or not. This replacement-function would have a CC of its own but why should it add to the CC of the other function?

    To make an example:

    lambda1 = lambda var: var
    lambda2 = lambda var: var if type(var) is str else str(var)
    
    def f1(var):
        return lambda1(var)
    
    def f2(var):
        return lambda2(var)
    
    def f3(var):
        lambda1 = lambda var: var
        return lambda1(var)
    
    def f4(var):
        lambda2 = lambda var: var if type(var) is str else str(var)
        return lambda2(var)
    

    When calling radon cc -s with the above saved in a script, the following output is obtained:

        F 14:0 f4 - A (3)
        F 10:0 f3 - A (2)
        F 4:0 f1 - A (1)
        F 7:0 f2 - A (1)
    

    ... where the argument made in this post is that all four functions should have CC = 1.

    bug 
    opened by ppeder08 13
  • Fix for issue 109 and 110

    Fix for issue 109 and 110

    opened by jkhoriaty 13
  • Return a non-zero exit code for results below a certain threshold

    Return a non-zero exit code for results below a certain threshold

    There should be an option to set a threshold so that this tool will be used during the CI process. For example radon cc --min=B -a --min-average=A will fail if there are modules with cyclic complexity of C and below and if the average is below A.

    feature 
    opened by thedrow 13
  • Radon as a flake8 plugin

    Radon as a flake8 plugin

    Would it make sense to make a simple wrapper around radon to make it flake8 pluggable (similar to mccabe)?

    Thanks.

    opened by alecxe 12
  • ERROR: super() takes at least 1 argument (0 given)

    ERROR: super() takes at least 1 argument (0 given)

    I'm running radon hal myfile.py, but got this: ERROR: super() takes at least 1 argument (0 given). Any idea why? thanks!

    OS: macOS Majove 10.14.5 radon==3.0.1

    opened by kimi-p 12
  • Fixing versions of required libs

    Fixing versions of required libs

    Hey! It's us again from coala.

    Seems you just did a release with this line: https://github.com/rubik/radon/blob/master/setup.py#L21

    And it's giving us a lot of headaches (and CI failures) because you fix the colorama version to 0.3.6. So we have had long discussions last night and first off we don't know what's the best way to handle dependencies.

    We totally see that it's a huge value to fix the dependencies to a certain version as your stability increases, you can rely on your program to not have any issues due to any new releases of your dependency. OTOH if you have users that possibly want to use coala/radon on their python application you don't want to require them to

    a) Fix their requirements to yours if they overlap or b) Make an own virtualenv just for code checking.

    In general you'd rather want your requirements a bit more flexible because otherwise the user will be spending half of his workday working around clashing dependencies.

    What is your stand on that discussion?

    opened by sils 11
  • Support configuration file

    Support configuration file

    I use radon on CodeClimate, and it's the only engine that requires configuration inside my .codeclimate.yml file. It would be much more straightforward to have a .radon.yml or .radon.txt file with the configurations, so I could run codeclimate analyze -r radon and/or radon itself and have the same output without having to figure which parameters codeclimate passes for each configuration on .codeclimate.yml.

    opened by caiofbpa 9
  • Ensure that loc = sloc + multi + single-line comments + blank.

    Ensure that loc = sloc + multi + single-line comments + blank.

    This PR tries to address https://github.com/rubik/radon/issues/109. It fixes loc to genuinely be the sum of sloc, multi-line comments (including blank lines), single-line comments and blank lines (outside of comments). This requires a lot of test changes.

    There is a TODO on one case where the tokenizer approach seemed to be getting tripped up:

    def func():
        """ my comment """ \
       
        pass
    

    In this case, the tokenizer is reporting an error until it joins the line containing pass. Not sure if this is a bug with the tokenizer or not.

    I'm also not sure what the intermediate values in the comments should be for the second_mi example.

    opened by ashanbrown 9
  • Added support of match pattern

    Added support of match pattern

    Added support of match pattern introduced in python 3.10. @rubik comments/proposals are welcomed.

    opened by DolajoCZ 2
  • Python 3.10: match-case syntax not yet supported by radon?

    Python 3.10: match-case syntax not yet supported by radon?

    I have analyzed cyclomatic complexity of a function that has this new Python 3.10 match-case syntax. The result of that function was A (1). That's not correct. The function had a lot of case statements in it.

    Is there any undergoing work yet to have radon analyze and correctly report cyclomatic complexity where there's match-case syntax in Python 3.10 code?

    opened by PedanticHacker 1
  • Radon struggles to collect statistics from large files

    Radon struggles to collect statistics from large files

    I have some large files that radon struggles to analyse. I created an example to demonstrate the problem: https://gist.githubusercontent.com/Sam152/50e8ef27cceb899084b42a069237a7b8/raw/bb21870395df86a0062c22353b532b45d31bd3f5/sample.py (~800 lines)

    In my case running radon raw big-package takes 28.38s. In reality the module I'm trying to analyse has ~ 5000 lines with a similar amount of AST per line.

    If I double my 800 line example, the script takes roughly 115.50s to run, so my feeling is that there might be something which scales worse than O(n) per-AST.

    Any pointers if there might be something that can be optimised here, or if the nature of the analysis is such that speeding this process up is simply not possible?

    Thanks in advance, if anyone can share their experience.

    Cheers, Sam


    On a side note, while researching this issue, I found radon cited in an academic paper, which I thought was interesting and worth sharing (https://arxiv.org/pdf/2007.08978.pdf).

    opened by Sam152 2
  • Support of pyproject.toml file

    Support of pyproject.toml file

    Hello, do you plan to support pyproject.toml file based on PEP518? For example here is list of some tools which support pyproject.toml.

    opened by DolajoCZ 1
  • Nested classes issue

    Nested classes issue

    class student2:
        def nott(self):
            if True and False:
                return
            elif True:
                return
            else:
                return
            return self
        class classmate:
            def example(self):
                return 0
        @staticmethod
        def staticMethod():
            return None
    

    the "radon cc {path}.py" does not detect any nested classes. The above example is one of many. Do not bother about the logic of the code I am just experimenting something for other purposes. The program will not detect the nested classes nor the methods of that class.

    opened by Mahdi-py 1
  • Feature Request: Cohesion and Coupling metrics

    Feature Request: Cohesion and Coupling metrics

    Hi,

    I was wondering whenever adding a subset of Chidamber and Kemerer programming complexity metrics would be of interest to you and in the scope of radon tool?

    While using radon I found it more effective in finding methods/functions that are complex, rather than tightly coupled, so I believe having a couple of metrics to estimate coupling and cohesion would be nice.

    Some of the more popular metrics are LCOM and RFC, which are focused on estimating program coupling and cohesion. Here is a short Wikipedia description of these metrics, and here's the original paper.

    P.S. I really like your project and use it sometimes, both for personal projects and work. It really helps when figuring out what refactoring to do next.

    opened by AlexandruBurlacu 1
  • Feature request: node visitors for style metrics

    Feature request: node visitors for style metrics

    For reference, please see https://github.com/dollodart/pymetrics. This amounts to adding new node visitors and is like issue #163. Since complexity metrics are used in linters which have the main purpose enforcing style rules you may want style metrics. These analytics could be useful in project-specific guidelines up to PEPs where you are trying to assess what stylistic rules most users want (nominally which are best).

    Is this within the scope of this project and would a PR having node visitors like in the link for pymetrics be accepted?

    opened by dollodart 0
  • Add architecture ppc64le to travis build

    Add architecture ppc64le to travis build

    Add support for architecture ppc64le.

    Exclude python "pypy3.5" and "2.7" for ppc64le

    This is part of the Ubuntu distribution for ppc64le. This helps us simplify testing later when distributions are re-building and re-releasing. For more info tag @gerrith3

    opened by ddeka2910 7
  • Provide option to return raw metrics by block type (#192

    Provide option to return raw metrics by block type (#192

    This is a first attempt at implementing a raw_visitor to provide metrics by block type.

    It is lightly tested reusing some of the tests from test_raw.py, not all of which are currently passing. Just looking for some feedback @rubik before adding more tests.

    ast.get_source_segement was implemented in Python 3.8 which makes it easy to reproduce a segment of the input code from an ast node.

    opened by BlaneG 3
McCabe complexity checker for Python

McCabe complexity checker Ned's script to check McCabe complexity. This module provides a plugin for flake8, the Python code checker. Installation You

Python Code Quality Authority 439 Oct 24, 2021
Inspects Python source files and provides information about type and location of classes, methods etc

prospector About Prospector is a tool to analyse Python code and output information about errors, potential problems, convention violations and comple

Python Code Quality Authority 1.5k Oct 22, 2021
Monitoring tool based on radon

xenon Xenon is a monitoring tool based on Radon. It monitors your code's complexity. Ideally, Xenon is run every time you commit code. Through command

Michele Lacchia 196 Oct 10, 2021
A tool for measuring Python class cohesion.

Cohesion Cohesion is a tool for measuring Python class cohesion. In computer programming, cohesion refers to the degree to which the elements of a mod

null 144 Oct 13, 2021
Code Review, hosted on Google App Engine

Welcome to Rietveld GitHub Wiki: https://github.com/rietveld-codereview/rietveld/wiki Google Group: http://groups.google.com/group/codereview-discuss

null 493 Oct 11, 2021
Read-only mirror of https://gitlab.gnome.org/GNOME/meld

About Meld Meld is a visual diff and merge tool targeted at developers. Meld helps you compare files, directories, and version controlled projects. It

GNOME Github Mirror 716 Oct 24, 2021
An extensible and friendly code review tool for projects and companies of all sizes.

Review Board Review Board is an open source, web-based code and document review tool built to help companies, open source projects, and other organiza

Review Board 1.4k Oct 14, 2021