Flask API ignoring elif and else statements - python

I am writing a flask API that receives different types of nested json files. I want to do something based on different information from said files.
I sort the files based on an if statement, this is the simplified version:
if (jsonFile['data']['shape'] == "cube"):
function(jsonFile)
elif (jsonFile['data']['shape'] == "cone"):
function(jsonFile)
elif (jsonFile['data']['sphere']):
function(jsonFile)
else:
print("Unknown file")
When I send a nested json file through postman, for example one containing the sphere, I get a 500 error "KeyError: shape" and I never reach the elif statement.
If I switch the elif statement containing the sphere with the one at the top, then only the sphere works and the rest do not. It only works for the if statement at the top, if the condition is not satisfied, it throws an error and ignores the rest of the block. Even when I send something random, I never get to the else statement.
Rest of the statements all work on their own.
Example of json file containing cube:
{
"data": {
"shape": "cube"
}
}
Example of json file containing sphere:
{
"data": {
"sphere": {
"description": "spherical"
}
}
}
This is the full error:
ERROR in app: Exception on /processshape [POST]
Traceback (most recent call last):
File "C:\Users\user1\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\user1\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\user1\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "d:\python\shape-api\app.py", line 34, in processshape
if (resp['data']['shape'] == "cube"):
KeyError: 'shape'
127.0.0.1 - - [02/Feb/2023 00:03:38] "POST /processshape HTTP/1.1" 500 -

The issue is that the if (jsonFile['data']['shape'] == "cube") is executed.
This will execute the expression jsonFile['data']['shape'].
jsonFile['data'] will evaluate to a dict.
However, this dict does not contain the key shape.
Thus, a KeyError will be thrown and the elif will not be executed.
You could fix it by changing
if (jsonFile['data']['shape'] == "cube")
to
if ('shape' in jsonFile['data'] and jsonFile['data']['shape'] == "cube")
Such that you do not try to access the value for the key shape if it doesn't exist.
The same change must be applied to the other cases as well.
If it is not certain that the key data is always contained in jsonFile, you must also check for that.

Related

I want to make a playlist from all my liked songs on spotify with spotipy library

