Peewee: reducing where conditionals break after a certain length - python

This is what I have:
SomeTable.select.where(reduce(operator.or_, (SomeTable.stuff == entry for entry in big_list)))
The problem arises when I have a relatively large list of elements in big_list and I get this:
RuntimeError: maximum recursion depth exceeded
Is there another way to approach this that doesn't involve splitting up the list into several chunks?
Tried the suggestion to use any, here's my error:
Traceback (most recent call last):
File "C:/Users/f9xk3li/Documents/GitHub/leoshop_web/leoshop_web/data_models/data_model.py", line 347, in <module>
search_bins_all("BoA 0")
File "C:/Users/f9xk3li/Documents/GitHub/leoshop_web/leoshop_web/data_models/data_model.py", line 179, in search_bins_all
for d in generator.order_by(SomeTable.RetrievedDate.desc()):
File "C:\Users\f9xk3li\AppData\Local\Continuum\Anaconda\lib\site-packages\peewee.py", line 282, in inner
clone = self.clone() # Assumes object implements `clone`.
File "C:\Users\f9xk3li\AppData\Local\Continuum\Anaconda\lib\site-packages\peewee.py", line 2202, in clone
return self._clone_attributes(query)
File "C:\Users\f9xk3li\AppData\Local\Continuum\Anaconda\lib\site-packages\peewee.py", line 2412, in _clone_attributes
query = super(SelectQuery, self)._clone_attributes(query)
File "C:\Users\f9xk3li\AppData\Local\Continuum\Anaconda\lib\site-packages\peewee.py", line 2206, in _clone_attributes
query._where = self._where.clone()
AttributeError: 'bool' object has no attribute 'clone'
And here's the code
generator = SomeTable.select()
generator = generator.where(any(SomeTable.BIN == entry for entry in big_list))
for d in generator:
....

Try ...where(SomeTable.BIN.in_(big_list))
PeeWee has restrictions as to what can be used in their where clause in order to work with the library.
http://docs.peewee-orm.com/en/latest/peewee/querying.html#query-operators

To expand on Jacob's comment on the approved answer, I think he's saying you can use subqueries rather than resolving all the IDs.
E.G.
admin_users = User.select().where(User.is_admin == True)
admin_messages = Message.select().where(Message.user.in_(admin_users))

Related

How to fix "TypeError: can only concatenate list (not "str") to list" Error

