Is the context manager only for raising exceptions? [closed] - python

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
Is it good or bad practice to use context manager in python only for validating some data and handling exceptions to make code cleaner?
This is what I mean:
#contextmanager
def validate_data(a, b):
if a != b:
raise ValidationError("Wrong values")
if a ==- 1:
raise ValidationError("You can't use -1")
if a ==- 2:
raise ValidationError("You can't use -2")
# etc validations
yield
if __name__ == '__main__':
a = 1
b = 2
with validate_data(a, b):
print(a + b)
The problem is almost all information what I found about context managers in Python is about handling connections or reading files operations.
Can I use context managers to simple operations like this one?
As for me it looks like a good example of separating responsibilities, validation is separated from function body and you can concentrate on what function does, not reading all those lines of validation.

In this case, a function that simply returns True (for valid data) or False (for invalid data) and an if statement would be clearer.
def is_valid_data(a, b):
if a != b:
return False
...
return True
if is_valid_data(a, b):
print(a + b)
Context managers are primarily useful for ensuring that something gets run after the body of the with statement, whether or not any exceptions are raised during the execution of that body. It was intended as a simpler replacement for a pattern like
# 1) Initialize some stuff
try:
# 2) Do something with the stuff
finally:
# 3) Do stuff whether or not the above
A context manager encapsulates steps 1 and 3:
with context_manager as cm:
# Do something
The with statement ensures that cm.__enter__ is run before the body, and ensures that cm.__exit__ is run, even if an exception would prevent the entire body of the with statement (or anything after it) from running.

Related

