Repository: boxed/mutmut

Issue:
Generation of unary plus in exponent is un-killable
Hello, thanks for the lovely tool!

mutmut generates mutants like the following, which are identical to the original code and thus un-killable (immortal?):

```diff
--- mvce/mvce.py
+++ mvce/mvce.py
@@ -1,3 +1,3 @@
 def multiply_by_1e100(number):
-    return number * 1e100
+    return number * 1e+100
```

Here's a test so that you can reproduce the whole thing:

```py
from mvce import multiply_by_1e100


def test_multiply_by_1e100():
    assert multiply_by_1e100(4) == 4e100
```

`1e16` seems to be the smallest number to which this happens. Smaller numbers get expanded from e.g. `1e2` to `101.0`

Discussion:

Patch:
diff --git a/mutmut/__init__.py b/mutmut/__init__.py
index a736caf..9af8f48 100644
--- a/mutmut/__init__.py
+++ b/mutmut/__init__.py
@@ -227,11 +227,17 @@ def number_mutation(value, **_):
 
     try:
         parsed = int(value, base=base)
+        result = repr(parsed + 1)
     except ValueError:
         # Since it wasn't an int, it must be a float
         parsed = float(value)
+        # This avoids all very small numbers becoming 1.0, and very
+        # large numbers not changing at all
+        if (1e-5 < abs(parsed) < 1e5) or (parsed == 0.0):
+            result = repr(parsed + 1)
+        else:
+            result = repr(parsed * 2)
 
-    result = repr(parsed + 1)
     if not result.endswith(suffix):
         result += suffix
     return result


Test patch:
diff --git a/tests/test_mutation.py b/tests/test_mutation.py
index 710c741..42c063e 100644
--- a/tests/test_mutation.py
+++ b/tests/test_mutation.py
@@ -74,6 +74,7 @@ for x in y:
         ('1.0', '2.0'),
         ('0.1', '1.1'),
         ('1e-3', '1.001'),
+        ('1e16', '2e+16'),
         ('True', 'False'),
         ('False', 'True'),
         ('"foo"', '"XXfooXX"'),
@@ -101,7 +102,8 @@ for x in y:
         ('1j', '2j'),
         ('1.0j', '2.0j'),
         ('0o1', '2'),
-        ('1.0e10', '10000000001.0'),
+        ('1.0e10', '20000000000.0'),
+        ('1.1e-16', '2.2e-16'),
         ("dict(a=b)", "dict(aXX=b)"),
         ("Struct(a=b)", "Struct(aXX=b)"),
         ("FooBarDict(a=b)", "FooBarDict(aXX=b)"),