mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
	
	
		
			146 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			146 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | from test.test_json import PyTest | ||
|  | import pickle | ||
|  | import sys | ||
|  | import unittest | ||
|  | 
 | ||
|  | kepler_dict = { | ||
|  |     "orbital_period": { | ||
|  |         "mercury": 88, | ||
|  |         "venus": 225, | ||
|  |         "earth": 365, | ||
|  |         "mars": 687, | ||
|  |         "jupiter": 4331, | ||
|  |         "saturn": 10_756, | ||
|  |         "uranus": 30_687, | ||
|  |         "neptune": 60_190, | ||
|  |     }, | ||
|  |     "dist_from_sun": { | ||
|  |         "mercury": 58, | ||
|  |         "venus": 108, | ||
|  |         "earth": 150, | ||
|  |         "mars": 228, | ||
|  |         "jupiter": 778, | ||
|  |         "saturn": 1_400, | ||
|  |         "uranus": 2_900, | ||
|  |         "neptune": 4_500, | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | class TestAttrDict(PyTest): | ||
|  | 
 | ||
|  |     def test_dict_subclass(self): | ||
|  |         self.assertTrue(issubclass(self.AttrDict, dict)) | ||
|  | 
 | ||
|  |     def test_slots(self): | ||
|  |         d = self.AttrDict(x=1, y=2) | ||
|  |         with self.assertRaises(TypeError): | ||
|  |             vars(d) | ||
|  | 
 | ||
|  |     def test_constructor_signatures(self): | ||
|  |         AttrDict = self.AttrDict | ||
|  |         target = dict(x=1, y=2) | ||
|  |         self.assertEqual(AttrDict(x=1, y=2), target)                   # kwargs | ||
|  |         self.assertEqual(AttrDict(dict(x=1, y=2)), target)             # mapping | ||
|  |         self.assertEqual(AttrDict(dict(x=1, y=0), y=2), target)        # mapping, kwargs | ||
|  |         self.assertEqual(AttrDict([('x', 1), ('y', 2)]), target)       # iterable | ||
|  |         self.assertEqual(AttrDict([('x', 1), ('y', 0)], y=2), target)  # iterable, kwargs | ||
|  | 
 | ||
|  |     def test_getattr(self): | ||
|  |         d = self.AttrDict(x=1, y=2) | ||
|  |         self.assertEqual(d.x, 1) | ||
|  |         with self.assertRaises(AttributeError): | ||
|  |             d.z | ||
|  | 
 | ||
|  |     def test_setattr(self): | ||
|  |         d = self.AttrDict(x=1, y=2) | ||
|  |         d.x = 3 | ||
|  |         d.z = 5 | ||
|  |         self.assertEqual(d, dict(x=3, y=2, z=5)) | ||
|  | 
 | ||
|  |     def test_delattr(self): | ||
|  |         d = self.AttrDict(x=1, y=2) | ||
|  |         del d.x | ||
|  |         self.assertEqual(d, dict(y=2)) | ||
|  |         with self.assertRaises(AttributeError): | ||
|  |             del d.z | ||
|  | 
 | ||
|  |     def test_dir(self): | ||
|  |         d = self.AttrDict(x=1, y=2) | ||
|  |         self.assertTrue(set(dir(d)), set(dir(dict)).union({'x', 'y'})) | ||
|  | 
 | ||
|  |     def test_repr(self): | ||
|  |         # This repr is doesn't round-trip.  It matches a regular dict. | ||
|  |         # That seems to be the norm for AttrDict recipes being used | ||
|  |         # in the wild.  Also it supports the design concept that an | ||
|  |         # AttrDict is just like a regular dict but has optional | ||
|  |         # attribute style lookup. | ||
|  |         self.assertEqual(repr(self.AttrDict(x=1, y=2)), | ||
|  |                          repr(dict(x=1, y=2))) | ||
|  | 
 | ||
|  |     def test_overlapping_keys_and_methods(self): | ||
|  |         d = self.AttrDict(items=50) | ||
|  |         self.assertEqual(d['items'], 50) | ||
|  |         self.assertEqual(d.items(), dict(d).items()) | ||
|  | 
 | ||
|  |     def test_invalid_attribute_names(self): | ||
|  |         d = self.AttrDict({ | ||
|  |             'control': 'normal case', | ||
|  |             'class': 'keyword', | ||
|  |             'two words': 'contains space', | ||
|  |             'hypen-ate': 'contains a hyphen' | ||
|  |         }) | ||
|  |         self.assertEqual(d.control, dict(d)['control']) | ||
|  |         self.assertEqual(d['class'], dict(d)['class']) | ||
|  |         self.assertEqual(d['two words'], dict(d)['two words']) | ||
|  |         self.assertEqual(d['hypen-ate'], dict(d)['hypen-ate']) | ||
|  | 
 | ||
|  |     def test_object_hook_use_case(self): | ||
|  |         AttrDict = self.AttrDict | ||
|  |         json_string = self.dumps(kepler_dict) | ||
|  |         kepler_ad = self.loads(json_string, object_hook=AttrDict) | ||
|  | 
 | ||
|  |         self.assertEqual(kepler_ad, kepler_dict)     # Match regular dict | ||
|  |         self.assertIsInstance(kepler_ad, AttrDict)   # Verify conversion | ||
|  |         self.assertIsInstance(kepler_ad.orbital_period, AttrDict)  # Nested | ||
|  | 
 | ||
|  |         # Exercise dotted lookups | ||
|  |         self.assertEqual(kepler_ad.orbital_period, kepler_dict['orbital_period']) | ||
|  |         self.assertEqual(kepler_ad.orbital_period.earth, | ||
|  |                          kepler_dict['orbital_period']['earth']) | ||
|  |         self.assertEqual(kepler_ad['orbital_period'].earth, | ||
|  |                          kepler_dict['orbital_period']['earth']) | ||
|  | 
 | ||
|  |         # Dict style error handling and Attribute style error handling | ||
|  |         with self.assertRaises(KeyError): | ||
|  |             kepler_ad.orbital_period['pluto'] | ||
|  |         with self.assertRaises(AttributeError): | ||
|  |             kepler_ad.orbital_period.Pluto | ||
|  | 
 | ||
|  |         # Order preservation | ||
|  |         self.assertEqual(list(kepler_ad.items()), list(kepler_dict.items())) | ||
|  |         self.assertEqual(list(kepler_ad.orbital_period.items()), | ||
|  |                              list(kepler_dict['orbital_period'].items())) | ||
|  | 
 | ||
|  |         # Round trip | ||
|  |         self.assertEqual(self.dumps(kepler_ad), json_string) | ||
|  | 
 | ||
|  |     def test_pickle(self): | ||
|  |         AttrDict = self.AttrDict | ||
|  |         json_string = self.dumps(kepler_dict) | ||
|  |         kepler_ad = self.loads(json_string, object_hook=AttrDict) | ||
|  | 
 | ||
|  |         # Pickling requires the cached module to be the real module | ||
|  |         cached_module = sys.modules.get('json') | ||
|  |         sys.modules['json'] = self.json | ||
|  |         try: | ||
|  |             for protocol in range(6): | ||
|  |                 kepler_ad2 = pickle.loads(pickle.dumps(kepler_ad, protocol)) | ||
|  |                 self.assertEqual(kepler_ad2, kepler_ad) | ||
|  |                 self.assertEqual(type(kepler_ad2), AttrDict) | ||
|  |         finally: | ||
|  |             sys.modules['json'] = cached_module | ||
|  | 
 | ||
|  | 
 | ||
|  | if __name__ == "__main__": | ||
|  |     unittest.main() |