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/datasource/data_connector/configured_asset_s3_data_connector.py`
Content:
```
1 import logging
2 import os
3 from typing import List, Optional
4 
5 try:
6     import boto3
7 except ImportError:
8     boto3 = None
9 
10 from great_expectations.core.batch import BatchDefinition
11 from great_expectations.core.batch_spec import PathBatchSpec, S3BatchSpec
12 from great_expectations.datasource.data_connector import (
13     ConfiguredAssetFilePathDataConnector,
14 )
15 from great_expectations.datasource.data_connector.asset import Asset
16 from great_expectations.datasource.data_connector.util import list_s3_keys
17 from great_expectations.execution_engine import ExecutionEngine
18 
19 logger = logging.getLogger(__name__)
20 
21 
22 class ConfiguredAssetS3DataConnector(ConfiguredAssetFilePathDataConnector):
23     """
24     Extension of ConfiguredAssetFilePathDataConnector used to connect to S3
25 
26     DataConnectors produce identifying information, called "batch_spec" that ExecutionEngines
27     can use to get individual batches of data. They add flexibility in how to obtain data
28     such as with time-based partitioning, downsampling, or other techniques appropriate
29     for the Datasource.
30 
31     The ConfiguredAssetS3DataConnector is one of two classes (InferredAssetS3DataConnector being the
32     other one) designed for connecting to data on S3.
33 
34     A ConfiguredAssetS3DataConnector requires an explicit listing of each DataAsset you want to connect to.
35     This allows more fine-tuning, but also requires more setup.
36     """
37 
38     def __init__(
39         self,
40         name: str,
41         datasource_name: str,
42         bucket: str,
43         assets: dict,
44         execution_engine: Optional[ExecutionEngine] = None,
45         default_regex: Optional[dict] = None,
46         sorters: Optional[list] = None,
47         prefix: Optional[str] = "",
48         delimiter: Optional[str] = "/",
49         max_keys: Optional[int] = 1000,
50         boto3_options: Optional[dict] = None,
51         batch_spec_passthrough: Optional[dict] = None,
52     ):
53         """
54         ConfiguredAssetDataConnector for connecting to S3.
55 
56         Args:
57             name (str): required name for DataConnector
58             datasource_name (str): required name for datasource
59             bucket (str): bucket for S3
60             assets (dict): dict of asset configuration (required for ConfiguredAssetDataConnector)
61             execution_engine (ExecutionEngine): optional reference to ExecutionEngine
62             default_regex (dict): optional regex configuration for filtering data_references
63             sorters (list): optional list of sorters for sorting data_references
64             prefix (str): S3 prefix
65             delimiter (str): S3 delimiter
66             max_keys (int): S3 max_keys (default is 1000)
67             boto3_options (dict): optional boto3 options
68             batch_spec_passthrough (dict): dictionary with keys that will be added directly to batch_spec
69         """
70         logger.debug(f'Constructing ConfiguredAssetS3DataConnector "{name}".')
71 
72         super().__init__(
73             name=name,
74             datasource_name=datasource_name,
75             execution_engine=execution_engine,
76             assets=assets,
77             default_regex=default_regex,
78             sorters=sorters,
79             batch_spec_passthrough=batch_spec_passthrough,
80         )
81         self._bucket = bucket
82         self._prefix = os.path.join(prefix, "")
83         self._delimiter = delimiter
84         self._max_keys = max_keys
85 
86         if boto3_options is None:
87             boto3_options = {}
88 
89         try:
90             self._s3 = boto3.client("s3", **boto3_options)
91         except (TypeError, AttributeError):
92             raise ImportError(
93                 "Unable to load boto3 (it is required for ConfiguredAssetS3DataConnector)."
94             )
95 
96     def build_batch_spec(self, batch_definition: BatchDefinition) -> S3BatchSpec:
97         """
98         Build BatchSpec from batch_definition by calling DataConnector's build_batch_spec function.
99 
100         Args:
101             batch_definition (BatchDefinition): to be used to build batch_spec
102 
103         Returns:
104             BatchSpec built from batch_definition
105         """
106         batch_spec: PathBatchSpec = super().build_batch_spec(
107             batch_definition=batch_definition
108         )
109         return S3BatchSpec(batch_spec)
110 
111     def _get_data_reference_list_for_asset(self, asset: Optional[Asset]) -> List[str]:
112         query_options: dict = {
113             "Bucket": self._bucket,
114             "Prefix": self._prefix,
115             "Delimiter": self._delimiter,
116             "MaxKeys": self._max_keys,
117         }
118         if asset is not None:
119             if asset.bucket:
120                 query_options["Bucket"] = asset.bucket
121             if asset.prefix:
122                 query_options["Prefix"] = asset.prefix
123             if asset.delimiter:
124                 query_options["Delimiter"] = asset.delimiter
125             if asset.max_keys:
126                 query_options["MaxKeys"] = asset.max_keys
127 
128         path_list: List[str] = [
129             key
130             for key in list_s3_keys(
131                 s3=self._s3,
132                 query_options=query_options,
133                 iterator_dict={},
134                 recursive=False,
135             )
136         ]
137         return path_list
138 
139     def _get_full_file_path(
140         self,
141         path: str,
142         data_asset_name: Optional[str] = None,
143     ) -> str:
144         # data_assert_name isn't used in this method.
145         # It's only kept for compatibility with parent methods.
146         return f"s3a://{os.path.join(self._bucket, path)}"
147
```

Path: `great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py`
Content:
```
1 import logging
2 import os
3 from typing import List, Optional
4 
5 from great_expectations.core.batch import BatchDefinition
6 from great_expectations.core.batch_spec import PathBatchSpec, S3BatchSpec
7 from great_expectations.exceptions.exceptions import ParserError
8 
9 try:
10     import boto3
11 except ImportError:
12     boto3 = None
13 
14 from great_expectations.datasource.data_connector import (
15     InferredAssetFilePathDataConnector,
16 )
17 from great_expectations.datasource.data_connector.util import list_s3_keys
18 from great_expectations.execution_engine import ExecutionEngine
19 
20 logger = logging.getLogger(__name__)
21 
22 INVALID_S3_CHARS = ["*"]
23 
24 
25 class InferredAssetS3DataConnector(InferredAssetFilePathDataConnector):
26     """
27     Extension of InferredAssetFilePathDataConnector used to connect to S3
28 
29     The InferredAssetS3DataConnector is one of two classes (ConfiguredAssetS3DataConnector being the
30     other one) designed for connecting to filesystem-like data, more specifically files on S3. It connects to assets
31     inferred from bucket, prefix, and file name by default_regex.
32 
33     InferredAssetS3DataConnector that operates on S3 buckets and determines
34     the data_asset_name implicitly (e.g., through the combination of the regular expressions pattern and group names)
35 
36     """
37 
38     def __init__(
39         self,
40         name: str,
41         datasource_name: str,
42         bucket: str,
43         execution_engine: Optional[ExecutionEngine] = None,
44         default_regex: Optional[dict] = None,
45         sorters: Optional[list] = None,
46         prefix: Optional[str] = "",
47         delimiter: Optional[str] = "/",
48         max_keys: Optional[int] = 1000,
49         boto3_options: Optional[dict] = None,
50         batch_spec_passthrough: Optional[dict] = None,
51     ):
52         """
53         InferredAssetS3DataConnector for connecting to S3.
54 
55         Args:
56             name (str): required name for data_connector
57             datasource_name (str): required name for datasource
58             bucket (str): bucket for S3
59             execution_engine (ExecutionEngine): optional reference to ExecutionEngine
60             default_regex (dict): optional regex configuration for filtering data_references
61             sorters (list): optional list of sorters for sorting data_references
62             prefix (str): S3 prefix
63             delimiter (str): S3 delimiter
64             max_keys (int): S3 max_keys (default is 1000)
65             boto3_options (dict): optional boto3 options
66             batch_spec_passthrough (dict): dictionary with keys that will be added directly to batch_spec
67         """
68         logger.debug(f'Constructing InferredAssetS3DataConnector "{name}".')
69 
70         super().__init__(
71             name=name,
72             datasource_name=datasource_name,
73             execution_engine=execution_engine,
74             default_regex=default_regex,
75             sorters=sorters,
76             batch_spec_passthrough=batch_spec_passthrough,
77         )
78 
79         self._bucket = bucket
80         self._prefix = os.path.join(prefix, "")
81         self._delimiter = delimiter
82         self._max_keys = max_keys
83 
84         if boto3_options is None:
85             boto3_options = {}
86 
87         try:
88             self._s3 = boto3.client("s3", **boto3_options)
89         except (TypeError, AttributeError):
90             raise ImportError(
91                 "Unable to load boto3 (it is required for InferredAssetS3DataConnector)."
92             )
93 
94     def build_batch_spec(self, batch_definition: BatchDefinition) -> S3BatchSpec:
95         """
96         Build BatchSpec from batch_definition by calling DataConnector's build_batch_spec function.
97 
98         Args:
99             batch_definition (BatchDefinition): to be used to build batch_spec
100 
101         Returns:
102             BatchSpec built from batch_definition
103         """
104         batch_spec: PathBatchSpec = super().build_batch_spec(
105             batch_definition=batch_definition
106         )
107         return S3BatchSpec(batch_spec)
108 
109     def _get_data_reference_list(
110         self, data_asset_name: Optional[str] = None
111     ) -> List[str]:
112         """
113         List objects in the underlying data store to create a list of data_references.
114 
115         This method is used to refresh the cache.
116         """
117         query_options: dict = {
118             "Bucket": self._bucket,
119             "Prefix": self._prefix,
120             "Delimiter": self._delimiter,
121             "MaxKeys": self._max_keys,
122         }
123 
124         path_list: List[str] = [
125             key
126             for key in list_s3_keys(
127                 s3=self._s3,
128                 query_options=query_options,
129                 iterator_dict={},
130                 recursive=True,
131             )
132         ]
133         return path_list
134 
135     def _get_full_file_path(
136         self,
137         path: str,
138         data_asset_name: Optional[str] = None,
139     ) -> str:
140         # data_assert_name isn't used in this method.
141         # It's only kept for compatibility with parent methods.
142         _check_valid_s3_path(path)
143         return f"s3a://{os.path.join(self._bucket, path)}"
144 
145 
146 def _check_valid_s3_path(
147     path: str,
148 ) -> None:
149     """Performs a basic check for validity of the S3 path"""
150     bad_chars = [c for c in INVALID_S3_CHARS if c in path]
151     if len(bad_chars) > 0:
152         msg = (
153             f"The parsed S3 path={path} contains the invalid characters {bad_chars}."
154             "Please make sure your regex is correct and characters are escaped."
155         )
156         if "*" in bad_chars:
157             msg += "Note: `*` is internally used to replace the regex for `.`."
158         raise ParserError(msg)
159
```
--- 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/datasource/data_connector/configured_asset_s3_data_connector.py b/great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py
--- a/great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py
+++ b/great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py
@@ -141,6 +141,6 @@
         path: str,
         data_asset_name: Optional[str] = None,
     ) -> str:
-        # data_assert_name isn't used in this method.
+        # data_asset_name isn't used in this method.
         # It's only kept for compatibility with parent methods.
         return f"s3a://{os.path.join(self._bucket, path)}"
diff --git a/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py b/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py
--- a/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py
+++ b/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py
@@ -137,7 +137,7 @@
         path: str,
         data_asset_name: Optional[str] = None,
     ) -> str:
-        # data_assert_name isn't used in this method.
+        # data_asset_name isn't used in this method.
         # It's only kept for compatibility with parent methods.
         _check_valid_s3_path(path)
         return f"s3a://{os.path.join(self._bucket, path)}"

{"golden_diff": "diff --git a/great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py b/great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py\n--- a/great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py\n+++ b/great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py\n@@ -141,6 +141,6 @@\n         path: str,\n         data_asset_name: Optional[str] = None,\n     ) -> str:\n-        # data_assert_name isn't used in this method.\n+        # data_asset_name isn't used in this method.\n         # It's only kept for compatibility with parent methods.\n         return f\"s3a://{os.path.join(self._bucket, path)}\"\ndiff --git a/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py b/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py\n--- a/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py\n+++ b/great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py\n@@ -137,7 +137,7 @@\n         path: str,\n         data_asset_name: Optional[str] = None,\n     ) -> str:\n-        # data_assert_name isn't used in this method.\n+        # data_asset_name isn't used in this method.\n         # It's only kept for compatibility with parent methods.\n         _check_valid_s3_path(path)\n         return f\"s3a://{os.path.join(self._bucket, path)}\"\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 logging\nimport os\nfrom typing import List, Optional\n\ntry:\n    import boto3\nexcept ImportError:\n    boto3 = None\n\nfrom great_expectations.core.batch import BatchDefinition\nfrom great_expectations.core.batch_spec import PathBatchSpec, S3BatchSpec\nfrom great_expectations.datasource.data_connector import (\n    ConfiguredAssetFilePathDataConnector,\n)\nfrom great_expectations.datasource.data_connector.asset import Asset\nfrom great_expectations.datasource.data_connector.util import list_s3_keys\nfrom great_expectations.execution_engine import ExecutionEngine\n\nlogger = logging.getLogger(__name__)\n\n\nclass ConfiguredAssetS3DataConnector(ConfiguredAssetFilePathDataConnector):\n    \"\"\"\n    Extension of ConfiguredAssetFilePathDataConnector used to connect to S3\n\n    DataConnectors produce identifying information, called \"batch_spec\" that ExecutionEngines\n    can use to get individual batches of data. They add flexibility in how to obtain data\n    such as with time-based partitioning, downsampling, or other techniques appropriate\n    for the Datasource.\n\n    The ConfiguredAssetS3DataConnector is one of two classes (InferredAssetS3DataConnector being the\n    other one) designed for connecting to data on S3.\n\n    A ConfiguredAssetS3DataConnector requires an explicit listing of each DataAsset you want to connect to.\n    This allows more fine-tuning, but also requires more setup.\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        datasource_name: str,\n        bucket: str,\n        assets: dict,\n        execution_engine: Optional[ExecutionEngine] = None,\n        default_regex: Optional[dict] = None,\n        sorters: Optional[list] = None,\n        prefix: Optional[str] = \"\",\n        delimiter: Optional[str] = \"/\",\n        max_keys: Optional[int] = 1000,\n        boto3_options: Optional[dict] = None,\n        batch_spec_passthrough: Optional[dict] = None,\n    ):\n        \"\"\"\n        ConfiguredAssetDataConnector for connecting to S3.\n\n        Args:\n            name (str): required name for DataConnector\n            datasource_name (str): required name for datasource\n            bucket (str): bucket for S3\n            assets (dict): dict of asset configuration (required for ConfiguredAssetDataConnector)\n            execution_engine (ExecutionEngine): optional reference to ExecutionEngine\n            default_regex (dict): optional regex configuration for filtering data_references\n            sorters (list): optional list of sorters for sorting data_references\n            prefix (str): S3 prefix\n            delimiter (str): S3 delimiter\n            max_keys (int): S3 max_keys (default is 1000)\n            boto3_options (dict): optional boto3 options\n            batch_spec_passthrough (dict): dictionary with keys that will be added directly to batch_spec\n        \"\"\"\n        logger.debug(f'Constructing ConfiguredAssetS3DataConnector \"{name}\".')\n\n        super().__init__(\n            name=name,\n            datasource_name=datasource_name,\n            execution_engine=execution_engine,\n            assets=assets,\n            default_regex=default_regex,\n            sorters=sorters,\n            batch_spec_passthrough=batch_spec_passthrough,\n        )\n        self._bucket = bucket\n        self._prefix = os.path.join(prefix, \"\")\n        self._delimiter = delimiter\n        self._max_keys = max_keys\n\n        if boto3_options is None:\n            boto3_options = {}\n\n        try:\n            self._s3 = boto3.client(\"s3\", **boto3_options)\n        except (TypeError, AttributeError):\n            raise ImportError(\n                \"Unable to load boto3 (it is required for ConfiguredAssetS3DataConnector).\"\n            )\n\n    def build_batch_spec(self, batch_definition: BatchDefinition) -> S3BatchSpec:\n        \"\"\"\n        Build BatchSpec from batch_definition by calling DataConnector's build_batch_spec function.\n\n        Args:\n            batch_definition (BatchDefinition): to be used to build batch_spec\n\n        Returns:\n            BatchSpec built from batch_definition\n        \"\"\"\n        batch_spec: PathBatchSpec = super().build_batch_spec(\n            batch_definition=batch_definition\n        )\n        return S3BatchSpec(batch_spec)\n\n    def _get_data_reference_list_for_asset(self, asset: Optional[Asset]) -> List[str]:\n        query_options: dict = {\n            \"Bucket\": self._bucket,\n            \"Prefix\": self._prefix,\n            \"Delimiter\": self._delimiter,\n            \"MaxKeys\": self._max_keys,\n        }\n        if asset is not None:\n            if asset.bucket:\n                query_options[\"Bucket\"] = asset.bucket\n            if asset.prefix:\n                query_options[\"Prefix\"] = asset.prefix\n            if asset.delimiter:\n                query_options[\"Delimiter\"] = asset.delimiter\n            if asset.max_keys:\n                query_options[\"MaxKeys\"] = asset.max_keys\n\n        path_list: List[str] = [\n            key\n            for key in list_s3_keys(\n                s3=self._s3,\n                query_options=query_options,\n                iterator_dict={},\n                recursive=False,\n            )\n        ]\n        return path_list\n\n    def _get_full_file_path(\n        self,\n        path: str,\n        data_asset_name: Optional[str] = None,\n    ) -> str:\n        # data_assert_name isn't used in this method.\n        # It's only kept for compatibility with parent methods.\n        return f\"s3a://{os.path.join(self._bucket, path)}\"\n", "path": "great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py"}, {"content": "import logging\nimport os\nfrom typing import List, Optional\n\nfrom great_expectations.core.batch import BatchDefinition\nfrom great_expectations.core.batch_spec import PathBatchSpec, S3BatchSpec\nfrom great_expectations.exceptions.exceptions import ParserError\n\ntry:\n    import boto3\nexcept ImportError:\n    boto3 = None\n\nfrom great_expectations.datasource.data_connector import (\n    InferredAssetFilePathDataConnector,\n)\nfrom great_expectations.datasource.data_connector.util import list_s3_keys\nfrom great_expectations.execution_engine import ExecutionEngine\n\nlogger = logging.getLogger(__name__)\n\nINVALID_S3_CHARS = [\"*\"]\n\n\nclass InferredAssetS3DataConnector(InferredAssetFilePathDataConnector):\n    \"\"\"\n    Extension of InferredAssetFilePathDataConnector used to connect to S3\n\n    The InferredAssetS3DataConnector is one of two classes (ConfiguredAssetS3DataConnector being the\n    other one) designed for connecting to filesystem-like data, more specifically files on S3. It connects to assets\n    inferred from bucket, prefix, and file name by default_regex.\n\n    InferredAssetS3DataConnector that operates on S3 buckets and determines\n    the data_asset_name implicitly (e.g., through the combination of the regular expressions pattern and group names)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        datasource_name: str,\n        bucket: str,\n        execution_engine: Optional[ExecutionEngine] = None,\n        default_regex: Optional[dict] = None,\n        sorters: Optional[list] = None,\n        prefix: Optional[str] = \"\",\n        delimiter: Optional[str] = \"/\",\n        max_keys: Optional[int] = 1000,\n        boto3_options: Optional[dict] = None,\n        batch_spec_passthrough: Optional[dict] = None,\n    ):\n        \"\"\"\n        InferredAssetS3DataConnector for connecting to S3.\n\n        Args:\n            name (str): required name for data_connector\n            datasource_name (str): required name for datasource\n            bucket (str): bucket for S3\n            execution_engine (ExecutionEngine): optional reference to ExecutionEngine\n            default_regex (dict): optional regex configuration for filtering data_references\n            sorters (list): optional list of sorters for sorting data_references\n            prefix (str): S3 prefix\n            delimiter (str): S3 delimiter\n            max_keys (int): S3 max_keys (default is 1000)\n            boto3_options (dict): optional boto3 options\n            batch_spec_passthrough (dict): dictionary with keys that will be added directly to batch_spec\n        \"\"\"\n        logger.debug(f'Constructing InferredAssetS3DataConnector \"{name}\".')\n\n        super().__init__(\n            name=name,\n            datasource_name=datasource_name,\n            execution_engine=execution_engine,\n            default_regex=default_regex,\n            sorters=sorters,\n            batch_spec_passthrough=batch_spec_passthrough,\n        )\n\n        self._bucket = bucket\n        self._prefix = os.path.join(prefix, \"\")\n        self._delimiter = delimiter\n        self._max_keys = max_keys\n\n        if boto3_options is None:\n            boto3_options = {}\n\n        try:\n            self._s3 = boto3.client(\"s3\", **boto3_options)\n        except (TypeError, AttributeError):\n            raise ImportError(\n                \"Unable to load boto3 (it is required for InferredAssetS3DataConnector).\"\n            )\n\n    def build_batch_spec(self, batch_definition: BatchDefinition) -> S3BatchSpec:\n        \"\"\"\n        Build BatchSpec from batch_definition by calling DataConnector's build_batch_spec function.\n\n        Args:\n            batch_definition (BatchDefinition): to be used to build batch_spec\n\n        Returns:\n            BatchSpec built from batch_definition\n        \"\"\"\n        batch_spec: PathBatchSpec = super().build_batch_spec(\n            batch_definition=batch_definition\n        )\n        return S3BatchSpec(batch_spec)\n\n    def _get_data_reference_list(\n        self, data_asset_name: Optional[str] = None\n    ) -> List[str]:\n        \"\"\"\n        List objects in the underlying data store to create a list of data_references.\n\n        This method is used to refresh the cache.\n        \"\"\"\n        query_options: dict = {\n            \"Bucket\": self._bucket,\n            \"Prefix\": self._prefix,\n            \"Delimiter\": self._delimiter,\n            \"MaxKeys\": self._max_keys,\n        }\n\n        path_list: List[str] = [\n            key\n            for key in list_s3_keys(\n                s3=self._s3,\n                query_options=query_options,\n                iterator_dict={},\n                recursive=True,\n            )\n        ]\n        return path_list\n\n    def _get_full_file_path(\n        self,\n        path: str,\n        data_asset_name: Optional[str] = None,\n    ) -> str:\n        # data_assert_name isn't used in this method.\n        # It's only kept for compatibility with parent methods.\n        _check_valid_s3_path(path)\n        return f\"s3a://{os.path.join(self._bucket, path)}\"\n\n\ndef _check_valid_s3_path(\n    path: str,\n) -> None:\n    \"\"\"Performs a basic check for validity of the S3 path\"\"\"\n    bad_chars = [c for c in INVALID_S3_CHARS if c in path]\n    if len(bad_chars) > 0:\n        msg = (\n            f\"The parsed S3 path={path} contains the invalid characters {bad_chars}.\"\n            \"Please make sure your regex is correct and characters are escaped.\"\n        )\n        if \"*\" in bad_chars:\n            msg += \"Note: `*` is internally used to replace the regex for `.`.\"\n        raise ParserError(msg)\n", "path": "great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py"}], "after_files": [{"content": "import logging\nimport os\nfrom typing import List, Optional\n\ntry:\n    import boto3\nexcept ImportError:\n    boto3 = None\n\nfrom great_expectations.core.batch import BatchDefinition\nfrom great_expectations.core.batch_spec import PathBatchSpec, S3BatchSpec\nfrom great_expectations.datasource.data_connector import (\n    ConfiguredAssetFilePathDataConnector,\n)\nfrom great_expectations.datasource.data_connector.asset import Asset\nfrom great_expectations.datasource.data_connector.util import list_s3_keys\nfrom great_expectations.execution_engine import ExecutionEngine\n\nlogger = logging.getLogger(__name__)\n\n\nclass ConfiguredAssetS3DataConnector(ConfiguredAssetFilePathDataConnector):\n    \"\"\"\n    Extension of ConfiguredAssetFilePathDataConnector used to connect to S3\n\n    DataConnectors produce identifying information, called \"batch_spec\" that ExecutionEngines\n    can use to get individual batches of data. They add flexibility in how to obtain data\n    such as with time-based partitioning, downsampling, or other techniques appropriate\n    for the Datasource.\n\n    The ConfiguredAssetS3DataConnector is one of two classes (InferredAssetS3DataConnector being the\n    other one) designed for connecting to data on S3.\n\n    A ConfiguredAssetS3DataConnector requires an explicit listing of each DataAsset you want to connect to.\n    This allows more fine-tuning, but also requires more setup.\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        datasource_name: str,\n        bucket: str,\n        assets: dict,\n        execution_engine: Optional[ExecutionEngine] = None,\n        default_regex: Optional[dict] = None,\n        sorters: Optional[list] = None,\n        prefix: Optional[str] = \"\",\n        delimiter: Optional[str] = \"/\",\n        max_keys: Optional[int] = 1000,\n        boto3_options: Optional[dict] = None,\n        batch_spec_passthrough: Optional[dict] = None,\n    ):\n        \"\"\"\n        ConfiguredAssetDataConnector for connecting to S3.\n\n        Args:\n            name (str): required name for DataConnector\n            datasource_name (str): required name for datasource\n            bucket (str): bucket for S3\n            assets (dict): dict of asset configuration (required for ConfiguredAssetDataConnector)\n            execution_engine (ExecutionEngine): optional reference to ExecutionEngine\n            default_regex (dict): optional regex configuration for filtering data_references\n            sorters (list): optional list of sorters for sorting data_references\n            prefix (str): S3 prefix\n            delimiter (str): S3 delimiter\n            max_keys (int): S3 max_keys (default is 1000)\n            boto3_options (dict): optional boto3 options\n            batch_spec_passthrough (dict): dictionary with keys that will be added directly to batch_spec\n        \"\"\"\n        logger.debug(f'Constructing ConfiguredAssetS3DataConnector \"{name}\".')\n\n        super().__init__(\n            name=name,\n            datasource_name=datasource_name,\n            execution_engine=execution_engine,\n            assets=assets,\n            default_regex=default_regex,\n            sorters=sorters,\n            batch_spec_passthrough=batch_spec_passthrough,\n        )\n        self._bucket = bucket\n        self._prefix = os.path.join(prefix, \"\")\n        self._delimiter = delimiter\n        self._max_keys = max_keys\n\n        if boto3_options is None:\n            boto3_options = {}\n\n        try:\n            self._s3 = boto3.client(\"s3\", **boto3_options)\n        except (TypeError, AttributeError):\n            raise ImportError(\n                \"Unable to load boto3 (it is required for ConfiguredAssetS3DataConnector).\"\n            )\n\n    def build_batch_spec(self, batch_definition: BatchDefinition) -> S3BatchSpec:\n        \"\"\"\n        Build BatchSpec from batch_definition by calling DataConnector's build_batch_spec function.\n\n        Args:\n            batch_definition (BatchDefinition): to be used to build batch_spec\n\n        Returns:\n            BatchSpec built from batch_definition\n        \"\"\"\n        batch_spec: PathBatchSpec = super().build_batch_spec(\n            batch_definition=batch_definition\n        )\n        return S3BatchSpec(batch_spec)\n\n    def _get_data_reference_list_for_asset(self, asset: Optional[Asset]) -> List[str]:\n        query_options: dict = {\n            \"Bucket\": self._bucket,\n            \"Prefix\": self._prefix,\n            \"Delimiter\": self._delimiter,\n            \"MaxKeys\": self._max_keys,\n        }\n        if asset is not None:\n            if asset.bucket:\n                query_options[\"Bucket\"] = asset.bucket\n            if asset.prefix:\n                query_options[\"Prefix\"] = asset.prefix\n            if asset.delimiter:\n                query_options[\"Delimiter\"] = asset.delimiter\n            if asset.max_keys:\n                query_options[\"MaxKeys\"] = asset.max_keys\n\n        path_list: List[str] = [\n            key\n            for key in list_s3_keys(\n                s3=self._s3,\n                query_options=query_options,\n                iterator_dict={},\n                recursive=False,\n            )\n        ]\n        return path_list\n\n    def _get_full_file_path(\n        self,\n        path: str,\n        data_asset_name: Optional[str] = None,\n    ) -> str:\n        # data_asset_name isn't used in this method.\n        # It's only kept for compatibility with parent methods.\n        return f\"s3a://{os.path.join(self._bucket, path)}\"\n", "path": "great_expectations/datasource/data_connector/configured_asset_s3_data_connector.py"}, {"content": "import logging\nimport os\nfrom typing import List, Optional\n\nfrom great_expectations.core.batch import BatchDefinition\nfrom great_expectations.core.batch_spec import PathBatchSpec, S3BatchSpec\nfrom great_expectations.exceptions.exceptions import ParserError\n\ntry:\n    import boto3\nexcept ImportError:\n    boto3 = None\n\nfrom great_expectations.datasource.data_connector import (\n    InferredAssetFilePathDataConnector,\n)\nfrom great_expectations.datasource.data_connector.util import list_s3_keys\nfrom great_expectations.execution_engine import ExecutionEngine\n\nlogger = logging.getLogger(__name__)\n\nINVALID_S3_CHARS = [\"*\"]\n\n\nclass InferredAssetS3DataConnector(InferredAssetFilePathDataConnector):\n    \"\"\"\n    Extension of InferredAssetFilePathDataConnector used to connect to S3\n\n    The InferredAssetS3DataConnector is one of two classes (ConfiguredAssetS3DataConnector being the\n    other one) designed for connecting to filesystem-like data, more specifically files on S3. It connects to assets\n    inferred from bucket, prefix, and file name by default_regex.\n\n    InferredAssetS3DataConnector that operates on S3 buckets and determines\n    the data_asset_name implicitly (e.g., through the combination of the regular expressions pattern and group names)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        name: str,\n        datasource_name: str,\n        bucket: str,\n        execution_engine: Optional[ExecutionEngine] = None,\n        default_regex: Optional[dict] = None,\n        sorters: Optional[list] = None,\n        prefix: Optional[str] = \"\",\n        delimiter: Optional[str] = \"/\",\n        max_keys: Optional[int] = 1000,\n        boto3_options: Optional[dict] = None,\n        batch_spec_passthrough: Optional[dict] = None,\n    ):\n        \"\"\"\n        InferredAssetS3DataConnector for connecting to S3.\n\n        Args:\n            name (str): required name for data_connector\n            datasource_name (str): required name for datasource\n            bucket (str): bucket for S3\n            execution_engine (ExecutionEngine): optional reference to ExecutionEngine\n            default_regex (dict): optional regex configuration for filtering data_references\n            sorters (list): optional list of sorters for sorting data_references\n            prefix (str): S3 prefix\n            delimiter (str): S3 delimiter\n            max_keys (int): S3 max_keys (default is 1000)\n            boto3_options (dict): optional boto3 options\n            batch_spec_passthrough (dict): dictionary with keys that will be added directly to batch_spec\n        \"\"\"\n        logger.debug(f'Constructing InferredAssetS3DataConnector \"{name}\".')\n\n        super().__init__(\n            name=name,\n            datasource_name=datasource_name,\n            execution_engine=execution_engine,\n            default_regex=default_regex,\n            sorters=sorters,\n            batch_spec_passthrough=batch_spec_passthrough,\n        )\n\n        self._bucket = bucket\n        self._prefix = os.path.join(prefix, \"\")\n        self._delimiter = delimiter\n        self._max_keys = max_keys\n\n        if boto3_options is None:\n            boto3_options = {}\n\n        try:\n            self._s3 = boto3.client(\"s3\", **boto3_options)\n        except (TypeError, AttributeError):\n            raise ImportError(\n                \"Unable to load boto3 (it is required for InferredAssetS3DataConnector).\"\n            )\n\n    def build_batch_spec(self, batch_definition: BatchDefinition) -> S3BatchSpec:\n        \"\"\"\n        Build BatchSpec from batch_definition by calling DataConnector's build_batch_spec function.\n\n        Args:\n            batch_definition (BatchDefinition): to be used to build batch_spec\n\n        Returns:\n            BatchSpec built from batch_definition\n        \"\"\"\n        batch_spec: PathBatchSpec = super().build_batch_spec(\n            batch_definition=batch_definition\n        )\n        return S3BatchSpec(batch_spec)\n\n    def _get_data_reference_list(\n        self, data_asset_name: Optional[str] = None\n    ) -> List[str]:\n        \"\"\"\n        List objects in the underlying data store to create a list of data_references.\n\n        This method is used to refresh the cache.\n        \"\"\"\n        query_options: dict = {\n            \"Bucket\": self._bucket,\n            \"Prefix\": self._prefix,\n            \"Delimiter\": self._delimiter,\n            \"MaxKeys\": self._max_keys,\n        }\n\n        path_list: List[str] = [\n            key\n            for key in list_s3_keys(\n                s3=self._s3,\n                query_options=query_options,\n                iterator_dict={},\n                recursive=True,\n            )\n        ]\n        return path_list\n\n    def _get_full_file_path(\n        self,\n        path: str,\n        data_asset_name: Optional[str] = None,\n    ) -> str:\n        # data_asset_name isn't used in this method.\n        # It's only kept for compatibility with parent methods.\n        _check_valid_s3_path(path)\n        return f\"s3a://{os.path.join(self._bucket, path)}\"\n\n\ndef _check_valid_s3_path(\n    path: str,\n) -> None:\n    \"\"\"Performs a basic check for validity of the S3 path\"\"\"\n    bad_chars = [c for c in INVALID_S3_CHARS if c in path]\n    if len(bad_chars) > 0:\n        msg = (\n            f\"The parsed S3 path={path} contains the invalid characters {bad_chars}.\"\n            \"Please make sure your regex is correct and characters are escaped.\"\n        )\n        if \"*\" in bad_chars:\n            msg += \"Note: `*` is internally used to replace the regex for `.`.\"\n        raise ParserError(msg)\n", "path": "great_expectations/datasource/data_connector/inferred_asset_s3_data_connector.py"}]}