How to get the variable where a KeyError was raised [duplicate] - python

This question already has answers here:
Which key failed in Python KeyError?
(3 answers)
Closed 4 days ago.
I have a code like this:
foo = {'bar': {}}
test = foo['bar']['wrong_key']
which ends in an exception like this:
Traceback (most recent call last):
File "test.py", line 2, in <module>
test = foo['bar']['wrong_key']
KeyError: 'wrong_key'
Now i want to catch the exeption and write a error message which says, that foo['bar']['wrong_key'] is not set correctly.
The solution should look like this:
try:
foo = { 'bar': {} }
test = foo['bar']['wrong_key']
test1 = foo['bar']['another_wrong_key']
test3 = foo['bar']['many_posible_wrong_keys']
except KeyError as exc:
variable_name = ??? # <- no idea how to get this Information
print(f'The Key {exc} is not present in {variable_name}')
But how do i programmatically get variable_name from the KeyError exception?

You can use try and except:
try:
foo = { 'bar': {} }
test = foo['bar']['wrong_key']
except KeyError as exc:
print(f'Following Key is not present in the dictionary: {exc}')
# Following Key is not present in the dictionary: 'wrong_key'

Use a try/except with catching of the error message:
foo = { 'bar': {} }
try:
test = foo['bar']['wrong_key']
except KeyError as e:
print(e)
Output: 'wrong_key'

Related

Python shelve not saving nested keys

I am using the shelve module to save some Python objects (strings in the example).
When I am trying to save an object as a nested key, then it is not being saved.
class Car:
def __init__(self, ID):
self.id = ID
def save_to_shelf(self):
with shelve.open('shelf') as shelf:
if not shelf.get('users'):
shelf['users'] = {}
print(shelf['users'])
try:
shelf['users'][self.id] = "hello"
except Exception as e:
print(e)
print('saved')
print(shelf['users'])
car = Car(123)
car.save_to_shelf()
The code should print:
{}
saved
{123: hello}
But instead it prints:
{}
saved
{}
Meaning that it is not getting saved
If I print the value of the key, it gives KeyError
shelf['users'][self.id] = "hello"
print(shelf['users'][self.id])
Error
Traceback (most recent call last):
File "P:/Python practice/Shelll/main.py", line 3, in <module>
car.save_to_shelf()
File "P:/Python practice/Shelll\db.py", line 20, in save_to_shelf
print(shelf['users'][self.id])
KeyError: '123'
I am able to save it if I do the following while saving
Instead of
with shelve.open('shelf') as shelf:
shelf['users'][self.id] = "hello"
This works
with shelve.open('shelf') as shelf:
USERS = shelf['users']
USERS[self.id] = self.id
shelf['users'] = USERS
# or this works
# with shelve.open('shelf') as shelf:
# shelf['users'] = {self.id:"hello"}
I want to understand the reason behind this. As far as I know, shelve objects work as a dictionary. So the way I was saving earlier should work but does not.

an undefined error in a simple python code- KeyError: '284882215'

I'm getting this: KeyError: '284882215'. I
couldn't find anything via google/on StackOverflow; can some one assist?
Cheers!
ios_clean = []
ios_already_added = []
for app in ios:
name = app[0]
n_reviews = float(app[5])
print (n_reviews)
if n_reviews == reviews_max[name] and name not in ios_already_added:
ios_clean.append(app)
ios_already_added.append(name)
print (ios_clean)
print (len(ios_already_added))
KeyError Traceback (most recent call last)
<ipython-input-26-e59f5982da23> in <module>
11 n_reviews = float(app[5])
12 print (n_reviews)
---> 13 if n_reviews == reviews_max[name] and name not in ios_already_added:
14 ios_clean.append(app)
15 ios_already_added.append(name)
KeyError: '284882215'
The issue here is that you're trying to access an item in reviews_max with the key "284882215", and it does not exist.
As a solution, you can use Dict get() to safely lookup a key.
if n_reviews == reviews_max.get(name) and name not in ios_already_added:
Python documentation says:
exception KeyError
Raised when a mapping (dictionary) key is not found in the set of existing keys.
Meaning you tried to access a key which doesn't exist.
You can use the get() method which will either return the value found OR a default value, if you want to bypass the KeyError. This is the standard method for handling a use case like yours.
dict.get(key, default = None)

How to catch pg8000.core.IntegrityError exception in python?

