diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..e4b98aa --- /dev/null +++ b/.coveragerc @@ -0,0 +1,12 @@ +[run] +command_line=-m pytest +omit= + *_js.py + pyRCV2/transcrypt.py +source=pyRCV2 + +[report] +exclude_lines= + __pragma__ + def __repr__ + pragma: no cover diff --git a/.gitignore b/.gitignore index fe4698c..7eb9203 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ +/.coverage /.python-version /__target__ -/test /html/bundle.js +/htmlcov +/test __pycache__ .~* diff --git a/pyRCV2/method/base_stv.py b/pyRCV2/method/base_stv.py index be23488..1e7d456 100644 --- a/pyRCV2/method/base_stv.py +++ b/pyRCV2/method/base_stv.py @@ -142,7 +142,7 @@ class BaseSTVCounter: if result: return result - raise STVException('Unable to complete step') + raise STVException('Unable to complete step') # pragma: no cover def step_count_cards(self): """ @@ -249,7 +249,7 @@ class BaseSTVCounter: has_surplus.sort(key=lambda x: x[1].votes, reverse=True) elif self.options['surplus_order'] == 'order': has_surplus.sort(key=lambda x: x[1].order_elected) - else: + else: # pragma: no cover raise STVException('Invalid surplus order option') # Attempt to defer all remaining surpluses if possible @@ -286,7 +286,7 @@ class BaseSTVCounter: Transfer the surplus of the given candidate Subclasses must override this function """ - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover def before_exclusion(self): """ @@ -440,7 +440,7 @@ class BaseSTVCounter: Exclude the given candidate and transfer the votes Subclasses must override this function """ - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover def compute_quota(self): """ @@ -457,7 +457,7 @@ class BaseSTVCounter: elif self.options['quota'] == 'hare' or self.options['quota'] == 'hare_exact': self.quota = self.total / Num(self.election.seats) else: - raise STVException('Invalid quota option') + raise STVException('Invalid quota option') # pragma: no cover if self.options['round_quota'] is not None: if self.options['quota'] == 'droop' or self.options['quota'] == 'hare': @@ -501,7 +501,7 @@ class BaseSTVCounter: return count_card.votes > self.quota or (self.options['quota_mode'] == 'ers97' and count_card.votes > self.vote_required_election) __pragma__('noopov') else: - raise STVException('Invalid quota criterion') + raise STVException('Invalid quota criterion') # pragma: no cover def elect_meeting_quota(self): """ diff --git a/pyRCV2/method/gregory.py b/pyRCV2/method/gregory.py index 91835ea..8a47100 100644 --- a/pyRCV2/method/gregory.py +++ b/pyRCV2/method/gregory.py @@ -31,7 +31,7 @@ def groupby(iterable, keyfunc): import itertools return [list(g) for k, g in itertools.groupby(iterable, keyfunc)] __pragma__('noskip') - else: + else: # pragma: no cover groups = [] group = [] last_result = None @@ -173,7 +173,7 @@ class WIGSTVCounter(BaseSTVCounter): # TODO: Can we combine ballots for each candidate within each stage? self._exclusion = (candidates_excluded, [[(c, [(b, bv)]) for c, b, bv in x] for x in ballots_by_value]) else: - raise STVException('Invalid exclusion mode') + raise STVException('Invalid exclusion mode') # pragma: no cover this_exclusion = self._exclusion[1][0] self._exclusion[1].remove(this_exclusion) diff --git a/pyRCV2/model.py b/pyRCV2/model.py index 80935d5..22dd454 100644 --- a/pyRCV2/model.py +++ b/pyRCV2/model.py @@ -25,7 +25,7 @@ class Candidate: def __repr__(self): return '' - def toString(self): + def toString(self): # pragma: no cover return repr(self) class CandidateState: diff --git a/pyRCV2/numbers/__init__.py b/pyRCV2/numbers/__init__.py index b01ea40..4ff3ae9 100644 --- a/pyRCV2/numbers/__init__.py +++ b/pyRCV2/numbers/__init__.py @@ -26,7 +26,7 @@ if is_py: from pyRCV2.numbers.native_py import Native from pyRCV2.numbers.rational_py import Rational __pragma__('noskip') -else: +else: # pragma: no cover from pyRCV2.numbers.fixed_js import Fixed, set_dps, get_dps from pyRCV2.numbers.native_js import Native from pyRCV2.numbers.rational_js import Rational diff --git a/pyRCV2/numbers/base.py b/pyRCV2/numbers/base.py index 423c1c5..1cd7563 100644 --- a/pyRCV2/numbers/base.py +++ b/pyRCV2/numbers/base.py @@ -36,7 +36,7 @@ def compatible_types(f): else: return f __pragma__('noskip') - else: + else: # pragma: no cover # FIXME: Do we need to perform type checking in JS? return f @@ -61,7 +61,7 @@ class BaseNum: Internal use: Convert the given value to an impl Subclasses must override this method """ - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @classmethod def _from_impl(cls, impl): @@ -79,52 +79,52 @@ class BaseNum: Pretty print to specified number of decimal places Subclasses must override this method """ - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover # Implementation of arithmetic on impls # Subclasses must override these functions: @classmethod def _add_impl(cls, i1, i2): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @classmethod def _sub_impl(cls, i1, i2): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @classmethod def _mul_impl(cls, i1, i2): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @classmethod def _truediv_impl(cls, i1, i2): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @compatible_types def __eq__(self, other): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @compatible_types def __ne__(self, other): return not (self.__eq__(other)) @compatible_types def __gt__(self, other): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @compatible_types def __ge__(self, other): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @compatible_types def __lt__(self, other): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover @compatible_types def __le__(self, other): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover def __pow__(self, power): - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover def round(self, dps, mode): """ Round to the specified number of decimal places, using the ROUND_* mode specified Subclasses must override this method """ - raise NotImplementedError('Method not implemented') + raise NotImplementedError('Method not implemented') # pragma: no cover # Implement various data model functions based on _*_impl diff --git a/pyRCV2/random/__init__.py b/pyRCV2/random/__init__.py index cc5772d..f146ce3 100644 --- a/pyRCV2/random/__init__.py +++ b/pyRCV2/random/__init__.py @@ -24,5 +24,5 @@ if is_py: __pragma__('skip') from pyRCV2.random.sharandom_py import SHARandom __pragma__('noskip') -else: +else: # pragma: no cover from pyRCV2.random.sharandom_js import SHARandom diff --git a/pyRCV2/safedict/__init__.py b/pyRCV2/safedict/__init__.py index 40b3b7e..1fc4814 100644 --- a/pyRCV2/safedict/__init__.py +++ b/pyRCV2/safedict/__init__.py @@ -24,5 +24,5 @@ if is_py: __pragma__('skip') from pyRCV2.safedict.safedict_py import SafeDict __pragma__('noskip') -else: +else: # pragma: no cover from pyRCV2.safedict.safedict_js import SafeDict diff --git a/pyRCV2/ties.py b/pyRCV2/ties.py index f35673c..7453e85 100644 --- a/pyRCV2/ties.py +++ b/pyRCV2/ties.py @@ -22,7 +22,8 @@ __pragma__('noskip') from pyRCV2.random import SHARandom -class RequireInput(Exception): +class RequireInput(Exception): # pragma: no cover + # For JS only # Exceptions for control flow? In my code? It's more likely thank you think! def __init__(self, message): self.message = message @@ -51,7 +52,7 @@ class TiesPrompt: print() return l[i - 1] - else: + else: # pragma: no cover if self.buffer is not None: try: choice = int(self.buffer) diff --git a/requirements.txt b/requirements.txt index 89918da..ffcc411 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,9 @@ # Dependencies -Transcrypt==3.7.16 +coverage==5.3.1 py-mini-racer==0.4.0 pytest==6.2.1 pytest-steps==1.7.3 +Transcrypt==3.7.16 # Dependency tree attrs==20.3.0