Add instance command - toot - Unnamed repository; edit this file 'description' … | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
commit dfdad045f00b3faa9679989031d0a4dabe4753ce | |
parent 5c0a797b66faf3d6ef14549301bfd56df79dfc07 | |
Author: Ivan Habunek <[email protected]> | |
Date: Fri, 29 Dec 2017 14:26:40 +0100 | |
Add instance command | |
Diffstat: | |
CHANGELOG.md | 5 +++-- | |
toot/api.py | 30 ++++++++++++++++++++++++++++-- | |
toot/commands.py | 11 ++++++++++- | |
toot/console.py | 12 ++++++++++++ | |
toot/output.py | 20 ++++++++++++++++++++ | |
toot/utils.py | 9 +++++++++ | |
6 files changed, 82 insertions(+), 5 deletions(-) | |
--- | |
diff --git a/CHANGELOG.md b/CHANGELOG.md | |
@@ -3,9 +3,10 @@ Changelog | |
**0.16.0 (TBA)** | |
-* **Dropped support for Python 2** because it's a pain to support and was | |
- causing bugs with handling unicode. | |
+* **Drop support for Python 2** because it's a pain to support and caused bugs | |
+ with handling unicode. | |
* Remove hacky `login_2fa` command, use `login_browser` instead | |
+* Add `instance` command | |
**0.15.1 (2017-12-12)** | |
diff --git a/toot/api.py b/toot/api.py | |
@@ -4,10 +4,11 @@ import logging | |
import re | |
import requests | |
-from urllib.parse import urlparse, urlencode | |
from requests import Request, Session | |
+from urllib.parse import urlparse, urlencode | |
from toot import CLIENT_NAME, CLIENT_WEBSITE | |
+from toot.utils import domain_exists | |
SCOPES = 'read write follow' | |
@@ -28,7 +29,9 @@ class AuthenticationError(ApiError): | |
def _log_request(request): | |
logger.debug(">>> \033[32m{} {}\033[0m".format(request.method, request.url… | |
- logger.debug(">>> HEADERS: \033[33m{}\033[0m".format(request.headers)) | |
+ | |
+ if request.headers: | |
+ logger.debug(">>> HEADERS: \033[33m{}\033[0m".format(request.headers)) | |
if request.data: | |
logger.debug(">>> DATA: \033[33m{}\033[0m".format(request.data)) | |
@@ -83,6 +86,14 @@ def _get(app, user, url, params=None): | |
return _process_response(response) | |
+def _unauthorized_get(url, params=None): | |
+ _log_request(Request('GET', url, None, params=params)) | |
+ | |
+ response = requests.get(url, params) | |
+ | |
+ return _process_response(response) | |
+ | |
+ | |
def _post(app, user, url, data=None, files=None): | |
url = app.base_url + url | |
headers = {"Authorization": "Bearer " + user.access_token} | |
@@ -239,3 +250,18 @@ def verify_credentials(app, user): | |
def get_notifications(app, user): | |
return _get(app, user, '/api/v1/notifications').json() | |
+ | |
+ | |
+def get_instance(app, user, domain): | |
+ if not domain_exists(domain): | |
+ raise ApiError("Domain {} not found".format(domain)) | |
+ | |
+ url = "http://{}/api/v1/instance".format(domain) | |
+ | |
+ try: | |
+ return _unauthorized_get(url).json() | |
+ except NotFoundError: | |
+ raise ApiError( | |
+ "Instance info not found at {}.\n" | |
+ "The given domain probably does not host a Mastodon instance.".for… | |
+ ) | |
diff --git a/toot/commands.py b/toot/commands.py | |
@@ -11,7 +11,7 @@ from itertools import chain | |
from textwrap import TextWrapper, wrap | |
from toot import api, config, DEFAULT_INSTANCE, User, App, ConsoleError | |
-from toot.output import print_out | |
+from toot.output import print_out, print_instance | |
def register_app(instance): | |
@@ -329,3 +329,12 @@ def whoami(app, user, args): | |
def whois(app, user, args): | |
account = _find_account(app, user, args.account) | |
_print_account(account) | |
+ | |
+ | |
+def instance(app, user, args): | |
+ name = args.instance or (app and app.instance) | |
+ if not name: | |
+ raise ConsoleError("Please specify instance name.") | |
+ | |
+ instance = api.get_instance(app, user, name) | |
+ print_instance(instance) | |
diff --git a/toot/console.py b/toot/console.py | |
@@ -96,6 +96,18 @@ READ_COMMANDS = [ | |
require_auth=True, | |
), | |
Command( | |
+ name="instance", | |
+ description="Display instance details", | |
+ arguments=[ | |
+ (["instance"], { | |
+ "help": "instance domain (e.g. 'mastodon.social') or blank to … | |
+ "nargs": "?", | |
+ }), | |
+ | |
+ ], | |
+ require_auth=False, | |
+ ), | |
+ Command( | |
name="search", | |
description="Search for users or hashtags", | |
arguments=[ | |
diff --git a/toot/output.py b/toot/output.py | |
@@ -3,6 +3,9 @@ | |
import sys | |
import re | |
+from textwrap import wrap | |
+from toot.utils import format_content | |
+ | |
START_CODES = { | |
'red': '\033[31m', | |
'green': '\033[32m', | |
@@ -50,3 +53,20 @@ def print_err(*args, **kwargs): | |
args = ["<red>{}</red>".format(a) for a in args] | |
args = [colorize(a) if USE_ANSI_COLOR else strip_tags(a) for a in args] | |
print(*args, file=sys.stderr, **kwargs) | |
+ | |
+ | |
+def print_instance(instance): | |
+ print_out("<green>{}</green>".format(instance['title'])) | |
+ print_out("<blue>{}</blue>".format(instance['uri'])) | |
+ print_out("running Mastodon {}".format(instance['version'])) | |
+ print_out("") | |
+ | |
+ description = instance['description'].strip() | |
+ if not description: | |
+ return | |
+ | |
+ lines = [line.strip() for line in format_content(description) if line.stri… | |
+ for line in lines: | |
+ for l in wrap(line.strip()): | |
+ print(l) | |
+ print() | |
diff --git a/toot/utils.py b/toot/utils.py | |
@@ -1,6 +1,7 @@ | |
# -*- coding: utf-8 -*- | |
import re | |
+import socket | |
from bs4 import BeautifulSoup | |
@@ -41,3 +42,11 @@ def format_content(content): | |
yield line | |
first = False | |
+ | |
+ | |
+def domain_exists(name): | |
+ try: | |
+ socket.gethostbyname(name) | |
+ return True | |
+ except OSError: | |
+ return False |