Skip to content

Commit

Permalink
Merge branch 'release/0.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
XayOn committed Sep 23, 2017
2 parents caf4633 + f37ac8e commit b73eea4
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 52 deletions.
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
David Francos <davidfrancos@sipay.es>
David Francos <me@davidfrancos.net>
David Francos Cuartero <dfrancos@buguroo.com>
Gonzalo Sarrablo <gsarrablo@gmail.com>
pyup-bot <github-bot@pyup.io>
sarrablo <gsarrablo@gmail.com>
25 changes: 25 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
CHANGES
=======

* Refactor, fixed almost all tests
* Readme accuracy
* Cleaner readme
* Readme updated with new usage
* Changed readme image and added shortener to bot
* Shortmag.net use
* Update inquirer from 2.1.11 to 2.2.0
* Fixed tests
* updated\_requirements
* Not removing parts of the magnet link
* Added url shortener
* Pin flake8\_docstrings to latest version 1.1.0
* Pin flake8 to latest version 3.4.1
* Pin pylint to latest version 1.7.2
* Pin pytest-cov to latest version 2.5.1
* Pin pytest-flake8 to latest version 0.8.1
* Pin pytest to latest version 3.2.1
* Pin torrentmirror to latest version 0.0.1.dev5
* Pin robobrowser to latest version 0.5.3
* Pin telepot to latest version 12.3
* Pin inquirer to latest version 2.1.11
* Pin tabulate to latest version 0.7.7
* Pin requests to latest version 2.18.4
* Pin docopt to latest version 0.6.2

0.3.0
-----

Expand Down
73 changes: 47 additions & 26 deletions katcr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import torrentmirror


class BaseSearch:
class BaseSearch(metaclass=abc.ABCMeta):
"""Base Search."""

def __init__(self):
Expand Down Expand Up @@ -75,7 +75,12 @@ def search(self, query: str, pagelen: int = 1):


class ThePirateBay(BaseSearch):
"""Katcr main class."""
"""ThePirateBay search engine.
Search on any of the pirate bay proxies or thepiratebay itself if
available. Extract torrents, description and return it tabulated and ready
to be printed
"""

proxy_name = 'The Pirate Bay'
url_format = '{}{}/search/{}/{}/99'
Expand All @@ -97,7 +102,12 @@ def get_torrents(self):


class Katcr(BaseSearch):
"""Katcr main class."""
"""KickAssTorrents search engine.
Search on any of the pirate bay proxies or thepiratebay itself if
available. Extract torrents, description and return it tabulated and ready
to be printed
"""

proxy_name = 'Kickass Torrents'
url_format = '{}{}/search.php?q={}&p={}'
Expand Down Expand Up @@ -125,52 +135,63 @@ def get_short(where, what):
where, requests.post(where, data={'magnet': what}).text)


def get_from_short(shortener, search_res):
"""Get new search res from shortened urls."""
for elem in search_res:
yield elem[:-1] + (get_short(shortener, elem[-1]),)


def main():
"""Search in multiple torrent sites.
Usage: katcr [options] <SEARCH_TERM>
Usage: katcr [options] [interactive options] <SEARCH_TERM>
Currently available search engines:
- Katcr
- ThePirateBay
Options:
--search=<SEARCH_TERM> Search term(s)
--pages=<PAGES_NUM> Number of pages to lookup
-i --interactive Enable interactive menu
-p --plugin=<Katcr|ThePirateBay> Download method [default: Katcr]
-e --enable-shortener Enable url shortener
-s --sortener=<SHORTENER_URL> Use given magnet shortener
-e --search-engine=<SearchEngine> Torrent search engine to use
[default: Any].
-p --pages=<PAGES_NUM> Number of pages to lookup
[default: 1]
-d --disable-shortener Disable url shortener
-s --sortener=<SHORTENER_URL> Use given magnet shortener to
prettify urls.
[default: http://www.shortmag.net]
-h --help Show this screen
Interactive Options:
-i --interactive Enable interactive mode
-o --open Launch with default torrent app
-d Debug mode.
in interactive mode [default: True]
-h --help Show this help screen
-d --debug Enable debug mode
"""
opt = docopt(main.__doc__, version="0.0.1")

if opt['-d']:
logging.basicConfig(level=logging.DEBUG)

search_res = list(globals()[opt['--plugin']]().search(
opt["<SEARCH_TERM>"], int(opt.get("--pages") or 1)))
opt["<SEARCH_TERM>"], int(opt.get("--pages"))))

