ZetCode

Python Fire

last modified May 25, 2026

In this article, we show how to use the Fire module to create command-line interfaces (CLIs) in Python.

Fire is a Python library that automatically generates command-line interfaces from any Python object, including functions, classes, and modules.

With Fire, you can turn any Python component into a CLI with minimal effort. This makes it an excellent tool for automating the creation of CLIs for your scripts, libraries, and applications.

To install the Fire module, run:

$ pip install fire

With uv manager, you can install it with:

$ uv add fire

Simple CLI

The first example demonstrates how to create a simple CLI using Fire.

main.py
import fire

def greet(name="guest"):
    return f"Hello, {name}!"

if __name__ == '__main__':
    fire.Fire(greet)

In this program, we define a simple function greet that takes an optional argument name. Fire automatically generates a CLI for this function.

import fire

We import the Fire module.

def greet(name="guest"):
    return f"Hello, {name}!"

This is a simple function that greets the user. The name parameter has a default value of "guest"; it can be overridden by providing a command-line argument. Fire automatically handles the parsing of command-line arguments. In our case, the --name flag will be used to specify the name to greet.

if __name__ == '__main__':
    fire.Fire(greet)

When we pass the greet function to fire.Fire, Fire automatically turns the function's parameters into command-line arguments. The name parameter in greet(name="guest") can be provided in two different ways: as a flag or as a positional argument. Fire inspects the function signature and maps the values accordingly.

$ python main.py --name=Alice
Hello, Alice!

Fire matches --name=Alice to the name parameter and passes the value to the function.

If the user provides a value without a flag, Fire treats it as the first positional parameter:

$ python main.py Alice
Hello, Alice!

This is equivalent to calling greet("Alice") directly in Python.

$ python main.py
Hello, guest!

If no argument is provided, the default value "guest" is used.

$ python main.py --help
INFO: Showing help with the command 'main.py -- --help'.

NAME
    main.py

SYNOPSIS
    main.py <flags>

FLAGS
    --name=NAME

Fire also provides a --help flag to display information about the available options.

CLI with a class

In the next example, we create a CLI using a class.

main.py
import fire

class Calculator:

    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

    def multiply(self, a, b):
        return a * b

    def divide(self, a, b):
        return a / b

if __name__ == '__main__':
    fire.Fire(Calculator)

In this program, we define a Calculator class with four methods: add, subtract, multiply, and divide. Fire generates a CLI for the class, allowing us to call these methods from the command line.

class Calculator:

    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

    def multiply(self, a, b):
        return a * b

    def divide(self, a, b):
        return a / b

This is the Calculator class with four arithmetic methods.

if __name__ == '__main__':
    fire.Fire(Calculator)

We use fire.Fire to turn the Calculator class into a CLI. Fire automatically generates commands for each method in the class.

$ python main.py add 3 5
8
$ python main.py subtract 10 4
6
$ python main.py multiply 6 7
42
$ python main.py divide 20 4
5.0

We run the script with different commands and arguments to perform arithmetic operations.

Creating nested commands

Fire also supports nested commands, allowing you to create more complex CLIs.

main.py
import fire

class Math:
    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

class String:
    def concat(self, a, b):
        return a + b

    def repeat(self, a, times):
        return a * times

class CLI:
    def __init__(self):
        self.math = Math()
        self.string = String()

if __name__ == '__main__':
    fire.Fire(CLI)

In this program, we define two classes, Math and String, each with their own methods. We then create a CLI class that instantiates these classes as attributes. Fire generates a CLI with nested commands for each class.

class Math:
    def add(self, a, b):
        return a + b

    def subtract(self, a, b):
        return a - b

class String:
    def concat(self, a, b):
        return a + b

    def repeat(self, a, times):
        return a * times

These are the Math and String classes with their respective methods.

class CLI:
    def __init__(self):
        self.math = Math()
        self.string = String()

The CLI class instantiates the Math and String classes as attributes.

if __name__ == '__main__':
    fire.Fire(CLI)

We use fire.Fire to turn the CLI class into a CLI. Fire generates nested commands for the math and string attributes.

$ python main.py math add 3 5
8
$ python main.py string repeat falcon 3
falconfalconfalcon

We run the script with nested commands to perform operations from the Math and String classes.

CLI from dictionary

It is possible to derive commands from a dictionary.

main.py
import fire

def add(a, b):
    return a + b

def multiply(a, b):
    return a * b

commands = {
    'add': add,
    'multiply': multiply,
}

if __name__ == '__main__':
    fire.Fire(commands)

We define two functions. The functions are mapped to commands via a dictionary.

$ python main.py add 3 5
8
$ python main.py multiply 6 7
42

Fire exposes the dictionary keys as CLI commands, each mapped to the corresponding function.

Variable number of arguments

When we define a function with a parameter preceded by an asterisk (*), such as *elements, it means that the function can accept any number of positional arguments, which are then packed into a tuple.

main.py
import fire

def sort_elements(*elements):
    """Sort the given elements."""
    sorted_elements = sorted(elements)
    return sorted_elements

def uppercase_elements(*elements):
    """Convert the given elements to uppercase."""
    uppercased_elements = [element.upper() for element in elements]
    return uppercased_elements

