Skip to main content
Facts are pyinfra’s mechanism for collecting information about remote systems. They enable operations to make intelligent decisions by querying current state before generating commands. This guide will teach you how to write custom facts.

Understanding Facts

Facts in pyinfra:
  • Execute commands on remote hosts and process the output
  • Cache results to avoid redundant command execution
  • Can accept parameters to customize behavior
  • Return structured data (strings, lists, dicts, or custom types)
  • Are defined as classes inheriting from FactBase

Basic Fact Structure

Here’s a simple fact definition based on patterns from src/pyinfra/facts/server.py:23:

The FactBase Class

All facts inherit from FactBase, defined in src/pyinfra/api/facts.py:53:

Creating Facts with Parameters

Facts can accept parameters to customize their behavior:
Usage in operations:

Processing Command Output

The process method converts command output into structured data. Here’s an example from the file facts:

Setting Default Values

Provide sensible defaults when facts cannot be determined:

Complex Facts: Returning Structured Data

Facts can return complex data structures like dictionaries:

Facts with Multiple Commands

Some facts need to try multiple commands for cross-platform compatibility:

Using StringCommand for Complex Commands

For commands with complex quoting or structure, use StringCommand:

ShortFactBase: Derived Facts

Create facts that derive their value from other facts:

Complete Example: Service Status Fact

Here’s a complete fact that checks service status:
Usage:

Error Handling in Facts

Handle errors gracefully:

Shell Executable Override

Override the shell for platform-specific facts:

Testing Facts

Test facts during development:

Best Practices

  1. Use type hints: Specify the return type with FactBase[T] for better IDE support
  2. Provide defaults: Always implement default() for graceful fallback
  3. Handle missing commands: Use requires_command() for command dependencies
  4. Parse robustly: Handle edge cases in process() - empty output, malformed data, etc.
  5. Cache-friendly: Facts are cached by parameters, so ensure parameters uniquely identify the result
  6. Cross-platform: Consider using command fallbacks for Linux/BSD/macOS compatibility
  7. Document return types: Clearly document what the fact returns and when it returns None/default
  8. Quote paths: Use QuoteString for file paths that might contain spaces
  9. Error messages: Raise FactProcessError with helpful messages when processing fails
  10. Test thoroughly: Test facts on all target platforms with various edge cases

Fact Naming Convention

Facts are automatically named as module.ClassName:

Next Steps