if opt['--enable-shortener']:
def get_from_short(search_res):
"""Get new search res from shortened urls."""
for elem in search_res:
yield elem[:-1] + (get_short(opt['--sortener'], elem[-1]),)

search_res = list(get_from_short(search_res))
search_res = list(get_from_short(opt['--shortener'], search_res))

if not search_res:
return

lengths = [max(len(a[pos]) for a in search_res)
for pos in range(0, len(search_res[0]))]

if not opt['--interactive']:
lengths = [max(len(a[pos]) for a in search_res)
for pos in range(0, len(search_res[0]))]
return tableprint.table(search_res, ['Description', 'Size', 'Link'],
width=lengths)

results = {a[:Terminal().width - 4]: b for a, b in search_res}
result = results[prompt([List('Torrent', message="Choose",
choices=results.keys())])['Torrent']]
res = {a[:Terminal().width - 20]: b for a, b in search_res}
result = res[prompt([List('Link', message="",
choices=res.keys())])['Link']]

if opt['--open']:
return subprocess.check_call(['xdg-open', result])

print(result)
1 change: 1 addition & 0 deletions katcr/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def on_chat_message(self, msg):
keyboard = InlineKeyboardMarkup(inline_keyboard=list(
[InlineKeyboardButton(text=k, callback_data=str(r))]
for r, (k, _) in enumerate(res)))
print(keyboard)

self.responses[chat_id] = {r: (k, v) for r, (k, v) in enumerate(res)}
self.sendMessage(chat_id, "Results for: {}".format(msg['text']),
Expand Down
45 changes: 42 additions & 3 deletions tests/unit/test_katbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ def test_katbot_isinstance():
from telepot import Bot
from katcr.bot import KATBot
assert issubclass(KATBot, Bot)
assert isinstance(KATBot("foo"), Bot)
opts = {'--token': "foo", '--shortener': ''}
assert isinstance(KATBot(opts), Bot)


def test_katbot_main():
Expand All @@ -20,7 +21,7 @@ def test_katbot_main():
with patch('katcr.bot.KATBot') as bot:
with patch('katcr.bot.MessageLoop'):
main()
bot.assert_called_with('foo')
bot.assert_called_with({'--token': 'foo'})


def test_on_chat_message_start():
Expand All @@ -33,12 +34,48 @@ class FakeKATBot(KATBot):
def __init__(self, token):
"""Set token."""
self.token = token
self.shortener = "foo"

fkb = FakeKATBot("foo")
assert not fkb.on_chat_message({'text': '/start'})


def test_on_chat_message():
"""Test on chat message handler."""
from katcr.bot import KATBot
from unittest.mock import patch, MagicMock
from telepot.namedtuple import InlineKeyboardMarkup, InlineKeyboardButton

class FakeKATBot(KATBot):
"""Fake kat bot to avoid initializing telepot."""

def __init__(self, token):
"""Set token."""
self.token = token
self.katcr = MagicMock()
self.katcr.search.return_value = (('foo', 'bar'),)
self.shortener = "http://foo"
self.responses = {}
self.sendMessage = MagicMock()

with patch('katcr.bot.telepot.glance', return_value=((0, 0, 1))):
fkb = FakeKATBot("foo")
assert not fkb.on_chat_message({'text': 'debian'})
fkb.sendMessage.assert_called_with(
1, 'Results for: debian',
parse_mode='html',
reply_markup=InlineKeyboardMarkup(
inline_keyboard=[[
InlineKeyboardButton(
text='foo',
url=None, callback_data='0',
switch_inline_query=None,
switch_inline_query_current_chat=None,
callback_game=None, pay=None)]]))
assert fkb.responses


def test_on_chat_message_empty():
"""Test on chat message handler."""
from katcr.bot import KATBot
from unittest.mock import patch, MagicMock
Expand All @@ -51,6 +88,7 @@ def __init__(self, token):
"""Set token."""
self.token = token
self.katcr = MagicMock()
self.shortener = "http://foo"
self.responses = {}
self.sendMessage = MagicMock()

Expand All @@ -76,10 +114,11 @@ def __init__(self, token):
self.token = token
self.katcr = MagicMock()
self.responses = {1: {1: ['foo', 'foo']}}
self.shortener = "http://foo"
self.sendMessage = MagicMock()

with patch('katcr.bot.telepot.glance', return_value=((0, 1, 1))):
with patch('katcr.bot.requests'):
with patch('katcr.bot.get_short', return_value=(('foo'))):
fkb = FakeKATBot("foo")
assert not fkb.on_callback_query({'text': 'debian'})
assert fkb.sendMessage.called
Expand Down
64 changes: 41 additions & 23 deletions tests/unit/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,48 @@

def test_main():
"""Test argument parsing and calling."""
from katcr import main
from unittest.mock import patch
from katcr import main, get_from_short
from unittest.mock import patch, call
opts = {'<SEARCH_TERM>': "foo", '--plugin': 'Katcr',
'--interactive': False, '--open': False, '-d': False,
'--enable-shortener': False}
'--enable-shortener': False, '--pages': 1}
with patch('katcr.Katcr') as mock:
with patch('katcr.docopt', side_effect=(opts,)):
main()
mock().search.assert_called_with(opts['<SEARCH_TERM>'], 1)

