Browse Source

Intermediate changes

robot-piglet 11 months ago
parent
commit
bc252a2dec

+ 1 - 1
contrib/python/clickhouse-connect/.dist-info/METADATA

@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: clickhouse-connect
-Version: 0.7.2
+Version: 0.7.3
 Summary: ClickHouse Database Core Driver for Python, Pandas, and Superset
 Home-page: https://github.com/ClickHouse/clickhouse-connect
 Author: ClickHouse Inc.

+ 1 - 1
contrib/python/clickhouse-connect/clickhouse_connect/__version__.py

@@ -1 +1 @@
-version = '0.7.2'
+version = '0.7.3'

+ 9 - 1
contrib/python/clickhouse-connect/clickhouse_connect/dbapi/cursor.py

@@ -1,7 +1,7 @@
 import logging
 import re
 
-from typing import Optional, Sequence
+from typing import Optional, Sequence, List, Dict
 
 from clickhouse_connect.datatypes.registry import get_from_name
 from clickhouse_connect.driver.common import unescape_identifier
@@ -17,6 +17,7 @@ str_type = get_from_name('String')
 int_type = get_from_name('Int32')
 
 
+# pylint: disable=too-many-instance-attributes
 class Cursor:
     """
     See :ref:`https://peps.python.org/pep-0249/`
@@ -29,6 +30,7 @@ class Cursor:
         self.names = []
         self.types = []
         self._rowcount = 0
+        self._summary: List[Dict[str, str]] = []
         self._ix = 0
 
     def check_valid(self):
@@ -43,6 +45,10 @@ class Cursor:
     def rowcount(self):
         return self._rowcount
 
+    @property
+    def summary(self) -> List[Dict[str, str]]:
+        return self._summary
+
     def close(self):
         self.data = None
 
@@ -50,6 +56,7 @@ class Cursor:
         query_result = self.client.query(operation, parameters)
         self.data = query_result.result_set
         self._rowcount = len(self.data)
+        self._summary.append(query_result.summary)
         if query_result.column_names:
             self.names = query_result.column_names
             self.types = [x.name for x in query_result.column_types]
@@ -94,6 +101,7 @@ class Cursor:
                 else:
                     self.names = query_result.column_names
                     self.types = query_result.column_types
+                self._summary.append(query_result.summary)
         except TypeError as ex:
             raise ProgrammingError(f'Invalid parameters {parameters} passed to cursor executemany') from ex
         self._rowcount = len(self.data)

+ 1 - 1
contrib/python/clickhouse-connect/ya.make

@@ -2,7 +2,7 @@
 
 PY3_LIBRARY()
 
-VERSION(0.7.2)
+VERSION(0.7.3)
 
 LICENSE(Apache-2.0)
 

+ 1 - 1
contrib/python/hypothesis/py3/.dist-info/METADATA

@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: hypothesis
-Version: 6.99.5
+Version: 6.99.6
 Summary: A library for property-based testing
 Home-page: https://hypothesis.works
 Author: David R. MacIver and Zac Hatfield-Dodds

+ 68 - 3
contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py

@@ -920,6 +920,50 @@ class IRNode:
     kwargs: IRKWargsType = attr.ib()
     was_forced: bool = attr.ib()
 
+    def copy(self, *, with_value: IRType) -> "IRNode":
+        # we may want to allow this combination in the future, but for now it's
+        # a footgun.
+        assert not self.was_forced, "modifying a forced node doesn't make sense"
+        return IRNode(
+            ir_type=self.ir_type,
+            value=with_value,
+            kwargs=self.kwargs,
+            was_forced=self.was_forced,
+        )
+
+
+def ir_value_permitted(value, ir_type, kwargs):
+    if ir_type == "integer":
+        if kwargs["min_value"] is not None and value < kwargs["min_value"]:
+            return False
+        if kwargs["max_value"] is not None and value > kwargs["max_value"]:
+            return False
+
+        return True
+    elif ir_type == "float":
+        if math.isnan(value):
+            return kwargs["allow_nan"]
+        return (
+            sign_aware_lte(kwargs["min_value"], value)
+            and sign_aware_lte(value, kwargs["max_value"])
+        ) and not (0 < abs(value) < kwargs["smallest_nonzero_magnitude"])
+    elif ir_type == "string":
+        if len(value) < kwargs["min_size"]:
+            return False
+        if kwargs["max_size"] is not None and len(value) > kwargs["max_size"]:
+            return False
+        return all(ord(c) in kwargs["intervals"] for c in value)
+    elif ir_type == "bytes":
+        return len(value) == kwargs["size"]
+    elif ir_type == "boolean":
+        if kwargs["p"] <= 2 ** (-64):
+            return value is False
+        if kwargs["p"] >= (1 - 2 ** (-64)):
+            return value is True
+        return True
+
+    raise NotImplementedError(f"unhandled type {type(value)} of ir value {value}")
+
 
 @dataclass_transform()
 @attr.s(slots=True)
@@ -1991,8 +2035,8 @@ class ConjectureData:
         p: float = 0.5,
         *,
         forced: Optional[bool] = None,
-        observe: bool = True,
         fake_forced: bool = False,
+        observe: bool = True,
     ) -> bool:
         # Internally, we treat probabilities lower than 1 / 2**64 as
         # unconditionally false.
@@ -2049,9 +2093,30 @@ class ConjectureData:
 
     def _pop_ir_tree_node(self, ir_type: IRTypeName, kwargs: IRKWargsType) -> IRNode:
         assert self.ir_tree_nodes is not None
+
+        if self.ir_tree_nodes == []:
+            self.mark_overrun()
+
         node = self.ir_tree_nodes.pop(0)
-        assert node.ir_type == ir_type
-        assert kwargs == node.kwargs
+        # If we're trying to draw a different ir type at the same location, then
+        # this ir tree has become badly misaligned. We don't have many good/simple
+        # options here for realigning beyond giving up.
+        #
+        # This is more of an issue for ir nodes while shrinking than it was for
+        # buffers: misaligned buffers are still usually valid, just interpreted
+        # differently. This would be somewhat like drawing a random value for
+        # the new ir type here. For what it's worth, misaligned buffers are
+        # rather unlikely to be *useful* buffers, so giving up isn't a big downgrade.
+        # (in fact, it is possible that giving up early here results in more time
+        # for useful shrinks to run).
+        if node.ir_type != ir_type:
+            self.mark_invalid()
+
+        # if a node has different kwargs (and so is misaligned), but has a value
+        # that is allowed by the expected kwargs, then we can coerce this node
+        # into an aligned one by using its value. It's unclear how useful this is.
+        if not ir_value_permitted(node.value, node.ir_type, kwargs):
+            self.mark_invalid()
 
         return node
 

+ 54 - 7
contrib/python/hypothesis/py3/hypothesis/internal/conjecture/datatree.py

@@ -30,7 +30,12 @@ from hypothesis.internal.conjecture.data import (
     Status,
     StringKWargs,
 )
-from hypothesis.internal.floats import count_between_floats, float_to_int, int_to_float
+from hypothesis.internal.floats import (
+    count_between_floats,
+    float_to_int,
+    int_to_float,
+    sign_aware_lte,
+)
 
 
 class PreviouslyUnseenBehaviour(HypothesisException):
@@ -184,7 +189,35 @@ def compute_max_children(ir_type, kwargs):
         return sum(len(intervals) ** k for k in range(min_size, max_size + 1))
 
     elif ir_type == "float":
-        return count_between_floats(kwargs["min_value"], kwargs["max_value"])
+        min_value = kwargs["min_value"]
+        max_value = kwargs["max_value"]
+        smallest_nonzero_magnitude = kwargs["smallest_nonzero_magnitude"]
+
+        count = count_between_floats(min_value, max_value)
+
+        # we have two intervals:
+        # a. [min_value, max_value]
+        # b. [-smallest_nonzero_magnitude, smallest_nonzero_magnitude]
+        #
+        # which could be subsets (in either order), overlapping, or disjoint. We
+        # want the interval difference a - b.
+
+        # next_down because endpoints are ok with smallest_nonzero_magnitude
+        min_point = max(min_value, -flt.next_down(smallest_nonzero_magnitude))
+        max_point = min(max_value, flt.next_down(smallest_nonzero_magnitude))
+
+        if min_point > max_point:
+            # case: disjoint intervals.
+            return count
+
+        count -= count_between_floats(min_point, max_point)
+        if sign_aware_lte(min_value, -0.0) and sign_aware_lte(-0.0, max_value):
+            # account for -0.0
+            count += 1
+        if sign_aware_lte(min_value, 0.0) and sign_aware_lte(0.0, max_value):
+            # account for 0.0
+            count += 1
+        return count
 
     raise NotImplementedError(f"unhandled ir_type {ir_type}")
 
@@ -247,16 +280,30 @@ def all_children(ir_type, kwargs):
 
         min_value = kwargs["min_value"]
         max_value = kwargs["max_value"]
+        smallest_nonzero_magnitude = kwargs["smallest_nonzero_magnitude"]
+
+        # handle zeroes separately so smallest_nonzero_magnitude can think of
+        # itself as a complete interval (instead of a hole at ±0).
+        if sign_aware_lte(min_value, -0.0) and sign_aware_lte(-0.0, max_value):
+            yield -0.0
+        if sign_aware_lte(min_value, 0.0) and sign_aware_lte(0.0, max_value):
+            yield 0.0
 
         if flt.is_negative(min_value):
             if flt.is_negative(max_value):
-                # if both are negative, have to invert order
-                yield from floats_between(max_value, min_value)
+                # case: both negative.
+                max_point = min(max_value, -smallest_nonzero_magnitude)
+                # float_to_int increases as negative magnitude increases, so
+                # invert order.
+                yield from floats_between(max_point, min_value)
             else:
-                yield from floats_between(-0.0, min_value)
-                yield from floats_between(0.0, max_value)
+                # case: straddles midpoint (which is between -0.0 and 0.0).
+                yield from floats_between(-smallest_nonzero_magnitude, min_value)
+                yield from floats_between(smallest_nonzero_magnitude, max_value)
         else:
-            yield from floats_between(min_value, max_value)
+            # case: both positive.
+            min_point = max(min_value, smallest_nonzero_magnitude)
+            yield from floats_between(min_point, max_value)
 
 
 @attr.s(slots=True)

+ 37 - 30
contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py

@@ -8,6 +8,7 @@
 # v. 2.0. If a copy of the MPL was not distributed with this file, You can
 # obtain one at https://mozilla.org/MPL/2.0/.
 
+import math
 from collections import defaultdict
 from typing import TYPE_CHECKING, Callable, Dict, Optional
 
@@ -19,14 +20,9 @@ from hypothesis.internal.conjecture.choicetree import (
     prefix_selection_order,
     random_selection_order,
 )
-from hypothesis.internal.conjecture.data import (
-    DRAW_FLOAT_LABEL,
-    ConjectureData,
-    ConjectureResult,
-    Status,
-)
+from hypothesis.internal.conjecture.data import ConjectureData, ConjectureResult, Status
 from hypothesis.internal.conjecture.dfa import ConcreteDFA
-from hypothesis.internal.conjecture.floats import float_to_lex, lex_to_float
+from hypothesis.internal.conjecture.floats import is_simple
 from hypothesis.internal.conjecture.junkdrawer import (
     binary_search,
     find_integer,
@@ -379,6 +375,12 @@ class Shrinker:
         test function."""
         return self.engine.call_count
 