commands = {
    'sort': sort_elements,
    'upper': uppercase_elements,
}

if __name__ == '__main__':
    fire.Fire(commands)

The program has two functions to sort and uppercase its elements.

$ py main.py sort war atom sky blue say pine
atom
blue
pine
say
sky
war
$ python main.py upper war atom sky blue say pine
WAR
ATOM
SKY
BLUE
SAY
PINE

Using an instance

Instead of passing a class, we can pass an instance. This allows us to preconfigure state that the CLI methods can use.

main.py
import fire

class BankAccount:

    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount
        return f"Deposited {amount}. New balance: {self.balance}"

    def withdraw(self, amount):
        if amount > self.balance:
            return "Insufficient funds"
        self.balance -= amount
        return f"Withdrew {amount}. New balance: {self.balance}"

    def status(self):
        return f"{self.owner}'s account balance: {self.balance}"

if __name__ == '__main__':
    account = BankAccount("John", 100)
    fire.Fire(account)

The BankAccount class holds state (owner name and balance). By passing a pre-configured instance to Fire, the CLI commands operate on a shared state throughout the session.

$ python main.py status
John's account balance: 100
$ python main.py deposit 50
Deposited 50. New balance: 150
$ python main.py withdraw 30
Withdrew 30. New balance: 120

Type hints for validation

Fire respects Python type hints and uses them to validate and convert arguments automatically.

main.py
import fire

def process_order(item: str, quantity: int, price: float):
    total = quantity * price
    return f"Order: {quantity} x {item} @ ${price:.2f} = ${total:.2f}"

if __name__ == '__main__':
    fire.Fire(process_order)

The function uses type hints for all parameters. Fire automatically converts the command-line arguments to the specified types.

$ python main.py --item=coffee --quantity=3 --price=2.50
Order: 3 x coffee @ $2.50 = $7.50

Boolean flags are also supported. A parameter with the bool type hint expects a --flag or --noflag syntax.

main.py
import fire

def build_project(name: str, optimized: bool = False, verbose: bool = False):
    status = f"Building {name}"
    if optimized:
        status += " (optimized)"
    if verbose:
        status += " [verbose mode]"
    return status

if __name__ == '__main__':
    fire.Fire(build_project)
$ python main.py --name=myapp
Building myapp
$ python main.py --name=myapp --optimized --verbose
Building myapp (optimized) [verbose mode]
$ python main.py --name=myapp --nooptimized
Building myapp

Using Fire with a module

Fire can also turn an entire module into a CLI, exposing all top-level functions and classes as commands.

main.py
import fire

def hello(name="World"):
    return f"Hello, {name}!"

def goodbye(name="World"):
    return f"Goodbye, {name}!"

class Converter:
    def to_upper(self, text: str):
        return text.upper()

    def to_lower(self, text: str):
        return text.lower()

if __name__ == '__main__':
    fire.Fire()

When fire.Fire() is called without arguments, it inspects the calling module and exposes all public functions and classes as commands. The Converter class becomes a nested command group.

$ python main.py hello John
Hello, John!
$ python main.py goodbye Alice
Goodbye, Alice!
$ python main.py Converter to_upper "hello world"
HELLO WORLD

Interactive mode

Fire supports an interactive REPL mode, which is useful for exploring the available commands and iteratively calling them.

$ python main.py -- --interactive
Fire is starting an interactive Python REPL.
...

In [1]: hello("Jane")
Out[1]: 'Hello, Jane!'

In [2]: Converter.to_upper("hello")
Out[2]: 'HELLO'

The -- --interactive flag drops you into an interactive Python session where all commands are directly available. You can inspect objects and call methods without restarting the script.

Using a value property

Fire exposes class properties as CLI arguments, allowing direct access to object attributes from the command line.

main.py
import fire

class Config:
    def __init__(self):
        self.host = "localhost"
        self.port = 8080
        self.debug = False

    def show(self):
        return f"Host: {self.host}, Port: {self.port}, Debug: {self.debug}"

if __name__ == '__main__':
    fire.Fire(Config)

Fire uses show as the default method and exposes the instance attributes as flags that can be set directly.

$ python main.py show
Host: localhost, Port: 8080, Debug: False
$ python main.py --host=0.0.0.0 --port=3000 --debug show
Host: 0.0.0.0, Port: 3000, Debug: True

Chaining methods

When a method returns self, Fire allows chaining multiple method calls in a single command.

main.py
import fire

class TextProcessor:

    def __init__(self, text=""):
        self.text = text

    def read(self, filename):
        with open(filename, 'r') as f:
            self.text = f.read()
        return self

    def strip(self):
        self.text = self.text.strip()
        return self

    def upper(self):
        self.text = self.text.upper()
        return self

    def result(self):
        return self.text

if __name__ == '__main__':
    fire.Fire(TextProcessor)

Each method returns self, enabling method chaining. The final result method outputs the processed text.

$ echo "  hello world  " > data.txt
$ python main.py read data.txt strip upper result
HELLO WORLD

Source

Python Fire guide

In this article, we have worked with the Python Fire module to create command-line interfaces (CLIs) in Python.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.