Exemplo n.º 1
0
def mi(paths, min='A', max='C', multi=True, exclude=None, ignore=None,
       show=False, json=False, sort=False):
    '''Analyze the given Python modules and compute the Maintainability Index.

    The maintainability index (MI) is a compound metric, with the primary aim
    being to determine how easy it will be to maintain a particular body of
    code.

    :param paths: The paths where to find modules or packages to analyze. More
        than one path is allowed.
    :param -n, --min <str>: The minimum MI to display (default to A).
    :param -x, --max <str>: The maximum MI to display (default to C).
    :param -e, --exclude <str>: Exclude files only when their path matches one
        of these glob patterns. Usually needs quoting at the command line.
    :param -i, --ignore <str>: Ignore directories when their name matches one
        of these glob patterns: radon won't even descend into them. By default,
        hidden directories (starting with '.') are ignored.
    :param -m, --multi: If given, multiline strings are not counted as
        comments.
    :param -s, --show: If given, the actual MI value is shown in results.
    :param -j, --json: Format results in JSON.
    :param --sort: If given, results are sorted in ascending order.
    '''
    config = Config(
        min=min.upper(),
        max=max.upper(),
        exclude=exclude,
        ignore=ignore,
        multi=multi,
        show=show,
        sort=sort,
    )

    harvester = MIHarvester(paths, config)
    log_result(harvester, json=json)
Exemplo n.º 2
0
 def radon_mi(self, f, config):
     result = True
     for mir in MIHarvester([f], config).results:
         ''' Не допускается Maintainability Index ниже 30% '''
         if mir[1]['mi'] < 30:
             print('%s: %u%%' % (mir[0], mir[1]['mi']))
             result = False
     return result
Exemplo n.º 3
0
 def radon_mi(self, filename, config):
     result = True
     for mir in MIHarvester([filename], config).results:
         ''' Не допускается Maintainability Index ниже 50% '''
         if mir[1]['mi'] < 50:
             print('%s: Low maintainability index - %u%%' %
                   (mir[0], mir[1]['mi']))
             result = False
     return result
Exemplo n.º 4
0
def mi(
        paths,
        min=_cfg.get_value('mi_min', str, 'A'),
        max=_cfg.get_value('mi_max', str, 'C'),
        multi=_cfg.get_value('multi', bool, True),
        exclude=_cfg.get_value('exclude', str, None),
        ignore=_cfg.get_value('ignore', str, None),
        show=_cfg.get_value('show_mi', bool, False),
        json=False,
        sort=False,
        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
    being to determine how easy it will be to maintain a particular body of
    code.

    :param paths: The paths where to find modules or packages to analyze. More
        than one path is allowed.
    :param -n, --min <str>: The minimum MI to display (default to A).
    :param -x, --max <str>: The maximum MI to display (default to C).
    :param -e, --exclude <str>: Exclude files only when their path matches one
        of these glob patterns. Usually needs quoting at the command line.
    :param -i, --ignore <str>: Ignore directories when their name matches one
        of these glob patterns: radon won't even descend into them. By default,
        hidden directories (starting with '.') are ignored.
    :param -m, --multi: If given, multiline strings are not counted as
        comments.
    :param -s, --show: If given, the actual MI value is shown in results.
    :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(),
        max=max.upper(),
        exclude=exclude,
        ignore=ignore,
        multi=multi,
        show=show,
        sort=sort,
        include_ipynb=include_ipynb,
        ipynb_cells=ipynb_cells,
    )

    harvester = MIHarvester(paths, config)
    with outstream(output_file) as stream:
        log_result(harvester, json=json, stream=stream)
Exemplo n.º 5
0
def get_files_maintainability_data(paths, ignore):
    config = Config(
        min="A",
        max="C",
        exclude=ignore,
        ignore=ignore,
        multi=True,
        show=True,
    )
    harvester = MIHarvester(paths, config)
    data = []
    for filename, mi_data in harvester.results:
        if not mi_data:
            continue
        data.append((filename, mi_data['mi']))

    sorted_scores = sorted(data, key=operator.itemgetter(1))
    return OrderedDict(sorted_scores)
Exemplo n.º 6
0
def raw(code_path, results):
    """
    Compute raw metrics such as number of lines of code, documentation rate or complexity metrics

    :param code_path: Path to the source code
    :param results: Dictionary to which the results are appended.
    """

    # Lines
    h = RawHarvester([code_path], Config(exclude=None, ignore=None, summary=True))
    file_metrics = dict(h.results)

    # Maintainability
    h = MIHarvester([code_path],
                Config(min='A', max='C', multi=True, exclude=None, ignore=None, show=False, json=False,
                       sort=False))
    mi_metrics = dict(h.results)
    always_merger.merge(file_metrics, mi_metrics)

    # Create a summary for the total of the code
    summary = dict()
    summation_keys = ['loc', 'lloc', 'sloc', 'comments', 'multi', 'blank', 'single_comments']
    for k in summation_keys:
        summary[k] = sum([metrics[k] for metrics in file_metrics.values()])

    # Weighted average summaries
    averaging_keys = {'mi': 'sloc'}
    for key_index, weight_index in averaging_keys.items():
        if summary[weight_index] == 0.0:
            summary[weight_index] = 0.0
        else:
            summary[key_index] = sum([metrics[key_index] * metrics[weight_index] for metrics in file_metrics.values()]) / summary[weight_index]

    # Export results
    results[LINES_OF_CODE] = summary.get('lloc', 0)
    results[COMMENT_RATE] = (float(summary.get('comments', 0)) + float(summary.get('multi', 0))) / (max(1, float(summary.get('loc', 1))))
    results[MAINTAINABILITY_INDEX] = summary.get('mi', 0.0) / 100.0
