Add search command - toot - Unnamed repository; edit this file 'description' to name the repository.
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
(DIR) commit 64d46955e2b827c406f503cabc1be8b6169e72dd
(DIR) parent d53849fe4b5c5b3f84a0ffc787d187bb641a51a5
(HTM) Author: Ivan Habunek <ivan@habunek.com>
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(-)
---
(DIR) 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
(DIR) 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=flat-square
+ :target: https://travis-ci.org/ihabunek/toot
.. image:: https://img.shields.io/badge/author-%40ihabunek-blue.svg?maxAge=3600&style=flat-square
:target: https://mastodon.social/@ihabunek
.. image:: https://img.shields.io/github/license/ihabunek/pdf417-py.svg?maxAge=3600&style=flat-square
@@ -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 later use.
+ ``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 tokens:
.. 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``, ``direct``. They are documented `here <https://github.com/tootsuite/documentation/blob/aa20089756c8cf9ff5a52fb35ad1a9472f10970c/Using-Mastodon/User-guide.md#toot-privacy>`_.
(DIR) 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_upload, cmd_search
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': 'thequeen@other.instance',
+ '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\033[0m" in out
+ assert "Accounts:" in out
+ assert "\033[32m@thequeen\033[0m Freddy Mercury" in out
+ assert "\033[32m@thequeen@other.instance\033[0m Mercury Freddy" in out
(DIR) 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,
+ })
(DIR) 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_media
+from toot.api import create_app, login, post_status, timeline_home, upload_media, search
from toot.config import save_user, load_user, load_app, save_app, CONFIG_APP_FILE, CONFIG_USER_FILE
@@ -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()