metripy 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of metripy might be problematic. Click here for more details.

Files changed (27) hide show
  1. metripy/Application/Application.py +2 -3
  2. metripy/Application/Config/Config.py +4 -3
  3. metripy/Application/Config/File/ConfigFileReaderFactory.py +2 -1
  4. metripy/Application/Config/File/ConfigFileReaderInterface.py +70 -3
  5. metripy/Application/Config/File/JsonConfigFileReader.py +2 -72
  6. metripy/Application/Config/File/YamlConfigFileReader.py +17 -0
  7. metripy/Application/Config/Parser.py +0 -2
  8. metripy/Application/Config/ProjectConfig.py +4 -3
  9. metripy/Application/Info.py +9 -2
  10. metripy/LangAnalyzer/Python/PythonAnalyzer.py +1 -1
  11. metripy/Metric/Code/Segmentor.py +2 -0
  12. metripy/Report/Html/DependencyPageRenderer.py +21 -0
  13. metripy/Report/Html/FilesPageRenderer.py +28 -0
  14. metripy/Report/Html/GitAnalysisPageRenderer.py +55 -0
  15. metripy/Report/Html/IndexPageRenderer.py +40 -0
  16. metripy/Report/Html/PageRenderer.py +43 -0
  17. metripy/Report/Html/PageRendererFactory.py +37 -0
  18. metripy/Report/Html/Reporter.py +34 -334
  19. metripy/Report/Html/TopOffendersPageRenderer.py +84 -0
  20. metripy/Report/Html/TrendsPageRenderer.py +114 -0
  21. metripy/Report/ReporterFactory.py +4 -2
  22. {metripy-0.3.0.dist-info → metripy-0.3.1.dist-info}/METADATA +1 -1
  23. {metripy-0.3.0.dist-info → metripy-0.3.1.dist-info}/RECORD +27 -18
  24. {metripy-0.3.0.dist-info → metripy-0.3.1.dist-info}/WHEEL +0 -0
  25. {metripy-0.3.0.dist-info → metripy-0.3.1.dist-info}/entry_points.txt +0 -0
  26. {metripy-0.3.0.dist-info → metripy-0.3.1.dist-info}/licenses/LICENSE +0 -0
  27. {metripy-0.3.0.dist-info → metripy-0.3.1.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,12 @@
1
- import json
2
1
  import os
3
2
  import shutil
4
3
  from datetime import datetime
5
4
 
6
- from py_template_engine import TemplateEngine
7
5
 
8
6
  from metripy.Application.Config.ReportConfig import ReportConfig
9
7
  from metripy.Component.Output.CliOutput import CliOutput
10
- from metripy.Dependency.Dependency import Dependency
11
- from metripy.Metric.Code.FileMetrics import FileMetrics
12
- from metripy.Metric.Code.Segmentor import Segmentor
13
- from metripy.Metric.FileTree.FileTreeParser import FileTreeParser
14
8
  from metripy.Metric.ProjectMetrics import ProjectMetrics
9
+ from metripy.Report.Html.PageRendererFactory import PageRendererFactory
15
10
  from metripy.Report.ReporterInterface import ReporterInterface
16
11
 
17
12
 
@@ -22,6 +17,11 @@ class Reporter(ReporterInterface):
22
17
  self.config: ReportConfig = config
23
18
  self.output = output
24
19
  self.template_dir = os.path.join(os.getcwd(), "templates/html_report")
20
+ self.project_name = project_name
21
+
22
+ self.page_renderer_factory = PageRendererFactory(
23
+ self.template_dir, self.config.path, self.project_name
24
+ )
25
25
 
26
26
  self.global_template_args = {
27
27
  "project_name": project_name,
@@ -64,361 +64,61 @@ class Reporter(ReporterInterface):
64
64
  # shutil.copytree(os.path.join(self.template_dir, "fonts"), os.path.join(self.config.path, "fonts"), dirs_exist_ok=True)
65
65
 
66
66
  # copy logo, lies 2 down from the templates directory
67
- shutil.copy(os.path.join(self.template_dir, "../..", "logo.svg"), os.path.join(self.config.path, "images", "logo.svg"))
67
+ shutil.copy(
68
+ os.path.join(self.template_dir, "../..", "logo.svg"),
69
+ os.path.join(self.config.path, "images", "logo.svg"),
70
+ )
68
71
 
69
72
  # Render main pages
70
73
  self.render_index_page(metrics)
71
74
  self.render_files_page(metrics)
75
+ self.render_top_offenders_page(metrics)
72
76
  self.render_git_analysis_page(metrics)
73
77
  self.render_dependencies_page(metrics)
74
- self.render_top_offenders_page(metrics)
75
78
  self.render_trends_page(metrics)
76
79
 
77
80
  self.output.writeln(
78
81
  f"<success>HTML report generated in {self.config.path} directory</success>"
79
82
  )
80
-
81
- def render_template(self, template_name: str, data: dict) -> str:
82
- engine = TemplateEngine(os.path.join(self.template_dir, template_name))
83
- content = engine.render(**data)
84
- with open(os.path.join(self.config.path, template_name), "w") as file:
85
- file.write(content)
86
-
87
- def render_trends_page(self, metrics: ProjectMetrics):
88
- def compile(file: FileMetrics) -> dict:
89
- return {
90
- "name": file.full_name,
91
- "path": file.full_name,
92
- "complexity_current": file.totalCc,
93
- "complexity_prev": round(file.trend.historical_totalCc, 2),
94
- "complexity_delta": round(file.trend.totalCc_delta, 2),
95
- "maintainability_current": round(file.maintainabilityIndex, 2),
96
- "maintainability_prev": round(
97
- file.trend.historical_maintainabilityIndex, 2
98
- ),
99
- "maintainability_delta": round(
100
- file.trend.maintainabilityIndex_delta, 2
101
- ),
102
- }
103
-
104
- # Top improved complexity (complexity went down - negative delta)
105
- top_improved_complexity = [
106
- x
107
- for x in metrics.file_metrics
108
- if x.trend is not None and x.trend.totalCc_delta < 0
109
- ]
110
- top_improved_complexity = sorted(
111
- top_improved_complexity, key=lambda x: x.trend.totalCc_delta
112
- )[:10]
113
-
114
- # Top worsened complexity (complexity went up - positive delta)
115
- top_worsened_complexity = [
116
- x
117
- for x in metrics.file_metrics
118
- if x.trend is not None and x.trend.totalCc_delta > 0
119
- ]
120
- top_worsened_complexity = sorted(
121
- top_worsened_complexity, key=lambda x: x.trend.totalCc_delta, reverse=True
122
- )[:10]
123
-
124
- # Top improved maintainability (maintainability went up - positive delta)
125
- top_improved_maintainability = [
126
- x
127
- for x in metrics.file_metrics
128
- if x.trend is not None and round(x.trend.maintainabilityIndex_delta, 2) > 0
129
- ]
130
- top_improved_maintainability = sorted(
131
- top_improved_maintainability,
132
- key=lambda x: x.trend.maintainabilityIndex_delta,
133
- reverse=True,
134
- )[:10]
135
-
136
- # Top worsened maintainability (maintainability went down - negative delta)
137
- top_worsened_maintainability = [
138
- x
139
- for x in metrics.file_metrics
140
- if x.trend is not None and round(x.trend.maintainabilityIndex_delta, 2) < 0
141
- ]
142
- top_worsened_maintainability = sorted(
143
- top_worsened_maintainability,
144
- key=lambda x: x.trend.maintainabilityIndex_delta,
145
- )[:10]
146
-
147
- trend_data = {
148
- # Segment distributions for each metric
149
- "loc_segments_current": metrics.total_code_metrics.segmentation_data[
150
- "loc"
151
- ].to_dict_with_percent(),
152
- "loc_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
153
- "loc"
154
- ].to_dict_with_percent(),
155
- "complexity_segments_current": metrics.total_code_metrics.segmentation_data[
156
- "complexity"
157
- ].to_dict_with_percent(),
158
- "complexity_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
159
- "complexity"
160
- ].to_dict_with_percent(),
161
- "maintainability_segments_current": metrics.total_code_metrics.segmentation_data[
162
- "maintainability"
163
- ].to_dict_with_percent(),
164
- "maintainability_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
165
- "maintainability"
166
- ].to_dict_with_percent(),
167
- "method_size_segments_current": metrics.total_code_metrics.segmentation_data[
168
- "methodSize"
169
- ].to_dict_with_percent(),
170
- "method_size_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
171
- "methodSize"
172
- ].to_dict_with_percent(),
173
- "top_improved_complexity": [compile(x) for x in top_improved_complexity],
174
- "top_improved_maintainability": [
175
- compile(x) for x in top_improved_maintainability
176
- ],
177
- "top_worsened_complexity": [compile(x) for x in top_worsened_complexity],
178
- "top_worsened_maintainability": [
179
- compile(x) for x in top_worsened_maintainability
180
- ],
181
- }
182
-
183
- self.output.writeln("<info>Rendering trends page</info>")
184
- self.render_template(
185
- "trends.html",
186
- {
187
- "has_trend_data": metrics.total_code_metrics.trend is not None,
188
- "trend_data": trend_data,
189
- "project_name": "Metripy",
190
- "last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
191
- "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
192
- "author": "Metripy",
193
- "version": "1.0.0",
194
- },
83
+ self.output.writeln(
84
+ f"<success>Open HTML report: {self.config.path}/index.html</success>"
195
85
  )
196
86
 
197
87
  def render_index_page(self, metrics: ProjectMetrics):
198
- git_stats_data = {}
199
- if metrics.git_metrics:
200
- git_stats_data = metrics.git_metrics.get_commit_stats_per_month()
201
-
202
88
  self.output.writeln("<info>Rendering index page</info>")
203
- self.render_template(
204
- "index.html",
205
- {
206
- "git_stats_data": json.dumps(git_stats_data, indent=4),
207
- "total_code_metrics": metrics.total_code_metrics.to_dict(),
208
- "has_total_code_metrics_trend": metrics.total_code_metrics.trend
209
- is not None,
210
- "total_code_metrics_trend": (
211
- metrics.total_code_metrics.trend.to_dict()
212
- if metrics.total_code_metrics.trend
213
- else None
214
- ),
215
- "segmentation_data": json.dumps(
216
- metrics.total_code_metrics.to_dict_segmentation(), indent=4
217
- ),
218
- "segmentation_data_trend": (
219
- json.dumps(
220
- metrics.total_code_metrics.trend.to_dict_segmentation(),
221
- indent=4,
222
- )
223
- if metrics.total_code_metrics.trend
224
- else None
225
- ),
226
- "project_name": "Metripy",
227
- "last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
228
- "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
229
- "author": "Metripy",
230
- "version": "1.0.0",
231
- },
232
- )
89
+ self.page_renderer_factory.create_index_page_renderer().render(metrics)
233
90
  self.output.writeln("<success>Done rendering index page</success>")
234
91
 
92
+ def render_files_page(self, metrics: ProjectMetrics):
93
+ """Render the files page with file details and analysis"""
94
+ self.output.writeln("<info>Rendering files page</info>")
95
+ self.page_renderer_factory.create_files_page_renderer().render(metrics)
96
+ self.output.writeln("<success>Files page generated successfully</success>")
97
+
235
98
  def render_top_offenders_page(self, metrics: ProjectMetrics):
236
99
  self.output.writeln("<info>Rendering top offenders page</info>")
237
-
238
- orderedByTotalCc = sorted(
239
- metrics.file_metrics, key=lambda x: x.totalCc, reverse=True
240
- )[:10]
241
- orderedByMI = sorted(
242
- metrics.file_metrics, key=lambda x: x.maintainabilityIndex, reverse=False
243
- )[:10]
244
- orderedByLoc = sorted(metrics.file_metrics, key=lambda x: x.loc, reverse=True)[
245
- :10
246
- ]
247
-
248
- all_functions: list = []
249
- for fm in metrics.file_metrics:
250
- all_functions.extend(fm.function_nodes)
251
-
252
- functionsOrderedByCc = sorted(
253
- all_functions, key=lambda x: x.complexity, reverse=True
254
- )[:10]
255
- functionsOrderedByMi = sorted(
256
- all_functions, key=lambda x: x.maintainability_index, reverse=False
257
- )[:10]
258
- functionsOrderedByLoc = sorted(
259
- all_functions, key=lambda x: x.get_loc(), reverse=True
260
- )[:10]
261
-
262
- # TODO maintainability index per function, we dont calc yet
263
-
264
- self.render_template(
265
- "top_offenders.html",
266
- Reporter._stringify_values(
267
- {
268
- "file_loc_offenders": [
269
- {**e.to_dict(), "status": Segmentor.get_loc_segment(e.loc)}
270
- for e in orderedByLoc
271
- ],
272
- "file_cc_offenders": [
273
- {
274
- **e.to_dict(),
275
- "status": Segmentor.get_complexity_segment(e.totalCc),
276
- }
277
- for e in orderedByTotalCc
278
- ],
279
- "file_mi_offenders": [
280
- {
281
- **e.to_dict(),
282
- "status": Segmentor.get_maintainability_segment(
283
- e.maintainabilityIndex
284
- ),
285
- }
286
- for e in orderedByMI
287
- ],
288
- "function_size_offenders": [
289
- {
290
- **e.to_dict(),
291
- "status": Segmentor.get_method_size_segment(e.get_loc()),
292
- }
293
- for e in functionsOrderedByLoc
294
- ],
295
- "function_cc_offenders": [
296
- {
297
- **e.to_dict(),
298
- "status": Segmentor.get_complexity_segment(e.complexity),
299
- }
300
- for e in functionsOrderedByCc
301
- ],
302
- "function_mi_offenders": [
303
- {
304
- **e.to_dict(),
305
- "status": Segmentor.get_maintainability_segment(
306
- e.maintainability_index
307
- ),
308
- }
309
- for e in functionsOrderedByMi
310
- ],
311
- "project_name": "Metripy",
312
- "last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
313
- }
314
- ),
315
- )
100
+ self.page_renderer_factory.create_top_offenders_page_renderer().render(metrics)
316
101
  self.output.writeln(
317
102
  "<success>Top offenders page generated successfully</success>"
318
103
  )
319
104
 
105
+ def render_git_analysis_page(self, metrics: ProjectMetrics):
106
+ """Render the git analysis page with comprehensive git data"""
107
+ self.output.writeln("<info>Rendering git analysis page</info>")
108
+ self.page_renderer_factory.create_git_analysis_page_renderer().render(metrics)
109
+ self.output.writeln(
110
+ "<success>Git analysis page generated successfully</success>"
111
+ )
112
+
320
113
  def render_dependencies_page(self, metrics: ProjectMetrics):
321
114
  """Render the dependencies page with dependency details and stats"""
322
- if not metrics.dependencies:
323
- self.output.writeln("<success>No dependencies to render</success>")
324
- return
325
-
326
115
  self.output.writeln("<info>Rendering dependencies page</info>")
327
-
328
- dependencies = metrics.dependencies if metrics.dependencies is not None else []
329
-
330
- license_by_type = Dependency.get_lisence_distribution(dependencies)
331
-
332
- self.render_template(
333
- "dependencies.html",
334
- {
335
- "dependencies": [d.to_dict() for d in dependencies],
336
- "project_name": "Metripy",
337
- "last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
338
- },
339
- )
116
+ self.page_renderer_factory.create_dependency_page_renderer().render(metrics)
340
117
  self.output.writeln(
341
118
  "<success>Dependencies page generated successfully</success>"
342
119
  )
343
120
 
344
- def render_files_page(self, metrics: ProjectMetrics):
345
- """Render the files page with file details and analysis"""
346
- self.output.writeln("<info>Rendering files page</info>")
347
-
348
- file_names = []
349
- file_details = {}
350
- for file_metrics in metrics.file_metrics:
351
- file_name = file_metrics.full_name
352
- file_details[file_name] = file_metrics.to_dict()
353
- file_names.append(file_name)
354
-
355
- filetree = FileTreeParser.parse(file_names, shorten=True)
356
-
357
- self.render_template(
358
- "files.html",
359
- {
360
- "filetree": json.dumps(filetree.to_dict()),
361
- "file_details": json.dumps(file_details),
362
- "project_name": "Metripy",
363
- "last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
364
- },
365
- )
366
- self.output.writeln("<success>Files page generated successfully</success>")
367
-
368
- @staticmethod
369
- def _stringify_values(obj):
370
- if isinstance(obj, dict):
371
- return {
372
- key: Reporter._stringify_values(value) for key, value in obj.items()
373
- }
374
- elif isinstance(obj, list):
375
- return [Reporter._stringify_values(item) for item in obj]
376
- else:
377
- return str(obj)
378
-
379
- def render_git_analysis_page(self, metrics: ProjectMetrics):
380
- """Render the git analysis page with comprehensive git data"""
381
- if not metrics.git_metrics:
382
- self.output.writeln("<success>No git metrics to render</success>")
383
- return
384
-
385
- self.output.writeln("<info>Rendering git analysis page</info>")
386
- try:
387
- # Render git analysis template
388
- self.render_template(
389
- "git_analysis.html",
390
- Reporter._stringify_values(
391
- {
392
- "git_analysis": metrics.git_metrics.to_dict(),
393
- "git_analysis_json": json.dumps(
394
- metrics.git_metrics.get_contributors_dict(), indent=4
395
- ),
396
- "git_stats_data": json.dumps(
397
- metrics.git_metrics.get_commit_stats_per_month(), indent=4
398
- ), # git commit graph
399
- "git_churn_data": json.dumps(
400
- metrics.git_metrics.get_churn_per_month(), indent=4
401
- ), # git chrun graph
402
- "git_silos_data": metrics.git_metrics.get_silos_list()[
403
- :10
404
- ], # silos list
405
- "git_contributors": metrics.git_metrics.get_contributors_list()[
406
- :10
407
- ], # contributors list
408
- "git_hotspots_data": metrics.git_metrics.get_hotspots_list()[
409
- :10
410
- ], # hotspots list
411
- "project_name": "Metripy",
412
- "last_updated": metrics.git_metrics.get_analysis_start_date(),
413
- }
414
- ),
415
- )
416
-
417
- self.output.writeln(
418
- "<success>Git analysis page generated successfully</success>"
419
- )
420
- except Exception as e:
421
- raise e
422
- self.output.writeln(
423
- f"<error>Error generating git analysis page: {e}</error>"
424
- )
121
+ def render_trends_page(self, metrics: ProjectMetrics):
122
+ self.output.writeln("<info>Rendering trends page</info>")
123
+ self.page_renderer_factory.create_trends_page_renderer().render(metrics)
124
+ self.output.writeln("<success>Trends page generated successfully</success>")
@@ -0,0 +1,84 @@
1
+ from metripy.Metric.Code.Segmentor import Segmentor
2
+ from metripy.Metric.ProjectMetrics import ProjectMetrics
3
+ from metripy.Report.Html.PageRenderer import PageRenderer
4
+
5
+
6
+ class TopOffendersPageRenderer(PageRenderer):
7
+ def __init__(self, template_dir: str, output_dir: str, project_name: str):
8
+ super().__init__(template_dir, output_dir, project_name)
9
+
10
+ def render(self, metrics: ProjectMetrics):
11
+ orderedByTotalCc = sorted(
12
+ metrics.file_metrics, key=lambda x: x.totalCc, reverse=True
13
+ )[:10]
14
+ orderedByMI = sorted(
15
+ metrics.file_metrics, key=lambda x: x.maintainabilityIndex, reverse=False
16
+ )[:10]
17
+ orderedByLoc = sorted(metrics.file_metrics, key=lambda x: x.loc, reverse=True)[
18
+ :10
19
+ ]
20
+
21
+ all_functions: list = []
22
+ for fm in metrics.file_metrics:
23
+ all_functions.extend(fm.function_nodes)
24
+
25
+ functionsOrderedByCc = sorted(
26
+ all_functions, key=lambda x: x.complexity, reverse=True
27
+ )[:10]
28
+ functionsOrderedByMi = sorted(
29
+ all_functions, key=lambda x: x.maintainability_index, reverse=False
30
+ )[:10]
31
+ functionsOrderedByLoc = sorted(
32
+ all_functions, key=lambda x: x.get_loc(), reverse=True
33
+ )[:10]
34
+
35
+ # TODO maintainability index per function, we dont calc yet
36
+
37
+ self.render_template(
38
+ "top_offenders.html",
39
+ {
40
+ "file_loc_offenders": [
41
+ {**e.to_dict(), "status": Segmentor.get_loc_segment(e.loc)}
42
+ for e in orderedByLoc
43
+ ],
44
+ "file_cc_offenders": [
45
+ {
46
+ **e.to_dict(),
47
+ "status": Segmentor.get_complexity_segment(e.totalCc),
48
+ }
49
+ for e in orderedByTotalCc
50
+ ],
51
+ "file_mi_offenders": [
52
+ {
53
+ **e.to_dict(),
54
+ "status": Segmentor.get_maintainability_segment(
55
+ e.maintainabilityIndex
56
+ ),
57
+ }
58
+ for e in orderedByMI
59
+ ],
60
+ "function_size_offenders": [
61
+ {
62
+ **e.to_dict(),
63
+ "status": Segmentor.get_method_size_segment(e.get_loc()),
64
+ }
65
+ for e in functionsOrderedByLoc
66
+ ],
67
+ "function_cc_offenders": [
68
+ {
69
+ **e.to_dict(),
70
+ "status": Segmentor.get_complexity_segment(e.complexity),
71
+ }
72
+ for e in functionsOrderedByCc
73
+ ],
74
+ "function_mi_offenders": [
75
+ {
76
+ **e.to_dict(),
77
+ "status": Segmentor.get_maintainability_segment(
78
+ e.maintainability_index
79
+ ),
80
+ }
81
+ for e in functionsOrderedByMi
82
+ ],
83
+ },
84
+ )
@@ -0,0 +1,114 @@
1
+ from metripy.Metric.Code.FileMetrics import FileMetrics
2
+ from metripy.Metric.ProjectMetrics import ProjectMetrics
3
+ from metripy.Report.Html.PageRenderer import PageRenderer
4
+
5
+
6
+ class TrendsPageRenderer(PageRenderer):
7
+ def __init__(self, template_dir: str, output_dir: str, project_name: str):
8
+ super().__init__(template_dir, output_dir, project_name)
9
+
10
+ def _compile_trend_item(self, file: FileMetrics) -> dict:
11
+ return {
12
+ "name": file.full_name,
13
+ "path": file.full_name,
14
+ "complexity_current": file.totalCc,
15
+ "complexity_prev": round(file.trend.historical_totalCc, 2),
16
+ "complexity_delta": round(file.trend.totalCc_delta, 2),
17
+ "maintainability_current": round(file.maintainabilityIndex, 2),
18
+ "maintainability_prev": round(
19
+ file.trend.historical_maintainabilityIndex, 2
20
+ ),
21
+ "maintainability_delta": round(file.trend.maintainabilityIndex_delta, 2),
22
+ }
23
+
24
+ def render(self, metrics: ProjectMetrics):
25
+ # Top improved complexity (complexity went down - negative delta)
26
+ top_improved_complexity = [
27
+ x
28
+ for x in metrics.file_metrics
29
+ if x.trend is not None and x.trend.totalCc_delta < 0
30
+ ]
31
+ top_improved_complexity = sorted(
32
+ top_improved_complexity, key=lambda x: x.trend.totalCc_delta
33
+ )[:10]
34
+
35
+ # Top worsened complexity (complexity went up - positive delta)
36
+ top_worsened_complexity = [
37
+ x
38
+ for x in metrics.file_metrics
39
+ if x.trend is not None and x.trend.totalCc_delta > 0
40
+ ]
41
+ top_worsened_complexity = sorted(
42
+ top_worsened_complexity, key=lambda x: x.trend.totalCc_delta, reverse=True
43
+ )[:10]
44
+
45
+ # Top improved maintainability (maintainability went up - positive delta)
46
+ top_improved_maintainability = [
47
+ x
48
+ for x in metrics.file_metrics
49
+ if x.trend is not None and round(x.trend.maintainabilityIndex_delta, 2) > 0
50
+ ]
51
+ top_improved_maintainability = sorted(
52
+ top_improved_maintainability,
53
+ key=lambda x: x.trend.maintainabilityIndex_delta,
54
+ reverse=True,
55
+ )[:10]
56
+
57
+ # Top worsened maintainability (maintainability went down - negative delta)
58
+ top_worsened_maintainability = [
59
+ x
60
+ for x in metrics.file_metrics
61
+ if x.trend is not None and round(x.trend.maintainabilityIndex_delta, 2) < 0
62
+ ]
63
+ top_worsened_maintainability = sorted(
64
+ top_worsened_maintainability,
65
+ key=lambda x: x.trend.maintainabilityIndex_delta,
66
+ )[:10]
67
+
68
+ trend_data = {
69
+ # Segment distributions for each metric
70
+ "loc_segments_current": metrics.total_code_metrics.segmentation_data[
71
+ "loc"
72
+ ].to_dict_with_percent(),
73
+ "loc_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
74
+ "loc"
75
+ ].to_dict_with_percent(),
76
+ "complexity_segments_current": metrics.total_code_metrics.segmentation_data[
77
+ "complexity"
78
+ ].to_dict_with_percent(),
79
+ "complexity_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
80
+ "complexity"
81
+ ].to_dict_with_percent(),
82
+ "maintainability_segments_current": metrics.total_code_metrics.segmentation_data[
83
+ "maintainability"
84
+ ].to_dict_with_percent(),
85
+ "maintainability_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
86
+ "maintainability"
87
+ ].to_dict_with_percent(),
88
+ "method_size_segments_current": metrics.total_code_metrics.segmentation_data[
89
+ "methodSize"
90
+ ].to_dict_with_percent(),
91
+ "method_size_segments_prev": metrics.total_code_metrics.trend.historical_segmentation_data[
92
+ "methodSize"
93
+ ].to_dict_with_percent(),
94
+ "top_improved_complexity": [
95
+ self._compile_trend_item(x) for x in top_improved_complexity
96
+ ],
97
+ "top_improved_maintainability": [
98
+ self._compile_trend_item(x) for x in top_improved_maintainability
99
+ ],
100
+ "top_worsened_complexity": [
101
+ self._compile_trend_item(x) for x in top_worsened_complexity
102
+ ],
103
+ "top_worsened_maintainability": [
104
+ self._compile_trend_item(x) for x in top_worsened_maintainability
105
+ ],
106
+ }
107
+
108
+ self.render_template(
109
+ "trends.html",
110
+ {
111
+ "has_trend_data": metrics.total_code_metrics.trend is not None,
112
+ "trend_data": trend_data,
113
+ },
114
+ )
@@ -8,9 +8,11 @@ from metripy.Report.Json.JsonReporter import JsonReporter
8
8
 
9
9
  class ReporterFactory:
10
10
  @staticmethod
11
- def create(config: ReportConfig, output: CliOutput) -> ReporterInterface:
11
+ def create(
12
+ config: ReportConfig, output: CliOutput, project_name: str
13
+ ) -> ReporterInterface:
12
14
  if config.type == "html":
13
- return HtmlReporter(config, output)
15
+ return HtmlReporter(config, output, project_name)
14
16
  elif config.type == "json":
15
17
  return JsonReporter(config, output)
16
18
  elif config.type == "csv":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metripy
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: A Python tool to generate multi project, multi language code metric reports
5
5
  Author-email: Yannick Zimmermann <yannick.zimmermann@proton.me>
6
6
  License: MIT