python: argument generated by a prior function error - python

so this is probably very simple but it's confusing me.
I have a function that takes in a txt file in JSON form and sorts it in descending order of bandwidth. The function is:
def sort_guards_with_input(guards):
json_source = json.dumps(guards)
data = json.loads(str(json_source))
data['relays'].sort(key=lambda item: item['bandwidth'], reverse=True)
data = json.dumps(data)
return data
segundo = sort_guards_with_input("the original txt file")
..and this returns the sorted file of the form (lets call it TEXT):
{"relays": [{"nickname": "Snowden4ever pd7wih1gdUU8bLhWsvH6QHDWfs8",
"bandwidth": 201000, "type": ["Fast", "Guard", "HSDir", "Named", "Running",
"Stable", "V2Dir", "Valid"]},{"nickname": "rmblue jMdIu0VZYE+S2oeHShQBAHsdj80",
"bandwidth": 8, "type": ["Fast", "Guard", "HSDir", "Running", "Stable", "Unnamed",
"V2Dir", "Valid"]}]}
Now I have a function that pulls out the banwidth and nickname and creates a list. The function is:
def get_sorted_names_bw(guards):
sorted_guards_bw = list(entry['bandwidth'] for entry in guards["relays"])
sorted_guards_names = list(d['nickname'] for d in guards["relays"])
temps = [None]*(len(sorted_guards_bw)+len(sorted_guards_names))
temps[::2] = sorted_guards_bw
temps[1::2] = sorted_guards_names
sorted_grds_w_names = [temps[i:i+2] for i in range(0, len(temps), 2)]
return sorted_grds_w_names
The problem is when I try and print the result of get_sorted_names_bw by doing:
print get_sorted_names_bw(segundo)
.. I get the error:
sorted_guards_bw = list(entry['bandwidth'] for entry in guards["relays"])
TypeError: string indices must be integers, not str
But if i try and print the the result of get_sorted_names_bw with copy and pasting TEXT as the argument it returns a result (the wrong one because nicknames and bandwidths are mixed up, that's another problem I'll deal with myself, unless the reader is feeling very kind and wants to help with that too :) ). Namely:
[[201000, 'rmblue jMdIu0VZYE+S2oeHShQBAHsdj80'], [8, 'Snowden4ever pd7wih1gdUU8bLhWsvH6QHDWfs8']]
Why do I get an error when I try use an argument generated by a prior function but don't get an error when I just copy and paste the argument?
Thanks and sorry for the long post.

Your function sort_guards_with_input dumps the data to a JSON string and returns that string. But get_sorted_names_bw assumes it is receiving the actual data (as a dict), not a string representation of it. The easiest thing is probably to just have sort_guards_with_input return data without dumping it to JSON. That is:
def sort_guards_with_input(guards):
json_source = json.dumps(guards)
data = json.loads(str(json_source))
data['relays'].sort(key=lambda item: item['bandwidth'], reverse=True)
return data

Related

List slicing a json.loads file

