xappy.fieldmappings

Package xappy :: Module fieldmappings |
[frames] | no frames]

# Source Code for Module xappy.fieldmappings

      1  #!/usr/bin/env python
      2  #
      3  # Copyright (C) 2007 Lemur Consulting Ltd
      4  #
      5  # This program is free software; you can redistribute it and/or modify
      6  # it under the terms of the GNU General Public License as published by
      7  # the Free Software Foundation; either version 2 of the License, or
      8  # (at your option) any later version.
      9  #
     10  # This program is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  # GNU General Public License for more details.
     14  #
     15  # You should have received a copy of the GNU General Public License along
     16  # with this program; if not, write to the Free Software Foundation, Inc.,
     17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18  r"""fieldmappings.py: Mappings from field names to term prefixes, etc.
     19
     20  """
     21  __docformat__ = "restructuredtext en"
     22
     23  import cPickle as _cPickle
     24
     25 -class FieldMappings(object):
     26      """Mappings from field names to term prefixes, slot values, etc.
     27
     28      The following mappings are maintained:
     29
     30      - a mapping from field name to the string prefix to insert at the start of
     31        terms.
     32      - a mapping from field name to the slot numbers to store the field contents
     33        in.
     34
     35      """
     36      __slots__ = '_prefixes', '_prefixcount', '_slots', '_slotcount',
     37
     38 -    def __init__(self, serialised=None):
     39          """Create a new field mapping object, or unserialise a saved one.
     40
     41          """
     42          if serialised is not None:
     43              (self._prefixes, self._prefixcount,
     44               self._slots, self._slotcount) = _cPickle.loads(serialised)
     45          else:
     46              self._prefixes = {}
     47              self._prefixcount = 0
     48              self._slots = {}
     49              self._slotcount = 0
     50
     51 -    def _genPrefix(self):
     52          """Generate a previously unused prefix.
     53
     54          Prefixes are uppercase letters, and start with 'X' (this is a Xapian
     55          convention, for compatibility with other Xapian tools: other starting
     56          letters are reserved for special meanings):
     57
     58          >>> maps = FieldMappings()
     59          >>> maps._genPrefix()
     60          'XA'
     61          >>> maps._genPrefix()
     62          'XB'
     63          >>> [maps._genPrefix() for i in xrange(60)]
     64          ['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']
     65          >>> maps = FieldMappings()
     66          >>> [maps._genPrefix() for i in xrange(27*26 + 5)][-10:]
     67          ['XVZ', 'XWZ', 'XXZ', 'XYZ', 'XZZ', 'XAAA', 'XBAA', 'XCAA', 'XDAA', 'XEAA']
     68          """
     69          res = []
     70          self._prefixcount += 1
     71          num = self._prefixcount
     72          while num != 0:
     73              ch = (num - 1) % 26
     74              res.append(chr(ch + ord('A')))
     75              num -= ch
     76              num = num // 26
     77          return 'X' + ''.join(res)
     78
     79 -    def get_fieldname_from_prefix(self, prefix):
     80          """Get a fieldname from a prefix.
     81
     82          If the prefix is not found, return None.
     83
     84          """
     85          for key, val in self._prefixes.iteritems():
     86              if val == prefix:
     87                  return key
     88          return None
     89
     90 -    def get_prefix(self, fieldname):
     91          """Get the prefix used for a given field name.
     92
     93          """
     94          return self._prefixes[fieldname]
     95
     96 -    def get_slot(self, fieldname, purpose):
     97          """Get the slot number used for a given field name and purpose.
     98
     99          """
    100          return self._slots[(fieldname, purpose)]
    101
    102 -    def add_prefix(self, fieldname):
    103          """Allocate a prefix for the given field.
    104
    105          If a prefix is already allocated for this field, this has no effect.
    106
    107          """
    108          if fieldname in self._prefixes:
    109              return
    110          self._prefixes[fieldname] = self._genPrefix()
    111
    112 -    def add_slot(self, fieldname, purpose, slotnum=None):
    113          """Allocate a slot number for the given field and purpose.
    114
    115          If a slot number is already allocated for this field and purpose, this
    116          has no effect.
    117
    118          Returns the slot number allocated for the field and purpose (whether
    119          newly allocated, or previously allocated).
    120
    121          If `slotnum` is supplied, the number contained in it is used to
    122          allocate the new slot, instead of allocating a new number.  No checks
    123          will be made to ensure that the slot number doesn't collide with
    124          existing (or later allocated) numbers: the main purpose of this
    125          parameter is to share allocations - ie, to collide deliberately.
    126
    127          """
    128          try:
    129              return self._slots[(fieldname, purpose)]
    130          except KeyError:
    131              pass
    132
    133          if slotnum is None:
    134              self._slots[(fieldname, purpose)] = self._slotcount
    135              self._slotcount += 1
    136              return self._slotcount - 1
    137          else:
    138              self._slots[(fieldname, purpose)] = slotnum
    139              return slotnum
    140
    141 -    def serialise(self):
    142          """Serialise the field mappings to a string.
    143
    144          This can be unserialised by passing the result of this method to the
    145          constructor of a new FieldMappings object.
    146
    147          """
    148          return _cPickle.dumps((self._prefixes,
    149                                 self._prefixcount,
    150                                 self._slots,
    151                                 self._slotcount,
    152                                ), 2)
    153