Python: How to Handle the Exception to Class variable - python

I have no idea to implement to handle the class variable exception. I am trying to create python module which has dependency with mongodb.
class HrmLookUps(DBMixin):
db_handle = DBMixin.get_db_handle(DBMixin, MONGO_STORE_DICT.get("DB_NAME"),
MONGO_STORE_DICT.get("DB_HOST"),
MONGO_STORE_DICT.get("DB_PORT"),
MONGO_STORE_DICT.get("USERNAME"),
MONGO_STORE_DICT.get("PASSWORD"))
#classmethod
def get_gender(cls):
collection_name = COLLECTION_NAME_DICT.get("COLLECTION_GENDER")
# collection_name = "departments"
gender_record = cls.get_from_db(cls, cls.db_handle, collection_name)
if gender_record[collection_name]:
return gender_record
else:
raise KeyError("Collection Name Invalid!")
I have multiple get method like above get_gender(). I am handling each method raised Keyerror if its data empty.
My question is,
Is this proper way to handle exception of methods?
If my class variable has some issues ex.database credential wrong how can I handle that?

Currently your else clause isn't really doing anything. Your if statement would already throw an error if collection_name wasn't a key in gender_record. So unless you want to raise KeyError in the else clause when collection_name is in gender_record but its value happens to be 0 or False or None.
I think what you are trying to do is something closer to these examples:
#classmethod
def get_gender(cls):
collection_name = COLLECTION_NAME_DICT.get("COLLECTION_GENDER")
# collection_name = "departments"
gender_record = cls.get_from_db(cls, cls.db_handle, collection_name)
if collection_name in gender_record:
return gender_record
else:
raise KeyError("Collection Name Invalid!")
or this maybe
#classmethod
def get_gender(cls):
collection_name = COLLECTION_NAME_DICT.get("COLLECTION_GENDER")
# collection_name = "departments"
gender_record = cls.get_from_db(cls, cls.db_handle, collection_name)
try:
gender_record[collection_name]
return gender_record
else KeyError as err:
raise KeyError("Collection Name Invalid!") from err
Handling exceptions is pretty much the same in any situation. so for the credentials it would be something like this:
try:
db_handle = DBMixin.get_db_handle(DBMixin, MONGO_STORE_DICT.get("DB_NAME"),
MONGO_STORE_DICT.get("DB_HOST"),
MONGO_STORE_DICT.get("DB_PORT"),
MONGO_STORE_DICT.get("USERNAME"),
MONGO_STORE_DICT.get("PASSWORD"))
except <SomeCredentialErrorHere>:
# whatever you put here is what gets executed if the error is raised.

Related

SonarQube python - 'not covered by tests' for exception handling and self.fail

I have this unittest:
class GeneralFeaturesV2Test(unittest.TestCase):
def setUp(self) -> None:
self.features_v2_enum = FeatureEnumV2
def test_features_names(self):
bad_features = list()
all_features_names = list(map(lambda value: value.name, self.features_v2_enum))
for feature in all_features_names:
try:
resolve_feature_call(self.features_v2_enum[feature].value.func_name)
except Exception:
bad_features.append(feature)
if bad_features:
self.fail(f'Failed resolving these features: {bad_features}')
For some weird reason sonarqube says that the exception handling and what's inside it and the line of self.fail are not being covered by tests.
And this is the function that I want to test:
def resolve_feature_call(feature_name):
for imp in FEATURES_IMPORT_FILES:
try:
call = getattr(imp, feature_name)
if feature_name is None:
continue
return call
except Exception:
continue
_logger.error("Can't import feature {}".format(feature_name))
raise ValueError("Can't import feature {}".format(feature_name))
What can I do so that it does cover it?
BTW I tried to make it look better like this, but it still failed:
class GeneralFeaturesV2Test(unittest.TestCase):
def setUp(self) -> None:
self.features_v2_enum = FeatureEnumV2
def test_features_names(self):
all_features_names = list(map(lambda value: value.name, self.features_v2_enum))
with self.subTest():
for feature in all_features_names:
try:
resolve_feature_call(self.features_v2_enum[feature].value.func_name)
except Exception:
self.fail(f'Failed resolving the feature: {feature}')

How show val er

Need some help with the if statements and Vaidation errors.
Right now I have this function:
def validate(self, validated_data):
if self.partial:
validated_data = self.fill_data(self.instance, validated_data)
if not validated_data['brand'].sunny_account.first():
raise ValidationError('This brand not Sunny')
validated_data['calculate'] = Account.NEW
return validated_data
Need to add another if statement:
if not validated_data['brand'].moon_account.first():
raise ValidationError('This brand not Moon')
If I add another if not statement in this function it's not going to the second one if not and raising the first Validation error.
I would like that this function checking all if's and raising Validation error for the each case.
From what I understand, you want both the Moon and Sunny errors to be raised. However, this cannot happen: if the first is raised, then the second will never be reached. If the first is not raised, only then can the second be raised. But both can't be raised at the same time.
One solution, do it in a loop:
def validate(self, validated_data):
if self.partial:
validated_data = self.fill_data(self.instance, validated_data)
validations = [
(
validated_data['brand'].sunny_account.first(),
'This brand does not have Sunny enabled'
),
(
validated_data['brand'].moon_account.first(),
'This brand does not have Moon enabled'
),
]
# Validate
err_msg = ""
for cond, msg in validations:
if not cond:
# Has error, add the error message
err_msg = err_msg + msg
if err_msg:
# Error message is not empty --> there is an error
raise ValidationError(err_msg)
validated_data['calculate'] = Account.NEW
return validated_data
It is unusual to want to do this, and handling your exceptions elsewhere might be tricky, but you could raise an Exception of Exceptions something like this:
def my_test(thing):
errors = []
if thing != 1:
errors.append(ValidationError('thing 1'))
if thing != 2:
errors.append(ValidationError('thing 2'))
if errors:
Raise(ValidationError(errors))
You can't raise two exceptions at once, but you can define your own Exception subclass that incorporates arbitrary data. For example, you could store a list of multiple error messages:
class ValidationError(Exception):
def __init__(self):
super().__init__()
self._why: list[str] = []
def __bool__(self) -> bool:
return bool(self._why)
def __str__(self) -> str:
return "\n".join(self._why)
def add(self, why: str) -> None:
self._why.append(why)
and then accumulate multiple messages before deciding to raise:
err = ValidationError()
if not validated_data['brand'].sunny_account.first():
err.add('This brand does not have Sunny enabled')
if not validated_data['brand'].moon_account.first():
err.add('This brand does not have Moon enabled')
if err:
raise err

