prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  QueryBatchKwargsGenerator._get_raw_query produces incorrect filepath
  I am using the `QueryBatchKwargsGenerator` to generate `BATCH_KWARGS` using a SQL file I have stored on disk. My `great_expectations.yml` looks like:
  
  ```yaml
  datasources:
      domi:
        class_name: SqlAlchemyDatasource
        module_name:
        data_asset_type:
          class_name: SqlAlchemyDataset
        credentials:
          drivername: postgres
          host: ${HOST}
          port: ${PORT}
          username: ${USER}
          password: ${PASSWORD}
          database: ${DBNAME}
        generators:
          apartments-generator:
            class_name: QueryBatchKwargsGenerator
            name: apartments
  ```
  
  I am running the following:
  
  ```python
  >>> import great_expectations as get
  
  >>> context = ge.data_context.DataContext()
  >>> context.get_available_data_asset_names()
  {'domi': {'apartments-generator': {'names': [('listings', 'query')]}}}
  
  >>> context.build_batch_kwargs(
      datasource='domi', generator='apartments-generator', name='listings'
  )
  ```
  
  Which raises this error:
  
  ![image](https://user-images.githubusercontent.com/11096727/79018747-8e14b080-7b42-11ea-9564-7b35b23dac72.png)
  
  This happens because `_get_raw_query` is doing `tuple('listings')` which returns: `('l', 'i', 's', 't', 'i', 'n', 'g', 's')`)
  
  ```python
      def _get_raw_query(self, generator_asset):
          return self._store_backend.get(tuple(generator_asset))
  ```
  
  I believe this should just be replaced with:
  
  ```python
      def _get_raw_query(self, generator_asset):
          return self._store_backend.get((generator_asset,))
  ```
  
  Currently I can get around this by providing a tuple instead of a string, i.e.
  
  ```python
  context.build_batch_kwargs(
      datasource='domi',
      generator='apartments-generator',
      name=('listings', )
  )
  ```
  
  But that goes against what the docs are saying [here](https://docs.greatexpectations.io/en/latest/module_docs/data_context_module.html#great_expectations.data_context.BaseDataContext.build_batch_kwargs):
  
  ![image](https://user-images.githubusercontent.com/11096727/79018985-30cd2f00-7b43-11ea-962c-3a563f19acc6.png)
  
  
  --- 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/generator/query_generator.py`
  Content:
  ```
  1 import os
  2 import logging
  3 
  4 from .batch_kwargs_generator import BatchKwargsGenerator
  5 from great_expectations.datasource.types import SqlAlchemyDatasourceQueryBatchKwargs
  6 from great_expectations.exceptions import (
  7     BatchKwargsError,
  8     ClassInstantiationError,
  9 )
  10 from ...data_context.util import instantiate_class_from_config
  11 
  12 logger = logging.getLogger(__name__)
  13 
  14 try:
  15     import sqlalchemy
  16     from sqlalchemy import create_engine
  17     from sqlalchemy.engine import reflection
  18 except ImportError:
  19     sqlalchemy = None
  20     create_engine = None
  21     reflection = None
  22     logger.debug("Unable to import sqlalchemy.")
  23 
  24 
  25 class QueryBatchKwargsGenerator(BatchKwargsGenerator):
  26     """Produce query-style batch_kwargs from sql files stored on disk
  27     """
  28     recognized_batch_parameters = {'query_parameters', 'partition_id'}
  29 
  30     def __init__(self, name="default", datasource=None, query_store_backend=None, queries=None):
  31         super(QueryBatchKwargsGenerator, self).__init__(name=name, datasource=datasource)
  32         root_directory = None
  33         if query_store_backend is None:
  34             # We will choose a Tuple store if there is a configured DataContext with a root_directory,
  35             # and an InMemoryStore otherwise
  36             if datasource and datasource.data_context and datasource.data_context.root_directory:
  37                 query_store_backend = {
  38                     "class_name": "TupleFilesystemStoreBackend",
  39                     "base_directory": os.path.join(datasource.data_context.root_directory, "datasources",
  40                                                    datasource.name, "generators", name),
  41                     "filepath_suffix": ".sql"
  42                 }
  43                 root_directory = datasource.data_context.root_directory
  44             else:
  45                 query_store_backend = {
  46                     "class_name": "InMemoryStoreBackend"
  47                 }
  48         module_name = 'great_expectations.data_context.store'
  49         self._store_backend = instantiate_class_from_config(
  50             config=query_store_backend,
  51             runtime_environment={
  52                 "root_directory": root_directory
  53             },
  54             config_defaults={
  55                 "module_name": module_name
  56             }
  57         )
  58         if not self._store_backend:
  59             raise ClassInstantiationError(
  60                 module_name=module_name,
  61                 package_name=None,
  62                 class_name=query_store_backend['class_name']
  63             )
  64         if queries is not None:
  65             for query_name, query in queries.items():
  66                 self.add_query(query_name, query)
  67 
  68     def _get_raw_query(self, generator_asset):
  69         return self._store_backend.get(tuple(generator_asset))
  70 
  71     def _get_iterator(self, generator_asset, query_parameters=None):
  72         raw_query = self._get_raw_query(generator_asset)
  73         if raw_query is None:
  74             logger.warning("No query defined for generator asset: %s" % generator_asset)
  75             # There is no valid query path or temp query storage defined with the generator_asset
  76             return None
  77 
  78         if query_parameters is None:
  79             iter_ = iter([
  80                 SqlAlchemyDatasourceQueryBatchKwargs(
  81                     query=raw_query
  82                 )])
  83         else:
  84             iter_= iter([
  85                 SqlAlchemyDatasourceQueryBatchKwargs(
  86                     query=raw_query,
  87                     query_parameters=query_parameters
  88                 )])
  89 
  90         return iter_
  91 
  92     def add_query(self, generator_asset, query):
  93         # Backends must have a tuple key; we use only a single-element tuple
  94         self._store_backend.set(tuple(generator_asset), query)
  95 
  96     def get_available_data_asset_names(self):
  97         defined_queries = self._store_backend.list_keys()
  98         # Backends must have a tuple key; we use only a single-element tuple
  99         return {"names": [(query_key_tuple[0], "query") for query_key_tuple in defined_queries]}
  100 
  101     def _build_batch_kwargs(self, batch_parameters):
  102         """Build batch kwargs from a partition id."""
  103         generator_asset = batch_parameters.pop("name")
  104         raw_query = self._get_raw_query(generator_asset)
  105         partition_id = batch_parameters.pop("partition_id", None)
  106         batch_kwargs = self._datasource.process_batch_parameters(**batch_parameters)
  107         batch_kwargs["query"] = raw_query
  108 
  109         if partition_id:
  110             if not batch_kwargs["query_parameters"]:
  111                 batch_kwargs["query_parameters"] = {}
  112             batch_kwargs["query_parameters"]["partition_id"] = partition_id
  113 
  114         return SqlAlchemyDatasourceQueryBatchKwargs(batch_kwargs)
  115 
  116     def get_available_partition_ids(self, generator_asset):
  117         raise BatchKwargsError("QueryBatchKwargsGenerator cannot identify partitions.", {})
  118
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/great_expectations/datasource/generator/query_generator.py b/great_expectations/datasource/generator/query_generator.py
  --- a/great_expectations/datasource/generator/query_generator.py
  +++ b/great_expectations/datasource/generator/query_generator.py
  @@ -25,7 +25,7 @@
   class QueryBatchKwargsGenerator(BatchKwargsGenerator):
       """Produce query-style batch_kwargs from sql files stored on disk
       """
  -    recognized_batch_parameters = {'query_parameters', 'partition_id'}
  +    recognized_batch_parameters = {'query_parameters', 'partition_id', 'name'}
   
       def __init__(self, name="default", datasource=None, query_store_backend=None, queries=None):
           super(QueryBatchKwargsGenerator, self).__init__(name=name, datasource=datasource)
  @@ -66,7 +66,7 @@
                   self.add_query(query_name, query)
   
       def _get_raw_query(self, generator_asset):
  -        return self._store_backend.get(tuple(generator_asset))
  +        return self._store_backend.get((generator_asset,))
   
       def _get_iterator(self, generator_asset, query_parameters=None):
           raw_query = self._get_raw_query(generator_asset)
  @@ -91,7 +91,7 @@
   
       def add_query(self, generator_asset, query):
           # Backends must have a tuple key; we use only a single-element tuple
  -        self._store_backend.set(tuple(generator_asset), query)
  +        self._store_backend.set((generator_asset,), query)
   
       def get_available_data_asset_names(self):
           defined_queries = self._store_backend.list_keys()
  
verification_info: {"golden_diff": "diff --git a/great_expectations/datasource/generator/query_generator.py b/great_expectations/datasource/generator/query_generator.py\n--- a/great_expectations/datasource/generator/query_generator.py\n+++ b/great_expectations/datasource/generator/query_generator.py\n@@ -25,7 +25,7 @@\n class QueryBatchKwargsGenerator(BatchKwargsGenerator):\n     \"\"\"Produce query-style batch_kwargs from sql files stored on disk\n     \"\"\"\n-    recognized_batch_parameters = {'query_parameters', 'partition_id'}\n+    recognized_batch_parameters = {'query_parameters', 'partition_id', 'name'}\n \n     def __init__(self, name=\"default\", datasource=None, query_store_backend=None, queries=None):\n         super(QueryBatchKwargsGenerator, self).__init__(name=name, datasource=datasource)\n@@ -66,7 +66,7 @@\n                 self.add_query(query_name, query)\n \n     def _get_raw_query(self, generator_asset):\n-        return self._store_backend.get(tuple(generator_asset))\n+        return self._store_backend.get((generator_asset,))\n \n     def _get_iterator(self, generator_asset, query_parameters=None):\n         raw_query = self._get_raw_query(generator_asset)\n@@ -91,7 +91,7 @@\n \n     def add_query(self, generator_asset, query):\n         # Backends must have a tuple key; we use only a single-element tuple\n-        self._store_backend.set(tuple(generator_asset), query)\n+        self._store_backend.set((generator_asset,), query)\n \n     def get_available_data_asset_names(self):\n         defined_queries = self._store_backend.list_keys()\n", "issue": "QueryBatchKwargsGenerator._get_raw_query produces incorrect filepath\nI am using the `QueryBatchKwargsGenerator` to generate `BATCH_KWARGS` using a SQL file I have stored on disk. My `great_expectations.yml` looks like:\r\n\r\n```yaml\r\ndatasources:\r\n    domi:\r\n      class_name: SqlAlchemyDatasource\r\n      module_name:\r\n      data_asset_type:\r\n        class_name: SqlAlchemyDataset\r\n      credentials:\r\n        drivername: postgres\r\n        host: ${HOST}\r\n        port: ${PORT}\r\n        username: ${USER}\r\n        password: ${PASSWORD}\r\n        database: ${DBNAME}\r\n      generators:\r\n        apartments-generator:\r\n          class_name: QueryBatchKwargsGenerator\r\n          name: apartments\r\n```\r\n\r\nI am running the following:\r\n\r\n```python\r\n>>> import great_expectations as get\r\n\r\n>>> context = ge.data_context.DataContext()\r\n>>> context.get_available_data_asset_names()\r\n{'domi': {'apartments-generator': {'names': [('listings', 'query')]}}}\r\n\r\n>>> context.build_batch_kwargs(\r\n    datasource='domi', generator='apartments-generator', name='listings'\r\n)\r\n```\r\n\r\nWhich raises this error:\r\n\r\n![image](https://user-images.githubusercontent.com/11096727/79018747-8e14b080-7b42-11ea-9564-7b35b23dac72.png)\r\n\r\nThis happens because `_get_raw_query` is doing `tuple('listings')` which returns: `('l', 'i', 's', 't', 'i', 'n', 'g', 's')`)\r\n\r\n```python\r\n    def _get_raw_query(self, generator_asset):\r\n        return self._store_backend.get(tuple(generator_asset))\r\n```\r\n\r\nI believe this should just be replaced with:\r\n\r\n```python\r\n    def _get_raw_query(self, generator_asset):\r\n        return self._store_backend.get((generator_asset,))\r\n```\r\n\r\nCurrently I can get around this by providing a tuple instead of a string, i.e.\r\n\r\n```python\r\ncontext.build_batch_kwargs(\r\n    datasource='domi',\r\n    generator='apartments-generator',\r\n    name=('listings', )\r\n)\r\n```\r\n\r\nBut that goes against what the docs are saying [here](https://docs.greatexpectations.io/en/latest/module_docs/data_context_module.html#great_expectations.data_context.BaseDataContext.build_batch_kwargs):\r\n\r\n![image](https://user-images.githubusercontent.com/11096727/79018985-30cd2f00-7b43-11ea-962c-3a563f19acc6.png)\r\n\n", "before_files": [{"content": "import os\nimport logging\n\nfrom .batch_kwargs_generator import BatchKwargsGenerator\nfrom great_expectations.datasource.types import SqlAlchemyDatasourceQueryBatchKwargs\nfrom great_expectations.exceptions import (\n    BatchKwargsError,\n    ClassInstantiationError,\n)\nfrom ...data_context.util import instantiate_class_from_config\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    import sqlalchemy\n    from sqlalchemy import create_engine\n    from sqlalchemy.engine import reflection\nexcept ImportError:\n    sqlalchemy = None\n    create_engine = None\n    reflection = None\n    logger.debug(\"Unable to import sqlalchemy.\")\n\n\nclass QueryBatchKwargsGenerator(BatchKwargsGenerator):\n    \"\"\"Produce query-style batch_kwargs from sql files stored on disk\n    \"\"\"\n    recognized_batch_parameters = {'query_parameters', 'partition_id'}\n\n    def __init__(self, name=\"default\", datasource=None, query_store_backend=None, queries=None):\n        super(QueryBatchKwargsGenerator, self).__init__(name=name, datasource=datasource)\n        root_directory = None\n        if query_store_backend is None:\n            # We will choose a Tuple store if there is a configured DataContext with a root_directory,\n            # and an InMemoryStore otherwise\n            if datasource and datasource.data_context and datasource.data_context.root_directory:\n                query_store_backend = {\n                    \"class_name\": \"TupleFilesystemStoreBackend\",\n                    \"base_directory\": os.path.join(datasource.data_context.root_directory, \"datasources\",\n                                                   datasource.name, \"generators\", name),\n                    \"filepath_suffix\": \".sql\"\n                }\n                root_directory = datasource.data_context.root_directory\n            else:\n                query_store_backend = {\n                    \"class_name\": \"InMemoryStoreBackend\"\n                }\n        module_name = 'great_expectations.data_context.store'\n        self._store_backend = instantiate_class_from_config(\n            config=query_store_backend,\n            runtime_environment={\n                \"root_directory\": root_directory\n            },\n            config_defaults={\n                \"module_name\": module_name\n            }\n        )\n        if not self._store_backend:\n            raise ClassInstantiationError(\n                module_name=module_name,\n                package_name=None,\n                class_name=query_store_backend['class_name']\n            )\n        if queries is not None:\n            for query_name, query in queries.items():\n                self.add_query(query_name, query)\n\n    def _get_raw_query(self, generator_asset):\n        return self._store_backend.get(tuple(generator_asset))\n\n    def _get_iterator(self, generator_asset, query_parameters=None):\n        raw_query = self._get_raw_query(generator_asset)\n        if raw_query is None:\n            logger.warning(\"No query defined for generator asset: %s\" % generator_asset)\n            # There is no valid query path or temp query storage defined with the generator_asset\n            return None\n\n        if query_parameters is None:\n            iter_ = iter([\n                SqlAlchemyDatasourceQueryBatchKwargs(\n                    query=raw_query\n                )])\n        else:\n            iter_= iter([\n                SqlAlchemyDatasourceQueryBatchKwargs(\n                    query=raw_query,\n                    query_parameters=query_parameters\n                )])\n\n        return iter_\n\n    def add_query(self, generator_asset, query):\n        # Backends must have a tuple key; we use only a single-element tuple\n        self._store_backend.set(tuple(generator_asset), query)\n\n    def get_available_data_asset_names(self):\n        defined_queries = self._store_backend.list_keys()\n        # Backends must have a tuple key; we use only a single-element tuple\n        return {\"names\": [(query_key_tuple[0], \"query\") for query_key_tuple in defined_queries]}\n\n    def _build_batch_kwargs(self, batch_parameters):\n        \"\"\"Build batch kwargs from a partition id.\"\"\"\n        generator_asset = batch_parameters.pop(\"name\")\n        raw_query = self._get_raw_query(generator_asset)\n        partition_id = batch_parameters.pop(\"partition_id\", None)\n        batch_kwargs = self._datasource.process_batch_parameters(**batch_parameters)\n        batch_kwargs[\"query\"] = raw_query\n\n        if partition_id:\n            if not batch_kwargs[\"query_parameters\"]:\n                batch_kwargs[\"query_parameters\"] = {}\n            batch_kwargs[\"query_parameters\"][\"partition_id\"] = partition_id\n\n        return SqlAlchemyDatasourceQueryBatchKwargs(batch_kwargs)\n\n    def get_available_partition_ids(self, generator_asset):\n        raise BatchKwargsError(\"QueryBatchKwargsGenerator cannot identify partitions.\", {})\n", "path": "great_expectations/datasource/generator/query_generator.py"}], "after_files": [{"content": "import os\nimport logging\n\nfrom .batch_kwargs_generator import BatchKwargsGenerator\nfrom great_expectations.datasource.types import SqlAlchemyDatasourceQueryBatchKwargs\nfrom great_expectations.exceptions import (\n    BatchKwargsError,\n    ClassInstantiationError,\n)\nfrom ...data_context.util import instantiate_class_from_config\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    import sqlalchemy\n    from sqlalchemy import create_engine\n    from sqlalchemy.engine import reflection\nexcept ImportError:\n    sqlalchemy = None\n    create_engine = None\n    reflection = None\n    logger.debug(\"Unable to import sqlalchemy.\")\n\n\nclass QueryBatchKwargsGenerator(BatchKwargsGenerator):\n    \"\"\"Produce query-style batch_kwargs from sql files stored on disk\n    \"\"\"\n    recognized_batch_parameters = {'query_parameters', 'partition_id', 'name'}\n\n    def __init__(self, name=\"default\", datasource=None, query_store_backend=None, queries=None):\n        super(QueryBatchKwargsGenerator, self).__init__(name=name, datasource=datasource)\n        root_directory = None\n        if query_store_backend is None:\n            # We will choose a Tuple store if there is a configured DataContext with a root_directory,\n            # and an InMemoryStore otherwise\n            if datasource and datasource.data_context and datasource.data_context.root_directory:\n                query_store_backend = {\n                    \"class_name\": \"TupleFilesystemStoreBackend\",\n                    \"base_directory\": os.path.join(datasource.data_context.root_directory, \"datasources\",\n                                                   datasource.name, \"generators\", name),\n                    \"filepath_suffix\": \".sql\"\n                }\n                root_directory = datasource.data_context.root_directory\n            else:\n                query_store_backend = {\n                    \"class_name\": \"InMemoryStoreBackend\"\n                }\n        module_name = 'great_expectations.data_context.store'\n        self._store_backend = instantiate_class_from_config(\n            config=query_store_backend,\n            runtime_environment={\n                \"root_directory\": root_directory\n            },\n            config_defaults={\n                \"module_name\": module_name\n            }\n        )\n        if not self._store_backend:\n            raise ClassInstantiationError(\n                module_name=module_name,\n                package_name=None,\n                class_name=query_store_backend['class_name']\n            )\n        if queries is not None:\n            for query_name, query in queries.items():\n                self.add_query(query_name, query)\n\n    def _get_raw_query(self, generator_asset):\n        return self._store_backend.get((generator_asset,))\n\n    def _get_iterator(self, generator_asset, query_parameters=None):\n        raw_query = self._get_raw_query(generator_asset)\n        if raw_query is None:\n            logger.warning(\"No query defined for generator asset: %s\" % generator_asset)\n            # There is no valid query path or temp query storage defined with the generator_asset\n            return None\n\n        if query_parameters is None:\n            iter_ = iter([\n                SqlAlchemyDatasourceQueryBatchKwargs(\n                    query=raw_query\n                )])\n        else:\n            iter_= iter([\n                SqlAlchemyDatasourceQueryBatchKwargs(\n                    query=raw_query,\n                    query_parameters=query_parameters\n                )])\n\n        return iter_\n\n    def add_query(self, generator_asset, query):\n        # Backends must have a tuple key; we use only a single-element tuple\n        self._store_backend.set((generator_asset,), query)\n\n    def get_available_data_asset_names(self):\n        defined_queries = self._store_backend.list_keys()\n        # Backends must have a tuple key; we use only a single-element tuple\n        return {\"names\": [(query_key_tuple[0], \"query\") for query_key_tuple in defined_queries]}\n\n    def _build_batch_kwargs(self, batch_parameters):\n        \"\"\"Build batch kwargs from a partition id.\"\"\"\n        generator_asset = batch_parameters.pop(\"name\")\n        raw_query = self._get_raw_query(generator_asset)\n        partition_id = batch_parameters.pop(\"partition_id\", None)\n        batch_kwargs = self._datasource.process_batch_parameters(**batch_parameters)\n        batch_kwargs[\"query\"] = raw_query\n\n        if partition_id:\n            if not batch_kwargs[\"query_parameters\"]:\n                batch_kwargs[\"query_parameters\"] = {}\n            batch_kwargs[\"query_parameters\"][\"partition_id\"] = partition_id\n\n        return SqlAlchemyDatasourceQueryBatchKwargs(batch_kwargs)\n\n    def get_available_partition_ids(self, generator_asset):\n        raise BatchKwargsError(\"QueryBatchKwargsGenerator cannot identify partitions.\", {})\n", "path": "great_expectations/datasource/generator/query_generator.py"}]}