| 1 | 1 |  | import json | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 | 1 |  | from .attributesholder import AttributesHolder | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 5 | 1 |  | class SerializableAttributesHolder(AttributesHolder): | 
            
                                                        
            
                                    
            
            
                | 6 |  |  |     """AttributesHolder with methods handling serialization and | 
            
                                                        
            
                                    
            
            
                | 7 |  |  |     deserialization according to the PPP datamodel specification.""" | 
            
                                                        
            
                                    
            
            
                | 8 | 1 |  |     def as_dict(self): | 
            
                                                        
            
                                    
            
            
                | 9 |  |  |         """Returns a JSON-serializeable object representing this tree.""" | 
            
                                                        
            
                                    
            
            
                | 10 | 1 |  |         def conv(v): | 
            
                                                        
            
                                    
            
            
                | 11 | 1 |  |             if isinstance(v, SerializableAttributesHolder): | 
            
                                                        
            
                                    
            
            
                | 12 | 1 |  |                 return v.as_dict() | 
            
                                                        
            
                                    
            
            
                | 13 | 1 |  |             elif isinstance(v, list): | 
            
                                                        
            
                                    
            
            
                | 14 | 1 |  |                 return [conv(x) for x in v] | 
            
                                                        
            
                                    
            
            
                | 15 | 1 |  |             elif isinstance(v, dict): | 
            
                                                        
            
                                    
            
            
                | 16 | 1 |  |                 return {x:conv(y) for (x,y) in v.items()} | 
            
                                                        
            
                                    
            
            
                | 17 |  |  |             else: | 
            
                                                        
            
                                    
            
            
                | 18 | 1 |  |                 return v | 
            
                                                        
            
                                    
            
            
                | 19 | 1 |  |         return {k.replace('_', '-'): conv(v) for (k, v) in self._attributes.items()} | 
            
                                                        
            
                                    
            
            
                | 20 | 1 |  |     def as_json(self): | 
            
                                                        
            
                                    
            
            
                | 21 |  |  |         """Return a JSON dump of the object.""" | 
            
                                                        
            
                                    
            
            
                | 22 | 1 |  |         return json.dumps(self.as_dict()) | 
            
                                                        
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 24 | 1 |  |     @staticmethod | 
            
                                                        
            
                                    
            
            
                | 25 |  |  |     def _test_can_import_json(data): | 
            
                                                        
            
                                    
            
            
                | 26 |  |  |         """Sanity check on input JSON data""" | 
            
                                                        
            
                                    
            
            
                | 27 | 1 |  |         pass | 
            
                                                        
            
                                    
            
            
                | 28 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 29 | 1 |  |     @classmethod | 
            
                                                        
            
                                    
            
            
                | 30 |  |  |     def from_json(cls, data): | 
            
                                                        
            
                                    
            
            
                | 31 |  |  |         """Decode a JSON string and inflate a node instance.""" | 
            
                                                        
            
                                    
            
            
                | 32 |  |  |         # Decode JSON string | 
            
                                                        
            
                                    
            
            
                | 33 | 1 |  |         assert isinstance(data, str) | 
            
                                                        
            
                                    
            
            
                | 34 | 1 |  |         data = json.loads(data) | 
            
                                                        
            
                                    
            
            
                | 35 | 1 |  |         assert isinstance(data, dict) | 
            
                                                        
            
                                    
            
            
                | 36 | 1 |  |         return cls.from_dict(data) | 
            
                                                        
            
                                    
            
            
                | 37 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 38 | 1 |  |     @classmethod | 
            
                                                        
            
                                    
            
            
                | 39 |  |  |     def from_dict(cls, data): | 
            
                                                        
            
                                    
            
            
                | 40 | 1 |  |         cls._test_can_import_json(data) | 
            
                                                        
            
                                    
            
            
                | 41 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 42 |  |  |         # Find a class that will deserialize the dict as specifically | 
            
                                                        
            
                                    
            
            
                | 43 |  |  |         # as possible | 
            
                                                        
            
                                    
            
            
                | 44 | 1 |  |         while True: | 
            
                                                        
            
                                    
            
            
                | 45 | 1 |  |             cls2 = cls._select_class(data) | 
            
                                                        
            
                                    
            
            
                | 46 | 1 |  |             if cls is cls2: | 
            
                                                        
            
                                    
            
            
                | 47 | 1 |  |                 break | 
            
                                                        
            
                                    
            
            
                | 48 | 1 |  |             cls = cls2 | 
            
                                                        
            
                                    
            
            
                | 49 | 1 |  |         conv = (lambda k,v: cls.deserialize_attribute(k, v) | 
            
                                                        
            
                                    
            
            
                | 50 |  |  |                             if isinstance(v, dict) else v) | 
            
                                                        
            
                                    
            
            
                | 51 | 1 |  |         data = {k.replace('-', '_'): conv(k,v) for (k, v) in data.items()} | 
            
                                                        
            
                                    
            
            
                | 52 | 1 |  |         return cls(**data) | 
            
                                                        
            
                                    
            
            
                | 53 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 54 | 1 |  |     @classmethod | 
            
                                                        
            
                                    
            
            
                | 55 |  |  |     def deserialize_attribute(cls, key, value): | 
            
                                                        
            
                                    
            
            
                | 56 | 1 |  |         return cls.from_dict(value) | 
            
                                                        
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                        
            
                                    
            
            
                | 58 | 1 |  |     @classmethod | 
            
                                                        
            
                                    
            
            
                | 59 |  |  |     def _select_class(cls, data): | 
            
                                                        
            
                                    
            
            
                | 60 |  |  |         return cls | 
            
                                                        
            
                                    
            
            
                | 61 |  |  |  |