Funcflow

Tools are for basic operations with mappings and iterables. Chaining support to avoid intermediate variables. Inspired by Underscore.js: https://underscorejs.org. Despite that, a lot of methods have different naming and behaviour.

class fairways.funcflow.Chain(data)[source]

Chainable object which allow to return new instance of Chain after most operations of FuncFlow.

Parameters:object (Mapping | Iterable) – Source object
saveto(writer, slice=None)[source]

Helper which allows to output intermediate result using writer function.

Parameters:
  • writer (Callable[Any]) – Function which outputs the current value of chain somwhere (console, file, etc)
  • slice (int, optional) – Count of elements to limit output length, defaults to None
Returns:

chain object itself, without modification

Return type:

funcflow.Chain

value

Unwrap value of chain object

Returns:Current value of chain object
Return type:Any
class fairways.funcflow.FuncFlow[source]

This class contains functions to operate with mappings and iterables.

static apply(object, func)[source]

Apply function to entire object at once. Wrapper for chaining

Parameters:
  • object (Mapping | Iterable) – Source object
  • func (Callable(Any) -> Any) – Function to apply
Returns:

Result of the specified function

Return type:

Any

static chain(object)[source]

Wraps value in a chainable object which allows to apply FuncFlow methods sequentially. To unwrap the result, use .value property

Parameters:object (Any) – Source object
Returns:Chainable object
Return type:funcflow.Chain
static contains(iterable, value)[source]

Test whether iterable contains specified value

Parameters:
  • iterable (Iterable) – Source iterable
  • value (Any) – Value to search
Returns:

Result of test

Return type:

bool

>>> FuncFlow.contains([1, 2, 3], 3)
True
>>> FuncFlow.contains([1, 2, 3], 1000)
False
static copy(iterable)[source]

Make deep copy of iterable. Wrapper for chaining. Uses Python copy.deepcopy. Note that the source should support pickle operation

Parameters:iterable (Iterable) – Source iterble
Returns:New copy
Return type:Iterable
static count_by(iterable, iterfunc)[source]

Count items with grouping in accordance with rules

Parameters:
  • iterable (Iterable) – Source iterable
  • iterfunc (Callable) – Function which map item to some group
Returns:

Mapping where keas are groups and values are items count per group

Return type:

Dict

>>> FuncFlow.count_by([1, 2, 3, 4, 5], lambda num: 'even' if num % 2 == 0 else 'odd')
{'odd': 3, 'even': 2}
static deep_extend(*args)[source]

Deep copy of each item into leftmost argument When attribute itself is a mapping or iterable, it would be copied recursively

Args:*args: Mapping items to combine their attributes from leftmost to rightmost step-by-step. Note that the leftmost item will be updated during this operation!
Raises:TypeError – Unsupported type
Returns:Mapping where attributes are combined, rightmost args have higher precedence
Return type:Mapping
>>> FuncFlow.deep_extend({}, {'name': 'moe'}, {'age': 50}, {'name': 'new'}, {'nested':{'some': 1}})
{'name': 'new', 'age': 50, 'nested': {'some': 1}}
static each(iterable, iterfunc)[source]

Apply iterable to each item. Note that this function returns no result!

Parameters:
  • iterable (Iterable[Any]) – Source iterable
  • iterfunc (Callable(Any, Any, Iterable) -> None) – Iterator function which receives 3 arguments -value, index or key, and the source iterable itself
static every(iterable, iterfunc)[source]

Returns true if all of the values in the list pass the predicate truth test

Parameters:
  • iterable (Iterable) – Source
  • iterfunc (Callable(Any) -> bool) – Function which tests item and returns boolean value
Returns:

Test result

Return type:

bool

>>> FuncFlow.every([2, 4, 5], lambda num: num % 2 == 0)
False
>>> FuncFlow.every([3, 6, 9], lambda num: num % 3 == 0)
True
static extend(*args)[source]

Swallow copy of each item. When attribute itself is a mapping or iterable, it would be copied “by reference”

Args:*args: Mapping items to combine their attributes from leftmost to rightmost step-by-step. Note that the leftmost item will be updated during this operation!
Returns:Mapping where attributes are combined, rightmost args have higher precedence
Return type:Mapping
>>> FuncFlow.extend({}, {'name': 'moe'}, {'age': 50}, {'name': 'new'})
{'name': 'new', 'age': 50}
static filter(iterable, iterfunc)[source]

Filter iterable members with a rule defined as a function

Parameters:
  • iterable (Iterable) – Source iterable
  • iterfunc (Callable) – Rule to filter items, should return Truish value to select item into result
Returns:

Filtered subset

Return type:

list

>>> FuncFlow.filter([1, 2, 3, 4, 5, 6], lambda v: v % 2 == 0)
[2, 4, 6]
static find(iterable, iterfunc)[source]

Looks through each value in the list, returning the first one that passes a truth test (predicate), or None if no value passes the test.

Parameters:
  • iterable (Iterable) – Source iterable
  • iterfunc (Callable(Any) -> bool) – Function which tests item and returns boolean value
Returns:

First item which meets criteria

Return type:

Any

>>> FuncFlow.find([1, 2, 3, 4, 5, 6], lambda num: num % 2 == 0)
2
static find_where(iterable, **properties)[source]

Looks through the list and returns the first value that matches all of the key-value pairs listed in properties

