Using radon programmatically — Radon 1.4.2 documentation

# Using radon programmatically

Radon has a set of functions and classes that you can call from within your program to analyze files.

Radon’s API is composed of three layers:

- at the very bottom (the lowest level) there are the Visitors: with these classes one can build an AST out of the code and get basic metrics. Currently, there are two available visitors: `ComplexityVisitor` and `HalsteadVisitor`. With the former one analyzes the cyclomatic complexity of the code, while the latter gathers the so-called Halstead metrics. With those and other raw metrics one can compute the Maintainability Index. Example:

      >>> from radon.visitors import ComplexityVisitor
      >>> v = ComplexityVisitor.from_code('''
      def factorial(n):
          if n < 2: return 1
          return n * factorial(n - 1)

      def foo(bar):
          return sum(i for i in range(bar ** 2) if bar % i)
      ''')
      >>> v.functions
      [Function(name='factorial', lineno=2, col_offset=0, endline=4, is_method=False,
      classname=None, closures=[], complexity=2),
      Function(name='foo', lineno=6, col_offset=0, endline=7, is_method=False, classname=None,
      closures=[], complexity=3)]

- at a higher level, there are helper functions residing in separate modules. For cyclomatic complexity, one can use those inside `radon.complexity`. For Halstead metrics and MI index those inside `radon.metrics`. Finally, for raw metrics (that includes SLOC, LLOC, LOC, &c.) one can use the function `analyze()` inside the `radon.raw` module. With the majority of these functions the result is an object (`Module` object in the case of raw metrics) or a list of objects (`Function` or `Class` objects for cyclomatic complexity). Example:

      >>> from radon.complexity import cc_rank, cc_visit
      >>> cc_rank(4), cc_rank(9), cc_rank(14), cc_rank(23)
      ('A', 'B', 'C', 'D')
      >>> cc_visit('''
      class A(object):
          def meth(self):
              return sum(i for i in range(10) if i - 2 < 5)

      def fib(n):
          if n < 2: return 1
          return fib(n - 1) + fib(n - 2)
      ''')

      [Function(name='fib', lineno=6, col_offset=0, endline=8, is_method=False, classname=None,
      closures=[], complexity=2), Class(name='A', lineno=2, col_offset=0, endline=4,
      methods=[Function(name='meth', lineno=3, col_offset=4, endline=4, is_method=True,
      classname='A', closures=[], complexity=3)], real_complexity=3),
      Function(name='meth', lineno=3, col_offset=4, endline=4, is_method=True, classname='A',
      closures=[], complexity=3)]

      >>> from radon.raw import analyze
      >>> analyze("""def _split_tokens(tokens, token, value):
          '''Split a list of tokens on the specified token pair (token, value),
          where *token* is the token type (i.e. its code) and *value* its actual
          value in the code.
          '''
          res = [[]]
          for token_values in tokens:
              if (token, value) == token_values[:2]:
                  res.append([])
                  continue
              res[-1].append(token_values)
          return res
      """)
      >>> Module(loc=12, lloc=9, sloc=12, comments=0, multi=4, blank=0)

- at the highest level there are the Harvesters. A Harvester implements all the business logic of the CLI interface. To use a Harvester, it’s sufficient to create a `Config` object (which contains all the config values) and pass it to the Harvester instance along with a list of paths to analyze. An Harvester can then export its result to various formats (for cyclomatic complexity both JSON and XML are available). It’s possible to find an example for this in the Xenon project.

## Cyclomatic Complexity

`radon.complexity.` `cc_visit`(code, **kwargs)

  Visit the given code with `ComplexityVisitor`. All the keyword arguments are directly passed to the visitor.

`radon.complexity.` `cc_visit_ast`(ast_node, **kwargs)

  Visit the AST node with `ComplexityVisitor`. All the keyword arguments are directly passed to the visitor.

`radon.complexity.` `cc_rank`(cc)

  Rank the complexity score from A to F, where A stands for the simplest and best score and F the most complex and worst one:

  1 - 5 | A (low risk - simple block)
  6 - 10 | B (low risk - well structured and stable block)
  11 - 20 | C (moderate risk - slightly complex block)
  21 - 30 | D (more than moderate risk - more complex block)
  31 - 40 | E (high risk - complex block, alarming)
  41+ | F (very high risk - error-prone, unstable block)

  Here block is used in place of function, method or class.

  The formula used to convert the score into an index is the following:

  \[\text{rank} = \left \lceil \dfrac{\text{score}}{10} \right \rceil - H(5 - \text{score})\]

  where `H(s)` stands for the Heaviside Step Function. The rank is then associated to a letter (0 = A, 5 = F).

`radon.complexity.` `sorted_results`(blocks, order=SCORE)

  Given a ComplexityVisitor instance, returns a list of sorted blocks with respect to complexity. A block is a either `Function` object or a `Class` object. The blocks are sorted in descending order from the block with the highest complexity.

  The optional order parameter indicates how to sort the blocks. It can be:

  > - LINES: sort by line numbering;
  > - ALPHA: sort by name (from A to Z);
  > - SCORE: sorty by score (descending).

  Default is SCORE.

## Raw metrics

