I need to parse "order" from below JSON , if only value of "success" = 'true' , else raise an exception.
Tried below, but not sure how to include the 'true' check in try:
{
"success":true,
"order":"123345"
}
below is the code , I am trying , which is not giving any result from print as well.
import json
from pprint import pprint
data = json.load(open('data.json'))
#pprint(data)
try:
check_key = data['success']
except KeyError:
#continue
print(check_key)
#print(data['order'])
You should evaluate data['success'] in a condition, whether it is false, then you raise your exception.
import json
data = json.load(open('data.json'))
if data['success'] is not True:
raise Exception("Success is false")
order = data['order']
print(order)
I need to parse "order" from below JSON , if only value of "success" = 'true' , else raise an exception.
There's no function that will automatically raise an exception if a value is False; you need to write that yourself.
But it's dead easy:
check_key = data.get('success')
if not check_key:
raise MyKindOfError(f'response success was {check_key}')
do_stuff(data['order'])
(You don't actually need to use get there; you could let data['success'] raise a KeyError if it's not present, and then separately check the value for falsiness and raise your own error. But I assume you probably want to handle a missing success the same way as false, and the error you want to raise probably isn't KeyError, in which case this is simpler.)
As a side note, you've already parsed the JSON at this point. What you have is a dict.
The fact that it originally came from parsing JSON doesn't make any difference; it's a plain old Python dict, with all the same methods, etc., as any other dict. So, it really isn't helpful to think of "how do I … with JSON …"; that just misleads you into forgetting about how easy dicts are to use.
Related
I have a function that processes an AWS Lambda context, looking for a query string parameter.
The return value for the function is always a Tuple that contains the error code and the returned value. In case of success, it returns (None, the_value_of_the_query_string). In case of failure, it returns (Exception, None).
The code is written to behave similarly to what is very commonly seen in the Go world.
Here is the line triggering the warning:
file_name = file_path.split("/")[-1]
And below is the code that takes you through everything.
class QSException(Exception):
pass
def get_query_string(
event: Dict, query_string: str
) -> Union[Tuple[QSException, None], Tuple[None, str]]:
error = QSException()
#* [...snip...]
if not query_string in event["queryStringParameters"]:
return (error, None)
return (None, event["queryStringParameters"][query_string])
def get_file(event: Dict, context: Dict) -> Dict:
err, file_path = get_query_string(event, "file")
if err is not None:
message = {"message": "No file specified."}
return {"statusCode": 403, "body": json.dumps(message)}
# from here on I'm on the happy path
file_name = file_path.split("/")[-1]
#* [...snip...]
return {
#* [...bogus dict...]
}
If you follow the code, I treat the exceptions first and return 403 on the unhappy path. That is, once I've processed all exceptions I know for a fact that the error code was None and my result was a str. So I would expect that doing a .split("/") would work (which it does) and not trigger a typing warning.
Instead, I'm getting Item "None" of "Optional[str]" has no attribute "split" [union-attr].
So the question is how should typing look for this code so that I don't get this typing warning?
It is annotated correctly.
However when you unpack the tuple err, file_path = get_... the connection between those two variables is lost.
A static code analyzer (mypy, pyright, ...) will now assume that err is an Optional[QSException] and file_path is an Optional[str]. And when you check for the type of the first variable, it doesn't have any effect on the second variable type.
If you really want to keep that idiom, returning a tuple (exception, value), then just help the static code analyzers with asserts.
It's manual work (and therefore error prone), but I guess the tools are not clever enough to figure out the correct type in such a case.
err, file_path = get_query_string(event, "file")
if err:
return ...
assert isinstance(file_path, str)
# now static code analyzers know the correct type
However Python is not the same language as Go, and has completely different idioms.
Returning such a tuple is an antipattern in Python. Python, unlike Go, has real exceptions. So use them.
def get_query_string(event: Dict, query_string: str) -> str:
if not query_string in event["queryStringParameters"]:
raise QSException()
return event["queryStringParameters"][query_string]
def get_file(event: Dict, context: Dict) -> Dict:
try:
file_path = get_query_string(event, "file")
except QSException:
message = {"message": "No file specified."}
return {"statusCode": 403, "body": json.dumps(message)}
file_name = file_path.split("/")[-1]
Or alternatively just return an Optional[str] in case you don't wanna raise an exception, or a Union[QSE, str].
I am currently using the json module to load some JSON content and I need to exclude NaN values. The standard way to do this seems to be to implement a parse_constant method and then pass this method to json.loads.
Example:
def parse_constant(c: str) -> float:
if c == "NaN":
raise ValueError("NaN is not valid JSON")
return float(c)
json_content = json.loads(some_json_string, parse_constant=parse_constant)
Apparently, the decode implementation does not catch the ValueError and transform it into a JSONDecodeError, which forces me to check for both exception types. I miss the context (line number, JSON document) to build the decode error myself. I know I could just catch ValueError, but is there a way to configure the json module to raise what I would expect to be the logical exception type?
I have to use a try and except block with the following code, as I am trying to get a model class object but in case if database is empty so for that I need to use try and except.
if(txStatus=='SUCCESS'):
order=Order.objects.get(id=id) #NEED TRY ACCEPT BLOCK FOR THIS
URL = payment_collection_webhook_url
request_data ={}
json_data = json.dumps(request_data)
requests.post(url = URL, data = json_data)
return Response(status=status.HTTP_200_OK)
try..except..else..finally block works like this:
try:
order=Order.objects.get(id=id)
except ObjectDoesNotExist(or MultipleObjectsReturned in case it returns more
than 1 queryset or instance):
...Handle the exception, Write any code you want
else:
...This gets called if there is no exception or error, means it will
execute right after try statement if there's no error, so if you want
something more to happen only if the code doesn't throw an error, you can
write it here
finally:
...This gets executed no matter what in any case, means if there's
something you want to execute regardless of whether it throws an
exception or not, you write it here.
It is as simple as this:
try:
order = Order.objects.get(id=order_id)
except Order.DoesNotExist:
# Exception thrown when the .get() function does not find any item.
pass # Handle the exception here.
You can find more information about DoesNotExist exception here.
#Hagyn is correct, but in Django there is another way to do that:
Something like this:
orders = Order.objects.filter(id=order_id)
if orders.exists():
order = orders.last()
else:
# do rest of the things
I am working on a small texting application using Twilio API. Recently, I had some issues with the API so I added an Exception in my get_current_credits() function.
I am quite new to Python and programming in general and I would like to know what would be the cleanest way to do that.
If the Exception is throw, I only return a String. If not, I am returning a tuple. What would be the cleanest way to see what was the return from my inject_credits() function, I am thinking about type(res) but does seems a quick and dirty solution?
def get_current_credits():
try:
balance_data = twilio_client.api.v2010.balance.fetch()
balance = float(balance_data.balance)
currency = balance_data.currency
return balance, currency
except Exception:
return "503 Service Unavailable"
def inject_credit():
res = get_current_credits()
# if Exception:
# return the Exception message as a string
# else, do the following:
(credit, currency) = res
if currency != "EUR":
credit = currency_converter.convert(credit, currency, 'EUR')
return dict(credit=(round(credit,2)))
You could move the Exception outside, into the body of inject_credit. Thus, you don't have to do any if statements inside inject_credit, you can just catch the Exception there itself.
Checking the type isn't a bad idea, but it is not very clear what is being done if someone is only reading inject_credit.
You can try this:
if type(get_current_credits()) == str:
# Do something if it is a string
else:
# Do something if it is a tuple
However, the best way would be to add the try statement outside of the function so that you can catch the exception there instead.
try:
get_current_credits()
except Exception as e:
print(e)
# Do whatever
In a view function, I have something like:
try:
url = request.POST.get('u', '')
if len(url) == 0:
raise ValidationError('Empty URL')
except ValidationError, err:
print err
The output is a string: [u'Empty URL']
When I try to pass the error message to my template (stuffed in a dict, something like { 'error_message': err.value }), the template successfully gets the message (using {{ error_message }}).
The problem is that I get the exact same string as above, [u'Empty URL'], with the [u'...']!
How do I get rid of that?
(Python 2.6.5, Django 1.2.4, Xubuntu 10.04)
ValidationError actually holds multiple error messages.
The output of print err is [u'Empty URL'] because that is the string returned by repr(err.messages) (see ValidationError.__str__ source code).
If you want to print a single readable message out of a ValidationError, you can concatenate the list of error messages, for example:
# Python 2
print '; '.join(err.messages)
# Python 3
print('; '.join(err.messages))
If you are importing ValidationError from django.core.exceptions you can simply use messages method as err.messages.
https://github.com/django/django/blob/main/django/core/exceptions.py#L124
If you are importing ValidationError from rest_framework.serializers , there is no messages property for the ValidationError but there is detail property. so you can use err.detail which will give you a dictionary.
In order to concatenate all the error messages as a string, you can use
"".join(["".join(v) for v in err.detail.values()])
or
"".join([k+" - "+"".join(v) for k,v in err.detail.items()])
https://github.com/encode/django-rest-framework/blob/master/rest_framework/exceptions.py#L143
A more general way to always know where the message is to call the dir function on your err variable to show you all the attribute of this object.
from that list you can infer where the messages are, in my case (with django 3.2) i found out that the message dict is in an attribute called args.
so to use it (with a print for example)
try:
url = request.POST.get('u', '')
if len(url) == 0:
raise ValidationError('Empty URL')
except ValidationError, err:
print(err.args) # HERE THE ERROR DICT MESSAGE IS ACCESSIBLE
I fixed it by changing ValidationError to BaseException.