I want my function getPlaylists(a,b,c) to take values from lists a,b, and c and run until all elements in each list are used.
Specifically, I'd like to setup getPlaylists(a,b,c) so it runs getPlaylists(a[0],b[0],c[0]) then getPlaylists(a[1],b[1],c[1]) etc... until it completes all values in lists a,b, and c.
I have tried running getPlaylists(a[0:],b[0:],c[0:]) and it gives me the error:
"TypeError: can only concatenate list (not "str") to list"
I have also tried running getPlaylists(a[0],b[0],c[0]) followed by getPlaylists(a[1],b[1],c[1]) in the following line. Only the first function prints successfully.
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
def getPlaylists(a,b,c):
client_credentials_manager = SpotifyClientCredentials(client_id=a, client_secret=b)
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
playlists = sp.user_playlists(c)
while playlists:
for i, playlist in enumerate(playlists['items']):
print("%4d %s %s" % (i + 1 + playlists['offset'], playlist['uri'], playlist['name']))
if playlists['next']:
playlists = sp.next(playlists)
else:
playlists = None
a= ["7ce6355bc7a34c659b6ce0b6a0c53395","a15e38973eb64f9bba30258a9dde407d"]
b= ["026081a8e1a544dbbcc2bf8a373f3088","8af7eaa281dc49a58d08e46adf06e637"]
c= ["121147088","20mc3a9w582vc7a7o5cjm03d8"]
getPlaylists(a[0:],b[0:],c[0:])
I expected all the playlists from each spotify account to print. However, when I format my code as I did above, I get the following errors:
Traceback (most recent call last):
File "C:/Users/19083/AppData/Local/Programs/Python/Python37-32/SpotifyTest2_9.18.py", line 22, in <module>
getPlaylists(a[0:],b[0:],c[0:])
File "C:/Users/19083/AppData/Local/Programs/Python/Python37-32/SpotifyTest2_9.18.py", line 9, in getPlaylists
playlists = sp.user_playlists(c)
File "C:\Users\19083\AppData\Local\Programs\Python\Python37-32\lib\site-packages\spotipy\client.py", line 366, in user_playlists
offset=offset)
File "C:\Users\19083\AppData\Local\Programs\Python\Python37-32\lib\site-packages\spotipy\client.py", line 146, in _get
return self._internal_call('GET', url, payload, kwargs)
File "C:\Users\19083\AppData\Local\Programs\Python\Python37-32\lib\site-packages\spotipy\client.py", line 100, in _internal_call
headers = self._auth_headers()
File "C:\Users\19083\AppData\Local\Programs\Python\Python37-32\lib\site-packages\spotipy\client.py", line 90, in _auth_headers
token = self.client_credentials_manager.get_access_token()
File "C:\Users\19083\AppData\Local\Programs\Python\Python37-32\lib\site-packages\spotipy\oauth2.py", line 57, in get_access_token
token_info = self._request_access_token()
File "C:\Users\19083\AppData\Local\Programs\Python\Python37-32\lib\site-packages\spotipy\oauth2.py", line 67, in _request_access_token
auth_header = base64.b64encode(str(self.client_id + ':' + self.client_secret).encode())
TypeError: can only concatenate list (not "str") to list
Here:
getPlaylists(a[0:],b[0:],c[0:])
a[0:] (slice notation) means "return a sublist elements from list a from index 0 to the last item- IOW, it returns alist(and in this case the whole list), not a single item. You wanta[0]` instead.
This being said, your data structure is wrong. Using "parallel lists" (2 or more lists where items are supposed to be matched by position) is brittle at best - reorder one of the list and the whole thing is broken... The proper structure here would be a list of tuples or dicts, ie:
clients = [
# (client_id, client_secret, what_is_c)
("7ce6355bc7a34c659b6ce0b6a0c53395", "026081a8e1a544dbbcc2bf8a373f3088", "121147088"),
# etc
]
which allow you to simply loop over it:
for a, b, c in clients:
getPlaylists(a, b, c)
or using the the *args syntax:
for args in clients:
getPlaylists(*args)
Also, do yourself a favour: use meaningfull names. a, b and c means nothing, and you have to lookup how those variables are used to find out what they are. Proper naming makes for more readable code:
def get_playlists(client_id, client_secret, whatever_is_c_we_dont_know_but_you_proably_do):
# ...

populating word template with python .merge() but TypeError: merge() argument after ** must be a mapping, not str

