Package pyperry :: Package adapter :: Module abstract_adapter
[frames] | no frames]

Source Code for Module pyperry.adapter.abstract_adapter

  1  """ 
  2  Adapter Overview 
  3  ================ 
  4   
  5  Adapters provide the bridge between the mapped object and the data store. 
  6  There are several layers to an adapter request and response:: 
  7   
  8       Req  Resp 
  9    pyperry.base.Base 
 10        |     ^ 
 11        V     | 
 12      Processors 
 13        |     ^ 
 14        V     | 
 15      Model Bridge 
 16        |     ^ 
 17        V     | 
 18      Middlewares 
 19        |     ^ 
 20        V     | 
 21        Adapter 
 22          \/ 
 23        Database 
 24   
 25  The request is initiated by the L{pyperry.base.Base} class and passes through 
 26  the adapter stack returning a response.  Within the stack the request goes 
 27  through a series of configurable stack items: processors, and middlewares 
 28  before being passed to the appropriate adapter method.  That adapter method 
 29  then executes the requested action and returns the results back through the 
 30  stack until returning to Base. 
 31   
 32  Processors and middlewares are ways of customizing requests and responses. 
 33  There is a middleware that is always installed called the ModelBridge.  It 
 34  takes the raw response of the adapter and converts it to mapped objects.  The 
 35  only difference between a middleware and a processor is that the objects 
 36  returned to a processor are always instantiated records whereas middlewares 
 37  receive the raw response. 
 38   
 39  """ 
 40  from copy import copy 
 41  import socket 
 42   
 43  import pyperry 
 44  from pyperry import errors 
 45  from pyperry.middlewares.model_bridge import ModelBridge 
46 47 -class DelayedConfig(object):
48 """ 49 Simple class that takes kwargs or a dictionary in initializer and sets 50 values to the class dictionary. Any values set as lambdas will be 51 evaluated when they are accessed. 52 """ 53
54 - def __init__(self, *args, **kwargs):
55 """Set values in kwargs to attributes""" 56 if not kwargs and len(args) is 1: 57 kwargs = args[0] 58 59 for k, v in kwargs.items(): 60 self.__dict__[k] = v
61
62 - def __getattribute__(self, key):
63 attr = object.__getattribute__(self, key) 64 if type(attr).__name__ == 'function': 65 attr = attr() 66 return attr
67
68 69 -class AbstractAdapter(object):
70 """The base class for all adapters""" 71 72 adapter_types = ['read', 'write'] 73
74 - def __init__(self, config, mode=None, middlewares=None, processors=[]):
75 """ 76 Create a new adapter object with the given configuration running as a 77 `mode` adapter 78 """ 79 if not middlewares: 80 middlewares = [(ModelBridge, {})] 81 82 self.config = DelayedConfig(config) 83 self.mode = mode 84 self.middlewares = middlewares 85 self.processors = processors 86 self._stack = None 87 88 if hasattr(self.config, 'timeout'): 89 socket.setdefaulttimeout(self.config.timeout) 90 elif socket.getdefaulttimeout() is None: 91 socket.setdefaulttimeout(10) 92 93 # Add in configured middlewares 94 if hasattr(self.config, '_middlewares'): 95 self.middlewares = self.middlewares + self.config._middlewares 96 if hasattr(self.config, '_processors'): 97 self.processors = self.processors + self.config._processors 98 99 if not mode in self.adapter_types: 100 raise errors.ConfigurationError("Adapter requires `mode` keyword")
101 102 @property
103 - def stack(self):
104 """ 105 Setup the stack plumbing with the configured stack items 106 107 Wrap each stack item (processors and middleware) in reverse order 108 around the call to the adapter method. This will allow stack items to 109 intercept requests, modify query information and pass it along, do 110 things with the results of the query or any combination of these 111 things. 112 113 """ 114 if self._stack: return self._stack 115 116 self._stack = self.execute 117 stack_items = copy(self.processors) + copy(self.middlewares) 118 stack_items.reverse() 119 120 for (klass, config) in stack_items: 121 self._stack = klass(self._stack, config) 122 123 return self._stack
124
125 - def reset(self):
126 """Clear out the stack causing it to be rebuilt on the next request""" 127 self._stack = None
128
129 - def __call__(self, **kwargs):
130 """Makes a request to the stack""" 131 pyperry.logger.info('%s: %s' % (self.mode, kwargs.keys())) 132 if 'mode' not in kwargs: 133 kwargs.update(mode=self.mode) 134 result = self.stack(**kwargs) 135 136 if self.mode is 'read' and not hasattr(result, '__iter__'): 137 raise errors.BrokenAdapterStack( 138 "The adapter stack failed to return an iterable object" ) 139 140 return result
141
142 - def execute(self, **kwargs):
143 """Call read, write, or delete according to the mode kwarg.""" 144 return getattr(self, kwargs['mode'])(**kwargs)
145
146 - def read(self, **kwargs):
147 """Read from the datastore with the provided options""" 148 raise NotImplementedError("You must define this method in subclasses")
149
150 - def write(self, **kwargs):
151 """Write object's attributes to the datastore""" 152 raise NotImplementedError("You must define this method in subclasses")
153
154 - def delete(self, **kwargs):
155 """Delete the object from the datastore""" 156 raise NotImplementedError("You must define this method in subclasses")
157