def test_updated_from_namespaces(): composer_child = Composer().update(a=lambda: 5, c=lambda b: b * 2).link(b="a") composer = (Composer().update_namespaces( x=composer_child, y=composer_child).link(outer_x="x__c", outer_y="y__c").update( final=lambda outer_x, outer_y: outer_x + outer_y)) assert composer.final() == 20
def generate_random_graph(graph_size=42): functions = [] def function_0(): return 42 functions.append(function_0) for i in range(1, graph_size): fn_name = f"function_{i}" num_args = randint(0, min(5, i - 1)) arg_names = set() while len(arg_names) < num_args: arg_name = f"function_{randint(0, i-1)}" if arg_name not in arg_names: arg_names.add(arg_name) if arg_names: body = " + ".join(arg_names) else: body = str(randint(0, 100)) exec( dedent(f""" def {fn_name}({', '.join(sorted(arg_names))}): return {body} """)) functions.append(locals()[fn_name]) return Composer().update(*functions)
def test_empty_kwargs(): a = 1 b = 2 result = a + b + sum(a * 5 for i in range(5)) def d(a, *d_, b, **c_): return a + sum(d_) + b + sum(c_.values()) composer = (Composer().update_parameters( a=1, b=2).update(**{f"d_{i}": lambda a: a * 5 for i in range(5)}).update(d)) assert composer.d() == result
def get_cheaper_cars(car_prices, your_car_price): df = car_prices return df[df.price < your_car_price] def get_savings_on_cheaper_cars(cheaper_cars, mean_car_price): return cheaper_cars.assign(savings=lambda df: mean_car_price - df.price) def get_burger_savings(savings_on_cheaper_cars, price_of_a_burger): return savings_on_cheaper_cars.assign( burgers_saved=lambda df: df.savings / price_of_a_burger) def get_savings_histogram(burger_savings): return px.histogram(burger_savings, x="burgers_saved") f = (Composer().update_without_prefix( "get_", get_car_prices, get_cheaper_cars, get_mean_car_price, get_savings_on_cheaper_cars, get_burger_savings, get_savings_histogram, ).update_parameters(your_car_price=(int, 100_000), price_of_a_burger=(float, 100)))
def test_updated_from_links(): composer_a = Composer().update(a=lambda: 5, c=lambda b: b * 2).link(b="a") composer_b = Composer().update_from(composer_a).update(d=lambda b: b * 3) assert composer_b.d() == 15
def test_basic_links(): composer = Composer().update(a=lambda: 5, c=lambda b: b * 2).link(b="a") assert composer.c() == 10
def test_call_link(): composer = Composer().update(a=lambda: 5, c=lambda b: b * 2).link(b="a") assert composer.b() == 5
def function_37(): return 19 def function_38(function_33, function_34): return function_34 + function_33 def function_39(function_1, function_10, function_25): return function_25 + function_1 + function_10 def function_40(function_21, function_24, function_33): return function_21 + function_33 + function_24 def function_41(function_18): return function_18 #%% scope = locals() functions = [ scope[f"function_{i}"] for i in range(42) if f"function_{i}" in scope ] large_graph = (Composer().update(*functions).link(function_8="function_7", function_9="function_5"))
"An example with a broken composer." #%% from pathlib import Path from random import choice, random import pandas as pd import numpy as np import plotly.express as px import math from fn_graph import Composer prices = [random() * 100_000 + 50000 for _ in range(10)] f = (Composer().update( wave=lambda frequency, amplitude: pd.DataFrame(dict(x=range(501))).assign( y=lambda df: amplitude * np.cos(df.x / 500 * math.pi * 3) * np.sin( df.x / 500 * math.pi * frequency)), plot=lambda wave: px.line(wave, x="x", y="y"), broken=lambda wave, missing: wave, ).update_parameters(frequency=(float, 1), amplitude=(float, 1))) # %%
return 5 def b(data, factor): return data * factor def c(b): return b def combined_result(child_one__c, child_two__c): pass child = Composer().update(b, c) parent = (Composer().update_namespaces( child_one=child, child_two=child).update( data, combined_result).update_parameters(child_one__factor=3, child_two__factor=5)) # %% parent.graphviz() # %% # Link example def calculated_factor(data): return data / 2
# Introductory example def a(): return 5 def b(a): return a * 5 def c(a, b): return a * b composer = Composer().update(a, b, c) # Call any result composer.c() # 125 composer.a() # 5 composer.graphviz().render("intro.gv", format="png") # Some pure functions def get_car_prices(): df = pd.DataFrame( dict( model=[ choice(["corolla", "beetle", "ferrari"]) for _ in range(10) ],
def plot_total_market_cap(total_market_cap): """ Plot the total market cap """ return px.line(total_market_cap, x="datetime", y="market_cap") def plot_market_cap_changes(total_market_cap_change): """ Plot the market cap changes """ return px.bar( total_market_cap_change, x="datetime", y="market_cap_change", color="change_classification", ) f = (Composer().update_parameters(swing_threshold=0.1 * 10**12).update( share_prices, daily_share_prices, shares_in_issue, market_cap, total_market_cap, total_market_cap_change, plot_market_caps, plot_total_market_cap, plot_market_cap_changes, ))
def confusion_matrix(predictions, test_target): """ Show the confusion matrix """ cm = sklearn.metrics.confusion_matrix(test_target, predictions) return plot_confusion_matrix(cm, ["setosa", "versicolor", "virginica"]) f = ( Composer().update_parameters( # Parameter controlling the model type (ols, svc) model_type="olm", # Parameter enabling data preprocessing do_preprocess=True, ).update( iris, data, preprocess_data, investigate_data, split_data, training_features, training_target, test_features, test_target, model, predictions, classification_metrics, confusion_matrix, ))
def test_default_arguments(): composer = Composer().update(c=lambda a, b=3: a + b).update_parameters(a=1) assert composer.c() == 4 composer = Composer().update(c=lambda a, b=3: a + b).update_parameters(a=1, b=2) assert composer.c() == 3
def test_simple_parameters(): composer = (Composer().update(c=lambda a, b: a + b).update_parameters( a=1, b=(int, 2))) assert composer.c() == 3