Return value on try except

I'm writing a challenge in Python and I would like to know what is the right approach to return None case my function throws an Exception.
def get(email):
try:
customer = get_customer(email)
return customer
except TypeError as e:
logging.error(f'Customer {email} not found', e)
Should I do something like customer = None and return customer after except block?

Checking to see if multiple ENV variables exist

Is there a more optimal way I can check to see if multiple ENV variables exist with customized exceptions? Perhaps a way to match a group of EVN variables, and then have the exception self-reference the variable name in its output?
if os.environ.get('USERNAME') is not None:
self.username = os.environ.get('USERNAME')
else:
raise CustomException('Environment variable USERNAME not set')
if os.environ.get('PASSWORD') is not None:
self.password = os.environ.get('PASSWORD')
else:
raise CustomException('Environment variable PASSWORD not set')
I am using Python 2.7. Thanks!
You can do something like this:
#
# ENV vars you want to go over
#
env_vars = 'HOME,PATH,NONEXISTS'.split(',')
for evar in env_vars:
# Loop will create it as: self.$evar = os.environ.get(evar)
if evar not in os.environ:
# Will skip: NONEXISTS
continue
# or if you want to raise exception
raise ValueError('Environment variable "%s" was not set' % evar)
# setattr: will create a dynamic attribute for "self"
# self.home = ...
# self.path = ...
# evar.lower() => so we'll have self.home vs self.HOME
setattr(self, evar.lower(), os.environ.get(evar))
In general, just note that you don't need to verify if it's "None" in Python, so
# Replace this
if os.environ.get('USERNAME') is not None:
# With this, the default of get => is None, and None won't pass "if"
if os.environ.get('USERNAME'):
# Will create an exception if USERNAME doesn't exists
if os.environ['USERNAME']
Hope it helps ...
You could always use a loop with a three items list:
for data in [
["USERNAME", "username", CustomException],
["PASSWORD", "password", CustomException]
]:
env_var = os.environ.get(data[0])
if env_var:
setattr(self, data[1], env_var)
else:
# Should work, cannot check due to not having actually Python installed.
raise data[2]("Environment variable %s not set" % data[0])
If you don't like using indexes, you could replace the items by dicts like this to have a more consistent access if you change order:
{"env_var_name": "USERNAME", "attr": "username", "exception_cls": CustomException}
Just put all the environment lookups in a try: block:
try:
self.username= os.environ['USERNAME']
self.password= os.environ['PASSWORD']
except KeyError as e:
raise CustomException('Environment variable {} not set'.format(e.args[0]))

Check if object path exists in tree of objects

I have a tree of objects and I need to check that particular object contains specific branch of objects. For example:
def specificNodeHasTitle(specificNode):
# something like this
return specificNode.parent.parent.parent.header.title != None
Is there an elegant way to do this without throwing exception if needed attribute is missing?
This works as long as you don't need indexes of arrays in your path to the item.
def getIn(d, arraypath, default=None):
if not d:
return d
if not arraypath:
return d
else:
return getIn(d.get(arraypath[0]), arraypath[1:], default) \
if d.get(arraypath[0]) else default
getIn(specificNode,["parent", "parent", "parent", "header", "title"]) is not None
Use try..except:
def specificNodeHasTitle(specificNode):
try:
return specificNode.parent.parent.parent.header.title is not None
except AttributeError:
# handle exception, for example
return False
There is nothing wrong with raising exceptions, by the way. It is a normal part of Python programming. Using try..except is the way to handle them.
For your specific case, the solution provided by unutbu is the best and the most pythonic, but I can't help trying to show the great capabilities of python and its getattr method:
#!/usr/bin/env python
# https://stackoverflow.com/questions/22864932/python-check-if-object-path-exists-in-tree-of-objects
class A(object):
pass
class Header(object):
def __init__(self):
self.title = "Hello"
specificNode=A()
specificNode.parent = A()
specificNode.parent.parent = A()
specificNode.parent.parent.parent = A()
specificNode.parent.parent.parent.header = Header()
hierarchy1="parent.parent.parent.header.title"
hierarchy2="parent.parent.parent.parent.header.title"
tmp = specificNode
for attr in hierarchy1.split('.'):
try:
tmp = getattr(tmp, attr)
except AttributeError:
print "Ouch... nopes"
break
else:
print "Yeeeps. %s" % tmp
tmp = specificNode
for attr in hierarchy2.split('.'):
try:
tmp = getattr(tmp, attr)
except AttributeError:
print "Ouch... nopes"
break
else:
print "Yeeeps. %s" % tmp
That outputs:
Yeeeps. Hello
Ouch... nopes
Python's great :)

Categories