sympy/sympy — pull request #8017 by pbrady (2014-09-11 16:24:35+00:00)
Title: Add --rerun flag to tests

There are some rather hard to track down bugs that depend on the value of `PYTHONHASHSEED` and `seed` in the test suite. Furthermore, the hash values at which these errors occur are platform dependent which can make it difficult to debug. This recently happened in #7920.

To fix this, this PR adds a `--rerun X` flag to the sympy testing utilities which will rerun the tests X number of times or until the first error occurs.

Some examples:
```bash
$ bin/test sympy/integrals/tests/test_meijerint.py -k test_meijerint --rerun 2
============================== test process starts ==============================
executable: /home/ptb/miniconda3/bin/python (3.4.1-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 47298970
hash randomization: on (PYTHONHASHSEED=305866206)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 19.47 seconds ===================
============================== test process starts ==============================
executable: /home/ptb/miniconda3/bin/python (3.4.1-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 48144300
hash randomization: on (PYTHONHASHSEED=669950142)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 19.36 seconds ===================
============================== test process starts ==============================
executable: /home/ptb/miniconda3/bin/python (3.4.1-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 3733409
hash randomization: on (PYTHONHASHSEED=917857309)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 19.11 seconds ===================
```
Note that the total number if runs in X+1

Here's an example where a failure ends the rerunning

