[Debtorrent-commits] r57 - in /debtorrent/trunk: ./ DebTorrent/ DebTorrent/BT1/

camrdale-guest at users.alioth.debian.org camrdale-guest at users.alioth.debian.org
Mon May 21 03:38:40 UTC 2007


Author: camrdale-guest
Date: Mon May 21 03:38:40 2007
New Revision: 57

URL: http://svn.debian.org/wsvn/debtorrent/?sc=1&rev=57
Log:
Add some initial documentation (docstrings)

Modified:
    debtorrent/trunk/DebTorrent/BT1/Choker.py
    debtorrent/trunk/DebTorrent/BT1/Connecter.py
    debtorrent/trunk/DebTorrent/BT1/Storage.py
    debtorrent/trunk/DebTorrent/BT1/__init__.py
    debtorrent/trunk/DebTorrent/BT1/btformats.py
    debtorrent/trunk/DebTorrent/__init__.py
    debtorrent/trunk/DebTorrent/bencode.py
    debtorrent/trunk/DebTorrent/inifile.py
    debtorrent/trunk/btcompletedir.py
    debtorrent/trunk/btcopyannounce.py
    debtorrent/trunk/btdownloadheadless.py
    debtorrent/trunk/btlaunchmany.py
    debtorrent/trunk/btmakemetafile.py
    debtorrent/trunk/btreannounce.py
    debtorrent/trunk/btrename.py
    debtorrent/trunk/btsethttpseeds.py
    debtorrent/trunk/btshowmetainfo.py
    debtorrent/trunk/bttrack.py
    debtorrent/trunk/setup.py

Modified: debtorrent/trunk/DebTorrent/BT1/Choker.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Choker.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Choker.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Choker.py Mon May 21 03:38:40 2007
@@ -1,8 +1,10 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Contains the Choker class."""
 
 from random import randrange, shuffle
 from DebTorrent.clock import clock
@@ -13,7 +15,47 @@
     False = 0
 
 class Choker:
+    """Manages the choking and unchoking of other downloaders.
+    
+    @type config: C{dictonary}
+    @ivar config: the configuration variables
+    @type round_robin_period: C{int}
+    @ivar round_robin_period: the number of seconds between the client's 
+        switching of upload targets
+    @type schedule: C{method}
+    @ivar schedule: the method to call to schedule future events
+    @type picker: L{PiecePicker}
+    @ivar picker: the PiecePicker to get connection information from
+    @type connections: C{list} of L{Connecter.Connection}
+    @ivar connections: the connections from peers to the client
+    @type last_preferred: C{int}
+    @ivar last_preferred: the number of preferred connections found in the
+        last examination
+    @type last_round_robin: C{long}
+    @ivar last_round_robin: the last time the connections were examined
+    @type done: C{Event}
+    @ivar done: flag to indicate when the download is complete
+    @type super_seed: C{boolean}
+    @ivar super_seed: whether super-seeding is enabled
+    @type paused: C{Event}
+    @ivar paused: flag to indicate when the download is paused
+    
+    """
+    
     def __init__(self, config, schedule, picker, done = lambda: False):
+        """Initialize the Choker instance.
+        
+        @type config: C{dictonary}
+        @param config: the configuration variables
+        @type schedule: C{method}
+        @param schedule: the method to call to schedule future events
+        @type picker: L{PiecePicker}
+        @param picker: the piece picker to use to 
+        @type done: C{Event}
+        @param done: flag to indicate when the download is complete
+        
+        """
+        
         self.config = config
         self.round_robin_period = config['round_robin_period']
         self.schedule = schedule
@@ -27,9 +69,18 @@
         schedule(self._round_robin, 5)
 
     def set_round_robin_period(self, x):
+        """Set a new round-robin period.
+        
+        @type x: C{int}
+        @param x: the new round-robin period
+        @see: L{Choker.round_robin_period}
+        
+        """
+        
         self.round_robin_period = x
 
     def _round_robin(self):
+        """Periodically determine the ordering for connections and call the choker."""
         self.schedule(self._round_robin, 5)
         if self.super_seed:
             cons = range(len(self.connections))
@@ -59,6 +110,13 @@
         self._rechoke()
 
     def _rechoke(self):
+        """Unchoke some connections.
+        
+        Reads the current upload and download rates from the connections, 
+        as well as the connection state, and unchokes the most preferable
+        ones.
+        
+        """
         preferred = []
         maxuploads = self.config['max_uploads']
         if self.paused:
@@ -101,31 +159,70 @@
             u.unchoke()
 
     def connection_made(self, connection, p = None):
+        """Adds a new connection to the list.
+        
+        @type connection: L{Connecter.Connection}
+        @param connection: the connection to the client from the peer
+        @type p: C{int}
+        @param p: the location to insert the new connection into the list
+            (optional, default is to choose a random location)
+        
+        """
+        
         if p is None:
             p = randrange(-2, len(self.connections) + 1)
         self.connections.insert(max(p, 0), connection)
         self._rechoke()
 
     def connection_lost(self, connection):
+        """Removes a lost connection from the list.
+        
+        @type connection: L{Connecter.Connection}
+        @param connection: the connection to the client from the peer
+        
+        """
+        
         self.connections.remove(connection)
         self.picker.lost_peer(connection)
         if connection.get_upload().is_interested() and not connection.get_upload().is_choked():
             self._rechoke()
 
     def interested(self, connection):
+        """Indicate the connection is now interesting.
+        
+        @type connection: L{Connecter.Connection}
+        @param connection: the connection to the client from the peer
+        
+        """
+        
         if not connection.get_upload().is_choked():
             self._rechoke()
 
     def not_interested(self, connection):
+        """Indicate the connection is no longer interesting.
+        
+        @type connection: L{Connecter.Connection}
+        @param connection: the connection to the client from the peer
+        
+        """
+        
         if not connection.get_upload().is_choked():
             self._rechoke()
 
     def set_super_seed(self):
+        """Change to super seed state."""
         while self.connections:             # close all connections
             self.connections[0].close()
         self.picker.set_superseed()
         self.super_seed = True
 
     def pause(self, flag):
+        """Pause the choker.
+        
+        @type flag: C{Event}
+        @param flag: flag to indicate when pausing is finished
+        
+        """
+        
         self.paused = flag
         self._rechoke()

Modified: debtorrent/trunk/DebTorrent/BT1/Connecter.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Connecter.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Connecter.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Connecter.py Mon May 21 03:38:40 2007
@@ -1,8 +1,35 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""For maintaining connections to peers.
+
+ at type DEBUG1: C{boolean}
+ at var DEBUG1: whether to print debugging information for the L{Connection}
+ at type DEBUG2: C{boolean}
+ at var DEBUG2: whether to print debugging information for the L{Connecter}
+ at type CHOKE: C{char}
+ at var CHOKE: the code for choke messages
+ at type UNCHOKE: C{char}
+ at var UNCHOKE: the code for unchoke messages
+ at type INTERESTED: C{char}
+ at var INTERESTED: the code for interested messages
+ at type NOT_INTERESTED: C{char}
+ at var NOT_INTERESTED: the code for not interested messages
+ at type HAVE: C{char}
+ at var HAVE: the code for have messages
+ at type BITFIELD: C{char}
+ at var BITFIELD: the code for bitfield messages
+ at type REQUEST: C{char}
+ at var REQUEST: the code for request messages
+ at type PIECE: C{char}
+ at var PIECE: the code for piece messages
+ at type CANCEL: C{char}
+ at var CANCEL: the code for cancel messages
+
+"""
 
 from DebTorrent.bitfield import Bitfield
 from DebTorrent.clock import clock
@@ -18,9 +45,23 @@
 DEBUG2 = True
 
 def toint(s):
+    """Convert four-byte big endian representation to a long.
+    
+    @type s: C{string}
+    @param s: the string to convert
+    
+    """
+    
     return long(b2a_hex(s), 16)
 
 def tobinary(i):
+    """Convert an integer to a four-byte big endian representation.
+    
+    @type i: C{int}
+    @param i: the integer to convert
+    
+    """
+    
     return (chr(i >> 24) + chr((i >> 16) & 0xFF) + 
         chr((i >> 8) & 0xFF) + chr(i & 0xFF))
 
@@ -40,7 +81,46 @@
 CANCEL = chr(8)
 
 class Connection:
+    """A connection to an individual peer.
+    
+    @type connection: unknown
+    @ivar connection: the connection
+    @type connecter: L{Connecter}
+    @ivar connecter: the collection of all connections
+    @type ccount: C{int}
+    @ivar ccount: the number of the connection
+    @type got_anything: C{boolean}
+    @ivar got_anything: whether a message has ever been received on the connection
+    @type next_upload: unknown
+    @ivar next_upload: the connection that will next be allowed to upload
+    @type outqueue: C{list}
+    @ivar outqueue: the queue of messages to send on the connection that are
+        waiting for the current piece to finish sending
+    @type partial_message: C{string}
+    @ivar partial_message: the remaining data in the current piece being sent
+    @type upload: C{Uploader.Upload}
+    @ivar upload: the Uploader instance to use for the connection
+    @type download: C{Downloader.Downloader}
+    @ivar download: the Downloader instance to use for the connection
+    @type send_choke_queued: C{boolean}
+    @ivar send_choke_queued: whether to suppress the next L{CHOKE} message
+    @type just_unchoked: C{long}
+    @ivar just_unchoked: the time of a recent L{UNCHOKE}, if it was the first
+    
+    """
+    
     def __init__(self, connection, connecter, ccount):
+        """Initialize the class.
+        
+        @type connection: unknown
+        @param connection: the connection
+        @type connecter: L{Connecter}
+        @param connecter: the collection of all connections
+        @type ccount: C{int}
+        @param ccount: the number of the connection
+        
+        """
+        
         self.connection = connection
         self.connecter = connecter
         self.ccount = ccount
@@ -53,32 +133,71 @@
         self.just_unchoked = None
 
     def get_ip(self, real=False):
+        """Get the IP address of the connection.
+        
+        @type real: C{boolean}
+        @param real: unknown (optional, defaults to False)
+        
+        """
+        
         return self.connection.get_ip(real)
 
     def get_id(self):
+        """Get the Peer ID of the connection.
+        
+        @rtype: C{string}
+        @return: the ID of the connection
+        
+        """
+        
         return self.connection.get_id()
 
     def get_readable_id(self):
+        """Get a human readable version of the ID of the connection.
+        
+        @rtype: C{string}
+        @return: the ID of the connection
+        
+        """
+        
         return self.connection.get_readable_id()
 
     def close(self):
+        """Close the connection."""
         if DEBUG1:
             print (self.ccount,'connection closed')
         self.connection.close()
 
     def is_locally_initiated(self):
+        """Check whether the connection was established by the client.
+        
+        @rtype: C{boolean}
+        @return: whether the connection was established by the client
+        
+        """
+        
         return self.connection.is_locally_initiated()
 
     def is_encrypted(self):
+        """Check whether the connection is encrypted.
+        
+        @rtype: C{boolean}
+        @return: whether the connection is encrypted
+        
+        """
+        
         return self.connection.is_encrypted()
 
     def send_interested(self):
+        """Send the L{INTERESTED} message."""
         self._send_message(INTERESTED)
 
     def send_not_interested(self):
+        """Send the L{NOT_INTERESTED} message."""
         self._send_message(NOT_INTERESTED)
 
     def send_choke(self):
+        """Send the L{CHOKE} message."""
         if self.partial_message:
             self.send_choke_queued = True
         else:
@@ -87,6 +206,7 @@
             self.just_unchoked = 0
 
     def send_unchoke(self):
+        """Send the L{UNCHOKE} message."""
         if self.send_choke_queued:
             self.send_choke_queued = False
             if DEBUG1:
@@ -100,27 +220,73 @@
                 self.just_unchoked = clock()
 
     def send_request(self, index, begin, length):
+        """Send the L{REQUEST} message.
+        
+        @type index: C{int}
+        @param index: the piece to request some of
+        @type begin: C{int}
+        @param begin: the starting offset within the piece
+        @type length: C{int}
+        @param length: the length of the part of the piece to get
+        
+        """
+        
         self._send_message(REQUEST + tobinary(index) + 
             tobinary(begin) + tobinary(length))
         if DEBUG1:
             print (self.ccount,'sent request',index,begin,begin+length)
 
     def send_cancel(self, index, begin, length):
+        """Send the L{CANCEL} message.
+        
+        Cancels a previously sent L{REQUEST} message.
+        
+        @type index: C{int}
+        @param index: the piece that was requested
+        @type begin: C{int}
+        @param begin: the starting offset within the piece
+        @type length: C{int}
+        @param length: the length of the part of the piece to get
+        
+        """
+        
         self._send_message(CANCEL + tobinary(index) + 
             tobinary(begin) + tobinary(length))
         if DEBUG1:
             print (self.ccount,'sent cancel',index,begin,begin+length)
 
     def send_bitfield(self, bitfield):
+        """Send the L{BITFIELD} message.
+        
+        @type bitfield: C{string}
+        @param bitfield: the bitfield to send
+        
+        """
+        
         self._send_message(BITFIELD + bitfield)
 
     def send_have(self, index):
+        """Send the L{HAVE} message.
+        
+        @type index: C{int}
+        @param index: the piece index to indicate having
+        
+        """
+        
         self._send_message(HAVE + tobinary(index))
 
     def send_keepalive(self):
+        """Send a keepalive message."""
         self._send_message('')
 
     def _send_message(self, s):
+        """Actually send the message.
+        
+        @type s: C{string}
+        @param s: the message to send
+        
+        """
+        
         if DEBUG2:
             if s:
                 print (self.ccount,'SENDING MESSAGE',ord(s[0]),len(s))
@@ -133,6 +299,15 @@
             self.connection.send_message_raw(s)
 
     def send_partial(self, bytes):
+        """Send a L{PIECE} message containing part of a piece.
+        
+        @type bytes: C{int}
+        @param bytes: the number of bytes of piece data to send
+        @rtype: C{int}
+        @return: the actual number of bytes sent
+        
+        """
+        
         if self.connection.closed:
             return 0
         if self.partial_message is None:
@@ -165,18 +340,57 @@
         return len(q)
 
     def get_upload(self):
+        """Get the L{Uploader.Upload} instance for this connection.
+        
+        @rtype: L{Uploader.Upload}
+        @return: the Upload instance
+        
+        """
+        
         return self.upload
 
     def get_download(self):
+        """Get the L{Downloader.Downloader} instance for this connection.
+        
+        @rtype: L{Downloader.Downloader}
+        @return: the Downloader instance
+        
+        """
+        
         return self.download
 
     def set_download(self, download):
+        """Set the L{Downloader.Downloader} instance for this connection.
+        
+        @type download: L{Downloader.Downloader}
+        @param download: the Downloader instance
+        
+        """
+        
         self.download = download
 
     def backlogged(self):
+        """Check whether the connection is ready to send.
+        
+        @rtype: C{boolean}
+        @return: whether the connection is backlogged
+        
+        """
+        
         return not self.connection.is_flushed()
 
     def got_request(self, i, p, l):
+        """Process a request from a peer for a part of a piece.
+        
+        @type i: C{int}
+        @param i: the piece index
+        @type p: C{int}
+        @param p: the position to start at
+        @type l: C{int}
+        @param l: the length to send
+        
+        """
+        
         self.upload.got_request(i, p, l)
         if self.just_unchoked:
             self.connecter.ratelimiter.ping(clock() - self.just_unchoked)
@@ -186,8 +400,59 @@
 
 
 class Connecter:
+    """A collection of all connections to peers.
+    
+    @type downloader: L{Downloader.Downloader}
+    @ivar downloader: the Downloader instance to use
+    @type make_upload: C{method}
+    @ivar make_upload: the method to create a new L{Uploader.Upload}
+    @type choker: L{Choker.Choker}
+    @ivar choker: the Choker instance to use
+    @type numpieces: C{int}
+    @ivar numpieces: the number of pieces in the download
+    @type config: C{dictionary}
+    @ivar config: the configration information
+    @type ratelimiter: L{RateLimiter.RateLimiter}
+    @ivar ratelimiter: the RateLimiter instance to use
+    @type rate_capped: unknown
+    @ivar rate_capped: unknown
+    @type sched: unknown
+    @ivar sched: unknown
+    @type totalup: L{Debtorrent.CurrentRateMeasure.Measure}
+    @ivar totalup: the Measure instance to use
+    @type connections: C{dictionary}
+    @ivar connections: the collection of connections that are open
+    @type external_connection_made: C{int}
+    @ivar external_connection_made: greater than 0 if there have been external connections
+    @type ccount: C{int}
+    @ivar ccount: the largest connection number used
+    
+    """
+    
     def __init__(self, make_upload, downloader, choker, numpieces,
             totalup, config, ratelimiter, sched = None):
