Back to index

moin  1.9.0~rc2
fieldmappings.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright (C) 2007 Lemur Consulting Ltd
00004 #
00005 # This program is free software; you can redistribute it and/or modify
00006 # it under the terms of the GNU General Public License as published by
00007 # the Free Software Foundation; either version 2 of the License, or
00008 # (at your option) any later version.
00009 #
00010 # This program is distributed in the hope that it will be useful,
00011 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 # GNU General Public License for more details.
00014 # 
00015 # You should have received a copy of the GNU General Public License along
00016 # with this program; if not, write to the Free Software Foundation, Inc.,
00017 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018 r"""fieldmappings.py: Mappings from field names to term prefixes, etc.
00019 
00020 """
00021 __docformat__ = "restructuredtext en"
00022 
00023 import cPickle as _cPickle
00024 
00025 class FieldMappings(object):
00026     """Mappings from field names to term prefixes, slot values, etc.
00027 
00028     The following mappings are maintained:
00029 
00030     - a mapping from field name to the string prefix to insert at the start of
00031       terms.
00032     - a mapping from field name to the slot numbers to store the field contents
00033       in.
00034 
00035     """
00036     __slots__ = '_prefixes', '_prefixcount', '_slots', '_slotcount', 
00037 
00038     def __init__(self, serialised=None):
00039         """Create a new field mapping object, or unserialise a saved one.
00040 
00041         """
00042         if serialised is not None:
00043             (self._prefixes, self._prefixcount,
00044              self._slots, self._slotcount) = _cPickle.loads(serialised)
00045         else:
00046             self._prefixes = {}
00047             self._prefixcount = 0
00048             self._slots = {}
00049             self._slotcount = 0
00050 
00051     def _genPrefix(self):
00052         """Generate a previously unused prefix.
00053 
00054         Prefixes are uppercase letters, and start with 'X' (this is a Xapian
00055         convention, for compatibility with other Xapian tools: other starting
00056         letters are reserved for special meanings):
00057 
00058         >>> maps = FieldMappings()
00059         >>> maps._genPrefix()
00060         'XA'
00061         >>> maps._genPrefix()
00062         'XB'
00063         >>> [maps._genPrefix() for i in xrange(60)]
00064         ['XC', 'XD', 'XE', 'XF', 'XG', 'XH', 'XI', 'XJ', 'XK', 'XL', 'XM', 'XN', 'XO', 'XP', 'XQ', 'XR', 'XS', 'XT', 'XU', 'XV', 'XW', 'XX', 'XY', 'XZ', 'XAA', 'XBA', 'XCA', 'XDA', 'XEA', 'XFA', 'XGA', 'XHA', 'XIA', 'XJA', 'XKA', 'XLA', 'XMA', 'XNA', 'XOA', 'XPA', 'XQA', 'XRA', 'XSA', 'XTA', 'XUA', 'XVA', 'XWA', 'XXA', 'XYA', 'XZA', 'XAB', 'XBB', 'XCB', 'XDB', 'XEB', 'XFB', 'XGB', 'XHB', 'XIB', 'XJB']
00065         >>> maps = FieldMappings()
00066         >>> [maps._genPrefix() for i in xrange(27*26 + 5)][-10:]
00067         ['XVZ', 'XWZ', 'XXZ', 'XYZ', 'XZZ', 'XAAA', 'XBAA', 'XCAA', 'XDAA', 'XEAA']
00068         """
00069         res = []
00070         self._prefixcount += 1
00071         num = self._prefixcount
00072         while num != 0:
00073             ch = (num - 1) % 26
00074             res.append(chr(ch + ord('A')))
00075             num -= ch
00076             num = num // 26
00077         return 'X' + ''.join(res)
00078 
00079     def get_fieldname_from_prefix(self, prefix):
00080         """Get a fieldname from a prefix.
00081 
00082         If the prefix is not found, return None.
00083 
00084         """
00085         for key, val in self._prefixes.iteritems():
00086             if val == prefix:
00087                 return key
00088         return None
00089 
00090     def get_prefix(self, fieldname):
00091         """Get the prefix used for a given field name.
00092 
00093         """
00094         return self._prefixes[fieldname]
00095 
00096     def get_slot(self, fieldname, purpose):
00097         """Get the slot number used for a given field name and purpose.
00098 
00099         """
00100         return self._slots[(fieldname, purpose)]
00101 
00102     def add_prefix(self, fieldname):
00103         """Allocate a prefix for the given field.
00104 
00105         If a prefix is already allocated for this field, this has no effect.
00106 
00107         """
00108         if fieldname in self._prefixes:
00109             return
00110         self._prefixes[fieldname] = self._genPrefix()
00111 
00112     def add_slot(self, fieldname, purpose, slotnum=None):
00113         """Allocate a slot number for the given field and purpose.
00114 
00115         If a slot number is already allocated for this field and purpose, this
00116         has no effect.
00117 
00118         Returns the slot number allocated for the field and purpose (whether
00119         newly allocated, or previously allocated).
00120 
00121         If `slotnum` is supplied, the number contained in it is used to
00122         allocate the new slot, instead of allocating a new number.  No checks
00123         will be made to ensure that the slot number doesn't collide with
00124         existing (or later allocated) numbers: the main purpose of this
00125         parameter is to share allocations - ie, to collide deliberately.
00126 
00127         """
00128         try:
00129             return self._slots[(fieldname, purpose)]
00130         except KeyError:
00131             pass
00132 
00133         if slotnum is None:
00134             self._slots[(fieldname, purpose)] = self._slotcount
00135             self._slotcount += 1
00136             return self._slotcount - 1
00137         else:
00138             self._slots[(fieldname, purpose)] = slotnum
00139             return slotnum
00140 
00141     def serialise(self):
00142         """Serialise the field mappings to a string.
00143 
00144         This can be unserialised by passing the result of this method to the
00145         constructor of a new FieldMappings object.
00146 
00147         """
00148         return _cPickle.dumps((self._prefixes,
00149                                self._prefixcount,
00150                                self._slots,
00151                                self._slotcount,
00152                               ), 2)