Hello community,

here is the log from the commit of package python-hypothesis for 
openSUSE:Factory checked in at 2018-07-21 10:09:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-hypothesis (Old)
 and      /work/SRC/openSUSE:Factory/.python-hypothesis.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-hypothesis"

Sat Jul 21 10:09:37 2018 rev:24 rq:624329 version:3.66.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-hypothesis/python-hypothesis.changes      
2018-07-13 10:17:55.834210845 +0200
+++ /work/SRC/openSUSE:Factory/.python-hypothesis.new/python-hypothesis.changes 
2018-07-21 10:09:38.775178581 +0200
@@ -1,0 +2,6 @@
+Fri Jul 20 15:28:09 UTC 2018 - [email protected]
+
+- update to version 3.66.4:
+  * This release improves the shrinker’s ability to reorder examples.
+
+-------------------------------------------------------------------

Old:
----
  hypothesis-python-3.66.1.tar.gz

New:
----
  hypothesis-python-3.66.4.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-hypothesis.spec ++++++
--- /var/tmp/diff_new_pack.ouL3w1/_old  2018-07-21 10:09:39.167178491 +0200
+++ /var/tmp/diff_new_pack.ouL3w1/_new  2018-07-21 10:09:39.171178490 +0200
@@ -28,7 +28,7 @@
 %endif
 %bcond_without python2
 Name:           python-hypothesis
-Version:        3.66.1
+Version:        3.66.4
 Release:        0
 Summary:        A library for property based testing
 License:        MPL-2.0

++++++ hypothesis-python-3.66.1.tar.gz -> hypothesis-python-3.66.4.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hypothesis-hypothesis-python-3.66.1/CONTRIBUTING.rst 
new/hypothesis-hypothesis-python-3.66.4/CONTRIBUTING.rst
--- old/hypothesis-hypothesis-python-3.66.1/CONTRIBUTING.rst    2018-07-09 
01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/CONTRIBUTING.rst    2018-07-20 
15:37:18.000000000 +0200
@@ -158,6 +158,7 @@
 * `Alex Stapleton <https://www.github.com/public>`_
 * `Alex Willmer <https://github.com/moreati>`_ ([email protected])
 * `Ben Peterson <https://github.com/killthrush>`_ ([email protected])
+* `Bill Tucker <https://github.com/imbilltucker>`_ ([email protected])
 * `Buck Evan, copyright Google LLC <https://github.com/bukzor>`_
 * `Charles O'Farrell <https://www.github.com/charleso>`_
 * `Charlie Tanksley <https://www.github.com/charlietanksley>`_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/CHANGELOG.md 
new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/CHANGELOG.md
--- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/CHANGELOG.md        
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/CHANGELOG.md        
2018-07-20 15:37:18.000000000 +0200
@@ -1,3 +1,10 @@
+# Conjecture for Rust 0.3.0 (2018-07-16)
+
+This release adds support for annotating interesting examples
+to indicate that they are logically distinct. When multiple distinct
+reasons for being interesting are found, Conjecture will attempt to
+shrink all of them.
+
 # Conjecture for Rust 0.2.1 (2018-06-25)
 
 This release fixes an occasional assertion failure that could occur
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/Cargo.toml 
new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/Cargo.toml
--- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/Cargo.toml  
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/Cargo.toml  
2018-07-20 15:37:18.000000000 +0200
@@ -1,6 +1,6 @@
 [package]
 name = "conjecture"
-version = '0.2.1'
+version = '0.3.0'
 authors = ["David R. MacIver <[email protected]>"]
 
 homepage = 
"https://github.com/HypothesisWorks/hypothesis/tree/master/conjecture-rust";
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/data.rs 
new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/data.rs
--- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/data.rs 
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/data.rs 
2018-07-20 15:37:18.000000000 +0200
@@ -3,6 +3,7 @@
 
 use rand::{ChaChaRng, Rng};
 use std::collections::HashSet;
+use std::cmp::Ordering;
 
 pub type DataStream = Vec<u64>;
 
@@ -167,7 +168,7 @@
 
     // This was an interesting test execution! (Usually this
     // means failing, but for things like find it may not).
-    Interesting,
+    Interesting(u64),
 }
 
 // Once a data source is finished it "decays" to a
@@ -182,3 +183,25 @@
     pub sizes: Vec<u64>,
     pub written_indices: HashSet<usize>,
 }
+
+
+impl Ord for TestResult {
+    fn cmp(&self, other: &TestResult) -> Ordering {
+      self.record.len().cmp(&other.record.len()).
+      then(self.record.cmp(&other.record))
+    }
+}
+
+impl PartialOrd for TestResult {
+    fn partial_cmp(&self, other: &TestResult) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl PartialEq for TestResult {
+    fn eq(&self, other: &TestResult) -> bool {
+        self.record == other.record
+    }
+}
+
+impl Eq for TestResult { }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/engine.rs 
new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/engine.rs
--- old/hypothesis-hypothesis-python-3.66.1/conjecture-rust/src/engine.rs       
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/conjecture-rust/src/engine.rs       
2018-07-20 15:37:18.000000000 +0200
@@ -4,7 +4,7 @@
 use rand::{ChaChaRng, Rng, SeedableRng};
 
 use std::cmp::Reverse;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::mem;
 use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
 use std::thread;
@@ -33,6 +33,8 @@
     random: ChaChaRng,
 
     best_example: Option<TestResult>,
+    minimized_examples: HashMap<u64, TestResult>,
+    fully_minimized: HashSet<u64>,
 
     valid_examples: u64,
     invalid_examples: u64,
@@ -59,13 +61,36 @@
     }
 
     fn loop_body(&mut self) -> StepResult {
-        let interesting_example = self.generate_examples()?;
+        self.generate_examples()?;
 
-        let mut shrinker = Shrinker::new(self, interesting_example, |r| {
-            r.status == Status::Interesting
-        });
+        // At the start of this loop we can only have example in
+        // self.minimized_examples, but as we shrink we may find other ones.
+        // The reason why we loop is twofold:
+        // a) This allows us to include newly discovered examples. Labels that
+        //    are not found in self.minimized_examples at the beginning of the
+        //    loop will be added for the next iteration around.
+        // b) If we've previously marked a label as finished it can become
+        //    unfinished again if when shrinking another label, as when trying
+        //    to shrink one label we might accidentally find an improved shrink
+        //    for another.
+        // 
+        // In principle this might cause us to loop for a very long time before
+        // eventually settling on a fixed point, but when that happens we
+        // should hit limits on shrinking (which we haven't implemented yet).
+        while self.minimized_examples.len() > self.fully_minimized.len() {
+          let keys: Vec<u64> = self.minimized_examples.keys().map(|i| 
*i).collect();
+          for label in keys.iter() {
+            if self.fully_minimized.insert(*label) {
+              let target = self.minimized_examples[label].clone();
+              let mut shrinker = Shrinker::new(
+                self, target, |r| {
+                  r.status == Status::Interesting(*label)
+              });
 
-        shrinker.run()?;
+              shrinker.run()?;
+            }
+          }
+        }
 
         return Err(LoopExitReason::Complete);
     }
