~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/util.py

  • Committer: William Grant
  • Date: 2012-06-28 01:52:02 UTC
  • Revision ID: me@williamgrant.id.au-20120628015202-f6ru7o367gt6nvgz
Hah

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
# Contains common utility functions.
23
23
 
24
24
import os
25
 
 
26
 
class IVLEError(Exception):
27
 
    """Legacy general IVLE exception.
28
 
 
29
 
    This is the old "standard" exception class for IVLE errors. It is only
30
 
    used in fileservice, and should not be used in any new code.
31
 
    """
32
 
    def __init__(self, httpcode, message=None):
33
 
        self.httpcode = httpcode
34
 
        self.message = message
35
 
        self.args = (httpcode, message)
 
25
import sys
 
26
import stat
36
27
 
37
28
class IVLEJailError(Exception):
38
29
    """Exception proxying an in-jail error.
94
85
    else:
95
86
        return tuple(splitpath)
96
87
 
 
88
def relpath(path, start=os.path.curdir):
 
89
    """Return a relative version of a path.
 
90
    XXX Backported from Python 2.6 posixpath.py.
 
91
    """
 
92
 
 
93
    if not path:
 
94
        raise ValueError("no path specified")
 
95
 
 
96
    start_list = os.path.abspath(start).split(os.path.sep)
 
97
    path_list = os.path.abspath(path).split(os.path.sep)
 
98
 
 
99
    # Work out how much of the filepath is shared by start and path.
 
100
    i = len(os.path.commonprefix([start_list, path_list]))
 
101
 
 
102
    rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
 
103
    if not rel_list:
 
104
        return os.path.curdir
 
105
    return os.path.join(*rel_list)
 
106
 
97
107
def incomplete_utf8_sequence(byteseq):
98
108
    """Calculate the completeness of a UTF-8 encoded string.
99
109
 
173
183
        # Incomplete
174
184
        return count
175
185
 
176
 
def object_to_dict(attrnames, obj):
177
 
    """Convert an object into a dictionary.
178
 
 
179
 
    This takes a shallow copy of the object.
180
 
 
181
 
    @param attrnames: Set (or iterable) of names of attributes to be copied
182
 
                      into the dictionary. (We don't auto-lookup, because this
183
 
                      function needs to be used on magical objects).
184
 
    """
185
 
    return dict((k, getattr(obj, k))
186
 
        for k in attrnames if not k.startswith('_'))
 
186
def safe_rmtree(path, ignore_errors=False, onerror=None):
 
187
    """Recursively delete a directory tree.
 
188
 
 
189
    Copied from shutil.rmtree from Python 2.6, which does not follow symbolic
 
190
    links (it is otherwise unsafe to call as root on untrusted directories; do
 
191
    not use shutil.rmtree in this case, as you may be running Python 2.5).
 
192
 
 
193
    If ignore_errors is set, errors are ignored; otherwise, if onerror
 
194
    is set, it is called to handle the error with arguments (func,
 
195
    path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
 
196
    path is the argument to that function that caused it to fail; and
 
197
    exc_info is a tuple returned by sys.exc_info().  If ignore_errors
 
198
    is false and onerror is None, an exception is raised.
 
199
 
 
200
    """
 
201
    if ignore_errors:
 
202
        def onerror(*args):
 
203
            pass
 
204
    elif onerror is None:
 
205
        def onerror(*args):
 
206
            raise
 
207
    try:
 
208
        if os.path.islink(path):
 
209
            # symlinks to directories are forbidden, see bug #1669
 
210
            raise OSError("Cannot call safe_rmtree on a symbolic link")
 
211
    except OSError:
 
212
        onerror(os.path.islink, path, sys.exc_info())
 
213
        # can't continue even if onerror hook returns
 
214
        return
 
215
    names = []
 
216
    try:
 
217
        names = os.listdir(path)
 
218
    except os.error, err:
 
219
        onerror(os.listdir, path, sys.exc_info())
 
220
    for name in names:
 
221
        fullname = os.path.join(path, name)
 
222
        try:
 
223
            mode = os.lstat(fullname).st_mode
 
224
        except os.error:
 
225
            mode = 0
 
226
        if stat.S_ISDIR(mode):
 
227
            safe_rmtree(fullname, ignore_errors, onerror)
 
228
        else:
 
229
            try:
 
230
                os.remove(fullname)
 
231
            except os.error, err:
 
232
                onerror(os.remove, fullname, sys.exc_info())
 
233
    try:
 
234
        os.rmdir(path)
 
235
    except os.error:
 
236
        onerror(os.rmdir, path, sys.exc_info())
 
237
 
 
238
def format_submission_principal(user, principal):
 
239
    """Render a list of users to fit in the offering project listing.
 
240
 
 
241
    Given a user and a list of submitters, returns 'solo' if the
 
242
    only submitter is the user, or a string of the form
 
243
    'with A, B and C' if there are any other submitters.
 
244
 
 
245
    If submitters is None, we assume that the list of members could
 
246
    not be determined, so we just return 'group'.
 
247
    """
 
248
    if principal is None:
 
249
        return 'group'
 
250
 
 
251
    if principal is user:
 
252
        return 'solo'
 
253
 
 
254
    display_names = sorted(
 
255
        member.display_name for member in principal.members
 
256
        if member is not user)
 
257
 
 
258
    if len(display_names) == 0:
 
259
        return 'solo (%s)' % principal.name
 
260
    elif len(display_names) == 1:
 
261
        return 'with %s (%s)' % (display_names[0], principal.name)
 
262
    elif len(display_names) > 5:
 
263
        return 'with %d others (%s)' % (len(display_names), principal.name)
 
264
    else:
 
265
        return 'with %s and %s (%s)' % (', '.join(display_names[:-1]),
 
266
                                        display_names[-1], principal.name)