I wrote a function that validates if all the fields exist in a python dictionary. Below is the code.
def validate_participants(self, xml_line):
try:
participant_type = xml_line["participants"]["participant_type"]
participant_role = xml_line["participants"]["participant_role"]
participant_type = xml_line["participants"]["participant_type"]
participant_id = xml_line["participants"]["participant_id"]
return True
except KeyError as err:
log.error(f'{err}')
return False
This raises an error about the missing key that it finds first and breaks execution. I want to go through the entire set of fields and raise error with all the missing fields. What's the best/efficient way to solve the problem?
Using a set you can get the difference and if it is empty the keys are not missing.
def validate_participants(self, xml_line):
keys = {"participant_type", "participant_role", "participant_id"}
return keys - xml_line["participants"].keys() or True
The or True means return the set of missing keys if there are missing keys otherwise return True
Edit:
To answer your comment there is no need to use a try/except if you check first:
def validate_participants(self, xml_line):
keys = {"participant_type", "participant_role", "participant_id"}
missing_keys = keys - xml_line["participants"].keys()
if missing_keys:
#return False or
raise Value_Error(f"Missing values: {', '.join(missing_keys)}")
#access the values/do work or
return True
I would define a set of the expected keys and subtract the actual keys:
expected_keys = {...}
actual_keys = xml_line["participants"].keys()
key_diff = expected_keys - actual_keys
Now create a message from key_diff about which keys are missing.
Related
Assume I have an empty dict.
test_dict = {}
My original code is like this.
x = input()
try:
info = test_dict.get(x)
except:
print("Key Does Not Exist!")
but it doesn't raise a KeyError in my console, instead, it returns None. I am very sure I tested it and it works but after I updated my Spyder from 4.1.2 to 4.1.5, it doesn't work any more and I have to change my code to this:
x = input()
if x in test_dict.keys():
info = test_dict.get(x)
else:
print("Key Does Not Exist!")
Why does it return None instead of KeyError?
If you do not understand some behavior help can often be useful. In this case you can do:
test_dict = {}
help(test_dict.get)
to become aware that:
Help on built-in function get:
get(key, default=None, /) method of builtins.dict instance
Return the value for key if key is in the dictionary, else default.
I have a dictionary and I want to add some index of the dictionary to variables.
I know that try except is more pythonic than else if. And I tried with try except and it's works perfectly but I have a lot of key to check and I can't figure out of which code is more pythonic
Here is my dictionary :
test = {"token":"eating", "stemm": "eat", "lemm": "eat", "pos":"VPP"}
def method_one(test):
try:
token = test["token"]
except KeyError:
token = None
try:
stemm = test["stemm"]
except KeyError:
stemm = None
def method_two(test):
token = None
stemm = None
if "token" in test:
token = test["token"]
if "stemm" in test:
stemm = test["stemm"]
I also tried one try except for all but when one failed, I can't know which one is failing so this is useless.
Any ideas of a third method? Or method one is the good one?
dict has get method that will return value or None. you could do item = dict.get(key) and this will return either the value(if the key exists) or None otherwise, which is what you are looking for it seems :)
>>> d = {'foo': 'bar'}
>>> d.get('foo')
'bar'
>>> item = d.get('fooo')
>>> item is None
True
There is a direct lookup construct where create a set of valid keys that should exist in the dictionary
test = {"token":"eating", "stemm": "eat", "lemm": "eat", "pos":"VPP"}
def validate(d, valkeys):
keyset = set(test.keys())
if valkeys.issubset(keyset):
return True
else:
return False
if __name__ == "__main__":
val = set(["token", "stemm"])
inval = set(["token", "stemm", "st"])
assert validate(test, val) == True
assert validate(test, inval) == False
I tried to enter 5 similar elements in a set and print it at last. It took all the elements without raising any error but stored only one since all were same. I want to know if it is possible that the moment i input a value which is already present in the set , user is prompted with an error that the value already present in the set. I want to do this with set only , not with list or dict on anything else.
If you want to raise an exception on duplicate insertion, you could do something like this:
class DuplicateKeyError(Exception): pass
class SingleSet(set):
def add(self, value):
if value in self:
raise DuplicateKeyError('Value {!r} already present'.format(value))
super().add(value)
def update(self, values):
error_values = []
for value in values:
if value in self:
error_values.append(value)
if error_values:
raise DuplicateKeyError('Value(s) {!r} already present'.format(
error_values))
super().update(values)
my_set = SingleSet()
value = 'something'
while value:
value = input('Enter a value: ')
try:
my_set.add(value)
except DuplicateKeyError as e:
print(e)
You can just check if it exist, then raise an error:
my_set = set()
for i in some_list_of_user_input:
if i in my_set:
print('{} is already present in the set'.format(i))
my_set.add(i)
Is there a way or a function to check if a key is a valid key for the current app id?
e.g.
key = fetch_urlsafe_key_from_external_source()
key = ndb.Key(urlsafe=key)
if not is_valid_key(key):
return
# do something with the key
EDIT: For the moment I'm doing
def is_valid_key(key):
try:
key.get()
except datastore_errors.BadRequestError:
return False
return True
But hopefully someone suggests something that doesn't requiring hitting the datastore
You can check for correct application ID included in the key:
import os
def is_valid_key(key):
"""Valid key should include an ID and current application ID.
"""
if key.app() == os.getenv('APPLICATION_ID') and key.id():
return True
return False
Is this what you are looking for?
def is_valid_key(key):
try:
key.id()
except TypeError:
return False
return True
EDIT:
I know realize that OP wanted application validation not just key validation. The currently selected "correct" answer works in most cases but would still raise an exception if the key was incomplete/changed (i.e. missing some characters or having extra characters at the end of the string), the better way to validate would be:
def is_valid_key(key):
try:
key.id()
except TypeError:
return False
return key.app() == os.getenv('APPLICATION_ID')
In order to make CSV files with many columns, I have many, many instances of
try:
printlist.append(text['data'])
except:
printlist.append('')
Is it possible to condense these 4 lines into 1 or 2 (mostly for easier reading of the code)? I've tried with this function but I haven't discovered a way to pass something that doesn't exist.
def tryexcept(input):
try:
printlist.append(input)
except:
printlist.append('')
return printlist
UPDATE I should mention that 'text' is actually a dict value, so it should look like
printlist.append(text['data'])
(changed above)
What about:
printlist.append(text['data'] if 'data' in text else '')
Or even better as #bruno desthuilliers suggested:
printlist.append(text.get('data',''))
[EDIT]
For nested dict I normally use my dict selector:
class TokenDataType:
LIST = "list"
DICT = "dict"
def _select_key(keyitt, data):
try:
new_key = keyitt.next()
except StopIteration:
return data
if new_key["t"] == TokenDataType.DICT:
return _select_key(keyitt, data[new_key["k"]])
elif new_key["t"] == TokenDataType.LIST:
return _select_key(keyitt, data[new_key["i"]])
def tokenize_query(query):
tokens = []
for token in query.split("."):
token = token.strip()
if token:
ttype = TokenDataType.LIST if "[" in token else TokenDataType.DICT
if ttype == TokenDataType.LIST:
index = None
if len(token) >= 3:
index = int(token.replace("[", "").replace("]", ""))
tokens.append({"k":token, "t":ttype, "i":index})
else:
tokens.append({"k":token, "t":ttype})
return tokens
def normalize_query(query=None, tokens=None):
if tokens == None:
tokens = tokenize_query(query)
return ".".join([token["k"] for token in tokens])
def select(query, data, throw_exception_on_key_not_found=False):
tokens = tokenize_query(query)
try:
return _select_key(iter(tokens), data)
except Exception as e:
if throw_exception_on_key_not_found:
raise e
return None
DQ = select
if __name__ == "__main__":
test = {"bla":1, "foo":{"bar":2}, "baz":[{"x":1}, {"x":2}]}
print(DQ(".bla", test))
print(DQ("bla", test))
print(DQ("nothere", test))
print(DQ(".foo", test))
print(DQ("foo.bar", test))
print(DQ("baz", test))
print(DQ("baz.[0]", test))
print(DQ("baz.[1].x", test))
print(DQ("baz.[2].x", test))
for your case (appends None when one of the keys is not found):
printlist.append(DQ("data.someotherkey.yetanotherkey", text))
There's a dictionary method that does exactly this, and it let's you specify any default value.
input = text.get('data', default='')
printlist.append(input)
It checks if the key exists in the dictionary, and if not, it returns the default value. More on dictionaries here.
Try this simple wrapper:
def execute_with_exception_handling(f):
try:
return f()
except:
raise
Then you execute your function:
def my_func():
return 0 / 0
execute_with_exception_handling(my_func)
You can also add arguments to the function with *args. And you can even use decorators...that you can google because I recall off the top of my head how that works.
Why do you need to pass something that does not exist?
You can simply call function if the value that is being passed in is not "None" (Or any other unwanted value).
tryexcept( x ) if x is not None else None
Edit:
Are you are trying to see if the variable is declared or not? If yes, one way to get around this would be to declare the variable beforehand:
x = None
...
tryexcept( x ) if x is not None else None