~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/canonical/launchpad/helpers.py

Undo rename. Again.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
 
13
13
from difflib import unified_diff
14
14
import os
 
15
import random
15
16
import re
16
17
from StringIO import StringIO
17
18
import subprocess
94
95
    return str.decode('UTF-8').encode('ASCII', 'backslashreplace')
95
96
 
96
97
 
 
98
def join_lines(*lines):
 
99
    """Concatenate a list of strings, adding a newline at the end of each."""
 
100
 
 
101
    return ''.join([x + '\n' for x in lines])
 
102
 
 
103
 
97
104
def string_to_tarfile(s):
98
105
    """Convert a binary string containing a tar file into a tar file obj."""
99
106
 
100
107
    return tarfile.open('', 'r', StringIO(s))
101
108
 
102
109
 
 
110
def shortest(sequence):
 
111
    """Return a list with the shortest items in sequence.
 
112
 
 
113
    Return an empty list if the sequence is empty.
 
114
    """
 
115
    shortest_list = []
 
116
    shortest_length = None
 
117
 
 
118
    for item in list(sequence):
 
119
        new_length = len(item)
 
120
 
 
121
        if shortest_length is None:
 
122
            # First item.
 
123
            shortest_list.append(item)
 
124
            shortest_length = new_length
 
125
        elif new_length == shortest_length:
 
126
            # Same length than shortest item found, we append it to the list.
 
127
            shortest_list.append(item)
 
128
        elif min(new_length, shortest_length) != shortest_length:
 
129
            # Shorter than our shortest length found, discard old values.
 
130
            shortest_list = [item]
 
131
            shortest_length = new_length
 
132
 
 
133
    return shortest_list
 
134
 
 
135
 
 
136
def getRosettaBestBinaryPackageName(sequence):
 
137
    """Return the best binary package name from a list.
 
138
 
 
139
    It follows the Rosetta policy:
 
140
 
 
141
    We don't need a concrete value from binary package name, we use shortest
 
142
    function as a kind of heuristic to choose the shortest binary package
 
143
    name that we suppose will be the more descriptive one for our needs with
 
144
    PO templates. That's why we get always the first element.
 
145
    """
 
146
    return shortest(sequence)[0]
 
147
 
 
148
 
 
149
def getRosettaBestDomainPath(sequence):
 
150
    """Return the best path for a concrete .pot file from a list of paths.
 
151
 
 
152
    It follows the Rosetta policy for this path:
 
153
 
 
154
    We don't need a concrete value from domain_paths list, we use shortest
 
155
    function as a kind of heuristic to choose the shortest path if we have
 
156
    more than one, usually, we will have only one element.
 
157
    """
 
158
    return shortest(sequence)[0]
 
159
 
 
160
 
 
161
def getValidNameFromString(invalid_name):
 
162
    """Return a valid name based on a string.
 
163
 
 
164
    A name in launchpad has a set of restrictions that not all strings follow.
 
165
    This function converts any string in another one that follows our name
 
166
    restriction rules.
 
167
 
 
168
    To know more about all restrictions, please, look at valid_name function
 
169
    in the database.
 
170
    """
 
171
    # All chars should be lower case, underscores and spaces become dashes.
 
172
    return text_replaced(invalid_name.lower(), {'_': '-', ' ': '-'})
 
173
 
 
174
 
103
175
def browserLanguages(request):
104
176
    """Return a list of Language objects based on the browser preferences."""
105
177
    return IRequestPreferredLanguages(request).getPreferredLanguages()
142
214
        for mail_person in get_recipients(person))
143
215
 
144
216
 
 
217
replacements = {0: {'.': ' |dot| ',
 
218
                    '@': ' |at| '},
 
219
                1: {'.': ' ! ',
 
220
                    '@': ' {} '},
 
221
                2: {'.': ' , ',
 
222
                    '@': ' % '},
 
223
                3: {'.': ' (!) ',
 
224
                    '@': ' (at) '},
 
225
                4: {'.': ' {dot} ',
 
226
                    '@': ' {at} '},
 
227
                }
 
228
 
 
229
 
 
230
def obfuscateEmail(emailaddr, idx=None):
 
231
    """Return an obfuscated version of the provided email address.
 
232
 
 
233
    Randomly chose a set of replacements for some email address characters and
 
234
    replace them. This will make harder for email harvesters to fetch email
 
235
    address from launchpad.
 
236
 
 
237
    >>> obfuscateEmail('foo@bar.com', 0)
 
238
    'foo |at| bar |dot| com'
 
239
    >>> obfuscateEmail('foo.bar@xyz.com.br', 1)
 
240
    'foo ! bar {} xyz ! com ! br'
 
241
    """
 
242
    if idx is None:
 
243
        idx = random.randint(0, len(replacements) - 1)
 
244
    return text_replaced(emailaddr, replacements[idx])
 
245
 
 
246
 
145
247
class ShortListTooBigError(Exception):
146
248
    """This error is raised when the shortlist hardlimit is reached"""
147
249
 
331
433
        return 0
332
434
 
333
435
 
 
436
def positiveIntOrZero(value):
 
437
    """Return 0 if int(value) fails or if int(value) is less than 0.
 
438
 
 
439
    Return int(value) otherwise.
 
440
 
 
441
    >>> positiveIntOrZero(None)
 
442
    0
 
443
    >>> positiveIntOrZero(-9)
 
444
    0
 
445
    >>> positiveIntOrZero(1)
 
446
    1
 
447
    >>> positiveIntOrZero('-3')
 
448
    0
 
449
    >>> positiveIntOrZero('5')
 
450
    5
 
451
    >>> positiveIntOrZero(3.1415)
 
452
    3
 
453
    """
 
454
    value = intOrZero(value)
 
455
    if value < 0:
 
456
        return 0
 
457
    return value
 
458
 
 
459
 
334
460
def get_email_template(filename, app=None):
335
461
    """Returns the email template with the given file name.
336
462