I am trying to run a test case to catch an primary key exception when trying to load into a table in postgresql using pg8000. But, I'm unable to catch it in python. Below is my code.
import pg8000
def create_albums(self,music):
experts = []
exp = music.data_info.get("artist_list") # List of a dictionary
try:
for expert in exp:
experts.append(ArtistData({
"name": expert.name,
"age": expert.age,
"present": True,
"nodiscs": expert.get("disc_code")
}))
except pg8000.core.IntegrityError:
raise Exception
return experts
Below is the error message
pg8000.core.IntegrityError: {'S': 'ERROR', 'V': 'ERROR', 'C': '23505', 'M': 'duplicate key value violates unique constraint "artist_discs_pkey"}
Any help is really appreciated. Thank you.
You do catch the exception, but all you do is raise it again, so it's rather useless.
Add a simple print before the raise, eg. print("Failed to insert"), and you'll see that message followed by the exeption that raised it.
According to the documentation,
"pg8000.core.IntegrityError:" Belongs to the generic (DatabaseError). So you would need to format your code like this replacing IntegrityError with DatabaseError:
import pg8000
def create_albums(self,music):
experts = []
exp = music.data_info.get("artist_list") # List of a dictionary
try:
for expert in exp:
experts.append(ArtistData({
"name": expert.name,
"age": expert.age,
"present": True,
"nodiscs": expert.get("disc_code")
}))
except pg8000.core.DatabaseError:
raise Exception
return experts

Check that a key from json output exists

I keep getting the following error when trying to parse some json:
Traceback (most recent call last):
File "/Users/batch/projects/kl-api/api/helpers.py", line 37, in collect_youtube_data
keywords = channel_info_response_data['items'][0]['brandingSettings']['channel']['keywords']
KeyError: 'brandingSettings'
How do I make sure that I check my JSON output for a key before assigning it to a variable? If a key isn’t found, then I just want to assign a default value. Code below:
try:
channel_id = channel_id_response_data['items'][0]['id']
channel_info_url = YOUTUBE_URL + '/channels/?key=' + YOUTUBE_API_KEY + '&id=' + channel_id + '&part=snippet,contentDetails,statistics,brandingSettings'
print('Querying:', channel_info_url)
channel_info_response = requests.get(channel_info_url)
channel_info_response_data = json.loads(channel_info_response.content)
no_of_videos = int(channel_info_response_data['items'][0]['statistics']['videoCount'])
no_of_subscribers = int(channel_info_response_data['items'][0]['statistics']['subscriberCount'])
no_of_views = int(channel_info_response_data['items'][0]['statistics']['viewCount'])
avg_views = round(no_of_views / no_of_videos, 0)
photo = channel_info_response_data['items'][0]['snippet']['thumbnails']['high']['url']
description = channel_info_response_data['items'][0]['snippet']['description']
start_date = channel_info_response_data['items'][0]['snippet']['publishedAt']
title = channel_info_response_data['items'][0]['snippet']['title']
keywords = channel_info_response_data['items'][0]['brandingSettings']['channel']['keywords']
except Exception as e:
raise Exception(e)
You can either wrap all your assignment in something like
try:
keywords = channel_info_response_data['items'][0]['brandingSettings']['channel']['keywords']
except KeyError as ignore:
keywords = "default value"
or, let say, use .has_key(...). IMHO In your case first solution is preferable
suppose you have a dict, you have two options to handle the key-not-exist situation:
1) get the key with default value, like
d = {}
val = d.get('k', 10)
val will be 10 since there is not a key named k
2) try-except
d = {}
try:
val = d['k']
except KeyError:
val = 10
This way is far more flexible since you can do anything in the except block, even ignore the error with a pass statement if you really don't care about it.
How do I make sure that I check my JSON output
At this point your "JSON output" is just a plain native Python dict
for a key before assigning it to a variable? If a key isn’t found, then I just want to assign a default value
Now you know you have a dict, browsing the official documention for dict methods should answer the question:
https://docs.python.org/3/library/stdtypes.html#dict.get
get(key[, default])
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
so the general case is:
var = data.get(key, default)
Now if you have deeply nested dicts/lists where any key or index could be missing, catching KeyErrors and IndexErrors can be simpler:
try:
var = data[key1][index1][key2][index2][keyN]
except (KeyError, IndexError):
var = default
As a side note: your code snippet is filled with repeated channel_info_response_data['items'][0]['statistics'] and channel_info_response_data['items'][0]['snippet'] expressions. Using intermediate variables will make your code more readable, easier to maintain, AND a bit faster too:
# always set a timeout if you don't want the program to hang forever
channel_info_response = requests.get(channel_info_url, timeout=30)
# always check the response status - having a response doesn't
# mean you got what you expected. Here we use the `raise_for_status()`
# shortcut which will raise an exception if we have anything else than
# a 200 OK.
channel_info_response.raise_for_status()
# requests knows how to deal with json:
channel_info_response_data = channel_info_response.json()
# we assume that the response MUST have `['items'][0]`,
# and that this item MUST have "statistics" and "snippets"
item = channel_info_response_data['items'][0]
stats = item["statistics"]
snippet = item["snippet"]
no_of_videos = int(stats.get('videoCount', 0))
no_of_subscribers = int(stats.get('subscriberCount', 0))
no_of_views = int(stats.get('viewCount', 0))
avg_views = round(no_of_views / no_of_videos, 0)
try:
photo = snippet['thumbnails']['high']['url']
except KeyError:
photo = None
description = snippet.get('description', "")
start_date = snippet.get('publishedAt', None)
title = snippet.get('title', "")
try:
keywords = item['brandingSettings']['channel']['keywords']
except KeyError
keywords = ""
You may also want to learn about string formatting (contatenating strings is quite error prone and barely readable), and how to pass arguments to requests.get()

python: check if variable is defined and return its value or return other value

I am trying to use this code
result = arr['key1'] or arr['key2'] or arr['key3']
explanation:
I want to have value in result from either or dict keys .. the availability of keys depends on the environment. This is not about None .. only one of the arr keys might be defined ...
so is there a function or method like is_defined()
How do we do this in python ??
UPDATE
I'm having a new problem here ..
CODE 1:
try:
urlParams += "%s=%s&"%(val['name'], data.get(val['name'], serverInfo_D.get(val['name'])))
except KeyError:
print "expected parameter not provided - "+val["name"]+" is missing"
exit(0)
CODE 2:
try:
urlParams += "%s=%s&"%(val['name'], data.get(val['name'], serverInfo_D[val['name']]))
except KeyError:
print "expected parameter not provided - "+val["name"]+" is missing"
exit(0)
see the diffrence in serverInfo_D[val['name']] & serverInfo_D.get(val['name'])
code 2 fails but code 1 works
the data
serverInfo_D:{'user': 'usr', 'pass': 'pass'}
data: {'par1': 9995, 'extraparam1': 22}
val: {'par1','user','pass','extraparam1'}
exception are raised for for data dict .. and all code in for loop which iterates over val
result = arr.get('key1', arr.get('key2', arr.get('key3')))

Categories