opts = {'<SEARCH_TERM>': "foo", '--plugin': 'Katcr',
'--interactive': False, '--open': False, '-d': False,
'--shortener': 'bar',
'--enable-shortener': True, '--pages': 1}
with patch('katcr.Katcr') as mock:
with patch('katcr.get_from_short') as short_mock:
with patch('katcr.docopt', side_effect=(opts,)):
main()
mock().search.assert_called_with(opts['<SEARCH_TERM>'], 1)
short_mock.assert_called_with('bar', [])

class Foo:
text = "foo"

with patch('katcr.requests.post', return_value=Foo) as mock:
with patch('katcr.docopt', side_effect=(opts,)):
result = list(get_from_short(
"foo.com", [("1", "2"), ("3", "4")]))
assert [result == [('1', '2', 'foo.com/foo'),
('3', '4', 'foo.com/foo')]]
mock.assert_has_calls([call('foo.com', data={'magnet': '2'}),
call('foo.com', data={'magnet': '4'})])

opts = {'<SEARCH_TERM>': "foo", '--plugin': 'Katcr',
'--interactive': True, '--open': True, '-d': False,
'--enable-shortener': False}
torr = {'Torrent': 'foo'}
'--enable-shortener': False, '--pages': 1}
torr = {'Link': 'foo'}
args = opts['<SEARCH_TERM>'], 1

with patch('katcr.Katcr') as mock:
with patch('katcr.Terminal') as tmock:
tmock().width = 10
tmock().width = 50
mock().search.side_effect = ((('foo', 'bar'),),)
with patch('katcr.subprocess') as smock:
with patch('katcr.docopt', side_effect=(opts,)):
Expand All @@ -33,11 +56,11 @@ def test_main():

opts = {'<SEARCH_TERM>': "foo", '--plugin': 'Katcr',
'--interactive': True, '--open': False, '-d': False,
'--enable-shortener': False}
'--enable-shortener': False, '--pages': 1}

with patch('katcr.Katcr') as mock:
with patch('katcr.Terminal') as tmock:
tmock().width = 10
tmock().width = 50
mock().search.side_effect = ((('foo', 'bar'),),)
with patch('katcr.subprocess') as smock:
with patch('katcr.docopt', side_effect=(opts,)):
Expand All @@ -48,11 +71,11 @@ def test_main():

opts = {'<SEARCH_TERM>': "foo", '--plugin': 'Katcr',
'--interactive': True, '--open': False, '-d': True,
'--enable-shortener': False}
'--enable-shortener': False, '--pages': 1}

with patch('katcr.Katcr') as mock:
with patch('katcr.Terminal') as tmock:
tmock().width = 10
tmock().width = 50
mock().search.side_effect = ((('foo', 'bar'),),)
with patch('katcr.subprocess') as smock:
with patch('katcr.docopt', side_effect=(opts,)):
Expand All @@ -73,21 +96,16 @@ def test_basesearch():

with unittest.mock.patch('katcr.BaseSearch.search_magnets',
side_effect=(['foo'],)) as mock:
BaseSearch().search('foo', 2)
class FakeSearch(BaseSearch):
def get_torrents(self):
return "foo"
proxy_name = "The Pirate Bay"
url = "Foo"
url_format = None

FakeSearch().search('foo', 2)
assert mock.call_count == 2

proxies = {'The Pirate Bay': [['foo', None]]}
BaseSearch.proxy_name = "The Pirate Bay"
BaseSearch.url = "Foo"
BaseSearch.url_format = "None"

with unittest.mock.patch('katcr.torrentmirror.get_proxies',
side_effect=(proxies,)) as mock:
with unittest.mock.patch('katcr.BaseSearch.get_torrents',
side_effect=(['foo'],)) as mock:
with unittest.mock.patch('katcr.robobrowser.RoboBrowser'):
BaseSearch().search('foo', 2)


def test_cli_help():
"""Test help call."""
Expand Down

0 comments on commit b73eea4

Please sign in to comment.