Since my liked songs aren't public I want spotipy to get a list from all the songs and add them to my playlist, but when I try to do that with a loop it says that the uri is incorrect, I don't know if I should use another method.
client_credentials_manager = SpotifyClientCredentials(client_id=cid, client_secret=secret)
scope = 'user-library-read playlist-modify-public'
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager,auth_manager=SpotifyOAuth(scope=scope))
def show_tracks(results):
for item in results['items']:
track = item['track']
#print("%32.32s %s" % (track['artists'][0]['name'], track['name']))
sp.playlist_add_items(playlist_id, track['uri'])
results = sp.current_user_saved_tracks()
show_tracks(results)
while results['next']:
results = sp.next(results)
show_tracks(results)
The error is
HTTP Error for POST to https://api.spotify.com/v1/playlists/5ZzsovDgANZfiXgRrwq5fw/tracks returned 400 due to Invalid track uri: spotify:track:s
Traceback (most recent call last):
File "C:\Users\ferch\AppData\Local\Programs\Python\Python37\lib\site-packages\spotipy\client.py", line 245, in _internal_call
response.raise_for_status()
File "C:\Users\ferch\AppData\Local\Programs\Python\Python37\lib\site-packages\requests\models.py", line 941, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.spotify.com/v1/playlists/5ZzsovDgANZfiXgRrwq5fw/tracks
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "make_playlists.py", line 23, in <module>
show_tracks(results)
File "make_playlists.py", line 20, in show_tracks
sp.playlist_add_items(playlist_id, track['uri'])
File "C:\Users\ferch\AppData\Local\Programs\Python\Python37\lib\site-packages\spotipy\client.py", line 1025, in playlist_add_items
position=position,
File "C:\Users\ferch\AppData\Local\Programs\Python\Python37\lib\site-packages\spotipy\client.py", line 296, in _post
return self._internal_call("POST", url, payload, kwargs)
File "C:\Users\ferch\AppData\Local\Programs\Python\Python37\lib\site-packages\spotipy\client.py", line 266, in _internal_call
headers=response.headers,
spotipy.exceptions.SpotifyException: http status: 400, code:-1 - https://api.spotify.com/v1/playlists/5ZzsovDgANZfiXgRrwq5fw/tracks:
Invalid track uri: spotify:track:s, reason: None
I think this problem is because of the type of variable of track['uri']
playlist_add_items is expecting a list of URIs, URLs, or IDs to add to the playlist, but right now you're passing a single URI, which is a string like this: spotify:track:2t7rS8BHF5TmnBR5PmnnSU. The code for the spotipy library is likely doing a loop for item in items..., so when you pass it a string, it considers each character in the string as a different item. So it encounters the first character, s and tries to make a URI out of it resulting in spotify:track:s. This isn't a valid URI, so the request fails.
You can try wrapping the uri in a list like so:
for item in results['items']:
track = item['track']
# Note brackets around track['uri']
sp.playlist_add_items(playlist_id, [track['uri']])
This will handle the issue you're getting now, but you may have issues down the line making one request per track you want to add to the playlist. You could run into rate limiting issues, so I recommend trying to build a list of 100 URIs at a time, which is the max that can be sent in one request.
Keeping this in mind, we could try something like this:
def show_tracks(results):
for idx in range(0, len(results['items']), 100):
uris = [item['track']['uri'] for item in results['items'][idx:idx+100]]
sp.playlist_add_items(playlist_id, uris)
Another way to do this would be to create a list with all the uris/ids of the tracks you want to add, and then pass that list into the sp.playlist_add_items() function. This could be useful if you need the list of uris again further down the line. Like so :
uris = []
for item in results['items']:
track = item['track']
uris.append(track['uri'])
sp.playlist_add_items(playlist_id, uris)
Bear in mind, sp.playlist_add_items only lets you add <= 100 tracks at a time. i created this loop to handle adding a list of tracks no matter the size: (where songIDs is a list of song ids / uris)
i = 0
increment = 99
while i < len(songIDS)+increment:
try:
sp.playlist_add_items(playlistID, songIDS[i: i+increment])
except spotipy.exceptions.SpotifyException:
pass
i += increment
Hope this helps, i've only been using spotipy for a week myself

Python parsing Json - "X is None" doesn't catch empty objects