I am trying to create a script that will take in user info and populate word templates with the information.
I keep getting the following error and I don't understand why:
TypeError: merge() argument after ** must be a mapping, not str
My script begins by gathering information from the user and storing it into a dictionary. then the following code is executed:
stress_notes_document = MailMerge(os.path.join(new_path,new_notes))
stress_notes_document.merge(
TR_num = packet_info['TR#'],
pckg_num = packet_info['Package#'],
TED_num = packet_info['TED#'],
Charge_Line = packet_info['Charge Line'],
Change_num = packet_info['Change#'],
Installation_list = packet_list['Installations list'],
Drawings_list = packet_list['Drawings list'],
Designer = packet_info['Designer'],
phone_number_designer = packet_info['Phone Number of designer'],
Date_in = packet_info['Date in'],
Stress_Due_Date = packet_info['Stress Due Date'],
Date_out = packet_info['Date out'],
model = packet_info['model'],
Customer = packet_info['Customer'],
Effectivity = packet_info['Effectivity'],
panel_excel = 'new_panel')
stress_notes_document.write(os.path.join(new_path,new_notes + "ver A"))
The error happens when I try to execute the second line, stress_notes_document.merge(..). I am trying to assign a value from my dictionary to a mergefield in the word document.
Any suggestions?
edit: I am using this as a guide: http://pbpython.com/python-word-template.html
The examples shown they use strings in the merge() function.
Here is the full error :
Traceback (most recent call last):
File "<ipython-input-1-e67354559525>", line 1, in <module>
runfile('C:/Python_All/python_scripts/data_gather.py', wdir='C:/Python_All/python_scripts')
File "C:\Python_All\Anaconda\lib\site-packages\spyder\utils\site\sitecustomize.py", line 710, in runfile
execfile(filename, namespace)
File "C:\Python_All\Anaconda\lib\site-packages\spyder\utils\site\sitecustomize.py", line 101, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "C:/Python_All/python_scripts/data_gather.py", line 114, in <module>
Effectivity = packet_info['Effectivity'])
File "C:\Python_All\Anaconda\lib\site-packages\mailmerge.py", line 176, in merge
self.merge_rows(field, replacement)
File "C:\Python_All\Anaconda\lib\site-packages\mailmerge.py", line 219, in merge_rows
self.merge([row], **row_data)
TypeError: merge() argument after ** must be a mapping, not str
The reason for the error is that one of parameter values you pass to merge() is a list not a string.
merge() as described in the docs enables you to pass list of dictionaries as a shortcut to merge_rows() function. So if you pass code as below (taken from docs) then it runs merge_rows() function using given list.
document.merge(field1='docx Mail Merge',
col1=[
{'col1': 'A'},
{'col1': 'B'},
])
Now, in your code one of the values you provide (packet_list['Installations list'] from comments) is a list, so merge() decides to run merge_rows on that. But format of your list does not match the expected format (expected format is list with dictionaries as elements, but in your code elements are strings). Thus you get error, when merge_rows tries to read provided data as dictionary.
To fix this you either convert list packet_list['Installations list'] into a string, for example:
",".join(packet_list['Installations list'] )
or convert that list into expected list of dictionaries format.
Whichever makes sense.

random.choice raises KeyError when called on nodes of a NodeView object

I am trying to select one of the elements out of a group of nodes (G.nodes()) but not getting the output. Instead getting errors. Below are the details. I am using Python 3.6
When G is:
Out[36]: NodeView(('Delhi', 'Bangalore', 'Hyderabad', 'Ahmedabad', 'Chennai', 'Kolkatta', 'Surat', 'Pune', 'Jaipur'))
code:
c1=random.choice(G.nodes())
Traceback (most recent call last):
File "<ipython-input-43-8dfc19a66804>", line 1, in <module>
c1=random.choice(G.nodes())
File "C:\Users\prasa\Anaconda3\lib\random.py", line 259, in choice
return seq[i]
File "C:\Users\prasa\Anaconda3\lib\site-packages\networkx\classes\reportviews.py", line 178, in __getitem__
return self._nodes[n]
KeyError: 5
Apparently you are using networkx. Looking up the documentation for Graph I can see that it says this:
A NodeView of the Graph as G.nodes or G.nodes().
Can be used as G.nodes for data lookup and for set-like operations.
[...]
Returns
NodeView
Allows set-like operations over the
nodes as well as node attribute dict lookup and calling to get a
NodeDataView. A NodeDataView iterates over (n, data) and has no
set operations. A NodeView iterates over n and includes set
operations.
However random.choice needs a sequence not a set/map-like object. You can obtain a sequence by simply calling list:
random.choice(list(G.nodes()))
The error is due to the fact that the NodeView is not indexed by the position of the nodes in the set, hence when random.choice generates the random index (according to the number of nodes present) to return the random node it fails with that KeyError.

Pandas DataFrame exists in list

