Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e276a45

Browse files
committed
ToDictMixin no longer relies on ToJsonMixin
Added to_dict function that recursively converts a Python object into a dictionary
1 parent c07c78b commit e276a45

File tree

2 files changed

+85
-4
lines changed

2 files changed

+85
-4
lines changed

quickbooks/mixins.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import simplejson as json
2+
import six
23
from .utils import build_where_clause, build_choose_clause
34
from .client import QuickBooks
45
from .exceptions import QuickbooksException
@@ -50,9 +51,40 @@ def from_json(cls, json_data):
5051
return obj
5152

5253

54+
# Based on http://stackoverflow.com/a/1118038
55+
def to_dict(obj, classkey=None):
56+
"""
57+
Recursively converts Python object into a dictionary
58+
"""
59+
if isinstance(obj, dict):
60+
data = {}
61+
for (k, v) in obj.items():
62+
data[k] = to_dict(v, classkey)
63+
return data
64+
elif hasattr(obj, "_ast"):
65+
return to_dict(obj._ast())
66+
elif hasattr(obj, "__iter__") and not isinstance(obj, str):
67+
return [to_dict(v, classkey) for v in obj]
68+
elif hasattr(obj, "__dict__"):
69+
if six.PY2:
70+
data = dict([(key, to_dict(value, classkey))
71+
for key, value in obj.__dict__.iteritems()
72+
if not callable(value) and not key.startswith('_')])
73+
else:
74+
data = dict([(key, to_dict(value, classkey))
75+
for key, value in obj.__dict__.items()
76+
if not callable(value) and not key.startswith('_')])
77+
78+
if classkey is not None and hasattr(obj, "__class__"):
79+
data[classkey] = obj.__class__.__name__
80+
return data
81+
else:
82+
return obj
83+
84+
5385
class ToDictMixin(object):
5486
def to_dict(self):
55-
return json.loads(self.to_json())
87+
return to_dict(self)
5688

5789

5890
class ReadMixin(object):

tests/unit/test_mixins.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,59 @@ def test_from_json_missing_detail_object(self):
6464

6565
class ToDictMixinTest(unittest.TestCase):
6666
def test_to_dict(self):
67-
phone = PhoneNumber()
68-
phone.FreeFormNumber = "555-555-5555"
67+
json_data = {
68+
'DocNumber': '123',
69+
'TotalAmt': 100,
70+
'Line': [
71+
{
72+
"Id": "0",
73+
"Description": "Test",
74+
"Amount": 25.54,
75+
"DetailType": "JournalEntryLineDetail",
76+
"JournalEntryLineDetail": {
77+
"PostingType": "Debit",
78+
}
79+
},
80+
],
81+
}
82+
83+
entry = JournalEntry.from_json(json_data)
84+
expected = {
85+
'DocNumber': '123',
86+
'SyncToken': 0,
87+
'domain': 'QBO',
88+
'TxnDate': '',
89+
'TotalAmt': 100,
90+
'ExchangeRate': 1,
91+
'CurrencyRef': None,
92+
'PrivateNote': '',
93+
'sparse': False,
94+
'Line': [{
95+
'LinkedTxn': [],
96+
'Description': 'Test',
97+
'JournalEntryLineDetail': {
98+
'TaxAmount': 0,
99+
'Entity': None,
100+
'DepartmentRef': None,
101+
'TaxCodeRef': None,
102+
'BillableStatus': '',
103+
'TaxApplicableOn': 'Sales',
104+
'PostingType': 'Debit',
105+
'AccountRef': None,
106+
'ClassRef': None,
107+
},
108+
'DetailType': 'JournalEntryLineDetail',
109+
'LineNum': 0,
110+
'Amount': 25.54,
111+
'CustomField': [],
112+
'Id': '0',
113+
}],
114+
'Adjustment': False,
115+
'Id': None,
116+
'TxnTaxDetail': None,
117+
}
69118

70-
self.assertEquals(phone.to_dict(), {"FreeFormNumber": "555-555-5555"})
119+
self.assertEquals(expected, entry.to_dict())
71120

72121

73122
class ListMixinTest(unittest.TestCase):

0 commit comments

Comments
 (0)