2016-04-21 68 views
-2

我需要將SQL的結果轉換爲分層字典。我創建DictMaker類並編寫單個測試。但測試的運行在某個時候失敗或成功。我不會拒絕這種行爲。在課堂上沒有隨機的電話。蟒蛇單測試在任何運行得到不同的結果

import unittest 


class DictMaker: 
    def __init__(self, input_): 
     self._input = input_ 
     self._dict = { } 

    def dict(self): 
     self._make() 
     return self._dict 

    def _make(self): 
     for item in self._input: 
      for long_key, val in item.items(): 
       self._add_leaf_value(long_key, val) 

    def _add_leaf_value(self, long_key, val): 
     last = self._get_last_item(long_key) 
     leaf = self._get_leaf_key(long_key) 
     if leaf in last: 
      if last[ leaf ] != val: 
       list_ = self._get_last_list(long_key) 
       key = self._get_leaf_key(long_key) 
       list_.append({ key: val }) 
     else: 
      last[ leaf ] = val 

    def _get_leaf_key(self, long_key): 
     return long_key.split('.')[ -1 ] 

    def _get_last_item(self, long_key): 
     keys = long_key.split('.')[ :-1 ] 
     parent_dict = self._dict 
     parent_list = None 
     for key in keys: 
      if key in parent_dict: 
       parent_list = parent_dict[ key ] 
       parent_dict = parent_list[ -1 ] 
      else: 
       sub_dict = { } 
       parent_list = [ sub_dict ] 
       parent_dict[ key ] = parent_list 
       parent_dict = sub_dict 

     return parent_list[ -1 ] 

    def _get_last_list(self, long_key): 
     keys = long_key.split('.')[ :-1 ] 
     parent_dict = self._dict 
     parent_list = None 
     for key in keys: 
      if key in parent_dict: 
       parent_list = parent_dict[ key ] 
       parent_dict = parent_list[ -1 ] 
      else: 
       sub_dict = { } 
       parent_list = [ sub_dict ] 
       parent_dict[ key ] = parent_list 
       parent_dict = sub_dict 

     return parent_list 


class MyTestCase(unittest.TestCase): 
    def test_run(self): 
    input_ = [ 
     { 
      'categories.id': 1, 
      'categories.label': 'Computers', 
      'categories.groups.id': 18, 
      'categories.groups.label': 'Servers and Servers equipment', 
      'categories.groups.names.id': 48, 
      'categories.groups.names.label': 'HP Memory' 
     }, 
     { 
      'categories.id': 1, 
      'categories.label': 'Computers', 
      'categories.groups.id': 18, 
      'categories.groups.label': 'Servers and Servers equipment', 
      'categories.groups.names.id': 73, 
      'categories.groups.names.label': 'HP Options for servers' 
     }, 
     { 
      'categories.id': 1, 
      'categories.label': 'Computers', 
      'categories.groups.id': 84, 
      'categories.groups.label': 'Tablets', 
      'categories.groups.names.id': 310, 
      'categories.groups.names.label': 'Tablets Samsung' 
     }, 
     { 
      'categories.id': 1, 
      'categories.label': 'Computers', 
      'categories.groups.id': 84, 
      'categories.groups.label': 'Tablets', 
      'categories.groups.names.id': 313, 
      'categories.groups.names.label': 'Tablets Sony' 
     }, 
     { 
      'categories.id': 2, 
      'categories.label': 'Periphery', 
      'categories.groups.id': 55, 
      'categories.groups.label': 'Loundspeakers', 
      'categories.groups.names.id': 330, 
      'categories.groups.names.label': 'Loundspeakers Ritmix' 
     }, 
     { 
      'categories.id': 2, 
      'categories.label': 'Periphery', 
      'categories.groups.id': 55, 
      'categories.groups.label': 'Loundspeakers', 
      'categories.groups.names.id': 402, 
      'categories.groups.names.label': 'Loundspeakers MICROLAB' 
     }, 
     { 
      'categories.id': 2, 
      'categories.label': 'Periphery', 
      'categories.groups.id': 58, 
      'categories.groups.label': 'Keyboards, mouses', 
      'categories.groups.names.id': 25, 
      'categories.groups.names.label': 'mouses G-Cube' 
     }, 
     { 
      'categories.id': 2, 
      'categories.label': 'Periphery', 
      'categories.groups.id': 58, 
      'categories.groups.label': 'Keyboards, mouses', 
      'categories.groups.names.id': 27, 
      'categories.groups.names.label': 'Keyboards BTC ' 
     }, 
    ] 
    expected = { 
     'categories': [ 
      { 
       'id': 1, 
       'label': 'Computers', 
       'groups': [ 
        { 
         'id': 18, 
         'label': 'Servers and Servers equipment', 
         'names': [ 
          { 
           'id': 48, 
           'label': 'HP Memory' 
          }, 
          { 
           'id': 73, 
           'label': 'HP Options for servers' 
          } 
         ] 
        }, 
        { 
         'id': 84, 
         'label': 'Tablets', 
         'names': [ 
          { 
           'id': 310, 
           'label': 'Tablets Samsung' 
          }, 
          { 
           'id': 313, 
           'label': 'Tablets Sony' 
          } 
         ] 
        } 
       ] 
      }, 
      { 
       'id': 2, 
       'label': 'Periphery', 
       'groups': [ 
        { 
         'id': 55, 
         'label': 'Loundspeakers', 
         'names': [ 
          { 
           'id': 330, 
           'label': 'Loundspeakers Ritmix' 
          }, 
          { 
           'id': 402, 
           'label': 'Loundspeakers MICROLAB' 
          } 
         ] 
        }, 
        { 
         'id': 58, 
         'label': 'Keyboards, mouses', 
         'names': [ 
          { 
           'id': 25, 
           'label': 'mouses G-Cube' 
          }, 
          { 
           'id': 27, 
           'label': 'Keyboards BTC ' 
          } 
         ] 
        } 
       ] 
      } 
     ] 
    } 

    maker = DictMaker(input_) 
    actual = maker.dict() 

    self.assertEqual(actual, expected) 


if __name__ == '__main__': 
    unittest.main() 

在網上它工作正常(可能是由於Pypy)。但本地運行很奇怪。 python(3.4.3)

+0

請出示你的代碼 –

+0

代碼參考http://ideone.com/sPFNOJ –

+0

請的問題,而不是代碼的鏈接的身體內發佈您的代碼。 – Kritner

回答

0

FIX。這是由於字典鍵迭代時未定義的順序。 解決問題添加力排序。

def _make(self): 
    for item in self._input: 
     for long_key, val in item.items(): 
      self._add_leaf_value(long_key, val) 

變化

def _make(self): 
    for item in self._input: 
     items = list(item.items()) 
     items.sort(key=lambda t: len(t[ 0 ])) 
     for long_key, val in items: 
      self._add_leaf_value(long_key, val)