I am new to Python and I am trying to parse a Json file using Python.
The Json file is a nested file. While I am trying to exact the "conversation_id" item, the list that contains this item, and the list above sometimes can be empty. I am hoping to replace empty list as string "N/A", otherwise grab the item. Code I am using is as following:
for log in data['logs']:
print("Processing log "+log['log_id'])
logcolumns=[]
if log['request'] is None:
logcolumns.append("N/A")
elif log['request']['context'] is None:
logcolumns.append("N/A")
else:
logcolumns.append(log['request']['context']['conversation_id'])
try:
print("\t".join(logcolumns),file = conv_tsv)
except KeyError:pass
del logcolumns
Traceback error I got is
Processing log cafa1077-f479-4c55-ac34-3bc3ebbb41fc
Traceback (most recent call last):
File "conversation_log_2.py", line 43, in <module>
logcolumns.append(log['request']['context']['conversation_id'])
KeyError: 'conversation_id'
The "request" list that is associated with this log id is shown as below in the json file:
{"request": {"input": {}, "context": {}},
A full request list would be like this:
{"request": {"input": {"text": "haha"}, "context": {"conversation_id": "328d2320-f488-4f46-b71f-6cdfb1b79106", "system": {"dialog_stack": [{"dialog_node_s": "root"}], "dialog_turn_counter": 1, "dialog_request_counter": 1, "_node_output_map_s": "{\"Welcome\":[0,1,0]}", "branch_exited_s": "true", "branch_exited_reason_s": "completed"}}},
When I went to the output file, which is conv.tsv, there is N/A in the output.
You seem to have the syntax quite moodled up. Is the try/except supposed to be wrapping the if/elif? Do you actually want if/elifs?
Note that log['request'] is None does not test that the key's value is an empty dict.
You can use the .get method that returns a default when the key is not found:
logcolumns.append(log.get('request', {}).get('context', {}).get('conversation', 'N/A'))
Or better still, use a try/except to append the default value if any of the keys in missing:
try:
logcolumns.append(log['request']['context']['conversation_id'])
except KeyError:
logcolumns.append('N/A')

How to avoid or skip error 400 in python while calling the API

Note:- I have written my code after referring to few examples in stack overflow but still could not get the required output
I have a python script in which loop iterates with an Instagram API. I give the user_id as an input to the API which gets the no of posts, no of followers and no of following. Each time it gets a response, I load it into a JSON schema and append to lists data1, data2 and data3.
The issue is:= Some accounts are private accounts and the API call is not allowed to it. When I run the script in IDLE Python shell, its gives the error
Traceback (most recent call last):
File "<pyshell#144>", line 18, in <module>
beta=json.load(url)
File "C:\Users\rnair\AppData\Local\Programs\Python\Python35\lib\site- packages\simplejson-3.8.2-py3.5-win-amd64.egg\simplejson\__init__.py", line 455, in load
return loads(fp.read(),
File "C:\Users\rnair\AppData\Local\Programs\Python\Python35\lib\tempfile.py", line 483, in func_wrapper
return func(*args, **kwargs)
**ValueError: read of closed file**
But the JSON contains this:-
{
"meta": {
"error_type": "APINotAllowedError",
"code": 400,
"error_message": "you cannot view this resource"
}
}
My code is:-
for r in range(307,601):
var=r,sheet.cell(row=r,column=2).value
xy=var[1]
ij=str(xy)
if xy=="Account Deleted":
data1.append('null')
data2.append('null')
data3.append('null')
continue
myopener=Myopen()
try:
url=myopener.open('https://api.instagram.com/v1/users/'+ij+'/?access_token=641567093.1fb234f.a0ffbe574e844e1c818145097050cf33')
except urllib.error.HTTPError as e: // I want the change here
data1.append('Private Account')
data2.append('Private Account')
data3.append('Private Account')
continue
beta=json.load(url)
item=beta['data']['counts']
data1.append(item['media'])
data2.append(item['followed_by'])
data3.append(item['follows'])
I am using Python version 3.5.2. The main question is If the loop runs and a particular call is blocked and getting this error, how to avoid it and keep running the next iterations? Also, if the account is private, I want to append "Private account" to the lists.
Looks like the code that is actually fetching the URL is within your custom type - "Myopen" (which is not shown). It also looks like its not throwing the HTTPError you are expecting since your "json.load" line is still being executed (and leading to the ValueError that is being thrown).
If you want your error handling block to fire, you would need to check the response status code to see if its != 200 within Myopen and throw the HTTPError you are expecting instead of whatever its doing now.
I'm not personally familiar with FancyURLOpener, but it looks like it supports a getcode method. Maybe try something like this instead of expecting an HTTPError:
url = myopener.open('yoururl')
if url.getcode() == 400:
data1.append('Private Account')
data2.append('Private Account')
data3.append('Private Account')
continue

alchemyapi-recipes-twitter -Doesnot work properly

The github link for the code is given below:
https://github.com/AlchemyAPI/alchemyapi-recipes-twitter
I get the following error when I run recipe.py:
Traceback (most recent call last):
File "recipe.py", line 340, in <module>
main(sys.argv[1], int(sys.argv[2]))
File "recipe.py", line 43, in main
print_results()
File "recipe.py", line 303, in print_results
avg_pos_score = mean_results['result'][2]['avgScore']
TypeError: 'CommandCursor' object has no attribute '__getitem__'
I am using python version 2.7.6
Please do help me out to solve this.
Yeah, I finally got the correct output.Thanks to Games Brainiac for helping me to figure it out.
mean_results = list(tweets.aggregate([{"$group" : {"_id": "$sentiment",
"avgScore" : { "$avg" : "$score"}}}]))
avg_pos_score = mean_results[1]['avgScore']
avg_neg_score = mean_results[0]['avgScore']
The mean_results will contain a list of dictionary entities(in this case 3 entities-neg,pos,neutral).
So mean_results[0] refers to the negative entity.
mean_results[1] refers to the positive entity.
and so on.
mean_results[1]['avgScore]=avg score of the positive entity.
and so on...
I think you need to change line 301 to 304 to reflect the new changes in the API.
Firstly, change this line:
mean_results = tweets.aggregate([{"$group" : {"_id": "$sentiment", "avgScore" : { "$avg" : "$score"}}}])
to
mean_results = list(tweets.agg....)
So now, you no longer need to use the result for the CommandCursor.
Instead, what you have to do is this:
list(mean_results[2]['avgScore'])
Instead, and repeat with the next line too. Just remove the result part.

Google app engine key value error

I am writing a google app engine app and I have this key value error upon requests coming in
from the backtrace I just access and cause the key error
self.request.headers
entire code snippet is here, I just forward the headers unmodified
response = fetch( "%s%s?%s" % (
self.getApiServer() ,
self.request.path.replace("/twitter/", ""),
self.request.query_string
),
self.request.body,
method,
self.request.headers,
)
and get method handling the request calling proxy()
# handle http get
def get(self, *args):
parameters = self.convertParameters(self.request.query_string)
# self.prepareHeader("GET", parameters)
self.request.query_string = "&".join("%s=%s" % (quote(key) , quote(value)) for key, value in parameters.items())
self.proxy(GET, *args)
def convertParameters(self, source):
parameters = {}
for pairs in source.split("&"):
item = pairs.split("=")
if len(item) == 2:
parameters[item[0]] = unquote(item[1])
return parameters
the error back trace:
'CONTENT_TYPE'
Traceback (most recent call last):
File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 513, in __call__
handler.post(*groups)
File "/base/data/home/apps/waytosing/1.342850593213842824/com/blogspot/zizon/twitter/RestApiProxy.py", line 67, in post
self.proxy(POST, *args)
File "/base/data/home/apps/waytosing/1.342850593213842824/com/blogspot/zizon/twitter/RestApiProxy.py", line 47, in proxy
self.request.headers,
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/urlfetch.py", line 240, in fetch
allow_truncated, follow_redirects)
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/urlfetch.py", line 280, in make_fetch_call
for key, value in headers.iteritems():
File "/base/python_runtime/python_dist/lib/python2.5/UserDict.py", line 106, in iteritems
yield (k, self[k])
File "/base/python_runtime/python_lib/versions/1/webob/datastruct.py", line 40, in __getitem__
return self.environ[self._trans_name(item)]
KeyError: 'CONTENT_TYPE'
Any idea why it happens or is this a known bug?
This looks weird. The docs mention that response "Headers objects do not raise an error when you try to get or delete a key that isn't in the wrapped header list. Getting a nonexistent header just returns None". It's not clear from the request documentation if request.headers are also objects of this class, but even they were regular dictionaries, iteritems seems to be misbehaving. So this might be a bug.
It might be worth inspecting self.request.headers, before calling fetch, and see 1) its actual type, 2) its keys, and 3) if trying to get self.request.headers['CONTENT_TYPE'] raises an error then.
But, if you simply want to solve your problem and move forward, you can try to bypass it like:
if 'CONTENT_TYPE' not in self.request.headers:
self.request.headers['CONTENT_TYPE'] = None
(I'm suggesting setting it to None, because that's what a response Header object should return on non-existing keys)
Here's my observation about this problem:
When the content-type is application/x-www-form-urlencoded and POST data is empty (e.g. jquery.ajax GET, twitter's favorite and retweet API...), the content-type is dropped by Google appengine.
You can add:
self.request.headers.update({'content-type':'application/x-www-form-urlencoded'})
before urlfetch.
Edit: indeed, looking at the error more carefully, it doesn't seem to be related to convertParameters, as the OP points out in the comments. I'm retiring this answer.
I'm not entirely sure what you mean by "just forward the headers unmodified", but have you taken a look at self.request.query_string before and after you call convertParameters? More to the point, you're leaving out any (valid) GET parameters of the form "key=" (that is, keys with empty values).
Maybe your original query_string had a value like "CONTENT_TYPE=", and your convertParameters is stripping it out.
Known issue http://code.google.com/p/googleappengine/issues/detail?id=3427 and potential workarounds here http://code.google.com/p/googleappengine/issues/detail?id=2040

Categories