Parameters:iterable (Iterable) – Source iterable
Returns:First item which meets criteria
Return type:Any
>>> test_data = [
...    {"name":"John", "age":25, "occupation":"soldier"},
...    {"name":"Jim", "age":30, "occupation":"actor"},
...    {"name":"Jane", "age":25, "occupation":"soldier"},
...    {"name":"Joker", "age":50, "occupation":"actor"},
...    {"name":"Jarvis", "age":100, "occupation":"mad scientist"},
...    {"name":"Jora", "age":5, "occupation":"child"}]
>>> criteria = {"age": 25, "occupation":"soldier"}
>>> FuncFlow.find_where(test_data, **criteria)
{'name': 'John', 'age': 25, 'occupation': 'soldier'}
static group_by(iterable, iteratee)[source]

Splits a collection into sets, grouped by the result of running each value through iteratee. If iteratee is a string instead of a function, groups by the property named by iteratee on each of the values

Parameters:
  • iterable (Iterable) – Source iterable
  • iteratee (Callable(Any) -> Any) – Function which returns group for item (or a string name of key to group by it)
Raises:

TypeError – Throws exception if second argument neither callable nor string

Returns:

Mapping where keys are groups and values are lists of related items

Return type:

Dict

>>> FuncFlow.group_by(["London", "Paris", "Lisbon", "Perth"], lambda s: s[:1])
{'L': ['London', 'Lisbon'], 'P': ['Paris', 'Perth']}
static index_by(iterable, iteratee)[source]

Given an iterable, and an iteratee function that returns a key for each element (or a property name), returns a dict with a key of each item. Just like group_by, but for when you know your keys are unique.

Parameters:
  • iterable (Iterable) – Source iterable
  • iteratee (Callable(Any) -> Any) – Function which returns key for item (or a string name of key to index by it)
Raises:

TypeError – Throws exception if second argument neither callable nor string

Returns:

Mapping where keys are groups and values are lists of related items

Return type:

Dict

static map(iterable, iterfunc=None)[source]

Build new iterable where each item modified by function providen

Parameters:
  • iterable (Iterable) – Source iterable
  • iterfunc (Callable(Any) -> Any) – Function which computes new item value using previous one
Returns:

Entirely new list with modified items

Return type:

list

>>> FuncFlow.map([1, 2, 3, 4, 5, 6], lambda num: num * 2)
[2, 4, 6, 8, 10, 12]
>>> FuncFlow.map({"a":1, "b":2, "c":3, "d":4, "e":5, "f":6}, lambda num, k: num * 2)
{'a': 2, 'b': 4, 'c': 6, 'd': 8, 'e': 10, 'f': 12}
static omit(data, *keys)[source]

Build dict from the source mapping, without specified keys

Parameters:
  • data (Mapping) – Source mapping
  • *keys – List of keys which should not present in result
Returns:

Mapping where

Return type:

Dict

>>> FuncFlow.omit({'name': 'moe', 'age': 50, 'userid': 'moe1'}, 'userid')
{'name': 'moe', 'age': 50}
static pick(data, *keys)[source]

Build dict from the source mapping, with specified keys only. This is opposite operation for omit.

Parameters:
  • data (Mapping) – Source mapping
  • *keys – List of keys which should present in result
Returns:

Mapping where

Return type:

Dict

>>> FuncFlow.pick({'name': 'moe', 'age': 50, 'userid': 'moe1'}, 'name', 'age')
{'name': 'moe', 'age': 50}
static pluck(iterable, propname)[source]

Enumerate unique values of key for all items in iterable

Parameters:
  • iterable (Iterable[Mapping]) – Source iterable
  • propname (str) – Name of key
Returns:

List of unique values

Return type:

list

static reduce(iterable, iterfunc, memo)[source]

Compute single result from iterable using supplied function

Parameters:
  • iterable (Iterable) – Source iterable
  • iterfunc (Callable (Any, Any) -> Any) – Function which receives item from source iterable and current value of memo and returns memo updated
  • memo (Any) – Initial value of combined result
Returns:

Reduced item (its type depends on type of memo)

Return type:

Any

>>> FuncFlow.reduce([1, 2, 3], lambda memo, num: memo + num, 0)
6
static size(iterable)[source]

Return length of iterable

Parameters:iterable (Iterable) – Source iterable
Returns:Length
Return type:int
static sort_by(iterable, iterfunc)[source]

Sort items using function and return new list without modifications in a source one

Parameters:
  • iterable (Iterable[Any]) – Source iterable
  • iterfunc (Callable(Any) -> Any) – Function which maps item to any value which is suitable for ordering (int, str, …)
Returns:

New list

Return type:

list

static uniq(iterable)[source]

Make set of distinct values from Iterable

Parameters:iterable (Iterable) – Source iterable
Returns:List of unique values. Note that values can be out of order
Return type:list
>>> a = FuncFlow.uniq([1, 2, 1, 4, 1, 3])
>>> a.sort() # Note: order not guaranteed!
>>> a
[1, 2, 3, 4]
static weld(*args)[source]

Similar to deep_extend, but returns entirely new dict, wwithout modifications in a leftmost item.

Args:*args: Mapping items to combine their attributes from leftmost to rightmost step-by-step. All items will be unchanged.
Returns:Mapping where attributes are combined, rightmost args have higher precedence
Return type:Dict
>>> FuncFlow.weld({'name': 'moe'}, {'age': 50}, {'name': 'new'})
{'name': 'new', 'age': 50}
class fairways.funcflow.Lazy[source]

Chainable object which allow to return “lazy” or “frozen” sequence of operations for deferred invocation.

class fairways.funcflow.add_lazy(mapping_lambda)[source]

Decorator to register “lazy” option for method.

Parameters:mapping_lambda (callable) – Proxy (invocation protocol) which places “frozen” and “deferred” values in desired places. Two first (function and data) are pre-defined for dynamic values, remaining values are intended for frozen ones
Returns:Original function
Return type:callable