Repository: ishepard/pydriller
Pull request #101 (2020-03-06 14:18:16)

Updated documentation and refactored class ContributorsCount


Patch:
diff --git a/docs/processmetrics.rst b/docs/processmetrics.rst
index fcec1b8..2ca44cc 100644
--- a/docs/processmetrics.rst
+++ b/docs/processmetrics.rst
@@ -5,15 +5,50 @@ Process Metrics
 ==================
 
 Process metrics capture aspects of the development process rather than aspects about the code itself.
-From release 1.11 PyDriller can calculate ``code churn``, ``commits count``, ``contributors count``, ``contributors experience``, ``history complexity``, ``hunks count``, ``lines count`` and ``minor contributors``. Everything in just one line!
+From release 1.11 PyDriller can calculate ``change_set``, ``code churn``, ``commits count``, ``contributors count``, ``contributors experience``, ``history complexity``, ``hunks count``, ``lines count`` and ``minor contributors``. Everything in just one line!
 
 Below an example of how call the metrics.
 
 
+Change Set
+==========
+
+This metric measures the of files committed together.
+
+The class ``ChangeSet`` has two methods:
+
+* ``max()`` to count the *maximum* number of files committed together;
+* ``avg()`` to count the *average* number of files committed together. **Note:** The average value is rounded off to the nearest integer.
+
+For example::
+
+    from pydriller.metrics.process.change_set import ChangeSet
+    metric = ChangeSet(path_to_repo='path/to/the/repo',
+                       from_commit='from commit hash',
+                       to_commit='to commit hash')
+    
+    maximum = metric.max()
+    average = metric.avg()
+    print('Maximum number of files committed together: {}'.format(maximum))
+    print('Average number of files committed together: {}'.format(average))
+
+will print the maximum and average number of files committed together in the evolution period ``[from_commit, to_commit]``. 
+
+**Note:** differently from the other metrics below, the scope of this metrics is the evolution period rather than the single files.
+
+
 Code Churn
-===============
+==========
+
+This metric measures the code churns of a file.
+A code churn is the sum of (added lines - removed lines) across the analyzed commits.
+
+The class ``CodeChurn`` has three methods:
+
+* ``count()`` to count the *total* size of code churns of a file;
+* ``max()`` to count the *maximum* size of a code churn of a file;
+* ``avg()`` to count the *average* size of a code churn of a file. **Note:** The average value is rounded off to the nearest integer.
 
-This metric measures the number of commits made to a file.
 For example::
 
     from pydriller.metrics.process.code_churn import CodeChurn
@@ -31,9 +66,14 @@ will print the total, maximum and average number of code churn for each modified
 
 
 Commits Count
-===============
+=============
 
 This metric measures the number of commits made to a file.
+
+The class ``CommitCount`` has one method:
+
+* ``count()`` to count the number of commits to a file.
+
 For example::
 
     from pydriller.metrics.process.commits_count import CommitsCount
@@ -46,28 +86,39 @@ For example::
 will print the number of commits for each modified file in the evolution period ``[from_commit, to_commit]``. 
 
 
-
 Contributors Count
-===============
+==================
 
 This metric measures the number of developers that contributed to a file.
+
+The class ``ContributorsCount`` has two methods:
+
+* ``count()`` to count the number of contributors who modified a file;
+* ``count_minor()`` to count the number of *minor* contributors who modified a file, i.e., those that contributed less than 5% to the file.
+
 For example::
 
     from pydriller.metrics.process.contributors_count import ContributorsCount
     metric = ContributorsCount(path_to_repo='path/to/the/repo',
                                from_commit='from commit hash',
                                to_commit='to commit hash')
-    files = metric.count()
-    print('Files: {}'.format(files))
-
-will print the number of developers that contributed to each of the modified file in the evolution period ``[from_commit, to_commit]``. 
+    count = metric.count()
+    minor = metric.count_minor()
+    print('Number of contributors per file: {}'.format(count))
+    print('Number of "minor" contributors per file: {}'.format(minor))
 
+will print the number of developers that contributed to each of the modified file in the evolution period ``[from_commit, to_commit]`` and the number of developers that contributed less than 5% to each of the modified file in the evolution period ``[from_commit, to_commit]``. 
 
 
 Contributors Experience
-===============
+========================
 
 This metric measures the percetage of the lines authored by the highest contributor of a file.
