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

« back to all changes in this revision

Viewing changes to ivle/util.py

  • Committer: William Grant
  • Date: 2009-04-28 07:22:03 UTC
  • Revision ID: grantw@unimelb.edu.au-20090428072203-j5ratziusj3kv4tq
Allow template string interpolation in the config.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE - Informatics Virtual Learning Environment
 
2
# Copyright (C) 2007-2008 The University of Melbourne
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 
 
18
# Module: util
 
19
# Author: Matt Giuca
 
20
# Date: 12/12/2007
 
21
 
 
22
# Contains common utility functions.
 
23
 
 
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)
 
36
 
 
37
class IVLEJailError(Exception):
 
38
    """Exception proxying an in-jail error.
 
39
 
 
40
    This exception indicates an error that occurred inside an IVLE CGI script
 
41
    inside the jail. It should never be raised directly - only by the 
 
42
    interpreter.
 
43
 
 
44
    Information will be retrieved from it, and then treated as a normal
 
45
    error.
 
46
    """
 
47
    def __init__(self, type_str, message, info):
 
48
        self.type_str = type_str
 
49
        self.message = message
 
50
        self.info = info
 
51
 
 
52
class FakeObject(object):
 
53
    """ A representation of an object that can't be Pickled """
 
54
    def __init__(self, type, name, attrib={}):
 
55
        self.type = type
 
56
        self.name = name
 
57
        self.attrib = attrib
 
58
 
 
59
    def __repr__(self):
 
60
        return "<Fake %s %s>"%(self.type, self.name)
 
61
 
 
62
def split_path(path):
 
63
    """Given a path, returns a tuple consisting of the top-level directory in
 
64
    the path, and the rest of the path. Note that both items in the tuple will
 
65
    NOT begin with a slash, regardless of whether the original path did. Also
 
66
    normalises the path.
 
67
 
 
68
    Always returns a pair of strings, except for one special case, in which
 
69
    the path is completely empty (or just a single slash). In this case the
 
70
    return value will be (None, ''). But still always returns a pair.
 
71
 
 
72
    Examples:
 
73
 
 
74
    >>> split_path("")
 
75
    (None, '')
 
76
    >>> split_path("/")
 
77
    (None, '')
 
78
    >>> split_path("home")
 
79
    ('home', '')
 
80
    >>> split_path("home/docs/files")
 
81
    ('home', 'docs/files')
 
82
    >>> split_path("//home/docs/files")
 
83
    ('', 'home/docs/files')
 
84
    """
 
85
    path = os.path.normpath(path)
 
86
    # Ignore the opening slash
 
87
    if path.startswith(os.sep):
 
88
        path = path[len(os.sep):]
 
89
    if path == '' or path == '.':
 
90
        return (None, '')
 
91
    splitpath = path.split(os.sep, 1)
 
92
    if len(splitpath) == 1:
 
93
        return (splitpath[0], '')
 
94
    else:
 
95
        return tuple(splitpath)
 
96
 
 
97
def incomplete_utf8_sequence(byteseq):
 
98
    """Calculate the completeness of a UTF-8 encoded string.
 
99
 
 
100
    Given a UTF-8-encoded byte sequence (str), returns the number of bytes at
 
101
    the end of the string which comprise an incomplete UTF-8 character
 
102
    sequence.
 
103
 
 
104
    If the string is empty or ends with a complete character OR INVALID
 
105
    sequence, returns 0.
 
106
    Otherwise, returns 1-3 indicating the number of bytes in the final
 
107
    incomplete (but valid) character sequence.
 
108
 
 
109
    Does not check any bytes before the final sequence for correctness.
 
110
 
 
111
    >>> incomplete_utf8_sequence("")
 
112
    0
 
113
    >>> incomplete_utf8_sequence("xy")
 
114
    0
 
115
    >>> incomplete_utf8_sequence("xy\xc3\xbc")
 
116
    0
 
117
    >>> incomplete_utf8_sequence("\xc3")
 
118
    1
 
119
    >>> incomplete_utf8_sequence("\xbc\xc3")
 
120
    1
 
121
    >>> incomplete_utf8_sequence("xy\xbc\xc3")
 
122
    1
 
123
    >>> incomplete_utf8_sequence("xy\xe0\xa0")
 
124
    2
 
125
    >>> incomplete_utf8_sequence("xy\xf4")
 
126
    1
 
127
    >>> incomplete_utf8_sequence("xy\xf4\x8f")
 
128
    2
 
129
    >>> incomplete_utf8_sequence("xy\xf4\x8f\xa0")
 
130
    3
 
131
    """
 
132
    count = 0
 
133
    expect = None
 
134
    for b in byteseq[::-1]:
 
135
        b = ord(b)
 
136
        count += 1
 
137
        if b & 0x80 == 0x0:
 
138
            # 0xxxxxxx (single-byte character)
 
139
            expect = 1
 
140
            break
 
141
        elif b & 0xc0 == 0x80:
 
142
            # 10xxxxxx (subsequent byte)
 
143
            pass
 
144
        elif b & 0xe0 == 0xc0:
 
145
            # 110xxxxx (start of 2-byte sequence)
 
146
            expect = 2
 
147
            break
 
148
        elif b & 0xf0 == 0xe0:
 
149
            # 1110xxxx (start of 3-byte sequence)
 
150
            expect = 3
 
151
            break
 
152
        elif b & 0xf8 == 0xf0:
 
153
            # 11110xxx (start of 4-byte sequence)
 
154
            expect = 4
 
155
            break
 
156
        else:
 
157
            # Invalid byte
 
158
            return 0
 
159
 
 
160
        if count >= 4:
 
161
            # Seen too many "subsequent bytes", invalid
 
162
            return 0
 
163
 
 
164
    if expect is None:
 
165
        # We never saw a "first byte", invalid
 
166
        return 0
 
167
 
 
168
    # We now know expect and count
 
169
    if count >= expect:
 
170
        # Complete, or we saw an invalid sequence
 
171
        return 0
 
172
    elif count < expect:
 
173
        # Incomplete
 
174
        return count
 
175
 
 
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('_'))