I tried searching but didnt see anything relevant, or it may have skipped my eyes.
So what I want is pretty specific. I have a list of Pandas DataFrame, and I want to check wheather the dataframe created in current step / workflow already exists in list, if yes then pass or else append to it. Now I tried using following:
if df not in best_dfs:
# process something here
best_dfs.append(df)
else:
pass
This is how you would do to check weather a list contains some object of fixed type. But When I do the same, I recieve following error:
Traceback (most recent call last):
File "C:/Projects/Barclays/Email Analytics/POC - Stop Cheque Classification/03_CodeBase/CodeBase/utils/FindBestDf.py", line 239, in <module>
print(obj.find_(dfs))
File "C:/Projects/Barclays/Email Analytics/POC - Stop Cheque Classification/03_CodeBase/CodeBase/utils/FindBestDf.py", line 19, in find_
r = self.__driver(list_of_df)
File "C:/Projects/Barclays/Email Analytics/POC - Stop Cheque Classification/03_CodeBase/CodeBase/utils/FindBestDf.py", line 201, in __driver
if v[0] not in best_dfs:
File "C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\pandas\core\ops.py", line 1296, in f
return self._compare_frame(other, func, str_rep)
File "C:\Users\IBM_ADMIN\Anaconda3\lib\site-packages\pandas\core\frame.py", line 3670, in _compare_frame
raise ValueError('Can only compare identically-labeled '
ValueError: Can only compare identically-labeled DataFrame objects
How do I tacke this? Any work around?
Any help will be grately appreciated.
Thanks
Probably not the most efficient way, but this works for pandas:
if not True in [df.equals(x) for x in df_list]:
df_list.append(df)
Pandas has a built-in method to check for df equality called df.equals(). Basically you iterate this through your df_list to create another list of result, then check if any of the result return True (i.e. the same df exist in the list).

ValueError: too many values to unpack

I am trying to sort dictionaries in MongoDB. However, I get the value error "too many values to unpack" because I think it's implying that there are too many values in each dictionary (there are 16 values in each one). This is my code:
FortyMinute.find().sort(['Rank', 1])
Anyone know how to get around this?
EDIT: Full traceback
Traceback (most recent call last):
File "main.py", line 33, in <module>
main(sys.argv[1:])
File "main.py", line 21, in main
fm.readFortyMinute(args[0])
File "/Users/Yih-Jen/Documents/Rowing Project/FortyMinute.py", line 71, in readFortyMinute
writeFortyMinute(FortyMinData)
File "/Users/Yih-Jen/Documents/Rowing Project/FortyMinute.py", line 104, in writeFortyMinute
FortyMinute.find().sort(['Rank', 1])
File "/Users/Yih-Jen/anaconda/lib/python2.7/site-packages/pymongo/cursor.py", line 692, in sort
self.__ordering = helpers._index_document(keys)
File "/Users/Yih-Jen/anaconda/lib/python2.7/site-packages/pymongo/helpers.py", line 65, in _index_document
for (key, value) in index_list:
ValueError: too many values to unpack
You pass the arguments and values in unpacked as so:
FortyMinute.find().sort('Rank', 1)
It is only when you're passing multiple sort parameters that you group arguments and values using lists, and then too you must surround all your parameters with a tuple as so:
FortyMinute.find().sort([(Rank', 1), ('Date', 1)])
Pro-tip: Even the Cursor.sort documentation linked below recommends using pymongo.DESCENDING and pymongo.ASCENDING instead of 1 and -1; in general, you should use descriptive variable names instead of magic constants in your code as so:
FortyMinute.find().sort('Rank',pymongo.DESCENDING)
Finally, if you are so inclined, you can sort the list using Python's built-in as the another answerer mentioned; but even thought sorted accepts iterators and not just sequences it might be more inefficient and nonstandard:
sorted(FortyMinute.find(), key=key_function)
where you might define key_function to return the Rank column of a record.
Link to the official documentation
If you want mong/pymongo to sort:
FortyMinute.find().sort('Rank', 1)
If you want to sort using multiple fields:
FortyMinute.find().sort([('Rank': 1,), ('other', -1,)])
You also have constants to make it more clear what you're doing:
FortyMinute.find().sort('Rank',pymongo.DESCENDING)
If you want to sort in python first you have to return the result and use a sorting method in python:
sorted(FortyMinute.find(), key=<some key...>)

Categories

Resources