What this code does it gets the values of a json.loads file. It gives me a list of dictionary that are organized by dates. This code works, my understanding is, i am taking the the first value in the list of dictionaries, so the first dictionary, but shouldn't. self.get_jsonparsed_data(self.ticker_text.get().upper())[0] work as well? In my case it doesn't, I was hoping if someone can explain why I does not work.
def get_jsonparsed_data(self, ticker):
#quote
url = (f"https://financialmodelingprep.com/api/v3/quote/{ticker}?)
response = urlopen(url)
data = response.read().decode("utf-8")
return json.loads(data)
def search_info(self):
#self.info.delete(0, END)
recent_filing = []
for header in self.get_jsonparsed_data(self.ticker_text.get().upper())[:1]:
recent_filing.append(header)
ticker = self.ticker_text.get()
#output dictionary values with proper format
try:
recent_filing_dict = recent_filing[0]
This works.
I get the first dictionary which is what i want but when i do self.get_jsonparsed_data(self.ticker_text.get().upper())[0] instead of self.get_jsonparsed_data(self.ticker_text.get().upper())[:1] it gives me an error
which pretty much is saying there isnt any values appended to recent_filing_dict. I was just hoping if someone can explain why?
"for" loops through iterable and self.get_jsonparsed_data(self.ticker_text.get().upper())[0] seemingly returns an item rather than iterable (list) while self.get_jsonparsed_data(self.ticker_text.get().upper())[:1] returns an iterable (single item list) which is iterated over by for loop

txt with str of dict into dict [duplicate]

I am trying to pass in a JSON file and convert the data into a dictionary.
So far, this is what I have done:
import json
json1_file = open('json1')
json1_str = json1_file.read()
json1_data = json.loads(json1_str)
I'm expecting json1_data to be a dict type but it actually comes out as a list type when I check it with type(json1_data).
What am I missing? I need this to be a dictionary so I can access one of the keys.
Your JSON is an array with a single object inside, so when you read it in you get a list with a dictionary inside. You can access your dictionary by accessing item 0 in the list, as shown below:
json1_data = json.loads(json1_str)[0]
Now you can access the data stored in datapoints just as you were expecting:
datapoints = json1_data['datapoints']
I have one more question if anyone can bite: I am trying to take the average of the first elements in these datapoints(i.e. datapoints[0][0]). Just to list them, I tried doing datapoints[0:5][0] but all I get is the first datapoint with both elements as opposed to wanting to get the first 5 datapoints containing only the first element. Is there a way to do this?
datapoints[0:5][0] doesn't do what you're expecting. datapoints[0:5] returns a new list slice containing just the first 5 elements, and then adding [0] on the end of it will take just the first element from that resulting list slice. What you need to use to get the result you want is a list comprehension:
[p[0] for p in datapoints[0:5]]
Here's a simple way to calculate the mean:
sum(p[0] for p in datapoints[0:5])/5. # Result is 35.8
If you're willing to install NumPy, then it's even easier:
import numpy
json1_file = open('json1')
json1_str = json1_file.read()
json1_data = json.loads(json1_str)[0]
datapoints = numpy.array(json1_data['datapoints'])
avg = datapoints[0:5,0].mean()
# avg is now 35.8
Using the , operator with the slicing syntax for NumPy's arrays has the behavior you were originally expecting with the list slices.
Here is a simple snippet that read's in a json text file from a dictionary. Note that your json file must follow the json standard, so it has to have " double quotes rather then ' single quotes.
Your JSON dump.txt File:
{"test":"1", "test2":123}
Python Script:
import json
with open('/your/path/to/a/dict/dump.txt') as handle:
dictdump = json.loads(handle.read())
You can use the following:
import json
with open('<yourFile>.json', 'r') as JSON:
json_dict = json.load(JSON)
# Now you can use it like dictionary
# For example:
print(json_dict["username"])
The best way to Load JSON Data into Dictionary is You can user the inbuilt json loader.
Below is the sample snippet that can be used.
import json
f = open("data.json")
data = json.load(f))
f.close()
type(data)
print(data[<keyFromTheJsonFile>])
I am working with a Python code for a REST API, so this is for those who are working on similar projects.
I extract data from an URL using a POST request and the raw output is JSON. For some reason the output is already a dictionary, not a list, and I'm able to refer to the nested dictionary keys right away, like this:
datapoint_1 = json1_data['datapoints']['datapoint_1']
where datapoint_1 is inside the datapoints dictionary.
pass the data using javascript ajax from get methods
**//javascript function
function addnewcustomer(){
//This function run when button click
//get the value from input box using getElementById
var new_cust_name = document.getElementById("new_customer").value;
var new_cust_cont = document.getElementById("new_contact_number").value;
var new_cust_email = document.getElementById("new_email").value;
var new_cust_gender = document.getElementById("new_gender").value;
var new_cust_cityname = document.getElementById("new_cityname").value;
var new_cust_pincode = document.getElementById("new_pincode").value;
var new_cust_state = document.getElementById("new_state").value;
var new_cust_contry = document.getElementById("new_contry").value;
//create json or if we know python that is call dictionary.
var data = {"cust_name":new_cust_name, "cust_cont":new_cust_cont, "cust_email":new_cust_email, "cust_gender":new_cust_gender, "cust_cityname":new_cust_cityname, "cust_pincode":new_cust_pincode, "cust_state":new_cust_state, "cust_contry":new_cust_contry};
//apply stringfy method on json
data = JSON.stringify(data);
//insert data into database using javascript ajax
var send_data = new XMLHttpRequest();
send_data.open("GET", "http://localhost:8000/invoice_system/addnewcustomer/?customerinfo="+data,true);
send_data.send();
send_data.onreadystatechange = function(){
if(send_data.readyState==4 && send_data.status==200){
alert(send_data.responseText);
}
}
}
django views
def addNewCustomer(request):
#if method is get then condition is true and controller check the further line
if request.method == "GET":
#this line catch the json from the javascript ajax.
cust_info = request.GET.get("customerinfo")
#fill the value in variable which is coming from ajax.
#it is a json so first we will get the value from using json.loads method.
#cust_name is a key which is pass by javascript json.
#as we know json is a key value pair. the cust_name is a key which pass by javascript json
cust_name = json.loads(cust_info)['cust_name']
cust_cont = json.loads(cust_info)['cust_cont']
cust_email = json.loads(cust_info)['cust_email']
cust_gender = json.loads(cust_info)['cust_gender']
cust_cityname = json.loads(cust_info)['cust_cityname']
cust_pincode = json.loads(cust_info)['cust_pincode']
cust_state = json.loads(cust_info)['cust_state']
cust_contry = json.loads(cust_info)['cust_contry']
#it print the value of cust_name variable on server
print(cust_name)
print(cust_cont)
print(cust_email)
print(cust_gender)
print(cust_cityname)
print(cust_pincode)
print(cust_state)
print(cust_contry)
return HttpResponse("Yes I am reach here.")**