`radon.raw.` `analyze`(source)

  Analyze the source code and return a namedtuple with the following fields:

  > - loc: The number of lines of code (total)

  > - lloc: The number of logical lines of code

  > - sloc: The number of source lines of code (not necessarily

  >     corresponding to the LLOC)

  > - comments: The number of Python comment lines

  > - multi: The number of lines which represent multi-line strings

  > - blank: The number of blank lines (or whitespace-only ones)

  The equation \(sloc + blanks = loc\) should always hold. Multiline strings are not counted as comments, since, to the Python interpreter, they are not comments but strings.

## Other metrics

`radon.metrics.` `h_visit`(code)

  Compile the code into an AST tree and then pass it to `h_visit_ast()`.

`radon.metrics.` `h_visit_ast`(ast_node)

  Visit the AST node using the `HalsteadVisitor` visitor. A namedtuple with the following fields is returned:

  > - h1: the number of distinct operators
  > - h2: the number of distinct operands
  > - N1: the total number of operators
  > - N2: the total number of operands
  > - h: the vocabulary, i.e. h1 + h2
  > - N: the length, i.e. N1 + N2
  > - calculated_length: h1 * log2(h1) + h2 * log2(h2)
  > - volume: V = N * log2(h)
  > - difficulty: D = h1 / 2 * N2 / h2
  > - effort: E = D * V
  > - time: T = E / 18 seconds
  > - bugs: B = V / 3000 - an estimate of the errors in the implementation

`radon.metrics.` `mi_visit`(code, multi)

  Visit the code and compute the Maintainability Index (MI) from it.

`radon.metrics.` `mi_rank`(score)

  Rank the score with a letter:

  - A if \(\text{score} > 19\);
  - B if \(9 < \text{score} \le 19\);
  - C if \(\text{score} \le 9\).

`radon.metrics.` `mi_parameters`(code, count_multi=True)

  Given a source code snippet, compute the necessary parameters to compute the Maintainability Index metric. These include:

  > - the Halstead Volume
  > - the Cyclomatic Complexity
  > - the number of LLOC (Logical Lines of Code)
  > - the percent of lines of comment

  Parameters: | multi – If True, then count multiline strings as comment lines as well. This is not always safe because Python multiline strings are not always docstrings.

`radon.metrics.` `mi_compute`(halstead_volume, complexity, sloc, comments)

  Compute the Maintainability Index (MI) given the Halstead Volume, the Cyclomatic Complexity, the SLOC number and the number of comment lines. Usually it is not used directly but instead `mi_visit()` is preferred.

## Visitors

class `radon.visitors.` `ComplexityVisitor`(to_method=False, classname=None, off=True, no_assert=False)

  A visitor that keeps track of the cyclomatic complexity of the elements.

  Parameters: | to_method – If True, every function is treated as a method. In this case the classname parameter is used as class name. classname – Name of parent class. off – If True, the starting value for the complexity is set to 1, otherwise to 0.

class `radon.visitors.` `HalsteadVisitor`(context=None)

  Visitor that keeps track of operators and operands, in order to compute Halstead metrics (see `radon.metrics.h_visit()`).

## Harvesters

class `radon.cli.harvest.` `Harvester`(paths, config)

  Base class defining the interface of a Harvester object.

  A Harvester has the following lifecycle:

  1. Initialization: h = Harvester(paths, config)
  2. Execution: r = h.results. results holds an iterable object. The first time results is accessed, h.run() is called. This method should not be subclassed. Instead, the `gobble()` method should be implemented.
  3. Reporting: the methods as_json and as_xml return a string with the corrisponding format. The method to_terminal is a generator that yields the lines to be printed in the terminal.

  This class is meant to be subclasses and cannot be used directly, since the methods `gobble()`, `as_xml()` and `to_terminal()` are not implemented.

  `__init__`(paths, config)

    Initialize the Harvester.

    paths is a list of paths to analyze. config is a `Config` object holding the configuration values specific to the Harvester.

  `as_codeclimate_issues`()

    Format the results as Code Climate issues.

  `as_json`()

    Format the results as JSON.

  `as_xml`()

    Format the results as XML.

  `gobble`(fobj)

    Subclasses must implement this method to define behavior.

    This method is called for every file to analyze. fobj is the file object. This method should return the results from the analysis, preferably a dictionary.

  `results`

    This property holds the results of the analysis.

    The first time it is accessed, an iterator is returned. Its elements are cached into a list as it is iterated over. Therefore, if results is accessed multiple times after the first one, a list will be returned.

  `run`()

    Start the analysis. For every file, this method calls the `gobble()` method. Results are yielded as tuple: `(filename, analysis_results)`.

  `to_terminal`()

    Yields tuples representing lines to be printed to a terminal.

    The tuples have the following format: `(line, args, kwargs)`. The line is then formatted with line.format(*args, **kwargs).

class `radon.cli.harvest.` `CCHarvester`(paths, config)

  A class that analyzes Python modules’ Cyclomatic Complexity.

class `radon.cli.harvest.` `RawHarvester`(paths, config)

  A class that analyzes Python modules’ raw metrics.

class `radon.cli.harvest.` `MIHarvester`(paths, config)

  A class that analyzes Python modules’ Maintainability Index.