The list:string type does not store empty strings. Because of the way the function bar_encode() formats an empty list as ||, there's no room for empty strings in it.
But that's python and web2py.. it can't be difficult.
class EmptyStrAble(object):
""" (1)Define filter_in/filter_out for the desired field and (2)wrap its
`contains` operator for full functionality as a list:string able to
work with empty strings
"""
empty_string_mark = '-*- empty string -*-'
def filter_in(self, obj):
""" change empty string with empty_string_mark
"""
if obj == '':
obj = self.empty_string_mark
elif hasattr(obj, '__iter__'):
if '' in obj:
obj[obj.index('')] = self.empty_string_mark
return obj
def filter_out(self, obj):
""" change empty_string_mark with empty string
"""
if isinstance(obj, list): # it's list or None
if self.empty_string_mark in obj:
obj[obj.index(self.empty_string_mark)] = ''
return obj
def contains_wrapper(self, func):
""" apply `filter_in` to the first argument of `contains` operator wich
always is either a string or a list of strings
"""
def checker(*args, **kwargs):
largs = args[:]
largs[0] = self.filter_in(largs[0])
return func(*largs, **kwargs)
return checker
And apply:
# ==== in models =====
db.define_table('thing',
Field('options', 'list:string'))
# Define filters and wrap `contains` operator
esa = EmptyStringAble()
db.thing.options.filter_in = lambda obj, my_in=esa.filter_in: my_in( obj )
db.thing.options.filter_out = lambda obj, my_out=esa.filter_out: my_out( obj )
db.thing.options.contains = esa.contains_wrapper( db.thing.options.contains )
Now we've got our desire satisfied:
def test_me():
db.thing.truncate()
db.thing.insert(options='')
db.thing.insert(options=None)
db.thing.insert(options=[])
db.thing.insert(options=['a', '', 'ca'])
assert(db(db.thing.options.contains('')).count()==2), 'Error'
assert(db(db.thing.options.contains('', all=True)).count()==2), 'Error'
assert(db(db.thing.options.contains(['', 'ca'], all=True)).count()==1), 'Error'
return 'Python and Web2py rules!'



Comments (0)