Package amplee :: Package loader :: Module iniloader
[hide private]
[frames] | no frames]

Source Code for Module amplee.loader.iniloader

  1  # -*- coding: utf-8 -*- 
  2  __docformat__ = 'epytext'  
  3  __doc__ = """Atom Publising Store loader 
  4   
  5  Synopsis 
  6  -------- 
  7   
  8  The process of creating an Atom Publishing store is 
  9  a repetitive task that is common to all projects. 
 10   
 11  The loader module offers the possibility to automate 
 12  this task by putting required information in a 
 13  configuration file and let the `loader`function 
 14  generates the store from the configuration settings. 
 15   
 16  Consider the following: 
 17   
 18  >>> from amplee.loader import loader 
 19  >>> service, config = loader('/my/config.cfg') 
 20   
 21  The ``service`` object returned is an instance of 
 22  ``amplee.atompub.service.AtomPubService`` and is your 
 23  reference to all the related objects. 
 24   
 25  The ``config`` object is an instance of 
 26  ``amplee.loader.Config`` and is the representation 
 27  of your configuration file. 
 28   
 29  """ 
 30   
 31  import sys 
 32  import os.path 
 33  import imp 
 34  import re 
 35  import ConfigParser 
 36  from warnings import warn 
 37   
 38  warn('The INI loader will be deprecated in a future release of amplee.', DeprecationWarning) 
 39   
 40  from amplee.atompub.store import * 
 41  from amplee.atompub.service import * 
 42  from amplee.atompub.workspace import * 
 43  from amplee.atompub.collection import * 
 44  from amplee.utils import strip_list 
 45   
 46  __all__ = ['loader', 'Config'] 
 47   
