My intersection() method returns an error - python

I have tried to make a piece of code that shows me only the common values of user input as compared to a set list. I continue to get the error:
TypeError: unhashable type: 'list'
Here's what I've done:
main_List = ["name", "job", "backstory", "all"]
provided_List = []
def main()
resp = input("Do you need a name, job, backstory, or all?")
provided_List.append(resp.split())
update_Set = provided_List.intersection(main_List)
print(update_Set)
main()
Essentially, I'm trying to ignore everything but key words the user inputs. As far as I can tell I am doing everything exactly like the examples but it still isn't coming out the way I want. I'm not sure what I'm missing here.

You are attempting to use set methods on list objects. You need to cast both main_list and provided_list as set objects:
main_options = {"name", "job", "backstory", "all"}
prompt = "Select any of name, job, backstory, or all: "
resp = main_options & set(input(prompt).split())
Usage:
Select any of name, job, backstory, or all: name
# resp: {'name'}
Select any of name, job, backstory, or all:
# resp: set()
Select any of name, job, backstory, or all: name backstory job
# resp: {'backstory', 'job', 'name'}

Related

Issue with 'else' sequence using Spotipy/Spotify API

My team and I (newbies to python) have written the following code to generate spotify songs related to a specific city and related terms.
If the user inputs a city that is not in our CITY_KEY_WORDS list, then it tells the user that the input will be added to a requests file, and then writes the input to a file.
The code is as follows:
from random import shuffle
from typing import Any, Dict, List
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
sp = spotipy.Spotify(
auth_manager=SpotifyClientCredentials(client_id="",
client_secret="")
)
CITY_KEY_WORDS = {
'london': ['big ben', 'fuse'],
'paris': ['eiffel tower', 'notre dame', 'louvre'],
'manhattan': ['new york', 'new york city', 'nyc', 'empire state', 'wall street', ],
'rome': ['colosseum', 'roma', 'spanish steps', 'pantheon', 'sistine chapel', 'vatican'],
'berlin': ['berghain', 'berlin wall'],
}
def main(city: str, num_songs: int) -> List[Dict[str, Any]]:
if city in CITY_KEY_WORDS:
"""Searches Spotify for songs that are about `city`. Returns at most `num_songs` tracks."""
results = []
# Search for songs that have `city` in the title
results += sp.search(city, limit=50)['tracks']['items'] # 50 is the maximum Spotify's API allows
# Search for songs that have key words associated with `city`
if city.lower() in CITY_KEY_WORDS.keys():
for related_term in CITY_KEY_WORDS[city.lower()]:
results += sp.search(related_term, limit=50)['tracks']['items']
# Shuffle the results so that they are not ordered by key word and return at most `num_songs`
shuffle(results)
return results[: num_songs]
else:
print("Unfortunately, this city is not yet in our system. We will add it to our requests file.")
with open('requests.txt', 'r') as text_file:
request = text_file.read()
request = request + city + '\n'
with open('requests.txt', 'w+') as text_file:
text_file.write(request)
def display_tracks(tracks: List[Dict[str, Any]]) -> None:
"""Prints the name, artist and URL of each track in `tracks`"""
for num, track in enumerate(tracks):
# Print the relevant details
print(f"{num + 1}. {track['name']} - {track['artists'][0]['name']} {track['external_urls']['spotify']}")
if __name__ == '__main__':
city = input("Virtual holiday city? ")
number_of_songs = input("How many songs would you like? ")
tracks = main(city, int(number_of_songs))
display_tracks(tracks)
The code runs fine for the "if" statement (if someone enters a city we have listed). But when the else statement is run, 2 errors come up after the actions have been executed ok (it prints and writes the user's input into a file).
The errors that come up are:
Traceback (most recent call last):
File "...", line 48, in <module>
display_tracks(tracks)
File "...", line 41, in display_tracks
for num, track in enumerate(tracks):
TypeError: 'NoneType' object is not iterable
Please excuse my lack of knowledge, but please could someone help with this issue?
We would also like to create a playlist of the songs at the end, however have been facing difficulties with this.
Your main function does not have a return statement in the else clause and that causes tracks to be None. Iterating on tracks when it's None is what's causing the error.
There are a few things you can do to improve the code:
separation of concerns: the main function is doing two different things, checking the input and fetching the tracks.
do .lower() once in the beginning so you don't have to repeat it.
following documentation conventions.
checking the response before using it
some code cleaning
see below the changes I suggested above:
def fetch_tracks(city: str, num_songs: int) -> List[Dict[str, Any]]:
"""Searches Spotify for songs that are about `city`.
:param city: TODO: TBD
:param num_songs: TODO: TBD
:return: at most `num_songs` tracks.
"""
results = []
for search_term in [city, *CITY_KEY_WORDS[city]]:
response = sp.search(search_term, limit=50)
if response and 'tracks' in response and 'items' in response['tracks']:
results += response['tracks']['items']
# Shuffle the results so that they are not ordered by key word and return
# at most `num_songs`
shuffle(results)
return results[: num_songs]
def display_tracks(tracks: List[Dict[str, Any]]) -> None:
"""Prints the name, artist and URL of each track in `tracks`"""
for num, track in enumerate(tracks):
# Print the relevant details
print(
f"{num + 1}. {track['name']} - {track['artists'][0]['name']} "
f"{track['external_urls']['spotify']}")
def main():
city = input("Virtual holiday city? ")
city = city.lower()
# Check the input city and handle unsupported cities.
if city not in CITY_KEY_WORDS:
print("Unfortunately, this city is not yet in our system. "
"We will add it to our requests file.")
with open('requests.txt', 'a') as f:
f.write(f"{city}\n")
exit()
number_of_songs = input("How many songs would you like? ")
tracks = fetch_tracks(city, int(number_of_songs))
display_tracks(tracks)
if __name__ == '__main__':
main()
When your if-statement is executed, you return a list of items and feed them into the display_tracks() function. But what happens when the else-statement is executed? You add the request to your text-file, but do not return anything (or a NoneType item) and feed that into display_tracks(). display_tracks then iterates of this NoneType-item, throwing your exception.
You only want to show the tracks if there actually are any tracks to display. One way to do this would be to move the call of display_tracks() into your main function, but then the same error would be thrown if no tracks are found to your search-terms. Another solution would be to first check if your tracks are not empty or to catch the TypeError-exception with something like
tracks = main(city, int(number_of_songs))
try:
display_tracks(tracks)
except TypeError:
pass

Python JSON scraping - how can I handle missing values?

I'm pretty new to coding, so I'm learning a lot as I go. This problem got me stumped, and even though I can find several similar questions on here, I can't find one that works or has a recognizable syntax to me.
I'm trying to scrape various user data from a JSON API, og then store those values in a MySQL database I've set up.
The code seems to run fine for the most part, but some users does not have the attributes I'm trying to scrape in the JSON, and thus I'm left with Nonetype errors that I cant seem to foil.
If possible I'd like to just store "0" in the database where the json does not contain the attribute.
In the m/snippet below this works fine for users that has a job, but users without a job returns Nonetype on jobposition and apparently breaks the loop.
response = requests.get("URL")
json_obj = json.loads(response.text)
timer = json_obj['timestamp']
jobposition = json_obj['job']['position']
query = "INSERT INTO users (timer, jobposition) VALUES (%s, %s)"
values = (timer, jobposition)
cursor = db.cursor()
cursor.execute(query, values)
db.commit()
Thanks in advance!
You can use for that the get() method of the dictionary as follow
timer = json_obj.get('timestamp', 0)
0 is the default value and in case there is no 'timestamp' attribute it will return 0.
For job position, you can do
jobposition = json_obj['job'].get('position', 0) if 'job' in json_obj else 0
Try this
try:
jobposition = json_obj['job']['position']
except:
jobposition = 0
You can more clearly declare the data schema using dataclasses:
from dataclasses import dataclass
from validated_dc import ValidatedDC
#dataclass
class Job(ValidatedDC):
name: str
position: int = 0
#dataclass
class Workers(ValidatedDC):
timer: int
job: Job
input_data = {
'timer': 123,
'job': {'name': 'driver'}
}
workers = Workers(**input_data)
assert workers.job.position == 0
https://github.com/EvgeniyBurdin/validated_dc

float() argument must be a string or a number, not 'Float'

I know this question has been asked before but none of the questions were helpful hence asking again..
I am using graphene and parsing some Elasticsearch data before passing it to Graphene
PFB :- my resolved function
def resolve_freelancers(self, info):
session = get_session()
[ids, scores] = self._get_freelancers()
freelancers = session.query(FreelancerModel).filter(FreelancerModel.id.in_(ids)).all()
for index in range(len(ids)):
print("index", scores[index])
freelancers[index].score = scores[index]
if self.sort:
reverse = self.sort.startswith("-")
self.sort = self.sort.replace("-", "")
if self.sort == "alphabetical":
freelancers = sorted(freelancers, key=lambda f: f.name if f.name else "", reverse=reverse)
if self.sort == "created":
freelancers = sorted(freelancers, key=lambda f: f.created_on, reverse=reverse)
if self.sort == "modified":
freelancers = sorted(freelancers, key=lambda f: f.modified_at, reverse=reverse)
freelancers = [Freelancer(f) for f in freelancers[self.start:self.end]]
session.close()
return freelancers
now if I do
print(freelancers[index].score)
it gives me 10.989184 and the type of this is <class 'float'>
In my class Freelancer(graphene.ObjectType):
I have added score = graphene.Float()
Now when I try to add score to my query it gives the error .. otherwise there is no issue .. all I am interested is in getting that score value in the json response .. I do not understand what is causing this error and I am fairly new to Python so any advise will be appreciated.
Please feel free to ask for additional code or information as I have tried to paste whatever I thought was relevant
So I can't comment or I would, and I very well may be wrong, but here goes.
My guess is that somewhere you are calling float(score), but the graphene.Float() type cannot be directly converted to a Python float via float(). This is probably due to the graphene.Float type having so much data it can hold in its data structure due to inheriting from graphene.Scalar (graphene GH/Scalars).
My guess would be to hunt down the float() call and remove it. If that doesn't work, I would then move onto Float.num field in your query.
Again, all conjecture here, but I hope it helped.
Actually I cannot pass the fields directly to the Graphene Object and we need to pass it within the init method of the class which has the Graphene Object and then we need to return in a resolver method ( in my case resolve_score )

I have an Error with python flask cause of an API result (probably cause of my list) and my Database

I use flask, an api and SQLAlchemy with SQLite.
I begin in python and flask and i have problem with the list.
My application work, now i try a news functions.
I need to know if my json informations are in my db.
The function find_current_project_team() get information in the API.
def find_current_project_team():
headers = {"Authorization" : "bearer "+session['token_info']['access_token']}
user = requests.get("https://my.api.com/users/xxxx/", headers = headers)
user = user.json()
ids = [x['id'] for x in user]
return(ids)
I use ids = [x['id'] for x in user] (is the same that) :
ids = []
for x in user:
ids.append(x['id'])
To get ids information. Ids information are id in the api, and i need it.
I have this result :
[2766233, 2766237, 2766256]
I want to check the values ONE by One in my database.
If the values doesn't exist, i want to add it.
If one or all values exists, I want to check and return "impossible sorry, the ids already exists".
For that I write a new function:
def test():
test = find_current_project_team()
for find_team in test:
find_team_db = User.query.filter_by(
login=session['login'], project_session=test
).first()
I have absolutely no idea to how check values one by one.
If someone can help me, thanks you :)
Actually I have this error :
sqlalchemy.exc.InterfaceError: (InterfaceError) Error binding
parameter 1 - probably unsupported type. 'SELECT user.id AS user_id,
user.login AS user_login, user.project_session AS user_project_session
\nFROM user \nWHERE user.login = ? AND user.project_session = ?\n
LIMIT ? OFFSET ?' ('my_tab_login', [2766233, 2766237, 2766256], 1, 0)
It looks to me like you are passing the list directly into the database query:
def test():
test = find_current_project_team()
for find_team in test:
find_team_db = User.query.filter_by(login=session['login'], project_session=test).first()
Instead, you should pass in the ID only:
def test():
test = find_current_project_team()
for find_team in test:
find_team_db = User.query.filter_by(login=session['login'], project_session=find_team).first()
Asides that, I think you can do better with the naming conventions though:
def test():
project_teams = find_current_project_team()
for project_team in project_teams:
project_team_result = User.query.filter_by(login=session['login'], project_session=project_team).first()
All works thanks
My code :
project_teams = find_current_project_team()
for project_team in project_teams:
project_team_result = User.query.filter_by(project_session=project_team).first()
print(project_team_result)
if project_team_result is not None:
print("not none")
else:
project_team_result = User(login=session['login'], project_session=project_team)
db.session.add(project_team_result)
db.session.commit()