+
+The class ``ContriutorExperience`` has one method:
+
+* ``count()`` to count the number of lines authored by the highest contributor of a file;
+
 For example::
 
     from pydriller.metrics.process.contributors_experience import ContributorsExperience
@@ -82,10 +133,15 @@ will print the percentage of the lines authored by the highest contributor for e
 
 
 Hunks Count
-===============
+===========
 
 This metric measures the number of hunks made to a file.
 As a hunk is a continuous block of changes in a ``diff``, this number assesses how fragmented the commit file is (i.e. lots of changes all over the file versus one big change).
+
+The class ``HunksCount`` has one method:
+
+* ``count()`` to count the median number of hunks of a file.
+
 For example::
 
     from pydriller.metrics.process.hunks_count import HunksCount
@@ -98,20 +154,46 @@ For example::
 will print the median number of hunks for each of the modified file in the evolution period ``[from_commit, to_commit]``. 
 
 
-
 Lines Count
-===============
+===========
 
 This metric measures the number of added and removed lines in a file.
+The class ``LinesCount`` has seven methods:
+
+* ``count()`` to count the total number of added and removed lines for each modified file;
+* ``count_added()``, ``max_added()`` and ``avg_added()`` to count the total, maximum and average number of added lines for each modified file;
+* ``count_removed()``, ``max_removed()`` and ``avg_removed()`` to count the total, maximum and average number of removed lines for each modified file.
+
+**Note:** The average values are rounded off to the nearest integer.
+
 For example::
 
     from pydriller.metrics.process.lines_count import LinesCount
     metric = LinesCount(path_to_repo='path/to/the/repo',
                         from_commit='from commit hash',
                         to_commit='to commit hash')
-    files = metric.count()
-    print('Files: {}'.format(files))
+    
+    added_count = metric.count_added()
+    added_max = metric.max_added()
+    added_avg = metric.avg_added()
+    print('Total lines added per file: {}'.format(added_count))
+    print('Maximum lines added per file: {}'.format(added_max))
+    print('Average lines added per file: {}'.format(added_avg))
 
-will print a dictionary ``{'added': int, 'removed': int}`` of added and removed lines for each of the modified file in the evolution period ``[from_commit, to_commit]``. 
+will print the total, maximum and average number of lines added for each modified file in the evolution period ``[from_commit, to_commit]``. 
 
+While::
 
+    from pydriller.metrics.process.lines_count import LinesCount
+    metric = LinesCount(path_to_repo='path/to/the/repo',
+                        from_commit='from commit hash',
+                        to_commit='to commit hash')
+    
+    removed_count = metric.count_removed()
+    removed_max = metric.max_removed()
+    removed_avg = metric.avg_removed()
+    print('Total lines removed per file: {}'.format(removed_count))
+    print('Maximum lines removed per file: {}'.format(removed_max))
+    print('Average lines removed per file: {}'.format(removed_avg))
+
+will print the total, maximum and average number of lines removed for each modified file in the evolution period ``[from_commit, to_commit]``. 
diff --git a/pydriller/metrics/process/change_set.py b/pydriller/metrics/process/change_set.py
index a3ab87e..cd7585c 100644
--- a/pydriller/metrics/process/change_set.py
+++ b/pydriller/metrics/process/change_set.py
@@ -18,9 +18,9 @@ class ChangeSet(ProcessMetric):
                  from_commit: str,
                  to_commit: str):
         super().__init__(path_to_repo, from_commit, to_commit)
-        self._initialize()
+        self.__initialize()
 
-    def _initialize(self):
+    def __initialize(self):
 
         self.committed_together = []
 
diff --git a/pydriller/metrics/process/code_churn.py b/pydriller/metrics/process/code_churn.py
index c46ac49..2708faf 100644
--- a/pydriller/metrics/process/code_churn.py
+++ b/pydriller/metrics/process/code_churn.py
@@ -22,9 +22,10 @@ class CodeChurn(ProcessMetric):
                  from_commit: str,
                  to_commit: str):
         super().__init__(path_to_repo, from_commit, to_commit)
-        self._initialize()
+        self.__initialize()
 
-    def _initialize(self):
+
+    def __initialize(self):
 
         renamed_files = {}
         self.files = {}