Extracting data from a json file into a csv

I am new to dealing with json files and I am hoping for some help.
Here is a part of the json file (since it would be way too much for me to post it all) that I am dealing with
[{"id":804,"name":{"english":"Naganadel","japanese":"\u30a2\u30fc\u30b4\u30e8\u30f3"},"type":["Poison","Dragon"],"base":{"HP":73,"Attack":73,"Defense":73,"Sp. Attack":127,"Sp. Defense":73,"Speed":121}},{"id":805,"name":{"english":"Stakataka","japanese":"\u30c4\u30f3\u30c7\u30c4\u30f3\u30c7"},"type":["Rock","Steel"],"base":{"HP":61,"Attack":131,"Defense":211,"Sp. Attack":53,"Sp. Defense":101,"Speed":13}},{"id":806,"name":{"english":"Blacephalon","japanese":"\u30ba\u30ac\u30c9\u30fc\u30f3"},"type":["Fire","Ghost"],"base":{"HP":53,"Attack":127,"Defense":53,"Sp. Attack":151,"Sp. Defense":79,"Speed":107}},{"id":807,"name":{"english":"Zeraora","japanese":"\u30bc\u30e9\u30aa\u30e9"},"type":["Electric"],"base":{"HP":88,"Attack":112,"Defense":75,"Sp. Attack":102,"Sp. Defense":80,"Speed":143}},{"id":808,"name":{"english":"Meltan","japanese":"\u30e1\u30eb\u30bf\u30f3"},"type":["Steel"],"base":{"HP":46,"Attack":65,"Defense":65,"Sp. Attack":55,"Sp. Defense":35,"Speed":34}},{"id":809,"name":{"english":"Melmetal","japanese":"\u30e1\u30eb\u30e1\u30bf\u30eb"},"type":["Steel"],"base":{"HP":135,"Attack":143,"Defense":143,"Sp. Attack":80,"Sp. Defense":65,"Speed":34}}]
I am attempting to take the id, name, type, base, hp, attack, defense, and speed of each pokemon. I attached what I currently have which include my attempting to take the id and print it.
When I run this file I get list indices must be integers or slices, not str.
import json
def main():
f = open('pokedex.json')
data = json.load(f)
f.close()
#print data
id_poke = data['_embedded']['id_poke']
id_info = []
for i in id_poke:
id_poke.append(i['id'])
if __name__ == '__main__':
main()
Take a look at the json sample you included in your question: It starts with a [, meaning it is a list, not a dictionary. When you assign this object to the variable data and then try to index into this list with the (string) key _embedded, you get the error you saw.
I don't know how you expected this to work since your json file has neither _embedded nor id_poke as keys, but to get you started, here's how to print out the numeric id and English name of each object; you can take it from there.
for poke in data: # magic iteration over a list: data[0], data[1] etc.
print(poke["id"], poke["name"]["english"])
Declare
id_poke = data['_embedded']['id_poke']
As str()

Yet another Python looping over JSON array

I spent several hours on this, tried everything I found online, pulled some of the hair left on my head...
I have this JSON sent to a Flask webservice I'm writing :
{'jsonArray': '[
{
"nom":"0012345679",
"Start":"2018-08-01",
"Finish":"2018-08-17",
"Statut":"Validee"
},
{
"nom":"0012345679",
"Start":"2018-09-01",
"Finish":"2018-09-10",
"Statut":"Demande envoyée au manager"
},
{
"nom":"0012345681",
"Start":"2018-04-01",
"Finish":"2018-04-08",
"Statut":"Validee"
},
{
"nom":"0012345681",
"Start":"2018-07-01",
"Finish":"2018-07-15",
"Statut":"Validee"
}
]'}
I want to simply loop through the records :
app = Flask(__name__)
#app.route('/graph', methods=['POST'])
def webhook():
if request.method == 'POST':
req_data = request.get_json()
print(req_data) #-> shows JSON that seems to be right
##print(type(req_data['jsonArray']))
#j1 = json.dumps(req_data['jsonArray'])
#j2 = json.loads(req_data['jsonArray'])
#data = json.loads(j1)
#for rec in data:
# print(rec) #-> This seems to consider rec as one of the characters of the whole JSON string, and prints every character one by one
#for key in data:
# value = data[key]
# print("The key and value are ({}) = ({})".format(key, value)) #-> TypeError: string indices must be integers
for record in req_data['jsonArray']:
for attribute, value in rec.items(): #-> Gives error 'str' object has no attribute 'items'
print(attribute, value)
I believe I am lost between JSON object, python dict object, strings, but I don't know what I am missing. I really tried to put the JSON received through json.dumps and json.loads methods, but still nothing. What am I missing ??
I simply want to loop through each record to create another python object that I will feed to a charting library like this :
df = [dict(Task="0012345678", Start='2017-01-01', Finish='2017-02-02', Statut='Complete'),
dict(Task="0012345678", Start='2017-02-15', Finish='2017-03-15', Statut='Incomplete'),
dict(Task="0012345679", Start='2017-01-17', Finish='2017-02-17', Statut='Not Started'),
dict(Task="0012345679", Start='2017-01-17', Finish='2017-02-17', Statut='Complete'),
dict(Task="0012345680", Start='2017-03-10', Finish='2017-03-20', Statut='Not Started'),
dict(Task="0012345680", Start='2017-04-01', Finish='2017-04-20', Statut='Not Started'),
dict(Task="0012345680", Start='2017-05-18', Finish='2017-06-18', Statut='Not Started'),
dict(Task="0012345681", Start='2017-01-14', Finish='2017-03-14', Statut='Complete')]
The whole thing is wrapped in single quotes, meaning it's a string and you need to parse it.
for record in json.loads(req_data['jsonArray']):
Looking at your commented code, you did this:
j1 = json.dumps(req_data['jsonArray'])
data = json.loads(j1)
Using json.dumps on a string is the wrong idea, and moreover json.loads(json.dumps(x)) is just the same as x, so that just got you back where you started, i.e. data was the same thing as req_data['jsonArray'] (a string).
This was the right idea:
j2 = json.loads(req_data['jsonArray'])
but you never used j2.
As you've seen, iterating over a string gives you each character of the string.

Why am I seeing "TypeError: string indices must be integers"?

I'm playing with both learning Python and am trying to get GitHub issues into a readable form. Using the advice on How can I convert JSON to CSV?, I came up with this:
import json
import csv
f = open('issues.json')
data = json.load(f)
f.close()
f = open("issues.csv", "wb+")
csv_file = csv.writer(f)
csv_file.writerow(["gravatar_id", "position", "number", "votes", "created_at", "comments", "body", "title", "updated_at", "html_url", "user", "labels", "state"])
for item in data:
csv_file.writerow([item["gravatar_id"], item["position"], item["number"], item["votes"], item["created_at"], item["comments"], item["body"], item["title"], item["updated_at"], item["html_url"], item["user"], item["labels"], item["state"]])
Where "issues.json" is the JSON file containing my GitHub issues. When I try to run that, I get
File "foo.py", line 14, in <module>
csv_file.writerow([item["gravatar_id"], item["position"], item["number"], item["votes"], item["created_at"], item["comments"], item["body"], item["title"], item["updated_at"], item["html_url"], item["user"], item["labels"], item["state"]])
TypeError: string indices must be integers
What am I missing here? Which are the "string indices"? I'm sure that once I get this working I'll have more issues, but for now, I'd just love for this to work!
When I tweak the for statement to simply
for item in data:
print item
what I get is ... "issues" -- so I'm doing something more basic wrong. Here's a bit of my JSON content:
{"issues": [{"gravatar_id": "44230311a3dcd684b6c5f81bf2ec9f60", "position": 2.0, "number": 263, "votes": 0, "created_at": "2010/09/17 16:06:50 -0700", "comments": 11, "body": "Add missing paging (Older>>) links...
when I print data, it looks like it is getting munged really oddly:
{u'issues': [{u'body': u'Add missing paging (Older>>) lin...
The variable item is a string. An index looks like this:
>>> mystring = 'helloworld'
>>> print mystring[0]
'h'
The above example uses the 0 index of the string to refer to the first character.
Strings can't have string indices (like dictionaries can). So this won't work:
>>> mystring = 'helloworld'
>>> print mystring['stringindex']
TypeError: string indices must be integers
item is most likely a string in your code; the string indices are the ones in the square brackets, e.g., gravatar_id. So I'd first check your data variable to see what you received there; I guess that data is a list of strings (or at least a list containing at least one string) while it should be a list of dictionaries.
TypeError for Slice Notation str[a:b]
Short Answer
Use a colon : instead of a comma , in between the two indices a and b in str[a:b]:
my_string[0,5] # wrong ❌
my_string[0:5] # correct ✅
Long Answer
When working with strings and slice notation (a common sequence operation), it can happen that a TypeError is raised, pointing out that the indices must be integers, even if they obviously are.
Example
>>> my_string = "Hello, World!"
>>> my_string[0,5]
TypeError: string indices must be integers
We obviously passed two integers for the indices to the slice notation, right? So what is the problem here?
This error can be very frustrating - especially at the beginning of learning Python - because the error message is a little bit misleading.
Explanation
We implicitly passed a tuple of two integers to the slice notation when we called my_string[0,5]. 0,5 evaluates to the same tuple as (0,5) does - even without the parentheses. Why though?
A trailing comma , is actually enough for the Python interpreter to evaluate something as a tuple:
>>> my_variable = 0,
>>> type(my_variable)
<class 'tuple'>
So what we did there, this time explicitly:
>>> my_string = "Hello, World!"
>>> my_tuple = 0, 5
>>> my_string[my_tuple]
TypeError: string indices must be integers
Now, at least, the error message makes sense.
Solution
We need to replace the comma , with a colon : to separate the two integers correctly, not having them interpreted as a tuple:
>>> my_string = "Hello, World!"
>>> my_string[0:5]
'hello'
A clearer and more helpful error message could have been something like:
TypeError: string indices must be integers not tuple
^^^^^
(actual type here)
A good error message should show the user directly what they did wrong! With this kind of information it would have been much more easier to find the root cause and solve the problem - and you wouldn't have had to come here.
So next time, when you find yourself responsible for writing error description messages, remind yourself of this example and add the reason (or other useful information) to error message! Help other people (or maybe even your future self) to understand what went wrong.
Lessons learned
slice notation uses colons : to separate its indices (and step range, i.e., str[from:to:step])
tuples are defined by commas , (i.e., t = 1,)
add some information to error messages for users to understand what went wrong
data is a dict object. So, iterate over it like this:
Python 2
for key, value in data.iteritems():
print key, value
Python 3
for key, value in data.items():
print(key, value)
I had a similar issue with Pandas, you need to use the iterrows() function to iterate through a Pandas dataset Pandas documentation for iterrows
data = pd.read_csv('foo.csv')
for index,item in data.iterrows():
print('{} {}'.format(item["gravatar_id"], item["position"]))
note that you need to handle the index in the dataset that is also returned by the function.
As a rule of thumb, when I receive this error in Python I compare the function signature with the function execution.
For example:
def print_files(file_list, parent_id):
for file in file_list:
print(title: %s, id: %s' % (file['title'], file['id']
So if I'll call this function with parameters placed in the wrong order and pass the list as the 2nd argument and a string as the 1st argument:
print_files(parent_id, list_of_files) # <----- Accidentally switching arguments location
The function will try to iterate over the parent_id string instead of file_list and it will expect to see the index as an integer pointing to the specific character in string and not an index which is a string (title or id).
This will lead to the TypeError: string indices must be integers error.
Due to its dynamic nature (as opposed to languages like Java, C# or Typescript), Python will not inform you about this syntax error.
How to read the first element of this JSON?
when the file appears like this
for i in data[1]:
print("Testing"+i['LocalObservationDateTime'])
This is not working for me.
Below is the JSON file
[
{
"LocalObservationDateTime":"2022-09-15T19:05:00+02:00",
"EpochTime":1663261500,
"WeatherText":"Mostly cloudy",
"WeatherIcon":6,
"HasPrecipitation":false,
"PrecipitationType":"None",
"IsDayTime":true,
"Temperature":{
"Metric":{
"Value":11.4,
"Unit":"C",
"UnitType":17
},
"Imperial":{
"Value":52.0,
"Unit":"F",
"UnitType":18
}
},
"RealFeelTemperature":{
"Metric":{
"Value":8.4,
"Unit":"C",
"UnitType":17,
"Phrase":"Chilly"
}
}
},
{
"LocalObservationDateTime":"2022-09-16T19:05:00+02:00",
"EpochTime":1663261500,
"WeatherText":"Mostly cloudy",
"WeatherIcon":6,
"HasPrecipitation":false,
"PrecipitationType":"None",
"IsDayTime":true,
"Temperature":{
"Metric":{
"Value":11.4,
"Unit":"C",
"UnitType":17
},
"Imperial":{
"Value":52.0,
"Unit":"F",
"UnitType":18
}
},
"RealFeelTemperature":{
"Metric":{
"Value":8.4,
"Unit":"C",
"UnitType":17,
"Phrase":"Chilly"
}
}
}
]
This can happen if a comma is missing. I ran into it when I had a list of two-tuples, each of which consisted of a string in the first position, and a list in the second. I erroneously omitted the comma after the first component of a tuple in one case, and the interpreter thought I was trying to index the first component.
Converting the lower case letters to upper:
str1 = "Hello How are U"
new_str = " "
for i in str1:
if str1[i].islower():
new_str = new_str + str1[i].upper()
print(new_str)
Error :
TypeError: string indices must be integers
Solution :
for i in range(0, len(str1))
// Use range while iterating the string.

Categories