From 93c4e20fb8b33ec2c05fcdecbb13030081804176 Mon Sep 17 00:00:00 2001 From: Mattia Campolese Date: Wed, 30 Sep 2020 15:37:36 +0100 Subject: [PATCH 1/6] Adding submodules recursive data in representation --- swift_code_metrics/_metrics.py | 3 ++- swift_code_metrics/tests/test_metrics.py | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/swift_code_metrics/_metrics.py b/swift_code_metrics/_metrics.py index 92326e8..d520f73 100644 --- a/swift_code_metrics/_metrics.py +++ b/swift_code_metrics/_metrics.py @@ -443,7 +443,8 @@ def as_dict(self) -> Dict: return { self.name: { "n_of_files": self.n_of_files, - "metric": self.data.as_dict + "metric": self.data.as_dict, + "submodules": [s.as_dict for s in self.submodules] } } diff --git a/swift_code_metrics/tests/test_metrics.py b/swift_code_metrics/tests/test_metrics.py index 5afa814..015bbf1 100644 --- a/swift_code_metrics/tests/test_metrics.py +++ b/swift_code_metrics/tests/test_metrics.py @@ -399,7 +399,24 @@ def test_dict_repr(self): "nom": 8, "not": 2, "poc": 87.5 - } + }, + "submodules": [ + { + "Helper": { + "n_of_files": 1, + "metric": { + "loc": 1, + "n_a": 8, + "n_c": 4, + "noc": 7, + "nom": 4, + "not": 1, + "poc": 87.5 + }, + "submodules": [] + } + } + ] } }, self.submodule.as_dict) From 8bb59577ad4e555468b8d3b5b65c757b99e90658 Mon Sep 17 00:00:00 2001 From: Mattia Campolese Date: Wed, 30 Sep 2020 15:41:55 +0100 Subject: [PATCH 2/6] Adding submodules metrics to the output JSON report --- swift_code_metrics/_report.py | 1 + .../tests/test_resources/expected_output.json | 349 +++++++++++++++++- 2 files changed, 347 insertions(+), 3 deletions(-) diff --git a/swift_code_metrics/_report.py b/swift_code_metrics/_report.py index e52b322..17e304e 100644 --- a/swift_code_metrics/_report.py +++ b/swift_code_metrics/_report.py @@ -78,6 +78,7 @@ def __framework_analysis(framework: 'Framework', frameworks: List['Framework']) "noi": n_of_imports, "analysis": analysis, "dependencies": dependencies, + "submodules": framework.submodule.as_dict } return { diff --git a/swift_code_metrics/tests/test_resources/expected_output.json b/swift_code_metrics/tests/test_resources/expected_output.json index 423deb0..0c2277c 100644 --- a/swift_code_metrics/tests/test_resources/expected_output.json +++ b/swift_code_metrics/tests/test_resources/expected_output.json @@ -15,6 +15,53 @@ "FoundationFramework(1)", "SecretLib(1)" ], + "submodules": { + "BusinessLogic": { + "n_of_files": 1, + "metric": { + "loc": 51, + "noc": 7, + "n_a": 0, + "n_c": 3, + "nom": 3, + "not": 0, + "poc": 12.069 + }, + "submodules": [ + { + "BusinessLogic": { + "n_of_files": 1, + "metric": { + "loc": 51, + "noc": 7, + "n_a": 0, + "n_c": 3, + "nom": 3, + "not": 0, + "poc": 12.069 + }, + "submodules": [ + { + "BusinessLogic": { + "n_of_files": 1, + "metric": { + "loc": 51, + "noc": 7, + "n_a": 0, + "n_c": 3, + "nom": 3, + "not": 0, + "poc": 12.069 + }, + "submodules": [] + } + } + ] + } + } + ] + } + }, "fan_in": 1, "fan_out": 2, "i": 0.667, @@ -34,6 +81,84 @@ "noi": 0, "analysis": "The code is over commented. Zone of Pain. Highly stable and concrete component - rigid, hard to extend (not abstract). This component should not be volatile (e.g. a stable foundation library such as Strings).", "dependencies": [], + "submodules": { + "FoundationFramework": { + "n_of_files": 3, + "metric": { + "loc": 27, + "noc": 21, + "n_a": 1, + "n_c": 2, + "nom": 3, + "not": 0, + "poc": 43.75 + }, + "submodules": [ + { + "Foundation": { + "n_of_files": 3, + "metric": { + "loc": 27, + "noc": 21, + "n_a": 1, + "n_c": 2, + "nom": 3, + "not": 0, + "poc": 43.75 + }, + "submodules": [ + { + "FoundationFramework": { + "n_of_files": 2, + "metric": { + "loc": 23, + "noc": 14, + "n_a": 1, + "n_c": 1, + "nom": 2, + "not": 0, + "poc": 37.838 + }, + "submodules": [ + { + "Interfaces": { + "n_of_files": 1, + "metric": { + "loc": 12, + "noc": 7, + "n_a": 1, + "n_c": 0, + "nom": 1, + "not": 0, + "poc": 36.842 + }, + "submodules": [] + } + } + ] + } + }, + { + "Shared": { + "n_of_files": 1, + "metric": { + "loc": 4, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 0, + "poc": 63.636 + }, + "submodules": [] + } + } + ] + } + } + ] + } + }, "fan_in": 1, "fan_out": 0, "i": 0.0, @@ -53,6 +178,68 @@ "noi": 0, "analysis": "The code is over commented. Zone of Pain. Highly stable and concrete component - rigid, hard to extend (not abstract). This component should not be volatile (e.g. a stable foundation library such as Strings).", "dependencies": [], + "submodules": { + "SecretLib": { + "n_of_files": 2, + "metric": { + "loc": 12, + "noc": 14, + "n_a": 0, + "n_c": 2, + "nom": 2, + "not": 0, + "poc": 53.846 + }, + "submodules": [ + { + "Foundation": { + "n_of_files": 2, + "metric": { + "loc": 12, + "noc": 14, + "n_a": 0, + "n_c": 2, + "nom": 2, + "not": 0, + "poc": 53.846 + }, + "submodules": [ + { + "SecretLib": { + "n_of_files": 1, + "metric": { + "loc": 8, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 0, + "poc": 46.667 + }, + "submodules": [] + } + }, + { + "Shared": { + "n_of_files": 1, + "metric": { + "loc": 4, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 0, + "poc": 63.636 + }, + "submodules": [] + } + } + ] + } + } + ] + } + }, "fan_in": 1, "fan_out": 0, "i": 0.0, @@ -74,6 +261,37 @@ "dependencies": [ "BusinessLogic(1)" ], + "submodules": { + "SwiftCodeMetricsExample": { + "n_of_files": 2, + "metric": { + "loc": 22, + "noc": 14, + "n_a": 0, + "n_c": 2, + "nom": 4, + "not": 0, + "poc": 38.889 + }, + "submodules": [ + { + "SwiftCodeMetricsExample": { + "n_of_files": 2, + "metric": { + "loc": 22, + "noc": 14, + "n_a": 0, + "n_c": 2, + "nom": 4, + "not": 0, + "poc": 38.889 + }, + "submodules": [] + } + } + ] + } + }, "fan_in": 0, "fan_out": 1, "i": 1.0, @@ -96,7 +314,54 @@ "analysis": "The code is over commented. ", "dependencies": [ "BusinessLogic(1)" - ] + ], + "submodules": { + "BusinessLogic_Test": { + "n_of_files": 1, + "metric": { + "loc": 7, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 1, + "poc": 50.0 + }, + "submodules": [ + { + "BusinessLogic": { + "n_of_files": 1, + "metric": { + "loc": 7, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 1, + "poc": 50.0 + }, + "submodules": [ + { + "BusinessLogicTests": { + "n_of_files": 1, + "metric": { + "loc": 7, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 1, + "poc": 50.0 + }, + "submodules": [] + } + } + ] + } + } + ] + } + } } }, { @@ -112,7 +377,54 @@ "analysis": "", "dependencies": [ "FoundationFramework(2)" - ] + ], + "submodules": { + "FoundationFrameworkTests": { + "n_of_files": 2, + "metric": { + "loc": 41, + "noc": 14, + "n_a": 0, + "n_c": 2, + "nom": 5, + "not": 3, + "poc": 25.455 + }, + "submodules": [ + { + "Foundation": { + "n_of_files": 2, + "metric": { + "loc": 41, + "noc": 14, + "n_a": 0, + "n_c": 2, + "nom": 5, + "not": 3, + "poc": 25.455 + }, + "submodules": [ + { + "FoundationFrameworkTests": { + "n_of_files": 2, + "metric": { + "loc": 41, + "noc": 14, + "n_a": 0, + "n_c": 2, + "nom": 5, + "not": 3, + "poc": 25.455 + }, + "submodules": [] + } + } + ] + } + } + ] + } + } } }, { @@ -128,7 +440,38 @@ "analysis": "The code is over commented. ", "dependencies": [ "SwiftCodeMetricsExample(1)" - ] + ], + "submodules": { + "SwiftCodeMetricsExampleTests_Test": { + "n_of_files": 1, + "metric": { + "loc": 5, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 1, + "poc": 58.333 + }, + "submodules": [ + { + "SwiftCodeMetricsExampleTests": { + "n_of_files": 1, + "metric": { + "loc": 5, + "noc": 7, + "n_a": 0, + "n_c": 1, + "nom": 1, + "not": 1, + "poc": 58.333 + }, + "submodules": [] + } + } + ] + } + } } } ], From 0e33fe2edd000970106b5d6baa07df0ec5f8dd53 Mon Sep 17 00:00:00 2001 From: Mattia Campolese Date: Wed, 30 Sep 2020 17:06:25 +0100 Subject: [PATCH 3/6] Refactor code to isolate graphs creation logic --- .../{_graphics.py => _graph_helpers.py} | 0 .../{_presenter.py => _graphs_presenter.py} | 2 +- swift_code_metrics/_graphs_renderer.py | 58 +++++++++++++++++++ swift_code_metrics/scm.py | 51 ++++------------ 4 files changed, 69 insertions(+), 42 deletions(-) rename swift_code_metrics/{_graphics.py => _graph_helpers.py} (100%) rename swift_code_metrics/{_presenter.py => _graphs_presenter.py} (99%) create mode 100644 swift_code_metrics/_graphs_renderer.py diff --git a/swift_code_metrics/_graphics.py b/swift_code_metrics/_graph_helpers.py similarity index 100% rename from swift_code_metrics/_graphics.py rename to swift_code_metrics/_graph_helpers.py diff --git a/swift_code_metrics/_presenter.py b/swift_code_metrics/_graphs_presenter.py similarity index 99% rename from swift_code_metrics/_presenter.py rename to swift_code_metrics/_graphs_presenter.py index a9fcbb0..ae004e9 100644 --- a/swift_code_metrics/_presenter.py +++ b/swift_code_metrics/_graphs_presenter.py @@ -1,5 +1,5 @@ from swift_code_metrics._metrics import Metrics -from ._graphics import Graph +from ._graph_helpers import Graph from functional import seq from math import ceil diff --git a/swift_code_metrics/_graphs_renderer.py b/swift_code_metrics/_graphs_renderer.py new file mode 100644 index 0000000..d2e9052 --- /dev/null +++ b/swift_code_metrics/_graphs_renderer.py @@ -0,0 +1,58 @@ +from ._metrics import Framework, Metrics +from ._report import Report, ReportingHelpers +from dataclasses import dataclass +from typing import List +from ._graphs_presenter import GraphPresenter + + +@dataclass +class GraphsRender: + """ + Component responsible to generate the needed graphs for the given report. + """ + artifacts_path: str + test_frameworks: List['Framework'] + non_test_frameworks: List['Framework'] + report: 'Report' + + def render_graphs(self): + graph_presenter = GraphPresenter(self.artifacts_path) + + # Sorted data plots + non_test_reports_sorted_data = { + 'N. of classes and structs': lambda fr: fr.data.number_of_concrete_data_structures, + 'Lines Of Code - LOC': lambda fr: fr.data.loc, + 'Number Of Comments - NOC': lambda fr: fr.data.noc, + 'N. of imports - NOI': lambda fr: fr.number_of_imports + } + + tests_reports_sorted_data = { + 'Number of tests - NOT': lambda fr: fr.data.number_of_tests + } + + # Non-test graphs + for title, framework_function in non_test_reports_sorted_data.items(): + graph_presenter.sorted_data_plot(title, self.non_test_frameworks, framework_function) + + # Distance from the main sequence + all_frameworks = self.test_frameworks + self.non_test_frameworks + graph_presenter.distance_from_main_sequence_plot(self.non_test_frameworks, + lambda fr: Metrics.instability(fr, all_frameworks), + lambda fr: Metrics.abstractness(fr)) + + # Dependency graph + graph_presenter.dependency_graph(self.non_test_frameworks, + self.report.non_test_framework_aggregate.loc, + self.report.non_test_framework_aggregate.n_o_i) + + # Code distribution + graph_presenter.pie_plot('Code distribution', self.non_test_frameworks, + lambda fr: + ReportingHelpers.decimal_format(fr.data.loc + / self.report.non_test_framework_aggregate.loc)) + + # Test graphs + for title, framework_function in tests_reports_sorted_data.items(): + graph_presenter.sorted_data_plot(title, self.test_frameworks, framework_function) + + diff --git a/swift_code_metrics/scm.py b/swift_code_metrics/scm.py index c1828a1..0948132 100644 --- a/swift_code_metrics/scm.py +++ b/swift_code_metrics/scm.py @@ -1,10 +1,9 @@ -#!/usr/bin/python +#!/usr/bin/python3 from argparse import ArgumentParser -from ._helpers import Log,ReportingHelpers +from ._helpers import Log from ._analyzer import Inspector -from ._metrics import Metrics from .version import VERSION import sys @@ -74,43 +73,13 @@ def main(): sys.exit(0) # Creates graphs - from ._presenter import GraphPresenter - graph_presenter = GraphPresenter(artifacts) + from ._graphs_renderer import GraphsRender non_test_frameworks = analyzer.filtered_frameworks(is_test=False) test_frameworks = analyzer.filtered_frameworks(is_test=True) - - # Sorted data plots - non_test_reports_sorted_data = { - 'N. of classes and structs': lambda fr: fr.data.number_of_concrete_data_structures, - 'Lines Of Code - LOC': lambda fr: fr.data.loc, - 'Number Of Comments - NOC': lambda fr: fr.data.noc, - 'N. of imports - NOI': lambda fr: fr.number_of_imports - } - - tests_reports_sorted_data = { - 'Number of tests - NOT': lambda fr: fr.data.number_of_tests - } - - # Non-test graphs - for title, framework_function in non_test_reports_sorted_data.items(): - graph_presenter.sorted_data_plot(title, non_test_frameworks, framework_function) - - # Distance from the main sequence - graph_presenter.distance_from_main_sequence_plot(non_test_frameworks, - lambda fr: Metrics.instability(fr, analyzer.frameworks), - lambda fr: Metrics.abstractness(fr)) - - # Dependency graph - graph_presenter.dependency_graph(non_test_frameworks, - analyzer.report.non_test_framework_aggregate.loc, - analyzer.report.non_test_framework_aggregate.n_o_i) - - # Code distribution - graph_presenter.pie_plot('Code distribution', non_test_frameworks, - lambda fr: - ReportingHelpers.decimal_format(fr.data.loc - / analyzer.report.non_test_framework_aggregate.loc)) - - # Test graphs - for title, framework_function in tests_reports_sorted_data.items(): - graph_presenter.sorted_data_plot(title, test_frameworks, framework_function) + graphs_renderer = GraphsRender( + artifacts_path=artifacts, + test_frameworks=test_frameworks, + non_test_frameworks=non_test_frameworks, + report=analyzer.report + ) + graphs_renderer.render_graphs() From 99c94b0fd146df9f1e9ffdd72be9d7989a4abdd7 Mon Sep 17 00:00:00 2001 From: Mattia Campolese Date: Wed, 30 Sep 2020 20:25:10 +0100 Subject: [PATCH 4/6] Render submodule LOC charts for each framework --- swift_code_metrics/_analyzer.py | 2 +- swift_code_metrics/_graphs_presenter.py | 12 +++++- swift_code_metrics/_graphs_renderer.py | 50 +++++++++++++++++++--- swift_code_metrics/_metrics.py | 29 ++++++++++++- swift_code_metrics/tests/test_metrics.py | 53 ++++++++++++++++++++---- 5 files changed, 130 insertions(+), 16 deletions(-) diff --git a/swift_code_metrics/_analyzer.py b/swift_code_metrics/_analyzer.py index 86e3c0a..86b2713 100644 --- a/swift_code_metrics/_analyzer.py +++ b/swift_code_metrics/_analyzer.py @@ -83,7 +83,7 @@ def __populate_submodule(framework: 'Framework', swift_file: 'SwiftFile'): if len(list(existing_submodule)) > 0: submodule = existing_submodule.first() else: - new_submodule = SubModule(name=path, files=[], submodules=[]) + new_submodule = SubModule(name=path, files=[], submodules=[], parent=submodule) submodule.submodules.append(new_submodule) submodule = new_submodule diff --git a/swift_code_metrics/_graphs_presenter.py b/swift_code_metrics/_graphs_presenter.py index ae004e9..104f9f2 100644 --- a/swift_code_metrics/_graphs_presenter.py +++ b/swift_code_metrics/_graphs_presenter.py @@ -20,7 +20,7 @@ def sorted_data_plot(self, title, list_of_frameworks, f_of_framework): self.graph.bar_plot(title, plot_data) - def pie_plot(self, title, list_of_frameworks, f_of_framework): + def frameworks_pie_plot(self, title, list_of_frameworks, f_of_framework): """ Renders the percentage distribution data related to a framework in a pie chart. :param title: The chart title @@ -40,6 +40,16 @@ def pie_plot(self, title, list_of_frameworks, f_of_framework): self.graph.pie_plot(title, plot_data[0], plot_data[1], plot_data[2]) + def submodules_pie_plot(self, title, list_of_submodules, f_of_submodules): + sorted_data = sorted(list(map(lambda s: (f_of_submodules(s), + s.name), + list_of_submodules)), + key=lambda tup: tup[0]) + plot_data = (list(map(lambda f: f[0], sorted_data)), + list(map(lambda f: f[1], sorted_data))) + + self.graph.pie_plot(title, plot_data[0], plot_data[1], plot_data[1]) + def distance_from_main_sequence_plot(self, list_of_frameworks, x_ax_f_framework, y_ax_f_framework): """ Renders framework related data to a scattered plot diff --git a/swift_code_metrics/_graphs_renderer.py b/swift_code_metrics/_graphs_renderer.py index d2e9052..71e6442 100644 --- a/swift_code_metrics/_graphs_renderer.py +++ b/swift_code_metrics/_graphs_renderer.py @@ -1,4 +1,4 @@ -from ._metrics import Framework, Metrics +from ._metrics import Framework, Metrics, SubModule from ._report import Report, ReportingHelpers from dataclasses import dataclass from typing import List @@ -18,6 +18,13 @@ class GraphsRender: def render_graphs(self): graph_presenter = GraphPresenter(self.artifacts_path) + # Project graphs + self.__project_graphs(graph_presenter=graph_presenter) + + # Submodules graphs + self.__submodules_graphs(graph_presenter=graph_presenter) + + def __project_graphs(self, graph_presenter: 'GraphPresenter'): # Sorted data plots non_test_reports_sorted_data = { 'N. of classes and structs': lambda fr: fr.data.number_of_concrete_data_structures, @@ -46,13 +53,46 @@ def render_graphs(self): self.report.non_test_framework_aggregate.n_o_i) # Code distribution - graph_presenter.pie_plot('Code distribution', self.non_test_frameworks, - lambda fr: - ReportingHelpers.decimal_format(fr.data.loc - / self.report.non_test_framework_aggregate.loc)) + graph_presenter.frameworks_pie_plot('Code distribution', self.non_test_frameworks, + lambda fr: + ReportingHelpers.decimal_format(fr.data.loc + / self.report.non_test_framework_aggregate.loc)) # Test graphs for title, framework_function in tests_reports_sorted_data.items(): graph_presenter.sorted_data_plot(title, self.test_frameworks, framework_function) + def __submodules_graphs(self, graph_presenter: 'GraphPresenter'): + for framework in self.non_test_frameworks: + GraphsRender.__render_submodules(parent='Code distribution', + root_submodule=framework.submodule, + graph_presenter=graph_presenter) + + @staticmethod + def __render_submodules(parent: str, root_submodule: 'SubModule', graph_presenter: 'GraphPresenter'): + current_submodule = root_submodule.next + while current_submodule != root_submodule: + GraphsRender.__render_submodule_loc(parent=parent, + submodule=current_submodule, + graph_presenter=graph_presenter) + current_submodule = current_submodule.next + + @staticmethod + def __render_submodule_loc(parent: str, submodule: 'SubModule', graph_presenter: 'GraphPresenter'): + submodules = submodule.submodules + if len(submodules) == 0: + return + total_loc = submodule.data.loc + if total_loc == submodules[0].data.loc: + # Single submodule folder - not useful + return + if len(submodule.files) > 0: + # Add a submodule with the name of the current module to represent the root slice + submodules = submodules + [SubModule(name=submodule.name, + files=submodule.files, + submodules=[], + parent=submodule)] + chart_name = f'{parent} {submodule.path}' + graph_presenter.submodules_pie_plot(chart_name, submodules, + lambda s: ReportingHelpers.decimal_format(s.data.loc / total_loc)) diff --git a/swift_code_metrics/_metrics.py b/swift_code_metrics/_metrics.py index d520f73..947026d 100644 --- a/swift_code_metrics/_metrics.py +++ b/swift_code_metrics/_metrics.py @@ -344,7 +344,8 @@ def __init__(self, name: str, is_test_framework: bool = False): self.submodule = SubModule( name=self.name, files=[], - submodules=[] + submodules=[], + parent=None ) self.is_test_framework = is_test_framework @@ -423,6 +424,27 @@ class SubModule: name: str files: List['SwiftFile'] submodules: List['SubModule'] + parent: Optional['SubModule'] + + @property + def next(self) -> 'SubModule': + if len(self.submodules) == 0: + if self.parent is None: + return self + else: + return self.submodules[0] + + next_level = self.parent + current_level = self + while next_level is not None: + next_i = next_level.submodules.index(current_level) + 1 + if next_i < len(next_level.submodules): + return next_level.submodules[next_i] + else: + current_level = next_level + next_level = next_level.parent + + return current_level @property def n_of_files(self) -> int: @@ -430,6 +452,11 @@ def n_of_files(self) -> int: seq([s.n_of_files for s in self.submodules]).reduce(lambda a, b: a + b) return len(self.files) + sub_files + @property + def path(self) -> str: + parent_path = "" if not self.parent else f'{self.parent.path} > ' + return f'{parent_path}{self.name}' + @property def data(self) -> 'SyntheticData': root_module_files = [SyntheticData()] if (len(self.files) == 0) else \ diff --git a/swift_code_metrics/tests/test_metrics.py b/swift_code_metrics/tests/test_metrics.py index 015bbf1..421bb98 100644 --- a/swift_code_metrics/tests/test_metrics.py +++ b/swift_code_metrics/tests/test_metrics.py @@ -353,18 +353,55 @@ def setUp(self): self.submodule = SubModule( name="BusinessModule", files=[example_swiftfile], - submodules=[ - SubModule( - name="Helper", - files=[example_file2], - submodules=[] - ) - ] + submodules=[], + parent=None ) + self.helper = SubModule( + name="Helper", + files=[example_file2], + submodules=[], + parent=self.submodule + ) + self.additional_module = SubModule( + name="AdditionalModule", + files=[example_file2], + submodules=[], + parent=self.submodule + ) + self.additional_submodule = SubModule( + name="AdditionalSubModule", + files=[example_file2], + submodules=[], + parent=self.additional_module + ) + self.additional_module.submodules.append(self.additional_submodule) + self.submodule.submodules.append(self.helper) def test_n_of_files(self): self.assertEqual(2, self.submodule.n_of_files) + def test_path(self): + self.submodule.submodules.append(self.additional_module) + self.assertEqual('BusinessModule > AdditionalModule > AdditionalSubModule', self.additional_submodule.path) + + def test_next_only_module(self): + self.additional_submodule.parent = None + self.assertEqual(self.additional_submodule, self.additional_submodule.next) + + def test_next_closed_circle(self): + self.submodule.submodules.append(self.additional_module) + """ + * + / \ + H AM + \ + AS + """ + self.assertEqual(self.helper, self.submodule.next) + self.assertEqual(self.additional_module, self.helper.next) + self.assertEqual(self.additional_submodule, self.additional_module.next) + self.assertEqual(self.submodule, self.additional_submodule.next) + def test_data(self): data = SyntheticData( loc=2, @@ -385,7 +422,7 @@ def test_empty_data(self): number_of_methods=0, number_of_tests=0 ) - self.assertEqual(data, SubModule(name="", files=[], submodules=[]).data) + self.assertEqual(data, SubModule(name="", files=[], submodules=[], parent=None).data) def test_dict_repr(self): self.assertEqual({ From 5290d21bbe19096caa209ff96111dbd6b21f6e28 Mon Sep 17 00:00:00 2001 From: Mattia Campolese Date: Wed, 30 Sep 2020 20:44:39 +0100 Subject: [PATCH 5/6] Improved plot layout --- swift_code_metrics/_graph_helpers.py | 4 ++-- swift_code_metrics/_graphs_renderer.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/swift_code_metrics/_graph_helpers.py b/swift_code_metrics/_graph_helpers.py index f0af0a1..8c8a086 100644 --- a/swift_code_metrics/_graph_helpers.py +++ b/swift_code_metrics/_graph_helpers.py @@ -27,8 +27,8 @@ def pie_plot(self, title, sizes, labels, legend): plt.title(title) patches, _, _ = plt.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90) plt.legend(patches, legend, loc='best') - plt.tight_layout() plt.axis('equal') + plt.tight_layout() self.__render(plt, title) @@ -84,7 +84,7 @@ def __render(self, plt, name): plt.show() else: save_file = self.__file_path(name) - plt.savefig(save_file) + plt.savefig(save_file, bbox_inches='tight') plt.close() def __file_path(self, name, extension='.pdf'): diff --git a/swift_code_metrics/_graphs_renderer.py b/swift_code_metrics/_graphs_renderer.py index 71e6442..bba9b75 100644 --- a/swift_code_metrics/_graphs_renderer.py +++ b/swift_code_metrics/_graphs_renderer.py @@ -87,8 +87,8 @@ def __render_submodule_loc(parent: str, submodule: 'SubModule', graph_presenter: # Single submodule folder - not useful return if len(submodule.files) > 0: - # Add a submodule with the name of the current module to represent the root slice - submodules = submodules + [SubModule(name=submodule.name, + # Add a submodule to represent the root slice + submodules = submodules + [SubModule(name='(root)', files=submodule.files, submodules=[], parent=submodule)] From be8bc539b37a5dc91a6290fde7a30492f485c61b Mon Sep 17 00:00:00 2001 From: Mattia Campolese Date: Fri, 2 Oct 2020 09:37:02 +0100 Subject: [PATCH 6/6] Improved code style --- swift_code_metrics/_graphs_renderer.py | 8 +++----- swift_code_metrics/_helpers.py | 2 +- swift_code_metrics/tests/test_metrics.py | 12 +++++------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/swift_code_metrics/_graphs_renderer.py b/swift_code_metrics/_graphs_renderer.py index bba9b75..1e5edf1 100644 --- a/swift_code_metrics/_graphs_renderer.py +++ b/swift_code_metrics/_graphs_renderer.py @@ -1,5 +1,5 @@ -from ._metrics import Framework, Metrics, SubModule -from ._report import Report, ReportingHelpers +from ._metrics import Metrics, SubModule +from ._report import ReportingHelpers from dataclasses import dataclass from typing import List from ._graphs_presenter import GraphPresenter @@ -7,9 +7,7 @@ @dataclass class GraphsRender: - """ - Component responsible to generate the needed graphs for the given report. - """ + "Component responsible to generate the needed graphs for the given report." artifacts_path: str test_frameworks: List['Framework'] non_test_frameworks: List['Framework'] diff --git a/swift_code_metrics/_helpers.py b/swift_code_metrics/_helpers.py index 1bd3c69..8ea5368 100644 --- a/swift_code_metrics/_helpers.py +++ b/swift_code_metrics/_helpers.py @@ -1,7 +1,7 @@ import re import logging import json -from typing import List,Dict +from typing import Dict from functional import seq diff --git a/swift_code_metrics/tests/test_metrics.py b/swift_code_metrics/tests/test_metrics.py index 421bb98..860c76a 100644 --- a/swift_code_metrics/tests/test_metrics.py +++ b/swift_code_metrics/tests/test_metrics.py @@ -390,13 +390,11 @@ def test_next_only_module(self): def test_next_closed_circle(self): self.submodule.submodules.append(self.additional_module) - """ - * - / \ - H AM - \ - AS - """ + # * + # / \ + # H AM + # \ + # AS self.assertEqual(self.helper, self.submodule.next) self.assertEqual(self.additional_module, self.helper.next) self.assertEqual(self.additional_submodule, self.additional_module.next)