Skip to content

Commit

Permalink
Merge 0e113d2 into 92fa247
Browse files Browse the repository at this point in the history
  • Loading branch information
tonybaloney committed Sep 17, 2019
2 parents 92fa247 + 0e113d2 commit 8b8061b
Show file tree
Hide file tree
Showing 10 changed files with 3,085 additions and 16 deletions.
48 changes: 47 additions & 1 deletion docs/commandline.rst
Expand Up @@ -152,6 +152,18 @@ Options

Value can be set in a configuration file using the ``no_assert`` property.

.. option:: --include-ipynb

Include the Python cells within IPython Notebooks in the reporting.

Value can be set in a configuration file using the ``include_ipynb`` property.

.. option:: --ipynb-cells

Report on individual cells in any .ipynb files.

Value can be set in a configuration file using the ``ipynb_cells`` property.

.. option:: -O, --output-file

Save output to the specified output file.
Expand Down Expand Up @@ -268,6 +280,18 @@ Options

Format results in JSON.

.. option:: --include-ipynb

Include the Python cells within IPython Notebooks in the reporting.

Value can be set in a configuration file using the ``include_ipynb`` property.

.. option:: --ipynb-cells

Report on individual cells in any .ipynb files.

Value can be set in a configuration file using the ``ipynb_cells`` property.

.. option:: -O, --output-file

Save output to the specified output file.
Expand Down Expand Up @@ -356,6 +380,17 @@ Options

Value can be set in a configuration file using the ``output_file`` property.

.. option:: --include-ipynb

Include the Python cells within IPython Notebooks in the reporting.

Value can be set in a configuration file using the ``include_ipynb`` property.

.. option:: --ipynb-cells

Report on individual cells in any .ipynb files.

Value can be set in a configuration file using the ``ipynb_cells`` property.

