Skip to content

Commit

Permalink
Refactor config parsing to allow custom parsers. (#412)
Browse files Browse the repository at this point in the history
* Refactor config parsing to allow custom parsers.

* Fix pep8

* Update version and changelog.

* Changed default for tabpy_auth_info to a boolean.
  • Loading branch information
lriggs committed Apr 15, 2020
1 parent e18e31e commit 870f265
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 32 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v1.1.0

### Improvements

- Added ability to require authorization for the /info API method.
This is set with TABPY_AUTH_INFO.
- Improved config parsing flexibility. Previously the
TABPY_EVALUATE_TIMEOUT setting would be set to a default if
tabpy couldn't parse the value. Now it will throw an exception
at startup.

## v1.0.0

### Improvements
Expand Down
2 changes: 1 addition & 1 deletion tabpy/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.0
1.1.0
49 changes: 21 additions & 28 deletions tabpy/tabpy_server/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,17 @@ def try_exit(self):

return application

def _set_parameter(self, parser, settings_key, config_key, default_val):
def _set_parameter(self, parser, settings_key, config_key, default_val, parse_function):
key_is_set = False

if (
config_key is not None
and parser.has_section("TabPy")
and parser.has_option("TabPy", config_key)
):
self.settings[settings_key] = parser.get("TabPy", config_key)
if parse_function is None:
parse_function = parser.get
self.settings[settings_key] = parse_function("TabPy", config_key)
key_is_set = True
logger.debug(
f"Parameter {settings_key} set to "
Expand Down Expand Up @@ -252,41 +254,32 @@ def _parse_config(self, config_file):
)

settings_parameters = [
(SettingsParameters.Port, ConfigParameters.TABPY_PORT, 9004),
(SettingsParameters.ServerVersion, None, __version__),
(SettingsParameters.EvaluateTimeout, ConfigParameters.TABPY_EVALUATE_TIMEOUT, 30),
(SettingsParameters.Port, ConfigParameters.TABPY_PORT, 9004, None),
(SettingsParameters.ServerVersion, None, __version__, None),
(SettingsParameters.EvaluateTimeout, ConfigParameters.TABPY_EVALUATE_TIMEOUT,
30, parser.getfloat),
(SettingsParameters.UploadDir, ConfigParameters.TABPY_QUERY_OBJECT_PATH,
os.path.join(pkg_path, "tmp", "query_objects")),
os.path.join(pkg_path, "tmp", "query_objects"), None),
(SettingsParameters.TransferProtocol, ConfigParameters.TABPY_TRANSFER_PROTOCOL,
"http"),
"http", None),
(SettingsParameters.CertificateFile, ConfigParameters.TABPY_CERTIFICATE_FILE,
None),
(SettingsParameters.KeyFile, ConfigParameters.TABPY_KEY_FILE, None),
None, None),
(SettingsParameters.KeyFile, ConfigParameters.TABPY_KEY_FILE, None, None),
(SettingsParameters.StateFilePath, ConfigParameters.TABPY_STATE_PATH,
os.path.join(pkg_path, "tabpy_server")),
os.path.join(pkg_path, "tabpy_server"), None),
(SettingsParameters.StaticPath, ConfigParameters.TABPY_STATIC_PATH,
os.path.join(pkg_path, "tabpy_server", "static")),
(ConfigParameters.TABPY_PWD_FILE, ConfigParameters.TABPY_PWD_FILE, None),
os.path.join(pkg_path, "tabpy_server", "static"), None),
(ConfigParameters.TABPY_PWD_FILE, ConfigParameters.TABPY_PWD_FILE, None, None),
(SettingsParameters.LogRequestContext, ConfigParameters.TABPY_LOG_DETAILS,
"false"),
"false", None),
(SettingsParameters.MaxRequestSizeInMb, ConfigParameters.TABPY_MAX_REQUEST_SIZE_MB,
100),
(SettingsParameters.AuthInfo, ConfigParameters.TABPY_AUTH_INFO, "false"),
100, None),
(SettingsParameters.AuthInfo, ConfigParameters.TABPY_AUTH_INFO, False,
parser.getboolean),
]

