Package Pyblio :: Module Registry
[hide private]
[frames] | no frames]

Source Code for Module Pyblio.Registry

  1  # This file is part of pybliographer 
  2  #  
  3  # Copyright (C) 1998-2006 Frederic GOBRY 
  4  # Email : gobry@pybliographer.org 
  5  #           
  6  # This program is free software; you can redistribute it and/or 
  7  # modify it under the terms of the GNU General Public License 
  8  # as published by the Free Software Foundation; either version 2  
  9  # of the License, or (at your option) any later version. 
 10  #    
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details.  
 15  #  
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
 19  #  
 20   
 21  """ 
 22  Support for RIP files. 
 23   
 24  RIP files are files containing registering information for schemas, 
 25  and extension classes customized for these schemas (like importers, 
 26  exporters, citation formatters,...) 
 27   
 28  First, you need to parse a few RIP repositories with L{parse}, then 
 29  you can browse the results with L{schemas}, L{getSchema} and L{get}. 
 30  """ 
 31   
 32  import os, re 
 33   
 34  from ConfigParser import SafeConfigParser as Parser 
 35   
 36  from Pyblio import Schema 
 37   
 38  from gettext import gettext as _ 
 39   
 40   
 41  # Global registry of schemas 
 42  _schema = {} 
 43   
 44  # We have a system-wide directory of RIPs that is known to the system, 
 45  # and a local one, in the user's home directory. 
 46  import Pyblio 
 47   
 48  _base = os.path.abspath(os.path.dirname(Pyblio.__file__)) 
 49  _user = os.path.expanduser('~/.pyblio') 
 50   
 51  RIP_dirs = { 
 52      'system': os.path.join(_base, 'RIP'), 
 53      'user': _user, 
 54      } 
 55   
 56   
57 -def get(schema, category):
58 """ Return the extensions in a given category, for a given schema.""" 59 60 try: 61 return _schema[schema][category] 62 except KeyError: 63 return []
64
65 -def getSchema(schema):
66 """ Return the L{Pyblio.Schema.Schema} corresponding to an 67 identifier returned by L{schemas}.""" 68 69 rip = _schema[schema] 70 71 s = Schema.Schema(open(rip.path)) 72 73 assert s.id == schema, _('schema %s has not the same id %s as in the RIP files') % ( 74 rip.path, schema) 75 return s
76 77
78 -def schemas():
79 """ Return the list of known schemas.""" 80 81 return [k for k in _schema.keys() if _schema[k].path]
82 83
84 -def reset():
85 """ Forget all the schemas and extensions previously parsed with 86 L{parse}. 87 """ 88 89 global _schema 90 _schema = {}
91 92
93 -class RIP(object):
94 95 """ A RIP object represents a dynamic class that can be loaded on 96 demand, and that has been registered via the Registry system. 97 98 These objects are usually not instanciated by the user, but 99 returned by L{get}.""" 100
101 - def __init__(self, schema, category, name):
102 self.schema = schema 103 self.category = category 104 self.name = name 105 self._module = None 106 return
107
108 - def __call__(self):
109 """ When the RIP is called, it returns the dynamic class it 110 refers to, or raises an ImportError exception. 111 """ 112 113 if not self._module: 114 parts = self.name.split('.') 115 116 module = __import__('.'.join(parts[:-1])) 117 118 for comp in parts[1:]: 119 module = getattr (module, comp) 120 121 self._module = module 122 123 return self._module
124
125 - def help(self):
126 """ Return some help associated with the corresponding dynamic class. 127 128 Warning: this forces loading of the class. 129 """ 130 131 m = self() 132 133 doc = m.__doc__ 134 135 if not doc: 136 doc = _('undocumented %s' % repr(self.name)) 137 else: 138 doc = doc.lstrip() 139 doc = doc.split('\n')[0].rstrip(' .\n') 140 141 return doc
142
143 -class AdapterRIP(RIP):
144 """ A special RIP that keeps the description of an Adapter.""" 145
146 - def __init__(self, schema, category, name, target):
147 RIP.__init__(self, schema, category, name) 148 149 self.target = target 150 return
151 152 _adapt_re = re.compile(r'([\w\d.]+)\s*->\s*([\w\d./]+)') 153
154 -class _RIPCategory(dict):
155 - def __init__(self, schema):
156 dict.__init__(self) 157 self.schema = schema 158 self.path = None 159 return
160 161
162 -def load_settings(directory):
163 """ Parse the specified directory, and load all the .rip files it 164 contains.""" 165 166 for f in os.listdir(directory): 167 base, ext = os.path.splitext(f) 168 if ext != '.rip': continue 169 170 name = os.path.join(directory, f) 171 172 allvars = {} 173 allvars.update(RIP_dirs) 174 allvars['cwd'] = directory 175 176 p = Parser(allvars) 177 p.readfp(open(name), name) 178 179 for schema in p.sections(): 180 for cat in p.options(schema): 181 value = p.get(schema, cat).strip() 182 183 # Schema are special values, which are not merged but 184 # checked for unicity. 185 if cat == 'path': 186 if _schema.has_key(schema): 187 s = _schema[schema] 188 assert (s.path is None or 189 s.path == value), \ 190 _('Schema %s is available in %s and %s') % ( 191 schema, s.path, value) 192 193 s.path = value 194 195 else: 196 r = _RIPCategory(schema) 197 r.path = value 198 199 _schema[schema] = r 200 201 continue 202 203 if cat == 'adapters': 204 names = [] 205 for m, t in _adapt_re.findall(value): 206 names.append(AdapterRIP(schema, cat, m, t)) 207 208 209 else: 210 names = [RIP(schema, cat, x.strip()) 211 for x in value.split('\n') ] 212 213 # For the other fields, we simply extend the list 214 # of known values. 215 try: 216 _schema[schema].setdefault(cat,[]).extend(names) 217 218 except KeyError: 219 r = _RIPCategory(schema) 220 r[cat] = names 221 222 _schema[schema] = r 223 224 return
225
226 -def load_default_settings():
227 """Load the RIP files contained in the default system-wide and 228 user-specific directories. 229 230 The system directory is in '<installation prefix>/Pyblio/RIP', and 231 the user directory is '~/.pyblio'. 232 """ 233 for d in RIP_dirs.values(): 234 try: 235 load_settings(d) 236 except OSError: 237 pass 238 return
239