Exemplo n.º 7
0
def analyse(paths):

    #Setup the Configuration for each Harvester 
    config = Config(
        exclude=[],
        ignore=[],
        order=SCORE,
        no_assert= False,
        show_closures=False,
        min='A',
        max='F',
    )

    config2 = Config(
        exclude=[],
        ignore=[],
        by_function= False
    )

    config3 = Config(
        min= 'A',
        max= 'C',
        exclude=[],
        ignore=[],
        multi=True,
        show=True,
    )

    config4 = Config(
        exclude=[],
        ignore=[],
        summary=False,
        json=True,
    )
    


    """
    ----------------------
    Cyclomatic Complexity 
    ---------------------
    Cyclomatic Complexity corresponds to the number of decisions a block of code contains plus 1. 
    This number (also called McCabe number) is equal to the number of linearly independent paths through the code. 
    This number can be used as a guide when testing conditional logic in blocks.Radon analyzes the AST tree 
    of a Python program to compute Cyclomatic Complexity. Statements have the following effects on Cyclomatic Complexity:
    """
    
    h = CCHarvester(paths, config)
    ccResults = h._to_dicts()
    # print(ccResults)
    numOfFunctions = 0
    complexity = 0

    # for result in ccResults.values():
    #     numOfFunctions += 1
    #     complexity += result['complexity'] if isinstance(result, dict) else 0

    for path in paths:
        for i in ccResults.get(path, []):
            numOfFunctions += 1
            complexity += i["complexity"] if isinstance(i, dict) else 0

    cc = complexity/numOfFunctions if numOfFunctions != 0 else 0

    """
    -------------------
    Halstead's Metrics
    ------------------
    Halstead’s goal was to identify measurable properties of software, and the relations between them. 
    These numbers are statically computed from the source code: Effort, Bugs, Length, Difficulty, Time, Vocabulary , Volume
    """
    i = HCHarvester(paths, config2)
    hcResults = i._to_dicts()
  
    halsteadEffort = 0
    halsteadBugs = 0
    halsteadLength = 0 
    halsteadDifficulty = 0
    halsteadTime = 0
    halsteadVocabulary = 0 
    halsteadVolume = 0
    numberOfFiles = 0

    for result in hcResults.values():
        if 'total' in result:
            halsteadEffort += result["total"][9]
            halsteadBugs  += result["total"][11]
            halsteadLength  += result["total"][5]
            halsteadDifficulty += result["total"][8]
            halsteadTime += result["total"][10]
            halsteadVocabulary += result["total"][4]
            halsteadVolume += result["total"][7]
        numberOfFiles += 1

    avgHalsteadEffort = halsteadEffort/numberOfFiles
    avgHalsteadBugs = halsteadBugs/numberOfFiles
    avgHalsteadLength = halsteadLength /numberOfFiles
    avgHalsteadDifficulty = halsteadDifficulty/numberOfFiles
    avgHalsteadTime = halsteadTime/numberOfFiles
    avgHalsteadVocabulary = halsteadVocabulary/numberOfFiles
    avgHalsteadVolume = halsteadVolume/numberOfFiles

    
    """
    ---------------------------------------
    MI Harvester for Maintainability index
    --------------------------------------
    Maintainability Index is a software metric which measures how maintainable (easy to support and change)
    the source code is. The maintainability index is calculated as a factored formula consisting of SLOC (Source Lines Of Code),
    Cyclomatic Complexity and Halstead volume. It is used in several automated software metric tools, including the Microsoft 
    Visual Studio 2010 development environment, which uses a shifted scale (0 to 100) derivative.
    """
    j = MIHarvester(paths, config3)
    miResults = dict(j.filtered_results)

    miVal = 0 
    numOfFiles = 0
    for result in miResults.values():
        if 'mi' in result:
            miVal += result["mi"] 
        numOfFiles += 1

    mi = miVal/numOfFiles
    


    """
    ------------
    Raw Metrics
    -----------
    The following are the definitions employed by Radon:
     - LOC: The total number of lines of code. It does not necessarily correspond to the number of lines in the file.
     - LLOC: The number of logical lines of code. Every logical line of code contains exactly one statement.
     - SLOC: The number of source lines of code - not necessarily corresponding to the LLOC. [sloc]
     - Comments: The number of comment lines. Multi-line strings are not counted as comment since, to the Python interpreter, they are just strings.
     - Multi: The number of lines which represent multi-line strings.  [multi] 
     - Blanks: The number of blank lines (or whitespace-only ones).  [blank]
    """
    k = RawHarvester(paths, config4)
    rawResults = (dict(k.results))

    comments = 0
    lloc = 0
    loc = 0
    for result in rawResults.values():
        if 'comments' in result:
            comments += result['comments']
        if 'lloc' in result:
            lloc += result['lloc']
        if 'loc' in result:
            loc += result['loc']


    data = {
        "numberOfFiles" : len(paths),
        "numberOfLines" : loc,
        "numberOfLogicalLines" : lloc, 
        "numberOfComments" : comments, 
        "cyclomaticComplexity" : cc, 
        "maintainabilityIndex" : mi,
        "halsteadEffort" : avgHalsteadEffort,
        "halsteadBugs" : avgHalsteadBugs,
        "halsteadLength" :avgHalsteadLength,
        "halsteadDifficulty" : avgHalsteadDifficulty,
        "halsteadTime" : avgHalsteadTime, 
        "halsteadVocabulary" : avgHalsteadVocabulary, 
        "halsteadVolume" : avgHalsteadVolume
    }

    return data