Introduction
Introduction Statistics Contact Development Disclaimer Help
Replace deprecated optparse with argparse - toot - Unnamed repository; edit thi…
Log
Files
Refs
LICENSE
---
commit d7701bd2e6beb3a303d4133f685ac685080cf1dd
parent 86f4e1beacd49e803358d22927c00b7a4a1ffc2b
Author: Ivan Habunek <[email protected]>
Date: Sun, 16 Apr 2017 14:06:16 +0200
Replace deprecated optparse with argparse
Diffstat:
.gitignore | 5 +++--
Makefile | 5 ++++-
requirements-dev.txt | 8 ++++----
tests/test_console.py | 109 ++++++++++++++++++++++++-------
toot/console.py | 103 +++++++++++++++++--------------
5 files changed, 154 insertions(+), 76 deletions(-)
---
diff --git a/.gitignore b/.gitignore
@@ -5,4 +5,6 @@ build/
dist/
tmp/
.pypirc
-/.env
-\ No newline at end of file
+/.env
+/.coverage
+/htmlcov
diff --git a/Makefile b/Makefile
@@ -12,7 +12,10 @@ dist :
@echo "\nDone."
clean :
- rm -rf build dist *.egg-info MANIFEST
+ rm -rf build dist *.egg-info MANIFEST htmlcov
publish :
twine upload dist/*
+
+coverage:
+ py.test --cov=toot --cov-report html tests/
diff --git a/requirements-dev.txt b/requirements-dev.txt
@@ -1,3 +1,4 @@
-pytest>=3.0.0
-twine>=1.8.1
-wheel>=0.29.0
-\ No newline at end of file
+pytest-cov~=2.4.0
+pytest~=3.0.0
+twine~=1.8.1
+wheel~=0.29.0
diff --git a/tests/test_console.py b/tests/test_console.py
@@ -1,9 +1,9 @@
+# -*- coding: utf-8 -*-
import pytest
import requests
-import sys
from toot import User, App
-from toot.console import cmd_post_status, ConsoleError
+from toot.console import print_usage, cmd_post_status, cmd_timeline, cmd_upload
from tests.utils import MockResponse
@@ -11,12 +11,19 @@ app = App('https://habunek.com', 'foo', 'bar')
user = User('[email protected]', 'xxx')
-def test_post_status_defaults(monkeypatch):
+def test_print_usagecap(capsys):
+ print_usage()
+ out, err = capsys.readouterr()
+ assert "toot - interact with Mastodon from the command line" in out
+
+
+def test_post_status_defaults(monkeypatch, capsys):
def mock_prepare(request):
assert request.method == 'POST'
assert request.url == 'https://habunek.com/api/v1/statuses'
+ assert request.headers == {'Authorization': 'Bearer xxx'}
assert request.data == {
- 'status': '"Hello world"',
+ 'status': 'Hello world',
'visibility': 'public',
'media_ids[]': None,
}
@@ -29,14 +36,17 @@ def test_post_status_defaults(monkeypatch):
monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
monkeypatch.setattr(requests.Session, 'send', mock_send)
- sys.argv = ['toot', 'post', '"Hello world"']
- cmd_post_status(app, user)
+ cmd_post_status(app, user, ['Hello world'])
+
+ out, err = capsys.readouterr()
+ assert "Toot posted" in out
-def test_post_status_with_options(monkeypatch):
+def test_post_status_with_options(monkeypatch, capsys):
def mock_prepare(request):
assert request.method == 'POST'
assert request.url == 'https://habunek.com/api/v1/statuses'
+ assert request.headers == {'Authorization': 'Bearer xxx'}
assert request.data == {
'status': '"Hello world"',
'visibility': 'unlisted',
@@ -51,25 +61,80 @@ def test_post_status_with_options(monkeypatch):
monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
monkeypatch.setattr(requests.Session, 'send', mock_send)
- sys.argv = ['toot', 'post', '"Hello world"',
- '--visibility', 'unlisted']
+ args = ['"Hello world"', '--visibility', 'unlisted']
+
+ cmd_post_status(app, user, args)
+
+ out, err = capsys.readouterr()
+ assert "Toot posted" in out
+
+
+def test_post_status_invalid_visibility(monkeypatch, capsys):
+ args = ['Hello world', '--visibility', 'foo']
+
+ with pytest.raises(SystemExit):
+ cmd_post_status(app, user, args)
+
+ out, err = capsys.readouterr()
+ assert "invalid visibility value: 'foo'" in err
+
+
+def test_post_status_invalid_media(monkeypatch, capsys):
+ args = ['Hello world', '--media', 'does_not_exist.jpg']
+
+ with pytest.raises(SystemExit):
+ cmd_post_status(app, user, args)
- cmd_post_status(app, user)
+ out, err = capsys.readouterr()
+ assert "can't open 'does_not_exist.jpg'" in err
-def test_post_status_invalid_visibility(monkeypatch):
- sys.argv = ['toot', 'post', '"Hello world"',
- '--visibility', 'foo']
+def test_timeline(monkeypatch, capsys):
+ def mock_get(url, params, headers=None):
+ assert url == 'https://habunek.com/api/v1/timelines/home'
+ assert headers == {'Authorization': 'Bearer xxx'}
+ assert params is None
- with pytest.raises(ConsoleError) as ex:
- cmd_post_status(app, user)
- assert str(ex.value) == "Invalid visibility value given: 'foo'"
+ return MockResponse([{
+ 'account': {
+ 'display_name': 'Frank Zappa',
+ 'username': 'fz'
+ },
+ 'created_at': '2017-04-12T15:53:18.174Z',
+ 'content': "<p>The computer can't tell you the emotional story. It…
+ 'reblog': None,
+ }])
+ monkeypatch.setattr(requests, 'get', mock_get)
+
+ cmd_timeline(app, user, [])
+
+ out, err = capsys.readouterr()
+ assert "The computer can't tell you the emotional story." in out
+ assert "Frank Zappa @fz" in out
+
+
+def test_upload(monkeypatch, capsys):
+ def mock_prepare(request):
+ assert request.method == 'POST'
+ assert request.url == 'https://habunek.com/api/v1/media'
+ assert request.headers == {'Authorization': 'Bearer xxx'}
+ assert request.files.get('file') is not None
+
+ def mock_send(*args):
+ return MockResponse({
+ 'id': 123,
+ 'url': 'https://bigfish.software/123/456',
+ 'preview_url': 'https://bigfish.software/789/012',
+ 'text_url': 'https://bigfish.software/345/678',
+ 'type': 'image',
+ })
+
+ monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
+ monkeypatch.setattr(requests.Session, 'send', mock_send)
-def test_post_status_invalid_media(monkeypatch):
- sys.argv = ['toot', 'post', '"Hello world"',
- '--media', 'does_not_exist.jpg']
+ cmd_upload(app, user, [__file__])
- with pytest.raises(ConsoleError) as ex:
- cmd_post_status(app, user)
- assert str(ex.value) == "File does not exist: does_not_exist.jpg"
+ out, err = capsys.readouterr()
+ assert "Uploading media" in out
+ assert __file__ in out
diff --git a/toot/console.py b/toot/console.py
@@ -12,7 +12,7 @@ from datetime import datetime
from future.moves.itertools import zip_longest
from getpass import getpass
from itertools import chain
-from optparse import OptionParser
+from argparse import ArgumentParser, FileType
from textwrap import TextWrapper
from .config import save_user, load_user, load_app, save_app, CONFIG_APP_FILE,…
@@ -131,7 +131,13 @@ def parse_timeline(item):
}
-def cmd_timeline(app, user):
+def cmd_timeline(app, user, args):
+ parser = ArgumentParser(prog="toot timeline",
+ description="Show recent items in your public time…
+ epilog="https://github.com/ihabunek/toot")
+
+ args = parser.parse_args(args)
+
items = timeline_home(app, user)
parsed_items = [parse_timeline(t) for t in items]
@@ -141,39 +147,41 @@ def cmd_timeline(app, user):
print("─" * 31 + "┼" + "─" * 88)
-def cmd_post_status(app, user):
- parser = OptionParser(usage="toot post [options] TEXT")
+def visibility(value):
+ if value not in ['public', 'unlisted', 'private', 'direct']:
+ raise ValueError("Invalid visibility value")
- parser.add_option("-m", "--media", dest="media", type="string",
- help="path to the media file to attach")
+ return value
- parser.add_option("-v", "--visibility", dest="visibility", type="string", …
- help='post visibility, either "public" (default), "direc…
- (options, args) = parser.parse_args()
+def cmd_post_status(app, user, args):
+ parser = ArgumentParser(prog="toot post",
+ description="Post a status text to the timeline",
+ epilog="https://github.com/ihabunek/toot")
+ parser.add_argument("text", help="The status text to post.")
+ parser.add_argument("-m", "--media", type=FileType('rb'),
+ help="path to the media file to attach")
+ parser.add_argument("-v", "--visibility", type=visibility, default="public…
+ help='post visibility, either "public" (default), "dir…
- if len(args) < 2:
- parser.print_help()
- raise ConsoleError("No text given")
+ args = parser.parse_args(args)
- if options.visibility not in ['public', 'unlisted', 'private', 'direct']:
- raise ConsoleError("Invalid visibility value given: '{}'".format(optio…
-
- if options.media:
- media = do_upload(app, user, options.media)
+ if args.media:
+ media = do_upload(app, user, args.media)
media_ids = [media['id']]
else:
media_ids = None
- response = post_status(
- app, user, args[1], media_ids=media_ids, visibility=options.visibility)
+ response = post_status(app, user, args.text, media_ids=media_ids, visibili…
print("Toot posted: " + green(response.get('url')))
-def cmd_auth(app, user):
- parser = OptionParser(usage='%prog auth')
- parser.parse_args()
+def cmd_auth(app, user, args):
+ parser = ArgumentParser(prog="toot auth",
+ description="Show login details",
+ epilog="https://github.com/ihabunek/toot")
+ parser.parse_args(args)
if app and user:
print("You are logged in to " + green(app.base_url))
@@ -185,7 +193,9 @@ def cmd_auth(app, user):
def cmd_login():
- parser = OptionParser(usage='%prog login')
+ parser = ArgumentParser(prog="toot login",
+ description="Log into a Mastodon instance",
+ epilog="https://github.com/ihabunek/toot")
parser.parse_args()
app = create_app_interactive()
@@ -194,24 +204,26 @@ def cmd_login():
return app, user
-def cmd_logout(app, user):
- parser = OptionParser(usage='%prog logout')
- parser.parse_args()
+def cmd_logout(app, user, args):
+ parser = ArgumentParser(prog="toot logout",
+ description="Log out, delete stored access keys",
+ epilog="https://github.com/ihabunek/toot")
+ parser.parse_args(args)
os.unlink(CONFIG_APP_FILE)
os.unlink(CONFIG_USER_FILE)
print("You are now logged out")
-def cmd_upload(app, user):
- parser = OptionParser(usage='%prog upload <path_to_media>')
- parser.parse_args()
+def cmd_upload(app, user, args):
+ parser = ArgumentParser(prog="toot upload",
+ description="Upload an image or video file",
+ epilog="https://github.com/ihabunek/toot")
+ parser.add_argument("file", help="Path to the file to upload", type=FileTy…
- if len(sys.argv) < 3:
- print_error("No status text given")
- return
+ args = parser.parse_args(args)
- response = do_upload(sys.argv[2])
+ response = do_upload(app, user, args.file)
print("\nSuccessfully uploaded media ID {}, type '{}'".format(
yellow(response['id']), yellow(response['type'])))
@@ -220,16 +232,12 @@ def cmd_upload(app, user):
print("Text URL: " + green(response['text_url']))
-def do_upload(app, user, path):
- if not os.path.exists(path):
- raise ConsoleError("File does not exist: " + path)
-
- with open(path, 'rb') as f:
- print("Uploading media: {}".format(green(f.name)))
- return upload_media(app, user, f)
+def do_upload(app, user, file):
+ print("Uploading media: {}".format(green(file.name)))
+ return upload_media(app, user, file)
-def run_command(command):
+def run_command(command, args):
app = load_app()
user = load_user()
@@ -238,7 +246,7 @@ def run_command(command):
return cmd_login()
if command == 'auth':
- return cmd_auth(app, user)
+ return cmd_auth(app, user, args)
# Commands which require user to be logged in
if not app or not user:
@@ -247,16 +255,16 @@ def run_command(command):
return
if command == 'logout':
- return cmd_logout(app, user)
+ return cmd_logout(app, user, args)
if command == 'post':
- return cmd_post_status(app, user)
+ return cmd_post_status(app, user, args)
if command == 'timeline':
- return cmd_timeline(app, user)
+ return cmd_timeline(app, user, args)
if command == 'upload':
- return cmd_upload(app, user)
+ return cmd_upload(app, user, args)
print(red("Unknown command '{}'\n".format(command)))
print_usage()
@@ -267,11 +275,12 @@ def main():
logging.basicConfig(level=logging.DEBUG)
command = sys.argv[1] if len(sys.argv) > 1 else None
+ args = sys.argv[2:]
if not command:
return print_usage()
try:
- run_command(command)
+ run_command(command, args)
except ConsoleError as e:
print_error(str(e))
You are viewing proxied material from vernunftzentrum.de. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.