invoke

repository·main·Indexed 26 days ago

https://github.com/pyinvoke/invoke

A Python library for managing shell-oriented subprocesses and organizing executable Python code into CLI-invokable tasks, drawing inspiration from tools like make and rake. Version 3.0.3 provides utilities for executing shell commands via run() and sudo(), organizing tasks into namespaces using the Collection class, and managing hierarchical configuration through the Config and Context classes.

Tokens
22.1K
Snippets
52
Records
150
Agent score
88%

What's inside invoke

  1. Overview of Invoke

    main

    Invoke is a Python library designed for two primary purposes:

    1. Managing shell-oriented subprocesses.
    2. Organizing executable Python code into CLI-invokable tasks.

    It is inspired by tools like make and rake to provide a clean and powerful interface for task automation.

  2. Explore Invoke concepts and API

    main
    For deep dives into specific architectural topics or detailed technical specifications, consult the Concepts and API documentation sections. The API documentation is auto-generated and provides exhaustive details on all public interfaces.
  3. Understand the Invoke command-line parsing framework structure

    main

    The command-line parsing framework in Invoke is organized into three primary sub-modules. When working with low-level parsing logic, you will interact with these components:

    • parser.argument: Handles individual argument definitions.
    • parser.context: Manages the parsing context (note: this is distinct from the top-level invoke.context).
    • parser.parser: The core parsing engine.

    Refer to the specific API documentation for each sub-module to implement custom parsing logic or extend command-line behavior.

  4. Prevent Invoke from exiting on non-zero command exit codes

    main
    By default, if an Invoke run command returns a non-zero exit code, Invoke will immediately halt execution and exit with that same code. If you want to handle failures gracefully (for example, if a tool like pylint returns a non-zero code for warnings but you want the task to continue), use the warn=True flag. You can then inspect the .exited attribute of the returned result object to check the status manually.
  5. Use `pty=True` to fix command behavior and output buffering

    main

    If a command behaves differently under Invoke than it does in a manual shell (e.g., missing colors, incorrect line lengths, or missing password prompts), or if output from a Python script appears all at once at the end of execution instead of line-by-line, use the pty=True flag in your run call. This forces the command to run in a pseudo-terminal (PTY), which mimics an interactive terminal session.

    Common use cases for pty=True:

    • Enabling colored output in terminal-aware programs.
    • Fixing output buffering in Python scripts.
    • Enabling password prompts (e.g., from getpass) that write directly to the TTY.
    • Resolving err: stdin: is not a tty errors.
    run("python foo", pty=True)
  6. Configure Invoke using configuration files

    main

    Invoke searches for configuration files in several locations. For each location, it looks for files with the following extensions in this specific order: .yaml, .yml, .json, or .py. It loads the first one it finds and ignores the rest.

    Supported formats include:

    YAML

    debug: true
    run:
        echo: true

    JSON

    {
        "debug": true,
        "run": {
            "echo": true
        }
    }

    Python

    debug = True
    run = {
        "echo": True
    }
    debug: true
    run:
        echo: true
  7. Define and organize tasks in a tasks.py file

    main

    Invoke allows you to define shell commands and organized task functions within a tasks.py file using the @task decorator. Each task function must accept a context object (conventionally named c) as its first argument. You can define task parameters which Invoke will automatically expose as command-line flags.

    from invoke import task
    
    @task
    def clean(c, docs=False, bytecode=False, extra=""):
        patterns = ["build"]
        if docs:
            patterns.append("docs/_build")
        if bytecode:
            patterns.append("**/*.pyc")
        if extra:
            patterns.append(extra)
        for pattern in patterns:
            c.run(f"rm -rf {pattern}")
    
    @task
    def build(c, docs=False):
        c.run("python setup.py build")
        if docs:
            c.run("sphinx-build docs docs/_build")
  8. Discover task modules automatically

    main

    By default, running the invoke command triggers a search for a Python module or package named tasks. Invoke treats this as the root namespace.

    Invoke searches for the tasks module in this order:

    1. It checks if a module named tasks already exists on Python's sys.path.
    2. If not found, it searches from the current working directory towards the filesystem root, temporarily adding each directory to sys.path until a candidate is found.

    Note on precedence: If both a package directory (tasks/ with an __init__.py) and a module file (tasks.py) exist in the same location, Invoke will favor the package directory.

  9. Use tab completion for tasks and flags

    main

    Once the completion script is active, you can use the Tab key to accelerate your workflow:

    • Task Names: Tabbing after typing inv or invoke will list available tasks from your current project's tasks file.
    • Flags and Options: Tabbing after a dash (-) or double dash (--) will display valid options. If no task has been typed yet, it shows core Invoke options; otherwise, it shows options for the most recently typed task.
    • Partial Options: You can type a partial long option (e.g., --e<tab>) to complete it (e.g., --echo).
    • Value Completion: If a flag requires a value (e.g., --config <tab>), hitting Tab will trigger your shell's native filename completion to help you select a file.
  10. Generate shell tab completion scripts for Invoke

    main

    Invoke provides a --print-completion-script flag to generate ready-made wrapper scripts for common shells like bash and zsh. These scripts allow your shell to dynamically query Invoke for task names and valid flags using the --complete core option.

    To generate a script for a specific shell, run the command with the desired shell name as an argument. Replace inv with your specific binary name if you are using a tool that inherits from Invoke (like fab).