1
# IVLE - Informatics Virtual Learning Environment
2
# Copyright (C) 2007-2008 The University of Melbourne
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.
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.
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
22
# Contains common utility functions.
29
class IVLEError(Exception):
31
This is the "standard" exception class for IVLE errors.
32
It is the ONLY exception which should propagate to the top - it will then
33
be displayed to the user as an HTTP error with the given code.
35
All other exceptions are considered IVLE bugs and should not occur
36
(they will display a traceback).
38
This error should not be raised directly. Call req.throw_error.
40
def __init__(self, httpcode, message=None):
41
self.httpcode = httpcode
42
self.message = message
43
self.args = (httpcode, message)
45
class IVLEJailError(Exception):
47
This exception indicates an error that occurred inside an IVLE CGI script
48
inside the jail. It should never be raised directly - only by the
51
Information will be retrieved from it, and then treated as a normal
54
def __init__(self, type_str, message, info):
55
self.type_str = type_str
56
self.message = message
59
class FakeObject(object):
60
""" A representation of an object that can't be Pickled """
61
def __init__(self, type, name, attrib={}):
67
return "<Fake %s %s>"%(self.type, self.name)
70
"""Given a path relative to the IVLE root, makes the path relative to the
71
site root using ivle.conf.root_dir. This path can be used in URLs sent to
73
return os.path.join(ivle.conf.root_dir, path)
76
"""Given a path, returns a tuple consisting of the top-level directory in
77
the path, and the rest of the path. Note that both items in the tuple will
78
NOT begin with a slash, regardless of whether the original path did. Also
81
Always returns a pair of strings, except for one special case, in which
82
the path is completely empty (or just a single slash). In this case the
83
return value will be (None, ''). But still always returns a pair.
91
>>> split_path("home")
93
>>> split_path("home/docs/files")
94
('home', 'docs/files')
95
>>> split_path("//home/docs/files")
96
('', 'home/docs/files')
98
path = os.path.normpath(path)
99
# Ignore the opening slash
100
if path.startswith(os.sep):
101
path = path[len(os.sep):]
102
if path == '' or path == '.':
104
splitpath = path.split(os.sep, 1)
105
if len(splitpath) == 1:
106
return (splitpath[0], '')
108
return tuple(splitpath)
110
def incomplete_utf8_sequence(byteseq):
113
Given a UTF-8-encoded byte sequence (str), returns the number of bytes at
114
the end of the string which comprise an incomplete UTF-8 character
117
If the string is empty or ends with a complete character OR INVALID
119
Otherwise, returns 1-3 indicating the number of bytes in the final
120
incomplete (but valid) character sequence.
122
Does not check any bytes before the final sequence for correctness.
124
>>> incomplete_utf8_sequence("")
126
>>> incomplete_utf8_sequence("xy")
128
>>> incomplete_utf8_sequence("xy\xc3\xbc")
130
>>> incomplete_utf8_sequence("\xc3")
132
>>> incomplete_utf8_sequence("\xbc\xc3")
134
>>> incomplete_utf8_sequence("xy\xbc\xc3")
136
>>> incomplete_utf8_sequence("xy\xe0\xa0")
138
>>> incomplete_utf8_sequence("xy\xf4")
140
>>> incomplete_utf8_sequence("xy\xf4\x8f")
142
>>> incomplete_utf8_sequence("xy\xf4\x8f\xa0")
147
for b in byteseq[::-1]:
151
# 0xxxxxxx (single-byte character)
154
elif b & 0xc0 == 0x80:
155
# 10xxxxxx (subsequent byte)
157
elif b & 0xe0 == 0xc0:
158
# 110xxxxx (start of 2-byte sequence)
161
elif b & 0xf0 == 0xe0:
162
# 1110xxxx (start of 3-byte sequence)
165
elif b & 0xf8 == 0xf0:
166
# 11110xxx (start of 4-byte sequence)
174
# Seen too many "subsequent bytes", invalid
178
# We never saw a "first byte", invalid
181
# We now know expect and count
183
# Complete, or we saw an invalid sequence
189
def object_to_dict(attrnames, obj):
191
Convert an object into a dictionary. This takes a shallow copy of the
193
attrnames: Set (or iterable) of names of attributes to be copied into the
194
dictionary. (We don't auto-lookup, because this function needs to be
195
used on magical objects).
197
return dict((k, getattr(obj, k))
198
for k in attrnames if not k.startswith('_'))