@@ -76,8 +101,9 @@
         {
             let r = self.random.gen();
             let result = self.execute(DataSource::from_random(r))?;
-            if result.status == Status::Interesting {
-                return Ok(result);
+            match result.status {
+              Status::Interesting(_) => return Ok(result),
+              _ => (),
             }
         }
         return Err(LoopExitReason::MaxExamples);
@@ -95,8 +121,19 @@
             Status::Overflow => (),
             Status::Invalid => self.invalid_examples += 1,
             Status::Valid => self.valid_examples += 1,
-            Status::Interesting => {
+            Status::Interesting(n) => {
                 self.best_example = Some(result.clone());
+                let mut changed = false;
+                self.minimized_examples.entry(n).or_insert_with(|| 
{result.clone()}); 
+                self.minimized_examples.entry(n).and_modify(|e| {
+                  if result < *e {
+                    changed = true;
+                    *e = result.clone()
+                  }; 
+                });
+                if changed {
+                  self.fully_minimized.remove(&n);
+                }
                 self.interesting_examples += 1;
             }
         }
@@ -497,6 +534,8 @@
             sender: send_remote,
             receiver: recv_remote,
             best_example: None,
+            minimized_examples: HashMap::new(),
+            fully_minimized: HashSet::new(),
             valid_examples: 0,
             invalid_examples: 0,
             interesting_examples: 0,
@@ -541,6 +580,23 @@
         }
     }
 
+    pub fn list_minimized_examples(&self) -> Vec<TestResult> {
+        match &self.loop_response {
+            &Some(LoopCommand::Finished(
+                _,
+                MainGenerationLoop {
+                    ref minimized_examples,
+                    ..
+                },
+            )) => {
+              let mut results: Vec<TestResult> = 
minimized_examples.values().map(|v| v.clone()).collect();
+              results.sort();
+              results
+            },
+            _ => Vec::new(),
+        }
+    }
+
     pub fn best_source(&self) -> Option<DataSource> {
         match &self.loop_response {
             &Some(LoopCommand::Finished(
@@ -554,6 +610,7 @@
         }
     }
 
+
     fn consume_test_result(&mut self, result: TestResult) -> () {
         assert!(self.state == EngineState::AwaitingCompletion);
         self.state = EngineState::ReadyToProvide;
@@ -623,3 +680,40 @@
         }
     }
 }
