Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dev

- Add :ref:`command-report` to produce static HTML output for a run.
- Fix a problem with the "ignore" path management under virtualenv.
- Fix some bugs with JSON encoding

0.6
===
Expand Down
13 changes: 11 additions & 2 deletions smiley/jsonutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import xml.dom.minidom

from cliff import commandmanager
from six import string_types

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -38,6 +39,13 @@ def _json_special_types(obj):
return data


def _stringify(data):
"""Convert data to a string if it's not already one"""
# It's not good enough to just call str(k):
# In python2 if data is a `unicode` with non-ascii chars, this will fail.
return data if isinstance(data, string_types) else str(data)


def _scrub_item(v):
"""Look for a few types that cause circular references.
"""
Expand All @@ -63,7 +71,7 @@ def _scrub_item(v):


def _scrub_dict(data):
return {k: _scrub_item(v) for k, v in data.items()}
return {_stringify(k): _scrub_item(v) for k, v in data.items()}


def _scrub_list(data):
Expand All @@ -89,5 +97,6 @@ def dumps(data):
return json.dumps([repr(v) for v in data])
elif isinstance(data, dict):
# LOG.debug('trying with repr')
return json.dumps({k: repr(v) for k, v in data.items()})
return json.dumps(
{_stringify(k): repr(v) for k, v in data.items()})
raise
20 changes: 20 additions & 0 deletions smiley/tests/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,26 @@ def test_local_vars(self):
self.assertEqual(json.loads(row['local_vars']),
self.local_values)

def test_local_var_encoding(self):
"""The database should properly encode dict keys as strings"""
self.db.trace(
run_id='12345',
thread_id='t1',
call_id='abcd',
event='test',
func_name='test_trace',
line_no=101,
filename='test_db.py',
trace_arg=self.trace_arg,
local_vars={"tuple_dict": {(1, 2): 3}},
timestamp=1370436104.65,
)
c = self.db.conn.cursor()
c.execute("select * from trace where trace.line_no = 101")
row = c.fetchone()
self.assertEqual(row["local_vars"],
'{"tuple_dict": {"(1, 2)": 3}}')

def test_trace_arg(self):
c = self.db.conn.cursor()
c.execute('select * from trace order by id')
Expand Down
6 changes: 6 additions & 0 deletions smiley/tests/test_jsonutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,9 @@ def test_type(self):
expected = "<class 'int'>"
actual = jsonutil._json_special_types(int)
self.assertEqual(expected, actual)

def test_dict_tuple_keys(self):
"""Keys in dicts should be converted to strings"""
actual = jsonutil.dumps({(1, 2): 3})
expected = '{"(1, 2)": 3}'
self.assertEqual(expected, actual)