for setting, parameter, default_val in settings_parameters:
self._set_parameter(parser, setting, parameter, default_val)

try:
self.settings[SettingsParameters.EvaluateTimeout] = float(
self.settings[SettingsParameters.EvaluateTimeout]
)
except ValueError:
logger.warning(
"Evaluate timeout must be a float type. Defaulting "
"to evaluate timeout of 30 seconds."
)
self.settings[SettingsParameters.EvaluateTimeout] = 30
for setting, parameter, default_val, parse_function in settings_parameters:
self._set_parameter(parser, setting, parameter, default_val, parse_function)

if not os.path.exists(self.settings[SettingsParameters.UploadDir]):
os.makedirs(self.settings[SettingsParameters.UploadDir])
Expand Down
2 changes: 1 addition & 1 deletion tabpy/tabpy_server/handlers/service_info_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def get(self):
# Some clients may wish to lock down the entire API which can be done through
# the configuration file.

if self.settings[SettingsParameters.AuthInfo] == "true":
if self.settings[SettingsParameters.AuthInfo]:
if self.should_fail_with_not_authorized():
self.fail_with_not_authorized()
return
Expand Down
46 changes: 44 additions & 2 deletions tests/unit/server_tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,48 @@ def test_config_file_present(
self.assertEqual(app.settings["log_request_context"], False)
self.assertEqual(app.settings["evaluate_timeout"], 30)

@patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
@patch("tabpy.tabpy_server.app.app._get_state_from_file")
@patch("tabpy.tabpy_server.app.app.TabPyState")
def test_info_auth_valid(
self, mock_state, mock_get_state_from_file, mock_path_exists
):
self.assertTrue(self.config_file is not None)
config_file = self.config_file
config_file.write("[TabPy]\n" "TABPY_AUTH_INFO = True".encode())
config_file.close()

app = TabPyApp(self.config_file.name)
self.assertEqual(app.settings["auth_info"], True)

@patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
@patch("tabpy.tabpy_server.app.app._get_state_from_file")
@patch("tabpy.tabpy_server.app.app.TabPyState")
def test_info_auth_camelcase_valid(
self, mock_state, mock_get_state_from_file, mock_path_exists
):
self.assertTrue(self.config_file is not None)
config_file = self.config_file
config_file.write("[TabPy]\n" "TABPY_AUTH_INFO = trUE".encode())
config_file.close()

app = TabPyApp(self.config_file.name)
self.assertEqual(app.settings["auth_info"], True)

@patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
@patch("tabpy.tabpy_server.app.app._get_state_from_file")
@patch("tabpy.tabpy_server.app.app.TabPyState")
def test_info_auth_false_valid(
self, mock_state, mock_get_state_from_file, mock_path_exists
):
self.assertTrue(self.config_file is not None)
config_file = self.config_file
config_file.write("[TabPy]\n" "TABPY_AUTH_INFO = no".encode())
config_file.close()

app = TabPyApp(self.config_file.name)
self.assertEqual(app.settings["auth_info"], False)

@patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
@patch("tabpy.tabpy_server.app.app._get_state_from_file")
@patch("tabpy.tabpy_server.app.app.TabPyState")
Expand Down Expand Up @@ -143,8 +185,8 @@ def test_custom_evaluate_timeout_invalid(
)
config_file.close()

app = TabPyApp(self.config_file.name)
self.assertEqual(app.settings["evaluate_timeout"], 30.0)
with self.assertRaises(ValueError) as err:
TabPyApp(self.config_file.name)

@patch("tabpy.tabpy_server.app.app.os")
@patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
Expand Down

0 comments on commit 870f265

Please sign in to comment.