prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Avoid "impossible" ZeroDivisionError we keep seeing
  https://github.com/HypothesisWorks/hypothesis/blob/592bc7cd2c642bf273113083457444b4823021c9/hypothesis-python/src/hypothesis/statistics.py#L88-L95
  
  This snippet occasionally leads to problems, when `total_drawtime` is nonzero but `total_runtime` *is* zero, causing test failures [like this one](https://ci.appveyor.com/project/DRMacIver/hypothesis/build/1.0.458/job/hl2d74810901ttf5#L926).  I'm not sure why this happens - it's been observed on Python 2 (without) and Python 3 (with) a monotonic clock, so there might be multiple causes - but the solution is pretty simple.  All you need to do to fix this is to change the first conditional to
  
  ```python
  if total_drawtime <= 0.0 or total_runtime <= 0.0:
  ```
  
  Then write up a short changelog (see guides/documentation.rst), add your name to the contributors list (in - and read! - contributing.rst), and open a pull request!  If you have any questions, just let me know and I'd be happy to help out.
  
  </issue>
  <code>
  [start of hypothesis-python/src/hypothesis/statistics.py]
  1 # coding=utf-8
  2 #
  3 # This file is part of Hypothesis, which may be found at
  4 # https://github.com/HypothesisWorks/hypothesis-python
  5 #
  6 # Most of this work is copyright (C) 2013-2018 David R. MacIver
  7 # (david@drmaciver.com), but it contains contributions by others. See
  8 # CONTRIBUTING.rst for a full list of people who may hold copyright, and
  9 # consult the git log if you need to determine who owns an individual
  10 # contribution.
  11 #
  12 # This Source Code Form is subject to the terms of the Mozilla Public License,
  13 # v. 2.0. If a copy of the MPL was not distributed with this file, You can
  14 # obtain one at http://mozilla.org/MPL/2.0/.
  15 #
  16 # END HEADER
  17 
  18 from __future__ import division, print_function, absolute_import
  19 
  20 import math
  21 
  22 from hypothesis.utils.dynamicvariables import DynamicVariable
  23 from hypothesis.internal.conjecture.data import Status
  24 from hypothesis.internal.conjecture.engine import MAX_SHRINKS, ExitReason
  25 
  26 collector = DynamicVariable(None)
  27 
  28 
  29 class Statistics(object):
  30 
  31     def __init__(self, engine):
  32         self.passing_examples = len(
  33             engine.status_runtimes.get(Status.VALID, ()))
  34         self.invalid_examples = len(
  35             engine.status_runtimes.get(Status.INVALID, []) +
  36             engine.status_runtimes.get(Status.OVERRUN, [])
  37         )
  38         self.failing_examples = len(engine.status_runtimes.get(
  39             Status.INTERESTING, ()))
  40 
  41         runtimes = sorted(
  42             engine.status_runtimes.get(Status.VALID, []) +
  43             engine.status_runtimes.get(Status.INVALID, []) +
  44             engine.status_runtimes.get(Status.INTERESTING, [])
  45         )
  46 
  47         self.has_runs = bool(runtimes)
  48         if not self.has_runs:
  49             return
  50 
  51         n = max(0, len(runtimes) - 1)
  52         lower = int(runtimes[int(math.floor(n * 0.05))] * 1000)
  53         upper = int(runtimes[int(math.ceil(n * 0.95))] * 1000)
  54         if upper == 0:
  55             self.runtimes = '< 1ms'
  56         elif lower == upper:
  57             self.runtimes = '~ %dms' % (lower,)
  58         else:
  59             self.runtimes = '%d-%d ms' % (lower, upper)
  60 
  61         if engine.exit_reason == ExitReason.finished:
  62             self.exit_reason = 'nothing left to do'
  63         elif engine.exit_reason == ExitReason.flaky:
  64             self.exit_reason = 'test was flaky'
  65         elif engine.exit_reason == ExitReason.max_shrinks:
  66             self.exit_reason = 'shrunk example %s times' % (MAX_SHRINKS,)
  67         elif engine.exit_reason == ExitReason.max_iterations:
  68             self.exit_reason = ((
  69                 'settings.max_examples={}, but < 10% of examples satisfied '
  70                 'assumptions').format(engine.settings.max_examples)
  71             )
  72         else:
  73             self.exit_reason = (
  74                 'settings.%s=%r' % (
  75                     engine.exit_reason.name,
  76                     getattr(engine.settings, engine.exit_reason.name)
  77                 )
  78             )
  79 
  80         self.events = [
  81             '%.2f%%, %s' % (
  82                 c / engine.call_count * 100, e
  83             ) for e, c in sorted(
  84                 engine.event_call_counts.items(), key=lambda x: -x[1])
  85         ]
  86 
  87         total_runtime = math.fsum(engine.all_runtimes)
  88         total_drawtime = math.fsum(engine.all_drawtimes)
  89 
  90         if total_drawtime == 0.0:
  91             self.draw_time_percentage = '~ 0%'
  92         else:
  93             draw_time_percentage = 100.0 * min(
  94                 1, total_drawtime / total_runtime)
  95 
  96             self.draw_time_percentage = '~ %d%%' % (
  97                 round(draw_time_percentage),)
  98 
  99 
  100 def note_engine_for_statistics(engine):
  101     callback = collector.value
  102     if callback is not None:
  103         callback(Statistics(engine))
  104
  [end of hypothesis-python/src/hypothesis/statistics.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/hypothesis-python/src/hypothesis/statistics.py b/hypothesis-python/src/hypothesis/statistics.py
  --- a/hypothesis-python/src/hypothesis/statistics.py
  +++ b/hypothesis-python/src/hypothesis/statistics.py
  @@ -87,8 +87,15 @@
           total_runtime = math.fsum(engine.all_runtimes)
           total_drawtime = math.fsum(engine.all_drawtimes)
   
  -        if total_drawtime == 0.0:
  +        if total_drawtime == 0.0 and total_runtime >= 0.0:
               self.draw_time_percentage = '~ 0%'
  +        elif total_drawtime < 0.0 or total_runtime <= 0.0:
  +            # This weird condition is possible in two ways:
  +            # 1.  drawtime and/or runtime are negative, due to clock changes
  +            #     on Python 2 or old OSs (we use monotonic() where available)
  +            # 2.  floating-point issues *very rarely* cause math.fsum to be
  +            #     off by the lowest bit, so drawtime==0 and runtime!=0, eek!
  +            self.draw_time_percentage = 'NaN'
           else:
               draw_time_percentage = 100.0 * min(
                   1, total_drawtime / total_runtime)
  
verification_info: {"golden_diff": "diff --git a/hypothesis-python/src/hypothesis/statistics.py b/hypothesis-python/src/hypothesis/statistics.py\n--- a/hypothesis-python/src/hypothesis/statistics.py\n+++ b/hypothesis-python/src/hypothesis/statistics.py\n@@ -87,8 +87,15 @@\n         total_runtime = math.fsum(engine.all_runtimes)\n         total_drawtime = math.fsum(engine.all_drawtimes)\n \n-        if total_drawtime == 0.0:\n+        if total_drawtime == 0.0 and total_runtime >= 0.0:\n             self.draw_time_percentage = '~ 0%'\n+        elif total_drawtime < 0.0 or total_runtime <= 0.0:\n+            # This weird condition is possible in two ways:\n+            # 1.  drawtime and/or runtime are negative, due to clock changes\n+            #     on Python 2 or old OSs (we use monotonic() where available)\n+            # 2.  floating-point issues *very rarely* cause math.fsum to be\n+            #     off by the lowest bit, so drawtime==0 and runtime!=0, eek!\n+            self.draw_time_percentage = 'NaN'\n         else:\n             draw_time_percentage = 100.0 * min(\n                 1, total_drawtime / total_runtime)\n", "issue": "Avoid \"impossible\" ZeroDivisionError we keep seeing\nhttps://github.com/HypothesisWorks/hypothesis/blob/592bc7cd2c642bf273113083457444b4823021c9/hypothesis-python/src/hypothesis/statistics.py#L88-L95\r\n\r\nThis snippet occasionally leads to problems, when `total_drawtime` is nonzero but `total_runtime` *is* zero, causing test failures [like this one](https://ci.appveyor.com/project/DRMacIver/hypothesis/build/1.0.458/job/hl2d74810901ttf5#L926).  I'm not sure why this happens - it's been observed on Python 2 (without) and Python 3 (with) a monotonic clock, so there might be multiple causes - but the solution is pretty simple.  All you need to do to fix this is to change the first conditional to\r\n\r\n```python\r\nif total_drawtime <= 0.0 or total_runtime <= 0.0:\r\n```\r\n\r\nThen write up a short changelog (see guides/documentation.rst), add your name to the contributors list (in - and read! - contributing.rst), and open a pull request!  If you have any questions, just let me know and I'd be happy to help out.\n", "before_files": [{"content": "# coding=utf-8\n#\n# This file is part of Hypothesis, which may be found at\n# https://github.com/HypothesisWorks/hypothesis-python\n#\n# Most of this work is copyright (C) 2013-2018 David R. MacIver\n# (david@drmaciver.com), but it contains contributions by others. See\n# CONTRIBUTING.rst for a full list of people who may hold copyright, and\n# consult the git log if you need to determine who owns an individual\n# contribution.\n#\n# This Source Code Form is subject to the terms of the Mozilla Public License,\n# v. 2.0. If a copy of the MPL was not distributed with this file, You can\n# obtain one at http://mozilla.org/MPL/2.0/.\n#\n# END HEADER\n\nfrom __future__ import division, print_function, absolute_import\n\nimport math\n\nfrom hypothesis.utils.dynamicvariables import DynamicVariable\nfrom hypothesis.internal.conjecture.data import Status\nfrom hypothesis.internal.conjecture.engine import MAX_SHRINKS, ExitReason\n\ncollector = DynamicVariable(None)\n\n\nclass Statistics(object):\n\n    def __init__(self, engine):\n        self.passing_examples = len(\n            engine.status_runtimes.get(Status.VALID, ()))\n        self.invalid_examples = len(\n            engine.status_runtimes.get(Status.INVALID, []) +\n            engine.status_runtimes.get(Status.OVERRUN, [])\n        )\n        self.failing_examples = len(engine.status_runtimes.get(\n            Status.INTERESTING, ()))\n\n        runtimes = sorted(\n            engine.status_runtimes.get(Status.VALID, []) +\n            engine.status_runtimes.get(Status.INVALID, []) +\n            engine.status_runtimes.get(Status.INTERESTING, [])\n        )\n\n        self.has_runs = bool(runtimes)\n        if not self.has_runs:\n            return\n\n        n = max(0, len(runtimes) - 1)\n        lower = int(runtimes[int(math.floor(n * 0.05))] * 1000)\n        upper = int(runtimes[int(math.ceil(n * 0.95))] * 1000)\n        if upper == 0:\n            self.runtimes = '< 1ms'\n        elif lower == upper:\n            self.runtimes = '~ %dms' % (lower,)\n        else:\n            self.runtimes = '%d-%d ms' % (lower, upper)\n\n        if engine.exit_reason == ExitReason.finished:\n            self.exit_reason = 'nothing left to do'\n        elif engine.exit_reason == ExitReason.flaky:\n            self.exit_reason = 'test was flaky'\n        elif engine.exit_reason == ExitReason.max_shrinks:\n            self.exit_reason = 'shrunk example %s times' % (MAX_SHRINKS,)\n        elif engine.exit_reason == ExitReason.max_iterations:\n            self.exit_reason = ((\n                'settings.max_examples={}, but < 10% of examples satisfied '\n                'assumptions').format(engine.settings.max_examples)\n            )\n        else:\n            self.exit_reason = (\n                'settings.%s=%r' % (\n                    engine.exit_reason.name,\n                    getattr(engine.settings, engine.exit_reason.name)\n                )\n            )\n\n        self.events = [\n            '%.2f%%, %s' % (\n                c / engine.call_count * 100, e\n            ) for e, c in sorted(\n                engine.event_call_counts.items(), key=lambda x: -x[1])\n        ]\n\n        total_runtime = math.fsum(engine.all_runtimes)\n        total_drawtime = math.fsum(engine.all_drawtimes)\n\n        if total_drawtime == 0.0:\n            self.draw_time_percentage = '~ 0%'\n        else:\n            draw_time_percentage = 100.0 * min(\n                1, total_drawtime / total_runtime)\n\n            self.draw_time_percentage = '~ %d%%' % (\n                round(draw_time_percentage),)\n\n\ndef note_engine_for_statistics(engine):\n    callback = collector.value\n    if callback is not None:\n        callback(Statistics(engine))\n", "path": "hypothesis-python/src/hypothesis/statistics.py"}]}