Examples
++++++++
Expand All @@ -376,7 +411,7 @@ matches ``path1/tests/*``.


The :command:`hal` command
--------------------------
-------------------------

.. program:: hal

Expand Down Expand Up @@ -422,6 +457,17 @@ Options

Value can be set in a configuration file using the ``output_file`` property.

.. option:: --include-ipynb

Include the Python cells within IPython Notebooks in the reporting.

Value can be set in a configuration file using the ``include_ipynb`` property.

.. option:: --ipynb-cells

Report on individual cells in any .ipynb files.

Value can be set in a configuration file using the ``ipynb_cells`` property.

Examples
++++++++
Expand Down
32 changes: 28 additions & 4 deletions radon/cli/__init__.py
Expand Up @@ -62,7 +62,9 @@ def cc(paths, min=_cfg.get_value('cc_min', str, 'A'),
total_average=_cfg.get_value('total_average', bool, False),
xml=False,
codeclimate=False,
output_file=_cfg.get_value('output_file', str, None), ):
output_file=_cfg.get_value('output_file', str, None),
include_ipynb=_cfg.get_value('include_ipynb', bool, False),
ipynb_cells=_cfg.get_value('ipynb_cells', bool, False),):
'''Analyze the given Python modules and compute Cyclomatic
Complexity (CC).
Expand Down Expand Up @@ -94,6 +96,8 @@ def cc(paths, min=_cfg.get_value('cc_min', str, 'A'),
complexity.
:param --show-closures: Add closures/inner classes to the output.
:param -O, --output-file <str>: The output file (default to stdout).
:param --include-ipynb: Include IPython Notebook files
:param --ipynb-cells: Include reports for individual IPYNB cells
'''
config = Config(
min=min.upper(),
Expand All @@ -106,6 +110,8 @@ def cc(paths, min=_cfg.get_value('cc_min', str, 'A'),
order=getattr(cc_mod, order.upper(), getattr(cc_mod, 'SCORE')),
no_assert=no_assert,
show_closures=show_closures,
include_ipynb=include_ipynb,
ipynb_cells=ipynb_cells,
)
harvester = CCHarvester(paths, config)
with outstream(output_file) as stream:
Expand All @@ -120,7 +126,9 @@ def raw(paths,
ignore=_cfg.get_value('ignore', str, None),
summary=False,
json=False,
output_file=_cfg.get_value('output_file', str, None), ):
output_file=_cfg.get_value('output_file', str, None),
include_ipynb=_cfg.get_value('include_ipynb', bool, False),
ipynb_cells=_cfg.get_value('ipynb_cells', bool, False),):
'''Analyze the given Python modules and compute raw metrics.
:param paths: The paths where to find modules or packages to analyze. More
Expand All @@ -134,11 +142,15 @@ def raw(paths,
summary of the gathered metrics. Default to False.
:param -j, --json: Format results in JSON.
:param -O, --output-file <str>: The output file (default to stdout).
:param --include-ipynb: Include IPython Notebook files
:param --ipynb-cells: Include reports for individual IPYNB cells
'''
config = Config(
exclude=exclude,
ignore=ignore,
summary=summary,
include_ipynb=include_ipynb,
ipynb_cells=ipynb_cells,
)
harvester = RawHarvester(paths, config)
with outstream(output_file) as stream:
Expand All @@ -156,7 +168,9 @@ def mi(paths,
show=_cfg.get_value('show_mi', bool, False),
json=False,
sort=False,
output_file=_cfg.get_value('output_file', str, None), ):
output_file=_cfg.get_value('output_file', str, None),
include_ipynb=_cfg.get_value('include_ipynb', bool, False),
ipynb_cells=_cfg.get_value('ipynb_cells', bool, False),):
'''Analyze the given Python modules and compute the Maintainability Index.
The maintainability index (MI) is a compound metric, with the primary aim
Expand All @@ -178,6 +192,8 @@ def mi(paths,
:param -j, --json: Format results in JSON.
:param --sort: If given, results are sorted in ascending order.
:param -O, --output-file <str>: The output file (default to stdout).
:param --include-ipynb: Include IPython Notebook files
:param --ipynb-cells: Include reports for individual IPYNB cells
'''
config = Config(
min=min.upper(),
Expand All @@ -187,6 +203,8 @@ def mi(paths,
multi=multi,
show=show,
sort=sort,
include_ipynb=include_ipynb,
ipynb_cells=ipynb_cells,
)

harvester = MIHarvester(paths, config)
Expand All @@ -201,7 +219,9 @@ def hal(paths,
ignore=_cfg.get_value('ignore', str, None),
json=False,
functions=_cfg.get_value('functions', bool, False),
output_file=_cfg.get_value('output_file', str, None), ):
output_file=_cfg.get_value('output_file', str, None),
include_ipynb=_cfg.get_value('include_ipynb', bool, False),
ipynb_cells=_cfg.get_value('ipynb_cells', bool, False),):
"""
Analyze the given Python modules and compute their Halstead metrics.
Expand All @@ -219,11 +239,15 @@ def hal(paths,
:param -j, --json: Format results in JSON.
:param -f, --functions: Analyze files by top-level functions instead of as a whole.
:param -O, --output-file <str>: The output file (default to stdout).
:param --include-ipynb: Include IPython Notebook files
:param --ipynb-cells: Include reports for individual IPYNB cells
"""
config = Config(
exclude=exclude,
ignore=ignore,
by_function=functions,
include_ipynb=include_ipynb,
ipynb_cells=ipynb_cells,
)

harvester = HCHarvester(paths, config)
Expand Down
26 changes: 24 additions & 2 deletions radon/cli/harvest.py
Expand Up @@ -10,7 +10,14 @@
from radon.cli.colors import RANKS_COLORS, MI_RANKS, RESET
from radon.cli.tools import (iter_filenames, _open, cc_to_dict, dict_to_xml,
dict_to_codeclimate_issues, cc_to_terminal,
raw_to_dict)
raw_to_dict, strip_ipython)

try:
import nbformat
import io
SUPPORTS_IPYNB = True
except ImportError:
SUPPORTS_IPYNB = False


class Harvester(object):
Expand Down Expand Up @@ -67,7 +74,22 @@ def run(self):
for name in self._iter_filenames():
with _open(name) as fobj:
try:
yield (name, self.gobble(fobj))
if name.endswith('.ipynb'):
if SUPPORTS_IPYNB and self.config.include_ipynb:
nb = nbformat.read(fobj, as_version=nbformat.NO_CONVERT)
cells = [cell.source for cell in nb.cells if cell.cell_type == 'code']
# Whole document
doc = "\n".join(cells)
yield (name, self.gobble(io.StringIO(strip_ipython(doc))))

if self.config.ipynb_cells:
# Individual cells
cellid = 0
for source in cells:
yield ("{0}:[{1}]".format(name, cellid), self.gobble(io.StringIO(strip_ipython(source))))
cellid += 1
else:
yield (name, self.gobble(fobj))
except Exception as e:
yield (name, {'error': str(e)})

Expand Down
11 changes: 10 additions & 1 deletion radon/cli/tools.py
Expand Up @@ -19,6 +19,11 @@
from radon.cli.colors import (LETTERS_COLORS, RANKS_COLORS, TEMPLATE, BRIGHT,
RESET)

try:
import nbformat
SUPPORTS_IPYNB = True
except ImportError:
SUPPORTS_IPYNB = False

# PyPy doesn't support encoding parameter in `open()` function and works with
# UTF-8 encoding by default
Expand Down Expand Up @@ -203,7 +208,7 @@ def _open(path):

def _is_python_file(filename):
'''Check if a file is a Python source file.'''
if filename == '-' or filename.endswith('.py'):
if filename == '-' or filename.endswith('.py') or (SUPPORTS_IPYNB and filename.endswith('.ipynb')):
return True
try:
with open(filename) as fobj:
Expand Down Expand Up @@ -497,3 +502,7 @@ def get_fingerprint(path, additional_parts):
key = '|'.join(parts)
m.update(key.encode('utf-8'))
return m.hexdigest()


def strip_ipython(code):
return '\n'.join([line for line in code.split('\n') if not line.startswith('%')])
5 changes: 5 additions & 0 deletions radon/tests/conftest.py
Expand Up @@ -3,6 +3,11 @@
import os


@pytest.fixture
def log_mock(mocker):
return mocker.patch('radon.cli.log_result')


class RadonConfig(object):
def __init__(self):
self._fname = os.path.join(os.path.dirname(__file__), 'radon.cfg')
Expand Down

0 comments on commit 8b8061b

Please sign in to comment.