Best Practices for re-raising the same error in Python [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I have a few functions in a call stack that will re-raise the same exception up the stack in the case of an error. I am familiar with the Python idiom that a standalone raise in a try/except block will re-raise the same exception being handled, but an exception will still be raised if a call is not in a try/except block.
Assuming that the exceptions are handled higher up in the call stack, would inbounds1() or inbounds2() be considered "better" practice, or neither?
import numpy as np
class ArrayShapeError(Exception):
...
def get_distance(points):
if points.ndim != 2 or points.shape[1] != 3:
raise ArrayShapeError("Parameter 'points' is not of shape (n, 3)")
return np.linalg.norm(points, axis=1)
# Implicit try/except
def inbounds1(points):
return get_distance(points) < 1
# Explicitly try/except and re-raise
def inbounds2(points):
try:
return get_distance(points) < 1
except ArrayShapeError:
raise
if __name__ == "__main__":
# Ok
print(inbounds1(np.random.rand(5, 3)))
print(inbounds2(np.random.rand(5, 3)))
# Raises ArrayShapeError
print(inbounds1(np.random.rand(5, 2)))
print(inbounds2(np.random.rand(5, 2)))
I would use inbounds2().
This is because re-raising the error is a good practice not only for insurance but also for readability for you and other people reading your code - it makes it clearer.
There's not a huge technical advantage as the error has already been raised.

Raise exception if condition is true in one-line? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I have a lot of assert statements I use to validate input data and state of the program. ie :
assert all((i.children is not None for i in items)), "Someone has no children."
I would like to use the same syntax but using specific Exception, ie:
if any((i.children is None for i in items)):
raise NoChildrenException("Someone has no children.")
Is there a one line syntax to achieve the same?
I tried :
if any((i.children is None for i in items)): raise NoChildrenException("Someone has no children.")
but that's not PEP8 valid.
or
def raise_if(condition, clazz, *args):
if condition:
raise(clazz(*args))
raise_if(any((i.children is None for i in items)), NoChildrenException, "Someone has no children.")
but that's a bit ugly.
UPDATE:
Thanks #Thomas. I fixed the examples in the problem description.
I think the closest to what I want to achieve is this one (based on #puchal's answer).
def raise_exc(exc):
raise exc
all((i.children is not None for i in items) or raise_exc(NoChildrenException("Someone has no children."))
I haven't thought about using or in this way.
Currently there is no way to do this that is also valid PEP8.
It doesn't get more pythonic than this:
if any(i.children is None for i in items):
raise NoChildrenException("Someone has no children.")
Note you have an error in your problem description - you have to negate the condition in your second code example. You can get rid of the two not by using any() like shown above.
There is no way to do it ellegantly.
I think the closest way to achieve it would be:
def raise_exc(clazz, msg=""):
raise clazz(msg)
all((i.children is not None for i in items)) or raise_exc(NoChildrenException, 'message')
The "correct" way to do this is without assert at all.
if any(i.children is None for i in items):
raise ValueError("Someone has no children") # Or whatever exception you feel is appropriate
In Python 3.8, you can capture which item had no children in the same line.
if any((childless:=i).children is None for i in items):
raise ValueError("%r is childless" % (childless,))
(The assignment expression operator := creates a variable in the scope where the generator expression is defined, not one local to the generator expression itself.)
Your second snippet is the most pythonic IMHO.
When I have to add a lot of validation rules I usually do something like this:
checks = {
lambda items: any(i.children is None for i in items): NoChildrenException("Someone has no children."),
lambda items: any(i.children.age >= 18 for i in items): AdultChildrenException("Someone has an adult children."),
lambda items: not bool(items): NoItemsException("No items given."),
}
for condition, exc in checks.items():
if condition(items):
raise exc
Moving all the checks (eventually having bigger functions instead of lambdas) in a separate .py file "validations.py".

Python type convertion based on string [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
How can I write this code so it works for every type given?
def set_val_type(val, val_type):
if val_type == 'bool':
return bool(val)
elif val_type == 'int':
return int(val)
You can do something like:
def set_val_type(val, val_type):
return eval(val_type + '({})'.format(val))
As much as this seems to be what you are looking for, using eval is not recommended. It seems like an XY problem as commented before by #pault
You can create a dictionary of all the types you need to process.
def set_val_type(val, val_type):
funcs = {'int': int, 'bool': bool}
return funcs[val_type](val)
To avoid using eval, and presuming you are only using builtin types, you can use a getattr() on the builtins module (if you want to make sure you don't call any functions, you can perform an isinstance(user_provided_type_here, type) before.
To allow any type in global scope, use globals()[user_provided_type_name]
Complete example:
import builtins
def set_val_type(val, val_type);
user_type = getattr(builtins, val_type) # possibly replace with globals()[val_type]
if not isinstance(user_type, type):
raise TypeError(f'{user_type} is no a type.')
return user_type(val)
Why not to use eval() (with untrusted user input):
def set_val_type(val, val_type):
return eval(val_type + '({})'.format(val))
evil_val_type = 'bool'
evil_val = 'exec("import os\\nos.chdir(os.path.sep)\\nprint(os.getcwd())")'
print(set_val_type(evil_val, evil_val_name))
'False' # yes, this actually works error-free
With this level of access, one is just a subprocess.Popen / os.system from very bad news.
That said, if your user input is trusted, using eval() is not less problematic.

Python: Throw Exception or return None? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I want to get your feedback on which of the two snippets is the more pythonic way to handle a lookup.
I'm developing a wrapper for an XML File. I'm loading the XML file, parsing it, store the content in a dictionary and then allow the access through a class method.
Specifically - if the a given returns no result, should I return None or raise an (Key)Error?
I'm a bit confused, because some people suggested me to throw an Error instead of returning an empty value. They said it would be easier and clearer to handle then the error no a higher level.
This is a simplified version of the code:
class NoResult(KeyError):
pass
class Wrapper(object):
....
self.my_dict = {}
....
get_Entity(self, id):
if id in self.my_dict:
value = self.my_dict[id]
return value
else:
return None
class Wrapper(object):
....
self.my_dict = {}
....
get_Entity(self, id):
if id in self.my_dict:
value = self.my_dict[id]
return value
else:
throw NoResult
I would really appreciate your thoughts!
The latter matches what you would expect with standard Python types, and can be simplified to:
def get_Entity(self, id):
return self.my_dict[id]
This will raise the KeyError for you if id isn't in self.my_dict. Getting an error tells the calling function that what was expected to be in the dictionary wasn't - quietly returning None leaves you open to subtle bugs later (unless you immediately check if val is None, in which case you could have used try anyway).
(The other version can also be simplified, to:
def get_Entity(self, id):
return self.my_dict.get(id)
).
dict already contains the 2 behaviors. (get -> None and [] -> KeyError).
Also, None is a valid value for a dict:
my_dict = {'key': None}
my_dict['key']
# Returns None
Ok, this will be a little bit generic but looks at the expectations of the programmer using your library. If I am doing a lookup in an XML file I am probably expecting that I will get a result.
Lets say I am then a lazy programmer who does no validation of what you return to me and try and use it. If you return to me a special none value my code will continue to run and will encounter an error later and it may not be obvious to me that that is the root cause.
On the other hand if you threw an exception as soon as I requested the invalid value my program would crash immediately and give me an accurate explanation of what went wrong.
If programmers all did careful validation on what your library returns either way will work fine but lazier (read most :P) programmers will likely not do so, thus the exception route will provide the least surprise and confusion. As a library you never want to surprise or confuse your user when avoidable so I would go for the exception route.
However I shall quickly note, if doing an invalid lookup is a 'normal' action in your libraries work-flow you can more reasonably expect programmers to check so then either becomes reasonable.
Remember the rule of thumb, use an exception when the action is actually exceptional and surprising, otherwise ymmv but you probably dont have to.

Which of these two coding-styles is better? Both are compliant with PEP8 [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I'm trying to be quite strict about PEP8 coding style, but this question has not been answered for me. These are two versions of the same code, one is using temporary variables of which each is used only once, the other version doesn't use temporary variables and looks more like what would be common in functional languages.
For me the functional one looks prettier, but I'm not sure if there is any guideline about how many functions I should chain together.
Version with temporary variables:
class EmailConfirmation():
#receiver(email_confirmed)
def confirmed(sender, **kwargs):
email = kwargs['email_address'].email
keystone_id = User.objects.get_by_natural_key(email).keystone_id
client = Client(token=settings.KEYSTONE_TOKEN,
endpoint=settings.KEYSTONE_URL)
client.users.update(keystone_id, enabled=True)
Version without temporary variables:
class EmailConfirmation():
#receiver(email_confirmed)
def confirmed(sender, **kwargs):
Client(
token=settings.KEYSTONE_TOKEN,
endpoint=settings.KEYSTONE_URL
).users.update(
User.objects.get_by_natural_key(
kwargs['email_address'].email
).keystone_id, enabled=True
)
Is there any guideline that defines which of these two versions is recommended, or are both ok?
The first version should be preferred. This is true, not just for Python, but for other languages like C++/Java because its prone to error and per the Zen of Python Errors should never pass silently., which would be the case in your second version.
The Reason:
Consider, the instantiate of Client fails, which results in returning None. Chaining the same object without checking for a success or proper error handling would result in errors unrelated to the actual problem AttributeError: 'NoneType' object has no attribute 'users'.
So it is always better, to avoid chaining objects, as that would cause errors to pass silently.
Example
Consider the following modification to your first version
class EmailConfirmation():
#receiver(email_confirmed)
def confirmed(sender, **kwargs):
email = kwargs['email_address'].email
keystone_id = User.objects.get_by_natural_key(email).keystone_id
try:
client = Client(token=settings.KEYSTONE_TOKEN,
endpoint=settings.KEYSTONE_URL)
except CustomClientError as e:
# Your Error Handling Code goes here
raise CustomClientError("Your Error Message")
else:
if client.users:
client.users.update(keystone_id, enabled=True)
else:
raise CustomEmailError("Your Error Message")
finally:
# Cleanup code goes here
PEP8 doesn't dictate whether or not to use temporary variables.
To my eyes, though, the second version does not look very Pythonic: most Python code avoids chaining methods like that. I might even store the User rather than the keystone_id:
user = User.objects.get_by_natural_key(email)
client = Client(token=settings.KEYSTONE_TOKEN,
endpoint=settings.KEYSTONE_URL)
client.users.update(user.keystone_id, enabled=True)

Categories

Resources