From 7ee22a8a5ee82f5d6b5e6f76156e315f3c9eba3e Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Mon, 17 Jul 2023 16:39:39 -0700 Subject: [PATCH] Move documentation to ReadTheDocs, refs #7 --- Justfile | 37 ++++++++ README.md | 191 +------------------------------------- docs/.gitignore | 1 + docs/Makefile | 23 +++++ docs/_templates/base.html | 6 ++ docs/aliases.md | 106 +++++++++++++++++++++ docs/authentication.md | 127 +++++++++++++++++++++++++ docs/conf.py | 174 ++++++++++++++++++++++++++++++++++ docs/index.md | 93 +++++++++++++++++++ docs/requirements.txt | 5 + 10 files changed, 576 insertions(+), 187 deletions(-) create mode 100644 Justfile create mode 100644 docs/.gitignore create mode 100644 docs/Makefile create mode 100644 docs/_templates/base.html create mode 100644 docs/aliases.md create mode 100644 docs/authentication.md create mode 100644 docs/conf.py create mode 100644 docs/index.md create mode 100644 docs/requirements.txt diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..b3cc38a --- /dev/null +++ b/Justfile @@ -0,0 +1,37 @@ +# Run tests and linters +@default: test lint + +# Install dependencies and test dependencies +@init: + pipenv run pip install -e '.[test]' + +# Run pytest with supplied options +@test *options: + pipenv run pytest {{options}} + +# Run linters +@lint: + echo "Linters..." + echo " Black" + pipenv run black . --check + echo " cog" + pipenv run cog --check README.md docs/*.md + echo " ruff" + pipenv run ruff . + +# Rebuild docs with cog +@cog: + pipenv run cog -r docs/*.md + +# Serve live docs on localhost:8000 +@docs: cog + cd docs && pipenv run make livehtml + +# Apply Black +@black: + pipenv run black . + +# Run automatic fixes +@fix: cog + pipenv run ruff . --fix + pipenv run black . diff --git a/README.md b/README.md index 4c23541..07310c2 100644 --- a/README.md +++ b/README.md @@ -17,198 +17,15 @@ If you want to install it in the same virtual environment as Datasette (to use i datasette install dclient -## Standalone v.s. plugin - -Once installed you can use this tool like so: - - dclient --help - -If you also have Datasette installed in the same environment it will register itself as a command plugin. - -This means you can run any of these commands using `datasette client` instead, like this: - - datasette client --help - datasette client query https://latest.datasette.io/fixtures "select * from facetable limit 1" - -## Running queries - -You can run SQL queries against a Datasette instance like this: - -``` -$ dclient query https://latest.datasette.io/fixtures "select * from facetable limit 1" -``` -Output: -```json -[ - { - "pk": 1, - "created": "2019-01-14 08:00:00", - "planet_int": 1, - "on_earth": 1, - "state": "CA", - "_city_id": 1, - "_neighborhood": "Mission", - "tags": "[\"tag1\", \"tag2\"]", - "complex_array": "[{\"foo\": \"bar\"}]", - "distinct_some_null": "one", - "n": "n1" - } -] -``` - -### dclient query --help - -``` -Usage: dclient query [OPTIONS] URL SQL - - Run a SQL query against a Datasette database URL - - Returns a JSON array of objects - -Options: - --help Show this message and exit. - -``` - - -## Authentication - -`dclient` can handle API tokens for Datasette instances that require authentication. - -You can pass an API token to `query` using `-t/--token` like this: +## Running a query ```bash -dclient query https://latest.datasette.io/fixtures "select * from facetable" -t dstok_mytoken -``` -You can also store tokens for a specific URL prefix. To always use `dstok_mytoken` for any URL on the `https://latest.datasette.io/` instance you can run this: -```bash -dclient auth add https://latest.datasette.io/ -``` -Then paste in the token and hit enter when prompted to do so. - -To list which URLs you have set tokens for, run the `auth list` command: -```bash -dclient auth list -``` -To delete the token for a specific URL, run `auth remove`: -```bash -dclient auth remove https://latest.datasette.io/ +dclient query https://latest.datasette.io/fixtures "select * from facetable limit 1" ``` -## Aliases +## Documentation -You can assign an alias to a Datasette database using the `dclient alias` command: - - dclient alias add content https://datasette.io/content - -You can list aliases with `dclient alias list`: - - $ dclient alias list - content = https://datasette.io/content - -Once registered, you can pass an alias to commands such as `dclient query`: - - dclient query content "select * from news limit 1" - -### dclient alias --help - - -``` -Usage: dclient alias [OPTIONS] COMMAND [ARGS]... - - Manage aliases for different instances - -Options: - --help Show this message and exit. - -Commands: - add Add an alias - list List aliases - remove Remove an alias - -``` - - -### dclient alias list --help - - -``` -Usage: dclient alias list [OPTIONS] - - List aliases - -Options: - --json Output raw JSON - --help Show this message and exit. - -``` - - -### dclient alias add --help - - -``` -Usage: dclient alias add [OPTIONS] NAME URL - - Add an alias - -Options: - --help Show this message and exit. - -``` - - -### dclient alias remove --help - - -``` -Usage: dclient alias remove [OPTIONS] NAME - - Remove an alias - -Options: - --help Show this message and exit. - -``` - +Visit **[dclient.datasette.io](https://dclient.datasette.io)** for full documentation on using this tool. ## Development diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..a279768 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,23 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = sqlite-utils +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) + +livehtml: + sphinx-autobuild -b html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(0) diff --git a/docs/_templates/base.html b/docs/_templates/base.html new file mode 100644 index 0000000..47a8bc3 --- /dev/null +++ b/docs/_templates/base.html @@ -0,0 +1,6 @@ +{%- extends "!base.html" %} + +{% block site_meta %} +{{ super() }} + +{% endblock %} diff --git a/docs/aliases.md b/docs/aliases.md new file mode 100644 index 0000000..6c0697f --- /dev/null +++ b/docs/aliases.md @@ -0,0 +1,106 @@ +# Aliases + +You can assign an alias to a Datasette database using the `dclient alias` command: + + dclient alias add content https://datasette.io/content + +You can list aliases with `dclient alias list`: + + $ dclient alias list + content = https://datasette.io/content + +Once registered, you can pass an alias to commands such as `dclient query`: + + dclient query content "select * from news limit 1" + +## dclient alias --help + +``` +Usage: dclient alias [OPTIONS] COMMAND [ARGS]... + + Manage aliases for different instances + +Options: + --help Show this message and exit. + +Commands: + add Add an alias + list List aliases + remove Remove an alias + +``` + + +## dclient alias list --help + + +``` +Usage: dclient alias list [OPTIONS] + + List aliases + +Options: + --json Output raw JSON + --help Show this message and exit. + +``` + + +## dclient alias add --help + + +``` +Usage: dclient alias add [OPTIONS] NAME URL + + Add an alias + +Options: + --help Show this message and exit. + +``` + + +## dclient alias remove --help + + +``` +Usage: dclient alias remove [OPTIONS] NAME + + Remove an alias + +Options: + --help Show this message and exit. + +``` + diff --git a/docs/authentication.md b/docs/authentication.md new file mode 100644 index 0000000..5f0bd18 --- /dev/null +++ b/docs/authentication.md @@ -0,0 +1,127 @@ +# Authentication + +`dclient` can handle API tokens for Datasette instances that require authentication. + +You can pass an API token to `query` using `-t/--token` like this: + +```bash +dclient query https://latest.datasette.io/fixtures "select * from facetable" -t dstok_mytoken +``` + +A more convenient way to handle this is to store tokens to be used with different URL prefixes. + +## Using stored tokens + +To always use `dstok_mytoken` for any URL on the `https://latest.datasette.io/` instance you can run this: +```bash +dclient auth add https://latest.datasette.io/ +``` +Then paste in the token and hit enter when prompted to do so. + +To list which URLs you have set tokens for, run the `auth list` command: +```bash +dclient auth list +``` +To delete the token for a specific URL, run `auth remove`: +```bash +dclient auth remove https://latest.datasette.io/ +``` + + +## dclient auth --help + +``` +Usage: dclient auth [OPTIONS] COMMAND [ARGS]... + + Manage authentication for different instances + +Options: + --help Show this message and exit. + +Commands: + add Add an authentication token for an alias or URL + list List stored API tokens + remove Remove the API token for an alias or URL + +``` + + +## dclient auth add --help + + +``` +Usage: dclient auth add [OPTIONS] ALIAS_OR_URL + + Add an authentication token for an alias or URL + + Example usage: + + dclient auth add https://datasette.io/content + + Paste in the token when prompted. + +Options: + --token TEXT + --help Show this message and exit. + +``` + + +## dclient auth list --help + + +``` +Usage: dclient auth list [OPTIONS] + + List stored API tokens + +Options: + --help Show this message and exit. + +``` + + +## dclient auth remove --help + + +``` +Usage: dclient auth remove [OPTIONS] ALIAS_OR_URL + + Remove the API token for an alias or URL + +Options: + --help Show this message and exit. + +``` + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..587ed19 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from subprocess import PIPE, Popen + +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# 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. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ["myst_parser", "sphinx_copybutton"] +myst_enable_extensions = ["colon_fence"] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "dclient" +copyright = "2023, Simon Willison" +author = "Simon Willison" + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +pipe = Popen("git describe --tags --always", stdout=PIPE, shell=True) +git_version = pipe.stdout.read().decode("utf8") + +if git_version: + version = git_version.rsplit("-", 1)[0] + release = git_version +else: + version = "" + release = "" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- 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 = "furo" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. + +html_theme_options = {} +html_title = "dclient" + +# 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 = [] + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = "dclient-doc" + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ( + master_doc, + "dclient.tex", + "dclient documentation", + "Simon Willison", + "manual", + ) +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ( + master_doc, + "dclient", + "dclient documentation", + [author], + 1, + ) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + master_doc, + "dclient", + "dclient documentation", + author, + "dclient", + " A client CLI utility for Datasette instances ", + "Miscellaneous", + ) +] diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..c18e4a8 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,93 @@ +# dclient + +[![PyPI](https://img.shields.io/pypi/v/dclient.svg)](https://pypi.org/project/dclient/) +[![Changelog](https://img.shields.io/github/v/release/simonw/dclient?include_prereleases&label=changelog)](https://github.com/simonw/dclient/releases) +[![Tests](https://github.com/simonw/dclient/workflows/Test/badge.svg)](https://github.com/simonw/dclient/actions?query=workflow%3ATest) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/dclient/blob/master/LICENSE) + +A client CLI utility for [Datasette](https://datasette.io/) instances + +## Installation + +Install `dclient` using `pip` (or [pipx](https://pipxproject.github.io/pipx/): + +```bash +pip install dclient +``` + +### As a Datasette plugin + +If you also have Datasette installed in the same environment it will register itself as a command plugin. + +This means you can run any of these commands using `datasette client` instead, like this: +```bash +datasette client --help +datasette client query https://latest.datasette.io/fixtures "select * from facetable limit 1" +``` +You can install it into Datasette this way using: + +```bash +datasette install dclient +``` +## Running queries + +You can run SQL queries against a Datasette instance like this: + +```bash +dclient query https://latest.datasette.io/fixtures "select * from facetable limit 1" +``` +Output: +```json +[ + { + "pk": 1, + "created": "2019-01-14 08:00:00", + "planet_int": 1, + "on_earth": 1, + "state": "CA", + "_city_id": 1, + "_neighborhood": "Mission", + "tags": "[\"tag1\", \"tag2\"]", + "complex_array": "[{\"foo\": \"bar\"}]", + "distinct_some_null": "one", + "n": "n1" + } +] +``` + +### dclient query --help + +``` +Usage: dclient query [OPTIONS] URL SQL + + Run a SQL query against a Datasette database URL + + Returns a JSON array of objects + +Options: + -t, --token TEXT API token + --help Show this message and exit. + +``` + + + +## Contents + +```{toctree} +--- +maxdepth: 3 +--- +aliases +authentication +``` diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..df90031 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,5 @@ +furo==2022.06.21 +sphinx-autobuild +sphinx-copybutton +myst-parser +cogapp