Do not use property decorators as 2.5 does not support .setter et al

This commit is contained in:
Andrew Resch 2009-08-12 21:18:39 +00:00
parent f562e8aff3
commit 74ed19b5f2

View File

@ -52,19 +52,19 @@ class InvalidPieceSize(Exception):
16KiB. 16KiB.
""" """
pass pass
class TorrentMetadata(object): class TorrentMetadata(object):
""" """
This class is used to create .torrent files. This class is used to create .torrent files.
*** Usage *** *** Usage ***
>>> t = TorrentMetadata() >>> t = TorrentMetadata()
>>> t.data_path = "/tmp/torrent" >>> t.data_path = "/tmp/torrent"
>>> t.comment = "My Test Torrent" >>> t.comment = "My Test Torrent"
>>> t.trackers = [["http://tracker.openbittorent.com"]] >>> t.trackers = [["http://tracker.openbittorent.com"]]
>>> t.save("/tmp/test.torrent") >>> t.save("/tmp/test.torrent")
""" """
def __init__(self): def __init__(self):
self.__data_path = None self.__data_path = None
@ -78,15 +78,15 @@ class TorrentMetadata(object):
def save(self, torrent_path, progress=None): def save(self, torrent_path, progress=None):
""" """
Creates and saves the torrent file to `path`. Creates and saves the torrent file to `path`.
:param torrent_path: where to save the torrent file :param torrent_path: where to save the torrent file
:type torrent_path: string :type torrent_path: string
:param progress: a function to be called when a piece is hashed :param progress: a function to be called when a piece is hashed
:type progress: function(num_completed, num_pieces) :type progress: function(num_completed, num_pieces)
:raises InvalidPath: if the data_path has not been set :raises InvalidPath: if the data_path has not been set
""" """
if not self.data_path: if not self.data_path:
raise InvalidPath("Need to set a data_path!") raise InvalidPath("Need to set a data_path!")
@ -94,19 +94,19 @@ class TorrentMetadata(object):
torrent = { torrent = {
"info": {} "info": {}
} }
if self.comment: if self.comment:
torrent["comment"] = self.comment.encode("UTF-8") torrent["comment"] = self.comment.encode("UTF-8")
if self.private: if self.private:
torrent["info"]["private"] = True torrent["info"]["private"] = True
if self.trackers: if self.trackers:
torrent["announce"] = self.trackers[0][0] torrent["announce"] = self.trackers[0][0]
torrent["announce-list"] = self.trackers torrent["announce-list"] = self.trackers
else: else:
torrent["announce"] = "" torrent["announce"] = ""
if self.webseeds: if self.webseeds:
httpseeds = [] httpseeds = []
webseeds = [] webseeds = []
@ -120,7 +120,7 @@ class TorrentMetadata(object):
torrent["httpseeds"] = httpseeds torrent["httpseeds"] = httpseeds
if webseeds: if webseeds:
torrent["url-list"] = webseeds torrent["url-list"] = webseeds
datasize = get_path_size(self.data_path) datasize = get_path_size(self.data_path)
if not self.piece_size: if not self.piece_size:
@ -128,13 +128,13 @@ class TorrentMetadata(object):
psize = 16384 psize = 16384
while (datasize / psize) > 1024: while (datasize / psize) > 1024:
psize *= 2 psize *= 2
self.piece_size = psize self.piece_size = psize
# Calculate the number of pieces we will require for the data # Calculate the number of pieces we will require for the data
num_pieces = datasize / self.piece_size num_pieces = datasize / self.piece_size
torrent["info"]["piece length"] = self.piece_size torrent["info"]["piece length"] = self.piece_size
# Create the info # Create the info
if os.path.isdir(self.data_path): if os.path.isdir(self.data_path):
torrent["info"]["name"] = os.path.split(self.data_path)[1] torrent["info"]["name"] = os.path.split(self.data_path)[1]
@ -159,7 +159,7 @@ class TorrentMetadata(object):
p[-1] = "_____padding_file_" + str(padding_count) p[-1] = "_____padding_file_" + str(padding_count)
files.append((self.piece_size - left, p)) files.append((self.piece_size - left, p))
padding_count += 1 padding_count += 1
# Run the progress function with 0 completed pieces # Run the progress function with 0 completed pieces
if progress: if progress:
@ -198,7 +198,7 @@ class TorrentMetadata(object):
if progress: if progress:
progress(len(pieces), num_pieces) progress(len(pieces), num_pieces)
buf = "" buf = ""
torrent["info"]["pieces"] = "".join(pieces) torrent["info"]["pieces"] = "".join(pieces)
torrent["info"]["files"] = fs torrent["info"]["files"] = fs
@ -206,8 +206,8 @@ class TorrentMetadata(object):
torrent["info"]["name"] = os.path.split(self.data_path)[1] torrent["info"]["name"] = os.path.split(self.data_path)[1]
torrent["info"]["length"] = get_path_size(self.data_path) torrent["info"]["length"] = get_path_size(self.data_path)
pieces = [] pieces = []
fd = open(self.data_path, "rb") fd = open(self.data_path, "rb")
r = fd.read(self.piece_size) r = fd.read(self.piece_size)
while r: while r:
pieces.append(sha(r).digest()) pieces.append(sha(r).digest())
@ -215,144 +215,137 @@ class TorrentMetadata(object):
progress(len(pieces), num_pieces) progress(len(pieces), num_pieces)
r = fd.read(self.piece_size) r = fd.read(self.piece_size)
torrent["info"]["pieces"] = "".join(pieces) torrent["info"]["pieces"] = "".join(pieces)
# Write out the torrent file # Write out the torrent file
open(torrent_path, "wb").write(bencode(torrent)) open(torrent_path, "wb").write(bencode(torrent))
@property def get_data_path(self):
def data_path(self):
""" """
The path to the files that the torrent will contain. It can be either The path to the files that the torrent will contain. It can be either
a file or a folder. This property needs to be set before the torrent a file or a folder. This property needs to be set before the torrent
file can be created and saved. file can be created and saved.
""" """
return self.__data_path return self.__data_path
@data_path.setter def set_data_path(self, path):
def data_path(self, path):
""" """
:param path: the path to the data :param path: the path to the data
:type path: string :type path: string
:raises InvalidPath: if the path is not found :raises InvalidPath: if the path is not found
""" """
if os.path.exists(path) and (os.path.isdir(path) or os.path.isfile(path)): if os.path.exists(path) and (os.path.isdir(path) or os.path.isfile(path)):
self.__data_path = path self.__data_path = path
else: else:
raise InvalidPath("No such file or directory: %s" % path) raise InvalidPath("No such file or directory: %s" % path)
@property def get_piece_size(self):
def piece_size(self):
""" """
The size of pieces in bytes. The size must be a multiple of 16KiB. The size of pieces in bytes. The size must be a multiple of 16KiB.
If you don't set a piece size, one will be automatically selected to If you don't set a piece size, one will be automatically selected to
produce a torrent with less than 1024 pieces. produce a torrent with less than 1024 pieces.
""" """
return self.__piece_size return self.__piece_size
@piece_size.setter def set_piece_size(self, size):
def piece_size(self, size):
""" """
:param size: the desired piece size in bytes :param size: the desired piece size in bytes
:raises InvalidPieceSize: if the piece size is not a multiple of 16KiB :raises InvalidPieceSize: if the piece size is not a multiple of 16KiB
""" """
if size % 16384 and size: if size % 16384 and size:
raise InvalidPieceSize("Piece size must be a multiple of 16384") raise InvalidPieceSize("Piece size must be a multiple of 16384")
self.__piece_size = size self.__piece_size = size
@property def get_comment(self):
def comment(self):
""" """
Comment is some extra info to be stored in the torrent. This is Comment is some extra info to be stored in the torrent. This is
typically an informational string. typically an informational string.
""" """
return self.__comment return self.__comment
@comment.setter def set_comment(self, comment):
def comment(self, comment):
""" """
:param comment: an informational string :param comment: an informational string
:type comment: string :type comment: string
""" """
self.__comment = comment self.__comment = comment
@property def get_private(self):
def private(self):
""" """
Private torrents only announce to the tracker and will not use DHT or Private torrents only announce to the tracker and will not use DHT or
Peer Exchange. Peer Exchange.
See: http://bittorrent.org/beps/bep_0027.html See: http://bittorrent.org/beps/bep_0027.html
""" """
return self.__private return self.__private
@private.setter def set_private(self, private):
def private(self, private):
""" """
:param private: True if the torrent is to be private :param private: True if the torrent is to be private
:type private: bool :type private: bool
""" """
self.__private = private self.__private = private
@property def get_trackers(self):
def trackers(self):
""" """
The announce trackers is a list of lists. The announce trackers is a list of lists.
See: http://bittorrent.org/beps/bep_0012.html See: http://bittorrent.org/beps/bep_0012.html
""" """
return self.__trackers return self.__trackers
@trackers.setter def set_trackers(self, trackers):
def trackers(self, trackers):
""" """
:param trackers: a list of lists of trackers, each list is a tier :param trackers: a list of lists of trackers, each list is a tier
:type trackers: list of list of strings :type trackers: list of list of strings
""" """
self.__trackers = trackers self.__trackers = trackers
@property def get_webseeds(self):
def webseeds(self):
""" """
The web seeds can either be: The web seeds can either be:
Hoffman-style: http://bittorrent.org/beps/bep_0017.html Hoffman-style: http://bittorrent.org/beps/bep_0017.html
or, or,
GetRight-style: http://bittorrent.org/beps/bep_0019.html GetRight-style: http://bittorrent.org/beps/bep_0019.html
If the url ends in '.php' then it will be considered Hoffman-style, if If the url ends in '.php' then it will be considered Hoffman-style, if
not it will be considered GetRight-style. not it will be considered GetRight-style.
""" """
return self.__web_seeds return self.__web_seeds
@webseeds.setter def set_webseeds(self, webseeds):
def webseeds(self, webseeds):
""" """
:param webseeds: the webseeds which can be either Hoffman or GetRight style :param webseeds: the webseeds which can be either Hoffman or GetRight style
:type webseeds: list of urls :type webseeds: list of urls
""" """
self.__webseeds = webseeds self.__webseeds = webseeds
@property def get_pad_files(self):
def pad_files(self):
""" """
If this is True, padding files will be added to align files on piece If this is True, padding files will be added to align files on piece
boundaries. boundaries.
""" """
return self.__pad_files return self.__pad_files
@pad_files.setter def set_pad_files(self, pad):
def pad_files(self, pad):
""" """
:param pad: set True to align files on piece boundaries :param pad: set True to align files on piece boundaries
:type pad: bool :type pad: bool
""" """
self.__pad_files = pad self.__pad_files = pad
data_path = property(get_data_path, set_data_path)
piece_size = property(get_piece_size, set_piece_size)
comment = property(get_comment, set_comment)
private = property(get_private, set_private)
trackers = property(get_trackers, set_trackers)
webseeds = property(get_webseeds, set_webseeds)
pad_files = property(get_pad_files, set_pad_files)