Statistics
| Branch: | Tag: | Revision:

root / lib / compat.py @ 31d3b918

History | View | Annotate | Download (4.3 kB)

1
#
2
#
3

    
4
# Copyright (C) 2010, 2011 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# 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., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Module containing backported language/library functionality.
23

24
"""
25

    
26
import itertools
27
import operator
28

    
29
try:
30
  # pylint: disable=F0401
31
  import functools
32
except ImportError:
33
  functools = None
34

    
35
try:
36
  # pylint: disable=F0401
37
  import roman
38
except ImportError:
39
  roman = None
40

    
41

    
42
# compat.md5_hash and compat.sha1_hash can be called to generate and md5 and a
43
# sha1 hashing modules, under python 2.4, 2.5 and 2.6, even though some changes
44
# went on. compat.sha1 is python-version specific and is used for python
45
# modules (hmac, for example) which have changed their behavior as well from
46
# one version to the other.
47
try:
48
  # Yes, these don't always exist, that's why we're testing
49
  # Yes, we're not using the imports in this module.
50
  from hashlib import md5 as md5_hash # pylint: disable=W0611,E0611,F0401
51
  from hashlib import sha1 as sha1_hash # pylint: disable=W0611,E0611,F0401
52
  # this additional version is needed for compatibility with the hmac module
53
  sha1 = sha1_hash
54
except ImportError:
55
  from md5 import new as md5_hash
56
  import sha
57
  sha1 = sha
58
  sha1_hash = sha.new
59

    
60

    
61
def _all(seq):
62
  """Returns True if all elements in the iterable are True.
63

64
  """
65
  for _ in itertools.ifilterfalse(bool, seq):
66
    return False
67
  return True
68

    
69

    
70
def _any(seq):
71
  """Returns True if any element of the iterable are True.
72

73
  """
74
  for _ in itertools.ifilter(bool, seq):
75
    return True
76
  return False
77

    
78

    
79
try:
80
  # pylint: disable=E0601
81
  # pylint: disable=W0622
82
  all = all
83
except NameError:
84
  all = _all
85

    
86
try:
87
  # pylint: disable=E0601
88
  # pylint: disable=W0622
89
  any = any
90
except NameError:
91
  any = _any
92

    
93

    
94
def partition(seq, pred=bool): # pylint: disable=W0622
95
  """Partition a list in two, based on the given predicate.
96

97
  """
98
  return (list(itertools.ifilter(pred, seq)),
99
          list(itertools.ifilterfalse(pred, seq)))
100

    
101

    
102
# Even though we're using Python's built-in "partial" function if available,
103
# this one is always defined for testing.
104
def _partial(func, *args, **keywords): # pylint: disable=W0622
105
  """Decorator with partial application of arguments and keywords.
106

107
  This function was copied from Python's documentation.
108

109
  """
110
  def newfunc(*fargs, **fkeywords):
111
    newkeywords = keywords.copy()
112
    newkeywords.update(fkeywords)
113
    return func(*(args + fargs), **newkeywords) # pylint: disable=W0142
114

    
115
  newfunc.func = func
116
  newfunc.args = args
117
  newfunc.keywords = keywords
118
  return newfunc
119

    
120

    
121
if functools is None:
122
  partial = _partial
123
else:
124
  partial = functools.partial
125

    
126

    
127
def TryToRoman(val, convert=True):
128
  """Try to convert a value to roman numerals
129

130
  If the roman module could be loaded convert the given value to a roman
131
  numeral. Gracefully fail back to leaving the value untouched.
132

133
  @type val: integer
134
  @param val: value to convert
135
  @type convert: boolean
136
  @param convert: if False, don't try conversion at all
137
  @rtype: string or typeof(val)
138
  @return: roman numeral for val, or val if conversion didn't succeed
139

140
  """
141
  if roman is not None and convert:
142
    try:
143
      return roman.toRoman(val)
144
    except roman.RomanError:
145
      return val
146
  else:
147
    return val
148

    
149

    
150
def UniqueFrozenset(seq):
151
  """Makes C{frozenset} from sequence after checking for duplicate elements.
152

153
  @raise ValueError: When there are duplicate elements
154

155
  """
156
  if isinstance(seq, (list, tuple)):
157
    items = seq
158
  else:
159
    items = list(seq)
160

    
161
  result = frozenset(items)
162

    
163
  if len(items) != len(result):
164
    raise ValueError("Duplicate values found")
165

    
166
  return result
167

    
168

    
169
#: returns the first element of a list-like value
170
fst = operator.itemgetter(0)
171

    
172
#: returns the second element of a list-like value
173
snd = operator.itemgetter(1)