218 lines
7.6 KiB
Plaintext
218 lines
7.6 KiB
Plaintext
|
Metadata-Version: 2.1
|
||
|
Name: autopage
|
||
|
Version: 0.5.1
|
||
|
Summary: A library to provide automatic paging for console output
|
||
|
Home-page: https://github.com/zaneb/autopage
|
||
|
Author: Zane Bitter
|
||
|
Author-email: zbitter@redhat.com
|
||
|
Classifier: License :: OSI Approved
|
||
|
Classifier: License :: OSI Approved :: Apache Software License
|
||
|
Classifier: Programming Language :: Python :: 3
|
||
|
Classifier: Programming Language :: Python :: 3 :: Only
|
||
|
Classifier: Programming Language :: Python :: 3.6
|
||
|
Classifier: Programming Language :: Python :: 3.7
|
||
|
Classifier: Programming Language :: Python :: 3.8
|
||
|
Classifier: Programming Language :: Python :: 3.9
|
||
|
Classifier: Programming Language :: Python :: 3.10
|
||
|
Classifier: Operating System :: POSIX
|
||
|
Classifier: Environment :: Console
|
||
|
Classifier: Intended Audience :: Developers
|
||
|
Classifier: Topic :: Software Development :: Libraries
|
||
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||
|
Classifier: Topic :: Terminals
|
||
|
Classifier: Topic :: Utilities
|
||
|
Requires-Python: >=3.6
|
||
|
Description-Content-Type: text/markdown
|
||
|
License-File: LICENSE
|
||
|
|
||
|
# autopage
|
||
|
|
||
|
[Autopage](https://github.com/zaneb/autopage) is a Python library to
|
||
|
automatically display terminal output from a program in a pager (like `less`)
|
||
|
whenever you need it, and never when you don't. And it only takes one line of
|
||
|
code.
|
||
|
|
||
|
You know how some CLI programs like `git` (and a handful of others, including
|
||
|
`man` and `systemctl`) automatically pipe their output to `less`? Except not if
|
||
|
there's less than one screen's worth of data. And if you redirect the output to
|
||
|
a file or a pipe, it does the right thing instead. Colours are preserved. Don't
|
||
|
you wish all programs worked like that? Now at least all of your Python
|
||
|
programs can.
|
||
|
|
||
|
## License
|
||
|
|
||
|
© 2020-2022 by Zane Bitter
|
||
|
|
||
|
Open Source licensed under the terms of the Apache Software License, version
|
||
|
2.0.
|
||
|
|
||
|
## Installation
|
||
|
|
||
|
[Autopage is available from PyPI](https://pypi.org/project/autopage/). The
|
||
|
easiest way to install (preferably in a `virtualenv` virtual environment) is
|
||
|
with `pip`:
|
||
|
|
||
|
$ pip install autopage
|
||
|
|
||
|
### On Fedora and CentOS/RHEL
|
||
|
|
||
|
Autopage is [packaged for
|
||
|
Fedora](https://packages.fedoraproject.org/pkgs/python-autopage/python3-autopage/)
|
||
|
35 and later. To install:
|
||
|
|
||
|
# dnf install python3-autopage
|
||
|
|
||
|
Copr repositories are available for older versions of Fedora and EPEL. Before
|
||
|
attempting to install on those versions, first enable the copr repository:
|
||
|
|
||
|
# dnf copr enable zaneb/autopage
|
||
|
|
||
|
### On Ubuntu and Debian
|
||
|
|
||
|
Autopage is [packaged for
|
||
|
Ubuntu](https://packages.ubuntu.com/search?keywords=python3-autopage&searchon=names)
|
||
|
jammy and later, and [for Debian](https://packages.debian.org/python3-autopage)
|
||
|
bookworm. To install:
|
||
|
|
||
|
# apt-get install python3-autopage
|
||
|
|
||
|
A PPA is available for older versions of Ubuntu. Before attempting to install
|
||
|
on those versions, first enable the PPA:
|
||
|
|
||
|
# add-apt-repository ppa:zaneb/autopage
|
||
|
# apt-get update
|
||
|
|
||
|
### On Gentoo
|
||
|
|
||
|
Autopage is [packaged for
|
||
|
Gentoo](https://packages.gentoo.org/packages/dev-python/autopage). To install:
|
||
|
|
||
|
# emerge dev-python/autopage
|
||
|
|
||
|
## Basic Use
|
||
|
|
||
|
The `AutoPager` class provides a context manager that furnishes the output
|
||
|
stream to write to. Here is a basic example that reads from stdin and outputs
|
||
|
to a pager connected to stdout:
|
||
|
|
||
|
```python
|
||
|
import sys
|
||
|
import autopage
|
||
|
|
||
|
with autopage.AutoPager() as out:
|
||
|
for l in sys.stdin:
|
||
|
out.write(l)
|
||
|
```
|
||
|
|
||
|
If you are explicitly passing a stream to write to (rather than directly
|
||
|
referencing a global variable such as `sys.stdout` then you may be able to add
|
||
|
automatic paging support with only a single line of code.
|
||
|
|
||
|
## Paging help output
|
||
|
|
||
|
If your program uses the `argparse` module from the standard library, you can
|
||
|
ensure that the help output is automatically paged when possible by changing
|
||
|
the import statement to:
|
||
|
|
||
|
```python
|
||
|
from autopage import argparse
|
||
|
```
|
||
|
|
||
|
If you don't control the module that imports `argparse`, you can instead call
|
||
|
`autopage.argparse.monkey_patch()` to patch the module directly. This function
|
||
|
can also be used as a context manager.
|
||
|
|
||
|
## Environment
|
||
|
|
||
|
The default pager command (`autopage.command.DefaultPager()`) allows the end
|
||
|
user to override the pager command by setting the `PAGER` environment variable.
|
||
|
To disable this behaviour, pass
|
||
|
`pager_command=autopage.command.PlatformPager()` to use the default pager for
|
||
|
the current platform, or pass a specific pager from `autopage.commands`. The
|
||
|
default pager command is `less` on most platforms. On AIX the default pager
|
||
|
command is `more`, and on Windows `more.com`.
|
||
|
|
||
|
The end user can also override the settings for `less` by setting the `LESS`
|
||
|
environment variable. If not specified, the settings are determined by the
|
||
|
`allow_color` and `line_buffering` options. By default ANSI control characters
|
||
|
for setting colours are respected and the pager will not run if there is less
|
||
|
than a full screen of text to display.
|
||
|
|
||
|
## Line buffering
|
||
|
|
||
|
Normally output streams are buffered so that data is written to the output file
|
||
|
only when the buffer becomes full. This is efficient and generally works fine
|
||
|
as long as the data is being produced as fast as it can be consumed. However,
|
||
|
when the data is streaming at a slower rate than it could be displayed (e.g.
|
||
|
log output from something like `tail -f`) this results in a large delay between
|
||
|
data being produced and consumed. If you have ever tried to grep a streaming
|
||
|
log and pipe the output to a pager then you are familiar with how
|
||
|
unsatisfactory this is.
|
||
|
|
||
|
The solution is to flush the output buffer after each line is written, which is
|
||
|
known as [line
|
||
|
buffering](https://www.pixelbeat.org/programming/stdio_buffering/). The
|
||
|
`AutoPager` class supports a `line_buffering` argument to enable or disable
|
||
|
line buffering. The default is to use the line buffering mode already
|
||
|
configured for the output stream (which is usually to disable line buffering).
|
||
|
|
||
|
When reading from an input stream (which may be a file, pipe, or the console)
|
||
|
and optionally processing the data before outputting it again, the convenience
|
||
|
function `line_buffer_from_input()` returns the optimal line buffering setting
|
||
|
for a given input stream (`sys.stdin` by default).
|
||
|
|
||
|
```python
|
||
|
import sys
|
||
|
import autopage
|
||
|
|
||
|
with autopage.AutoPager(line_buffering=line_buffer_from_input()) as out:
|
||
|
for l in sys.stdin:
|
||
|
out.write(l)
|
||
|
```
|
||
|
|
||
|
## Terminal reset
|
||
|
|
||
|
By default, when the pager exits it will leave the latest displayed output on
|
||
|
screen in the terminal. This can be changed by passing `True` for the
|
||
|
`reset_on_exit` argument to the `AutoPager` class. If this option is set, the
|
||
|
terminal will be cleared when the pager exits, returning to its position prior
|
||
|
to starting the pager (as is the case by default when running `less` manually
|
||
|
from the command line).
|
||
|
|
||
|
## Exit code
|
||
|
|
||
|
Programs may wish to return a different exit code if they are interrupted by
|
||
|
the user (either with Ctrl-C or by closing the pager) than if they ran to
|
||
|
completion. The exceptions generated when the pager is closed prematurely are
|
||
|
suppressed, so the `AutoPager` class offers the `exit_code()` method to provide
|
||
|
a suitable exit code for the program. This also takes into account other
|
||
|
exceptions that bubble up through the context manager.
|
||
|
|
||
|
## Complete Example
|
||
|
|
||
|
```python
|
||
|
import sys
|
||
|
import autopage
|
||
|
|
||
|
def process(input_stream, output_stream):
|
||
|
pager = autopage.AutoPager(
|
||
|
output_stream,
|
||
|
line_buffering=autopage.line_buffer_from_input(input_stream),
|
||
|
allow_color=True,
|
||
|
reset_on_exit=True,
|
||
|
errors=autopage.ErrorStrategy.REPLACE,
|
||
|
)
|
||
|
|
||
|
try:
|
||
|
with pager as out:
|
||
|
for l in input_stream:
|
||
|
out.write(l)
|
||
|
except Exception as exc:
|
||
|
sys.stderr.write(f'{str(exc)}\n')
|
||
|
except KeyboardInterrupt:
|
||
|
pass
|
||
|
return pager.exit_code()
|
||
|
|
||
|
sys.exit(process(sys.stdin, sys.stdout))
|
||
|
```
|