Repository: ishepard/pydriller
Pull request #79 (2020-02-03 09:17:55)

Updated LinesCount process metric
Previous metric accounted for the:
- number of added and deleted lines in commit ```to_commit```;
- normalized added/deleted lines in period ```[from_commit, to_commit]```;
- total number of added/deleted lines in period ```[from_commit, to_commit]```.

However, in the previous implementation, the normalized number of lines was greater than zero only if a file was modified in ```to_commit```.
When that metric is computed for a file of a commit within the period ```[from_commit, to_commit]```, if it has not been modified also in ```to_commit``` the metric can return undesirable results.

I've simplified the code to count only for the total number of added and deleted lines in the evolution period ```[from_commit, to_commit]```.

If a user needs to compute the normalized number of added/deleted lines, i.e. ```added(commit_i)/total_added([from_commit, to_commit])```, where ```commit_i in (from_commit, to_commit)```, (and similar for deleted lines), s/he can call the method twice:
1. Once for the total number of added and deleted lines in the period ```[from_commit, to_commit]```;
2. Once for the number of  added and deleted lines in the period ```[to_commit, to_commit]``` (i.e. a single commit).

This makes code more easy to maintain.


Patch:
diff --git a/pydriller/metrics/process/lines_count.py b/pydriller/metrics/process/lines_count.py
index 862e0b3..dbef261 100644
--- a/pydriller/metrics/process/lines_count.py
+++ b/pydriller/metrics/process/lines_count.py
@@ -8,19 +8,9 @@ from pydriller.metrics.process.process_metric import ProcessMetric
 class LinesCount(ProcessMetric):
     """
     This class is responsible to implement the following metrics: \
-    * Added Lines: the number of added lines in commit 'to_commit'
-    * Deleted Lines: the number of deleted lines in commit 'to_commit'
-    * Normalized Added Lines: is the number of added lines in a file \
-        of a given commit over the total number of added lines in the \
-        provided evolution period, e.g. a [from_commit, to_commit] representing \
-        a release.
-    * Normalized Deleted Lines: is the number of deleted lines in a file \
-        of a given commit over the total number of deleted lines in the \
-        provided evolution period, e.g. a [from_commit, to_commit] representing \
-        a release.
-    * Total Added Lines: the number of added lines in the evolution period \
+    * Added Lines: the number of added lines in the evolution period \
         [from_commit, to_commit]
-    * Total Deleted Lines: the number of deleted lines in the evolution period \
+    * Deleted Lines: the number of deleted lines in the evolution period \
         [from_commit, to_commit]
     """
 
@@ -29,15 +19,14 @@ class LinesCount(ProcessMetric):
         Calculate the number of normalized (by the total number of added and \
         deleted lines) added and deleted lines per each modified file in \
         'to_commit', returning a dictionary:
-        {filepath: {
+        {
+          filepath: {
             added: int,
-            removed: int,
-            norm_added: float,
-            norm_removed: float
-            }
+            removed: int
+          }
         }
 
-        :return: dict of normalized added and deleted lines per modified file
+        :return: dict of total added and deleted lines per modified file
         """
         renamed_files = {}
         files = {}
@@ -55,27 +44,7 @@ class LinesCount(ProcessMetric):
                 if modified_file.change_type == ModificationType.RENAME:
                     renamed_files[modified_file.old_path] = filepath
 
-                if commit.hash == self.to_commit:
-                    files[filepath] = files.get(filepath,
-                                                {'added': 0,            # Added in to_commit
-                                                 'removed': 0,          # Removed in to_commit
-                                                 'total_added': 0,      # Added in time range [from_commit, to_commit]
-                                                 'total_removed': 0})   # Removed in time range [from_commit, to_commit]
-                    files[filepath]['added'] += modified_file.added
-                    files[filepath]['removed'] += modified_file.removed
-
-                if filepath in files:
-                    files[filepath]['total_added'] += modified_file.added
-                    files[filepath]['total_removed'] += modified_file.removed
-
-        for path in list(files.keys()):
-            files[path]['norm_added'] = 0
-            files[path]['norm_removed'] = 0
-
-            if files[path]['total_added']:
-                files[path]['norm_added'] = round(100 * files[path]['added'] / files[path]['total_added'], 2)
-
-            if files[path]['total_removed']:
-                files[path]['norm_removed'] = round(100 * files[path]['removed'] / files[path]['total_removed'], 2)
+                files.setdefault(filepath, {'added': 0, 'removed': 0})['added'] += modified_file.added
+                files.setdefault(filepath, {'added': 0, 'removed': 0})['removed'] += modified_file.removed
 
         return files


Test patch:
diff --git a/tests/metrics/process/test_lines_count.py b/tests/metrics/process/test_lines_count.py
index 78fda83..11de691 100644
--- a/tests/metrics/process/test_lines_count.py
+++ b/tests/metrics/process/test_lines_count.py
@@ -6,16 +6,16 @@ from pydriller.metrics.process.lines_count import LinesCount
 
 TEST_DATA = [
    ('test-repos/pydriller', '.gitignore', None, 'ab36bf45859a210b0eae14e17683f31d19eea041',
-      {'added': 197, 'removed': 0, 'norm_added': 100.0, 'norm_removed': .0, 'total_added': 197, 'total_removed': 0}),
+      {'added': 197, 'removed': 0}),
 
    ('test-repos/pydriller', '.gitignore', 'ab36bf45859a210b0eae14e17683f31d19eea041', 'ab36bf45859a210b0eae14e17683f31d19eea041',
-      {'added': 197, 'removed': 0, 'norm_added': 100.0, 'norm_removed': .0, 'total_added': 197, 'total_removed': 0}),
+      {'added': 197, 'removed': 0}),
 
    ('test-repos/pydriller', 'domain/modification.py', None, 'fdf671856b260aca058e6595a96a7a0fba05454b',
-      {'added': 1, 'removed': 1, 'norm_added': round(100*1/49, 2), 'norm_removed': 100.0, 'total_added': 49, 'total_removed': 1}),
+      {'added': 49, 'removed': 1}),
 
    ('test-repos/pydriller', 'domain/modification.py', 'ab36bf45859a210b0eae14e17683f31d19eea041', 'fdf671856b260aca058e6595a96a7a0fba05454b',
-      {'added': 1, 'removed': 1, 'norm_added': round(100*1/49, 2), 'norm_removed': 100.0, 'total_added': 49, 'total_removed': 1})
+      {'added': 49, 'removed': 1})
 ]
 
 @pytest.mark.parametrize('path_to_repo, filepath, from_commit, to_commit, expected', TEST_DATA)