Skip to content

Commit

Permalink
v3.0.3 - Bug fix release
Browse files Browse the repository at this point in the history
* Fixed bug in sqlite functions ignoring filter argument
  The db_filter argument of functions _len(), get_unique_ids(),
  and get_group_count() was ignored when filter returned 0 matches.
  • Loading branch information
bendikro committed Apr 2, 2016
1 parent 5b86881 commit b152d7b
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 23 deletions.
1 change: 1 addition & 0 deletions docs/source/api.rst
Expand Up @@ -27,6 +27,7 @@ PyDbLite.SQLite API
.. autoclass:: pydblite.sqlite.Table
:members:
:special-members:
:private-members:
:exclude-members: __weakref__


Expand Down
9 changes: 9 additions & 0 deletions docs/source/changelog.rst
@@ -1,6 +1,15 @@
Changelog
---------------

3.0.3 (2016-04-02)
~~~~~~~~~~~~~~~~~~~~~~~~

- Fixed bug where db_filter argument of function
:func:`_len() <pydblite.sqlite.Table._len>`,
:func:`get_unique_ids() <pydblite.sqlite.Table.get_unique_ids>`, and
:func:`get_group_count() <pydblite.sqlite.Table.get_group_count>` was
ignored if filter returns 0 matches.

3.0.2 (2015-04-18)
~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
9 changes: 3 additions & 6 deletions docs/source/conf.py
Expand Up @@ -20,9 +20,6 @@
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('.'))

# print "adding to path:", os.path.abspath('../..')
sys.path.insert(0, os.path.abspath('../..'))

# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
Expand All @@ -42,7 +39,7 @@
'sphinxcontrib.inlinesyntaxhighlight',
'sphinxcontrib.fulltoc',
'cloud_sptheme.ext.index_styling',
'cloud_sptheme.ext.relbar_toc',
# 'cloud_sptheme.ext.relbar_toc',
'sphinx.ext.coverage',
'sphinxcontrib.restbuilder',
'sphinxcontrib.issuetracker',
Expand Down Expand Up @@ -79,7 +76,7 @@
version_info = '' # alpha/beta/rc tags.

try:
sys.path.insert(0, '../..')
sys.path.insert(0, os.path.abspath('../..'))
import pydblite
version = "%s" % pydblite.__version__
print("Building docs for pydblite v%s" % version)
Expand Down Expand Up @@ -338,7 +335,7 @@ def _warn_node(self, msg, node):
if not msg.startswith('nonlocal image URI found:'):
self._warnfunc(msg, '%s:%s' % get_source_line(node))

sphinx.environment.BuildEnvironment.warn_node = _warn_node
#sphinx.environment.BuildEnvironment.warn_node = _warn_node

import sphinxcontrib.writers.rst
from sphinxcontrib.writers.rst import RstTranslator
Expand Down
8 changes: 4 additions & 4 deletions pydblite/pydblite.py
Expand Up @@ -20,7 +20,7 @@
except:
import pickle

version = "3.0.2"
version = "3.0.3"


def _in(a, b):
Expand Down Expand Up @@ -472,9 +472,9 @@ def __getitem__(self, key):

