how to get value in "reasons" field? - python

I have a variable output which can take the values #1,#2 ,
i am trying to get the value in "reasons" IF IT EXISTS,as you can see from #1 it does not exist always, can anyone suggest how this can be done?
output =
#1: {"took":42,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}
#2: {"took":88,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":1.0,"hits":[{"_index":"dispatcher","_type":"lookaheadDV","_id":"832238","_score":1.0, "_source" : {"reasons": ["12345 is associated with data in an invalid state"]}}]}}
OUTPUT:-
12345 is associated with data in an invalid state

Well, start with the logic:
hits inside hits may always be there... In additions hits looks to be a list, so you can test if hits (inside hits) is present and if it's not empty (you could test its length, for example).
Once you know that hits is there, you have to go inside that object and check if the value you're looking for is there.
When you have a dictionary in Python, you can retrieve values using the following syntax:
new_value = some_dictionary.get('some_key', None)
That value "None" at the end is the value Python gives me back if there is no value associated with that key. You can put whatever value you want in there and then check for it later on:
new_value = some_dictionary.get('some_key', 'BETTER ASK STACKOVERFLOW')
You have to just try stuff. Use the REPL.
Also, the following is not anything I've ever seen in Python. What gave you this error message:
12345 is associated with data in an invalid state

Ignore KeyErrors where necessary. There are possibly multiple reasons, so the following code gathers them all to a list, then join together using ', ' as the separator.
value = { "took":88,"timed_out":False,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":1.0,"hits":[{"_index":"dispatcher","_type":"lookaheadDV","_id":"832238","_score":1.0, "_source" : {"reasons": ["12345 is associated with data in an invalid state"]}}]}}
reasons = []
for i in value['hits']['hits']:
try:
reasons.extend(i['_source']['reasons'])
except KeyError:
pass
reason = ', '.join(reasons)

This should do it:
adict = {"took":42,"timed_out":False,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":0,"max_score":"null","hits":[]}}
bdict = {"took":88,"timed_out":False,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":1.0,"hits":[{"_index":"dispatcher","_type":"lookaheadDV","_id":"832238","_score":1.0, "_source" : {"reasons": ["12345 is associated with data in an invalid state"]}}]}}
def get_reasons(some_dict):
output = ""
try:
output = some_dict.get("hits").get("hits")[0].get("_source").get("reasons")
except:
pass
return output
print get_reasons(adict)
print get_reasons(bdict)
prints nothing for the first dictionary and prints
12345 is associated with data in an invalid state
for the second dictionary.
PS: I changed false to False and null to "null" in your dictionaries.

Related

How to fix the errors in my code for making a dictionary from a file

This is what I am supposed to do in my assignment:
This function is used to create a bank dictionary. The given argument
is the filename to load. Every line in the file will look like key:
value Key is a user's name and value is an amount to update the user's
bank account with. The value should be a number, however, it is
possible that there is no value or that the value is an invalid
number.
What you will do:
Try to make a dictionary from the contents of the file.
If the key doesn't exist, create a new key:value pair.
If the key does exist, increment its value with the amount.
You should also handle cases when the value is invalid. If so, ignore that line and don't update the dictionary.
Finally, return the dictionary.
Note: All of the users in the bank file are in the user account file.
Example of the contents of 'filename' file:
Brandon: 115.5
James: 128.87
Sarah: 827.43
Patrick:'18.9
This is my code:
bank = {}
with open(filename) as f:
for line in f:
line1 = line
list1 = line1.split(": ")
if (len(list1) == 2):
key = list1[0]
value = list1[1]
is_valid = value.isnumeric()
if is_valid == True
value1 = float(value)
bank[(key)] = value1
return bank
My code returns a NoneType object which causes an error but I don't know where the code is wrong. Also, there are many other errors. How can I improve/fix the code?
Try this code and let me explain everything on it because it depends on how much you're understanding Python Data structure:
Code Syntax
adict = {}
with open("text_data.txt") as data:
"""
adict (dict): is a dictionary variable which stores the data from the iteration
process that's happening when we're separating the file syntax into 'keys' and 'values'.
We're doing that by iterate the file lines from the file and looping into them.
The `line` is each line from the func `readlines()`. Now the magic happens here,
you're playing with the line using slicing process which helps you to choose
the location of the character and play start from it. BUT,
you'll face a problem with how will you avoid the '\n' that appears at the end of each line.
you can use func `strip` to remove this character from the end of the file.
"""
adict = {line[:line.index(':')]: line[line.index(':')+1: ].strip('\n') for line in data.readlines()}
print(adict)
Output
{' Brandon': '115.5', ' James': '128.87', ' Sarah': '827.43', ' Patrick': "'18.9"}
In term of Value Validation by little of search you will find that you can check the value if its a number or not
According to Detect whether a Python string is a number or a letter
a = 5
def is_number(a):
try:
float (a)
except ValueError:
return False
else:
return True
By Calling the function
print(is_number(a))
print(is_number(1.4))
print(is_number('hello'))
OUTPUT
True
True
False
Now, let's back to our code to edit;
All you need to do is to add condition to this dict..
adict = {line[:line.index(':')]: line[line.index(':')+1: ].strip(' \n') for line in data.readlines() if is_number(line[line.index(':')+1: ].strip('\n')) == True}
OUTPUT
{'Brandon': '115.5', 'James': '128.87', 'Sarah': '827.43'}
You can check the value of the dict by passing it to the function that we created
Code Syntax
print(is_number(adict['Brandon']))
OUTPUT
True
You can add more extensions to the is_number() function if you want.
You're likely hitting the return in the else statement, which doesn't return anything (hence None). So as soon as there is one line in your file that does not contain 2 white-space separated values, you're returning nothing.
Also note that your code is only trying to assign a value to a key in a dictionary. It is not adding a value to an existing key if it already exists, as per the documentation.
This should effectively do the job:
bank = {}
with open(filename) as file:
for line in file:
key, val = line.rsplit(": ", 1) # This will split on the last ': ' avoiding ambiguity of semi-colons in the middle
# Using a trial and error method to convert number to float
try:
bank[key] = float(val)
except ValueError as e:
print(e)
return bank

Removing duplicates from an attribute of a class variable

I'm extremely new to python and was having some trouble with removing duplicate values from an attribute of a class (I think this is the correct terminology).
Specifically I want to remove every value that is the same year. I should note that I'm printing only the first four value and searching for the first four values. The data within the attribute is actually in Yearmonthday format (example: 19070101 is the year 1907 on the first on january).
Anyways, here is my code:
import csv
import os
class Datatype:
'Data from the weather station'
def __init__ (self, inputline):
[ self.DATE,
self.PRCP] = inputline.split(',')
filename ='LAWe.txt'
LAWd = open(filename, 'r')
LAWefile = LAWd.read()
LAWd.close()
'Recognize the line endings for MS-DOS, UNIX, and Mac and apply the .split() method to the string wholeFile'
if '\r\n' in LAWefile:
filedat = LAWefile.split('\r\n') # the split method, applied to a string, produces a list
elif '\r' in LAWefile:
filedat = LAWefile.split('\r')
else:
filedat = LAWefile.split('\n')
collection = dict()
date= dict()
for thisline in filedat:
thispcp = Datatype(thisline) # here is where the Datatype object is created (running the __init__ function)
collection[thispcp.DATE] = thispcp # the dictionary will be keyed by the ID attribute
for thisID in collection.keys():
studyPRP = collection[thisID]
if studyPRP.DATE.isdigit():
list(studyPRP.DATE)
if len(date[studyPRP.DATE][0:4]):
pass #if year is seen once, then skip and go to next value in attribute
else:
print studyPRP.DATE[0:4] #print value in this case the year)
date[studyPRP.DATE]=studyPRP.DATE[0:4]
I get a this error:
Traceback (most recent call last):
File "project.py", line 61, in
if len(date[studyPRP.DATE][0:4]):
KeyError: '19770509'
A key error (which means a value isn't in a list? but it is for my data) can be fixed by using a set function (or so I've read), but I have 30,000 pieces of information I'm dealing with and it seems like you have to manually type in that info so that's not an option for me.
Any help at all would be appreciated
Sorry if this is confusing or nonsensical as I'm extremely new to python.
Replace this
if len(date[studyPRP.DATE][0:4])
by this
if len(date[studyPRP.DATE[0:4]]):
Explanation :
In the first line you are selecting the whole date as the key KeyError: '19770509' in the 4 first entry of date
In the correction you send the the first 4 character of the date(the year) in the dictionary
Don't know what exactly you want here. I'll reply based on I can help you on what.
Your error is because you are accessing your year in data before you are adding it.
Also, what you are adding to your collection is like
{
<object>.DATE: <object>
}
I don't know what you need here. Your lower for loop can be written as under:
for thisID in collection:
if thisID.isdigit():
if thisID[0:4] in date and len(date[thisID[0:4]]):
#if year is seen once, then skip and go to next
# value in attribute
pass
else:
print thisID[0:4] #print value in this case the year)
date[thisID[0:4]]=thisID[0:4]
Note your studyPRP.DATE is same as thisID.

Django / Python, using iteritems() to update database gives strange error: "dictionary update sequence element #0 has length 4; 2 is required"

I'm trying to do a Django database save from a form where I don't have to manually specify the fieldnames (as I do in the 2nd code block), the way I am trying to do this is as below (1st code block) as I got the tip from another S.O. post. However, when I try this I get the error "dictionary update sequence element #0 has length 4; 2 is required", I even tried it, as below, with just a testdict dictionary, instead of the request.POST, but am still getting the error.. obviously the field value is fine since it works in the 2nd code block, so I am stumped as to why this is happening, would appreciate if anyone can shed any light on this for me... thanks
trying it this way gives the error:
testdict = {'name':'account_username','value':'vvvvvv'}
for name, value in testdict.iteritems():
if name != '' and name != 'top_select':
b = Twitter(**dict((name, value)))
b.save()
>>> dictionary update sequence element #0 has length 4; 2 is required
but this works fine:
b = Twitter(account_username='vvvvvv')
b.save()
Not sure what you are trying to do, but maybe you want something like this
b = Twitter(**{name: value})
But to get the equivalent to Twitter(account_username='vvvvvv') you would need something like this
Twitter(**{testdict['name'], testdict['value']})
where testdict would only contain a single entity to send to Twitter()
Then the code would look more like this
test_twits = [{'name':'account_username','value':'vvvvvv'},
{'name':'account_username','value':'wwwwww'},
]
for twit in test_twits:
name = twit['name']
value = twit['value']
if name != '' and name != 'top_select':
b = Twitter(**{name: value})
b.save()
Correct me if I am wrong.
From your second code snippet I take it that the Twitter class needs account_username as a keyword argument. When you are iterating through the dictionary using iteritems you are passing the name - i.e. the key of the dictionary as the keyword argument to the class. Isn't this wrong? The dictionary's keys are name and value, _not _ account_username. I believe you need the one of values from the dictionary to be passed as keyword argument, not one of the keys.
just do this:
dict(((name, value),))
'dict' takes a sequence of key, value tuples whereas you are giving it one key, value tuple.
The reason it says '... sequence element #0 has length 4' is because the key 'name' from testdict has a length of 4.

Reading from Python dict if key might not be present

I am very new to Python and parsing data.
I can pull an external JSON feed into a Python dictionary and iterate over the dictionary.
for r in results:
print r['key_name']
As I walk through the results returned, I am getting an error when a key does not have a value (a value may not always exist for a record). If I print the results, it shows as
'key_name': None, 'next_key':.................
My code breaks on the error. How can I control for a key not having a value?
Any help will be greatly appreciated!
Brock
The preferred way, when applicable:
for r in results:
print r.get('key_name')
this will simply print None if key_name is not a key in the dictionary. You can also have a different default value, just pass it as the second argument:
for r in results:
print r.get('key_name', 'Missing: key_name')
If you want to do something different than using a default value (say, skip the printing completely when the key is absent), then you need a bit more structure, i.e., either:
for r in results:
if 'key_name' in r:
print r['key_name']
or
for r in results:
try: print r['key_name']
except KeyError: pass
the second one can be faster (if it's reasonably rare than a key is missing), but the first one appears to be more natural for many people.
There are two straightforward ways of reading from Python dict if key might not be present. for example:
dicty = {'A': 'hello', 'B': 'world'}
The pythonic way to access a key-value pair is:
value = dicty.get('C', 'default value')
The non-pythonic way:
value = dicty['C'] if dicty['C'] else 'default value'
even worse:
try:
value = dicty['C']
except KeyError as ke:
value = 'default value'
If possible, use the simplejson library for managing JSON data.
the initial question in this thread is why I wrote the Dictor library, it handles JSON fallback and None values gracefully without needing try/except or If blocks.
Also gives you additional options like ignore upper/lower case,
see,
https://github.com/perfecto25/dictor
use has_key() , and that will return true or false
[Updated to remove careless mistake]
You could also do something like this:
for r in (row for row in results if 'a' in row):
print r['a']
This uses a generator expression to pick "rows" out of "results" where "row" includes the key "a".
Here's a little test script:
results = [{'a':True}, {'b':True}, {'a':True}]
for r in (row for row in results if 'a' in row): print r['a']
You can use the built in function hasattr
key='key_name'
# or loop your keys
if hasattr(e, key):
print(e[key])
else:
print('No key for %s' % key)
Taken from https://stackoverflow.com/a/14923509/1265070
id = getattr(myobject, 'id', None)

GQL does not work for GET paramters for keys

I am trying to compare the key to filter results in GQL in Python but the direct comparison nor typecasting to int works. Therefore, I am forced to make a work around as mentioned in the uncommented lines below. Any clues?
row = self.request.get("selectedrow")
#mydbobject = DbModel.gql("WHERE key=:1", row).fetch(1)
#mydbobject = DbModel.gql("WHERE key=:1", int(row)).fetch(1)#invalid literal for int() with base 10
#print mydbobject,row
que = db.Query(DbModel)
results = que.fetch(100)
mydbobject = None
for item in results:
if item.key().__str__() in row:
mydbobject = item
EDIT1- one more attempt that does not retrieve the record, the key exists in the Datastore along with the record
mydbobject = DbModel.gql("WHERE key = KEY('%s')"%row).fetch(1)
Am I correct in my assumption that you're basically just want to retrieve an object with a particular key? If so, the get and get_by_id methods may be of help:
mydbobject = DbModel.get_by_id(int(self.request.get("selectedrow")))
The error "invalid literal for int()" indicate that the paramater pass to int was not a string representing an integer. Try to print the value of "row" for debuging, I bet it is an empty string.
The correct way to retrieve an element from the key is simply by using the method "get" or "get_by_id".
In your case:
row = self.request.get("selectedrow")
mydbobject = DbModel.get(row)

Categories