blob: f74dc1489938cb9c9910f2d25543a58672b8e7cb [file] [log] [blame]
Brett Cannonb47243a2003-06-16 21:54:50 +00001import unittest
Florent Xiclunadc1531c2010-03-06 18:07:18 +00002from test import test_support, test_genericpath
Ezio Melotti9e9af212010-02-20 22:34:21 +00003
Brett Cannonb47243a2003-06-16 21:54:50 +00004import posixpath, os
Georg Brandlb86d3fa2010-02-07 12:55:12 +00005from posixpath import realpath, abspath, dirname, basename
Johannes Gijsbers4ec40642004-08-14 15:01:53 +00006
7# An absolute path to a temporary filename for testing. We can't rely on TESTFN
8# being an absolute path, so we need this.
9
10ABSTFN = abspath(test_support.TESTFN)
Skip Montanaroe809b002000-07-12 00:20:08 +000011
Serhiy Storchakac8e75ba2013-02-18 13:32:06 +020012def skip_if_ABSTFN_contains_backslash(test):
13 """
14 On Windows, posixpath.abspath still returns paths with backslashes
15 instead of posix forward slashes. If this is the case, several tests
16 fail, so skip them.
17 """
18 found_backslash = '\\' in ABSTFN
19 msg = "ABSTFN is not a posix path - tests fail"
20 return [test, unittest.skip(msg)(test)][found_backslash]
21
Collin Winterdbead562007-03-10 02:23:40 +000022def safe_rmdir(dirname):
23 try:
24 os.rmdir(dirname)
25 except OSError:
26 pass
27
Brett Cannonb47243a2003-06-16 21:54:50 +000028class PosixPathTest(unittest.TestCase):
Skip Montanaroe809b002000-07-12 00:20:08 +000029
Collin Winterdbead562007-03-10 02:23:40 +000030 def setUp(self):
31 self.tearDown()
32
33 def tearDown(self):
34 for suffix in ["", "1", "2"]:
35 test_support.unlink(test_support.TESTFN + suffix)
36 safe_rmdir(test_support.TESTFN + suffix)
Tim Petersea5962f2007-03-12 18:07:52 +000037
Brett Cannonb47243a2003-06-16 21:54:50 +000038 def test_join(self):
39 self.assertEqual(posixpath.join("/foo", "bar", "/bar", "baz"), "/bar/baz")
40 self.assertEqual(posixpath.join("/foo", "bar", "baz"), "/foo/bar/baz")
41 self.assertEqual(posixpath.join("/foo/", "bar/", "baz/"), "/foo/bar/baz/")
Skip Montanaroe809b002000-07-12 00:20:08 +000042
Brett Cannonb47243a2003-06-16 21:54:50 +000043 def test_split(self):
44 self.assertEqual(posixpath.split("/foo/bar"), ("/foo", "bar"))
45 self.assertEqual(posixpath.split("/"), ("/", ""))
46 self.assertEqual(posixpath.split("foo"), ("", "foo"))
47 self.assertEqual(posixpath.split("////foo"), ("////", "foo"))
48 self.assertEqual(posixpath.split("//foo//bar"), ("//foo", "bar"))
49
Martin v. Löwis05c075d2007-03-07 11:04:33 +000050 def splitextTest(self, path, filename, ext):
51 self.assertEqual(posixpath.splitext(path), (filename, ext))
52 self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext))
53 self.assertEqual(posixpath.splitext("abc/" + path), ("abc/" + filename, ext))
54 self.assertEqual(posixpath.splitext("abc.def/" + path), ("abc.def/" + filename, ext))
55 self.assertEqual(posixpath.splitext("/abc.def/" + path), ("/abc.def/" + filename, ext))
56 self.assertEqual(posixpath.splitext(path + "/"), (filename + ext + "/", ""))
Brett Cannonb47243a2003-06-16 21:54:50 +000057
Martin v. Löwis05c075d2007-03-07 11:04:33 +000058 def test_splitext(self):
59 self.splitextTest("foo.bar", "foo", ".bar")
60 self.splitextTest("foo.boo.bar", "foo.boo", ".bar")
61 self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar")
62 self.splitextTest(".csh.rc", ".csh", ".rc")
63 self.splitextTest("nodots", "nodots", "")
64 self.splitextTest(".cshrc", ".cshrc", "")
65 self.splitextTest("...manydots", "...manydots", "")
66 self.splitextTest("...manydots.ext", "...manydots", ".ext")
67 self.splitextTest(".", ".", "")
68 self.splitextTest("..", "..", "")
69 self.splitextTest("........", "........", "")
70 self.splitextTest("", "", "")
Brett Cannonb47243a2003-06-16 21:54:50 +000071
72 def test_isabs(self):
73 self.assertIs(posixpath.isabs(""), False)
74 self.assertIs(posixpath.isabs("/"), True)
75 self.assertIs(posixpath.isabs("/foo"), True)
76 self.assertIs(posixpath.isabs("/foo/bar"), True)
77 self.assertIs(posixpath.isabs("foo/bar"), False)
78
Brett Cannonb47243a2003-06-16 21:54:50 +000079 def test_basename(self):
80 self.assertEqual(posixpath.basename("/foo/bar"), "bar")
81 self.assertEqual(posixpath.basename("/"), "")
82 self.assertEqual(posixpath.basename("foo"), "foo")
83 self.assertEqual(posixpath.basename("////foo"), "foo")
84 self.assertEqual(posixpath.basename("//foo//bar"), "bar")
85
Brett Cannonb47243a2003-06-16 21:54:50 +000086 def test_dirname(self):
87 self.assertEqual(posixpath.dirname("/foo/bar"), "/foo")
88 self.assertEqual(posixpath.dirname("/"), "/")
89 self.assertEqual(posixpath.dirname("foo"), "")
90 self.assertEqual(posixpath.dirname("////foo"), "////")
91 self.assertEqual(posixpath.dirname("//foo//bar"), "//foo")
92
Tim Petersea5962f2007-03-12 18:07:52 +000093 def test_islink(self):
Brett Cannonb47243a2003-06-16 21:54:50 +000094 self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False)
95 f = open(test_support.TESTFN + "1", "wb")
96 try:
97 f.write("foo")
98 f.close()
99 self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False)
100 if hasattr(os, "symlink"):
101 os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2")
102 self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True)
103 os.remove(test_support.TESTFN + "1")
104 self.assertIs(posixpath.islink(test_support.TESTFN + "2"), True)
105 self.assertIs(posixpath.exists(test_support.TESTFN + "2"), False)
Johannes Gijsbersae882f72004-08-30 10:19:56 +0000106 self.assertIs(posixpath.lexists(test_support.TESTFN + "2"), True)
Brett Cannonb47243a2003-06-16 21:54:50 +0000107 finally:
108 if not f.close():
109 f.close()
Brett Cannonb47243a2003-06-16 21:54:50 +0000110
Collin Winterdbead562007-03-10 02:23:40 +0000111 def test_samefile(self):
112 f = open(test_support.TESTFN + "1", "wb")
113 try:
114 f.write("foo")
115 f.close()
116 self.assertIs(
117 posixpath.samefile(
118 test_support.TESTFN + "1",
119 test_support.TESTFN + "1"
120 ),
121 True
122 )
Benjamin Peterson8a1a17b2012-11-30 16:12:15 -0500123
124 # If we don't have links, assume that os.stat doesn't return
125 # reasonable inode information and thus, that samefile() doesn't
126 # work.
Collin Winterdbead562007-03-10 02:23:40 +0000127 if hasattr(os, "symlink"):
128 os.symlink(
129 test_support.TESTFN + "1",
130 test_support.TESTFN + "2"
131 )
132 self.assertIs(
133 posixpath.samefile(
134 test_support.TESTFN + "1",
135 test_support.TESTFN + "2"
136 ),
137 True
138 )
139 os.remove(test_support.TESTFN + "2")
140 f = open(test_support.TESTFN + "2", "wb")
141 f.write("bar")
Brett Cannonb47243a2003-06-16 21:54:50 +0000142 f.close()
143 self.assertIs(
144 posixpath.samefile(
145 test_support.TESTFN + "1",
Brett Cannonb47243a2003-06-16 21:54:50 +0000146 test_support.TESTFN + "2"
Collin Winterdbead562007-03-10 02:23:40 +0000147 ),
148 False
149 )
150 finally:
151 if not f.close():
152 f.close()
Brett Cannonb47243a2003-06-16 21:54:50 +0000153
Brett Cannonb47243a2003-06-16 21:54:50 +0000154 def test_samestat(self):
155 f = open(test_support.TESTFN + "1", "wb")
156 try:
157 f.write("foo")
158 f.close()
159 self.assertIs(
160 posixpath.samestat(
161 os.stat(test_support.TESTFN + "1"),
162 os.stat(test_support.TESTFN + "1")
163 ),
164 True
165 )
Benjamin Peterson71966052012-11-30 16:13:14 -0500166 # If we don't have links, assume that os.stat() doesn't return
167 # reasonable inode information and thus, that samestat() doesn't
168 # work.
Brett Cannonb47243a2003-06-16 21:54:50 +0000169 if hasattr(os, "symlink"):
Benjamin Peterson8a1a17b2012-11-30 16:12:15 -0500170 os.symlink(test_support.TESTFN + "1", test_support.TESTFN + "2")
171 self.assertIs(
172 posixpath.samestat(
173 os.stat(test_support.TESTFN + "1"),
174 os.stat(test_support.TESTFN + "2")
175 ),
176 True
177 )
178 os.remove(test_support.TESTFN + "2")
Brett Cannonb47243a2003-06-16 21:54:50 +0000179 f = open(test_support.TESTFN + "2", "wb")
180 f.write("bar")
181 f.close()
182 self.assertIs(
183 posixpath.samestat(
184 os.stat(test_support.TESTFN + "1"),
185 os.stat(test_support.TESTFN + "2")
186 ),
187 False
188 )
189 finally:
190 if not f.close():
191 f.close()
Brett Cannonb47243a2003-06-16 21:54:50 +0000192
Brett Cannonb47243a2003-06-16 21:54:50 +0000193 def test_ismount(self):
194 self.assertIs(posixpath.ismount("/"), True)
195
Brett Cannonb47243a2003-06-16 21:54:50 +0000196 def test_expanduser(self):
197 self.assertEqual(posixpath.expanduser("foo"), "foo")
Brett Cannonb47243a2003-06-16 21:54:50 +0000198 try:
199 import pwd
200 except ImportError:
201 pass
202 else:
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000203 self.assertIsInstance(posixpath.expanduser("~/"), basestring)
Neal Norwitz168e73d2003-07-01 03:33:31 +0000204 # if home directory == root directory, this test makes no sense
205 if posixpath.expanduser("~") != '/':
206 self.assertEqual(
207 posixpath.expanduser("~") + "/",
208 posixpath.expanduser("~/")
209 )
Ezio Melottib0f5adc2010-01-24 16:58:36 +0000210 self.assertIsInstance(posixpath.expanduser("~root/"), basestring)
211 self.assertIsInstance(posixpath.expanduser("~foo/"), basestring)
Brett Cannonb47243a2003-06-16 21:54:50 +0000212
Walter Dörwald4b965f62009-04-26 20:51:44 +0000213 with test_support.EnvironmentVarGuard() as env:
Walter Dörwald6733bed2009-05-01 17:35:37 +0000214 env['HOME'] = '/'
Walter Dörwald4b965f62009-04-26 20:51:44 +0000215 self.assertEqual(posixpath.expanduser("~"), "/")
Jesus Ceaf2011e32012-05-10 05:01:11 +0200216 self.assertEqual(posixpath.expanduser("~/foo"), "/foo")
Georg Brandl3f0ef202009-04-05 14:48:49 +0000217
Brett Cannonb47243a2003-06-16 21:54:50 +0000218 def test_normpath(self):
219 self.assertEqual(posixpath.normpath(""), ".")
220 self.assertEqual(posixpath.normpath("/"), "/")
221 self.assertEqual(posixpath.normpath("//"), "//")
222 self.assertEqual(posixpath.normpath("///"), "/")
223 self.assertEqual(posixpath.normpath("///foo/.//bar//"), "/foo/bar")
224 self.assertEqual(posixpath.normpath("///foo/.//bar//.//..//.//baz"), "/foo/baz")
225 self.assertEqual(posixpath.normpath("///..//./foo/.//bar"), "/foo/bar")
226
Serhiy Storchakac8e75ba2013-02-18 13:32:06 +0200227 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka142d2bc2013-02-18 12:20:44 +0200228 def test_realpath_curdir(self):
229 self.assertEqual(realpath('.'), os.getcwd())
230 self.assertEqual(realpath('./.'), os.getcwd())
231 self.assertEqual(realpath('/'.join(['.'] * 100)), os.getcwd())
232
Serhiy Storchakac8e75ba2013-02-18 13:32:06 +0200233 @skip_if_ABSTFN_contains_backslash
Serhiy Storchaka142d2bc2013-02-18 12:20:44 +0200234 def test_realpath_pardir(self):
235 self.assertEqual(realpath('..'), dirname(os.getcwd()))
236 self.assertEqual(realpath('../..'), dirname(dirname(os.getcwd())))
237 self.assertEqual(realpath('/'.join(['..'] * 100)), '/')
238
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000239 if hasattr(os, "symlink"):
240 def test_realpath_basic(self):
241 # Basic operation.
242 try:
243 os.symlink(ABSTFN+"1", ABSTFN)
244 self.assertEqual(realpath(ABSTFN), ABSTFN+"1")
245 finally:
Collin Winterdbead562007-03-10 02:23:40 +0000246 test_support.unlink(ABSTFN)
Tim Petersa45cacf2004-08-20 03:47:14 +0000247
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000248 def test_realpath_symlink_loops(self):
249 # Bug #930024, return the path unchanged if we get into an infinite
250 # symlink loop.
251 try:
252 old_path = abspath('.')
253 os.symlink(ABSTFN, ABSTFN)
254 self.assertEqual(realpath(ABSTFN), ABSTFN)
255
256 os.symlink(ABSTFN+"1", ABSTFN+"2")
257 os.symlink(ABSTFN+"2", ABSTFN+"1")
258 self.assertEqual(realpath(ABSTFN+"1"), ABSTFN+"1")
259 self.assertEqual(realpath(ABSTFN+"2"), ABSTFN+"2")
260
Serhiy Storchaka0dd3d302013-02-10 12:21:49 +0200261 self.assertEqual(realpath(ABSTFN+"1/x"), ABSTFN+"1/x")
262 self.assertEqual(realpath(ABSTFN+"1/.."), dirname(ABSTFN))
263 self.assertEqual(realpath(ABSTFN+"1/../x"), dirname(ABSTFN) + "/x")
264 os.symlink(ABSTFN+"x", ABSTFN+"y")
265 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "y"),
266 ABSTFN + "y")
267 self.assertEqual(realpath(ABSTFN+"1/../" + basename(ABSTFN) + "1"),
268 ABSTFN + "1")
269
270 os.symlink(basename(ABSTFN) + "a/b", ABSTFN+"a")
271 self.assertEqual(realpath(ABSTFN+"a"), ABSTFN+"a/b")
272
273 os.symlink("../" + basename(dirname(ABSTFN)) + "/" +
274 basename(ABSTFN) + "c", ABSTFN+"c")
275 self.assertEqual(realpath(ABSTFN+"c"), ABSTFN+"c")
276
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000277 # Test using relative path as well.
278 os.chdir(dirname(ABSTFN))
279 self.assertEqual(realpath(basename(ABSTFN)), ABSTFN)
280 finally:
281 os.chdir(old_path)
Collin Winterdbead562007-03-10 02:23:40 +0000282 test_support.unlink(ABSTFN)
283 test_support.unlink(ABSTFN+"1")
284 test_support.unlink(ABSTFN+"2")
Serhiy Storchaka0dd3d302013-02-10 12:21:49 +0200285 test_support.unlink(ABSTFN+"y")
286 test_support.unlink(ABSTFN+"c")
Ezio Melottic86e8662013-03-01 20:56:13 +0200287 test_support.unlink(ABSTFN+"a")
Serhiy Storchaka0dd3d302013-02-10 12:21:49 +0200288
289 def test_realpath_repeated_indirect_symlinks(self):
290 # Issue #6975.
291 try:
292 os.mkdir(ABSTFN)
293 os.symlink('../' + basename(ABSTFN), ABSTFN + '/self')
294 os.symlink('self/self/self', ABSTFN + '/link')
295 self.assertEqual(realpath(ABSTFN + '/link'), ABSTFN)
296 finally:
297 test_support.unlink(ABSTFN + '/self')
298 test_support.unlink(ABSTFN + '/link')
299 safe_rmdir(ABSTFN)
300
301 def test_realpath_deep_recursion(self):
302 depth = 10
303 old_path = abspath('.')
304 try:
305 os.mkdir(ABSTFN)
306 for i in range(depth):
307 os.symlink('/'.join(['%d' % i] * 10), ABSTFN + '/%d' % (i + 1))
308 os.symlink('.', ABSTFN + '/0')
309 self.assertEqual(realpath(ABSTFN + '/%d' % depth), ABSTFN)
310
311 # Test using relative path as well.
312 os.chdir(ABSTFN)
313 self.assertEqual(realpath('%d' % depth), ABSTFN)
314 finally:
315 os.chdir(old_path)
316 for i in range(depth + 1):
317 test_support.unlink(ABSTFN + '/%d' % i)
318 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000319
Tim Petersa45cacf2004-08-20 03:47:14 +0000320 def test_realpath_resolve_parents(self):
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000321 # We also need to resolve any symlinks in the parents of a relative
322 # path passed to realpath. E.g.: current working directory is
323 # /usr/doc with 'doc' being a symlink to /usr/share/doc. We call
324 # realpath("a"). This should return /usr/share/doc/a/.
325 try:
326 old_path = abspath('.')
327 os.mkdir(ABSTFN)
328 os.mkdir(ABSTFN + "/y")
329 os.symlink(ABSTFN + "/y", ABSTFN + "/k")
330
331 os.chdir(ABSTFN + "/k")
332 self.assertEqual(realpath("a"), ABSTFN + "/y/a")
333 finally:
334 os.chdir(old_path)
Collin Winterdbead562007-03-10 02:23:40 +0000335 test_support.unlink(ABSTFN + "/k")
336 safe_rmdir(ABSTFN + "/y")
337 safe_rmdir(ABSTFN)
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000338
339 def test_realpath_resolve_before_normalizing(self):
340 # Bug #990669: Symbolic links should be resolved before we
341 # normalize the path. E.g.: if we have directories 'a', 'k' and 'y'
342 # in the following hierarchy:
343 # a/k/y
344 #
345 # and a symbolic link 'link-y' pointing to 'y' in directory 'a',
346 # then realpath("link-y/..") should return 'k', not 'a'.
347 try:
348 old_path = abspath('.')
349 os.mkdir(ABSTFN)
350 os.mkdir(ABSTFN + "/k")
351 os.mkdir(ABSTFN + "/k/y")
352 os.symlink(ABSTFN + "/k/y", ABSTFN + "/link-y")
353
354 # Absolute path.
355 self.assertEqual(realpath(ABSTFN + "/link-y/.."), ABSTFN + "/k")
356 # Relative path.
357 os.chdir(dirname(ABSTFN))
Ezio Melottie3467d52010-02-20 09:40:07 +0000358 self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."),
359 ABSTFN + "/k")
Johannes Gijsbers4ec40642004-08-14 15:01:53 +0000360 finally:
361 os.chdir(old_path)
Collin Winterdbead562007-03-10 02:23:40 +0000362 test_support.unlink(ABSTFN + "/link-y")
363 safe_rmdir(ABSTFN + "/k/y")
364 safe_rmdir(ABSTFN + "/k")
365 safe_rmdir(ABSTFN)
Tim Peters5d36a552005-06-03 22:40:27 +0000366
Georg Brandl268e61c2005-06-03 14:28:50 +0000367 def test_realpath_resolve_first(self):
368 # Bug #1213894: The first component of the path, if not absolute,
369 # must be resolved too.
370
371 try:
372 old_path = abspath('.')
373 os.mkdir(ABSTFN)
374 os.mkdir(ABSTFN + "/k")
375 os.symlink(ABSTFN, ABSTFN + "link")
376 os.chdir(dirname(ABSTFN))
Tim Peters5d36a552005-06-03 22:40:27 +0000377
Georg Brandl268e61c2005-06-03 14:28:50 +0000378 base = basename(ABSTFN)
379 self.assertEqual(realpath(base + "link"), ABSTFN)
380 self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k")
381 finally:
382 os.chdir(old_path)
Collin Winterdbead562007-03-10 02:23:40 +0000383 test_support.unlink(ABSTFN + "link")
384 safe_rmdir(ABSTFN + "/k")
385 safe_rmdir(ABSTFN)
Brett Cannonb47243a2003-06-16 21:54:50 +0000386
Collin Winter6f187742007-03-16 22:16:08 +0000387 def test_relpath(self):
Collin Winter75c7eb42007-03-23 22:24:39 +0000388 (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar")
389 try:
390 curdir = os.path.split(os.getcwd())[-1]
391 self.assertRaises(ValueError, posixpath.relpath, "")
392 self.assertEqual(posixpath.relpath("a"), "a")
393 self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a")
394 self.assertEqual(posixpath.relpath("a/b"), "a/b")
395 self.assertEqual(posixpath.relpath("../a/b"), "../a/b")
396 self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a")
397 self.assertEqual(posixpath.relpath("a/b", "../c"), "../"+curdir+"/a/b")
398 self.assertEqual(posixpath.relpath("a", "b/c"), "../../a")
Georg Brandl183a0842008-01-06 14:27:15 +0000399 self.assertEqual(posixpath.relpath("a", "a"), ".")
Hirokazu Yamamoto50f7d7e2010-10-18 13:55:29 +0000400 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x/y/z"), '../../../foo/bar/bat')
401 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/foo/bar"), 'bat')
402 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/"), 'foo/bar/bat')
403 self.assertEqual(posixpath.relpath("/", "/foo/bar/bat"), '../../..')
404 self.assertEqual(posixpath.relpath("/foo/bar/bat", "/x"), '../foo/bar/bat')
405 self.assertEqual(posixpath.relpath("/x", "/foo/bar/bat"), '../../../x')
406 self.assertEqual(posixpath.relpath("/", "/"), '.')
407 self.assertEqual(posixpath.relpath("/a", "/a"), '.')
408 self.assertEqual(posixpath.relpath("/a/b", "/a/b"), '.')
Collin Winter75c7eb42007-03-23 22:24:39 +0000409 finally:
410 os.getcwd = real_getcwd
Collin Winter6f187742007-03-16 22:16:08 +0000411
Florent Xiclunadc1531c2010-03-06 18:07:18 +0000412
413class PosixCommonTest(test_genericpath.CommonTest):
Florent Xicluna985478d2010-03-06 18:52:52 +0000414 pathmodule = posixpath
Florent Xiclunadc1531c2010-03-06 18:07:18 +0000415 attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat']
416
417
Brett Cannonb47243a2003-06-16 21:54:50 +0000418def test_main():
Florent Xiclunadc1531c2010-03-06 18:07:18 +0000419 test_support.run_unittest(PosixPathTest, PosixCommonTest)
420
Brett Cannonb47243a2003-06-16 21:54:50 +0000421
422if __name__=="__main__":
423 test_main()