def _len(self, db_filter=None):
if db_filter is not None:
if not type(db_filter) is PyDbExpressionGroup:
raise ValueError("Filter argument is not of type "
"'PyDbExpressionGroup': %s" % type(db_filter))
if type(db_filter) is not PyDbExpressionGroup and type(db_filter) is not PyDbFilter:
raise ValueError("Filter argument should be of type 'PyDbExpressionGroup'"
" or 'PyDbFilter': %s" % type(db_filter))
if db_filter.is_filtered():
return len(db_filter.apply_filter(self.records))
return len(self.records)
Expand Down
17 changes: 10 additions & 7 deletions pydblite/sqlite.py
Expand Up @@ -14,7 +14,7 @@
- in :func:`create() <pydblite.sqlite.Table.create>` field definitions must specify a type.
- no `drop_field` (not supported by SQLite)
- the :class:`Table <pydblite.sqlite.Table>` instance has a
:attr:`cursor <pydblite.sqlite.Database.Table.cursor>` attribute, so that raw SQL requests can
:attr:`cursor <pydblite.sqlite.Table.cursor>` attribute, so that raw SQL requests can
be executed.
"""

Expand Down Expand Up @@ -402,7 +402,7 @@ def _make_sql_params(self, kw):
return ['%s=?' % k for k in kw.keys()]

def _make_record(self, row, fields=None):
"""Make a record dictionary from the result of a fetch_"""
"""Make a record dictionary from the result of a fetch"""
if fields is None:
fields = self.fields_with_id
res = dict(zip(fields, row))
Expand Down Expand Up @@ -490,7 +490,8 @@ def filter(self, key=None):
return Filter(self, key)

def _len(self, db_filter=None):
if db_filter and str(db_filter):
"""Return number of matching entries"""
if db_filter is not None and db_filter.is_filtered():
sql = "SELECT COUNT(*) AS count FROM %s WHERE %s" % (self.name, db_filter)
else:
sql = "SELECT COUNT(*) AS count FROM %s;" % self.name
Expand Down Expand Up @@ -523,17 +524,19 @@ def _err_msg(self, sql, args=None):
return msg

def get_group_count(self, group_by, db_filter=None):
if db_filter and str(db_filter):
sql = "SELECT %s, COUNT(*) FROM %s GROUP BY %s WHERE %s" % (group_by, self.name,
group_by, db_filter)
"""Return the grouped by count of the values of a column"""
if db_filter is not None and db_filter.is_filtered():
sql = "SELECT %s, COUNT(*) FROM %s WHERE %s GROUP BY %s " % (group_by, self.name,
db_filter, group_by)
else:
sql = "SELECT %s, COUNT(*) FROM %s GROUP BY %s;" % (group_by, self.name, group_by)
self.cursor.execute(sql)
return self.cursor.fetchall()

def get_unique_ids(self, unique_id, db_filter=None):
"""Return all the unique values of a column"""
sql = "SELECT rowid,%s FROM %s" % (unique_id, self.name)
if db_filter and str(db_filter):
if db_filter is not None and db_filter.is_filtered():
sql += " WHERE %s" % db_filter
self.cursor.execute(sql)
records = self.cursor.fetchall()
Expand Down
57 changes: 52 additions & 5 deletions tests/common_tests.py
Expand Up @@ -251,16 +251,63 @@ def test_filter_or(self):
self.assertEqual(str(f), "((active = 0) OR (name = 'Test4'))")
self.assertEqual(len(f), 4)

def test_len_with_filter(self):
self.setup_db_for_filter()
f = self.filter_db.filter()
f |= (self.filter_db("active") == True) # noqa
self.assertEquals(self.filter_db._len(f), 4)

def test_len_with_filter_non_matching(self):
self.setup_db_for_filter()
f = self.filter_db.filter()
f |= (self.filter_db("unique_id") == -1) # Will not match any entries
self.assertEqual(self.filter_db._len(f), 0)

def test_filter_get_unique_ids(self):
self.setup_db_for_filter()
ids = self.filter_db.get_unique_ids("unique_id")
self.assertEqual(ids, set([1, 2, 3, 4, 5, 6, 7]))
ids = self.filter_db.get_unique_ids("name")
self.assertEqual(ids, set(['Test0', 'Test6', 'Test4', 'Test7', 'test0']))

def test_get_group_count(self):
def test_filter_get_unique_ids_with_filter(self):
self.setup_db_for_filter()
result = self.filter_db.get_group_count("name")
f = self.filter_db.filter()
f |= (self.filter_db("active") == True) # noqa
ids = self.filter_db.get_unique_ids("name", f)
self.assertEquals(ids, set(['Test0', 'Test4', 'test0']))

def test_filter_get_unique_ids_with_filter_non_matching(self):
self.setup_db_for_filter()
f = self.filter_db.filter() | (self.filter_db("unique_id") == -1) # Will not match any
ids = self.filter_db.get_unique_ids("name", f)
self.assertEqual(ids, set())

def make_group_count_result(self, key, test_key=None, test_val=None):
counts = {}
for e in self.status:
counts[e["name"]] = counts.get(e["name"], 0) + 1
if test_key and e[test_key] != test_val:
continue
counts[e[key]] = counts.get(e[key], 0) + 1
return counts

def test_get_group_count(self):
self.setup_db_for_filter()
counts = self.make_group_count_result("name")
result = self.filter_db.get_group_count("name")
for name, count in result:
self.assertEqual(count, counts[name])

def test_get_group_count_with_filter(self):
self.setup_db_for_filter()
counts = self.make_group_count_result("name", test_key="active", test_val=True)
f = self.filter_db.filter() | (self.filter_db("active") == True) # noqa
result = self.filter_db.get_group_count("name", f)
for name, count in result:
self.assertEqual(count, counts[name])

def test_get_group_count_with_filter_non_matching(self):
self.setup_db_for_filter()
counts = self.make_group_count_result("name", test_key="unique_id", test_val=-1)
f = self.filter_db.filter() | (self.filter_db("unique_id") == -1)
result = self.filter_db.get_group_count("name", f)
for name, count in result:
self.assertEqual(count, counts[name])
2 changes: 1 addition & 1 deletion tox.ini
Expand Up @@ -102,7 +102,7 @@ deps =
isort
whitelist_externals =
isort
commands = python -c "import subprocess, sys; output = subprocess.check_output('isort --stdout --diff --recursive pydblite tests *.py', shell=True); print output; sys.exit(len(output) != 0)"
commands = python -c "import subprocess, sys; output = subprocess.check_output('isort -q --stdout --diff --recursive pydblite tests *.py', shell=True); print output; sys.exit(len(output) != 0)"

[testenv:docs]
# sphinxcontrib/restbuilder does not support python 3, so force python 2.7
Expand Down

0 comments on commit b152d7b

Please sign in to comment.