We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Use cleaner solution for non-truncating division in python 2
Prefer `from __future__ import division` to `1.*x/y`

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py`
Content:
```
1 import copy
2 import logging
3 from typing import Any, Dict
4 
5 import numpy as np
6 import pandas as pd
7 
8 from great_expectations.core.util import (
9     convert_to_json_serializable,
10     get_sql_dialect_floating_point_infinity_value,
11 )
12 from great_expectations.execution_engine import (
13     PandasExecutionEngine,
14     SparkDFExecutionEngine,
15     SqlAlchemyExecutionEngine,
16 )
17 from great_expectations.execution_engine.execution_engine import MetricDomainTypes
18 from great_expectations.expectations.metrics.column_aggregate_metric_provider import (
19     ColumnAggregateMetricProvider,
20 )
21 from great_expectations.expectations.metrics.import_manager import Bucketizer, F, sa
22 from great_expectations.expectations.metrics.metric_provider import metric_value
23 
24 logger = logging.getLogger(__name__)
25 
26 
27 class ColumnHistogram(ColumnAggregateMetricProvider):
28     metric_name = "column.histogram"
29     value_keys = ("bins",)
30 
31     @metric_value(engine=PandasExecutionEngine)
32     def _pandas(
33         cls,
34         execution_engine: PandasExecutionEngine,
35         metric_domain_kwargs: Dict,
36         metric_value_kwargs: Dict,
37         metrics: Dict[str, Any],
38         runtime_configuration: Dict,
39     ):
40         df, _, accessor_domain_kwargs = execution_engine.get_compute_domain(
41             domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN
42         )
43         column = accessor_domain_kwargs["column"]
44         bins = metric_value_kwargs["bins"]
45         column_series: pd.Series = df[column]
46         column_null_elements_cond: pd.Series = column_series.isnull()
47         column_nonnull_elements: pd.Series = column_series[~column_null_elements_cond]
48         hist, bin_edges = np.histogram(column_nonnull_elements, bins, density=False)
49         return list(hist)
50 
51     @metric_value(engine=SqlAlchemyExecutionEngine)
52     def _sqlalchemy(
53         cls,
54         execution_engine: SqlAlchemyExecutionEngine,
55         metric_domain_kwargs: Dict,
56         metric_value_kwargs: Dict,
57         metrics: Dict[str, Any],
58         runtime_configuration: Dict,
59     ):
60         """return a list of counts corresponding to bins
61 
62         Args:
63             column: the name of the column for which to get the histogram
64             bins: tuple of bin edges for which to get histogram values; *must* be tuple to support caching
65         """
66         selectable, _, accessor_domain_kwargs = execution_engine.get_compute_domain(
67             domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN
68         )
69         column = accessor_domain_kwargs["column"]
70         bins = metric_value_kwargs["bins"]
71 
72         case_conditions = []
73         idx = 0
74         if isinstance(bins, np.ndarray):
75             bins = bins.tolist()
76         else:
77             bins = list(bins)
78 
79         # If we have an infinite lower bound, don't express that in sql
80         if (
81             bins[0]
82             == get_sql_dialect_floating_point_infinity_value(
83                 schema="api_np", negative=True
84             )
85         ) or (
86             bins[0]
87             == get_sql_dialect_floating_point_infinity_value(
88                 schema="api_cast", negative=True
89             )
90         ):
91             case_conditions.append(
92                 sa.func.sum(
93                     sa.case([(sa.column(column) < bins[idx + 1], 1)], else_=0)
94                 ).label(f"bin_{str(idx)}")
95             )
96             idx += 1
97 
98         for idx in range(idx, len(bins) - 2):
99             case_conditions.append(
100                 sa.func.sum(
101                     sa.case(
102                         [
103                             (
104                                 sa.and_(
105                                     bins[idx] <= sa.column(column),
106                                     sa.column(column) < bins[idx + 1],
107                                 ),
108                                 1,
109                             )
110                         ],
111                         else_=0,
112                     )
113                 ).label(f"bin_{str(idx)}")
114             )
115 
116         if (
117             bins[-1]
118             == get_sql_dialect_floating_point_infinity_value(
119                 schema="api_np", negative=False
120             )
121         ) or (
122             bins[-1]
123             == get_sql_dialect_floating_point_infinity_value(
124                 schema="api_cast", negative=False
125             )
126         ):
127             case_conditions.append(
128                 sa.func.sum(
129                     sa.case([(bins[-2] <= sa.column(column), 1)], else_=0)
130                 ).label(f"bin_{str(len(bins) - 1)}")
131             )
132         else:
133             case_conditions.append(
134                 sa.func.sum(
135                     sa.case(
136                         [
137                             (
138                                 sa.and_(
139                                     bins[-2] <= sa.column(column),
140                                     sa.column(column) <= bins[-1],
141                                 ),
142                                 1,
143                             )
144                         ],
145                         else_=0,
146                     )
147                 ).label(f"bin_{str(len(bins) - 1)}")
148             )
149 
150         query = (
151             sa.select(case_conditions)
152             .where(
153                 sa.column(column) != None,
154             )
155             .select_from(selectable)
156         )
157 
158         # Run the data through convert_to_json_serializable to ensure we do not have Decimal types
159         hist = convert_to_json_serializable(
160             list(execution_engine.engine.execute(query).fetchone())
161         )
162         return hist
163 
164     @metric_value(engine=SparkDFExecutionEngine)
165     def _spark(
166         cls,
167         execution_engine: SparkDFExecutionEngine,
168         metric_domain_kwargs: Dict,
169         metric_value_kwargs: Dict,
170         metrics: Dict[str, Any],
171         runtime_configuration: Dict,
172     ):
173         df, _, accessor_domain_kwargs = execution_engine.get_compute_domain(
174             domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN
175         )
176         bins = metric_value_kwargs["bins"]
177         column = metric_domain_kwargs["column"]
178 
179         """return a list of counts corresponding to bins"""
180         bins = list(
181             copy.deepcopy(bins)
182         )  # take a copy since we are inserting and popping
183         if bins[0] == -np.inf or bins[0] == -float("inf"):
184             added_min = False
185             bins[0] = -float("inf")
186         else:
187             added_min = True
188             bins.insert(0, -float("inf"))
189 
190         if bins[-1] == np.inf or bins[-1] == float("inf"):
191             added_max = False
192             bins[-1] = float("inf")
193         else:
194             added_max = True
195             bins.append(float("inf"))
196 
197         temp_column = df.select(column).where(F.col(column).isNotNull())
198         bucketizer = Bucketizer(splits=bins, inputCol=column, outputCol="buckets")
199         bucketed = bucketizer.setHandleInvalid("skip").transform(temp_column)
200 
201         # This is painful to do, but: bucketizer cannot handle values outside of a range
202         # (hence adding -/+ infinity above)
203 
204         # Further, it *always* follows the numpy convention of lower_bound <= bin < upper_bound
205         # for all but the last bin
206 
207         # But, since the last bin in our case will often be +infinity, we need to
208         # find the number of values exactly equal to the upper bound to add those
209 
210         # We'll try for an optimization by asking for it at the same time
211         if added_max:
212             upper_bound_count = (
213                 temp_column.select(column).filter(F.col(column) == bins[-2]).count()
214             )
215         else:
216             upper_bound_count = 0
217 
218         hist_rows = bucketed.groupBy("buckets").count().collect()
219         # Spark only returns buckets that have nonzero counts.
220         hist = [0] * (len(bins) - 1)
221         for row in hist_rows:
222             hist[int(row["buckets"])] = row["count"]
223 
224         hist[-2] += upper_bound_count
225 
226         if added_min:
227             below_bins = hist.pop(0)
228             bins.pop(0)
229             if below_bins > 0:
230                 logger.warning("Discarding histogram values below lowest bin.")
231 
232         if added_max:
233             above_bins = hist.pop(-1)
234             bins.pop(-1)
235             if above_bins > 0:
236                 logger.warning("Discarding histogram values above highest bin.")
237 
238         return hist
239
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py b/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py
--- a/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py
+++ b/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py
@@ -95,15 +95,19 @@
             )
             idx += 1
 
