Move documentation to ReadTheDocs, refs #7

This commit is contained in:
Simon Willison 2023-07-17 16:39:39 -07:00
commit 7ee22a8a5e
10 changed files with 576 additions and 187 deletions

37
Justfile Normal file
View file

@ -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 .

191
README.md
View file

@ -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
<!-- [[[cog
import cog
from dclient import cli
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(cli.cli, ["query", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(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.
```
<!-- [[[end]]] -->
## 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
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["alias", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(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
```
<!-- [[[end]]] -->
### dclient alias list --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["alias", "list", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(help)
)
]]] -->
```
Usage: dclient alias list [OPTIONS]
List aliases
Options:
--json Output raw JSON
--help Show this message and exit.
```
<!-- [[[end]]] -->
### dclient alias add --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["alias", "add", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(help)
)
]]] -->
```
Usage: dclient alias add [OPTIONS] NAME URL
Add an alias
Options:
--help Show this message and exit.
```
<!-- [[[end]]] -->
### dclient alias remove --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["alias", "remove", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(help)
)
]]] -->
```
Usage: dclient alias remove [OPTIONS] NAME
Remove an alias
Options:
--help Show this message and exit.
```
<!-- [[[end]]] -->
Visit **[dclient.datasette.io](https://dclient.datasette.io)** for full documentation on using this tool.
## Development

1
docs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
_build

23
docs/Makefile Normal file
View file

@ -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)

6
docs/_templates/base.html vendored Normal file
View file

@ -0,0 +1,6 @@
{%- extends "!base.html" %}
{% block site_meta %}
{{ super() }}
<script defer data-domain="dclient.datasette.io" src="https://plausible.io/js/plausible.js"></script>
{% endblock %}

106
docs/aliases.md Normal file
View file

@ -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
<!-- [[[cog
import cog
from dclient import cli
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(cli.cli, ["alias", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(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
```
<!-- [[[end]]] -->
## dclient alias list --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["alias", "list", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(help)
)
]]] -->
```
Usage: dclient alias list [OPTIONS]
List aliases
Options:
--json Output raw JSON
--help Show this message and exit.
```
<!-- [[[end]]] -->
## dclient alias add --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["alias", "add", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(help)
)
]]] -->
```
Usage: dclient alias add [OPTIONS] NAME URL
Add an alias
Options:
--help Show this message and exit.
```
<!-- [[[end]]] -->
## dclient alias remove --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["alias", "remove", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(help)
)
]]] -->
```
Usage: dclient alias remove [OPTIONS] NAME
Remove an alias
Options:
--help Show this message and exit.
```
<!-- [[[end]]] -->

127
docs/authentication.md Normal file
View file

@ -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
<!-- [[[cog
import cog
from dclient import cli
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(cli.cli, ["auth", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(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
```
<!-- [[[end]]] -->
## dclient auth add --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["auth", "add", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(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.
```
<!-- [[[end]]] -->
## dclient auth list --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["auth", "list", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(help)
)
]]] -->
```
Usage: dclient auth list [OPTIONS]
List stored API tokens
Options:
--help Show this message and exit.
```
<!-- [[[end]]] -->
## dclient auth remove --help
<!-- [[[cog
import cog
result = runner.invoke(cli.cli, ["auth", "remove", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(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.
```
<!-- [[[end]]] -->

174
docs/conf.py Normal file
View file

@ -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",
)
]

93
docs/index.md Normal file
View file

@ -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
<!-- [[[cog
import cog
from dclient import cli
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(cli.cli, ["query", "--help"])
help = result.output.replace("Usage: cli", "Usage: dclient")
cog.out(
"```\n{}\n```".format(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.
```
<!-- [[[end]]] -->
## Contents
```{toctree}
---
maxdepth: 3
---
aliases
authentication
```

5
docs/requirements.txt Normal file
View file

@ -0,0 +1,5 @@
furo==2022.06.21
sphinx-autobuild
sphinx-copybutton
myst-parser
cogapp