wily\operators\__init__.py
-- -- --- --- --- --- --- --- ------- ------- ------- | """Models and types for "operators" the basic measure of a module that measures code."""
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | from collections import namedtuple
-- -- --- --- --- --- --- --- ------- ------- ------- | from enum import Enum
-- -- --- --- --- --- --- --- ------- ------- ------- | from functools import lru_cache
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
01 -- --- --- --- --- --- --- ------- ------- ------- | class MetricType(Enum):
01 -- --- --- --- --- --- --- ------- ------- ------- | """Type of metric, used in trends."""
01 -- --- --- --- --- --- --- ------- ------- ------- |
01 -- --- --- --- --- --- --- ------- ------- ------- | AimLow = 1 # Low is good, high is bad
01 -- --- --- --- --- --- --- ------- ------- ------- | AimHigh = 2 # High is good, low is bad
01 -- --- --- --- --- --- --- ------- ------- ------- | Informational = 3 # Doesn't matter
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | Metric = namedtuple("Metric", "name description type measure aggregate")
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | GOOD_COLORS = {
-- -- --- --- --- --- --- --- ------- ------- ------- | MetricType.AimHigh: 32,
-- -- --- --- --- --- --- --- ------- ------- ------- | MetricType.AimLow: 31,
-- -- --- --- --- --- --- --- ------- ------- ------- | MetricType.Informational: 33,
-- -- --- --- --- --- --- --- ------- ------- ------- | }
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | BAD_COLORS = {
-- -- --- --- --- --- --- --- ------- ------- ------- | MetricType.AimHigh: 31,
-- -- --- --- --- --- --- --- ------- ------- ------- | MetricType.AimLow: 32,
-- -- --- --- --- --- --- --- ------- ------- ------- | MetricType.Informational: 33,
-- -- --- --- --- --- --- --- ------- ------- ------- | }
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
01 -- --- --- --- --- --- --- ------- ------- ------- | class OperatorLevel(Enum):
01 -- --- --- --- --- --- --- ------- ------- ------- | """Level of operator."""
01 -- --- --- --- --- --- --- ------- ------- ------- |
01 -- --- --- --- --- --- --- ------- ------- ------- | File = 1
01 -- --- --- --- --- --- --- ------- ------- ------- | Object = 2
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- | class BaseOperator(object):
02 -- --- --- --- --- --- --- ------- ------- ------- | """Abstract Operator Class."""
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- | """Name of the operator."""
02 -- --- --- --- --- --- --- ------- ------- ------- | name = "abstract"
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- | """Default settings."""
02 -- --- --- --- --- --- --- ------- ------- ------- | defaults = {}
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- | """Available metrics as a list of tuple ("name"<str>, "description"<str>, "type"<type>, "metric_type"<MetricType>)."""
02 -- --- --- --- --- --- --- ------- ------- ------- | metrics = ()
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- | """Which metric is the default to display in the report command."""
02 -- --- --- --- --- --- --- ------- ------- ------- | default_metric_index = None
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 -- --- --- --- --- --- --- ------- ------- ------- | """Level at which the operator goes to."""
02 -- --- --- --- --- --- --- ------- ------- ------- | level = OperatorLevel.File
02 -- --- --- --- --- --- --- ------- ------- ------- |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def run(self, module, options):
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | Run the operator.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :param module: The target module path.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :type module: ``str``
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :param options: Any runtime options.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :type options: ``dict``
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :return: The operator results.
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :rtype: ``dict``
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """
02 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | raise NotImplementedError
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.operators.cyclomatic import CyclomaticComplexityOperator
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.operators.maintainability import MaintainabilityIndexOperator
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.operators.raw import RawMetricsOperator
-- -- --- --- --- --- --- --- ------- ------- ------- | from wily.operators.halstead import HalsteadOperator
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | """Type for an operator."""
-- -- --- --- --- --- --- --- ------- ------- ------- | Operator = namedtuple("Operator", "name cls description level")
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_CYCLOMATIC = Operator(
-- -- --- --- --- --- --- --- ------- ------- ------- | name="cyclomatic",
-- -- --- --- --- --- --- --- ------- ------- ------- | cls=CyclomaticComplexityOperator,
-- -- --- --- --- --- --- --- ------- ------- ------- | description="Cyclomatic Complexity of modules",
-- -- --- --- --- --- --- --- ------- ------- ------- | level=OperatorLevel.Object,
-- -- --- --- --- --- --- --- ------- ------- ------- | )
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_RAW = Operator(
-- -- --- --- --- --- --- --- ------- ------- ------- | name="raw",
-- -- --- --- --- --- --- --- ------- ------- ------- | cls=RawMetricsOperator,
-- -- --- --- --- --- --- --- ------- ------- ------- | description="Raw Python statistics",
-- -- --- --- --- --- --- --- ------- ------- ------- | level=OperatorLevel.File,
-- -- --- --- --- --- --- --- ------- ------- ------- | )
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_MAINTAINABILITY = Operator(
-- -- --- --- --- --- --- --- ------- ------- ------- | name="maintainability",
-- -- --- --- --- --- --- --- ------- ------- ------- | cls=MaintainabilityIndexOperator,
-- -- --- --- --- --- --- --- ------- ------- ------- | description="Maintainability index (lines of code and branching)",
-- -- --- --- --- --- --- --- ------- ------- ------- | level=OperatorLevel.File,
-- -- --- --- --- --- --- --- ------- ------- ------- | )
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_HALSTEAD = Operator(
-- -- --- --- --- --- --- --- ------- ------- ------- | name="halstead",
-- -- --- --- --- --- --- --- ------- ------- ------- | cls=HalsteadOperator,
-- -- --- --- --- --- --- --- ------- ------- ------- | description="Halstead metrics",
-- -- --- --- --- --- --- --- ------- ------- ------- | level=OperatorLevel.Object,
-- -- --- --- --- --- --- --- ------- ------- ------- | )
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | """Dictionary of all operators"""
-- -- --- --- --- --- --- --- ------- ------- ------- | ALL_OPERATORS = {
-- -- --- --- --- --- --- --- ------- ------- ------- | operator.name: operator
-- -- --- --- --- --- --- --- ------- ------- ------- | for operator in {
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_CYCLOMATIC,
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_MAINTAINABILITY,
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_RAW,
-- -- --- --- --- --- --- --- ------- ------- ------- | OPERATOR_HALSTEAD,
-- -- --- --- --- --- --- --- ------- ------- ------- | }
-- -- --- --- --- --- --- --- ------- ------- ------- | }
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | """Set of all metrics"""
-- -- --- --- --- --- --- --- ------- ------- ------- | ALL_METRICS = {
-- -- --- --- --- --- --- --- ------- ------- ------- | (operator, metric)
-- -- --- --- --- --- --- --- ------- ------- ------- | for operator in ALL_OPERATORS.values()
-- -- --- --- --- --- --- --- ------- ------- ------- | for metric in operator.cls.metrics
-- -- --- --- --- --- --- --- ------- ------- ------- | }
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | @lru_cache(maxsize=128)
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | def resolve_operator(name):
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | """
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | Get the :namedtuple:`wily.operators.Operator` for a given name.
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :param name: The name of the operator
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :return: The operator type
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | """
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | if name.lower() in ALL_OPERATORS:
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | return ALL_OPERATORS[name.lower()]
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | else:
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | raise ValueError(f"Operator {name} not recognised.")
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def resolve_operators(operators):
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | Resolve a list of operator names to their corresponding types.
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :param operators: The list of operators
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :type operators: iterable or ``str``
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :rtype: ``list`` of :class:`Operator`
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """
-- 02 000 000 000 000 000 000 0000.00 0000.00 0000.00 | return [resolve_operator(operator) for operator in iter(operators)]
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | @lru_cache(maxsize=128)
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | def resolve_metric(metric):
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | Resolve metric key to a given target.
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :param metric: the metric name.
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :type metric: ``str``
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 |
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | :rtype: :class:`Metric`
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | """
-- 01 000 000 000 000 000 000 0000.00 0000.00 0000.00 | return resolve_metric_as_tuple(metric)[1]
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- | @lru_cache(maxsize=128)
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | def resolve_metric_as_tuple(metric):
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | """
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | Resolve metric key to a given target.
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | :param metric: the metric name.
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | :type metric: ``str``
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | :rtype: :class:`Metric`
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | """
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | if "." in metric:
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | _, metric = metric.split(".")
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 |
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | r = [(operator, match) for operator, match in ALL_METRICS if match[0] == metric]
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | if not r or len(r) == 0:
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | raise ValueError(f"Metric {metric} not recognised.")
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | else:
-- 06 004 008 005 009 012 014 0050.19 0112.93 0002.25 | return r[0]
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- -- --- --- --- --- --- --- ------- ------- ------- |
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | def get_metric(revision, operator, path, key):
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | """
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | Get a metric from the cache.
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :param revision: The revision data.
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :type revision: ``dict``
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :param operator: The operator name.
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :type operator: ``str``
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :param path: The path to the file/function
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :type path: ``str``
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :param key: The key of the data
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :type key: ``str``
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 |
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :return: Data from the cache
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | :rtype: ``dict``
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | """
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | if ":" in path:
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | part, entry = path.split(":")
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | val = revision[operator][part]["detailed"][entry][key]
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | else:
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | val = revision[operator][path]["total"][key]
-- 02 001 002 001 002 003 003 0004.75 0002.38 0000.50 | return val