The fluently library provides several container data type implementations with fluent interfaces:
- a
listsubclass with a fluent interface - a
setsubclass with a fluent interface - a
tuplesubclass with a fluent interface
The Fluently library has been tested with Python 3.10, 3.11, 3.12, 3.13 and 3.14. The library is not compatible with Python 3.9 or earlier.
The Fluently library is available from PyPI, so may be added to a project's dependencies
via its requirements.txt file or similar by referencing the Fluently library's name,
fluently, or the library may be installed directly into your local runtime environment
using pip via the pip install command by entering the following into your shell:
$ pip install fluently
To use the Fluently library, import the library and the data type or data types you need and use them just like their regular counterparts, with the knowledge that they support fluent interfaces which can often be more convenient and expressive to use:
# The 'flulist' and 'flist' aliases can be used interchangeably with 'fluentlist'
from fluently import fluentlist, flulist, flist
# Create a new fluentlist instance
data = fluentlist(["A", "B", "C"])
# Assert that the list has the expected class identity, aliases and superclass
assert isinstance(data, fluentlist)
assert isinstance(data, flulist)
assert isinstance(data, flist)
assert isinstance(data, list)
# Assert that the list has the expected length
assert data.length() == len(data) == 3
# Assert that the list has the expected contents
assert "A" in data
assert "B" in data
assert "C" in data
# Append item in-place into original list, then create a new list of unique values
uniquedata = data.append("C").unique()
# Assert that the original list now contains the appended value
assert len(data) == 4
assert data == ["A", "B", "C", "C"]
# Assert that the unique list contains only the unique values
assert len(uniquedata) == 3
assert uniquedata == ["A", "B", "C"]# The 'fluset' and 'fset' aliases can be used interchangeably with 'fluentset'
from fluently import fluentset, fluset, fset
# Create a new fluentset instance
data = fluentset(["A", "B", "C"])
# Assert that the set has the expected class identity, aliases and superclass
assert isinstance(data, fluentset)
assert isinstance(data, fluset)
assert isinstance(data, fset)
assert isinstance(data, set)
# Assert that the set has the expected length
assert data.length() == len(data) == 3
# Assert that the set has the expected contents
assert "A" in data
assert "B" in data
assert "C" in data# The 'flutuple' and 'ftuple' aliases can be used interchangeably with 'fluenttuple'
from fluently import fluenttuple, flutuple, ftuple
# Create a new fluenttuple instance
data = fluenttuple(["A", "B", "C"])
# Assert that the tuple has the expected class identity, aliases and superclass
assert isinstance(data, fluenttuple)
assert isinstance(data, flutuple)
assert isinstance(data, ftuple)
assert isinstance(data, tuple)
# Assert that the tuple has the expected length
assert data.length() == len(data) == 3
# Assert that the tuple has the expected contents
assert "A" in data
assert "B" in data
assert "C" in dataThe Fluently library provides the following data type subclasses and each class offers
shorthand aliases that prefixes the superclass' name with flu or f to denote that
the class is its fluent variant. The aliases can be used interchangeably with the fully
qualified subclass names as they are direct aliases rather than further subclasses.
| Subclass | Superclass | Subclass Alias | Short Subclass Alias |
|---|---|---|---|
fluentlist |
list |
flulist |
flist |
fluentset |
set |
fluset |
fset |
fluenttuple |
tuple |
flutuple |
ftuple |
The Fluently library classes can be used interchangeably with their superclasses where one wishes to use a fluent chainable interface to interact with the container types. The classes offer all the usual functionality that their superclasses offer, and all the usual methods and interactions are available, in addition to the library provided fluent methods as documented below. All methods marked with the link symbol, π, can be chained.
The fluentlist class provides the following methods in addition to the methods provided
by the list superclass:
-
length()(int) β Thelength()method supports returning the total count of items in the current list. The method returns the count as anintvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluentlistmethods that do support chaining. -
clone()π (fluentlist) β Theclone()method supports creating a cloned copy of the current list, that contains the same items, in a separatefluentlistinstance. -
prepend(item: object)π (fluentlist) β Theprepend()method supports prepending the specified item to the start of the current list. -
append(item: object)π (fluentlist) β Theappend()method supports appending the specified item to the end of the current list. -
extend(iterable: object)π (fluentlist) β Theextend()method supports appending the specified items from the specifiediterableobject to the end of the current list. -
insert(index: int, item: object)π (fluentlist) β Theinsert()method supports appending the specified item into the current list at the specifiedindexposition. Theindexmust be in range of the current length of the list. -
remove(item: object, raises: bool = True)π (fluentlist) β Theremove()method supports removing the first occurrence of the specified item from the current list. If the specifieditemdoes not exist in the list, and if theraiseskeyword argument is set to its default value ofTrue, aValueErrorexception will be raised noting the absence of theitemvalue in the list. Ifraisesis set toFalseno exception will be raised, instead the error will be logged, visible via the standardlogginglibrary if the log level is set toERRORor higher. -
removeall(item: object, raises: bool = True)π (fluentlist) β Theremoveall()method supports removing all occurrences of the specified item from the current list. If the specifieditemdoes not exist in the list, and if theraiseskeyword argument is set to its default value ofTrue, aValueErrorexception will be raised noting the absence of theitemvalue in the list. Ifraisesis set toFalseno exception will be raised, instead the error will be logged, visible via the standardlogginglibrary if the log level is set toERRORor higher. -
discard(item: object)π (fluentlist) β Thediscard()method supports removing the first occurrence of the specifieditemfrom the current list if the item is present in the list. No error is raised if theitemdoes not exist in the list. Added for consistency with sets. -
clear()π (fluentlist) β Theclear()method supports clearing all of the items from the current list. -
repeat(count: int)π (fluentlist) β Therepeat()method supports repeating all the items from the current list by appending the items in the list to the end of the list in the order in which they were originally added to the list. The items will be repeated according to the specifiedcountvalue. The method extends the current list with the repeated items rather than returning the repeated sequence as a new list. -
reverse()π (fluentlist) β Thereverse()method supports reversing the order of the items from the current list. The list is reversed in-place. -
shuffle()π (fluentlist) β Theshuffle()method supports randomly shuffling all of the items from the current list. The list is shuffled in-place. -
slice(start: int, stop: int = None, step: int = 1)π (fluentlist) β Theslice()method supports returning a slice of the items from the current list according to the specified slice indices and step count. The method returns the slice within a new list; it does not modify the original list. -
take(index: int)π (fluentlist) β Thetake()method supports returning a slice of the items from the current list from the beginning of the list at index 0 to the stop index as specified by the providedindexargument. The method returns the slice within a new list; it does not modify the original list. -
drop(index: int)π (fluentlist) β Thedrop()method supports returning a slice of the items from the current list from the start index as specified by the providedindexargument until the end of the list. The method returns the slice within a new list; it does not modify the original list. -
swap(source: int, target: int)π (fluentlist) β Theswap()method supports swapping the items in the list at the specifiedsourceandtargetindices with each other. The items are swapped in-place, modifying the current list. -
unique()π (fluentlist) β Theunique()method supports providing a list of the unique items from the current list. The method returns a new list containing the unique items found in the current list; the original current list is not modified. -
count(item: object)(int) β Thecount()method supports providing a count of the number of times the specifieditemvalue appears in the current list. The method returns the count as anintvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluentlistmethods that do support chaining. -
contains(item: object)(bool) β Thecontains()method supports returning whether the specifieditemvalue appears in the current list at least once or not. The method returns aboolvalue indicating the presence or absence of the specifieditemvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluentlistmethods that do support chaining. -
any(item: object)(bool) β Theany()method supports returning whether the current list contains the specifieditemvalue at least once or not. As the method returns aboolvalue, it does not allow further chaining, but can be used as the last call on chain of otherfluentlistmethods that do support chaining. -
all(item: object)(bool) β Theall()method supports returning whether the current list solely contains the specifieditemvalue or not; that is for theall()method to returnTrue, the current list must only contain items that match the specifieditemvia the equality comparison==operator. As the method returns aboolvalue, it does not allow further chaining, but can be used as the last call on chain of otherfluentlistmethods that do support chaining. -
map(function: callable)π (fluentlist) β Themap()method supports running the specifiedfunctionon each item in the current list. The method returns a new list containing the result of running thefunctionon each item in the current list rather than modifying the current list in-place. -
reduce(function: callable)(object) β Thereduce()method supports running the specifiedfunctionon each item in the current list, reducing the list down to a single value, which the method returns upon completion. The method therefore does not support chaining but can be as the last call on a chain of otherfluentlistmethods that do support chaining. -
sort(key: object = None, reversed: bool = False)π (fluentlist) β Thesort()method supports sorting the current list in-place, according to any specifiedkeyandreversedarguments. The contents of the current list will be updated to reflect the specified sort. -
sorted(key: object = None, reversed: bool = False)π (fluentlist) β Thesorted()method supports sorting the current list and returning the sorted items as a new list, according to any specifiedkeyandreversedarguments. -
filter(predicate: callable = None, **filters: dict[str, object])π (fluentlist) β Thefilter()method supports filtering the contents of the current list in the two ways noted below, and returns the filtered results as a new list:- filtering can be performed via a
predicatecallable method that takes as input the current item as the list is iterated over, where thepredicatemust returnTruefor items that should remain in the output, andFalseotherwise; - alternatively, filtering can be performed via one or more keyword arguments, excepting
the reserved
predicatekeyword, which define the names and values of object attributes that the item objects held in the list must match to be included in the output. Each item in the list will be inspected to see if has the specified attribute (as per the keyword argument name) and if so, if that attribute also has a value matching the value of the keyword argument; for item objects that both have all of the specified attributes with matching values, they will be included in the new list created by the filtering call, otherwise they will be omitted.
- filtering can be performed via a
-
first(predicate: callable = None, **filters: dict[str, object])(fluentlist) β Thefirst()method supports returning the first item of the current list. Optionally, the contents of the list can first be filtered according to the specifiedpredicateorfilteringkeyword argument values (as per those passed to thefilter()method), and then the first matching item will be returned. If the list is either empty or there are no matches according to the specified filtering arguments, the method will returnNone. As the method returns the first value in the current list orNoneif the list is empty, the method cannot be chained onto, but can be as the last call on a chain of otherfluentlistmethods that do support chaining. -
last(predicate: callable = None, **filters: dict[str, object])(fluentlist) β Thelast()method supports returning the last item of the current list. Optionally, the contents of the list can last be filtered according to the specifiedpredicateorfilteringkeyword argument values (as per those passed to thefilter()method), and then the last matching item will be returned. If the list is either empty or there are no matches according to the specified filtering arguments, the method will returnNone. As the method returns the last value in the current list orNoneif the list is empty, the method cannot be chained onto, but can be as the last call on a chain of otherfluentlistmethods that do support chaining.
The fluentlist class also supports several operator overrides which provide some useful
and convenient behaviours for lists as noted in the table below:
| Operator | Value Type | Method Equivalent | Notes |
|---|---|---|---|
+ |
list |
append(...) |
Creates a new list and appends to that list. |
+= |
list |
append(...) |
Appends in-place, updating the current list. |
- |
object |
remove(...) |
Creates a new list and removes in that list. |
-= |
object |
remove(...) |
Removes in-place, updating the current list. |
* |
int |
repeat(...) |
Creates a new list and repeats to that list. |
*= |
int |
repeat(...) |
Repeats in-place, updating the current list. |
The + and += operator overloads can be used as follows:
from fluently import fluentlist
numbers = fluentlist([1, 2, 3])
# Using the `+` operator overload returns a new list into which the items are added
newnumbers = numbers + [4, 5, 6]
assert newnumbers == [1, 2, 3, 4, 5, 6]
# The `+=` operator overload appends items, returning the updated original list
numbers += [4, 5, 6]
assert numbers == [1, 2, 3, 4, 5, 6]The - and -= operator overloads can be used as follows:
from fluently import fluentlist
numbers = fluentlist([1, 2, 3])
# The `-` operator overload returns a new list from which the item is removed
newnumbers = numbers - 3 # Remove the first occurrence of `3` from the list
assert newnumbers == [1, 2]
# The `-=` operator overload removes the item, returning the updated original list
numbers -= 3 # Remove the first occurrence of `3` from the list
assert numbers == [1, 2]The * and *= operator overloads can be used as follows:
from fluently import fluentlist
numbers = fluentlist([1, 2, 3])
# The `*` operator overload, returning a new list into which the items are repeated
newnumbers = numbers * 2
assert newnumbers == [1, 2, 3, 1, 2, 3]
# The `*=` operator overload to repeats items, returning the updated original list
numbers *= 2
assert numbers == [1, 2, 3, 1, 2, 3]The fluentset class provides the following methods in addition to the methods provided
by the set superclass:
-
length()(int) β Thelength()method supports returning the total count of items in the current set. The method returns the count as anintvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluentsetmethods that do support chaining. -
clone()π (fluentset) β Theclone()method supports creating a cloned copy of the current set, that contains the same items, in a separatefluentsetinstance. -
add(item: object)π (fluentset) β Theadd()method supports adding the specifieditemto the current set, if a matching item has not already been added. This method updates the current set in-place. -
remove(item: object, raises: bool = True)π (fluentset) β Theremove()method supports removing the specifieditemfrom the current set if the item is present in the list. This method updates the current set in-place. If the item is not present, and the optionalraiseskeyword argument is set to its default ofTruethen the method will raise aKeyErrorexception will be raised noting the absence of theitemvalue in the set. Ifraisesis set toFalseno exception will be raised, instead the error will be logged, visible via the standardlogginglibrary if the log level is set toERRORor higher. -
discard(item: object)π (fluentset) β Thediscard()method supports removing the specifieditemfrom the current set if the item is present in the list. No error is raised if theitemdoes not exist in the set. -
clear()π (fluentset) β Theclear()method supports clearing all of the items from the current set. -
contains(item: object)(bool) β Thecontains()method supports returning whether the specifieditemvalue appears in the current set or not. The method returns aboolvalue indicating the presence or absence of the specifieditemvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluentsetmethods that do support chaining.
The fluenttuple class provides the following methods in addition to the methods provided
by the tuple superclass:
-
length()(int) β Thelength()method supports returning the total count of items in the current tuple. The method returns the count as anintvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluenttuplemethods that do support chaining. -
clone()π (fluenttuple) β Theclone()method supports creating a cloned copy of the current tuple, that contains the same items, in a separatefluenttupleinstance. -
add(item: object)π (fluenttuple) β Theadd()method supports appending the specifiediteminto a new tuple along with the values from the original tuple. -
append(item: object)π (fluenttuple) β Theappend()method supports appending the specifiediteminto a new tuple along with the values from the original tuple. -
prepend(item: object)π (fluenttuple) β Theappend()method supports prepending the specifiediteminto a new tuple along with the values from the original tuple. -
remove(item: object, raises: bool = True)π (fluenttuple) β Theremove()method supports removing the specifieditemfrom the current tuples values, returning the resulting values as new tuple. If the item is not present, and the optionalraiseskeyword argument is tuple to its default ofTruethen the method will raise aValueErrorexception will be raised noting the absence of theitemvalue in the tuple. Ifraisesis tuple toFalseno exception will be raised, instead the error will be logged, visible via the standardlogginglibrary if the log level is tuple toERRORor higher. -
discard(item: object)π (fluenttuple) β Thediscard()method supports removing the specifieditemfrom the current tuple if the item is present, returning the resulting values as a new tuple. No error is raised if theitemdoes not exist in the tuple. -
clear()π (fluenttuple) β Theclear()method mimics clearing all of the items from the current tuple, by returning a new emptyfluenttupleinstance. -
repeat(count: int)π (fluenttuple) β Therepeat()method supports repeating all the items from the current tuple by cloning the tuple values and appending the repeated item values to the end of the new tuple, following the order in which they were originally defined. The values are according to the specifiedcountvalue. The method returns a new tuple. -
reverse()π (fluenttuple) β Thereverse()method supports reversing the order of the items from the current tuple into a new tuple. -
shuffle()π (fluenttuple) β Theshuffle()method supports randomly shuffling all of the items from the current tuple into a new tuple. -
slice(start: int, stop: int = None, step: int = 1)π (fluenttuple) β Theslice()method supports returning a slice of the items from the current tuple according to the specified slice indices and step count. The method returns the slice within a new tuple; it does not modify the original tuple. -
take(index: int)π (fluenttuple) β Thetake()method supports returning a slice of the items from the current tuple from the beginning of the tuple at index 0 to the stop index as specified by the providedindexargument. The method returns the slice within a new tuple; it does not modify the original tuple. -
drop(index: int)π (fluenttuple) β Thedrop()method supports returning a slice of the items from the current tuple from the start index as specified by the providedindexargument until the end of the tuple. The method returns the slice within a new tuple; it does not modify the original tuple. -
swap(source: int, target: int)π (fluenttuple) β Theswap()method supports swapping the items in the tuple at the specifiedsourceandtargetindices with each other. The items are swapped into position within a new tuple, leaving the original untouched. -
unique()π (fluenttuple) β Theunique()method supports providing a tuple of the unique items from the current tuple. The method returns a new tuple containing the unique items found in the current tuple; the original current tuple is not modified. -
count(item: object)(int) β Thecount()method supports providing a count of the number of times the specifieditemvalue appears in the current tuple. The method returns the count as anintvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluenttuplemethods that do support chaining. -
contains(item: object)(bool) β Thecontains()method supports returning whether the specifieditemvalue appears in the current tuple at least once or not. The method returns aboolvalue indicating the presence or absence of the specifieditemvalue, so does not allow further chaining, but can be used as the last call on chain of otherfluenttuplemethods that do support chaining. -
any(item: object)(bool) β Theany()method supports returning whether the current tuple contains the specifieditemvalue at least once or not. As the method returns aboolvalue, it does not allow further chaining, but can be used as the last call on chain of otherfluenttuplemethods that do support chaining. -
all(item: object)(bool) β Theall()method supports returning whether the current tuple solely contains the specifieditemvalue or not; that is for theall()method to returnTrue, the current tuple must only contain items that match the specifieditemvia the equality comparison==operator. As the method returns aboolvalue, it does not allow further chaining, but can be used as the last call on chain of otherfluenttuplemethods that do support chaining. -
map(function: callable)π (fluenttuple) β Themap()method supports running the specifiedfunctionon each item in the current tuple. The method returns a new tuple containing the result of running thefunctionon each item in the current tuple rather than modifying the current tuple in-place. -
reduce(function: callable)(object) β Thereduce()method supports running the specifiedfunctionon each item in the current tuple, reducing the tuple down to a single value, which the method returns upon completion. The method therefore does not support chaining but can be as the last call on a chain of otherfluenttuplemethods that do support chaining. -
sort(key: object = None, reversed: bool = False)π (fluenttuple) β Thesort()method supports sorting the current tuple in-place, according to any specifiedkeyandreversedarguments. The contents of the current tuple will be updated to reflect the specified sort. -
sorted(key: object = None, reversed: bool = False)π (fluenttuple) β Thesorted()method supports sorting the current tuple and returning the sorted items as a new tuple, according to any specifiedkeyandreversedarguments. -
filter(predicate: callable = None, **filters: dict[str, object])π (fluenttuple) β Thefilter()method supports filtering the contents of the current tuple in the two ways noted below, and returns the filtered results as a new tuple:- filtering can be performed via a
predicatecallable method that takes as input the current item as the tuple is iterated over, where thepredicatemust returnTruefor items that should remain in the output, andFalseotherwise; - alternatively, filtering can be performed via one or more keyword arguments, excepting
the reserved
predicatekeyword, which define the names and values of object attributes that the item objects held in the tuple must match to be included in the output. Each item in the tuple will be inspected to see if has the specified attribute (as per the keyword argument name) and if so, if that attribute also has a value matching the value of the keyword argument; for item objects that both have all of the specified attributes with matching values, they will be included in the new tuple created by the filtering call, otherwise they will be omitted.
- filtering can be performed via a
-
first(predicate: callable = None, **filters: dict[str, object])(fluenttuple) β Thefirst()method supports returning the first item of the current tuple. Optionally, the contents of the tuple can first be filtered according to the specifiedpredicateorfilteringkeyword argument values (as per those passed to thefilter()method), and then the first matching item will be returned. If the tuple is either empty or there are no matches according to the specified filtering arguments, the method will returnNone. As the method returns the first value in the current tuple orNoneif the tuple is empty, the method cannot be chained onto, but can be as the last call on a chain of otherfluenttuplemethods that do support chaining. -
last(predicate: callable = None, **filters: dict[str, object])(fluenttuple) β Thelast()method supports returning the last item of the current tuple. Optionally, the contents of the tuple can last be filtered according to the specifiedpredicateorfilteringkeyword argument values (as per those passed to thefilter()method), and then the last matching item will be returned. If the tuple is either empty or there are no matches according to the specified filtering arguments, the method will returnNone. As the method returns the last value in the current tuple orNoneif the tuple is empty, the method cannot be chained onto, but can be as the last call on a chain of otherfluenttuplemethods that do support chaining.
The fluenttuple class also supports several operator overrides which provide some useful
and convenient behaviours for tuples as noted in the table below:
| Operator | Value Type | Method Equivalent | Notes |
|---|---|---|---|
+ |
tuple |
append(...) |
Creates a new tuple and appends to that tuple. |
+= |
tuple |
append(...) |
Appends in-place, updating the current tuple. |
- |
object |
remove(...) |
Creates a new tuple and removes in that tuple. |
-= |
object |
remove(...) |
Removes in-place, updating the current tuple. |
* |
int |
repeat(...) |
Creates a new tuple and repeats to that tuple. |
*= |
int |
repeat(...) |
Repeats in-place, updating the current tuple. |
The + and += operator overloads can be used as follows:
from fluently import fluenttuple
numbers = fluenttuple([1, 2, 3])
# The `+` operator overload returns a new tuple to which the items are added
newnumbers = numbers + (4, 5, 6)
assert newnumbers == (1, 2, 3, 4, 5, 6)
# The `+=` operator overload to append items, returning a new tuple
numbers += (4, 5, 6)
assert numbers == (1, 2, 3, 4, 5, 6)The - and -= operator overloads can be used as follows:
from fluently import fluenttuple
numbers = fluenttuple([1, 2, 3])
# The `-` operator overload returns a new tuple from which the item is removed
newnumbers = numbers - 3 # Remove the first occurrence of `3` from the tuple
assert newnumbers == (1, 2)
# The `-=` operator overload removes the item, returning a new tuple
numbers -= 3 # Remove the first occurrence of `3` from the tuple
assert numbers == (1, 2)The * and *= operator overloads can be used as follows:
from fluently import fluenttuple
numbers = fluenttuple([1, 2, 3])
# The `*` operator overload repeats the items, returning a new tuple
newnumbers = numbers * 2
assert newnumbers == (1, 2, 3, 1, 2, 3)
# The `*=` operator overload to repeats the items into a new tuple
numbers *= 2
assert numbers == (1, 2, 3, 1, 2, 3)The Fluently library includes a suite of comprehensive unit tests which ensure that the
library functionality operates as expected. The unit tests were developed with and are
run via pytest.
To ensure that the unit tests are run within a predictable runtime environment where all of the necessary dependencies are available, a Docker image is created within which the tests are run. To run the unit tests, ensure Docker and Docker Compose is installed, and perform the following commands, which will build the Docker image via docker compose build and then run the tests via docker compose run β the output of running the tests will be displayed:
$ docker compose build
$ docker compose run testsTo run the unit tests with optional command line arguments being passed to pytest, append the relevant arguments to the docker compose run tests command, as follows, for example passing -vv to enable verbose output:
$ docker compose run tests -vvSee the documentation for PyTest regarding available optional command line arguments.
Copyright Β© 2025-2026 Daniel Sissman; licensed under the MIT License.