+        """
+        
+        @type make_upload: C{method}
+        @param make_upload: the method to create a new L{Uploader.Upload}
+        @type downloader: L{Downloader.Downloader}
+        @param downloader: the Downloader instance to use
+        @type choker: L{Choker.Choker}
+        @param choker: the Choker instance to use
+        @type numpieces: C{int}
+        @param numpieces: the number of pieces in the download
+        @type totalup: L{Debtorrent.CurrentRateMeasure.Measure}
+        @param totalup: the Measure instance to use
+        @type config: C{dictionary}
+        @param config: the configration information
+        @type ratelimiter: L{RateLimiter.RateLimiter}
+        @param ratelimiter: the RateLimiter instance to use
+        @type sched: C{method}
+        @param sched: the method to call to schedule future actions
+            (optional, default is None)
+        
+        """
+        
         self.downloader = downloader
         self.make_upload = make_upload
         self.choker = choker
@@ -203,9 +468,25 @@
         self.ccount = 0
 
     def how_many_connections(self):
+        """Get the number of currently open connections.
+        
+        @rtype: C{int}
+        @return: the number of open connections
+        
+        """
+        
         return len(self.connections)
 
     def connection_made(self, connection):
+        """Make a new connection.
+        
+        @type connection: unknown
+        @param connection: the new connection to make
+        @rtype: L{Connection}
+        @return: the new connection
+        
+        """
+        
         self.ccount += 1
         c = Connection(connection, self, self.ccount)
         if DEBUG2:
@@ -217,6 +498,13 @@
         return c
 
     def connection_lost(self, connection):
+        """Process a lost connection.
+        
+        @type connection: unknown
+        @param connection: the connection that was lost
+        
+        """
+        
         c = self.connections[connection]
         if DEBUG2:
             print (c.ccount,'connection closed')
@@ -226,16 +514,39 @@
         self.choker.connection_lost(c)
 
     def connection_flushed(self, connection):
+        """Process a flushed connection.
+        
+        @type connection: unknown
+        @param connection: the connection that was flushed
+        
+        """
+        
         conn = self.connections[connection]
         if conn.next_upload is None and (conn.partial_message is not None
                or len(conn.upload.buffer) > 0):
             self.ratelimiter.queue(conn)
             
     def got_piece(self, i):
+        """Alert all the open connections that a piece was received.
+        
+        @type i: C{int}
+        @param i: the piece index that was received
+        
+        """
+        
         for co in self.connections.values():
             co.send_have(i)
 
     def got_message(self, connection, message):
+        """Process a received message on a connection.
+        
+        @type connection: unknown
+        @param connection: the connection that the message was received on
+        @type message: C{string}
+        @param message: the message that was received
+        
+        """
+        
         c = self.connections[connection]
         t = message[0]
         if DEBUG2:

