Add docs, closes #3
This commit is contained in:
parent
5ece50a3e1
commit
5cd5548d46
|
@ -22,11 +22,16 @@ flake8:
|
|||
script:
|
||||
- flake8
|
||||
|
||||
doc8:
|
||||
stage: test
|
||||
script:
|
||||
- doc8
|
||||
|
||||
deploy-pypi:
|
||||
stage: deploy
|
||||
when: manual
|
||||
only:
|
||||
- master@Lucidiot/twtxt-registry-client
|
||||
- tags@Lucidiot/twtxt-registry-client
|
||||
environment:
|
||||
name: pypi
|
||||
url: https://pypi.org/project/twtxt-registry-client
|
||||
|
@ -47,7 +52,7 @@ deploy-testpypi:
|
|||
stage: deploy
|
||||
when: manual
|
||||
only:
|
||||
- branches@Lucidiot/twtxt-registry-client
|
||||
- tags@Lucidiot/twtxt-registry-client
|
||||
environment:
|
||||
name: testpypi
|
||||
url: https://test.pypi.org/project/twtxt-registry-client
|
||||
|
@ -63,3 +68,17 @@ deploy-testpypi:
|
|||
- echo "password=$PYPI_DEPLOY_PASSWORD" >> ~/.pypirc
|
||||
- python setup.py sdist bdist_wheel
|
||||
- twine upload dist/* -r testpypi
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
when: manual
|
||||
only:
|
||||
- master@Lucidiot/twtxt-registry-client
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
|
||||
script:
|
||||
- cd docs
|
||||
- make html
|
||||
- mv _build/html ../public
|
||||
|
|
15
README.rst
15
README.rst
|
@ -2,19 +2,8 @@ twtxt-registry-client
|
|||
=====================
|
||||
|
||||
A simple API client for servers implementing `twtxt`_'s `registry`_ API.
|
||||
`Browse documentation`_
|
||||
|
||||
.. _twtxt: https://github.com/buckket/twtxt
|
||||
.. _registry: https://twtxt.readthedocs.io/en/stable/user/registry.html
|
||||
|
||||
To-do
|
||||
-----
|
||||
|
||||
* Error handling
|
||||
* Command-line help
|
||||
* Sphinx documentation
|
||||
|
||||
* Doc8 linting
|
||||
* GitLab Pages
|
||||
|
||||
* Parsing, enhanced outputs and porcelain mode, just like with `twtxt`_
|
||||
* Verbose output and logging
|
||||
.. _Browse documentation: https://lucidiot.gitlab.io/twtxt-registry-client
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,72 @@
|
|||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
sys.path.insert(0, BASE_DIR / '..')
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'twtxt-registry-client'
|
||||
copyright = '2019, Lucidiot'
|
||||
author = 'Lucidiot'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
with (BASE_DIR / '..' / 'VERSION').open() as f:
|
||||
release = f.read().strip()
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.viewcode',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
html_theme_options = {
|
||||
'description': 'API client and CLI for twtxt registries',
|
||||
'fixed_sidebar': 'true',
|
||||
}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
# html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# Concatenate the class' and __init__'s docstrings when documenting a class
|
||||
autoclass_content = 'both'
|
|
@ -0,0 +1,55 @@
|
|||
Contributing
|
||||
============
|
||||
|
||||
Contributions to the project are greatly appreciated.
|
||||
|
||||
Bugs and suggestions
|
||||
--------------------
|
||||
|
||||
You may `submit an issue`_ to GitLab to warn of any bugs, ask for new features,
|
||||
or ask any questions that are not answered in this documentation.
|
||||
|
||||
When reporting a bug, do not forget to put in your version of Python and your
|
||||
version of *twtxt-registry-client*. This will greatly help when
|
||||
troubleshooting, as most errors often come from version incompatibilities.
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
Setup
|
||||
^^^^^
|
||||
|
||||
You will need a virtual envionment to work properly. `virtualenvwrapper`_ is
|
||||
recommended::
|
||||
|
||||
git clone https://gitlab.com/Lucidiot/twtxt-registry-client
|
||||
cd twtxt-registry-client
|
||||
mkvirtualenv -a . twtxt-registry-client
|
||||
pip install -e .[dev]
|
||||
|
||||
This will clone the repository, create a virtual environment named
|
||||
``twtxt-registry-client``, then tell pip to let the package be editable
|
||||
(``-e``). The ``[dev]`` suffix adds the extra requirements useful for
|
||||
development.
|
||||
|
||||
Linting
|
||||
^^^^^^^
|
||||
|
||||
The source code follows the PEP 8 code style and performs CI checks using the
|
||||
``flake8`` tool. To perform the same checks locally, run ``flake8`` on the root
|
||||
directory of this repository.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
The documentation you are reading is generated by the `Sphinx`_ tool.
|
||||
The text files that hold the documentation's contents are written in
|
||||
`reStructuredText`_ and are available under the ``/docs`` folder of the
|
||||
`GitLab repository`_.
|
||||
They are also subject to linting using the ``doc8`` tool.
|
||||
|
||||
.. _submit an issue: https://gitlab.com/Lucidiot/twtxt-registry-client/issues/new
|
||||
.. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.io
|
||||
.. _GitLab repository: https://gitlab.com/Lucidiot/twtxt-registry-client
|
||||
.. _Sphinx: http://www.sphinx-doc.org/
|
||||
.. _reStructuredText: http://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html
|
|
@ -0,0 +1,211 @@
|
|||
twtxt-registry-client
|
||||
=====================
|
||||
|
||||
:ref:`genindex` - :ref:`modindex` - :ref:`search`
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/twtxt-registry-client.svg
|
||||
:target: https://pypi.org/project/twtxt-registry-client
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/twtxt-registry-client.svg
|
||||
:target: https://pypi.org/project/twtxt-registry-client
|
||||
|
||||
.. image:: https://img.shields.io/pypi/format/twtxt-registry-client.svg
|
||||
:target: https://pypi.org/project/twtxt-registry-client
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/twtxt-registry-client.svg
|
||||
:target: https://pypi.org/project/twtxt-registry-client
|
||||
|
||||
.. image:: https://img.shields.io/pypi/status/twtxt-registry-client.svg
|
||||
:target: https://pypi.org/project/twtxt-registry-client
|
||||
|
||||
.. image:: https://gitlab.com/Lucidiot/twtxt-registry-client/badges/master/pipeline.svg
|
||||
:target: https://gitlab.com/Lucidiot/twtxt-registry-client/pipelines
|
||||
|
||||
.. image:: https://requires.io/github/Lucidiot/twtxt-registry-client/requirements.svg?branch=master
|
||||
:target: https://requires.io/github/Lucidiot/twtxt-registry-client/requirements/?branch=master
|
||||
|
||||
.. image:: https://img.shields.io/github/last-commit/Lucidiot/twtxt-registry-client.svg
|
||||
:target: https://gitlab.com/Lucidiot/twtxt-registry-client/commits
|
||||
|
||||
.. image:: https://img.shields.io/badge/badge%20count-9-brightgreen.svg
|
||||
:target: https://gitlab.com/Lucidiot/twtxt-registry-client
|
||||
|
||||
A Python CLI for the twtxt `registry API`_.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
This package has a very standard Python setup::
|
||||
|
||||
pip install twtxt_registry_client
|
||||
|
||||
That's it, nothing more.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Base arguments
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
.. code::
|
||||
|
||||
$ twtxt-registry
|
||||
[--version]
|
||||
[--help]
|
||||
[-k|-insecure]
|
||||
[-f [raw|json|pretty]]
|
||||
REGISTRY_URL
|
||||
COMMAND
|
||||
[subcommand args]
|
||||
|
||||
``--version``
|
||||
Output the CLI's version number and exit.
|
||||
``--help``
|
||||
Output the main help text and exit.
|
||||
``-k`` / ``--insecure``
|
||||
Disable SSL certificate checks; first added for the `twtxt demo registry`_
|
||||
as it is appears to be unmaintained and has an expired certificate.
|
||||
``-f`` / ``--format`` with one of ``raw``, ``json`` or ``pretty``
|
||||
Use a specific :class:`Formatter <twtxt_registry_client.output.Formatter>`
|
||||
class to output the HTTP responses.
|
||||
``REGISTRY_URL``
|
||||
Base URL to a twtxt registry's API.
|
||||
|
||||
.. note::
|
||||
|
||||
The recommended base path for registry APIs is at ``http://host/api``,
|
||||
but the `registry API`_ specification does not enforce it. Therefore,
|
||||
on most registries, you will need to append ``/api`` to the hostname.
|
||||
|
||||
``COMMAND [subcommand args]``
|
||||
A client subcommand; see the subcommand-specific sections below.
|
||||
|
||||
Registration
|
||||
^^^^^^^^^^^^
|
||||
|
||||
.. code::
|
||||
|
||||
$ twtxt-registry
|
||||
[...base arguments...]
|
||||
register
|
||||
[--help]
|
||||
[-n|--nickname [NICK]]
|
||||
[-u|--url [URL]]
|
||||
|
||||
``--help``
|
||||
Output the subcommand help text and exit.
|
||||
``-n [NICK]`` / ``--nickname [NICK]``
|
||||
Set a custom nickname. If omitted, the CLI will try to read it from the
|
||||
``twtxt`` client's standard configuration; this may not work with other
|
||||
twtxt implementations.
|
||||
``-u [URL]`` / ``--url [URL]``
|
||||
Set a custom public URL. If omitted, the CLI will try to read it from the
|
||||
``twtxt`` client's standard configuration; this may not work with other
|
||||
twtxt implementations.
|
||||
|
||||
This subcommand outputs the HTTP response directly, see
|
||||
:meth:`Formatter.format_response()
|
||||
<twtxt_registry_client.output.Formatter.format_response>`.
|
||||
|
||||
List users
|
||||
^^^^^^^^^^
|
||||
|
||||
.. code::
|
||||
|
||||
$ twtxt-registry
|
||||
[...base arguments...]
|
||||
users
|
||||
[--help]
|
||||
[-q|--query [TEXT]]
|
||||
|
||||
``--help``
|
||||
Output the subcommand help text and exit.
|
||||
``-q [TEXT]`` / ``--query [TEXT]``
|
||||
Optionally filter users by a query.
|
||||
|
||||
This subcommand outputs the users list, see :meth:`Formatter.format_users()
|
||||
<twtxt_registry_client.output.Formatter.format_users>`.
|
||||
If the registry returns an HTTP 4xx or 5xx error code, the response is printed
|
||||
directly. See :meth:`Formatter.format_response()
|
||||
<twtxt_registry_client.output.Formatter.format_response>`.
|
||||
|
||||
List tweets
|
||||
^^^^^^^^^^^
|
||||
|
||||
.. code::
|
||||
|
||||
$ twtxt-registry
|
||||
[...base arguments...]
|
||||
tweets
|
||||
[--help]
|
||||
[-q|--query [TEXT]]
|
||||
|
||||
``--help``
|
||||
Output the subcommand help text and exit.
|
||||
``-q [TEXT]`` / ``--query [TEXT]``
|
||||
Optionally filter tweets by a query.
|
||||
|
||||
This subcommand outputs the tweets list, see :meth:`Formatter.format_tweets()
|
||||
<twtxt_registry_client.output.Formatter.format_tweets>`.
|
||||
If the registry returns an HTTP 4xx or 5xx error code, the response is printed
|
||||
directly. See :meth:`Formatter.format_response()
|
||||
<twtxt_registry_client.output.Formatter.format_response>`.
|
||||
|
||||
List tweets by mention
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code::
|
||||
|
||||
$ twtxt-registry
|
||||
[...base arguments...]
|
||||
mentions
|
||||
[--help]
|
||||
[NAME_OR_URL]
|
||||
|
||||
``--help``
|
||||
Output the subcommand help text and exit.
|
||||
``NAME_OR_URL``
|
||||
Name or URL of a user to list mentions to.
|
||||
|
||||
If a name is specified, the CLI will try to deduce its URL from the
|
||||
``twtxt`` client's configuration. If nothing is specified, the CLI will
|
||||
use the configured public URL to default to the local user.
|
||||
This may not work on other twtxt implementations.
|
||||
|
||||
This subcommand outputs the tweets list, see :meth:`Formatter.format_tweets()
|
||||
<twtxt_registry_client.output.Formatter.format_tweets>`.
|
||||
If the registry returns an HTTP 4xx or 5xx error code, the response is printed
|
||||
directly. See :meth:`Formatter.format_response()
|
||||
<twtxt_registry_client.output.Formatter.format_response>`.
|
||||
|
||||
List tweets by tag
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code::
|
||||
|
||||
$ twtxt-registry
|
||||
[...base arguments...]
|
||||
tag
|
||||
[--help]
|
||||
NAME
|
||||
|
||||
``--help``
|
||||
Output the subcommand help text and exit.
|
||||
``NAME``
|
||||
Tag to list tweets for.
|
||||
|
||||
This subcommand outputs the tweets list, see :meth:`Formatter.format_tweets()
|
||||
<twtxt_registry_client.output.Formatter.format_tweets>`.
|
||||
If the registry returns an HTTP 4xx or 5xx error code, the response is printed
|
||||
directly. See :meth:`Formatter.format_response()
|
||||
<twtxt_registry_client.output.Formatter.format_response>`.
|
||||
|
||||
Learn more
|
||||
----------
|
||||
|
||||
.. toctree::
|
||||
output
|
||||
contributing
|
||||
|
||||
.. _registry API: https://twtxt.readthedocs.io/en/stable/user/registry.html
|
||||
.. _twtxt demo registry: https://registry.twtxt.org
|
|
@ -0,0 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
|
@ -0,0 +1,29 @@
|
|||
Formatters
|
||||
==========
|
||||
|
||||
Base attributes
|
||||
---------------
|
||||
|
||||
.. autoclass:: twtxt_registry_client.output.Formatter
|
||||
:members:
|
||||
|
||||
.. autodata:: twtxt_registry_client.output.registry
|
||||
:annotation:
|
||||
|
||||
.. autoclass:: twtxt_registry_client.output.FormatterMetaclass
|
||||
:members:
|
||||
|
||||
.. autoclass:: twtxt_registry_client.output.FormatterRegistry
|
||||
:members:
|
||||
|
||||
Standard formatters
|
||||
-------------------
|
||||
|
||||
.. autoclass:: twtxt_registry_client.output.RawFormatter
|
||||
:members:
|
||||
|
||||
.. autoclass:: twtxt_registry_client.output.JSONFormatter
|
||||
:members:
|
||||
|
||||
.. autoclass:: twtxt_registry_client.output.PrettyFormatter
|
||||
:members:
|
|
@ -1 +1,3 @@
|
|||
flake8>=3.7
|
||||
Sphinx>=2.2
|
||||
doc8>=0.8
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
[flake8]
|
||||
exclude = .git,__pycache__,docs,*.pyc,venv
|
||||
|
||||
[doc8]
|
||||
ignore-path=**/*.txt,*.txt,*.egg-info,docs/_build,venv,.git
|
||||
|
|
|
@ -52,11 +52,13 @@ def cli(ctx, registry_url, insecure, format):
|
|||
'-n', '--nickname',
|
||||
help='Nickname to register with. '
|
||||
'Defaults to the configured twtxt nickname, if available.',
|
||||
metavar='[NICK]',
|
||||
)
|
||||
@click.option(
|
||||
'-u', '--url',
|
||||
help='URL to the twtxt file to register with. '
|
||||
'Defaults to the configured twtxt URL, if available.',
|
||||
metavar='[URL]',
|
||||
)
|
||||
@click.pass_context
|
||||
def register(ctx, nickname, url):
|
||||
|
|
|
@ -10,34 +10,113 @@ import textwrap
|
|||
|
||||
|
||||
class FormatterRegistry(ClassRegistry):
|
||||
"""
|
||||
The class that holds registered formatters; allows registering a formatter
|
||||
automatically by merely importing it.
|
||||
|
||||
You should not have to use this class directly; use the already
|
||||
instanciated :data:`registry` in this module instead.
|
||||
"""
|
||||
|
||||
def check_value(self, value):
|
||||
"""
|
||||
Ensure that a new formatter class subclasses :class:`Formatter`.
|
||||
|
||||
:param Callable value: A formatter subclass.
|
||||
:raises AssertionError:
|
||||
When the formatter subclass does not subclass :class:`Formatter`.
|
||||
"""
|
||||
assert issubclass(value, Formatter), 'Can only register formatters'
|
||||
|
||||
|
||||
registry = FormatterRegistry()
|
||||
"""
|
||||
The formatter registry: an enhanced ``dict`` which holds links between
|
||||
formatter names (used in the ``--format`` command-line argument) and formatter
|
||||
classes.
|
||||
"""
|
||||
|
||||
|
||||
class FormatterMetaclass(registry.metaclass, ABCMeta):
|
||||
pass
|
||||
"""
|
||||
The metaclass which allows auto-registration of each formatter.
|
||||
In most cases, you should not have to use this class directly;
|
||||
use the :class:`Formatter` abstract class instead.
|
||||
Registration of classes that do not subclass :class:`Formatter` will fail.
|
||||
"""
|
||||
|
||||
|
||||
class Formatter(metaclass=FormatterMetaclass, register=False):
|
||||
"""
|
||||
Abstract base class for output formatters.
|
||||
|
||||
When creating a new subclass, you may specify some parameters to pass to
|
||||
the auto-registration system::
|
||||
|
||||
class MyFormatter(key='something'):
|
||||
pass
|
||||
|
||||
class MyInvisibleFormatter(register=False):
|
||||
pass
|
||||
|
||||
In the above example, ``MyFormatter`` can be used in the command line
|
||||
client using ``twtxt-registry -f something``, and MyInvisibleFormatter
|
||||
will not be visible directly (which is useful for abstract classes).
|
||||
|
||||
``register`` defaults to ``True``, and ``key`` defaults to the class name.
|
||||
"""
|
||||
# TODO: Add link to objtools docs here once they are published
|
||||
|
||||
@abstractmethod
|
||||
def format_response(self, resp):
|
||||
pass
|
||||
"""
|
||||
Generic output for an HTTP response: generally, this would include
|
||||
the HTTP status code and the response body. This is used to output
|
||||
HTTP errors or basic requests which do not have a very meaningful
|
||||
response body, like the registration API.
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the formatter's output.
|
||||
:rtype: str
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def format_tweets(self, resp):
|
||||
pass
|
||||
"""
|
||||
Output tweets from a successful HTTP response. The tweets can be
|
||||
obtained from ``resp.text`` and parsing of the response text is left
|
||||
to the formatter.
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the formatter's output.
|
||||
:rtype: str
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def format_users(self, resp):
|
||||
pass
|
||||
"""
|
||||
Output users from a successful HTTP response. The users can be obtained
|
||||
from ``resp.text`` and parsing of the response text is left to the
|
||||
formatter.
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the formatter's output.
|
||||
:rtype: str
|
||||
"""
|
||||
|
||||
|
||||
class RawFormatter(Formatter, key='raw'):
|
||||
"""
|
||||
A very basic formatter which always outputs the response's body directly.
|
||||
|
||||
Use ``-f raw`` or ``--format raw`` in the CLI to select it.
|
||||
"""
|
||||
|
||||
def format_response(self, resp):
|
||||
return resp.text
|
||||
|
@ -50,8 +129,30 @@ class RawFormatter(Formatter, key='raw'):
|
|||
|
||||
|
||||
class JSONFormatter(Formatter, key='json'):
|
||||
"""
|
||||
A formatter which always returns valid JSON documents.
|
||||
|
||||
Use ``-f json`` or ``--format json`` in the CLI to select it.
|
||||
"""
|
||||
|
||||
def format_response(self, resp):
|
||||
"""
|
||||
Outputs a simple JSON payload for any HTTP response, including its
|
||||
HTTP status code, its URL and its body.
|
||||
Sample output with a 404 error::
|
||||
|
||||
{
|
||||
"status_code": 404,
|
||||
"url": "http://somewhere/api/not/found",
|
||||
"body": "Page Not Found!"
|
||||
}
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the JSON output.
|
||||
:rtype: str
|
||||
"""
|
||||
return json.dumps({
|
||||
'status_code': resp.status_code,
|
||||
'url': resp.url,
|
||||
|
@ -59,6 +160,26 @@ class JSONFormatter(Formatter, key='json'):
|
|||
})
|
||||
|
||||
def format_tweets(self, resp):
|
||||
"""
|
||||
Outputs a list of JSON objects for an HTTP response holding tweets,
|
||||
with the users' nickname and URL, the tweet's timestamp, and its
|
||||
content. Sample output::
|
||||
|
||||
[
|
||||
{
|
||||
"nick": "lucidiot",
|
||||
"url": "https://tilde.town/~lucidiot/twtxt.txt",
|
||||
"timestamp": "2019-02-31T13:37:42.123456Z",
|
||||
"message": "Hello, world!"
|
||||
}
|
||||
]
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the JSON output.
|
||||
:rtype: str
|
||||
"""
|
||||
if not resp.ok:
|
||||
return self.format_response(resp)
|
||||
output = []
|
||||
|
@ -73,6 +194,24 @@ class JSONFormatter(Formatter, key='json'):
|
|||
return json.dumps(output)
|
||||
|
||||
def format_users(self, resp):
|
||||
"""
|
||||
Outputs a list of JSON objects for an HTTP response holding users,
|
||||
with their nickname, URL, and last update timestamp. Sample output::
|
||||
|
||||
[
|
||||
{
|
||||
"nick": "lucidiot",
|
||||
"url": "https://tilde.town/~lucidiot/twtxt.txt",
|
||||
"timestamp": "2019-02-31T13:37:42.123456Z"
|
||||
}
|
||||
]
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the JSON output.
|
||||
:rtype: str
|
||||
"""
|
||||
if not resp.ok:
|
||||
return self.format_response(resp)
|
||||
output = []
|
||||
|
@ -87,6 +226,12 @@ class JSONFormatter(Formatter, key='json'):
|
|||
|
||||
|
||||
class PrettyFormatter(Formatter, key='pretty'):
|
||||
"""
|
||||
A formatter with pretty-printing for beautiful command line output.
|
||||
|
||||
This is the default formatter; Use ``-f pretty`` or ``--format pretty``
|
||||
in the CLI to explicitly select it.
|
||||
"""
|
||||
|
||||
status_colors = {
|
||||
1: 'white',
|
||||
|
@ -97,6 +242,24 @@ class PrettyFormatter(Formatter, key='pretty'):
|
|||
}
|
||||
|
||||
def format_response(self, resp):
|
||||
"""
|
||||
Outputs an HTTP response in a syntax similar to a true HTTP response,
|
||||
with its status code, reason and body:
|
||||
|
||||
HTTP **404 Not Found**
|
||||
|
||||
Page Not Found!
|
||||
|
||||
The HTTP status code may be coloured if the terminal supports it:
|
||||
white for 1xx, green for 2xx, cyan for 3xx, red for 4xx and magenta
|
||||
for 5xx.
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the human-readable output.
|
||||
:rtype: str
|
||||
"""
|
||||
return 'HTTP {code} {name}\n\n{body}'.format(
|
||||
code=click.style(
|
||||
str(resp.status_code),
|
||||
|
@ -108,6 +271,16 @@ class PrettyFormatter(Formatter, key='pretty'):
|
|||
)
|
||||
|
||||
def format_tweets(self, resp):
|
||||
"""
|
||||
Outputs an HTTP response as a list of tweets, in a format similar to
|
||||
the output of the original ``twtxt`` CLI.
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the human-readable output.
|
||||
:rtype: str
|
||||
"""
|
||||
if not resp.ok:
|
||||
return self.format_response(resp)
|
||||
|
||||
|
@ -152,6 +325,16 @@ class PrettyFormatter(Formatter, key='pretty'):
|
|||
return '\n\n'.join(output)
|
||||
|
||||
def format_users(self, resp):
|
||||
"""
|
||||
Outputs an HTTP response as a list of users, in a format similar to
|
||||
the output of the original ``twtxt`` CLI.
|
||||
|
||||
:param resp:
|
||||
A requests ``Response`` instance from an API request to a registry.
|
||||
:type resp: requests.Response
|
||||
:returns: A string holding the human-readable output.
|
||||
:rtype: str
|
||||
"""
|
||||
if not resp.ok:
|
||||
return self.format_response(resp)
|
||||
output = []
|
||||
|
|
Reference in New Issue