+    def consider_new_tree(self, tree):
+        data = ConjectureData.for_ir_tree(tree)
+        self.engine.test_function(data)
+
+        return self.consider_new_buffer(data.buffer)
+
     def consider_new_buffer(self, buffer):
         """Returns True if after running this buffer the result would be
         the current shrink_target."""
@@ -774,6 +776,10 @@ class Shrinker:
     def blocks(self):
         return self.shrink_target.blocks
 
+    @property
+    def nodes(self):
+        return self.shrink_target.examples.ir_tree_nodes
+
     @property
     def examples(self):
         return self.shrink_target.examples
@@ -1207,31 +1213,32 @@ class Shrinker:
         anything particularly meaningful for non-float values.
         """
 
-        ex = chooser.choose(
-            self.examples,
-            lambda ex: (
-                ex.label == DRAW_FLOAT_LABEL
-                and len(ex.children) == 2
-                and ex.children[1].length == 8
-            ),
+        node = chooser.choose(
+            self.nodes,
+            lambda node: node.ir_type == "float" and not node.was_forced
+            # avoid shrinking integer-valued floats. In our current ordering, these
+            # are already simpler than all other floats, so it's better to shrink
+            # them in other passes.
+            and not is_simple(node.value),
         )
 
-        u = ex.children[1].start
-        v = ex.children[1].end
-        buf = self.shrink_target.buffer
-        b = buf[u:v]
-        f = lex_to_float(int_from_bytes(b))
-        b2 = int_to_bytes(float_to_lex(f), 8)
-        if b == b2 or self.consider_new_buffer(buf[:u] + b2 + buf[v:]):
-            Float.shrink(
-                f,
-                lambda x: self.consider_new_buffer(
-                    self.shrink_target.buffer[:u]
-                    + int_to_bytes(float_to_lex(x), 8)
-                    + self.shrink_target.buffer[v:]
-                ),
-                random=self.random,
-            )
+        i = self.nodes.index(node)
+        # the Float shrinker was only built to handle positive floats. We'll
+        # shrink the positive portion and reapply the sign after, which is
+        # equivalent to this shrinker's previous behavior. We'll want to refactor
+        # Float to handle negative floats natively in the future. (likely a pure
+        # code quality change, with no shrinking impact.)
+        sign = math.copysign(1.0, node.value)
+        Float.shrink(
+            abs(node.value),
+            lambda val: self.consider_new_tree(
+                self.nodes[:i]
+                + [node.copy(with_value=sign * val)]
+                + self.nodes[i + 1 :]
+            ),
+            random=self.random,
+            node=node,
+        )
 
     @defines_shrink_pass()
     def redistribute_block_pairs(self, chooser):

+ 1 - 0
contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/common.py

@@ -133,6 +133,7 @@ class Shrinker:
     def consider(self, value):
         """Returns True if make_immutable(value) == self.current after calling
         self.incorporate(value)."""
+        self.debug(f"considering {value}")
         value = self.make_immutable(value)
         if value == self.current:
             return True

+ 9 - 1
contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/floats.py

@@ -11,6 +11,7 @@
 import math
 import sys
 
+from hypothesis.internal.conjecture.data import ir_value_permitted
 from hypothesis.internal.conjecture.floats import float_to_lex
 from hypothesis.internal.conjecture.shrinking.common import Shrinker
 from hypothesis.internal.conjecture.shrinking.integer import Integer
@@ -19,9 +20,16 @@ MAX_PRECISE_INTEGER = 2**53
 
 
 class Float(Shrinker):
-    def setup(self):
+    def setup(self, node):
         self.NAN = math.nan
         self.debugging_enabled = True
+        self.node = node
+
+    def consider(self, value):
+        if not ir_value_permitted(value, "float", self.node.kwargs):
+            self.debug(f"rejecting {value} as disallowed for {self.node.kwargs}")
+            return False
+        return super().consider(value)
 
     def make_immutable(self, f):
         f = float(f)

Some files were not shown because too many files changed in this diff