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)
75
def unmake_path(path):
76
"""Given a path relative to the site root, makes the path relative to the
77
IVLE root by removing ivle.conf.root_dir if it appears at the beginning. If
78
it does not appear at the beginning, returns path unchanged. Also
79
normalises the path."""
80
path = os.path.normpath(path)
81
root = os.path.normpath(ivle.conf.root_dir)
83
if path.startswith(root):
84
path = path[len(root):]
85
# Take out the slash as well
86
if len(path) > 0 and path[0] == os.sep:
92
"""Given a path, returns a tuple consisting of the top-level directory in
93
the path, and the rest of the path. Note that both items in the tuple will
94
NOT begin with a slash, regardless of whether the original path did. Also
97
Always returns a pair of strings, except for one special case, in which
98
the path is completely empty (or just a single slash). In this case the
99
return value will be (None, ''). But still always returns a pair.
107
>>> split_path("home")
109
>>> split_path("home/docs/files")
110
('home', 'docs/files')
111
>>> split_path("//home/docs/files")
112
('', 'home/docs/files')
114
path = os.path.normpath(path)
115
# Ignore the opening slash
116
if path.startswith(os.sep):
117
path = path[len(os.sep):]
118
if path == '' or path == '.':
120
splitpath = path.split(os.sep, 1)
121
if len(splitpath) == 1:
122
return (splitpath[0], '')
124
return tuple(splitpath)
126
def incomplete_utf8_sequence(byteseq):
129
Given a UTF-8-encoded byte sequence (str), returns the number of bytes at
130
the end of the string which comprise an incomplete UTF-8 character
133
If the string is empty or ends with a complete character OR INVALID
135
Otherwise, returns 1-3 indicating the number of bytes in the final
136
incomplete (but valid) character sequence.
138
Does not check any bytes before the final sequence for correctness.
140
>>> incomplete_utf8_sequence("")
142
>>> incomplete_utf8_sequence("xy")
144
>>> incomplete_utf8_sequence("xy\xc3\xbc")
146
>>> incomplete_utf8_sequence("\xc3")
148
>>> incomplete_utf8_sequence("\xbc\xc3")
150
>>> incomplete_utf8_sequence("xy\xbc\xc3")
152
>>> incomplete_utf8_sequence("xy\xe0\xa0")
154
>>> incomplete_utf8_sequence("xy\xf4")
156
>>> incomplete_utf8_sequence("xy\xf4\x8f")
158
>>> incomplete_utf8_sequence("xy\xf4\x8f\xa0")
163
for b in byteseq[::-1]:
167
# 0xxxxxxx (single-byte character)
170
elif b & 0xc0 == 0x80:
171
# 10xxxxxx (subsequent byte)
173
elif b & 0xe0 == 0xc0:
174
# 110xxxxx (start of 2-byte sequence)
177
elif b & 0xf0 == 0xe0:
178
# 1110xxxx (start of 3-byte sequence)
181
elif b & 0xf8 == 0xf0:
182
# 11110xxx (start of 4-byte sequence)
190
# Seen too many "subsequent bytes", invalid
194
# We never saw a "first byte", invalid
197
# We now know expect and count
199
# Complete, or we saw an invalid sequence
205
def object_to_dict(attrnames, obj):
207
Convert an object into a dictionary. This takes a shallow copy of the
209
attrnames: Set (or iterable) of names of attributes to be copied into the
210
dictionary. (We don't auto-lookup, because this function needs to be
211
used on magical objects).
213
return dict((k, getattr(obj, k))
214
for k in attrnames if not k.startswith('_'))