Getting wrong result from JSON - Python 3

Im working on a small project of retrieving information about books from the Google Books API using Python 3. For this i make a call to the API, read out the variables and store those in a list. For a search like "linkedin" this works perfectly. However when i enter "Google", it reads the second title from the JSON input. How can this happen?
Please find my code below (Google_Results is the class I use to initialize the variables):
import requests
def Book_Search(search_term):
parms = {"q": search_term, "maxResults": 3}
r = requests.get(url="https://www.googleapis.com/books/v1/volumes", params=parms)
print(r.url)
results = r.json()
i = 0
for result in results["items"]:
try:
isbn13 = str(result["volumeInfo"]["industryIdentifiers"][0]["identifier"])
isbn10 = str(result["volumeInfo"]["industryIdentifiers"][1]["identifier"])
title = str(result["volumeInfo"]["title"])
author = str(result["volumeInfo"]["authors"])[2:-2]
publisher = str(result["volumeInfo"]["publisher"])
published_date = str(result["volumeInfo"]["publishedDate"])
description = str(result["volumeInfo"]["description"])
pages = str(result["volumeInfo"]["pageCount"])
genre = str(result["volumeInfo"]["categories"])[2:-2]
language = str(result["volumeInfo"]["language"])
image_link = str(result["volumeInfo"]["imageLinks"]["thumbnail"])
dict = Google_Results(isbn13, isbn10, title, author, publisher, published_date, description, pages, genre,
language, image_link)
gr.append(dict)
print(gr[i].title)
i += 1
except:
pass
return
gr = []
Book_Search("Linkedin")
I am a beginner to Python, so any help would be appreciated!
It does so because there is no publisher entry in volumeInfo of the first entry, thus it raises a KeyError and your except captures it. If you're going to work with fuzzy data you have to account for the fact that it will not always have the expected structure. For simple cases you can rely on dict.get() and its default argument to return a 'valid' default entry if an entry is missing.
Also, there are a few conceptual problems with your function - it relies on a global gr which is bad design, it shadows the built-in dict type and it captures all exceptions guaranteeing that you cannot exit your code even with a SIGINT... I'd suggest you to convert it to something a bit more sane:
def book_search(search_term, max_results=3):
results = [] # a list to store the results
parms = {"q": search_term, "maxResults": max_results}
r = requests.get(url="https://www.googleapis.com/books/v1/volumes", params=parms)
try: # just in case the server doesn't return valid JSON
for result in r.json().get("items", []):
if "volumeInfo" not in result: # invalid entry - missing volumeInfo
continue
result_dict = {} # a dictionary to store our discovered fields
result = result["volumeInfo"] # all the data we're interested is in volumeInfo
isbns = result.get("industryIdentifiers", None) # capture ISBNs
if isinstance(isbns, list) and isbns:
for i, t in enumerate(("isbn10", "isbn13")):
if len(isbns) > i and isinstance(isbns[i], dict):
result_dict[t] = isbns[i].get("identifier", None)
result_dict["title"] = result.get("title", None)
authors = result.get("authors", None) # capture authors
if isinstance(authors, list) and len(authors) > 2: # you're slicing from 2
result_dict["author"] = str(authors[2:-2])
result_dict["publisher"] = result.get("publisher", None)
result_dict["published_date"] = result.get("publishedDate", None)
result_dict["description"] = result.get("description", None)
result_dict["pages"] = result.get("pageCount", None)
genres = result.get("authors", None) # capture genres
if isinstance(genres, list) and len(genres) > 2: # since you're slicing from 2
result_dict["genre"] = str(genres[2:-2])
result_dict["language"] = result.get("language", None)
result_dict["image_link"] = result.get("imageLinks", {}).get("thumbnail", None)
# make sure Google_Results accepts keyword arguments like title, author...
# and make them optional as they might not be in the returned result
gr = Google_Results(**result_dict)
results.append(gr) # add it to the results list
except ValueError:
return None # invalid response returned, you may raise an error instead
return results # return the results
Then you can easily retrieve as much info as possible for a term:
gr = book_search("Google")
And it will be far more tolerant of data omissions, provided that your Google_Results type makes most of the entries optional.
Following #Coldspeed's recommendation it became clear that missing information in the JSON file caused the exception to run. Since I only had a "pass" statement there it skipped the entire result. Therefore I will have to adapt the "Try and Except" statements so errors do get handled properly.
Thanks for the help guys!

Categories