Add search command - toot - Unnamed repository; edit this file 'description' to… | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
commit 64d46955e2b827c406f503cabc1be8b6169e72dd | |
parent d53849fe4b5c5b3f84a0ffc787d187bb641a51a5 | |
Author: Ivan Habunek <[email protected]> | |
Date: Sun, 16 Apr 2017 15:07:27 +0200 | |
Add search command | |
Diffstat: | |
CHANGELOG.md | 5 +++++ | |
README.rst | 51 +++++++++++++------------------ | |
tests/test_console.py | 34 ++++++++++++++++++++++++++++++- | |
toot/api.py | 7 +++++++ | |
toot/console.py | 48 ++++++++++++++++++++++++++++--- | |
5 files changed, 110 insertions(+), 35 deletions(-) | |
--- | |
diff --git a/CHANGELOG.md b/CHANGELOG.md | |
@@ -1,6 +1,11 @@ | |
Changelog | |
--------- | |
+**0.5.0 (2016-04-16)** | |
+ | |
+* Add `search` command | |
+* Migrate from `optparse` to `argparse` | |
+ | |
**0.4.0 (2016-04-15)** | |
* Add `upload` command to post media | |
diff --git a/README.rst b/README.rst | |
@@ -4,6 +4,8 @@ Toot - Mastodon CLI interface | |
Interact with Mastodon social networks from the command line. | |
+.. image:: https://img.shields.io/travis/ihabunek/toot.svg?maxAge=3600&style=f… | |
+ :target: https://travis-ci.org/ihabunek/toot | |
.. image:: https://img.shields.io/badge/author-%40ihabunek-blue.svg?maxAge=360… | |
:target: https://mastodon.social/@ihabunek | |
.. image:: https://img.shields.io/github/license/ihabunek/pdf417-py.svg?maxAge… | |
@@ -21,11 +23,28 @@ Install using pip: | |
pip install toot | |
- | |
Usage | |
----- | |
-Firstly, you will need to login to a Mastodon instance: | |
+Running ``toot`` displays a list of available commands. | |
+ | |
+Running ``toot <command> -h`` shows the documentation for the given command. | |
+ | |
+=================== =========================================================… | |
+ Command Description | |
+=================== =========================================================… | |
+ ``toot login`` Log into a Mastodon instance, saves access keys for late… | |
+ ``toot logout`` Log out, deletes stored access keys. | |
+ ``toot auth`` Display current login details. | |
+ ``toot post`` Post a status to your timeline. | |
+ ``toot search`` Search for accounts or hashtags. | |
+ ``toot timeline`` Display recent items in your public timeline. | |
+=================== =========================================================… | |
+ | |
+Authentication | |
+-------------- | |
+ | |
+Before tooting, you need to login to a Mastodon instance: | |
.. code-block:: | |
@@ -51,31 +70,3 @@ And you can logout which will remove the stored access token… | |
.. code-block:: | |
toot logout | |
- | |
-Show timeline | |
-~~~~~~~~~~~~~ | |
- | |
-To show recent items in your public timeline: | |
- | |
-.. code-block:: | |
- | |
- toot timeline | |
- | |
-Post status | |
-~~~~~~~~~~~ | |
- | |
-To post a new status to your timeline: | |
- | |
-.. code-block:: | |
- | |
- toot post "Hello world!" | |
- | |
-Optionally attach an image or video to the status: | |
- | |
- toot post "Hello world!" --media=path/to/world.jpg | |
- | |
-To set post visibility: | |
- | |
- toot post "Hello world!" --visibility=unlisted | |
- | |
-Possible visibility values are: ``public`` (default), ``unlisted``, ``private`… | |
diff --git a/tests/test_console.py b/tests/test_console.py | |
@@ -3,7 +3,7 @@ import pytest | |
import requests | |
from toot import User, App | |
-from toot.console import print_usage, cmd_post_status, cmd_timeline, cmd_upload | |
+from toot.console import print_usage, cmd_post_status, cmd_timeline, cmd_uploa… | |
from tests.utils import MockResponse | |
@@ -138,3 +138,35 @@ def test_upload(monkeypatch, capsys): | |
out, err = capsys.readouterr() | |
assert "Uploading media" in out | |
assert __file__ in out | |
+ | |
+ | |
+def test_search(monkeypatch, capsys): | |
+ def mock_get(url, params, headers=None): | |
+ assert url == 'https://habunek.com/api/v1/search' | |
+ assert headers == {'Authorization': 'Bearer xxx'} | |
+ assert params == { | |
+ 'q': 'freddy', | |
+ 'resolve': False, | |
+ } | |
+ | |
+ return MockResponse({ | |
+ 'hashtags': ['foo', 'bar', 'baz'], | |
+ 'accounts': [{ | |
+ 'acct': 'thequeen', | |
+ 'display_name': 'Freddy Mercury' | |
+ }, { | |
+ 'acct': '[email protected]', | |
+ 'display_name': 'Mercury Freddy' | |
+ }], | |
+ 'statuses': [], | |
+ }) | |
+ | |
+ monkeypatch.setattr(requests, 'get', mock_get) | |
+ | |
+ cmd_search(app, user, ['freddy']) | |
+ | |
+ out, err = capsys.readouterr() | |
+ assert "Hashtags:\n\033[32m#foo\033[0m, \033[32m#bar\033[0m, \033[32m#baz\… | |
+ assert "Accounts:" in out | |
+ assert "\033[32m@thequeen\033[0m Freddy Mercury" in out | |
+ assert "\033[32m@[email protected]\033[0m Mercury Freddy" in out | |
diff --git a/toot/api.py b/toot/api.py | |
@@ -108,3 +108,10 @@ def upload_media(app, user, file): | |
return _post(app, user, '/api/v1/media', files={ | |
'file': file | |
}) | |
+ | |
+ | |
+def search(app, user, query, resolve): | |
+ return _get(app, user, '/api/v1/search', { | |
+ 'q': query, | |
+ 'resolve': resolve, | |
+ }) | |
diff --git a/toot/console.py b/toot/console.py | |
@@ -16,7 +16,7 @@ from argparse import ArgumentParser, FileType | |
from textwrap import TextWrapper | |
from toot import DEFAULT_INSTANCE | |
-from toot.api import create_app, login, post_status, timeline_home, upload_med… | |
+from toot.api import create_app, login, post_status, timeline_home, upload_med… | |
from toot.config import save_user, load_user, load_app, save_app, CONFIG_APP_F… | |
@@ -84,6 +84,7 @@ def print_usage(): | |
print(" toot logout - log out (delete saved access tokens)") | |
print(" toot auth - shows currently logged in user and instance") | |
print(" toot post <msg> - toot a new post to your timeline") | |
+ print(" toot search - search for accounts or hashtags") | |
print(" toot timeline - shows your public timeline") | |
print("") | |
print("To get help for each command run:") | |
@@ -233,6 +234,42 @@ def cmd_upload(app, user, args): | |
print("Text URL: " + green(response['text_url'])) | |
+def _print_accounts(accounts): | |
+ if not accounts: | |
+ return | |
+ | |
+ print("\nAccounts:") | |
+ for account in accounts: | |
+ acct = green("@{}".format(account['acct'])) | |
+ display_name = account['display_name'] | |
+ print("* {} {}".format(acct, display_name)) | |
+ | |
+ | |
+def _print_hashtags(hashtags): | |
+ if not hashtags: | |
+ return | |
+ | |
+ print("\nHashtags:") | |
+ print(", ".join([green("#" + t) for t in hashtags])) | |
+ | |
+ | |
+def cmd_search(app, user, args): | |
+ parser = ArgumentParser(prog="toot serach", | |
+ description="Search for content", | |
+ epilog="https://github.com/ihabunek/toot") | |
+ | |
+ parser.add_argument("query", help="The search query") | |
+ parser.add_argument("-r", "--resolve", action='store_true', default=False, | |
+ help="Whether to resolve non-local accounts") | |
+ | |
+ args = parser.parse_args(args) | |
+ | |
+ response = search(app, user, args.query, args.resolve) | |
+ | |
+ _print_accounts(response['accounts']) | |
+ _print_hashtags(response['hashtags']) | |
+ | |
+ | |
def do_upload(app, user, file): | |
print("Uploading media: {}".format(green(file.name))) | |
return upload_media(app, user, file) | |
@@ -251,8 +288,8 @@ def run_command(command, args): | |
# Commands which require user to be logged in | |
if not app or not user: | |
- print(red("You are not logged in.")) | |
- print(red("Please run `toot login` first.")) | |
+ print_error("You are not logged in.") | |
+ print_error("Please run `toot login` first.") | |
return | |
if command == 'logout': | |
@@ -267,7 +304,10 @@ def run_command(command, args): | |
if command == 'upload': | |
return cmd_upload(app, user, args) | |
- print(red("Unknown command '{}'\n".format(command))) | |
+ if command == 'search': | |
+ return cmd_search(app, user, args) | |
+ | |
+ print_error("Unknown command '{}'\n".format(command)) | |
print_usage() | |