From f0422dd214f879760e93fa006b348917b273305d Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 10 Jan 2018 14:39:57 -0800 Subject: [PATCH 01/12] add additional error messages around invalid inputs to feature APIs --- optimizely/helpers/enums.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index b86a3164..7e9d5e19 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -29,16 +29,21 @@ class LogLevels(object): class Errors(object): - INVALID_INPUT_ERROR = 'Provided "{}" is in an invalid format.' INVALID_ATTRIBUTE_ERROR = 'Provided attribute is not in datafile.' INVALID_ATTRIBUTE_FORMAT = 'Attributes provided are in an invalid format.' - INVALID_EVENT_TAG_FORMAT = 'Event tags provided are in an invalid format.' INVALID_AUDIENCE_ERROR = 'Provided audience is not in datafile.' + INVALID_DATAFILE = 'Datafile has invalid format. Failing "{}".' + INVALID_EVENT_TAG_FORMAT = 'Event tags provided are in an invalid format.' INVALID_EXPERIMENT_KEY_ERROR = 'Provided experiment is not in datafile.' INVALID_EVENT_KEY_ERROR = 'Provided event is not in datafile.' - INVALID_DATAFILE = 'Datafile has invalid format. Failing "{}".' + INVALID_FEATURE_KEY_ERROR = 'Provided feature key parameter is not in the datafile.' INVALID_GROUP_ID_ERROR = 'Provided group is not in datafile.' + INVALID_INPUT_ERROR = 'Provided "{}" is in an invalid format.' INVALID_VARIATION_ERROR = 'Provided variation is not in datafile.' + INVALID_VARIABLE_KEY_ERROR = 'Provided variable key parameter is not in the feature flag.' + NONE_FEATURE_KEY_PARAMETER = 'Provided feature key parameter is `None`.' + NONE_USER_ID_PARAMETER = 'Provided user ID parameter is `None`.' + NONE_VARIABLE_KEY_PARAMETER = 'Provided variable key parameter is `None`.' UNSUPPORTED_DATAFILE_VERSION = 'Provided datafile has unsupported version. ' \ 'Please use SDK version 1.1.0 or earlier for datafile version 1.' From 9c48cdda50b9f91d4bb8b9399ea19df19add77fd Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 10 Jan 2018 14:41:28 -0800 Subject: [PATCH 02/12] add parameter validation to isFeatureEnabled --- optimizely/optimizely.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/optimizely/optimizely.py b/optimizely/optimizely.py index e0b5310e..17443da3 100644 --- a/optimizely/optimizely.py +++ b/optimizely/optimizely.py @@ -375,8 +375,17 @@ def is_feature_enabled(self, feature_key, user_id, attributes=None): self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_DATAFILE.format('is_feature_enabled')) return False + if not feature_key: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) + return False + + if not user_id: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) + return False + feature = self.config.get_feature_from_key(feature_key) if not feature: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_FEATURE_KEY_ERROR) return False decision = self.decision_service.get_variation_for_feature(feature, user_id, attributes) From c984a2e18bee7c43c512b42252169613028f37fb Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 10 Jan 2018 14:44:50 -0800 Subject: [PATCH 03/12] add parameter validation and logs to getFeatureVariable --- optimizely/optimizely.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/optimizely/optimizely.py b/optimizely/optimizely.py index 17443da3..815477f3 100644 --- a/optimizely/optimizely.py +++ b/optimizely/optimizely.py @@ -198,13 +198,25 @@ def _get_feature_variable_for_type(self, feature_key, variable_key, variable_typ - Variable key is invalid. - Mismatch with type of variable. """ + if not feature_key: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) + return None + + if not variable_key: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) + return None + + if not user_id: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) feature_flag = self.config.get_feature_from_key(feature_key) if not feature_flag: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_FEATURE_KEY_ERROR) return None variable = self.config.get_variable_for_feature(feature_key, variable_key) if not variable: + self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_VARIABLE_KEY_ERROR) return None # Return None if type differs From 86983e0de846055e982dc6e9b6b71d984b4c1655 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 10 Jan 2018 16:29:05 -0800 Subject: [PATCH 04/12] return None if user ID is None --- optimizely/optimizely.py | 1 + 1 file changed, 1 insertion(+) diff --git a/optimizely/optimizely.py b/optimizely/optimizely.py index 815477f3..1bcbef6e 100644 --- a/optimizely/optimizely.py +++ b/optimizely/optimizely.py @@ -208,6 +208,7 @@ def _get_feature_variable_for_type(self, feature_key, variable_key, variable_typ if not user_id: self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) + return None feature_flag = self.config.get_feature_from_key(feature_key) if not feature_flag: From 7656fc7607f204a52f31e20c3ac08792c978e4b4 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 10 Jan 2018 16:42:50 -0800 Subject: [PATCH 05/12] remove duplicate logs --- optimizely/optimizely.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/optimizely/optimizely.py b/optimizely/optimizely.py index 1bcbef6e..f4e38c52 100644 --- a/optimizely/optimizely.py +++ b/optimizely/optimizely.py @@ -212,12 +212,10 @@ def _get_feature_variable_for_type(self, feature_key, variable_key, variable_typ feature_flag = self.config.get_feature_from_key(feature_key) if not feature_flag: - self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_FEATURE_KEY_ERROR) return None variable = self.config.get_variable_for_feature(feature_key, variable_key) if not variable: - self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_VARIABLE_KEY_ERROR) return None # Return None if type differs @@ -398,7 +396,6 @@ def is_feature_enabled(self, feature_key, user_id, attributes=None): feature = self.config.get_feature_from_key(feature_key) if not feature: - self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_FEATURE_KEY_ERROR) return False decision = self.decision_service.get_variation_for_feature(feature, user_id, attributes) From fa2bcfe913157606dbbd0849c73e22e1c248c865 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 10 Jan 2018 18:33:55 -0800 Subject: [PATCH 06/12] add null parameter tests for get_feature_variable_* --- tests/test_optimizely.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/test_optimizely.py b/tests/test_optimizely.py index de6769e7..626e4a6f 100644 --- a/tests/test_optimizely.py +++ b/tests/test_optimizely.py @@ -1449,6 +1449,45 @@ def test_get_feature_variable__returns_default_value(self): 'Returning default value for variable "environment" of feature flag "test_feature_in_experiment".' ) + def test_get_feature_variable__returns_none_if_none_feature_key(self): + """ Test that get_feature_variable_* returns None for None feature key. """ + + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: + self.assertIsNone(opt_obj.get_feature_variable_boolean(None, 'variable_key', 'test_user')) + self.assertIsNone(opt_obj.get_feature_variable_double(None, 'variable_key', 'test_user')) + self.assertIsNone(opt_obj.get_feature_variable_integer(None, 'variable_key', 'test_user')) + self.assertIsNone(opt_obj.get_feature_variable_string(None, 'variable_key', 'test_user')) + + self.assertEqual(4, mock_logger.call_count) + mock_logger.assert_called_with(40, enums.Errors.NONE_FEATURE_KEY_PARAMETER) + + def test_get_feature_variable__returns_none_if_none_variable_key(self): + """ Test that get_feature_variable_* returns None for None variable key. """ + + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: + self.assertIsNone(opt_obj.get_feature_variable_boolean('feature_key', None, 'test_user')) + self.assertIsNone(opt_obj.get_feature_variable_double('feature_key', None, 'test_user')) + self.assertIsNone(opt_obj.get_feature_variable_integer('feature_key', None, 'test_user')) + self.assertIsNone(opt_obj.get_feature_variable_string('feature_key', None, 'test-User')) + + self.assertEqual(4, mock_logger.call_count) + mock_logger.assert_called_with(40, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) + + def test_get_feature_variable__returns_none_if_none_user_id(self): + """ Test that get_feature_variable_* returns None for None user ID. """ + + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: + self.assertIsNone(opt_obj.get_feature_variable_boolean('feature_key', 'variable_key', None)) + self.assertIsNone(opt_obj.get_feature_variable_double('feature_key', 'variable_key', None)) + self.assertIsNone(opt_obj.get_feature_variable_integer('feature_key', 'variable_key', None)) + self.assertIsNone(opt_obj.get_feature_variable_string('feature_key', 'variable_key', None)) + + self.assertEqual(4, mock_logger.call_count) + mock_logger.assert_called_with(40, enums.Errors.NONE_USER_ID_PARAMETER) + def test_get_feature_variable__returns_none_if_invalid_feature_key(self): """ Test that get_feature_variable_* returns None for invalid feature key. """ From e095395efeb5ed11de6912a213c19112b259fb06 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 10 Jan 2018 18:38:34 -0800 Subject: [PATCH 07/12] add null parameter tests for is_feature_enabled --- tests/test_optimizely.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_optimizely.py b/tests/test_optimizely.py index 626e4a6f..ae6f15d3 100644 --- a/tests/test_optimizely.py +++ b/tests/test_optimizely.py @@ -1173,6 +1173,28 @@ def test_get_variation__invalid_object(self): mock_logging.assert_called_once_with(enums.LogLevels.ERROR, 'Datafile has invalid format. Failing "get_variation".') + def test_is_feature_enabled__returns_false_for_none_feature_key(self): + """ Test that is_feature_enabled returns false if the provided feature key is None. """ + + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + + with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: + self.assertFalse(opt_obj.is_feature_enabled(None, 'test_user')) + + self.assertEqual(1, mock_logger.call_count) + mock_logger.assert_called_with(40, enums.Errors.NONE_FEATURE_KEY_PARAMETER) + + def test_is_feature_enabled__returns_false_for_none_user_id(self): + """ Test that is_feature_enabled returns false if the provided user ID is None. """ + + opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) + + with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: + self.assertFalse(opt_obj.is_feature_enabled('feature_key', None)) + + self.assertEqual(1, mock_logger.call_count) + mock_logger.assert_called_with(40, enums.Errors.NONE_USER_ID_PARAMETER) + def test_is_feature_enabled__returns_false_for_invalid_feature(self): """ Test that the feature is not enabled for the user if the provided feature key is invalid. """ From 53562bcb30340333dfca3bdaff1d10ecc8e69e0d Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 17 Jan 2018 13:53:27 -0800 Subject: [PATCH 08/12] fix feature enabled logger checks --- tests/test_optimizely.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_optimizely.py b/tests/test_optimizely.py index ae6f15d3..1b69baa1 100644 --- a/tests/test_optimizely.py +++ b/tests/test_optimizely.py @@ -1181,8 +1181,7 @@ def test_is_feature_enabled__returns_false_for_none_feature_key(self): with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: self.assertFalse(opt_obj.is_feature_enabled(None, 'test_user')) - self.assertEqual(1, mock_logger.call_count) - mock_logger.assert_called_with(40, enums.Errors.NONE_FEATURE_KEY_PARAMETER) + mock_logger.assert_called_once_with(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) def test_is_feature_enabled__returns_false_for_none_user_id(self): """ Test that is_feature_enabled returns false if the provided user ID is None. """ @@ -1192,8 +1191,7 @@ def test_is_feature_enabled__returns_false_for_none_user_id(self): with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: self.assertFalse(opt_obj.is_feature_enabled('feature_key', None)) - self.assertEqual(1, mock_logger.call_count) - mock_logger.assert_called_with(40, enums.Errors.NONE_USER_ID_PARAMETER) + mock_logger.assert_called_once_with(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) def test_is_feature_enabled__returns_false_for_invalid_feature(self): """ Test that the feature is not enabled for the user if the provided feature key is invalid. """ From 77d9bf37261f82492596eea245ae3dd61d5a9d9d Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Wed, 17 Jan 2018 13:58:20 -0800 Subject: [PATCH 09/12] check each feature variable API log after the method is called --- tests/test_optimizely.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/test_optimizely.py b/tests/test_optimizely.py index 1b69baa1..42d8c51a 100644 --- a/tests/test_optimizely.py +++ b/tests/test_optimizely.py @@ -1475,12 +1475,15 @@ def test_get_feature_variable__returns_none_if_none_feature_key(self): opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: self.assertIsNone(opt_obj.get_feature_variable_boolean(None, 'variable_key', 'test_user')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_double(None, 'variable_key', 'test_user')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_integer(None, 'variable_key', 'test_user')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_string(None, 'variable_key', 'test_user')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) self.assertEqual(4, mock_logger.call_count) - mock_logger.assert_called_with(40, enums.Errors.NONE_FEATURE_KEY_PARAMETER) def test_get_feature_variable__returns_none_if_none_variable_key(self): """ Test that get_feature_variable_* returns None for None variable key. """ @@ -1488,12 +1491,15 @@ def test_get_feature_variable__returns_none_if_none_variable_key(self): opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: self.assertIsNone(opt_obj.get_feature_variable_boolean('feature_key', None, 'test_user')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_double('feature_key', None, 'test_user')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_integer('feature_key', None, 'test_user')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_string('feature_key', None, 'test-User')) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) self.assertEqual(4, mock_logger.call_count) - mock_logger.assert_called_with(40, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) def test_get_feature_variable__returns_none_if_none_user_id(self): """ Test that get_feature_variable_* returns None for None user ID. """ @@ -1501,12 +1507,15 @@ def test_get_feature_variable__returns_none_if_none_user_id(self): opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features)) with mock.patch('optimizely.logger.NoOpLogger.log') as mock_logger: self.assertIsNone(opt_obj.get_feature_variable_boolean('feature_key', 'variable_key', None)) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_double('feature_key', 'variable_key', None)) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_integer('feature_key', 'variable_key', None)) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) self.assertIsNone(opt_obj.get_feature_variable_string('feature_key', 'variable_key', None)) + mock_logger.assert_called_with(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) self.assertEqual(4, mock_logger.call_count) - mock_logger.assert_called_with(40, enums.Errors.NONE_USER_ID_PARAMETER) def test_get_feature_variable__returns_none_if_invalid_feature_key(self): """ Test that get_feature_variable_* returns None for invalid feature key. """ From 5a84bb92cd3cc9a8e163d9d85f0064db9c3c9c97 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Thu, 18 Jan 2018 13:23:26 -0800 Subject: [PATCH 10/12] use double quotes for None --- optimizely/helpers/enums.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index 7e9d5e19..c3538294 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -41,9 +41,9 @@ class Errors(object): INVALID_INPUT_ERROR = 'Provided "{}" is in an invalid format.' INVALID_VARIATION_ERROR = 'Provided variation is not in datafile.' INVALID_VARIABLE_KEY_ERROR = 'Provided variable key parameter is not in the feature flag.' - NONE_FEATURE_KEY_PARAMETER = 'Provided feature key parameter is `None`.' - NONE_USER_ID_PARAMETER = 'Provided user ID parameter is `None`.' - NONE_VARIABLE_KEY_PARAMETER = 'Provided variable key parameter is `None`.' + NONE_FEATURE_KEY_PARAMETER = '"None" is an invalid value for feature key.' + NONE_USER_ID_PARAMETER = '"None" is an invalid value for user ID.' + NONE_VARIABLE_KEY_PARAMETER = '"None" is an invalid value for variable key.' UNSUPPORTED_DATAFILE_VERSION = 'Provided datafile has unsupported version. ' \ 'Please use SDK version 1.1.0 or earlier for datafile version 1.' From c19c18eea9a9cf36e4c21cf53ea3cdd6478a0f4b Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Thu, 18 Jan 2018 13:24:36 -0800 Subject: [PATCH 11/12] remove extraneous parameter in logs --- optimizely/helpers/enums.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/optimizely/helpers/enums.py b/optimizely/helpers/enums.py index c3538294..ad09b008 100644 --- a/optimizely/helpers/enums.py +++ b/optimizely/helpers/enums.py @@ -36,11 +36,11 @@ class Errors(object): INVALID_EVENT_TAG_FORMAT = 'Event tags provided are in an invalid format.' INVALID_EXPERIMENT_KEY_ERROR = 'Provided experiment is not in datafile.' INVALID_EVENT_KEY_ERROR = 'Provided event is not in datafile.' - INVALID_FEATURE_KEY_ERROR = 'Provided feature key parameter is not in the datafile.' + INVALID_FEATURE_KEY_ERROR = 'Provided feature key is not in the datafile.' INVALID_GROUP_ID_ERROR = 'Provided group is not in datafile.' INVALID_INPUT_ERROR = 'Provided "{}" is in an invalid format.' INVALID_VARIATION_ERROR = 'Provided variation is not in datafile.' - INVALID_VARIABLE_KEY_ERROR = 'Provided variable key parameter is not in the feature flag.' + INVALID_VARIABLE_KEY_ERROR = 'Provided variable key is not in the feature flag.' NONE_FEATURE_KEY_PARAMETER = '"None" is an invalid value for feature key.' NONE_USER_ID_PARAMETER = '"None" is an invalid value for user ID.' NONE_VARIABLE_KEY_PARAMETER = '"None" is an invalid value for variable key.' From ef0c0ee10759093ca87dea40f8881e45bf265595 Mon Sep 17 00:00:00 2001 From: wangjoshuah Date: Thu, 18 Jan 2018 13:26:11 -0800 Subject: [PATCH 12/12] explicitly check for None --- optimizely/optimizely.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/optimizely/optimizely.py b/optimizely/optimizely.py index f4e38c52..a1dac636 100644 --- a/optimizely/optimizely.py +++ b/optimizely/optimizely.py @@ -198,15 +198,15 @@ def _get_feature_variable_for_type(self, feature_key, variable_key, variable_typ - Variable key is invalid. - Mismatch with type of variable. """ - if not feature_key: + if feature_key is None: self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) return None - if not variable_key: + if variable_key is None: self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_VARIABLE_KEY_PARAMETER) return None - if not user_id: + if user_id is None: self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) return None @@ -386,11 +386,11 @@ def is_feature_enabled(self, feature_key, user_id, attributes=None): self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_DATAFILE.format('is_feature_enabled')) return False - if not feature_key: + if feature_key is None: self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_FEATURE_KEY_PARAMETER) return False - if not user_id: + if user_id is None: self.logger.log(enums.LogLevels.ERROR, enums.Errors.NONE_USER_ID_PARAMETER) return False