We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
URL query runner: URL base path doesn't need to be a required field


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `redash/query_runner/url.py`
Content:
```
1 from redash.query_runner import BaseHTTPQueryRunner, register
2 
3 
4 class Url(BaseHTTPQueryRunner):
5 
6     @classmethod
7     def annotate_query(cls):
8         return False
9 
10     def test_connection(self):
11         pass
12 
13     def run_query(self, query, user):
14         base_url = self.configuration.get("url", None)
15 
16         try:
17             query = query.strip()
18 
19             if base_url is not None and base_url != "":
20                 if query.find("://") > -1:
21                     return None, "Accepting only relative URLs to '%s'" % base_url
22 
23             if base_url is None:
24                 base_url = ""
25 
26             url = base_url + query
27 
28             response, error = self.get_response(url)
29             if error is not None:
30                 return None, error
31 
32             json_data = response.content.strip()
33 
34             if json_data:
35                 return json_data, None
36             else:
37                 return None, "Got empty response from '{}'.".format(url)
38         except KeyboardInterrupt:
39             return None, "Query cancelled by user."
40 
41 
42 register(Url)
43
```

Path: `redash/query_runner/__init__.py`
Content:
```
1 import logging
2 import requests
3 
4 from redash import settings
5 from redash.utils import json_loads
6 
7 logger = logging.getLogger(__name__)
8 
9 __all__ = [
10     'BaseQueryRunner',
11     'BaseHTTPQueryRunner',
12     'InterruptException',
13     'BaseSQLQueryRunner',
14     'TYPE_DATETIME',
15     'TYPE_BOOLEAN',
16     'TYPE_INTEGER',
17     'TYPE_STRING',
18     'TYPE_DATE',
19     'TYPE_FLOAT',
20     'SUPPORTED_COLUMN_TYPES',
21     'register',
22     'get_query_runner',
23     'import_query_runners'
24 ]
25 
26 # Valid types of columns returned in results:
27 TYPE_INTEGER = 'integer'
28 TYPE_FLOAT = 'float'
29 TYPE_BOOLEAN = 'boolean'
30 TYPE_STRING = 'string'
31 TYPE_DATETIME = 'datetime'
32 TYPE_DATE = 'date'
33 
34 SUPPORTED_COLUMN_TYPES = set([
35     TYPE_INTEGER,
36     TYPE_FLOAT,
37     TYPE_BOOLEAN,
38     TYPE_STRING,
39     TYPE_DATETIME,
40     TYPE_DATE
41 ])
42 
43 
44 class InterruptException(Exception):
45     pass
46 
47 
48 class NotSupported(Exception):
49     pass
50 
51 
52 class BaseQueryRunner(object):
53     noop_query = None
54 
55     def __init__(self, configuration):
56         self.syntax = 'sql'
57         self.configuration = configuration
58 
59     @classmethod
60     def name(cls):
61         return cls.__name__
62 
63     @classmethod
64     def type(cls):
65         return cls.__name__.lower()
66 
67     @classmethod
68     def enabled(cls):
69         return True
70 
71     @classmethod
72     def annotate_query(cls):
73         return True
74 
75     @classmethod
76     def configuration_schema(cls):
77         return {}
78 
79     def test_connection(self):
80         if self.noop_query is None:
81             raise NotImplementedError()
82         data, error = self.run_query(self.noop_query, None)
83 
84         if error is not None:
85             raise Exception(error)
86 
87     def run_query(self, query, user):
88         raise NotImplementedError()
89 
90     def fetch_columns(self, columns):
91         column_names = []
92         duplicates_counter = 1
93         new_columns = []
94 
95         for col in columns:
96             column_name = col[0]
97             if column_name in column_names:
98                 column_name = "{}{}".format(column_name, duplicates_counter)
99                 duplicates_counter += 1
100 
101             column_names.append(column_name)
102             new_columns.append({'name': column_name,
103                                 'friendly_name': column_name,
104                                 'type': col[1]})
105 
106         return new_columns
107 
108     def get_schema(self, get_stats=False):
109         raise NotSupported()
110 
111     def _run_query_internal(self, query):
112         results, error = self.run_query(query, None)
113 
114         if error is not None:
115             raise Exception("Failed running query [%s]." % query)
116         return json_loads(results)['rows']
117 
118     @classmethod
119     def to_dict(cls):
120         return {
121             'name': cls.name(),
122             'type': cls.type(),
123             'configuration_schema': cls.configuration_schema()
124         }
125 
126 
127 class BaseSQLQueryRunner(BaseQueryRunner):
128 
129     def get_schema(self, get_stats=False):
130         schema_dict = {}
131         self._get_tables(schema_dict)
132         if settings.SCHEMA_RUN_TABLE_SIZE_CALCULATIONS and get_stats:
133             self._get_tables_stats(schema_dict)
134         return schema_dict.values()
135 
136     def _get_tables(self, schema_dict):
137         return []
138 
139     def _get_tables_stats(self, tables_dict):
140         for t in tables_dict.keys():
141             if type(tables_dict[t]) == dict:
142                 res = self._run_query_internal('select count(*) as cnt from %s' % t)
143                 tables_dict[t]['size'] = res[0]['cnt']
144 
145 
146 class BaseHTTPQueryRunner(BaseQueryRunner):
147     response_error = "Endpoint returned unexpected status code"
148     requires_authentication = False
149     url_title = 'URL base path'
150     username_title = 'HTTP Basic Auth Username'
151     password_title = 'HTTP Basic Auth Password'
152 
153     @classmethod
154     def configuration_schema(cls):
155         schema = {
156             'type': 'object',
157             'properties': {
158                 'url': {
159                     'type': 'string',
160                     'title': cls.url_title,
161                 },
162                 'username': {
163                     'type': 'string',
164                     'title': cls.username_title,
165                 },
166                 'password': {
167                     'type': 'string',
168                     'title': cls.password_title,
169                 },
170             },
171             'required': ['url'],
172             'secret': ['password']
173         }
174         if cls.requires_authentication:
175             schema['required'] += ['username', 'password']
176         return schema
177 
178     def get_auth(self):
179         username = self.configuration.get('username')
180         password = self.configuration.get('password')
181         if username and password:
182             return (username, password)
183         if self.requires_authentication:
184             raise ValueError("Username and Password required")
185         else:
186             return None
187 
188     def get_response(self, url, auth=None, **kwargs):
189         # Get authentication values if not given
190         if auth is None:
191             auth = self.get_auth()
192 
193         # Then call requests to get the response from the given endpoint
194         # URL optionally, with the additional requests parameters.
195         error = None
196         response = None
197         try:
198             response = requests.get(url, auth=auth, **kwargs)
199             # Raise a requests HTTP exception with the appropriate reason
200             # for 4xx and 5xx response status codes which is later caught
201             # and passed back.
202             response.raise_for_status()
203 
204             # Any other responses (e.g. 2xx and 3xx):
205             if response.status_code != 200:
206                 error = '{} ({}).'.format(
207                     self.response_error,
208                     response.status_code,
209                 )
210 
211         except requests.HTTPError as exc:
212             logger.exception(exc)
213             error = (
214                 "Failed to execute query. "
215                 "Return Code: {} Reason: {}".format(
216                     response.status_code,
217                     response.text
218                 )
219             )
220         except requests.RequestException as exc:
221             # Catch all other requests exceptions and return the error.
222             logger.exception(exc)
223             error = str(exc)
224 
225         # Return response and error.
226         return response, error
227 
228 
229 query_runners = {}
230 
231 
232 def register(query_runner_class):
233     global query_runners
234     if query_runner_class.enabled():
235         logger.debug("Registering %s (%s) query runner.", query_runner_class.name(), query_runner_class.type())
236         query_runners[query_runner_class.type()] = query_runner_class
237     else:
238         logger.debug("%s query runner enabled but not supported, not registering. Either disable or install missing "
239                      "dependencies.", query_runner_class.name())
240 
241 
242 def get_query_runner(query_runner_type, configuration):
243     query_runner_class = query_runners.get(query_runner_type, None)
244     if query_runner_class is None:
245         return None
246 
247     return query_runner_class(configuration)
248 
249 
250 def get_configuration_schema_for_query_runner_type(query_runner_type):
251     query_runner_class = query_runners.get(query_runner_type, None)
252     if query_runner_class is None:
253         return None
254 
255     return query_runner_class.configuration_schema()
256 
257 
258 def import_query_runners(query_runner_imports):
259     for runner_import in query_runner_imports:
260         __import__(runner_import)
261
```
--- 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/redash/query_runner/__init__.py b/redash/query_runner/__init__.py
--- a/redash/query_runner/__init__.py
+++ b/redash/query_runner/__init__.py
@@ -146,6 +146,7 @@
 class BaseHTTPQueryRunner(BaseQueryRunner):
     response_error = "Endpoint returned unexpected status code"
     requires_authentication = False