Modified: debtorrent/trunk/DebTorrent/BT1/Storage.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/Storage.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/Storage.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/Storage.py Mon May 21 03:38:40 2007
@@ -1,8 +1,27 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Low-level writing of files.
+
+
+
+ at type DEBUG: C{boolean}
+ at var DEBUG: whether to enable printing of debug messages
+ at type MAXREADSIZE: C{long}
+ at var MAXREADSIZE: the maximum number of bytes that can be read at a time
+ at type MAXLOCKSIZE: C{long}
+ at var MAXLOCKSIZE: the maximum size to lock at a time (windows only)
+ at type MAXLOCKRANGE: C{long}
+ at var MAXLOCKRANGE: the maximum range to lock in a file (windows only)
+ at type _pool: L{DebTorrent.piecebuffer.BufferPool}
+ at var _pool: the buffer for temporary storage of pieces
+ at type PieceBuffer: C{method} L{DebTorrent.piecebuffer.BufferPool.new}
+ at var PieceBuffer: returns a new or existing L{DebTorrent.piecebuffer.SingleBuffer}
+
+"""
 
 from DebTorrent.piecebuffer import BufferPool
 from threading import Lock
@@ -33,12 +52,111 @@
 PieceBuffer = _pool.new
 
 def dummy_status(fractionDone = None, activity = None):
+    """Dummy function to print nothing."""
     pass
 
 class Storage:
+    """Low-level writing of files.
+    
+    Control the low-level management of files in the download. Contains
+    functions to open and close, read and write, enable and disable, 
+    flush and delete, all the files in the download. Also serves as an 
+    abstraction layer, as the reading and writing is called with no 
+    knowledge of file boundaries.
+    
+    @type files: C{list} of C{tuple} of (C{string}, C{long})
+    @ivar files: the files list from the info of the metainfo dictionary
+    @type piece_lengths: C{list} of C{long}
+    @ivar piece_lengths: the list of piece lengths
+    @type doneflag: unknown
+    @ivar doneflag: unknown
+    @type disabled: C{list} of C{boolean}
+    @ivar disabled: list of true for the files that are disabled
+    @type file_ranges: C{list} of (C{long}, C{long}, C{long}, C{string})
+    @ivar file_ranges: for each file, the start offset within the download, 
+        end offset, offset within the file, and file name
+    @type file_pieces: C{list} of (C{int}, C{int})
+    @ivar file_pieces: for each file, the starting and ending piece of the file
+    @type disabled_ranges: C{list} of C{tuple}
+    @ivar disabled_ranges: for each file, a tuple containing the working range, 
+        shared pieces, and disabled range (see L{_get_disabled_ranges} for their
+        meaning)
+    @type working_ranges: C{list} of C{list} of (C{long}, C{long}, C{long}, C{string})
+    @ivar working_ranges: For each file, the list of files to be written when
+        writing to that file (may not be the actual file, i.e if it is 
+        disabled). Ranges are temporarily stored here, before eventually being
+        written to self.ranges by L{_reset_ranges} to be used.
+    @type handles: C{dictionary} of {C{string}, C{file handle}}
+    @ivar handles: the file handles that are open, keys are file names and
+        values are the file handles
+    @type whandles: C{dictionary} of {C{string}, C{int}}
+    @ivar whandles: the files that are open for writing, keys are the file
+        names and values are all 1
+    @type tops: C{dictionary} of {C{string}, C{long}}
+    @ivar tops: the current length of each file (by name)
+    @type sizes: C{dictionary} of {C{string}, C{long}}
+    @ivar sizes: the desired length of each file (by name)
+    @type mtimes: C{dictionary} of {C{string}, C{long}}
+    @ivar mtimes: the last modified time of each file (by name)
+    @type lock_file: C{method}
+    @ivar lock_file: locks a file (if file locking is enabled, otherwise does
+        nothing)
+    @type lock_file: C{method}
+    @ivar lock_file: locks a file (if file locking is enabled, otherwise does
+        nothing)
+    @type unlock_file: C{method}
+    @ivar unlock_file: unlocks a file (if file locking is enabled, otherwise 
+        does nothing)
+    @type lock_while_reading: C{boolean}
+    @ivar lock_while_reading: whether to lock files while reading them
+    @type lock: C{lock}
+    @ivar lock: a threading lock object for synchorizing threads (semaphore)
+    @type total_length: C{long}
+    @ivar total_length: the total length in bytes of the download
+    @type max_files_open: C{int}
+    @ivar max_files_open: the maximum number of files to have open at a time
+        (0 means no maximum)
+    @type handlebuffer: C{list}
+    @ivar handlebuffer: the list of open files, in the order of most recently
+        accessed, with the most recently accessed at the end of the list
+        (only if there is a limit on the number of open files, otherwise None)
+    @type ranges: C{list} of C{list} of (C{long}, C{long}, C{long}, C{string})
+    @ivar ranges: for each file, the list of files to be written when
+        writing to that file (may not be the actual file, i.e if it is 
+        disabled)
+    @type begins: C{list} of C{long}
+    @ivar begins: the offset within the download that each non-disabled file
+        begins at
+    @type bufferdir: C{string}
+    @ivar bufferdir: the buffer directory
+    @type reset_file_status: C{method}
+    @ivar reset_file_status: a shortcut to the _reset_ranges method
+
+    """
+    
     def __init__(self, files, piece_lengths, doneflag, config,
                  disabled_files = None):
-        # can raise IOError and ValueError
+        """Initializes the Storage.
+        
+        Initializes some variables, and calculates defaults for others,
+        such as which pieces are contained by which file.
+        
+        @type files: C{list} of C{tuple} of (C{string}, C{long})
+        @param files: the files list from the info of the metainfo dictionary
+        @type piece_lengths: C{list} of C{long}
+        @param piece_lengths: the list of piece lengths
+        @type doneflag: unknown
+        @param doneflag: unknown
+        @type config: C{dictionary}
+        @param config: the configuration information
+        @type disabled_files: C{list} of C{boolean}
+        @param disabled_files: list of true for the files that are disabled
+            (optional, default is no files disabled)
+        @raise IOError: unknown
+        @raise ValueError: unknown
+        
+        """
+        
         self.files = files
         self.piece_lengths = piece_lengths
         self.doneflag = doneflag
@@ -129,6 +247,15 @@
 
     if os.name == 'nt':
         def _lock_file(self, name, f):
+            """Lock a file on Windows.
+            
+            @type name: C{string}
+            @param name: The file name to lock (only used to get the file size)
+            @type f: C{file}
+            @param f: a file handle for the file to lock
+
+            """
+            
             import msvcrt
             for p in range(0, min(self.sizes[name],MAXLOCKRANGE), MAXLOCKSIZE):
                 f.seek(p)
@@ -136,6 +263,15 @@
                                min(MAXLOCKSIZE,self.sizes[name]-p))
 
         def _unlock_file(self, name, f):
+            """Unlock a file on Windows.
+            
+            @type name: C{string}
+            @param name: The file name to unlock (only used to get the file size)
+            @type f: C{file}
+            @param f: a file handle for the file to unlock
+
+            """
+            
             import msvcrt
             for p in range(0, min(self.sizes[name],MAXLOCKRANGE), MAXLOCKSIZE):
                 f.seek(p)
@@ -144,21 +280,53 @@
 
     elif os.name == 'posix':
         def _lock_file(self, name, f):
+            """Lock a file on Linux.
+            
+            @type name: C{string}
+            @param name: The file name to lock (only used to get the file size)
+            @type f: C{file}
+            @param f: a file handle for the file to lock
+
+            """
+            
             import fcntl
             fcntl.flock(f.fileno(), fcntl.LOCK_EX)
 
         def _unlock_file(self, name, f):
+            """Unlock a file on Linux.
+            
+            @type name: C{string}
+            @param name: The file name to unlock (only used to get the file size)
+            @type f: C{file}
+            @param f: a file handle for the file to unlock
+
+            """
+            
             import fcntl
             fcntl.flock(f.fileno(), fcntl.LOCK_UN)
 
     else:
         def _lock_file(self, name, f):
+            """Dummy function to not Lock a file on other systems."""
             pass
+
         def _unlock_file(self, name, f):
+            """Dummy function to not unlock a file on other systems."""
             pass
 
 
     def was_preallocated(self, pos, length):
+        """Check if a download location was pre-allocated.
+        
+        @type pos: C{long}
+        @param pos: the location to start checking
+        @type length: C{long}
+        @param length: the amount of the download to check
+        @rtype: C{boolean}
+        @return: whether the download location was pre-allocated
+        
+        """
+        
         for file, begin, end in self._intervals(pos, length):
             if self.tops.get(file, 0) < end:
                 return False
@@ -166,17 +334,44 @@
 
 
     def _sync(self, file):
+        """Synchronize a file to disk.
+        
+        Closes the open file so that it is synchronize to disk, the next time
+        it is referenced it will be reopened.
+        
+        @type file: C{string}
+        @param file: the name of the file to sync
+        
+        """
+        
         self._close(file)
         if self.handlebuffer:
             self.handlebuffer.remove(file)
 
     def sync(self):
-        # may raise IOError or OSError
+        """Synchronize all read/write files to disk.
+        
+        @raise IOError: unknown
+        @raise OSError: unknown
+        
+        """
+        
         for file in self.whandles.keys():
             self._sync(file)
 
 
     def set_readonly(self, f=None):
+        """Set a file (or all files) to be read-only.
+        
+        Synchronizes the file (or all read/write files if none is given) to
+        disk. The next time the file is accessed it will be reopened.
+        
+        @type f: C{int}
+        @param f: the number of the file to set read-only 
+            (optional, default is to set all read/write files read-only)
+        
+        """
+        
         if f is None:
             self.sync()
             return
@@ -186,10 +381,30 @@
             
 
     def get_total_length(self):
+        """Get the total length of the download.
+        
+        @rtype: C{long}
+        @return: the total length of the download
+        
+        """
+        
         return self.total_length
 
 
     def _open(self, file, mode):
+        """Open a file with the given mode.
+        
+        @type file: C{string}
+        @param file: the file name to open
+        @type mode: C{string}
+        @param mode: the mode to open the file in 
+            (r = read, w = write, a = append, add b for binary)
+        @rtype: C{file handle}
+        @return: the file handle to access the file with
+        @raise IOError: if the file has been modified since it was last read
+        
+        """
+        
         if self.mtimes.has_key(file):
             try:
               if self.handlebuffer is not None:
@@ -214,6 +429,13 @@
 
 
     def _close(self, file):
+        """Close the file
+        
+        @type file: C{string}
+        @param file: the name of the file to close
+
+        """
+        
         f = self.handles[file]
         del self.handles[file]
         if self.whandles.has_key(file):
@@ -230,6 +452,13 @@
 
 
     def _close_file(self, file):
+        """Close the file and release the handle.
+        
+        @type file: C{string}
+        @param file: the name of the file to close
+
+        """
+        
         if not self.handles.has_key(file):
             return
         self._close(file)
@@ -238,6 +467,18 @@
         
 
     def _get_file_handle(self, file, for_write):
+        """Get a new or existing flie handle for the file.
+        
+        @type file: C{string}
+        @param file: the name of the file to get a handle for
+        @type for_write: C{boolean}
+        @param for_write: whether to open the file for writing
+        @rtype: C{file handle}
+        @return: the file handle that can be used for the file
+        @raise IOError: if the file can not be opened
+
+        """
+
         if self.handles.has_key(file):
             if for_write and not self.whandles.has_key(file):
                 self._close(file)
@@ -283,6 +524,7 @@
 
 
     def _reset_ranges(self):
+        """Re-initialize the ranges from the working copies."""
         self.ranges = []
         for l in self.working_ranges:
             self.ranges.extend(l)
@@ -292,6 +534,22 @@
             print str(self.begins)
 
     def _intervals(self, pos, amount):
+        """Get the files that are within the range.
+        
+        Finds all the files that occur within a given range in the download,
+        and return a list of them. Includes the range of the file that is
+        inside the range, which will be the start (0) and end (length) of the 
+        file unless it goes past the beginning or end of the range.
+        
+        @type pos: C{long}
+        @param pos: the start of the range within the download
+        @type amount: C{long}
+        @param amount: the length of the range
+        @rtype: C{list} of C{tuple} of (C{string}, C{long}, C{long})
+        @return: the list of files and their start and end offsets in the range
+        
+        """
+        
         r = []
         stop = pos + amount
         p = bisect(self.begins, pos) - 1
@@ -308,6 +566,20 @@
 
 
     def read(self, pos, amount, flush_first = False):
+        """Read data from the download.
+        
+        @type pos: C{long}
+        @param pos: the offset in the download to start reading from
+        @type amount: C{long}
+        @param amount: the length of the data to read
+        @type flush_first: C{boolean}
+        @param flush_first: whether to flush the files before reading the data
+            (optional, default is not to flush)
+        @rtype: L{DebTorrent.piecebuffer.SingleBuffer}
+        @return: the data that was read
+        
+        """
+        
         r = PieceBuffer()
         for file, pos, end in self._intervals(pos, amount):
             if DEBUG:
@@ -329,6 +601,15 @@
         return r
 
     def write(self, pos, s):
+        """Write data to the download.
+        
+        @type pos: C{long}
+        @param pos: the offset in the download to start writing at
+        @type s: unknown
+        @param s: data to write
+        
+        """
+
         # might raise an IOError
         total = 0
         for file, begin, end in self._intervals(pos, len(s)):
@@ -342,11 +623,19 @@
             total += end - begin
 
     def make_directories(self, file):
+        """Create missing parent directories for a file.
+        
+        @type file: C{string}
+        @param file: the file name to create directories for
+        
+        """
+        
         file = split(file)[0]
         if file != '' and not exists(file):
             makedirs(file)
 
     def top_off(self):
+        """Extend all files to their appropriate length."""
         for begin, end, offset, file in self.ranges:
             l = offset + end - begin
             if l > self.tops.get(file, 0):
@@ -357,6 +646,7 @@
                 self.lock.release()
 
     def flush(self):
+        """Flush all files to disk."""
         # may raise IOError or OSError
         for file in self.whandles.keys():
             self.lock.acquire()
@@ -364,6 +654,7 @@
             self.lock.release()
 
     def close(self):
+        """Close all open files."""
         for file, f in self.handles.items():
             try:
                 self.unlock_file(file, f)
@@ -379,6 +670,28 @@
 
 
     def _get_disabled_ranges(self, f):
+        """Calculate the file ranges for the disabled file.
+        
+        Calculates, based on the file lengths and piece lengths, the ranges
+        to write for the file. There are three lists calculated.
+        
+        The working range is the list of files and file offsets to write if 
+        the file is enabled.
+        
+        The shared pieces is a list of piece numbers that the file shares 
+        with other files.
+        
+        The disabled range is the list of files and file offsets to write if
+        the file is disabled.
+        
+        @type f: C{int}
+        @param f: the index of the file
+        @rtype: C{tuple}
+        @return: a tuple containing the working range, shared pieces, and 
+            disabled range
+        
+        """
+        
         if not self.file_ranges[f]:
             return ((),(),())
         r = self.disabled_ranges[f]
@@ -406,9 +719,23 @@
         
 
     def set_bufferdir(self, dir):
+        """Sets the buffer directory.
+        
+        @type dir: C{string}
+        @param dir: the new buffer directory
+        
+        """
+        
         self.bufferdir = dir
 
     def enable_file(self, f):
+        """Enable a file for writing.
+        
+        @type f: C{int}
+        @param f: the index of the file to enable
+        
+        """
+        
         if not self.disabled[f]:
             return
         self.disabled[f] = False
@@ -428,6 +755,12 @@
         self.working_ranges[f] = [r]
 
     def disable_file(self, f):
+        """Disable a file from writing.
+        
+        @type f: C{int}
+        @param f: the index of the file to disable
+        
+        """
         if self.disabled[f]:
             return
         self.disabled[f] = True
@@ -451,35 +784,56 @@
 
 
     def get_piece_update_list(self, f):
+        """Get the list of pieces the file shares with other files.
+        
+        @type f: C{int}
+        @param f: the index of the file to disable
+        @rtype: C{list} of C{int}
+        @return: the list of piece indexes
+        
+        """
+        
         return self._get_disabled_ranges(f)[1]
 
 
     def delete_file(self, f):
+        """Delete the file.
+        
+        @type f: C{int}
+        @param f: the index of the file to delete
+        
+        """
         try:
             os.remove(self.files[f][0])
         except:
             pass
 
 
-    '''
-    Pickled data format:
-
-    d['files'] = [ file #, size, mtime {, file #, size, mtime...} ]
-                    file # in torrent, and the size and last modification
-                    time for those files.  Missing files are either empty
-                    or disabled.
-    d['partial files'] = [ name, size, mtime... ]
-                    Names, sizes and last modification times of files containing
-                    partial piece data.  Filenames go by the following convention:
-                    {file #, 0-based}{nothing, "b" or "e"}
-                    eg: "0e" "3" "4b" "4e"
-                    Where "b" specifies the partial data for the first piece in
-                    the file, "e" the last piece, and no letter signifying that
-                    the file is disabled but is smaller than one piece, and that
-                    all the data is cached inside so adjacent files may be
-                    verified.
-    '''
     def pickle(self):
+        """Create a dictionary representing the current state of the download.
+        
+        Pickled data format::
+    
+            d['files'] = [ file #, size, mtime {, file #, size, mtime...} ]
+                        file # in torrent, and the size and last modification
+                        time for those files.  Missing files are either empty
+                        or disabled.
+            d['partial files'] = [ name, size, mtime... ]
+                        Names, sizes and last modification times of files containing
+                        partial piece data.  Filenames go by the following convention:
+                        {file #, 0-based}{nothing, "b" or "e"}
+                        eg: "0e" "3" "4b" "4e"
+                        Where "b" specifies the partial data for the first piece in
+                        the file, "e" the last piece, and no letter signifying that
+                        the file is disabled but is smaller than one piece, and that
+                        all the data is cached inside so adjacent files may be
+                        verified.
+        
+        @rtype: C{dictionary}
+        @return: the pickled current status of the download
+        
+        """
+        
         files = []
         pfiles = []
         for i in xrange(len(self.files)):
@@ -495,7 +849,17 @@
 
 
     def unpickle(self, data):
-        # assume all previously-disabled files have already been disabled
+        """Extract the current status of the download from a pickled dictionary.
+        
+        Assumes all previously-disabled files have already been disabled.
+        
+        @type data: C{dictionary}
+        @param data: the pickled current status of the download
+        @rtype: C{list} of C{int}
+        @return: a list of the currently enabled pieces
+        
+        """
+
         try:
             files = {}
             pfiles = {}
@@ -528,6 +892,19 @@
                 print valid_pieces.keys()
             
             def test(old, size, mtime):
+                """Test that the file has not changed since the status save.                
+                
+                @type old: C{tuple} of (C{long}, C{long})
+                @param old: the previous size and modification time of the file
+                @type size: C{long}
+                @param size: the current size of the file
+                @type mtime: C{long}
+                @param mtime: the current modification time of the file
+                @rtype: C{boolean}
+                @return: whether the file has been changed
+
+                """
+                
                 oldsize, oldmtime = old
                 if size != oldsize:
                     return False

Modified: debtorrent/trunk/DebTorrent/BT1/__init__.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/__init__.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/__init__.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/__init__.py Mon May 21 03:38:40 2007
@@ -1,6 +1,11 @@
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
 
-# placeholder
+"""More specific sub-modules for the debtorrent protocol.
+
+This package contains ome more specific sub-modules used by the
+L{DebTorrent} package.
+
+"""

Modified: debtorrent/trunk/DebTorrent/BT1/btformats.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/BT1/btformats.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/BT1/btformats.py (original)
+++ debtorrent/trunk/DebTorrent/BT1/btformats.py Mon May 21 03:38:40 2007
@@ -1,8 +1,20 @@
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Functions for verifying debtorrent metainfo.
+
+These functions all work on bdecoded debtorrent metainfo, and are used
+to verify their conformance with the protocol.
+
+ at type reg: C{regex}
+ at var reg: a compiled regex for verifying the security of path names
+ at type ints: C{tuple} of C{types}
+ at var ints: the types that are acceptable for integer values
+
+"""
 
 from types import StringType, LongType, IntType, ListType, DictType
 from re import compile
@@ -13,6 +25,17 @@
 ints = (LongType, IntType)
 
 def check_info(info):
+    """Checks the info dictionary for conformance.
+    
+    Verifies that the info dictionary of the metainfo conforms to the
+    debtorrent protocol.
+    
+    @type info: C{dictionary}
+    @param info: the info field from the metainfo dictionary
+    @raise ValueError: if the info doesn't conform
+    
+    """
+    
     if type(info) != DictType:
         raise ValueError, 'bad metainfo - not a dictionary'
     pieces = info.get('pieces')
@@ -58,6 +81,17 @@
 #                    raise ValueError, 'bad metainfo - duplicate path'
 
 def check_message(message):
+    """Checks the metainfo dictionary for conformance.
+    
+    Verifies that the metainfo dictionary conforms to the
+    debtorrent protocol.
+    
+    @type message: C{dictionary}
+    @param message: the bdecoded metainfo dictionary
+    @raise ValueError: if the metainfo doesn't conform
+    
+    """
+    
     if type(message) != DictType:
         raise ValueError
     check_info(message.get('info'))
@@ -70,6 +104,17 @@
         raise ValueError, 'name %s disallowed for security reasons' % name
 
 def check_peers(message):
+    """Checks the peers dictionary returned by a tracker for conformance.
+    
+    Verifies that the peers dictionary returned by a tracker conforms to the
+    debtorrent protocol.
+    
+    @type message: C{dictionary}
+    @param message: the bdecoded peers dictionary returned by a tracker
+    @raise ValueError: if the info doesn't conform
+    
+    """
+    
     if type(message) != DictType:
         raise ValueError
     if message.has_key('failure reason'):

Modified: debtorrent/trunk/DebTorrent/__init__.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/__init__.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/__init__.py (original)
+++ debtorrent/trunk/DebTorrent/__init__.py Mon May 21 03:38:40 2007
@@ -1,7 +1,19 @@
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""The main package to implement the debtorrent protocol.
+
+This package, and it's subpackage L{BT1}, contains all the modules needed
+to implement the DebTorrent protocol.
+
+ at type product_name: C{string}
+ at var product_name: the name given for the package
+ at type version_short: C{string}
+ at var version_short: the short version number
+
+"""
 
 product_name = 'DebTorrent'
 version_short = 'T-0.1.0'

Modified: debtorrent/trunk/DebTorrent/bencode.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/bencode.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/bencode.py (original)
+++ debtorrent/trunk/DebTorrent/bencode.py Mon May 21 03:38:40 2007
@@ -1,8 +1,24 @@
 # Written by Petru Paler, Uoti Urpala, Ross Cohen and John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""Functions for bencoding and bdecoding data.
+
+ at type decode_func: C{dictionary} of C{function}
+ at var decode_func: a dictionary of function calls to be made, based on data,
+    the keys are the first character of the data and the value is the
+    function to use to decode that data
+ at type bencached_marker: C{list}
+ at var bencached_marker: mutable type to ensure class origination
+ at type encode_func: C{dictionary} of C{function}
+ at var encode_func: a dictionary of function calls to be made, based on data,
+    the keys are the type of the data and the value is the
+    function to use to encode that data
+ at type BencachedType: C{type}
+ at var BencachedType: the L{Bencached} type
+"""
 
 from types import IntType, LongType, StringType, ListType, TupleType, DictType
 try:
@@ -16,6 +32,18 @@
 from cStringIO import StringIO
 
 def decode_int(x, f):
+    """Bdecode an integer.
+    
+    @type x: C{string}
+    @param x: the data to decode
+    @type f: C{int}
+    @param f: the offset in the data to start at
+    @rtype: C{int}, C{int}
+    @return: the bdecoded integer, and the offset to read next
+    @raise ValueError: if the data is improperly encoded
+    
+    """
+    
     f += 1
     newf = x.index('e', f)
     try:
@@ -30,6 +58,18 @@
     return (n, newf+1)
   
 def decode_string(x, f):
+    """Bdecode a string.
+    
+    @type x: C{string}
+    @param x: the data to decode
+    @type f: C{int}
+    @param f: the offset in the data to start at
+    @rtype: C{string}, C{int}
+    @return: the bdecoded string, and the offset to read next
+    @raise ValueError: if the data is improperly encoded
+    
+    """
+    
     colon = x.index(':', f)
     try:
         n = int(x[f:colon])
@@ -41,10 +81,32 @@
     return (x[colon:colon+n], colon+n)
 
 def decode_unicode(x, f):
+    """Bdecode a unicode string.
+    
+    @type x: C{string}
+    @param x: the data to decode
+    @type f: C{int}
+    @param f: the offset in the data to start at
+    @rtype: C{int}, C{int}
+    @return: the bdecoded unicode string, and the offset to read next
+    
+    """
+    
     s, f = decode_string(x, f+1)
     return (s.decode('UTF-8'),f)
 
 def decode_list(x, f):
+    """Bdecode a list.
+    
+    @type x: C{string}
+    @param x: the data to decode
+    @type f: C{int}
+    @param f: the offset in the data to start at
+    @rtype: C{list}, C{int}
+    @return: the bdecoded list, and the offset to read next
+    
+    """
+    
     r, f = [], f+1
     while x[f] != 'e':
         v, f = decode_func[x[f]](x, f)
@@ -52,6 +114,18 @@
     return (r, f + 1)
 
 def decode_dict(x, f):
+    """Bdecode a dictionary.
+    
+    @type x: C{string}
+    @param x: the data to decode
+    @type f: C{int}
+    @param f: the offset in the data to start at
+    @rtype: C{dictionary}, C{int}
+    @return: the bdecoded dictionary, and the offset to read next
+    @raise ValueError: if the data is improperly encoded
+    
+    """
+    
     r, f = {}, f+1
     lastkey = None
     while x[f] != 'e':
@@ -79,6 +153,18 @@
 #decode_func['u'] = decode_unicode
   
 def bdecode(x, sloppy = 0):
+    """Bdecode a string of data.
+    
+    @type x: C{string}
+    @param x: the data to decode
+    @type sloppy: C{boolean}
+    @param sloppy: whether to allow errors in the decoding
+    @rtype: unknown
+    @return: the bdecoded data
+    @raise ValueError: if the data is improperly encoded
+    
+    """
+    
     try:
         r, l = decode_func[x[0]](x, 0)
 #    except (IndexError, KeyError):
@@ -89,6 +175,7 @@
     return r
 
 def test_bdecode():
+    """A test routine for the bdecoding functions."""
     try:
         bdecode('0:0:')
         assert 0
@@ -233,36 +320,122 @@
 bencached_marker = []
 
 class Bencached:
+    """Dummy data structure for storing bencoded data in memory.
+    
+    @type marker: C{list}
+    @ivar marker: mutable type to make sure the data was encoded by this class
+    @type bencoded: C{string}
+    @ivar bencoded: the bencoded data stored in a string
+    
+    """
+    
     def __init__(self, s):
+        """
+        
+        @type s: C{string}
+        @param s: the new bencoded data to store
+        
+        """
+        
         self.marker = bencached_marker
         self.bencoded = s
 
 BencachedType = type(Bencached('')) # insufficient, but good as a filter
 
 def encode_bencached(x,r):
+    """Bencode L{Bencached} data.
+    
+    @type x: L{Bencached}
+    @param x: the data to encode
+    @type r: C{list}
+    @param r: the currently bencoded data, to which the bencoding of x
+        will be appended
+    
+    """
+    
     assert x.marker == bencached_marker
     r.append(x.bencoded)
 
 def encode_int(x,r):
+    """Bencode an integer.
+    
+    @type x: C{int}
+    @param x: the data to encode
+    @type r: C{list}
+    @param r: the currently bencoded data, to which the bencoding of x
+        will be appended
+    
+    """
+    
     r.extend(('i',str(x),'e'))
 
 def encode_bool(x,r):
+    """Bencode a boolean.
+    
+    @type x: C{boolean}
+    @param x: the data to encode
+    @type r: C{list}
+    @param r: the currently bencoded data, to which the bencoding of x
+        will be appended
+    
+    """
+    
     encode_int(int(x),r)
 
 def encode_string(x,r):    
+    """Bencode a string.
+    
+    @type x: C{string}
+    @param x: the data to encode
+    @type r: C{list}
+    @param r: the currently bencoded data, to which the bencoding of x
+        will be appended
+    
+    """
+    
     r.extend((str(len(x)),':',x))
 
 def encode_unicode(x,r):
+    """Bencode a unicode string.
+    
+    @type x: C{unicode}
+    @param x: the data to encode
+    @type r: C{list}
+    @param r: the currently bencoded data, to which the bencoding of x
+        will be appended
+    
+    """
+    
     #r.append('u')
     encode_string(x.encode('UTF-8'),r)
 
 def encode_list(x,r):
-        r.append('l')
-        for e in x:
-            encode_func[type(e)](e, r)
-        r.append('e')
+    """Bencode a list.
+    
+    @type x: C{list}
+    @param x: the data to encode
+    @type r: C{list}
+    @param r: the currently bencoded data, to which the bencoding of x
+        will be appended
+    
+    """
+    
+    r.append('l')
+    for e in x:
+        encode_func[type(e)](e, r)
+    r.append('e')
 
 def encode_dict(x,r):
+    """Bencode a dictionary.
+    
+    @type x: C{dictionary}
+    @param x: the data to encode
+    @type r: C{list}
+    @param r: the currently bencoded data, to which the bencoding of x
+        will be appended
+    
+    """
+    
     r.append('d')
     ilist = x.items()
     ilist.sort()
@@ -285,6 +458,15 @@
     encode_func[UnicodeType] = encode_unicode
     
 def bencode(x):
+    """Bencode some data.
+    
+    @type x: unknown
+    @param x: the data to encode
+    @rtype: string
+    @return: the bencoded data
+    @raise ValueError: if the data contains a type that cannot be encoded
+    
+    """
     r = []
     try:
         encode_func[type(x)](x, r)
@@ -294,6 +476,7 @@
     return ''.join(r)
 
 def test_bencode():
+    """A test routine for the bencoding functions."""
     assert bencode(4) == 'i4e'
     assert bencode(0) == 'i0e'
     assert bencode(-10) == 'i-10e'

Modified: debtorrent/trunk/DebTorrent/inifile.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/DebTorrent/inifile.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/DebTorrent/inifile.py (original)
+++ debtorrent/trunk/DebTorrent/inifile.py Mon May 21 03:38:40 2007
@@ -4,28 +4,33 @@
 
 # $Id$
 
-'''
-reads/writes a Windows-style INI file
-format:
-
-  aa = "bb"
-  cc = 11
-
-  [eee]
-  ff = "gg"
-
-decodes to:
-d = { '': {'aa':'bb','cc':'11'}, 'eee': {'ff':'gg'} }
-
-the encoder can also take this as input:
-
-d = { 'aa': 'bb, 'cc': 11, 'eee': {'ff':'gg'} }
+'''Functions to read/write a Windows-style INI file
+
+format::
+
+    aa = "bb"
+    cc = 11
+    
+    [eee]
+    ff = "gg"
+
+decodes to::
+
+    d = { '': {'aa':'bb','cc':'11'}, 'eee': {'ff':'gg'} }
+
+the encoder can also take this as input::
+
+    d = { 'aa': 'bb, 'cc': 11, 'eee': {'ff':'gg'} }
 
 though it will only decode in the above format.  Keywords must be strings.
 Values that are strings are written surrounded by quotes, and the decoding
-routine automatically strips any.
-Booleans are written as integers.  Anything else aside from string/int/float
-may have unpredictable results.
+routine automatically strips any quotes from the values.
+Booleans are written as integers.  Anything other than strings, integers, 
+and floats may have unpredictable results.
+
+ at type DEBUG: C{boolean}
+ at var DEBUG: whether to print debugging information
+
 '''
 
 from cStringIO import StringIO
@@ -45,6 +50,20 @@
 DEBUG = True
 
 def ini_write(f, d, comment=''):
+    """Write the ini file.
+    
+    @type f: C{string}
+    @param f: the file name to write
+    @type d: C{dictionary}
+    @param d: the data to write to the ini file
+    @type comment: C{string}
+    @param comment: a comment to write at the top of the file, hash marks
+        will be prefixed (optional, default is no comment)
+    @rtype: C{boolean}
+    @return: whether the write succeeded
+    
+    """
+    
     try:
         a = {'':{}}
         for k,v in d.items():
@@ -107,11 +126,34 @@
 
 if DEBUG:
     def errfunc(lineno, line, err):
+        """Display an error message when reading the ini file fails.
+        
+        @type lineno: C{int}
+        @param lineno: the line number that caused the error 
+        @type line: C{string}
+        @param line: the line that caused the error
+        @type err: C{string}
+        @param err: the error that was generated
+        
+        """
+        
         print '('+str(lineno)+') '+err+': '+line
 else:
     errfunc = lambda lineno, line, err: None
 
 def ini_read(f, errfunc = errfunc):
+    """Read the ini file.
+    
+    @type f: C{string}
+    @param f: the file name to read
+    @type errfunc: C{function}
+    @param errfunc: the function to call when an error occurs
+        (optional, default is to do nothing, unless debugging is enabled in
+        which case the error is printed to standard output)
+    @rtype: C{dictionary}
+    @return: the data read from the ini file
+    
+    """
     try:
         r = open(f,'r')
         ll = r.readlines()

Modified: debtorrent/trunk/btcompletedir.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btcompletedir.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btcompletedir.py (original)
+++ debtorrent/trunk/btcompletedir.py Mon May 21 03:38:40 2007
@@ -1,10 +1,16 @@
 #!/usr/bin/env python
-
+#
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Make a metainfo (.dtorrent) file for every file in a directory.
+
+Creates a new metainfo file for every file in a given directory.
+
+"""
 
 from DebTorrent import PSYCO
 if PSYCO.psyco:
@@ -22,9 +28,24 @@
 from DebTorrent.parseargs import parseargs, formatDefinitions
 
 def prog(amount):
+    """Display the current status of the file scan.
+    
+    @type amount: C{int}
+    @param amount: the number of packages that have been found so far in the
+        current file
+    
+    """
+    
     print '%d packages found\r' % amount,
     
 def next_file(file):
+    """Print the name of the file being scanned.
+    
+    @type file: C{string}
+    @param file: the file name
+    
+    """
+    
     print "\nProcessing file: %s" % file
     
 if len(argv) < 3:

Modified: debtorrent/trunk/btcopyannounce.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btcopyannounce.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btcopyannounce.py (original)
+++ debtorrent/trunk/btcopyannounce.py Mon May 21 03:38:40 2007
@@ -1,11 +1,18 @@
 #!/usr/bin/env python
-
+#
 # btreannounce.py written by Henry 'Pi' James and Bram Cohen
 # multitracker extensions by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Copy the announce information from one metainfo file to others.
+
+Copies all the announce information from an input metainfo file, and 
+makes all the other metainfo files match it.
+
+"""
 
 from sys import argv,exit
 from os.path import split
@@ -13,6 +20,15 @@
 
 
 def give_announce_list(l):
+    """Converts an announce list into human-readable output.
+    
+    @type l: C{list}
+    @param l: the announce list to convert
+    @rtype: C{string}
+    @return: the human-readbale announce list
+    
+    """
+    
     list = []
     for tier in l:
         for tracker in tier:

Modified: debtorrent/trunk/btdownloadheadless.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btdownloadheadless.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btdownloadheadless.py (original)
+++ debtorrent/trunk/btdownloadheadless.py Mon May 21 03:38:40 2007
@@ -1,10 +1,17 @@
 #!/usr/bin/env python
-
+#
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
-
+#
 # $Id$
+
+"""A single downloader for debtorrent.
+
+This script implements a command-line client for managing a single 
+debtorrent download.
+
+"""
 
 from DebTorrent import PSYCO
 if PSYCO.psyco:
@@ -43,6 +50,18 @@
 PROFILER = False
 
 def hours(n):
+    """Formats seconds into a human-readable time.
+    
+    Formats a given number of seconds into a human-readable time appropriate
+    for display to the user.
+    
+    @type n: C{int}
+    @param n: the number of seconds
+    @rtype: C{string}
+    @return: a displayable representation of the number of seconds
+    
+    """
+    
     if n == 0:
         return 'complete!'
     try:
@@ -58,7 +77,41 @@
         return '%d min %02d sec' % (m, s)
 
 class HeadlessDisplayer:
+    """Displays on the command-line the status of the download.
+    
+    Implements a displayer for showing in text format the current status
+    of the download.
+    
+    @type done: C{boolean}
+    @ivar done: whether the download has completed or not
+    @type file: C{string}
+    @ivar file: the download file name to display
+    @type percentDone: C{string}
+    @ivar percentDone: the current percentage of the download that is complete
+    @type timeEst: C{string}
+    @ivar timeEst: the estimated time remaining
+    @type downloadTo: C{string}
+    @ivar downloadTo: the location of the download show to the user
+    @type downRate: C{string}
+    @ivar downRate: the last download rate shown to the user
+    @type upRate: C{string}
+    @ivar upRate: the last upload rate shown to the user
+    @type shareRating: C{string}
+    @ivar shareRating: the last sharing information shown to the user
+    @type seedStatus: C{string}
+    @ivar seedStatus: information on the current status of seeds seen
+    @type peerStatus: C{string}
+    @ivar peerStatus: information on the current status of peers seen
+    @type errors: C{list} of C{string}
+    @ivar errors: a list of all the errors that have occurred, in the order
+        in which they occurred
+    @type last_update_time: C{float}
+    @ivar last_update_time: the time in seconds of the last update
+    
+    """
+    
     def __init__(self):
+        """Initialize the status of the download."""
         self.done = False
         self.file = ''
         self.percentDone = ''
@@ -73,6 +126,7 @@
         self.last_update_time = -1
 
     def finished(self):
+        """Concludes the download successfully."""
         self.done = True
         self.percentDone = '100'
         self.timeEst = 'Download Succeeded!'
@@ -80,6 +134,7 @@
         self.display()
 
     def failed(self):
+        """Ends the download when an error has occurred."""
         self.done = True
         self.percentDone = '0'
         self.timeEst = 'Download Failed!'
@@ -87,12 +142,34 @@
         self.display()
 
     def error(self, errormsg):
+        """Displays an error to the user."""
         self.errors.append(errormsg)
         self.display()
 
     def display(self, dpflag = Event(), fractionDone = None, timeEst = None, 
             downRate = None, upRate = None, activity = None,
             statistics = None,  **kws):
+        """Displays the current status of the download.
+        
+        Writes a status update to standard output.
+        
+        @type dpflag: a threading event
+        @param dpflag: unknown
+        @type fractionDone: C{float}
+        @param fractionDone: the amount of the download that is complete [0-1]
+        @type timeEst: C{int}
+        @param timeEst: the number of seconds remaining to complete the download
+        @type downRate: C{int} or C{float}
+        @param downRate: the current download rate in bytes per second
+        @type upRate: C{int} or C{float}
+        @param upRate: the current upload rate in bytes per second
+        @type activity: C{string}
+        @param activity: the currently occurring activity (overwrites the timeEst)
+        @type statistics: L{DebTorrent.BT1.Statistics.Statistics}
+        @param statistics: various statistics of the current download
+        
+        """
+        
         if self.last_update_time + 0.1 > clock() and fractionDone not in (0.0, 1.0) and activity is not None:
             return
         self.last_update_time = clock()        
@@ -132,6 +209,25 @@
         dpflag.set()        
 
     def chooseFile(self, default, size, saveas, dir):
+        """Sets up the save directory name.
+        
+        Takes the default and user-provided save directory, saves them, and
+        returns the directory to be used for the download.
+        
+        @type default: C{string}
+        @param default: the default save location
+        @type size: C{int}
+        @param size: the size of the download in bytes
+        @type saveas: C{string}
+        @param saveas: the user-provided directory to save the download to,
+            or an empty string indicating the default should be used
+        @type dir: unknown
+        @param dir: unknown
+        @rtype: C{string}
+        @return: the directory to save the download to
+        
+        """
+        
         self.file = '%s (%.1f MB)' % (default, float(size) / (1 << 20))
         if saveas != '':
             default = saveas
@@ -139,9 +235,19 @@
         return default
 
     def newpath(self, path):
+        """Overwrite the previously saved download location."""
         self.downloadTo = path
 
 def run(params):
+    """Runs the downloader.
+    
+    The main function used to create the displayer and start the download.
+    
+    @type params: C{list} of C{strings}
+    @param params: a list of the command-line arguments given to the script
+    
+    """
+    
     h = HeadlessDisplayer()
     while 1:
         configdir = ConfigDir('downloadheadless')
@@ -168,6 +274,7 @@
         
         doneflag = Event()
         def disp_exception(text):
+            """Prints exceptions to standard output."""
             print text
         rawserver = RawServer(doneflag, config['timeout_check_interval'],
                               config['timeout'], ipv6_enable = config['ipv6_enabled'],

Modified: debtorrent/trunk/btlaunchmany.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btlaunchmany.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btlaunchmany.py (original)
+++ debtorrent/trunk/btlaunchmany.py Mon May 21 03:38:40 2007
@@ -1,10 +1,17 @@
 #!/usr/bin/env python
-
+#
 # Written by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""A multiple downloader for debtorrent.
+
+This script implements a command-line client for managing multiple 
+debtorrent downloads.
+
+"""
 
 from DebTorrent import PSYCO
 if PSYCO.psyco:
@@ -32,6 +39,18 @@
     False = 0
 
 def hours(n):
+    """Formats seconds into a human-readable time.
+    
+    Formats a given number of seconds into a human-readable time appropriate
+    for display to the user.
+    
+    @type n: C{int}
+    @param n: the number of seconds
+    @rtype: C{string}
+    @return: a displayable representation of the number of seconds
+    
+    """
+    
     if n == 0:
         return 'complete!'
     try:
@@ -48,9 +67,28 @@
 
 
 Exceptions = []
+"""The exceptions that have occurred."""
 
 class HeadlessDisplayer:
+    """Displays on the command-line the status of the downloads.
+    
+    Implements a displayer for showing in text format the current status
+    of the downloads.
+
+    """
+    
     def display(self, data):
+        """Displays the current status of the downloads.
+        
+        Writes a status update to standard output.
+        
+        @type data: C{list} of C{tuple}
+        @param data: a tuple per download, containing the current status of the download
+        @rtype: C{boolean}
+        @return: False
+        
+        """
+
         print ''
         if not data:
             self.message('no torrents')
@@ -63,9 +101,23 @@
         return False
             
     def message(self, s):
+        """Prints a message to standard output.
+        
+        @type s: C{string}
+        @param s: the message to print to standard output
+        
+        """
+        
         print "### "+s
 
     def exception(self, s):
+        """Saves a new exception and alerts the user.
+        
+        @type s: C{string}
+        @param s: the exception that occurred
+        
+        """
+        
         Exceptions.append(s)
         self.message('SYSTEM ERROR - EXCEPTION GENERATED')
 

Modified: debtorrent/trunk/btmakemetafile.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btmakemetafile.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btmakemetafile.py (original)
+++ debtorrent/trunk/btmakemetafile.py Mon May 21 03:38:40 2007
@@ -1,11 +1,18 @@
 #!/usr/bin/env python
-
+#
 # Written by Bram Cohen
 # multitracker extensions by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Creates a metainfo file from a Packages file.
+
+Converts a Packages file into a metainfo file containing all the information
+needed to download all the packages in the Packages file.
+
+"""
 
 from DebTorrent import PSYCO
 if PSYCO.psyco:
@@ -24,6 +31,14 @@
 
 
 def prog(amount):
+    """Display the current status of the file scan.
+    
+    @type amount: C{int}
+    @param amount: the number of packages that have been found so far in the
+        file
+    
+    """
+    
     print '%d packages found\r' % amount,
 
 if len(argv) < 3:

Modified: debtorrent/trunk/btreannounce.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btreannounce.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btreannounce.py (original)
+++ debtorrent/trunk/btreannounce.py Mon May 21 03:38:40 2007
@@ -1,11 +1,13 @@
 #!/usr/bin/env python
-
+#
 # Written by Henry 'Pi' James and Bram Cohen
 # multitracker extensions by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Change the announce info in a metainfo file."""
 
 from sys import argv,exit
 from os.path import split

Modified: debtorrent/trunk/btrename.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btrename.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btrename.py (original)
+++ debtorrent/trunk/btrename.py Mon May 21 03:38:40 2007
@@ -1,10 +1,17 @@
 #!/usr/bin/env python
-
+#
 # Written by Henry 'Pi' James
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Change the name field in a metainfo file.
+
+Rename the directory that will be created (suggested) when the metainfo file's
+download is started.
+
+"""
 
 from sys import *
 from os.path import *

Modified: debtorrent/trunk/btsethttpseeds.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btsethttpseeds.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btsethttpseeds.py (original)
+++ debtorrent/trunk/btsethttpseeds.py Mon May 21 03:38:40 2007
@@ -1,11 +1,13 @@
 #!/usr/bin/env python
-
+#
 # Written by Henry 'Pi' James and Bram Cohen
 # multitracker extensions by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Change the http-seeds info in the metainfo file."""
 
 from sys import argv,exit
 from os.path import split

Modified: debtorrent/trunk/btshowmetainfo.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/btshowmetainfo.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/btshowmetainfo.py (original)
+++ debtorrent/trunk/btshowmetainfo.py Mon May 21 03:38:40 2007
@@ -1,11 +1,13 @@
 #!/usr/bin/env python
-
+#
 # Written by Henry 'Pi' James and Loring Holden
 # modified for multitracker display by John Hoffman
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Display a summary of the information in a metainfo file."""
 
 from sys import *
 from os.path import *

Modified: debtorrent/trunk/bttrack.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/bttrack.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/bttrack.py (original)
+++ debtorrent/trunk/bttrack.py Mon May 21 03:38:40 2007
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
-
+#
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""Start a debtorrent download tracker."""
 
 from DebTorrent import PSYCO
 if PSYCO.psyco:

Modified: debtorrent/trunk/setup.py
URL: http://svn.debian.org/wsvn/debtorrent/debtorrent/trunk/setup.py?rev=57&op=diff
==============================================================================
--- debtorrent/trunk/setup.py (original)
+++ debtorrent/trunk/setup.py Mon May 21 03:38:40 2007
@@ -1,10 +1,18 @@
 #!/usr/bin/env python
-
+#
 # Written by Bram Cohen
 # Modified by Cameron Dale
 # see LICENSE.txt for license information
+#
+# $Id$
 
-# $Id$
+"""The DebTorrent program for downloading debian packages.
+
+This program contains several scripts and packages to implement the debtorrent
+protocol for downloading debian packages from an archive is a bittorrent-like
+way.
+
+"""
 
 import sys
 assert sys.version >= '2', "Install Python 2.0 or greater"
@@ -21,11 +29,9 @@
     
     packages = ["DebTorrent","DebTorrent.BT1"],
 
-    scripts = ["btdownloadgui.py", "btdownloadheadless.py", 
+    scripts = ["btdownloadheadless.py", 
         "bttrack.py", "btmakemetafile.py", "btlaunchmany.py", "btcompletedir.py",
-        "btdownloadcurses.py", "btcompletedirgui.py", "btlaunchmanycurses.py", 
-        "btmakemetafile.py", "btreannounce.py", "btrename.py", "btshowmetainfo.py",
-        'btmaketorrentgui.py', 'btcopyannounce.py', 'btsethttpseeds.py',
-        'bt-t-make.py',
+        "btreannounce.py", "btrename.py", "btshowmetainfo.py",
+        'btcopyannounce.py', 'btsethttpseeds.py',
         ]
     )




More information about the Debtorrent-commits mailing list