+
+
+#[cfg(test)]
+mod tests {
+  use super::*;
+  use data::FailedDraw;
+
+  fn run_to_results<F>(mut f: F) -> Vec<TestResult>
+    where F: FnMut(&mut DataSource) -> Result<Status, FailedDraw> {
+    let seed: [u32; 2] = [0, 0];
+    let mut engine = Engine::new(1000, &seed);
+    while let Some(mut source) = engine.next_source() {
+      if let Ok(status) = f(&mut source) {
+        engine.mark_finished(source, status);
+      } else {
+        engine.mark_finished(source, Status::Overflow);
+      }
+    }
+    engine.list_minimized_examples()
+  }
+
+  #[test]
+  fn minimizes_all_examples(){
+    let results = run_to_results(|source| {
+      let n = source.bits(64)?;
+      if n >= 100 {
+        Ok(Status::Interesting(n % 2))
+      } else {
+        Ok(Status::Valid)
+      }
+    });
+
+    assert!(results.len() == 2);
+    assert_eq!(results[0].record[0], 100);
+    assert_eq!(results[1].record[0], 101);
+  }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/changes.rst 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/changes.rst
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/changes.rst  
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/changes.rst  
2018-07-20 15:37:18.000000000 +0200
@@ -21,6 +21,71 @@
 You should generally assume that an API is internal unless you have specific
 information to the contrary.
 
+.. _v3.66.4:
+
+-------------------
+3.66.4 - 2018-07-20
+-------------------
+
+This release improves the shrinker's ability to reorder examples.
+
+For example, consider the following test:
+
+.. code-block:: python
+
+    import hypothesis.strategies as st
+    from hypothesis import given
+
+    @given(st.text(), st.text())
+    def test_non_equal(x, y):
+        assert x != y
+
+Previously this could have failed with either of ``x="", y="0"`` or
+``x="0", y=""``. Now it should always fail with ``x="", y="0"``.
+
+This will allow the shrinker to produce more consistent results, especially in
+cases where test cases contain some ordered collection whose actual order does
+not matter.
+
+.. _v3.66.3:
+
+-------------------
+3.66.3 - 2018-07-20
+-------------------
+
+This patch fixes inference in the :func:`~hypothesis.strategies.builds`
+strategy with subtypes of :class:`python:typing.NamedTuple`, where the
+``__init__`` method is not useful for introspection.  We now use the
+field types instead - thanks to James Uther for identifying this bug.
+
+.. _v3.66.2:
+
+-------------------
+3.66.2 - 2018-07-19
+-------------------
+
+This release improves the shrinker's ability to handle situations where there
+is an additive constraint between two values.
+
+For example, consider the following test:
+
+
+.. code-block:: python
+
+    import hypothesis.strategies as st
+    from hypothesis import given
+
+    @given(st.integers(), st.integers())
+    def test_does_not_exceed_100(m, n):
+        assert m + n < 100
+
+Previously this could have failed with almost any pair ``(m, n)`` with
+``0 <= m <= n`` and ``m + n == 100``. Now it should almost always fail with
+``m=0, n=100``.
+
+This is a relatively niche specialisation, but can be useful in situations
+where e.g. a bug is triggered by an integer overflow.
+
 .. _v3.66.1:
 
 -------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/endorsements.rst 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/endorsements.rst
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/endorsements.rst 
    2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/endorsements.rst 
    2018-07-20 15:37:18.000000000 +0200
@@ -185,6 +185,18 @@
 
 __ 
https://github.com/merchise/xoutil/commit/0a4a0f529812fed363efb653f3ade2d2bc203945
 
+----------------------------------------------
+`Florian Kromer <https://github.com/fkromer>`_
+----------------------------------------------
+
+At `Roboception GmbH <https://roboception.com/en/>`_ I use Hypothesis to
+implement fully automated stateless and stateful reliability tests for the
+`3D sensor rc_visard <https://roboception.com/en/rc_visard-en/>`_ and
+`robotic software components <https://roboception.com/en/rc_reason-en/>`_ .
+
+Thank you very much for creating the (probably) most powerful property-based
+testing framework.
+
 -------------------------------------------
 `Your name goes here <http://example.com>`_
 -------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/examples.rst 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/examples.rst
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/docs/examples.rst 
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/docs/examples.rst 
2018-07-20 15:37:18.000000000 +0200
@@ -94,7 +94,7 @@
 
 .. code:: python
 
-  from hypothesis import settings, strategy
+  from hypothesis import settings, strategies
   import hypothesis.strategies as s
 
   NodeStrategy = s.builds(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/compat.py
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/compat.py
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/compat.py
 2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/compat.py
 2018-07-20 15:37:18.000000000 +0200
@@ -25,6 +25,7 @@
 import time
 import array
 import codecs
+import inspect
 import platform
 import importlib
 from base64 import b64encode
@@ -277,7 +278,6 @@
                              'kwonlyargs, kwonlydefaults, annotations')
 
     def getfullargspec(func):
-        import inspect
         args, varargs, varkw, defaults = inspect.getargspec(func)
         return FullArgSpec(args, varargs, varkw, defaults, [], None,
                            getattr(func, '__annotations__', {}))
@@ -296,9 +296,10 @@
         except TypeError:
             return {}
 else:
+    import typing
+
     def get_type_hints(thing):
         try:
-            import typing
             return typing.get_type_hints(thing)
         except TypeError:
             return {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/conjecture/engine.py
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/conjecture/engine.py
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/conjecture/engine.py
      2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/conjecture/engine.py
      2018-07-20 15:37:18.000000000 +0200
@@ -1335,10 +1335,12 @@
             if not run_expensive_shrinks:
                 continue
 
+            self.reorder_examples()
             self.shrink_offset_pairs()
             self.interval_deletion_with_block_lowering()
             self.pass_to_interval()
             self.reorder_bytes()
+            self.minimize_block_pairs_retaining_sum()
 
     @property
     def blocks(self):
@@ -2279,3 +2281,104 @@
                     break
             else:
                 i += 1
+
+    def minimize_block_pairs_retaining_sum(self):
+        """This pass minimizes pairs of blocks subject to the constraint that
+        their sum when interpreted as integers remains the same. This allow us
+        to normalize a number of examples that we would otherwise struggle on.
+        e.g. consider the following:
+
+        m = data.draw_bits(8)
+        n = data.draw_bits(8)
+        if m + n >= 256:
+            data.mark_interesting()
+
+        The ideal example for this is m=1, n=255, but we will almost never
+        find that without a pass like this - we would only do so if we
+        happened to draw n=255 by chance.
+
+        This kind of scenario comes up reasonably often in the context of e.g.
+        triggering overflow behaviour.
+        """
+        i = 0
+        while i < len(self.shrink_target.blocks):
+            if self.is_payload_block(i):
+                j = i + 1
+                while j < len(self.shrink_target.blocks):
+                    u, v = self.shrink_target.blocks[i]
+                    m = int_from_bytes(self.shrink_target.buffer[u:v])
+                    if m == 0:
+                        break
+                    r, s = self.shrink_target.blocks[j]
+                    n = int_from_bytes(self.shrink_target.buffer[r:s])
+
+                    if (
+                        s - r == v - u and
+                        self.is_payload_block(j)
+                    ):
+                        def trial(x, y):
+                            if s > len(self.shrink_target.buffer):
+                                return False
+                            attempt = bytearray(self.shrink_target.buffer)
+                            try:
+                                attempt[u:v] = int_to_bytes(x, v - u)
+                                attempt[r:s] = int_to_bytes(y, s - r)
+                            except OverflowError:
+                                return False
+                            return self.incorporate_new_buffer(attempt)
+                        # We first attempt to move 1 from m to n. If that works
+                        # then we treat that as a sign that it's worth trying
+                        # a more expensive minimization. But if m was already 1
+                        # (we know it's > 0) then there's no point continuing
+                        # because the value there is now zero.
+                        if trial(m - 1, n + 1) and m > 1:
+                            m = int_from_bytes(self.shrink_target.buffer[u:v])
+                            n = int_from_bytes(self.shrink_target.buffer[r:s])
+
+                            tot = m + n
+                            minimize_int(
+                                m, lambda x: trial(x, tot - x)
+                            )
+                    j += 1
+            i += 1
+
+    def reorder_examples(self):
+        """This pass allows us to reorder pairs of examples which come from the
+        same strategy (or strategies that happen to pun to the same label by
+        accident, but that shouldn't happen often).
+
+        For example, consider the following:
+
+        .. code-block:: python
+
+            import hypothesis.strategies as st
+            from hypothesis import given
+
+            @given(st.text(), st.text())
+            def test_does_not_exceed_100(x, y):
+                assert x != y
+
+        Without the ability to reorder x and y this could fail either with
+        ``x="", ``y="0"``, or the other way around. With reordering it will
+        reliably fail with ``x=""``, ``y="0"``.
+        """
+        i = 0
+        while i < len(self.shrink_target.examples):
+            j = i + 1
+            while j < len(self.shrink_target.examples):
+                ex1 = self.shrink_target.examples[i]
+                ex2 = self.shrink_target.examples[j]
+                if ex1.label == ex2.label and ex2.start >= ex1.end:
+                    buf = self.shrink_target.buffer
+                    attempt = (
+                        buf[:ex1.start] +
+                        buf[ex2.start:ex2.end] +
+                        buf[ex1.end:ex2.start] +
+                        buf[ex1.start:ex1.end] +
+                        buf[ex2.end:]
+                    )
+                    assert len(attempt) == len(buf)
+                    if attempt < buf:
+                        self.incorporate_new_buffer(attempt)
+                j += 1
+            i += 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/reflection.py
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/reflection.py
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/internal/reflection.py
     2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/internal/reflection.py
     2018-07-20 15:37:18.000000000 +0200
@@ -88,6 +88,18 @@
     return hasher.digest()
 
 
+def is_typed_named_tuple(cls):
+    """Return True if cls is probably a subtype of `typing.NamedTuple`.
+
+    Unfortunately types created with `class T(NamedTuple):` actually
+    subclass `tuple` directly rather than NamedTuple.  This is annoying,
+    and means we just have to hope that nobody defines a different tuple
+    subclass with similar attributes.
+    """
+    return issubclass(cls, tuple) and hasattr(cls, '_fields') and \
+        hasattr(cls, '_field_types')
+
+
 def required_args(target, args=(), kwargs=()):
     """Return a set of names of required args to target that were not supplied
     in args or kwargs.
@@ -97,6 +109,11 @@
     and bound methods).  args and kwargs should be as they are passed to
     builds() - that is, a tuple of values and a dict of names: values.
     """
+    # We start with a workaround for NamedTuples, which don't have nice inits
+    if inspect.isclass(target) and is_typed_named_tuple(target):
+        provided = set(kwargs) | set(target._fields[:len(args)])
+        return set(target._fields) - provided
+    # Then we try to do the right thing with getfullargspec
     try:
         spec = getfullargspec(
             target.__init__ if inspect.isclass(target) else target)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/strategies.py
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/strategies.py
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/strategies.py
      2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/strategies.py
      2018-07-20 15:37:18.000000000 +0200
@@ -46,7 +46,7 @@
 from hypothesis.internal.renaming import renamed_arguments
 from hypothesis.utils.conventions import infer, not_set
 from hypothesis.internal.reflection import proxies, required_args, \
-    define_function_signature
+    is_typed_named_tuple, define_function_signature
 from hypothesis.internal.validation import check_type, try_convert, \
     check_valid_size, check_valid_bound, check_valid_sizes, \
     check_valid_integer, check_valid_interval, check_valid_magnitude
@@ -1125,8 +1125,14 @@
             from hypothesis.searchstrategy.attrs import from_attrs
             return from_attrs(target, args, kwargs, required | to_infer)
         # Otherwise, try using type hints
-        hints = get_type_hints(
-            target.__init__ if isclass(target) else target)
+        if isclass(target):
+            if is_typed_named_tuple(target):
+                # Special handling for typing.NamedTuple
+                hints = target._field_types
+            else:
+                hints = get_type_hints(target.__init__)
+        else:
+            hints = get_type_hints(target)
         if to_infer - set(hints):
             raise InvalidArgument(
                 'passed infer for %s, but there is no type annotation'
@@ -1248,25 +1254,22 @@
         return one_of(strategies)
     # If we don't have a strategy registered for this type or any subtype, we
     # may be able to fall back on type annotations.
-    # Types created via typing.NamedTuple use a custom attribute instead -
-    # but we can still use builds(), if we work out the right kwargs.
-    if issubclass(thing, tuple) and hasattr(thing, '_fields') \
-            and hasattr(thing, '_field_types'):
-        kwargs = {k: from_type(thing._field_types[k]) for k in thing._fields}
-        return builds(thing, **kwargs)
     if issubclass(thing, enum.Enum):
         assert len(thing), repr(thing) + ' has no members to sample'
         return sampled_from(thing)
-    # If the constructor has an annotation for all required arguments,
-    # or the class was defined with attrs, builds(thing) will work.
-    # (unless inference fails for an argument, but that's the same above too)
+    # If we know that builds(thing) will fail, give a better error message
     required = required_args(thing)
-    if not required or required.issubset(get_type_hints(thing.__init__)) or \
-            attr.has(thing):
-        return builds(thing)
-    # We have utterly failed, and might as well say so now.
-    raise ResolutionFailed('Could not resolve %r to a strategy; consider '
-                           'using register_type_strategy' % (thing,))
+    if not any([
+        not required,
+        required.issubset(get_type_hints(thing.__init__)),
+        attr.has(thing),
+        # NamedTuples are weird enough that we need a specific check for them.
+        is_typed_named_tuple(thing),
+    ]):
+        raise ResolutionFailed('Could not resolve %r to a strategy; consider '
+                               'using register_type_strategy' % (thing,))
+    # Finally, try to build an instance by calling the type object
+    return builds(thing)
 
 
 @cacheable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/version.py
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/version.py
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/src/hypothesis/version.py
 2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/src/hypothesis/version.py
 2018-07-20 15:37:18.000000000 +0200
@@ -17,5 +17,5 @@
 
 from __future__ import division, print_function, absolute_import
 
-__version_info__ = (3, 66, 1)
+__version_info__ = (3, 66, 4)
 __version__ = '.'.join(map(str, __version_info__))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/cover/test_conjecture_engine.py
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/cover/test_conjecture_engine.py
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/cover/test_conjecture_engine.py
     2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/cover/test_conjecture_engine.py
     2018-07-20 15:37:18.000000000 +0200
@@ -1330,3 +1330,69 @@
         runner.run()
 
     assert runner.exit_reason == ExitReason.finished
+
+
[email protected]('lo', [0, 1, 50])
+def test_can_shrink_additively(monkeypatch, lo):
+    monkeypatch.setattr(
+        ConjectureRunner, 'generate_new_examples',
+        lambda self: self.test_function(
+            ConjectureData.for_buffer(hbytes([100, 100]))))
+
+    @run_to_buffer
+    def x(data):
+        m = data.draw_bits(8)
+        n = data.draw_bits(8)
+        if m >= lo and m + n == 200:
+            data.mark_interesting()
+
+    assert list(x) == [lo, 200 - lo]
+
+
+def test_can_shrink_additively_losing_size(monkeypatch):
+    monkeypatch.setattr(
+        ConjectureRunner, 'generate_new_examples',
+        lambda self: self.test_function(
+            ConjectureData.for_buffer(hbytes([100, 100]))))
+
+    monkeypatch.setattr(
+        Shrinker, 'shrink', lambda self: (
+            self.minimize_block_pairs_retaining_sum(),
+        )
+    )
+
+    @run_to_buffer
+    def x(data):
+        m = data.draw_bits(8)
+        if m >= 10:
+            if m <= 50:
+                data.mark_interesting()
+            else:
+                n = data.draw_bits(8)
+                if m + n == 200:
+                    data.mark_interesting()
+    assert len(x) == 1
+
+
+def test_can_reorder_examples(monkeypatch):
+    monkeypatch.setattr(
+        ConjectureRunner, 'generate_new_examples',
+        lambda runner: runner.test_function(
+            ConjectureData.for_buffer([1, 0, 1, 1, 0, 1, 0, 0, 0])))
+
+    monkeypatch.setattr(
+        Shrinker, 'shrink', Shrinker.reorder_examples,
+    )
+
+    @run_to_buffer
+    def x(data):
+        total = 0
+        for _ in range(5):
+            data.start_example(0)
+            if data.draw_bits(8):
+                total += data.draw_bits(9)
+            data.stop_example(0)
+        if total == 2:
+            data.mark_interesting()
+
+    assert list(x) == [0, 0, 0, 1, 0, 1, 1, 0, 1]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/py3/test_lookup.py
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/py3/test_lookup.py
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-python/tests/py3/test_lookup.py
  2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-python/tests/py3/test_lookup.py
  2018-07-20 15:37:18.000000000 +0200
@@ -367,6 +367,24 @@
               **{k: st.just(v) for k, v in kwargs.items()}).example()
 
 
+AnnotatedNamedTuple = typing.NamedTuple('AnnotatedNamedTuple', [('a', str)])
+
+
+@given(st.builds(AnnotatedNamedTuple))
+def test_infers_args_for_namedtuple_builds(thing):
+    assert isinstance(thing.a, str)
+
+
+@given(st.from_type(AnnotatedNamedTuple))
+def test_infers_args_for_namedtuple_from_type(thing):
+    assert isinstance(thing.a, str)
+
+
+@given(st.builds(AnnotatedNamedTuple, a=st.none()))
+def test_override_args_for_namedtuple(thing):
+    assert thing.a is None
+
+
 @pytest.mark.parametrize('thing', [
     typing.Optional, typing.List, getattr(typing, 'Type', typing.Set)
 ])  # check Type if it's available, otherwise Set is redundant but harmless
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/.rubocop.yml 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/.rubocop.yml
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/.rubocop.yml        
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/.rubocop.yml        
2018-07-20 15:37:18.000000000 +0200
@@ -26,3 +26,5 @@
   Enabled: false
 Lint/HandleExceptions:
   Enabled: false
+Style/GuardClause:
+  Enabled: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/CHANGELOG.md 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/CHANGELOG.md
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/CHANGELOG.md        
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/CHANGELOG.md        
2018-07-20 15:37:18.000000000 +0200
@@ -1,3 +1,8 @@
+# Hypothesis for Ruby 0.1.0 (2018-07-16)
+
+This release adds support for reporting multiple exceptions when Hypothesis
+finds more than one way for the test to fail.
+
 # Hypothesis for Ruby 0.0.15 (2018-06-25)
 
 This release fixes an occasional `RuntimeError` that could occur
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/Gemfile.lock 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/Gemfile.lock
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/Gemfile.lock        
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/Gemfile.lock        
2018-07-20 15:37:18.000000000 +0200
@@ -1,7 +1,7 @@
 PATH
   remote: .
   specs:
-    hypothesis-specs (0.0.14)
+    hypothesis-specs (0.0.15)
       helix_runtime (~> 0.7.0)
       rake (>= 10.0, < 13.0)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/hypothesis-specs.gemspec
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/hypothesis-specs.gemspec
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/hypothesis-specs.gemspec
    2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/hypothesis-specs.gemspec
    2018-07-20 15:37:18.000000000 +0200
@@ -2,8 +2,8 @@
 
 Gem::Specification.new do |s|
   s.name        = 'hypothesis-specs'
-  s.version     = '0.0.15'
-  s.date        = '2018-06-25'
+  s.version     = '0.1.0'
+  s.date        = '2018-07-16'
   s.description = <<~DESCRIPTION
     Hypothesis is a powerful, flexible, and easy to use library for 
property-based testing.
 DESCRIPTION
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/engine.rb
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/engine.rb
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/engine.rb
    2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/engine.rb
    2018-07-20 15:37:18.000000000 +0200
@@ -2,9 +2,12 @@
 
 require 'helix_runtime'
 require 'hypothesis-ruby/native'
+require 'rspec/expectations'
 
 module Hypothesis
   class Engine
+    include RSpec::Matchers
+
     attr_reader :current_source
     attr_accessor :is_find
 
@@ -13,6 +16,8 @@
       @core_engine = HypothesisCoreEngine.new(
         seed, options.fetch(:max_examples)
       )
+
+      @exceptions_to_tags = Hash.new { |h, k| h[k] = h.size }
     end
 
     def run
@@ -23,7 +28,7 @@
         begin
           result = yield(@current_source)
           if is_find && result
-            @core_engine.finish_interesting(core)
+            @core_engine.finish_interesting(core, 0)
           else
             @core_engine.finish_valid(core)
           end
@@ -31,54 +36,64 @@
           @core_engine.finish_invalid(core)
         rescue DataOverflow
           @core_engine.finish_overflow(core)
-        rescue Exception
+        rescue Exception => e
           raise if is_find
-          @core_engine.finish_interesting(core)
+          key = [
+            e.class,
+            HypothesisJunkDrawer.find_first_relevant_line(e.backtrace)
+          ]
+          @core_engine.finish_interesting(core, @exceptions_to_tags[key])
         end
       end
-      @current_source = nil
-      core = @core_engine.failing_example
-      if core.nil?
+      if @core_engine.count_failing_examples.zero?
         raise Unsatisfiable if @core_engine.was_unsatisfiable
+        @current_source = nil
         return
       end
 
       if is_find
+        core = @core_engine.failing_example(0)
         @current_source = TestCase.new(core, record_draws: true)
         yield @current_source
       else
-        @current_source = TestCase.new(core, print_draws: true)
-
-        begin
-          yield @current_source
-        rescue Exception => e
-          givens = @current_source.print_log
-          given_str = givens.each_with_index.map do |(name, s), i|
-            name = "##{i + 1}" if name.nil?
-            "Given #{name}: #{s}"
-          end.to_a
-
-          if e.respond_to? :hypothesis_data
-            e.hypothesis_data[0] = given_str
-          else
-            original_to_s = e.to_s
-            original_inspect = e.inspect
-
-            class <<e
-              attr_accessor :hypothesis_data
-
-              def to_s
-                ['', hypothesis_data[0], '', hypothesis_data[1]].join("\n")
-              end
-
-              def inspect
-                ['', hypothesis_data[0], '', hypothesis_data[2]].join("\n")
+        exceptions = []
+        (0...@core_engine.count_failing_examples).each do |example|
+          core = @core_engine.failing_example(example)
+          @current_source = TestCase.new(core, print_draws: true)
+
+          begin
+            yield @current_source
+          rescue Exception => e
+            givens = @current_source.print_log
+            given_str = givens.each_with_index.map do |(name, s), i|
+              name = "##{i + 1}" if name.nil?
+              "Given #{name}: #{s}"
+            end.to_a
+
+            if e.respond_to? :hypothesis_data
+              e.hypothesis_data[0] = given_str
+            else
+              original_to_s = e.to_s
+              original_inspect = e.inspect
+
+              class <<e
+                attr_accessor :hypothesis_data
+
+                def to_s
+                  ['', hypothesis_data[0], '', hypothesis_data[1]].join("\n")
+                end
+
+                def inspect
+                  ['', hypothesis_data[0], '', hypothesis_data[2]].join("\n")
+                end
               end
+              e.hypothesis_data = [given_str, original_to_s, original_inspect]
             end
-            e.hypothesis_data = [given_str, original_to_s, original_inspect]
+            raise e if @core_engine.count_failing_examples == 1
+            exceptions.push(e)
           end
-          raise e
         end
+        raise Hypothesis::MultipleExceptionError.new(*exceptions)
       end
     end
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/errors.rb
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/errors.rb
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/errors.rb
    2018-07-09 01:06:33.000000000 +0200
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/errors.rb
    2018-07-20 15:37:18.000000000 +0200
@@ -25,4 +25,37 @@
   # @!visibility private
   class DataOverflow < HypothesisError
   end
+
+  if defined?(RSpec::Core::MultipleExceptionError)
+    MultipleExceptionErrorParent = RSpec::Core::MultipleExceptionError
+  # :nocov:
+  else
+    class MultipleExceptionErrorParent < StandardError
+      def initialize(*exceptions)
+        super()
+
+        @all_exceptions = exceptions.to_a
+      end
+
+      attr_reader :all_exceptions
+    end
+  end
+
+  class MultipleExceptionError < MultipleExceptionErrorParent
+    def message
+      jd = HypothesisJunkDrawer
+      "Test raised #{all_exceptions.length} distinct errors:\n\n" +
+        all_exceptions.map do |e|
+          location = jd.find_first_relevant_line(e.backtrace).sub(/:in.+$/, '')
+          backtrace = jd.prune_backtrace(e.backtrace)
+          "#{e.class} at #{location}:\n" \
+            "#{e.message}\n#{backtrace.map { |s| '  ' + s }
+              .join("\n")}"
+        end.join("\n\n")
+    end
+
+    def backtrace
+      []
+    end
+  end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/junkdrawer.rb
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/junkdrawer.rb
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis/junkdrawer.rb
        1970-01-01 01:00:00.000000000 +0100
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis/junkdrawer.rb
        2018-07-20 15:37:18.000000000 +0200
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Hypothesis
+  # @!visibility private
+  module HypothesisJunkDrawer
+    HYPOTHESIS_ROOT = File.absolute_path(File.dirname(__FILE__))
+
+    def self.prune_backtrace(backtrace)
+      result = []
+      seen_hypothesis = false
+      backtrace.each do |b|
+        if b.start_with?(HYPOTHESIS_ROOT)
+          seen_hypothesis = true
+        else
+          result.push(b)
+          break if seen_hypothesis
+        end
+      end
+      result
+    end
+
+    def self.find_first_relevant_line(backtrace)
+      backtrace.each do |b|
+        next if b.include?('minitest/assertions.rb')
+        next if b.start_with?(HYPOTHESIS_ROOT)
+        return b
+      end
+      nil
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis.rb 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis.rb
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/lib/hypothesis.rb   
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/lib/hypothesis.rb   
2018-07-20 15:37:18.000000000 +0200
@@ -1,5 +1,6 @@
 # frozen_string_literal: true
 
+require 'hypothesis/junkdrawer'
 require 'hypothesis/errors'
 require 'hypothesis/possible'
 require 'hypothesis/testcase'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/minitests/test_multiple_failures.rb
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/minitests/test_multiple_failures.rb
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/minitests/test_multiple_failures.rb
 1970-01-01 01:00:00.000000000 +0100
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/minitests/test_multiple_failures.rb
 2018-07-20 15:37:18.000000000 +0200
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'minitest/autorun'
+require 'hypothesis'
+
+class TestMultipleFailures < Minitest::Test
+  include Hypothesis
+  include Hypothesis::Possibilities
+
+  def test_multiple_failures
+    assert_raises(Hypothesis::MultipleExceptionError) do
+      @initial = nil
+
+      hypothesis do
+        x = any integers
+        if @initial.nil?
+          if x >= 1000
+            @initial = x
+          else
+            next
+          end
+        end
+
+        assert(x != @initial)
+        raise 'Nope'
+      end
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/backtrace_spec.rb 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/backtrace_spec.rb
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/backtrace_spec.rb  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/backtrace_spec.rb  
    2018-07-20 15:37:18.000000000 +0200
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+RSpec.describe 'backtrace manipulation' do
+  JD = Hypothesis::HypothesisJunkDrawer
+
+  it 'identifies the test file as relevant' do
+    JD.find_first_relevant_line(caller).include?('backtrace_spec.rb')
+  end
+
+  it 'prunes out hypothesis and rspec related lines' do
+    hypothesis do
+      relevant = JD.prune_backtrace(caller)
+      relevant.each do |e|
+        expect(e).to_not include(JD::HYPOTHESIS_ROOT)
+        expect(e).to_not include('/rspec-core/')
+      end
+      expect(relevant.grep(/backtrace_spec.rb/)).to_not be_empty
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/multiple_failures_spec.rb
 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/multiple_failures_spec.rb
--- 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/multiple_failures_spec.rb
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/multiple_failures_spec.rb
      2018-07-20 15:37:18.000000000 +0200
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+RSpec.describe 'tests with multiple failures' do
+  they 'show multiple failures' do
+    expect do
+      @initial = nil
+
+      hypothesis do
+        x = any integers
+        if @initial.nil?
+          if x >= 1000
+            @initial = x
+          else
+            next
+          end
+        end
+
+        expect(x).to_not eq(@initial)
+        raise 'Nope'
+      end
+    end.to raise_exception(Hypothesis::MultipleExceptionError) { |e|
+      expect(e.all_exceptions.length).to eq(2)
+    }
+  end
+end
+
+RSpec.describe Hypothesis::MultipleExceptionError do
+  it 'includes the message from each exception' do
+    exceptions = []
+    %w[hello world].each do |m|
+      begin
+        raise m
+      rescue Exception => e
+        exceptions.append(e)
+      end
+    end
+
+    e = Hypothesis::MultipleExceptionError.new(*exceptions)
+    expect(e.message).to include('hello')
+    expect(e.message).to include('world')
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/spec_helper.rb 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/spec_helper.rb
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/spec/spec_helper.rb 
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/spec/spec_helper.rb 
2018-07-20 15:37:18.000000000 +0200
@@ -2,10 +2,51 @@
 
 require 'simplecov'
 SimpleCov.minimum_coverage 100
+
+class PrintingFormatter
+  # Takes a SimpleCov::Result and generates a string out of it
+  def format(result)
+    bad = []
+    result.files.each do |file|
+      bad.push file if file.covered_percent < 100.0
+    end
+
+    unless bad.empty?
+      puts 'Files with missing coverage!'
+      bad.each do |file|
+        lines = file.source_lines.select { |l| l.coverage == 0 }
+                    .map(&:line_number).sort
+        s = lines[0]
+        groups = [[s, s]]
+        lines.each do |i|
+          if i <= groups[-1][-1] + 1
+            groups[-1][-1] = i
+          else
+            groups.push([i, i])
+          end
+        end
+        markers = []
+        groups.each do |g|
+          if g[0] == g[1]
+            markers.push(g[0].to_s)
+          else
+            markers.push(g.join('-'))
+          end
+        end
+        puts "#{file.filename}: #{markers.join(', ')}"
+      end
+    end
+  end
+end
+
+SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(
+  [SimpleCov::Formatter::HTMLFormatter, PrintingFormatter]
+)
+
 SimpleCov.start do
   add_filter do |source_file|
     name = source_file.filename
-    !(name.include?('/hypothesis/') || name.end_with?('hypothesis.rb'))
+    !(name.include?('/hypothesis-ruby/lib/') || 
name.end_with?('hypothesis.rb'))
   end
 end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/src/lib.rs 
new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/src/lib.rs
--- old/hypothesis-hypothesis-python-3.66.1/hypothesis-ruby/src/lib.rs  
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/hypothesis-ruby/src/lib.rs  
2018-07-20 15:37:18.000000000 +0200
@@ -15,7 +15,7 @@
 
 use std::mem;
 
-use conjecture::data::{DataSource, Status};
+use conjecture::data::{DataSource, Status, TestResult};
 use conjecture::distributions::Repeat;
 use conjecture::distributions;
 use conjecture::engine::Engine;
@@ -49,6 +49,7 @@
     struct {
       engine: Engine,
       pending: Option<DataSource>,
+      interesting_examples: Vec<TestResult>,
     }
 
     def initialize(helix, seed: u64, max_examples: u64){
@@ -57,12 +58,16 @@
         helix,
         engine: Engine::new(max_examples, &xs),
         pending: None,
+        interesting_examples: Vec::new(),
       }
     }
 
     def new_source(&mut self) -> Option<HypothesisCoreDataSource> {
       match self.engine.next_source() {
-        None => None,
+        None => {
+          self.interesting_examples = self.engine.list_minimized_examples();
+          None
+        },
         Some(source) => {
           self.pending = Some(source);
           Some(HypothesisCoreDataSource::new(self))
@@ -70,13 +75,15 @@
       }
     }
 
-    def failing_example(&mut self) -> Option<HypothesisCoreDataSource> {
-      if let Some(source) = self.engine.best_source() {
-        self.pending = Some(source);
-        return Some(HypothesisCoreDataSource::new(self));
-      } else {
-        return None;
-      }
+    def count_failing_examples(&self) -> usize {
+      self.interesting_examples.len()
+    }
+
+    def failing_example(&mut self, i: usize) -> HypothesisCoreDataSource {
+      self.pending = Some(
+        DataSource::from_vec(self.interesting_examples[i].record.clone())
+      );
+      HypothesisCoreDataSource::new(self)
     }
 
     def was_unsatisfiable(&mut self) -> bool {
@@ -91,8 +98,8 @@
       mark_child_status(&mut self.engine, child, Status::Invalid);
     }
 
-    def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource){
-      mark_child_status(&mut self.engine, child, Status::Interesting);
+    def finish_interesting(&mut self, child: &mut HypothesisCoreDataSource, 
label: u64){
+      mark_child_status(&mut self.engine, child, Status::Interesting(label));
     }
 
     def finish_valid(&mut self, child: &mut HypothesisCoreDataSource){
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/requirements/coverage.txt 
new/hypothesis-hypothesis-python-3.66.4/requirements/coverage.txt
--- old/hypothesis-hypothesis-python-3.66.1/requirements/coverage.txt   
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/requirements/coverage.txt   
2018-07-20 15:37:18.000000000 +0200
@@ -6,7 +6,7 @@
 #
 coverage==4.5.1
 numpy==1.14.5
-pandas==0.23.1
+pandas==0.23.3
 python-dateutil==2.7.3    # via pandas
 pytz==2018.5
 six==1.11.0               # via python-dateutil
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/requirements/test.txt 
new/hypothesis-hypothesis-python-3.66.4/requirements/test.txt
--- old/hypothesis-hypothesis-python-3.66.1/requirements/test.txt       
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/requirements/test.txt       
2018-07-20 15:37:18.000000000 +0200
@@ -4,17 +4,17 @@
 #
 #    pip-compile --output-file requirements/test.txt requirements/test.in
 #
-apipkg==1.4               # via execnet
+apipkg==1.5               # via execnet
 atomicwrites==1.1.5       # via pytest
 attrs==18.1.0
 execnet==1.5.0            # via pytest-xdist
 flaky==3.4.0
 mock==2.0.0
 more-itertools==4.2.0     # via pytest
-pbr==4.0.4                # via mock
+pbr==4.1.0                # via mock
 pluggy==0.6.0             # via pytest
 py==1.5.4                 # via pytest
 pytest-forked==0.2        # via pytest-xdist
 pytest-xdist==1.22.2
-pytest==3.6.2
+pytest==3.6.3
 six==1.11.0               # via mock, more-itertools, pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/requirements/tools.in 
new/hypothesis-hypothesis-python-3.66.4/requirements/tools.in
--- old/hypothesis-hypothesis-python-3.66.1/requirements/tools.in       
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/requirements/tools.in       
2018-07-20 15:37:18.000000000 +0200
@@ -17,7 +17,3 @@
 django
 numpy
 IPython
-
-prompt-toolkit==1.0.15    # via ipython==6.4.0
-pycodestyle==2.3.1        # via flake8==3.5.0
-pyflakes==1.6.0           # via flake8==3.5.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/requirements/tools.txt 
new/hypothesis-hypothesis-python-3.66.4/requirements/tools.txt
--- old/hypothesis-hypothesis-python-3.66.1/requirements/tools.txt      
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/requirements/tools.txt      
2018-07-20 15:37:18.000000000 +0200
@@ -34,43 +34,43 @@
 markupsafe==1.0           # via jinja2
 mccabe==0.6.1             # via flake8
 more-itertools==4.2.0     # via pytest
-mypy==0.610
+mypy==0.620
 numpy==1.14.5
-packaging==17.1           # via dparse, pyupio, safety, sphinx
+packaging==17.1           # via dparse, pyupio, safety, sphinx, tox
 parso==0.3.0              # via jedi
 pexpect==4.6.0            # via ipython
 pickleshare==0.7.4        # via ipython
 pip-tools==2.0.2
 pkginfo==1.4.2            # via twine
 pluggy==0.6.0             # via pytest, tox
-prompt-toolkit==1.0.15
+prompt-toolkit==1.0.15    # via ipython
 ptyprocess==0.6.0         # via pexpect
 py==1.5.4                 # via pytest, tox
-pycodestyle==2.3.1
+pycodestyle==2.3.1        # via autopep8, flake8
 pydocstyle==2.1.1         # via flake8-docstrings
-pyflakes==1.6.0
+pyflakes==1.6.0           # via autoflake, flake8
 pyformat==0.7
 pygithub==1.40            # via pyupio
 pygments==2.2.0           # via ipython, sphinx
 pyjwt==1.6.4              # via pygithub
 pyparsing==2.2.0          # via packaging
-pytest==3.6.2
+pytest==3.6.3
 python-dateutil==2.7.3
 python-gitlab==1.5.1      # via pyupio
 pytz==2018.5              # via babel, django
 pyupio==1.0.1
-pyyaml==3.12              # via dparse, pyupio
+pyyaml==3.13              # via dparse, pyupio
 requests-toolbelt==0.8.0  # via twine
 requests==2.19.1          # via pygithub, python-gitlab, pyupio, 
requests-toolbelt, safety, sphinx, twine
 restructuredtext-lint==1.1.3
-safety==1.8.1             # via pyupio
+safety==1.8.2             # via pyupio
 simplegeneric==0.8.1      # via ipython
 six==1.11.0               # via dparse, more-itertools, packaging, pip-tools, 
prompt-toolkit, pydocstyle, pytest, python-dateutil, python-gitlab, pyupio, 
sphinx, tox, traitlets
 snowballstemmer==1.2.1    # via pydocstyle, sphinx
 sphinx-rtd-theme==0.4.0
 sphinx==1.7.5
 sphinxcontrib-websupport==1.1.0  # via sphinx
-tox==3.0.0
+tox==3.1.2
 tqdm==4.23.4              # via pyupio, twine
 traitlets==4.3.2          # via ipython
 twine==1.11.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hypothesis-hypothesis-python-3.66.1/tooling/scripts/ensure-rustup.sh 
new/hypothesis-hypothesis-python-3.66.4/tooling/scripts/ensure-rustup.sh
--- old/hypothesis-hypothesis-python-3.66.1/tooling/scripts/ensure-rustup.sh    
2018-07-09 01:06:33.000000000 +0200
+++ new/hypothesis-hypothesis-python-3.66.4/tooling/scripts/ensure-rustup.sh    
2018-07-20 15:37:18.000000000 +0200
@@ -13,4 +13,4 @@
 
 rustup default stable
 
-rustup update
+rustup update stable


Reply via email to