```bash
$ bin/test sympy/integrals/tests/test_meijerint.py -k test_meijerint --rerun 20
============================== test process starts ==============================
executable: /home/ptb/miniconda3/envs/py27/bin/python (2.7.8-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 6221742
hash randomization: on (PYTHONHASHSEED=3801313532)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 18.69 seconds ===================
============================== test process starts ==============================
executable: /home/ptb/miniconda3/envs/py27/bin/python (2.7.8-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 4434697
hash randomization: on (PYTHONHASHSEED=3630275914)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 18.83 seconds ===================
============================== test process starts ==============================
executable: /home/ptb/miniconda3/envs/py27/bin/python (2.7.8-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 75486063
hash randomization: on (PYTHONHASHSEED=881575022)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 18.63 seconds ===================
============================== test process starts ==============================
executable: /home/ptb/miniconda3/envs/py27/bin/python (2.7.8-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 30255244
hash randomization: on (PYTHONHASHSEED=1495287681)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 19.05 seconds ===================
============================== test process starts ==============================
executable: /home/ptb/miniconda3/envs/py27/bin/python (2.7.8-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 92757879
hash randomization: on (PYTHONHASHSEED=3730556679)

sympy/integrals/tests/test_meijerint.py[2] .. [OK]

================== tests finished: 2 passed, in 18.66 seconds ===================
============================== test process starts ==============================
executable: /home/ptb/miniconda3/envs/py27/bin/python (2.7.8-final-0) [CPython]
architecture: 64-bit
cache: yes
ground types: python
random seed: 41061280
hash randomization: on (PYTHONHASHSEED=3125210523)

sympy/integrals/tests/test_meijerint.py[2] .E [FAIL]

_________________________________________________________________________________
____________ sympy/integrals/tests/test_meijerint.py:test_meijerint _____________
File "/home/ptb/gitrepos/sympy/sympy/integrals/tests/test_meijerint.py", line 148, in test_meijerint
assert expand(meijerint_definite(exp(x), x, 0, I)[0]) == exp(I) - 1
File "sympy/integrals/meijerint.py", line 1795, in meijerint_definite
res = _meijerint_definite_2(f, x)
File "sympy/integrals/meijerint.py", line 1852, in _meijerint_definite_2
res = _meijerint_definite_3(g, x)
File "sympy/integrals/meijerint.py", line 1864, in _meijerint_definite_3
res = _meijerint_definite_4(f, x)
File "sympy/integrals/meijerint.py", line 1944, in _meijerint_definite_4
return _my_unpolarify(hyperexpand(res)), cond
File "sympy/simplify/hyperexpand.py", line 2482, in hyperexpand
return f.replace(hyper, do_replace).replace(meijerg, do_meijer)
File "sympy/core/basic.py", line 1351, in replace
rv = bottom_up(self, rec_replace, atoms=True)
File "sympy/simplify/simplify.py", line 4077, in bottom_up
for a in rv.args])
File "sympy/simplify/simplify.py", line 4080, in bottom_up
rv = F(rv)
File "sympy/core/basic.py", line 1336, in rec_replace
new = _value(expr, result)
File "sympy/core/basic.py", line 1280, in
_value = lambda expr, result: value(*expr.args)
File "sympy/simplify/hyperexpand.py", line 2479, in do_meijer
allow_hyper, rewrite=rewrite)
File "sympy/simplify/hyperexpand.py", line 2367, in _meijergexpand
slater1, cond1 = do_slater(func.an, func.bm, func.ap, func.bq, z, z0)
File "sympy/simplify/hyperexpand.py", line 2303, in do_slater
t, premult, bh, rewrite=None)
File "sympy/simplify/hyperexpand.py", line 2068, in _hyperexpand
return powdenest(r, polar=True).replace(hyper, hyperexpand_special)
File "sympy/simplify/simplify.py", line 2442, in powdenest
eq, rep = polarify(eq)
File "sympy/simplify/simplify.py", line 2166, in polarify
eq = _polarify(sympify(eq), lift)
File "sympy/simplify/simplify.py", line 2101, in _polarify
return polar_lift(eq)
File "sympy/core/function.py", line 375, in __new__
result = super(Function, cls).__new__(cls, *args, **options)
File "sympy/core/function.py", line 199, in __new__
evaluated = cls.eval(*args)
File "sympy/functions/elementary/complexes.py", line 651, in eval
ar = argument(arg)
File "sympy/core/function.py", line 375, in __new__
result = super(Function, cls).__new__(cls, *args, **options)
File "sympy/core/function.py", line 199, in __new__
evaluated = cls.eval(*args)
File "sympy/functions/elementary/complexes.py", line 487, in eval
sign(a) for a in arg_.args])
File "sympy/core/function.py", line 379, in __new__
pr = max(cls._should_evalf(a) for a in result.args)
File "sympy/core/function.py", line 379, in
pr = max(cls._should_evalf(a) for a in result.args)
File "sympy/core/function.py", line 398, in _should_evalf
re, im = arg.as_real_imag()
File "sympy/core/add.py", line 701, in as_real_imag
re, im = term.as_real_imag(deep=deep)
File "sympy/functions/elementary/exponential.py", line 330, in as_real_imag
return (exp(re)*cos, exp(re)*sin)
File "sympy/core/decorators.py", line 77, in __sympifyit_wrapper
return func(a, b)
File "sympy/core/decorators.py", line 118, in binary_op_wrapper
return func(self, other)
File "sympy/core/expr.py", line 127, in __mul__
return Mul(self, other)
File "sympy/core/operations.py", line 41, in __new__
c_part, nc_part, order_symbols = cls.flatten(args)
File "sympy/core/mul.py", line 415, in flatten
c_part.append(Pow(b, e))
File "sympy/core/power.py", line 170, in __new__
elif e.is_integer and _coeff_isneg(b):
File "sympy/core/assumptions.py", line 135, in getit
return _ask(fact, self)
File "sympy/core/assumptions.py", line 178, in _ask
a = evaluate(obj)
File "sympy/core/mul.py", line 986, in _eval_is_integer
is_rational = self.is_rational
File "sympy/core/assumptions.py", line 135, in getit
return _ask(fact, self)
File "sympy/core/assumptions.py", line 188, in _ask
_ask(pk, obj)
File "sympy/core/assumptions.py", line 188, in _ask
_ask(pk, obj)
File "sympy/core/assumptions.py", line 188, in _ask
_ask(pk, obj)
File "sympy/core/assumptions.py", line 180, in _ask
assumptions.deduce_all_facts(((fact, a),))
File "sympy/core/facts.py", line 506, in deduce_all_facts
if not self._tell(k, v) or v is None:
File "sympy/core/facts.py", line 477, in _tell
raise InconsistentAssumptions(self, k, v)
InconsistentAssumptions: {
commutative: True,
complex: True,
composite: False,
even: False,
hermitian: True,
imaginary: False,
integer: False,
irrational: True,
negative: False,
noninteger: True,
nonzero: True,
odd: False,
positive: False,
prime: False,
rational: False,
real: True,
zero: False}, negative=True

=========== tests finished: 1 passed, 1 exceptions, in 10.40 seconds ============
DO *NOT* COMMIT!
```