This guide introduces the core concepts of dags and shows you how to get started.
Core Concept¶
dags works by analyzing function signatures to build a dependency graph. If a function has a parameter named x, and another function is named x, then the first function depends on the second.
def x():
return 1
def y(x): # depends on x because parameter is named "x"
return x + 1Basic Usage¶
Creating a Combined Function¶
The main entry point is concatenate_functions:
import dags
def income():
return 50000
def tax_rate():
return 0.3
def tax(income, tax_rate):
return income * tax_rate
def net_income(income, tax):
return income - tax
# Combine all functions
combined = dags.concatenate_functions(
functions={"income": income, "tax_rate": tax_rate, "tax": tax, "net_income": net_income},
targets=["net_income", "tax"],
return_type="dict",
)
result = combined()
# result = {"net_income": 35000.0, "tax": 15000.0}Providing External Inputs¶
Functions can have parameters that are not provided by other functions. These become inputs to the combined function:
def tax(income, tax_rate):
return income * tax_rate
def net_income(income, tax):
return income - tax
combined = dags.concatenate_functions(
functions={"tax": tax, "net_income": net_income},
targets=["net_income"],
return_type="dict",
)
# income and tax_rate are external inputs
result = combined(income=50000, tax_rate=0.3)
# result = {"net_income": 35000.0}Return Types¶
By default, concatenate_functions returns a tuple. You can also get a dictionary:
# Default: returns tuple
combined = dags.concatenate_functions(
functions=functions,
targets=["a", "b", "c"],
)
a, b, c = combined()
# Returns dictionary with target names as keys
combined = dags.concatenate_functions(
functions=functions,
targets=["a", "b", "c"],
return_type="dict",
)
result = combined() # {"a": ..., "b": ..., "c": ...}Inspecting the DAG¶
Use create_dag to create and inspect the dependency graph:
import dags
dag = dags.create_dag(
functions={"income": income, "tax": tax, "net_income": net_income},
targets=["net_income"],
)
# dag is a networkx.DiGraph
print(list(dag.nodes())) # ['income', 'tax', 'net_income']
print(list(dag.edges())) # [('income', 'tax'), ('tax', 'net_income'), ...]Finding Dependencies¶
Use get_ancestors to find all functions that a target depends on:
ancestors = dags.get_ancestors(
functions=functions,
targets=["net_income"],
)
# Returns set of all function names that net_income depends onWorking with Annotations¶
Getting Function Arguments¶
get_free_arguments returns the parameter names of a function:
def my_func(a, b, c=1):
return a + b + c
args = dags.get_free_arguments(my_func)
# args = ["a", "b", "c"]Getting Type Annotations¶
get_annotations returns type annotations:
def my_func(a: int, b: float) -> float:
return a + b
annotations = dags.get_annotations(my_func)
# annotations = {"a": int, "b": float, "return": float}Renaming Arguments¶
Use rename_arguments to change parameter names:
def original(x, y):
return x + y
renamed = dags.rename_arguments(original, mapper={"x": "a", "y": "b"})
# renamed now has signature (a, b) instead of (x, y)This is useful when integrating functions from different sources that use different naming conventions.
Next Steps¶
Learn about common usage patterns from real projects
Explore tree structures for nested data