diff --git a/pydriller/metrics/process/contributors_count.py b/pydriller/metrics/process/contributors_count.py
index 7b16a3a..e55b4dc 100644
--- a/pydriller/metrics/process/contributors_count.py
+++ b/pydriller/metrics/process/contributors_count.py
@@ -11,28 +11,26 @@ from pydriller.metrics.process.process_metric import ProcessMetric
 class ContributorsCount(ProcessMetric):
     """
     This class is responsible to implement the following metrics:
+    
     * Contributors Count: measures the number of contributors who modified a
       file.
+    
     * Minor Contributors Count: measures the number of contributors who
       authored less than 5% of code of a file.
     """
 
-    def count(self):
-        """
-        Return the number of contributors who modified a file and those that
-        authored less than 5% of code for each modified file in the repository
-        in the provided time range [from_commit, to_commit]
-
-        :return: dict
-            {filepath: {
-                   contributors_count: int,
-                   minor_contributors_count: int
-                 }
-            }
-        of number of contributors for each modified file
-        """
+    def __init__(self, path_to_repo: str,
+                 from_commit: str,
+                 to_commit: str):
+        super().__init__(path_to_repo, from_commit, to_commit)
+        self._initialize()
+
+    def _initialize(self):
+
+        self.contributors = dict()
+        self.minor_contributors = dict()
+
         renamed_files = {}
-        files = {}
 
         for commit in self.repo_miner.traverse_commits():
 
@@ -47,23 +45,32 @@ class ContributorsCount(ProcessMetric):
                 author = commit.author.email.strip()
                 lines_authored = modified_file.added + modified_file.removed
 
-                files[filepath] = files.get(filepath, {})
-                files[filepath][author] = files[filepath].get(
-                    author, 0) + lines_authored
+                self.contributors[filepath] = self.contributors.get(filepath, {})
+                self.contributors[filepath][author] = self.contributors[filepath].get(author, 0) + lines_authored
 
-        for path, contributions in list(files.items()):
+        for path, contributions in list(self.contributors.items()):
             total = sum(contributions.values())
             if total == 0:
-                del files[path]
+                del self.contributors[path]
             else:
                 contributors_count = len(contributions.values())
                 minor_contributors_count = sum(1
                                                for v in contributions.values()
                                                if v/total < .05)
 
-                files[path] = {
-                    'contributors_count': contributors_count,
-                    'minor_contributors_count': minor_contributors_count
-                }
+                self.contributors[path] = contributors_count
+                self.minor_contributors[path] = minor_contributors_count
+    
+    
+    def count(self):
+        """
+        Return the number of contributors who modified a file.
+        """
+        return self.contributors
 
-        return files
+    def count_minor(self):
+        """
+        Return the number of contributors that authored less than
+        5% of code of a file.
+        """
+        return self.minor_contributors
diff --git a/pydriller/metrics/process/lines_count.py b/pydriller/metrics/process/lines_count.py
index 77c59a7..3ca3124 100644
--- a/pydriller/metrics/process/lines_count.py
+++ b/pydriller/metrics/process/lines_count.py
@@ -37,9 +37,9 @@ class LinesCount(ProcessMetric):
                  from_commit: str,
                  to_commit: str):
         super().__init__(path_to_repo, from_commit, to_commit)
-        self._initialize()
+        self.__initialize()
 
-    def _initialize(self):
+    def __initialize(self):
 
         self.lines_added = dict()
         self.lines_removed = dict()


Test patch:
diff --git a/tests/metrics/process/test_contributors_count.py b/tests/metrics/process/test_contributors_count.py
index 7fd0995..ad43bd5 100644
--- a/tests/metrics/process/test_contributors_count.py
+++ b/tests/metrics/process/test_contributors_count.py
@@ -17,4 +17,4 @@ def test(path_to_repo, filepath, from_commit, to_commit, expected):
 
     count = metric.count()
     filepath = str(Path(filepath))
-    assert count[filepath]['contributors_count'] == expected
+    assert count[filepath] == expected
diff --git a/tests/metrics/process/test_minor_contributors_count.py b/tests/metrics/process/test_minor_contributors_count.py
index 1565bcf..65d40fa 100644
--- a/tests/metrics/process/test_minor_contributors_count.py
+++ b/tests/metrics/process/test_minor_contributors_count.py
@@ -15,6 +15,6 @@ def test(path_to_repo, filepath, from_commit, to_commit, expected):
     metric = ContributorsCount(path_to_repo=path_to_repo,
                                from_commit=from_commit,
                                to_commit=to_commit)
-    count = metric.count()
+    count = metric.count_minor()
     filepath = str(Path(filepath))
-    assert count[filepath]['minor_contributors_count'] == expected
+    assert count[filepath] == expected