diff options
-rw-r--r-- | Doc/library/math.rst | 6 | ||||
-rw-r--r-- | Doc/library/tarfile.rst | 102 | ||||
-rw-r--r-- | Doc/whatsnew/2.6.rst | 96 | ||||
-rw-r--r-- | Lib/logging/handlers.py | 32 | ||||
-rw-r--r-- | Lib/poplib.py | 2 | ||||
-rw-r--r-- | Lib/test/test_subprocess.py | 4 | ||||
-rw-r--r-- | Lib/urllib.py | 23 | ||||
-rw-r--r-- | Makefile.pre.in | 2 | ||||
-rw-r--r-- | Misc/ACKS | 1 | ||||
-rw-r--r-- | Misc/developers.txt | 3 |
10 files changed, 168 insertions, 103 deletions
diff --git a/Doc/library/math.rst b/Doc/library/math.rst index b153f21..0868e8e 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -96,6 +96,12 @@ Number-theoretic and representation functions: Return the fractional and integer parts of *x*. Both results carry the sign of *x*, and both are floats. +.. function:: sum(iterable) + + Return an accurate floating point sum of values in the iterable. Avoids + loss of precision by tracking multiple intermediate partial sums. The + algorithm's accuracy depends on IEEE-754 arithmetic guarantees and the + typical case where the rounding mode is half-even. .. function:: trunc(x) diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst index 9f049c1..bc5ce62 100644 --- a/Doc/library/tarfile.rst +++ b/Doc/library/tarfile.rst @@ -30,10 +30,8 @@ Some facts and figures: character devices and block devices and is able to acquire and restore file information like timestamp, access permissions and owner. -* can handle tape devices. - -.. function:: open(name[, mode[, fileobj[, bufsize]]], **kwargs) +.. function:: open(name=None, mode='r', fileobj=None, bufsize=10240, \*\*kwargs) Return a :class:`TarFile` object for the pathname *name*. For detailed information on :class:`TarFile` objects and the keyword arguments that are @@ -74,7 +72,7 @@ Some facts and figures: for *name*. It is supposed to be at position 0. For special purposes, there is a second format for *mode*: - ``'filemode|[compression]'``. :func:`open` will return a :class:`TarFile` + ``'filemode|[compression]'``. :func:`tarfile.open` will return a :class:`TarFile` object that processes its data as a stream of blocks. No random seeking will be done on the file. If given, *fileobj* may be any object that has a :meth:`read` or :meth:`write` method (depending on the *mode*). *bufsize* @@ -112,7 +110,7 @@ Some facts and figures: .. class:: TarFile Class for reading and writing tar archives. Do not use this class directly, - better use :func:`open` instead. See :ref:`tarfile-objects`. + better use :func:`tarfile.open` instead. See :ref:`tarfile-objects`. .. function:: is_tarfile(name) @@ -121,7 +119,7 @@ Some facts and figures: module can read. -.. class:: TarFileCompat(filename[, mode[, compression]]) +.. class:: TarFileCompat(filename, mode='r', compression=TAR_PLAIN) Class for limited access to tar archives with a :mod:`zipfile`\ -like interface. Please consult the documentation of the :mod:`zipfile` module for more details. @@ -163,13 +161,14 @@ Some facts and figures: .. exception:: ExtractError - Is raised for *non-fatal* errors when using :meth:`extract`, but only if + Is raised for *non-fatal* errors when using :meth:`TarFile.extract`, but only if :attr:`TarFile.errorlevel`\ ``== 2``. .. exception:: HeaderError - Is raised by :meth:`frombuf` if the buffer it gets is invalid. + Is raised by :meth:`TarInfo.frombuf` if the buffer it gets is invalid. + Each of the following constants defines a tar archive format that the @@ -197,12 +196,21 @@ details. The default format for creating archives. This is currently :const:`GNU_FORMAT`. +The following variables are available on module level: + + +.. data:: ENCODING + + The default character encoding i.e. the value from either + :func:`sys.getfilesystemencoding` or :func:`sys.getdefaultencoding`. + + .. seealso:: Module :mod:`zipfile` Documentation of the :mod:`zipfile` standard module. - `GNU tar manual, Basic Tar Format <http://www.gnu.org/software/tar/manual/html_node/tar_134.html#SEC134>`_ + `GNU tar manual, Basic Tar Format <http://www.gnu.org/software/tar/manual/html_node/Standard.html>`_ Documentation for tar archive files, including GNU tar extensions. @@ -218,7 +226,7 @@ archive several times. Each archive member is represented by a :class:`TarInfo` object, see :ref:`tarinfo-objects` for details. -.. class:: TarFile(name=None, mode='r', fileobj=None, format=DEFAULT_FORMAT, tarinfo=TarInfo, dereference=False, ignore_zeros=False, encoding=None, errors=None, pax_headers=None, debug=0, errorlevel=0) +.. class:: TarFile(name=None, mode='r', fileobj=None, format=DEFAULT_FORMAT, tarinfo=TarInfo, dereference=False, ignore_zeros=False, encoding=ENCODING, errors=None, pax_headers=None, debug=0, errorlevel=0) All following arguments are optional and can be accessed as instance attributes as well. @@ -245,18 +253,18 @@ object, see :ref:`tarinfo-objects` for details. The *tarinfo* argument can be used to replace the default :class:`TarInfo` class with a different one. - If *dereference* is ``False``, add symbolic and hard links to the archive. If it - is ``True``, add the content of the target files to the archive. This has no + If *dereference* is :const:`False`, add symbolic and hard links to the archive. If it + is :const:`True`, add the content of the target files to the archive. This has no effect on systems that do not support symbolic links. - If *ignore_zeros* is ``False``, treat an empty block as the end of the archive. - If it is *True*, skip empty (and invalid) blocks and try to get as many members + If *ignore_zeros* is :const:`False`, treat an empty block as the end of the archive. + If it is :const:`True`, skip empty (and invalid) blocks and try to get as many members as possible. This is only useful for reading concatenated or damaged archives. *debug* can be set from ``0`` (no debug messages) up to ``3`` (all debug messages). The messages are written to ``sys.stderr``. - If *errorlevel* is ``0``, all errors are ignored when using :meth:`extract`. + If *errorlevel* is ``0``, all errors are ignored when using :meth:`TarFile.extract`. Nevertheless, they appear as error messages in the debug output, when debugging is enabled. If ``1``, all *fatal* errors are raised as :exc:`OSError` or :exc:`IOError` exceptions. If ``2``, all *non-fatal* errors are raised as @@ -273,8 +281,8 @@ object, see :ref:`tarinfo-objects` for details. .. method:: TarFile.open(...) - Alternative constructor. The :func:`open` function on module level is actually a - shortcut to this classmethod. See section :ref:`tarfile-mod` for details. + Alternative constructor. The :func:`tarfile.open` function is actually a + shortcut to this classmethod. .. method:: TarFile.getmember(name) @@ -310,11 +318,11 @@ object, see :ref:`tarinfo-objects` for details. .. method:: TarFile.next() Return the next member of the archive as a :class:`TarInfo` object, when - :class:`TarFile` is opened for reading. Return ``None`` if there is no more + :class:`TarFile` is opened for reading. Return :const:`None` if there is no more available. -.. method:: TarFile.extractall([path[, members]]) +.. method:: TarFile.extractall(path=".", members=None) Extract all members from the archive to the current working directory or directory *path*. If optional *members* is given, it must be a subset of the @@ -332,7 +340,7 @@ object, see :ref:`tarinfo-objects` for details. dots ``".."``. -.. method:: TarFile.extract(member[, path]) +.. method:: TarFile.extract(member, path="") Extract a member from the archive to the current working directory, using its full name. Its file information is extracted as accurately as possible. *member* @@ -341,9 +349,8 @@ object, see :ref:`tarinfo-objects` for details. .. note:: - Because the :meth:`extract` method allows random access to a tar archive there - are some issues you must take care of yourself. See the description for - :meth:`extractall` above. + The :meth:`extract` method does not take care of several extraction issues. + In most cases you should consider using the :meth:`extractall` method. .. warning:: @@ -355,7 +362,7 @@ object, see :ref:`tarinfo-objects` for details. Extract a member from the archive as a file object. *member* may be a filename or a :class:`TarInfo` object. If *member* is a regular file, a file-like object is returned. If *member* is a link, a file-like object is constructed from the - link's target. If *member* is none of the above, ``None`` is returned. + link's target. If *member* is none of the above, :const:`None` is returned. .. note:: @@ -363,7 +370,7 @@ object, see :ref:`tarinfo-objects` for details. :meth:`read`, :meth:`readline`, :meth:`readlines`, :meth:`seek`, :meth:`tell`. -.. method:: TarFile.add(name[, arcname[, recursive[, exclude]]]) +.. method:: TarFile.add(name, arcname=None, recursive=True, exclude=None) Add the file *name* to the archive. *name* may be any type of file (directory, fifo, symbolic link, etc.). If given, *arcname* specifies an alternative name @@ -374,7 +381,7 @@ object, see :ref:`tarinfo-objects` for details. (:const:`True`) or added (:const:`False`). -.. method:: TarFile.addfile(tarinfo[, fileobj]) +.. method:: TarFile.addfile(tarinfo, fileobj=None) Add the :class:`TarInfo` object *tarinfo* to the archive. If *fileobj* is given, ``tarinfo.size`` bytes are read from it and added to the archive. You can @@ -386,7 +393,7 @@ object, see :ref:`tarinfo-objects` for details. avoid irritation about the file size. -.. method:: TarFile.gettarinfo([name[, arcname[, fileobj]]]) +.. method:: TarFile.gettarinfo(name=None, arcname=None, fileobj=None) Create a :class:`TarInfo` object for either the file *name* or the file object *fileobj* (using :func:`os.fstat` on its file descriptor). You can modify some @@ -432,7 +439,7 @@ It does *not* contain the file's data itself. :meth:`getmember`, :meth:`getmembers` and :meth:`gettarinfo`. -.. class:: TarInfo([name]) +.. class:: TarInfo(name="") Create a :class:`TarInfo` object. @@ -450,7 +457,7 @@ It does *not* contain the file's data itself. a :class:`TarInfo` object. -.. method:: TarInfo.tobuf([format[, encoding [, errors]]]) +.. method:: TarInfo.tobuf(format=DEFAULT_FORMAT, encoding=ENCODING, errors='strict') Create a string buffer from a :class:`TarInfo` object. For information on the arguments see the constructor of the :class:`TarFile` class. @@ -579,6 +586,21 @@ How to extract an entire tar archive to the current working directory:: tar.extractall() tar.close() +How to extract a subset of a tar archive with :meth:`TarFile.extractall` using +a generator function instead of a list:: + + import os + import tarfile + + def py_files(members): + for tarinfo in members: + if os.path.splitext(tarinfo.name)[1] == ".py": + yield tarinfo + + tar = tarfile.open("sample.tar.gz") + tar.extractall(members=py_files(tar)) + tar.close() + How to create an uncompressed tar archive from a list of filenames:: import tarfile @@ -601,28 +623,6 @@ How to read a gzip compressed tar archive and display some member information:: print("something else.") tar.close() -How to create a tar archive with faked information:: - - import tarfile - tar = tarfile.open("sample.tar.gz", "w:gz") - for name in namelist: - tarinfo = tar.gettarinfo(name, "fakeproj-1.0/" + name) - tarinfo.uid = 123 - tarinfo.gid = 456 - tarinfo.uname = "johndoe" - tarinfo.gname = "fake" - tar.addfile(tarinfo, file(name)) - tar.close() - -The *only* way to extract an uncompressed tar stream from ``sys.stdin``:: - - import sys - import tarfile - tar = tarfile.open(mode="r|", fileobj=sys.stdin) - for tarinfo in tar: - tar.extract(tarinfo) - tar.close() - .. _tar-formats: diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 3fd892a..54ff968 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1477,7 +1477,44 @@ details. and some modules are being renamed or moved into packages. Python 2.6 running in 3.0-warning mode will warn about these modules when they are imported. + + The modules that have been renamed are: + + * :mod:`ConfigParser` has become :mod:`configparser`. + * :mod:`copy_reg` has become :mod:`copyreg`. + * :mod:`htmlentitydefs` has become :mod:`html.entities`. + * :mod:`HTMLParser` has become :mod:`html.parser`. + * :mod:`repr` (the module) has become :mod:`reprlib`. + * :mod:`SocketServer` has become :mod:`socketserver`. + * :mod:`Tkinter` has become the :mod:`tkinter` package. + * :mod:`Queue` has become :mod:`queue`. + The list of deprecated modules is: + :mod:`audiodev`, + :mod:`bgenlocations`, + :mod:`buildtools`, + :mod:`bundlebuilder`, + :mod:`Canvas`, + :mod:`compiler`, + :mod:`dircache`, + :mod:`dl`, + :mod:`fpformat`, + :mod:`gensuitemodule`, + :mod:`ihooks`, + :mod:`imageop`, + :mod:`imgfile`, + :mod:`linuxaudiodev`, + :mod:`mhlib`, + :mod:`multifile`, + :mod:`new`, + :mod:`popen2`, + :mod:`pure`, + :mod:`statvfs`, + :mod:`sunaudiodev`, + :mod:`test.testall`, + :mod:`toaiff`. + + Various MacOS modules have been removed: :mod:`_builtinSuites`, :mod:`aepack`, :mod:`aetools`, @@ -1487,68 +1524,57 @@ details. :mod:`appletrunner`, :mod:`argvemulator`, :mod:`Audio_mac`, - :mod:`audiodev`, :mod:`autoGIL`, - :mod:`bgenlocations`, - :mod:`buildtools`, - :mod:`bundlebuilder`, - :mod:`Canvas`, :mod:`Carbon`, :mod:`cfmfile`, :mod:`CodeWarrior`, :mod:`ColorPicker`, - :mod:`compiler`, - :mod:`cd`, - :mod:`cddb`, - :mod:`cdplayer`, - :mod:`CL` and :mod:`cl`, - :mod:`cd`, - :mod:`cd`, - :mod:`dircache`, - :mod:`dl`, :mod:`EasyDialogs`, :mod:`Explorer`, :mod:`Finder`, :mod:`FrameWork`, :mod:`findertools`, - :mod:`fpformat`, - :mod:`gensuitemodule`, :mod:`ic`, :mod:`icglue`, :mod:`icopen`, - :mod:`ihooks`, - :mod:`imageop`, - :mod:`linuxaudiodev`, :mod:`macerrors`, :mod:`MacOS`, :mod:`macostools`, :mod:`macresource`, - :mod:`mhlib`, :mod:`MiniAEFrame`, - :mod:`multifile`, :mod:`Nav`, :mod:`Netscape`, - :mod:`new`, :mod:`OSATerminology`, :mod:`pimp`, :mod:`PixMapWrapper`, - :mod:`popen2`, - :mod:`pure`, :mod:`StdSuites`, - :mod:`sv`, :mod:`SystemEvents`, :mod:`Terminal`, - :mod:`terminalcommand`, - :mod:`test.testall`, - :mod:`toaiff`, - :mod:`videoreader`. - - The modules that have been renamed are: + :mod:`terminalcommand`. - * :mod:`ConfigParser` has become :mod:`configparser`. - * :mod:`copy_reg` has become :mod:`copyreg`. - * :mod:`SocketServer` has become :mod:`socketserver`. - * :mod:`Queue` has become :mod:`queue`. + A number of old IRIX-specific modules were deprecated: + :mod:`cd`, + :mod:`cddb`, + :mod:`cdplayer`, + :mod:`CL` and :mod:`cl`, + :mod:`DEVICE`, + :mod:`ERRNO`, + :mod:`FILE`, + :mod:`FL` and :mod:`fl`, + :mod:`flp`, + :mod:`fm`, + :mod:`GET`, + :mod:`GLWS`, + :mod:`GL` and :mod:`gl`, + :mod:`IN`, + :mod:`IOCTL`, + :mod:`jpeg`, + :mod:`panelparser`, + :mod:`readcd`, + :mod:`SV` and :mod:`sv`, + :mod:`torgb`, + :mod:`videoreader`, + :mod:`WAIT`. * The :mod:`bsddb.dbshelve` module now uses the highest pickling protocol available, instead of restricting itself to protocol 1. diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py index 9cb0e09..c871ed0 100644 --- a/Lib/logging/handlers.py +++ b/Lib/logging/handlers.py @@ -153,10 +153,11 @@ class TimedRotatingFileHandler(BaseRotatingHandler): If backupCount is > 0, when rollover is done, no more than backupCount files are kept - the oldest ones are deleted. """ - def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0): + def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=0, utc=0): BaseRotatingHandler.__init__(self, filename, 'a', encoding, delay) self.when = when.upper() self.backupCount = backupCount + self.utc = utc # Calculate the real rollover interval, which is just the number of # seconds between rollovers. Also set the filename suffix used when # a rollover occurs. Current 'when' events supported: @@ -211,7 +212,10 @@ class TimedRotatingFileHandler(BaseRotatingHandler): # the rest. Note that this code doesn't care about leap seconds. :) if self.when == 'MIDNIGHT' or self.when.startswith('W'): # This could be done with less code, but I wanted it to be clear - t = time.localtime(currentTime) + if utc: + t = time.gmtime(currentTime) + else: + t = time.localtime(currentTime) currentHour = t[3] currentMinute = t[4] currentSecond = t[5] @@ -242,13 +246,14 @@ class TimedRotatingFileHandler(BaseRotatingHandler): else: daysToWait = 6 - day + self.dayOfWeek + 1 newRolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24)) - dstNow = t[-1] - dstAtRollover = time.localtime(newRolloverAt)[-1] - if dstNow != dstAtRollover: - if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour - newRolloverAt = newRolloverAt - 3600 - else: # DST bows out before next rollover, so we need to add an hour - newRolloverAt = newRolloverAt + 3600 + if not utc: + dstNow = t[-1] + dstAtRollover = time.localtime(newRolloverAt)[-1] + if dstNow != dstAtRollover: + if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour + newRolloverAt = newRolloverAt - 3600 + else: # DST bows out before next rollover, so we need to add an hour + newRolloverAt = newRolloverAt + 3600 self.rolloverAt = newRolloverAt #print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime) @@ -281,7 +286,7 @@ class TimedRotatingFileHandler(BaseRotatingHandler): if fileName[:plen] == prefix: suffix = fileName[plen:] if self.extMatch.match(suffix): - result.append(fileName) + result.append(os.path.join(dirName, fileName)) result.sort() if len(result) < self.backupCount: result = [] @@ -300,7 +305,10 @@ class TimedRotatingFileHandler(BaseRotatingHandler): self.stream.close() # get the time that this sequence started at and make it a TimeTuple t = self.rolloverAt - self.interval - timeTuple = time.localtime(t) + if self.utc: + timeTuple = time.gmtime(t) + else: + timeTuple = time.localtime(t) dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple) if os.path.exists(dfn): os.remove(dfn) @@ -321,7 +329,7 @@ class TimedRotatingFileHandler(BaseRotatingHandler): while newRolloverAt <= currentTime: newRolloverAt = newRolloverAt + self.interval #If DST changes and midnight or weekly rollover, adjust for this. - if self.when == 'MIDNIGHT' or self.when.startswith('W'): + if (self.when == 'MIDNIGHT' or self.when.startswith('W')) and not self.utc: dstNow = time.localtime(currentTime)[-1] dstAtRollover = time.localtime(newRolloverAt)[-1] if dstNow != dstAtRollover: diff --git a/Lib/poplib.py b/Lib/poplib.py index be78b3e..aa4600c 100644 --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -240,7 +240,7 @@ class POP3: def rset(self): - """Not sure what this does.""" + """Unmark all messages marked for deletion.""" return self._shortcmd('RSET') diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 5a325ce..3f877f2 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -534,7 +534,7 @@ class ProcessTestCase(unittest.TestCase): # args is a string f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") - os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % + os.write(f, "exec '%s' -c 'import sys; sys.exit(47)'\n" % sys.executable) os.close(f) os.chmod(fname, 0o700) @@ -576,7 +576,7 @@ class ProcessTestCase(unittest.TestCase): # call() function with string argument on UNIX f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") - os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % + os.write(f, "exec '%s' -c 'import sys; sys.exit(47)'\n" % sys.executable) os.close(f) os.chmod(fname, 0o700) diff --git a/Lib/urllib.py b/Lib/urllib.py index a5171ef..500bf06 100644 --- a/Lib/urllib.py +++ b/Lib/urllib.py @@ -1271,6 +1271,24 @@ def proxy_bypass_environment(host): if sys.platform == 'darwin': + + def _CFSetup(sc): + from ctypes import c_int32, c_void_p, c_char_p, c_int + sc.CFStringCreateWithCString.argtypes = [ c_void_p, c_char_p, c_int32 ] + sc.CFStringCreateWithCString.restype = c_void_p + sc.SCDynamicStoreCopyProxies.argtypes = [ c_void_p ] + sc.SCDynamicStoreCopyProxies.restype = c_void_p + sc.CFDictionaryGetValue.argtypes = [ c_void_p, c_void_p ] + sc.CFDictionaryGetValue.restype = c_void_p + sc.CFStringGetLength.argtypes = [ c_void_p ] + sc.CFStringGetLength.restype = c_int32 + sc.CFStringGetCString.argtypes = [ c_void_p, c_char_p, c_int32, c_int32 ] + sc.CFStringGetCString.restype = c_int32 + sc.CFNumberGetValue.argtypes = [ c_void_p, c_int, c_void_p ] + sc.CFNumberGetValue.restype = c_int32 + sc.CFRelease.argtypes = [ c_void_p ] + sc.CFRelease.restype = None + def _CStringFromCFString(sc, value): from ctypes import create_string_buffer length = sc.CFStringGetLength(value) + 1 @@ -1307,6 +1325,7 @@ if sys.platform == 'darwin': return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3] sc = cdll.LoadLibrary(find_library("SystemConfiguration")) + _CFSetup(sc) hostIP = None @@ -1319,6 +1338,8 @@ if sys.platform == 'darwin': proxyDict = sc.SCDynamicStoreCopyProxies(None) + if proxyDict is None: + return False try: # Check for simple host names: @@ -1372,11 +1393,11 @@ if sys.platform == 'darwin': from ctypes.util import find_library sc = cdll.LoadLibrary(find_library("SystemConfiguration")) + _CFSetup(sc) if not sc: return {} - kSCPropNetProxiesHTTPEnable = sc.CFStringCreateWithCString(0, b"HTTPEnable", 0) kSCPropNetProxiesHTTPProxy = sc.CFStringCreateWithCString(0, b"HTTPProxy", 0) kSCPropNetProxiesHTTPPort = sc.CFStringCreateWithCString(0, b"HTTPPort", 0) diff --git a/Makefile.pre.in b/Makefile.pre.in index 16cd57a..d813596 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -818,7 +818,7 @@ LIBSUBDIRS= tkinter site-packages test test/output test/data \ test/decimaltestdata \ encodings \ email email/mime email/test email/test/data \ - json json/tests \ + html json json/tests \ sqlite3 sqlite3/test \ logging bsddb bsddb/test csv wsgiref \ lib2to3 lib2to3/fixes lib2to3/pgen2 lib2to3/tests \ @@ -227,6 +227,7 @@ Achim Gaedke Lele Gaifax Santiago Gala Yitzchak Gale +Quentin Gallet-Gilles Raymund Galvin Nitin Ganatra Fred Gansevles diff --git a/Misc/developers.txt b/Misc/developers.txt index b96bede..c97900b 100644 --- a/Misc/developers.txt +++ b/Misc/developers.txt @@ -17,6 +17,9 @@ the format to accommodate documentation needs as they arise. Permissions History ------------------- +- Robert Schuppenies was given SVN access on 21 May 2008 by MvL, + for GSoC contributions. + - Rodrigo Bernardo Pimentel was given SVN access on 29 April 2008 by MvL, for GSoC contributions. |