48 -class Config(object):
49 """Represents an INI file as a tree of Config instances 50 51 Say you have C{test.conf}: 52 53 [general] 54 verbose = True 55 56 >>> from amplee.loader import Config 57 >>> config = Config() 58 >>> config.from_ini('test.conf') 59 >>> print config.general.verbose 60 >>> True 61 62 Each loaded value is an unicode object except the following strings: 63 - 'True' --> True 64 - 'False' --> False 65 - 'None' --> None 66 67 An empty string will not be transformed into a None though. 68 """
69 - def from_ini(self, filepath, encoding='ISO-8859-1'):
70 """Loads the configuration file into the current instance 71 of L{Config}. 72 73 >>> from amplee.loader import Config 74 >>> conf = Config() 75 >>> conf.from_ini('./my.conf') 76 77 @type filepath: string 78 @param filepath: path to the configuration file. 79 @type encoding: string 80 @param encoding: indicates how to decode each value. 81 """ 82 config = ConfigParser.ConfigParser() 83 config.readfp(file(filepath, 'rb')) 84 85 for section in config.sections(): 86 section_prop = Config() 87 section_prop.keys = [] 88 setattr(self, section, section_prop) 89 for option in config.options(section): 90 section_prop.keys.append(option) 91 value = self._convert_type(config.get(section, option).decode(encoding)) 92 setattr(section_prop, option, value)
93
94 - def get(self, section, option, default=None, raise_error=False):
95 """Retrieve the value for a particular node in the configuration tree. 96 97 >>> print config.get('general', 'verbose', default=1) 98 99 but also: 100 101 >>> try: 102 >>> config.get('general', 'verbose', raise_error=True) 103 >>> except AttributeError: 104 >>> print "Could not find 'general.verbose'" 105 106 @type section: string 107 @param section: name of the parent node of which L{option} is a child. 108 @type option: string 109 @param option: name of the node to lookup. 110 @type default: object 111 @param default: value when the node was not found. 112 This applies when L{raise_error} is C{False}, which is the default. 113 @type raise_error: bool 114 @param raise_error: set to C{True} an L{AttributeError} 115 exception will be raised if the node is not found. 116 @rtype: object 117 @return: the retrieved value or default. 118 """ 119 if hasattr(self, section): 120 obj = getattr(self, section, None) 121 if obj and hasattr(obj, option): 122 return getattr(obj, option, default) 123 124 if raise_error: 125 raise AttributeError, "%s %s" % (section, option) 126 127 return default
128
129 - def _convert_type(self, value):
130 """Do dummy conversion of the string 'True', 'False' and 'None' 131 into their object equivalent""" 132 if value == 'True': 133 return True 134 elif value == 'False': 135 return False 136 elif value == 'None': 137 return None 138 return value
139
140 - def get_section(self, section):
141 return getattr(self, section, None)
142
143 - def get_all_values(self, section, capitalize=False):
144 """Returns a dictionnary of all nodes which parent is the section. 145 146 @type section: string 147 @param section: name of the parent node to look for. 148 @type capitalize: bool 149 @param capitalize: indicates if the keys of the 150 dictionnary should start with a capital letter. 151 @rtype: dict 152 @return: dictionnary of all the nodes which parent is the 153 specified section. 154 """ 155 values = {} 156 if hasattr(self, section): 157 obj = getattr(self, section, None) 158 for key in obj.keys: 159 if hasattr(obj, key): 160 if capitalize: 161 values[key.capitalize()] = getattr(obj, key, None) 162 else: 163 values[key] = getattr(obj, key, None) 164 165 return values
166 167 _module_callable_regex = re.compile('module:(.*),callable:(.*)') 168 _module_symbol_regex = re.compile('module:(.*),symbol:(.*)') 169
170 -def init_storage(config, storage, base_path=None):
171 """Initializes a storage as described in the configuration object. 172 173 [svn_storage] 174 repository_uri = file:///var/repo 175 working_copy_path = /home/my/copy 176 username = test 177 password = 178 179 >>> from amplee.loader import loader, Config 180 >>> conf = Config() 181 >>> conf.from_ini('./my.conf') 182 >>> storage = loader.init_storage(conf, 'svn_storage') 183 184 @type config: L{Conf} 185 @param config: instance of a configuration object 186 @type storage: string 187 @param storage: section name of the storage to load. 188 @type base_path: string 189 @param base_path: only required when your configuration 190 settings use relative path in their values. 191 @rtype: object 192 @return: instance of the loaded storage 193 """ 194 if storage.startswith('fs_storage'): 195 from amplee.storage import storefs 196 root_dir = config.get(storage, 'base_path') 197 if base_path and not os.path.isabs(root_dir): 198 root_dir = os.path.join(base_path, root_dir) 199 enable_lock = config.get(storage, 'enable_lock', False) 200 encoding = config.get(storage, 'encoding', 'utf-8') 201 return storefs.FilesystemStorage(root_dir, enable_lock, encoding=encoding) 202 elif storage.startswith('svn_storage'): 203 from amplee.storage import storesvn 204 repository_uri = config.get(storage, 'repository_uri') 205 working_copy_path = config.get(storage, 'working_copy_path') 206 if base_path: 207 working_copy_path = os.path.join(base_path, working_copy_path) 208 username = config.get(storage, 'username', '') 209 password = config.get(storage, 'password', '') 210 if username == '': username = None 211 if password == '': password = None 212 return storesvn.SubversionStorage(repository_uri, working_copy_path, username, password) 213 elif storage.startswith('zodb_storage'): 214 from ZODB import DB 215 from amplee.storage import storezodb 216 fs_type = config.get(storage, 'fs_type', 'filestorage') 217 if fs_type == 'filestorage': 218 from ZODB import FileStorage 219 storage_path = config.get(storage, 'fs_path') 220 if base_path: 221 storage_path = os.path.join(base_path, storage_path) 222 db = DB(FileStorage.FileStorage(storage_path)) 223 elif fs_type == 'clientstorage': 224 from ZEO import ClientStorage 225 db = DB(ClientStorage.ClientStorage(config.get(storage, 'address'))) 226 return storezodb.ZODBStorage(db, config.get(storage, 'top_level_node_name')) 227 elif storage.startswith('dejavu_storage'): 228 from amplee.storage import storedejavu 229 capitalize = config.get(storage, 'capitalize', True) 230 conf = config.get_all_values(storage, capitalize=capitalize) 231 return storedejavu.DejavuStorage(config.get(storage, 'db_type'), conf) 232 elif storage.startswith('sqlite_storage'): 233 from amplee.storage import storesqlite3 234 return storesqlite3.SQLite3Storage(connection=config.get(storage, 'connection')) 235 elif storage.startswith('s3_storage'): 236 from amplee.storage import stores3 237 aws_access_key_id = config.get(storage, 'access_key') 238 aws_secret_access_key = config.get(storage, 'private_key') 239 unique_prefix = config.get(storage, 'bucket_unique_prefix') 240 encoding = config.get(storage, 'encoding', 'utf-8') 241 separator = config.get(storage, 'separator', '_') 242 aws_key_lookup = config.get(storage, 'aws_key_lookup', None) 243 aws_file_path = None 244 if aws_key_lookup: 245 aws_key_lookup = _load_callable(aws_key_lookup, base_path) 246 aws_file_path = config.get(storage, 'aws_file_path', None) 247 return stores3.S3Storage(aws_access_key_id, aws_secret_access_key, 248 unique_prefix, encoding=encoding, 249 separator=separator, aws_key_lookup=aws_key_lookup, 250 aws_file_path=aws_file_path) 251 elif storage.startswith('tar_storage'): 252 from amplee.storage import storetar 253 root_dir = config.get(storage, 'base_path') 254 if base_path and not os.path.isabs(root_dir): 255 root_dir = os.path.join(base_path, root_dir) 256 compression = config.get(storage, 'compression', 'gz') 257 encoding = config.get(storage, 'encoding', 'utf-8') 258 return storetar.TarFileStorage(root_dir, compression=compression, encoding=encoding) 259 elif storage.startswith('nonbuiltin_storage'): 260 storage_module = config.get(storage, 'storage_module') 261 storage_class = config.get(storage, 'storage_class') 262 directory, name = os.path.split(storage_module) 263 if base_path: 264 directory = os.path.join(base_path, directory) 265 266 file, filename, description = imp.find_module(name, [directory]) 267 mod = imp.load_module(name, file, filename, description) 268 mod_class = getattr(mod_class, storage_class, None) 269 if not mod_class: 270 raise RuntimeError, "could not load non built-in storage %s" % storage 271 272 return mod_class(config=getattr(config, storage, None))
273
274 -def init_workspaces(config, service, base_path=None):
275 """Initializes the Atom Publishing Protocol workspaces from the 276 provided service. 277 278 @type config: L{Conf} 279 @param config: instance of a configuration object 280 @type service: L{AtomPubService} 281 @param service: service instance 282 @type base_path: string 283 @param base_path: if provided, every relative path will be resolved to that 284 base path. 285 """ 286 workspaces = strip_list(config.get('store', 'workspaces', '').split(',')) 287 for workspace_name in workspaces: 288 name = config.get(workspace_name, 'name') 289 title = config.get(workspace_name, 'title') 290 xml_attrs = get_xml_attribs(config, workspace_name) 291 workspace = AtomPubWorkspace(service, name, title=title, xml_attrs=xml_attrs) 292 init_collections(config, workspace_name, workspace, base_path)
293
294 -def get_xml_attribs(config, section_name):
295 """Returns a dictionary of xml attributes with their associated value.""" 296 xml_attrs = config.get(section_name, 'xml_attrs', None) 297 if xml_attrs: 298 attrs = strip_list(xml_attrs.split(';')) 299 xml_attrs = {} 300 for attr in attrs: 301 key, value = attr.split(',') 302 xml_attrs[key] = value 303 return xml_attrs or {}
304
305 -def init_collections(config, workspace_name, workspace, base_path=None):
306 """Initializes the Atom Publishing Protocol collections from the 307 provided workspace. 308 309 @type config: L{Conf} 310 @param config: instance of a configuration object 311 @type workspace_name: string 312 @param workspace_name: name of the section associated with the parent workspace 313 @type workspace: L{AtomPubWorkspace} 314 @param workspace: loaded workspace 315 @type base_path: string 316 @param base_path: if provided, every relative path will be resolved to that 317 base path. 318 """ 319 collections = strip_list(config.get(workspace_name, 'collections', '').split(',')) 320 for collection_name in collections: 321 base_uri = config.get(collection_name, 'base_uri', u'') 322 id = config.get(collection_name, 'name', raise_error=True) 323 title = config.get(collection_name, 'title', raise_error=True) 324 base_edit_uri = config.get(collection_name, 'base_edit_uri') 325 base_media_edit_uri = config.get(collection_name, 'base_media_edit_uri', None) 326 accept_media_types = config.get(collection_name, 'accept_media_types', []) 327 editable_media_types = config.get(collection_name, 'editable_media_types', None) 328 member_media_type = config.get(collection_name, 'member_media_type', u'application/atom+xml;type=entry') 329 member_extension = config.get(collection_name, 'member_media_extension', u'atom') 330 if accept_media_types: 331 accept_media_types = strip_list(accept_media_types.split(',')) 332 if editable_media_types: 333 editable_media_types = strip_list(editable_media_types.split(',')) 334 favorite = config.get(collection_name, 'favorite', False) 335 fixed_categories = config.get(collection_name, 'fixed_categories', False) 336 xml_attrs = get_xml_attribs(config, collection_name) 337 338 cats = handle_categories(config, collection_name) 339 340 collection = AtomPubCollection(workspace, name_or_id=id, title=title, 341 xml_attrs=xml_attrs, favorite=favorite, 342 base_uri=base_uri, base_edit_uri=base_edit_uri, 343 base_media_edit_uri=base_media_edit_uri, 344 accept_media_types=accept_media_types, 345 fixed_categories=fixed_categories, 346 categories=cats, 347 member_media_type=member_media_type, 348 member_extension=member_extension, 349 editable_media_types=editable_media_types) 350 read_only = config.get(collection_name, 'read_only', False) 351 collection.is_read_only = read_only 352 353 set_collection_attributes(config, workspace_name, workspace, collection_name, collection, base_path)
354
355 -def set_collection_attributes(config, workspace_name, workspace, 356 collection_name, collection, base_path=None):
357 with_cache = config.get(collection_name, 'enable_cache') 358 if with_cache == None: 359 with_cache = config.get(workspace_name, 'enable_cache', True) 360 361 if with_cache: 362 collection.enable_cache() 363 364 member_class = config.get(collection_name, 'member_class') 365 if not member_class: 366 member_class = config.get(workspace_name, 'member_class', None) 367 368 if member_class: 369 member_class = _load_symbol(member_class, base_path) 370 collection.set_member_class(member_class) 371 372 autoreload = config.get(collection_name, 'reload_members') 373 if autoreload ==<