Skip to main content

A library to provide automatic paging for console output

Project description

autopage

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. 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 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 jammy and later, and for Debian 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. 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:

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:

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

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

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

autopage-0.5.1.tar.gz (31.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

autopage-0.5.1-py3-none-any.whl (29.8 kB view details)

Uploaded Python 3

File details

Details for the file autopage-0.5.1.tar.gz.

File metadata

  • Download URL: autopage-0.5.1.tar.gz
  • Upload date:
  • Size: 31.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.27.0 requests-toolbelt/0.9.1 tqdm/4.62.1 CPython/3.10.3

File hashes

Hashes for autopage-0.5.1.tar.gz
Algorithm Hash digest
SHA256 01be3ee61bb714e9090fcc5c10f4cf546c396331c620c6ae50a2321b28ed3199
MD5 a131cc1e1a8f35a16c55e55e2cc497c3
BLAKE2b-256 36b1e5a1c2ebeb64ccc9c2a4ae133f5955d9824482628ed4bf0331c73323f0de

See more details on using hashes here.

File details

Details for the file autopage-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: autopage-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 29.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.6.0 importlib_metadata/4.6.3 pkginfo/1.7.1 requests/2.27.0 requests-toolbelt/0.9.1 tqdm/4.62.1 CPython/3.10.3

File hashes

Hashes for autopage-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0fbf5efbe78d466a26753e1dee3272423a3adc989d6a778c700e89a3f8ff0d88
MD5 b38b325ceb533feb1ce222f78f8e5f0f
BLAKE2b-256 9befe9c31977ca09ebb9ef0e1c3d214f8f8392588de5ce37511bd1a9ad7ae5dc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page