+    requires_url = True
     url_title = 'URL base path'
     username_title = 'HTTP Basic Auth Username'
     password_title = 'HTTP Basic Auth Password'
@@ -168,9 +169,15 @@
                     'title': cls.password_title,
                 },
             },
-            'required': ['url'],
             'secret': ['password']
         }
+
+        if cls.requires_url or cls.requires_authentication:
+            schema['required'] = []
+
+        if cls.requires_url:
+            schema['required'] += ['url']
+
         if cls.requires_authentication:
             schema['required'] += ['username', 'password']
         return schema
diff --git a/redash/query_runner/url.py b/redash/query_runner/url.py
--- a/redash/query_runner/url.py
+++ b/redash/query_runner/url.py
@@ -2,6 +2,7 @@
 
 
 class Url(BaseHTTPQueryRunner):
+    requires_url = False
 
     @classmethod
     def annotate_query(cls):

{"golden_diff": "diff --git a/redash/query_runner/__init__.py b/redash/query_runner/__init__.py\n--- a/redash/query_runner/__init__.py\n+++ b/redash/query_runner/__init__.py\n@@ -146,6 +146,7 @@\n class BaseHTTPQueryRunner(BaseQueryRunner):\n     response_error = \"Endpoint returned unexpected status code\"\n     requires_authentication = False\n+    requires_url = True\n     url_title = 'URL base path'\n     username_title = 'HTTP Basic Auth Username'\n     password_title = 'HTTP Basic Auth Password'\n@@ -168,9 +169,15 @@\n                     'title': cls.password_title,\n                 },\n             },\n-            'required': ['url'],\n             'secret': ['password']\n         }\n+\n+        if cls.requires_url or cls.requires_authentication:\n+            schema['required'] = []\n+\n+        if cls.requires_url:\n+            schema['required'] += ['url']\n+\n         if cls.requires_authentication:\n             schema['required'] += ['username', 'password']\n         return schema\ndiff --git a/redash/query_runner/url.py b/redash/query_runner/url.py\n--- a/redash/query_runner/url.py\n+++ b/redash/query_runner/url.py\n@@ -2,6 +2,7 @@\n \n \n class Url(BaseHTTPQueryRunner):\n+    requires_url = False\n \n     @classmethod\n     def annotate_query(cls):\n", "issue": "URL query runner: URL base path doesn't need to be a required field\n\n", "before_files": [{"content": "from redash.query_runner import BaseHTTPQueryRunner, register\n\n\nclass Url(BaseHTTPQueryRunner):\n\n    @classmethod\n    def annotate_query(cls):\n        return False\n\n    def test_connection(self):\n        pass\n\n    def run_query(self, query, user):\n        base_url = self.configuration.get(\"url\", None)\n\n        try:\n            query = query.strip()\n\n            if base_url is not None and base_url != \"\":\n                if query.find(\"://\") > -1:\n                    return None, \"Accepting only relative URLs to '%s'\" % base_url\n\n            if base_url is None:\n                base_url = \"\"\n\n            url = base_url + query\n\n            response, error = self.get_response(url)\n            if error is not None:\n                return None, error\n\n            json_data = response.content.strip()\n\n            if json_data:\n                return json_data, None\n            else:\n                return None, \"Got empty response from '{}'.\".format(url)\n        except KeyboardInterrupt:\n            return None, \"Query cancelled by user.\"\n\n\nregister(Url)\n", "path": "redash/query_runner/url.py"}, {"content": "import logging\nimport requests\n\nfrom redash import settings\nfrom redash.utils import json_loads\n\nlogger = logging.getLogger(__name__)\n\n__all__ = [\n    'BaseQueryRunner',\n    'BaseHTTPQueryRunner',\n    'InterruptException',\n    'BaseSQLQueryRunner',\n    'TYPE_DATETIME',\n    'TYPE_BOOLEAN',\n    'TYPE_INTEGER',\n    'TYPE_STRING',\n    'TYPE_DATE',\n    'TYPE_FLOAT',\n    'SUPPORTED_COLUMN_TYPES',\n    'register',\n    'get_query_runner',\n    'import_query_runners'\n]\n\n# Valid types of columns returned in results:\nTYPE_INTEGER = 'integer'\nTYPE_FLOAT = 'float'\nTYPE_BOOLEAN = 'boolean'\nTYPE_STRING = 'string'\nTYPE_DATETIME = 'datetime'\nTYPE_DATE = 'date'\n\nSUPPORTED_COLUMN_TYPES = set([\n    TYPE_INTEGER,\n    TYPE_FLOAT,\n    TYPE_BOOLEAN,\n    TYPE_STRING,\n    TYPE_DATETIME,\n    TYPE_DATE\n])\n\n\nclass InterruptException(Exception):\n    pass\n\n\nclass NotSupported(Exception):\n    pass\n\n\nclass BaseQueryRunner(object):\n    noop_query = None\n\n    def __init__(self, configuration):\n        self.syntax = 'sql'\n        self.configuration = configuration\n\n    @classmethod\n    def name(cls):\n        return cls.__name__\n\n    @classmethod\n    def type(cls):\n        return cls.__name__.lower()\n\n    @classmethod\n    def enabled(cls):\n        return True\n\n    @classmethod\n    def annotate_query(cls):\n        return True\n\n    @classmethod\n    def configuration_schema(cls):\n        return {}\n\n    def test_connection(self):\n        if self.noop_query is None:\n            raise NotImplementedError()\n        data, error = self.run_query(self.noop_query, None)\n\n        if error is not None:\n            raise Exception(error)\n\n    def run_query(self, query, user):\n        raise NotImplementedError()\n\n    def fetch_columns(self, columns):\n        column_names = []\n        duplicates_counter = 1\n        new_columns = []\n\n        for col in columns:\n            column_name = col[0]\n            if column_name in column_names:\n                column_name = \"{}{}\".format(column_name, duplicates_counter)\n                duplicates_counter += 1\n\n            column_names.append(column_name)\n            new_columns.append({'name': column_name,\n                                'friendly_name': column_name,\n                                'type': col[1]})\n\n        return new_columns\n\n    def get_schema(self, get_stats=False):\n        raise NotSupported()\n\n    def _run_query_internal(self, query):\n        results, error = self.run_query(query, None)\n\n        if error is not None:\n            raise Exception(\"Failed running query [%s].\" % query)\n        return json_loads(results)['rows']\n\n    @classmethod\n    def to_dict(cls):\n        return {\n            'name': cls.name(),\n            'type': cls.type(),\n            'configuration_schema': cls.configuration_schema()\n        }\n\n\nclass BaseSQLQueryRunner(BaseQueryRunner):\n\n    def get_schema(self, get_stats=False):\n        schema_dict = {}\n        self._get_tables(schema_dict)\n        if settings.SCHEMA_RUN_TABLE_SIZE_CALCULATIONS and get_stats:\n            self._get_tables_stats(schema_dict)\n        return schema_dict.values()\n\n    def _get_tables(self, schema_dict):\n        return []\n\n    def _get_tables_stats(self, tables_dict):\n        for t in tables_dict.keys():\n            if type(tables_dict[t]) == dict:\n                res = self._run_query_internal('select count(*) as cnt from %s' % t)\n                tables_dict[t]['size'] = res[0]['cnt']\n\n\nclass BaseHTTPQueryRunner(BaseQueryRunner):\n    response_error = \"Endpoint returned unexpected status code\"\n    requires_authentication = False\n    url_title = 'URL base path'\n    username_title = 'HTTP Basic Auth Username'\n    password_title = 'HTTP Basic Auth Password'\n\n    @classmethod\n    def configuration_schema(cls):\n        schema = {\n            'type': 'object',\n            'properties': {\n                'url': {\n                    'type': 'string',\n                    'title': cls.url_title,\n                },\n                'username': {\n                    'type': 'string',\n                    'title': cls.username_title,\n                },\n                'password': {\n                    'type': 'string',\n                    'title': cls.password_title,\n                },\n            },\n            'required': ['url'],\n            'secret': ['password']\n        }\n        if cls.requires_authentication:\n            schema['required'] += ['username', 'password']\n        return schema\n\n    def get_auth(self):\n        username = self.configuration.get('username')\n        password = self.configuration.get('password')\n        if username and password:\n            return (username, password)\n        if self.requires_authentication:\n            raise ValueError(\"Username and Password required\")\n        else:\n            return None\n\n    def get_response(self, url, auth=None, **kwargs):\n        # Get authentication values if not given\n        if auth is None:\n            auth = self.get_auth()\n\n        # Then call requests to get the response from the given endpoint\n        # URL optionally, with the additional requests parameters.\n        error = None\n        response = None\n        try:\n            response = requests.get(url, auth=auth, **kwargs)\n            # Raise a requests HTTP exception with the appropriate reason\n            # for 4xx and 5xx response status codes which is later caught\n            # and passed back.\n            response.raise_for_status()\n\n            # Any other responses (e.g. 2xx and 3xx):\n            if response.status_code != 200:\n                error = '{} ({}).'.format(\n                    self.response_error,\n                    response.status_code,\n                )\n\n        except requests.HTTPError as exc:\n            logger.exception(exc)\n            error = (\n                \"Failed to execute query. \"\n                \"Return Code: {} Reason: {}\".format(\n                    response.status_code,\n                    response.text\n                )\n            )\n        except requests.RequestException as exc:\n            # Catch all other requests exceptions and return the error.\n            logger.exception(exc)\n            error = str(exc)\n\n        # Return response and error.\n        return response, error\n\n\nquery_runners = {}\n\n\ndef register(query_runner_class):\n    global query_runners\n    if query_runner_class.enabled():\n        logger.debug(\"Registering %s (%s) query runner.\", query_runner_class.name(), query_runner_class.type())\n        query_runners[query_runner_class.type()] = query_runner_class\n    else:\n        logger.debug(\"%s query runner enabled but not supported, not registering. Either disable or install missing \"\n                     \"dependencies.\", query_runner_class.name())\n\n\ndef get_query_runner(query_runner_type, configuration):\n    query_runner_class = query_runners.get(query_runner_type, None)\n    if query_runner_class is None:\n        return None\n\n    return query_runner_class(configuration)\n\n\ndef get_configuration_schema_for_query_runner_type(query_runner_type):\n    query_runner_class = query_runners.get(query_runner_type, None)\n    if query_runner_class is None:\n        return None\n\n    return query_runner_class.configuration_schema()\n\n\ndef import_query_runners(query_runner_imports):\n    for runner_import in query_runner_imports:\n        __import__(runner_import)\n", "path": "redash/query_runner/__init__.py"}], "after_files": [{"content": "from redash.query_runner import BaseHTTPQueryRunner, register\n\n\nclass Url(BaseHTTPQueryRunner):\n    requires_url = False\n\n    @classmethod\n    def annotate_query(cls):\n        return False\n\n    def test_connection(self):\n        pass\n\n    def run_query(self, query, user):\n        base_url = self.configuration.get(\"url\", None)\n\n        try:\n            query = query.strip()\n\n            if base_url is not None and base_url != \"\":\n                if query.find(\"://\") > -1:\n                    return None, \"Accepting only relative URLs to '%s'\" % base_url\n\n            if base_url is None:\n                base_url = \"\"\n\n            url = base_url + query\n\n            response, error = self.get_response(url)\n            if error is not None:\n                return None, error\n\n            json_data = response.content.strip()\n\n            if json_data:\n                return json_data, None\n            else:\n                return None, \"Got empty response from '{}'.\".format(url)\n        except KeyboardInterrupt:\n            return None, \"Query cancelled by user.\"\n\n\nregister(Url)\n", "path": "redash/query_runner/url.py"}, {"content": "import logging\nimport requests\n\nfrom redash import settings\nfrom redash.utils import json_loads\n\nlogger = logging.getLogger(__name__)\n\n__all__ = [\n    'BaseQueryRunner',\n    'BaseHTTPQueryRunner',\n    'InterruptException',\n    'BaseSQLQueryRunner',\n    'TYPE_DATETIME',\n    'TYPE_BOOLEAN',\n    'TYPE_INTEGER',\n    'TYPE_STRING',\n    'TYPE_DATE',\n    'TYPE_FLOAT',\n    'SUPPORTED_COLUMN_TYPES',\n    'register',\n    'get_query_runner',\n    'import_query_runners'\n]\n\n# Valid types of columns returned in results:\nTYPE_INTEGER = 'integer'\nTYPE_FLOAT = 'float'\nTYPE_BOOLEAN = 'boolean'\nTYPE_STRING = 'string'\nTYPE_DATETIME = 'datetime'\nTYPE_DATE = 'date'\n\nSUPPORTED_COLUMN_TYPES = set([\n    TYPE_INTEGER,\n    TYPE_FLOAT,\n    TYPE_BOOLEAN,\n    TYPE_STRING,\n    TYPE_DATETIME,\n    TYPE_DATE\n])\n\n\nclass InterruptException(Exception):\n    pass\n\n\nclass NotSupported(Exception):\n    pass\n\n\nclass BaseQueryRunner(object):\n    noop_query = None\n\n    def __init__(self, configuration):\n        self.syntax = 'sql'\n        self.configuration = configuration\n\n    @classmethod\n    def name(cls):\n        return cls.__name__\n\n    @classmethod\n    def type(cls):\n        return cls.__name__.lower()\n\n    @classmethod\n    def enabled(cls):\n        return True\n\n    @classmethod\n    def annotate_query(cls):\n        return True\n\n    @classmethod\n    def configuration_schema(cls):\n        return {}\n\n    def test_connection(self):\n        if self.noop_query is None:\n            raise NotImplementedError()\n        data, error = self.run_query(self.noop_query, None)\n\n        if error is not None:\n            raise Exception(error)\n\n    def run_query(self, query, user):\n        raise NotImplementedError()\n\n    def fetch_columns(self, columns):\n        column_names = []\n        duplicates_counter = 1\n        new_columns = []\n\n        for col in columns:\n            column_name = col[0]\n            if column_name in column_names:\n                column_name = \"{}{}\".format(column_name, duplicates_counter)\n                duplicates_counter += 1\n\n            column_names.append(column_name)\n            new_columns.append({'name': column_name,\n                                'friendly_name': column_name,\n                                'type': col[1]})\n\n        return new_columns\n\n    def get_schema(self, get_stats=False):\n        raise NotSupported()\n\n    def _run_query_internal(self, query):\n        results, error = self.run_query(query, None)\n\n        if error is not None:\n            raise Exception(\"Failed running query [%s].\" % query)\n        return json_loads(results)['rows']\n\n    @classmethod\n    def to_dict(cls):\n        return {\n            'name': cls.name(),\n            'type': cls.type(),\n            'configuration_schema': cls.configuration_schema()\n        }\n\n\nclass BaseSQLQueryRunner(BaseQueryRunner):\n\n    def get_schema(self, get_stats=False):\n        schema_dict = {}\n        self._get_tables(schema_dict)\n        if settings.SCHEMA_RUN_TABLE_SIZE_CALCULATIONS and get_stats:\n            self._get_tables_stats(schema_dict)\n        return schema_dict.values()\n\n    def _get_tables(self, schema_dict):\n        return []\n\n    def _get_tables_stats(self, tables_dict):\n        for t in tables_dict.keys():\n            if type(tables_dict[t]) == dict:\n                res = self._run_query_internal('select count(*) as cnt from %s' % t)\n                tables_dict[t]['size'] = res[0]['cnt']\n\n\nclass BaseHTTPQueryRunner(BaseQueryRunner):\n    response_error = \"Endpoint returned unexpected status code\"\n    requires_authentication = False\n    requires_url = True\n    url_title = 'URL base path'\n    username_title = 'HTTP Basic Auth Username'\n    password_title = 'HTTP Basic Auth Password'\n\n    @classmethod\n    def configuration_schema(cls):\n        schema = {\n            'type': 'object',\n            'properties': {\n                'url': {\n                    'type': 'string',\n                    'title': cls.url_title,\n                },\n                'username': {\n                    'type': 'string',\n                    'title': cls.username_title,\n                },\n                'password': {\n                    'type': 'string',\n                    'title': cls.password_title,\n                },\n            },\n            'secret': ['password']\n        }\n\n        if cls.requires_url or cls.requires_authentication:\n            schema['required'] = []\n\n        if cls.requires_url:\n            schema['required'] += ['url']\n\n        if cls.requires_authentication:\n            schema['required'] += ['username', 'password']\n        return schema\n\n    def get_auth(self):\n        username = self.configuration.get('username')\n        password = self.configuration.get('password')\n        if username and password:\n            return (username, password)\n        if self.requires_authentication:\n            raise ValueError(\"Username and Password required\")\n        else:\n            return None\n\n    def get_response(self, url, auth=None, **kwargs):\n        # Get authentication values if not given\n        if auth is None:\n            auth = self.get_auth()\n\n        # Then call requests to get the response from the given endpoint\n        # URL optionally, with the additional requests parameters.\n        error = None\n        response = None\n        try:\n            response = requests.get(url, auth=auth, **kwargs)\n            # Raise a requests HTTP exception with the appropriate reason\n            # for 4xx and 5xx response status codes which is later caught\n            # and passed back.\n            response.raise_for_status()\n\n            # Any other responses (e.g. 2xx and 3xx):\n            if response.status_code != 200:\n                error = '{} ({}).'.format(\n                    self.response_error,\n                    response.status_code,\n                )\n\n        except requests.HTTPError as exc:\n            logger.exception(exc)\n            error = (\n                \"Failed to execute query. \"\n                \"Return Code: {} Reason: {}\".format(\n                    response.status_code,\n                    response.text\n                )\n            )\n        except requests.RequestException as exc:\n            # Catch all other requests exceptions and return the error.\n            logger.exception(exc)\n            error = str(exc)\n\n        # Return response and error.\n        return response, error\n\n\nquery_runners = {}\n\n\ndef register(query_runner_class):\n    global query_runners\n    if query_runner_class.enabled():\n        logger.debug(\"Registering %s (%s) query runner.\", query_runner_class.name(), query_runner_class.type())\n        query_runners[query_runner_class.type()] = query_runner_class\n    else:\n        logger.debug(\"%s query runner enabled but not supported, not registering. Either disable or install missing \"\n                     \"dependencies.\", query_runner_class.name())\n\n\ndef get_query_runner(query_runner_type, configuration):\n    query_runner_class = query_runners.get(query_runner_type, None)\n    if query_runner_class is None:\n        return None\n\n    return query_runner_class(configuration)\n\n\ndef get_configuration_schema_for_query_runner_type(query_runner_type):\n    query_runner_class = query_runners.get(query_runner_type, None)\n    if query_runner_class is None:\n        return None\n\n    return query_runner_class.configuration_schema()\n\n\ndef import_query_runners(query_runner_imports):\n    for runner_import in query_runner_imports:\n        __import__(runner_import)\n", "path": "redash/query_runner/__init__.py"}]}