0

I'm having an issue when trying to pass a sqlite query to another function.

The issue is that the sqlite query MAY contains a list and therefore I cannot use *args as it unpacks the tuple but then ignores the list, example query I'm attempting to pass to the function:

'SELECT postname FROM history WHERE postname = ? COLLATE NOCASE', [u'Test']

So in this case I could use args as opposed to *args in the destination function, however I may have a sqlite query that doesn't contain a list and therefore I can't always do this e.g.

'SELECT * FROM history' 

so I guess my question in a nutshell is how can I successfully pass a sqlite query to another function whether it contains a list or not, using args?

Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
binhex
  • 374
  • 4
  • 13
  • I would argue the best answer (if it's possible) is to ensure that you always get a tuple. Remember you can get tuples of length 1 - ``("SELECT * FROM histroy", )`` would work perfectly. – Gareth Latty Nov 19 '12 at 16:19
  • @Lattyware -- Why not post that as an answer? I don't know sqlite, otherwise I might have something to contribute to that, but if what you say is correct, it really seems like a better solution than mine. – mgilson Nov 19 '12 at 16:24
  • hi Lattyware, i have tried your solution, however sqlite cant use a tuple, i get the error ValueError: operation parameter must be str or unicode, thus im back to the issue that i cannot unpack a tuple as i loose the list. – binhex Nov 19 '12 at 17:21
  • I'm not suggesting that you pass a tuple into a function, rather that you always unpack the argument, and make any arguments that are not tuples tuples of length one. – Gareth Latty Nov 19 '12 at 19:44

2 Answers2

1

Can you just try,except it?

try:
   func(*args)
except TypeError:
   func(args)

Of course, this will catch TypeErrors inside your function as well. As such, you may want to create another function which actually deals with the unpacking and makes sure to give you an unpackable object in return. This also doesn't work for strings since they'll unpack too (see comments).

Here's a function which will make sure an object can be unpacked.

def unpackable(obj):
    if hasattr(obj,'__iter__'):
       return obj
    else:
       return (obj,)

func(*unpackable(args))
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • This won't work (or at least, not as intended) if the single item is a string, as the string will be unpacked. (See ``print(*"test")`` on 3.x or with ``from __future__ import print_function``). – Gareth Latty Nov 19 '12 at 16:15
  • *grumbles* -- @Lattyware, It'll do something, but it probably won't be correct. I'll delete in a minute if I can't come up with a clean workaround... – mgilson Nov 19 '12 at 16:17
1

I would argue the best answer here is to try and ensure you are always putting in an iterable, rather than trying to handle the odd case of having a single item.

Where you have ('SELECT postname FROM history WHERE postname = ? COLLATE NOCASE', [u'Test']) in one place, it makes more sense to pass in a tuple of length one - ('SELECT * FROM history', ) as opposed to the string.

You haven't said where the strings are coming from, so it's possible you simply can't change the way the data is, but if you can, the tuple is the much better option to remove the edge case from your code.

If you truly can't do that, then what you want is to unpack any non-string iterable, checking for that can be done as shown in this question.

Community
  • 1
  • 1
Gareth Latty
  • 86,389
  • 17
  • 178
  • 183