Fix python client (#1512)

extend python test to include examples. add piece index and block index python bindings
This commit is contained in:
Falcosc 2017-01-24 14:50:36 +01:00 committed by Arvid Norberg
parent 4ddd4b72c6
commit 32e0028e32
8 changed files with 151 additions and 44 deletions

View File

@ -218,15 +218,12 @@ def main():
if options.max_download_rate <= 0:
options.max_download_rate = -1
settings = lt.session_settings()
settings.user_agent = 'python_client/' + lt.version
ses = lt.session()
ses.set_download_rate_limit(int(options.max_download_rate))
ses.set_upload_rate_limit(int(options.max_upload_rate))
ses.listen_on(options.port, options.port + 10)
ses.set_settings(settings)
ses.set_alert_mask(0xfffffff)
ses = lt.session({'user_agent': 'python_client/' + lt.__version__,
'listen_interfaces':'0.0.0.0:' + str(options.port),
'download_rate_limit': int(options.max_download_rate),
'upload_rate_limit': int(options.max_upload_rate),
'alert_mask' : 0xfffffff
})
if options.proxy_host != '':
ps = lt.proxy_settings()
@ -281,14 +278,13 @@ def main():
out = ''
for h in handles:
if h.has_metadata():
name = h.get_torrent_info().name()[:40]
s = h.status()
if s.has_metadata:
name = h.torrent_file().name()[:40]
else:
name = '-'
out += 'name: %-40s\n' % name
s = h.status()
if s.state != lt.torrent_status.seeding:
state_str = ['queued', 'checking', 'downloading metadata',
'downloading', 'finished', 'seeding',
@ -335,14 +331,7 @@ def main():
write_line(console, '(q)uit), (p)ause), (u)npause), (r)eannounce\n')
write_line(console, 76 * '-' + '\n')
while 1:
a = ses.pop_alert()
if not a:
break
alerts.append(a)
if len(alerts) > 8:
del alerts[:len(alerts) - 8]
alerts = ses.pop_alerts()
for a in alerts:
if type(a) == str:
@ -369,7 +358,7 @@ def main():
ses.pause()
for h in handles:
if not h.is_valid() or not h.has_metadata():
if not h.is_valid() or not s.has_metadata:
continue
data = lt.bencode(h.write_resume_data())
open(os.path.join(options.save_path, h.get_torrent_info().name() +

View File

@ -20,6 +20,11 @@ fs = libtorrent.file_storage()
parent_input = os.path.split(input)[0]
# if we have a single file, use it because os.walk does not work on a single files
if os.path.isfile(input):
size = os.path.getsize(input)
fs.add_file(input, size)
for root, dirs, files in os.walk(input):
# skip directories starting with .
if os.path.split(root)[1][0] == '.':
@ -48,8 +53,8 @@ t = libtorrent.create_torrent(fs, 0, 4 * 1024 * 1024)
t.add_tracker(sys.argv[2])
t.set_creator('libtorrent %s' % libtorrent.__version__)
libtorrent.set_piece_hashes(t, parent_input, lambda x: sys.stderr.write('.'))
sys.stderr.write('\n')
libtorrent.set_piece_hashes(t, parent_input, lambda x: sys.stdout.write('.'))
sys.stdout.write('\n')
f = open('out.torrent', 'wb+')
f.write(libtorrent.bencode(t.generate()))

View File

@ -8,14 +8,14 @@ import libtorrent as lt
import time
import sys
ses = lt.session()
ses.listen_on(6881, 6891)
ses = lt.session({'listen_interfaces':'0.0.0.0:6881'})
info = lt.torrent_info(sys.argv[1])
h = ses.add_torrent({'ti': info, 'save_path': '.'})
print('starting', h.name())
s = h.status()
print('starting', s.name)
while (not h.is_seed()):
while (not s.is_seeding):
s = h.status()
state_str = [

View File

@ -356,7 +356,7 @@ void bind_alert()
class_<hash_failed_alert, bases<torrent_alert>, noncopyable>(
"hash_failed_alert", no_init)
.def_readonly("piece_index", &hash_failed_alert::piece_index)
.add_property("piece_index", make_getter(&hash_failed_alert::piece_index, by_value()))
;
class_<peer_ban_alert, bases<peer_alert>, noncopyable>(
@ -389,13 +389,13 @@ void bind_alert()
class_<piece_finished_alert, bases<torrent_alert>, noncopyable>(
"piece_finished_alert", no_init)
.def_readonly("piece_index", &piece_finished_alert::piece_index)
.add_property("piece_index", make_getter(&piece_finished_alert::piece_index, by_value()))
;
class_<block_finished_alert, bases<peer_alert>, noncopyable>(
"block_finished_alert", no_init)
.def_readonly("block_index", &block_finished_alert::block_index)
.def_readonly("piece_index", &block_finished_alert::piece_index)
.add_property("block_index", make_getter(&block_finished_alert::block_index, by_value()))
.add_property("piece_index", make_getter(&block_finished_alert::piece_index, by_value()))
;
class_<block_downloading_alert, bases<peer_alert>, noncopyable>(
@ -403,8 +403,8 @@ void bind_alert()
#ifndef TORRENT_NO_DEPRECATE
.def_readonly("peer_speedmsg", &block_downloading_alert::peer_speedmsg)
#endif
.def_readonly("block_index", &block_downloading_alert::block_index)
.def_readonly("piece_index", &block_downloading_alert::piece_index)
.add_property("block_index", make_getter(&block_downloading_alert::block_index, by_value()))
.add_property("piece_index", make_getter(&block_downloading_alert::piece_index, by_value()))
;
class_<storage_moved_alert, bases<torrent_alert>, noncopyable>(
@ -693,20 +693,20 @@ void bind_alert()
class_<request_dropped_alert, bases<peer_alert>, noncopyable>(
"request_dropped_alert", no_init)
.def_readonly("block_index", &request_dropped_alert::block_index)
.def_readonly("piece_index", &request_dropped_alert::piece_index)
.add_property("block_index", make_getter(&request_dropped_alert::block_index, by_value()))
.add_property("piece_index", make_getter(&request_dropped_alert::piece_index, by_value()))
;
class_<block_timeout_alert, bases<peer_alert>, noncopyable>(
"block_timeout_alert", no_init)
.def_readonly("block_index", &block_timeout_alert::block_index)
.def_readonly("piece_index", &block_timeout_alert::piece_index)
.add_property("block_index", make_getter(&block_timeout_alert::block_index, by_value()))
.add_property("piece_index", make_getter(&block_timeout_alert::piece_index, by_value()))
;
class_<unwanted_block_alert, bases<peer_alert>, noncopyable>(
"unwanted_block_alert", no_init)
.def_readonly("block_index", &unwanted_block_alert::block_index)
.def_readonly("piece_index", &unwanted_block_alert::piece_index)
.add_property("block_index", make_getter(&unwanted_block_alert::block_index, by_value()))
.add_property("piece_index", make_getter(&unwanted_block_alert::piece_index, by_value()))
;
class_<torrent_delete_failed_alert, bases<torrent_alert>, noncopyable>(

View File

@ -47,6 +47,7 @@ list get_pieces(peer_info const& pi)
return ret;
}
using by_value = return_value_policy<return_by_value>;
void bind_peer_info()
{
scope pi = class_<peer_info>("peer_info")
@ -82,8 +83,8 @@ void bind_peer_info()
.def_readonly("download_queue_length", &peer_info::download_queue_length)
.def_readonly("upload_queue_length", &peer_info::upload_queue_length)
.def_readonly("failcount", &peer_info::failcount)
.def_readonly("downloading_piece_index", &peer_info::downloading_piece_index)
.def_readonly("downloading_block_index", &peer_info::downloading_block_index)
.add_property("downloading_piece_index", make_getter(&peer_info::downloading_piece_index, by_value()))
.add_property("downloading_block_index", make_getter(&peer_info::downloading_block_index, by_value()))
.def_readonly("downloading_progress", &peer_info::downloading_progress)
.def_readonly("downloading_total", &peer_info::downloading_total)
.def_readonly("client", &peer_info::client)

View File

@ -341,6 +341,7 @@ void add_piece(torrent_handle& th, piece_index_t piece, char const *data, int fl
th.add_piece(piece, data, flags);
}
using by_value = return_value_policy<return_by_value>;
void bind_torrent_handle()
{
// arguments are: number of seconds and tracker index
@ -473,7 +474,7 @@ void bind_torrent_handle()
;
class_<pool_file_status>("pool_file_status")
.def_readonly("file_index", &pool_file_status::file_index)
.add_property("file_index", make_getter((&pool_file_status::file_index), by_value()))
.def_readonly("last_use", &pool_file_status::last_use)
.def_readonly("open_mode", &pool_file_status::open_mode)
;

View File

@ -208,6 +208,7 @@ std::shared_ptr<torrent_info> bencoded_constructor1(entry const& ent)
return bencoded_constructor0(ent, 0);
}
using by_value = return_value_policy<return_by_value>;
void bind_torrent_info()
{
return_value_policy<copy_const_reference> copy;
@ -218,7 +219,7 @@ void bind_torrent_info()
#endif
class_<file_slice>("file_slice")
.def_readwrite("file_index", &file_slice::file_index)
.add_property("file_index", make_getter((&file_slice::file_index), by_value()))
.def_readwrite("offset", &file_slice::offset)
.def_readwrite("size", &file_slice::size)
;

View File

@ -8,6 +8,13 @@ import time
import os
import shutil
import binascii
import subprocess as sub
import sys
# include terminal interface for travis parallel executions of scripts which use
# terminal features: fix multiple stdin assignment at termios.tcgetattr
if os.name != 'nt':
import pty
class test_create_torrent(unittest.TestCase):
@ -263,6 +270,109 @@ class test_sha1hash(unittest.TestCase):
class test_session(unittest.TestCase):
def test_post_session_stats(self):
s = lt.session({'alert_mask': lt.alert.category_t.stats_notification, 'enable_dht': False})
s.post_session_stats()
a = s.wait_for_alert(1000)
self.assertTrue(isinstance(a, lt.session_stats_alert))
self.assertTrue(isinstance(a.values, dict))
self.assertTrue(len(a.values) > 0)
def test_add_torrent(self):
s = lt.session({'alert_mask': lt.alert.category_t.stats_notification, 'enable_dht': False})
h = s.add_torrent({'ti': lt.torrent_info('base.torrent'),
'save_path': '.',
'dht_nodes': [('1.2.3.4', 6881), ('4.3.2.1', 6881)],
'http_seeds': ['http://test.com/seed'],
'peers': [('5.6.7.8', 6881)],
'banned_peers': [('8.7.6.5', 6881)],
'file_priorities': [1,1,1,2,0]})
def test_unknown_settings(self):
try:
s = lt.session({'unexpected-key-name': 42})
self.assertFalse('should have thrown an exception')
except KeyError as e:
print(e)
def test_apply_settings(self):
s = lt.session({'enable_dht': False})
s.apply_settings({'num_want': 66, 'user_agent': 'test123'})
self.assertEqual(s.get_settings()['num_want'], 66)
self.assertEqual(s.get_settings()['user_agent'], 'test123')
class test_example_client(unittest.TestCase):
def test_execute_client(self):
if os.name == 'nt':
# TODO: fix windows includes of client.py
return
my_stdin = sys.stdin
if os.name != 'nt':
master_fd, slave_fd = pty.openpty()
# slave_fd fix multiple stdin assignment at termios.tcgetattr
my_stdin = slave_fd
process = sub.Popen(
[sys.executable,"client.py","url_seed_multi.torrent"],
stdin=my_stdin, stdout=sub.PIPE, stderr=sub.PIPE)
# python2 has no Popen.wait() timeout
time.sleep(5)
returncode = process.poll()
if returncode == None:
# this is an expected use-case
process.kill()
err = process.stderr.read().decode("utf-8")
self.assertEqual('', err, 'process throw errors: \n' + err)
# check error code if process did unexpected end
if returncode != None:
# in case of error return: output stdout if nothing was on stderr
if returncode != 0:
print("stdout:\n" + process.stdout.read().decode("utf-8"))
self.assertEqual(returncode, 0, "returncode: " + str(returncode) + "\n"
+ "stderr: empty\n"
+ "some configuration does not output errors like missing module members,"
+ "try to call it manually to get the error message\n")
def test_execute_simple_client(self):
process = sub.Popen(
[sys.executable,"simple_client.py","url_seed_multi.torrent"],
stdout=sub.PIPE, stderr=sub.PIPE)
# python2 has no Popen.wait() timeout
time.sleep(5)
returncode = process.poll()
if returncode == None:
# this is an expected use-case
process.kill()
err = process.stderr.read().decode("utf-8")
self.assertEqual('', err, 'process throw errors: \n' + err)
# check error code if process did unexpected end
if returncode != None:
# in case of error return: output stdout if nothing was on stderr
if returncode != 0:
print("stdout:\n" + process.stdout.read().decode("utf-8"))
self.assertEqual(returncode, 0, "returncode: " + str(returncode) + "\n"
+ "stderr: empty\n"
+ "some configuration does not output errors like missing module members,"
+ "try to call it manually to get the error message\n")
def test_execute_make_torrent(self):
process = sub.Popen(
[sys.executable,"make_torrent.py","url_seed_multi.torrent",
"http://test.com/test"], stdout=sub.PIPE, stderr=sub.PIPE)
returncode = process.wait()
# python2 has no Popen.wait() timeout
err = process.stderr.read().decode("utf-8")
self.assertEqual('', err, 'process throw errors: \n' + err)
# in case of error return: output stdout if nothing was on stderr
if returncode != 0:
print("stdout:\n" + process.stdout.read().decode("utf-8"))
self.assertEqual(returncode, 0, "returncode: " + str(returncode) + "\n"
+ "stderr: empty\n"
+ "some configuration does not output errors like missing module members,"
+ "try to call it manually to get the error message\n")
def test_post_session_stats(self):
s = lt.session({'alert_mask': lt.alert.category_t.stats_notification,
'enable_dht': False})