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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
In this article, we have worked with the Python Fire module to create command-line interfaces (CLIs) in Python.
Author
List all Python tutorials.