+        negative_boundary: float
+        positive_boundary: float
         for idx in range(idx, len(bins) - 2):
+            negative_boundary = float(bins[idx])
+            positive_boundary = float(bins[idx + 1])
             case_conditions.append(
                 sa.func.sum(
                     sa.case(
                         [
                             (
                                 sa.and_(
-                                    bins[idx] <= sa.column(column),
-                                    sa.column(column) < bins[idx + 1],
+                                    negative_boundary <= sa.column(column),
+                                    sa.column(column) < positive_boundary,
                                 ),
                                 1,
                             )
@@ -124,20 +128,23 @@
                 schema="api_cast", negative=False
             )
         ):
+            negative_boundary = float(bins[-2])
             case_conditions.append(
                 sa.func.sum(
-                    sa.case([(bins[-2] <= sa.column(column), 1)], else_=0)
+                    sa.case([(negative_boundary <= sa.column(column), 1)], else_=0)
                 ).label(f"bin_{str(len(bins) - 1)}")
             )
         else:
+            negative_boundary = float(bins[-2])
+            positive_boundary = float(bins[-1])
             case_conditions.append(
                 sa.func.sum(
                     sa.case(
                         [
                             (
                                 sa.and_(
-                                    bins[-2] <= sa.column(column),
-                                    sa.column(column) <= bins[-1],
+                                    negative_boundary <= sa.column(column),
+                                    sa.column(column) <= positive_boundary,
                                 ),
                                 1,
                             )

{"golden_diff": "diff --git a/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py b/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py\n--- a/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py\n+++ b/great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py\n@@ -95,15 +95,19 @@\n             )\n             idx += 1\n \n+        negative_boundary: float\n+        positive_boundary: float\n         for idx in range(idx, len(bins) - 2):\n+            negative_boundary = float(bins[idx])\n+            positive_boundary = float(bins[idx + 1])\n             case_conditions.append(\n                 sa.func.sum(\n                     sa.case(\n                         [\n                             (\n                                 sa.and_(\n-                                    bins[idx] <= sa.column(column),\n-                                    sa.column(column) < bins[idx + 1],\n+                                    negative_boundary <= sa.column(column),\n+                                    sa.column(column) < positive_boundary,\n                                 ),\n                                 1,\n                             )\n@@ -124,20 +128,23 @@\n                 schema=\"api_cast\", negative=False\n             )\n         ):\n+            negative_boundary = float(bins[-2])\n             case_conditions.append(\n                 sa.func.sum(\n-                    sa.case([(bins[-2] <= sa.column(column), 1)], else_=0)\n+                    sa.case([(negative_boundary <= sa.column(column), 1)], else_=0)\n                 ).label(f\"bin_{str(len(bins) - 1)}\")\n             )\n         else:\n+            negative_boundary = float(bins[-2])\n+            positive_boundary = float(bins[-1])\n             case_conditions.append(\n                 sa.func.sum(\n                     sa.case(\n                         [\n                             (\n                                 sa.and_(\n-                                    bins[-2] <= sa.column(column),\n-                                    sa.column(column) <= bins[-1],\n+                                    negative_boundary <= sa.column(column),\n+                                    sa.column(column) <= positive_boundary,\n                                 ),\n                                 1,\n                             )\n", "issue": "Use cleaner solution for non-truncating division in python 2\nPrefer `from __future__ import division` to `1.*x/y`\n", "before_files": [{"content": "import copy\nimport logging\nfrom typing import Any, Dict\n\nimport numpy as np\nimport pandas as pd\n\nfrom great_expectations.core.util import (\n    convert_to_json_serializable,\n    get_sql_dialect_floating_point_infinity_value,\n)\nfrom great_expectations.execution_engine import (\n    PandasExecutionEngine,\n    SparkDFExecutionEngine,\n    SqlAlchemyExecutionEngine,\n)\nfrom great_expectations.execution_engine.execution_engine import MetricDomainTypes\nfrom great_expectations.expectations.metrics.column_aggregate_metric_provider import (\n    ColumnAggregateMetricProvider,\n)\nfrom great_expectations.expectations.metrics.import_manager import Bucketizer, F, sa\nfrom great_expectations.expectations.metrics.metric_provider import metric_value\n\nlogger = logging.getLogger(__name__)\n\n\nclass ColumnHistogram(ColumnAggregateMetricProvider):\n    metric_name = \"column.histogram\"\n    value_keys = (\"bins\",)\n\n    @metric_value(engine=PandasExecutionEngine)\n    def _pandas(\n        cls,\n        execution_engine: PandasExecutionEngine,\n        metric_domain_kwargs: Dict,\n        metric_value_kwargs: Dict,\n        metrics: Dict[str, Any],\n        runtime_configuration: Dict,\n    ):\n        df, _, accessor_domain_kwargs = execution_engine.get_compute_domain(\n            domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN\n        )\n        column = accessor_domain_kwargs[\"column\"]\n        bins = metric_value_kwargs[\"bins\"]\n        column_series: pd.Series = df[column]\n        column_null_elements_cond: pd.Series = column_series.isnull()\n        column_nonnull_elements: pd.Series = column_series[~column_null_elements_cond]\n        hist, bin_edges = np.histogram(column_nonnull_elements, bins, density=False)\n        return list(hist)\n\n    @metric_value(engine=SqlAlchemyExecutionEngine)\n    def _sqlalchemy(\n        cls,\n        execution_engine: SqlAlchemyExecutionEngine,\n        metric_domain_kwargs: Dict,\n        metric_value_kwargs: Dict,\n        metrics: Dict[str, Any],\n        runtime_configuration: Dict,\n    ):\n        \"\"\"return a list of counts corresponding to bins\n\n        Args:\n            column: the name of the column for which to get the histogram\n            bins: tuple of bin edges for which to get histogram values; *must* be tuple to support caching\n        \"\"\"\n        selectable, _, accessor_domain_kwargs = execution_engine.get_compute_domain(\n            domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN\n        )\n        column = accessor_domain_kwargs[\"column\"]\n        bins = metric_value_kwargs[\"bins\"]\n\n        case_conditions = []\n        idx = 0\n        if isinstance(bins, np.ndarray):\n            bins = bins.tolist()\n        else:\n            bins = list(bins)\n\n        # If we have an infinite lower bound, don't express that in sql\n        if (\n            bins[0]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_np\", negative=True\n            )\n        ) or (\n            bins[0]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_cast\", negative=True\n            )\n        ):\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case([(sa.column(column) < bins[idx + 1], 1)], else_=0)\n                ).label(f\"bin_{str(idx)}\")\n            )\n            idx += 1\n\n        for idx in range(idx, len(bins) - 2):\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case(\n                        [\n                            (\n                                sa.and_(\n                                    bins[idx] <= sa.column(column),\n                                    sa.column(column) < bins[idx + 1],\n                                ),\n                                1,\n                            )\n                        ],\n                        else_=0,\n                    )\n                ).label(f\"bin_{str(idx)}\")\n            )\n\n        if (\n            bins[-1]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_np\", negative=False\n            )\n        ) or (\n            bins[-1]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_cast\", negative=False\n            )\n        ):\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case([(bins[-2] <= sa.column(column), 1)], else_=0)\n                ).label(f\"bin_{str(len(bins) - 1)}\")\n            )\n        else:\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case(\n                        [\n                            (\n                                sa.and_(\n                                    bins[-2] <= sa.column(column),\n                                    sa.column(column) <= bins[-1],\n                                ),\n                                1,\n                            )\n                        ],\n                        else_=0,\n                    )\n                ).label(f\"bin_{str(len(bins) - 1)}\")\n            )\n\n        query = (\n            sa.select(case_conditions)\n            .where(\n                sa.column(column) != None,\n            )\n            .select_from(selectable)\n        )\n\n        # Run the data through convert_to_json_serializable to ensure we do not have Decimal types\n        hist = convert_to_json_serializable(\n            list(execution_engine.engine.execute(query).fetchone())\n        )\n        return hist\n\n    @metric_value(engine=SparkDFExecutionEngine)\n    def _spark(\n        cls,\n        execution_engine: SparkDFExecutionEngine,\n        metric_domain_kwargs: Dict,\n        metric_value_kwargs: Dict,\n        metrics: Dict[str, Any],\n        runtime_configuration: Dict,\n    ):\n        df, _, accessor_domain_kwargs = execution_engine.get_compute_domain(\n            domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN\n        )\n        bins = metric_value_kwargs[\"bins\"]\n        column = metric_domain_kwargs[\"column\"]\n\n        \"\"\"return a list of counts corresponding to bins\"\"\"\n        bins = list(\n            copy.deepcopy(bins)\n        )  # take a copy since we are inserting and popping\n        if bins[0] == -np.inf or bins[0] == -float(\"inf\"):\n            added_min = False\n            bins[0] = -float(\"inf\")\n        else:\n            added_min = True\n            bins.insert(0, -float(\"inf\"))\n\n        if bins[-1] == np.inf or bins[-1] == float(\"inf\"):\n            added_max = False\n            bins[-1] = float(\"inf\")\n        else:\n            added_max = True\n            bins.append(float(\"inf\"))\n\n        temp_column = df.select(column).where(F.col(column).isNotNull())\n        bucketizer = Bucketizer(splits=bins, inputCol=column, outputCol=\"buckets\")\n        bucketed = bucketizer.setHandleInvalid(\"skip\").transform(temp_column)\n\n        # This is painful to do, but: bucketizer cannot handle values outside of a range\n        # (hence adding -/+ infinity above)\n\n        # Further, it *always* follows the numpy convention of lower_bound <= bin < upper_bound\n        # for all but the last bin\n\n        # But, since the last bin in our case will often be +infinity, we need to\n        # find the number of values exactly equal to the upper bound to add those\n\n        # We'll try for an optimization by asking for it at the same time\n        if added_max:\n            upper_bound_count = (\n                temp_column.select(column).filter(F.col(column) == bins[-2]).count()\n            )\n        else:\n            upper_bound_count = 0\n\n        hist_rows = bucketed.groupBy(\"buckets\").count().collect()\n        # Spark only returns buckets that have nonzero counts.\n        hist = [0] * (len(bins) - 1)\n        for row in hist_rows:\n            hist[int(row[\"buckets\"])] = row[\"count\"]\n\n        hist[-2] += upper_bound_count\n\n        if added_min:\n            below_bins = hist.pop(0)\n            bins.pop(0)\n            if below_bins > 0:\n                logger.warning(\"Discarding histogram values below lowest bin.\")\n\n        if added_max:\n            above_bins = hist.pop(-1)\n            bins.pop(-1)\n            if above_bins > 0:\n                logger.warning(\"Discarding histogram values above highest bin.\")\n\n        return hist\n", "path": "great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py"}], "after_files": [{"content": "import copy\nimport logging\nfrom typing import Any, Dict\n\nimport numpy as np\nimport pandas as pd\n\nfrom great_expectations.core.util import (\n    convert_to_json_serializable,\n    get_sql_dialect_floating_point_infinity_value,\n)\nfrom great_expectations.execution_engine import (\n    PandasExecutionEngine,\n    SparkDFExecutionEngine,\n    SqlAlchemyExecutionEngine,\n)\nfrom great_expectations.execution_engine.execution_engine import MetricDomainTypes\nfrom great_expectations.expectations.metrics.column_aggregate_metric_provider import (\n    ColumnAggregateMetricProvider,\n)\nfrom great_expectations.expectations.metrics.import_manager import Bucketizer, F, sa\nfrom great_expectations.expectations.metrics.metric_provider import metric_value\n\nlogger = logging.getLogger(__name__)\n\n\nclass ColumnHistogram(ColumnAggregateMetricProvider):\n    metric_name = \"column.histogram\"\n    value_keys = (\"bins\",)\n\n    @metric_value(engine=PandasExecutionEngine)\n    def _pandas(\n        cls,\n        execution_engine: PandasExecutionEngine,\n        metric_domain_kwargs: Dict,\n        metric_value_kwargs: Dict,\n        metrics: Dict[str, Any],\n        runtime_configuration: Dict,\n    ):\n        df, _, accessor_domain_kwargs = execution_engine.get_compute_domain(\n            domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN\n        )\n        column = accessor_domain_kwargs[\"column\"]\n        bins = metric_value_kwargs[\"bins\"]\n        column_series: pd.Series = df[column]\n        column_null_elements_cond: pd.Series = column_series.isnull()\n        column_nonnull_elements: pd.Series = column_series[~column_null_elements_cond]\n        hist, bin_edges = np.histogram(column_nonnull_elements, bins, density=False)\n        return list(hist)\n\n    @metric_value(engine=SqlAlchemyExecutionEngine)\n    def _sqlalchemy(\n        cls,\n        execution_engine: SqlAlchemyExecutionEngine,\n        metric_domain_kwargs: Dict,\n        metric_value_kwargs: Dict,\n        metrics: Dict[str, Any],\n        runtime_configuration: Dict,\n    ):\n        \"\"\"return a list of counts corresponding to bins\n\n        Args:\n            column: the name of the column for which to get the histogram\n            bins: tuple of bin edges for which to get histogram values; *must* be tuple to support caching\n        \"\"\"\n        selectable, _, accessor_domain_kwargs = execution_engine.get_compute_domain(\n            domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN\n        )\n        column = accessor_domain_kwargs[\"column\"]\n        bins = metric_value_kwargs[\"bins\"]\n\n        case_conditions = []\n        idx = 0\n        if isinstance(bins, np.ndarray):\n            bins = bins.tolist()\n        else:\n            bins = list(bins)\n\n        # If we have an infinite lower bound, don't express that in sql\n        if (\n            bins[0]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_np\", negative=True\n            )\n        ) or (\n            bins[0]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_cast\", negative=True\n            )\n        ):\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case([(sa.column(column) < bins[idx + 1], 1)], else_=0)\n                ).label(f\"bin_{str(idx)}\")\n            )\n            idx += 1\n\n        negative_boundary: float\n        positive_boundary: float\n        for idx in range(idx, len(bins) - 2):\n            negative_boundary = float(bins[idx])\n            positive_boundary = float(bins[idx + 1])\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case(\n                        [\n                            (\n                                sa.and_(\n                                    negative_boundary <= sa.column(column),\n                                    sa.column(column) < positive_boundary,\n                                ),\n                                1,\n                            )\n                        ],\n                        else_=0,\n                    )\n                ).label(f\"bin_{str(idx)}\")\n            )\n\n        if (\n            bins[-1]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_np\", negative=False\n            )\n        ) or (\n            bins[-1]\n            == get_sql_dialect_floating_point_infinity_value(\n                schema=\"api_cast\", negative=False\n            )\n        ):\n            negative_boundary = float(bins[-2])\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case([(negative_boundary <= sa.column(column), 1)], else_=0)\n                ).label(f\"bin_{str(len(bins) - 1)}\")\n            )\n        else:\n            negative_boundary = float(bins[-2])\n            positive_boundary = float(bins[-1])\n            case_conditions.append(\n                sa.func.sum(\n                    sa.case(\n                        [\n                            (\n                                sa.and_(\n                                    negative_boundary <= sa.column(column),\n                                    sa.column(column) <= positive_boundary,\n                                ),\n                                1,\n                            )\n                        ],\n                        else_=0,\n                    )\n                ).label(f\"bin_{str(len(bins) - 1)}\")\n            )\n\n        query = (\n            sa.select(case_conditions)\n            .where(\n                sa.column(column) != None,\n            )\n            .select_from(selectable)\n        )\n\n        # Run the data through convert_to_json_serializable to ensure we do not have Decimal types\n        hist = convert_to_json_serializable(\n            list(execution_engine.engine.execute(query).fetchone())\n        )\n        return hist\n\n    @metric_value(engine=SparkDFExecutionEngine)\n    def _spark(\n        cls,\n        execution_engine: SparkDFExecutionEngine,\n        metric_domain_kwargs: Dict,\n        metric_value_kwargs: Dict,\n        metrics: Dict[str, Any],\n        runtime_configuration: Dict,\n    ):\n        df, _, accessor_domain_kwargs = execution_engine.get_compute_domain(\n            domain_kwargs=metric_domain_kwargs, domain_type=MetricDomainTypes.COLUMN\n        )\n        bins = metric_value_kwargs[\"bins\"]\n        column = metric_domain_kwargs[\"column\"]\n\n        \"\"\"return a list of counts corresponding to bins\"\"\"\n        bins = list(\n            copy.deepcopy(bins)\n        )  # take a copy since we are inserting and popping\n        if bins[0] == -np.inf or bins[0] == -float(\"inf\"):\n            added_min = False\n            bins[0] = -float(\"inf\")\n        else:\n            added_min = True\n            bins.insert(0, -float(\"inf\"))\n\n        if bins[-1] == np.inf or bins[-1] == float(\"inf\"):\n            added_max = False\n            bins[-1] = float(\"inf\")\n        else:\n            added_max = True\n            bins.append(float(\"inf\"))\n\n        temp_column = df.select(column).where(F.col(column).isNotNull())\n        bucketizer = Bucketizer(splits=bins, inputCol=column, outputCol=\"buckets\")\n        bucketed = bucketizer.setHandleInvalid(\"skip\").transform(temp_column)\n\n        # This is painful to do, but: bucketizer cannot handle values outside of a range\n        # (hence adding -/+ infinity above)\n\n        # Further, it *always* follows the numpy convention of lower_bound <= bin < upper_bound\n        # for all but the last bin\n\n        # But, since the last bin in our case will often be +infinity, we need to\n        # find the number of values exactly equal to the upper bound to add those\n\n        # We'll try for an optimization by asking for it at the same time\n        if added_max:\n            upper_bound_count = (\n                temp_column.select(column).filter(F.col(column) == bins[-2]).count()\n            )\n        else:\n            upper_bound_count = 0\n\n        hist_rows = bucketed.groupBy(\"buckets\").count().collect()\n        # Spark only returns buckets that have nonzero counts.\n        hist = [0] * (len(bins) - 1)\n        for row in hist_rows:\n            hist[int(row[\"buckets\"])] = row[\"count\"]\n\n        hist[-2] += upper_bound_count\n\n        if added_min:\n            below_bins = hist.pop(0)\n            bins.pop(0)\n            if below_bins > 0:\n                logger.warning(\"Discarding histogram values below lowest bin.\")\n\n        if added_max:\n            above_bins = hist.pop(-1)\n            bins.pop(-1)\n            if above_bins > 0:\n                logger.warning(\"Discarding histogram values above highest bin.\")\n\n        return hist\n", "path": "great_expectations/expectations/metrics/column_aggregate_metrics/column_histogram.py"}]}