fluently 0.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fluently-0.9.0/PKG-INFO +670 -0
- fluently-0.9.0/README.md +639 -0
- fluently-0.9.0/pyproject.toml +77 -0
- fluently-0.9.0/requirements.development.txt +5 -0
- fluently-0.9.0/requirements.distribution.txt +4 -0
- fluently-0.9.0/requirements.txt +1 -0
- fluently-0.9.0/setup.cfg +4 -0
- fluently-0.9.0/source/fluently/__init__.py +15 -0
- fluently-0.9.0/source/fluently/list.py +346 -0
- fluently-0.9.0/source/fluently/logging.py +3 -0
- fluently-0.9.0/source/fluently/set.py +66 -0
- fluently-0.9.0/source/fluently/tuple.py +286 -0
- fluently-0.9.0/source/fluently/utilities.py +21 -0
- fluently-0.9.0/source/fluently/version.txt +1 -0
- fluently-0.9.0/source/fluently.egg-info/PKG-INFO +670 -0
- fluently-0.9.0/source/fluently.egg-info/SOURCES.txt +21 -0
- fluently-0.9.0/source/fluently.egg-info/dependency_links.txt +1 -0
- fluently-0.9.0/source/fluently.egg-info/requires.txt +11 -0
- fluently-0.9.0/source/fluently.egg-info/top_level.txt +1 -0
- fluently-0.9.0/source/fluently.egg-info/zip-safe +1 -0
- fluently-0.9.0/tests/test_list.py +1137 -0
- fluently-0.9.0/tests/test_set.py +215 -0
- fluently-0.9.0/tests/test_tuple.py +765 -0
fluently-0.9.0/PKG-INFO
ADDED
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fluently
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: Fluent data type container implementations for Python.
|
|
5
|
+
Author: Daniel Sissman
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: documentation, https://github.com/bluebinary/fluently/blob/main/README.md
|
|
8
|
+
Project-URL: changelog, https://github.com/bluebinary/fluently/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: repository, https://github.com/bluebinary/fluently
|
|
10
|
+
Project-URL: issues, https://github.com/bluebinary/fluently/issues
|
|
11
|
+
Project-URL: homepage, https://github.com/bluebinary/fluently
|
|
12
|
+
Keywords: fluent,containers,data types
|
|
13
|
+
Platform: any
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Provides-Extra: development
|
|
23
|
+
Requires-Dist: black==24.10.*; extra == "development"
|
|
24
|
+
Requires-Dist: pytest==8.3.*; extra == "development"
|
|
25
|
+
Requires-Dist: pytest-codeblocks==0.17.0; extra == "development"
|
|
26
|
+
Requires-Dist: pyflakes==3.4.0; extra == "development"
|
|
27
|
+
Provides-Extra: distribution
|
|
28
|
+
Requires-Dist: build; extra == "distribution"
|
|
29
|
+
Requires-Dist: twine; extra == "distribution"
|
|
30
|
+
Requires-Dist: wheel; extra == "distribution"
|
|
31
|
+
|
|
32
|
+
# Fluently
|
|
33
|
+
|
|
34
|
+
The `fluently` library provides several container data type implementations with fluent interfaces:
|
|
35
|
+
|
|
36
|
+
* a `list` subclass with a fluent interface
|
|
37
|
+
* a `set` subclass with a fluent interface
|
|
38
|
+
* a `tuple` subclass with a fluent interface
|
|
39
|
+
|
|
40
|
+
### Requirements
|
|
41
|
+
|
|
42
|
+
The Fluently library has been tested with Python 3.10, 3.11, 3.12, 3.13 and 3.14. The
|
|
43
|
+
library is not compatible with Python 3.9 or earlier.
|
|
44
|
+
|
|
45
|
+
### Installation
|
|
46
|
+
|
|
47
|
+
The Fluently library is available from PyPI, so may be added to a project's dependencies
|
|
48
|
+
via its `requirements.txt` file or similar by referencing the Fluently library's name,
|
|
49
|
+
`fluently`, or the library may be installed directly into your local runtime environment
|
|
50
|
+
using `pip` via the `pip install` command by entering the following into your shell:
|
|
51
|
+
|
|
52
|
+
$ pip install fluently
|
|
53
|
+
|
|
54
|
+
### Example Usage
|
|
55
|
+
|
|
56
|
+
To use the Fluently library, import the library and the data type or data types you
|
|
57
|
+
need and use them just like their regular counterparts, with the knowledge that they
|
|
58
|
+
support setting and getting values without regard to the casing of any string keys:
|
|
59
|
+
|
|
60
|
+
#### Fluent List
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# The 'flulist' and 'flist' aliases can be used interchangeably with 'fluentlist'
|
|
64
|
+
from fluently import fluentlist, flulist, flist
|
|
65
|
+
|
|
66
|
+
# Create a new fluentlist instance
|
|
67
|
+
data = fluentlist(["A", "B", "C"])
|
|
68
|
+
|
|
69
|
+
# Assert that the list has the expected class identity, aliases and superclass
|
|
70
|
+
assert isinstance(data, fluentlist)
|
|
71
|
+
assert isinstance(data, flulist)
|
|
72
|
+
assert isinstance(data, flist)
|
|
73
|
+
assert isinstance(data, list)
|
|
74
|
+
|
|
75
|
+
# Assert that the list has the expected length
|
|
76
|
+
assert data.length() == len(data) == 3
|
|
77
|
+
|
|
78
|
+
# Assert that the list has the expected contents
|
|
79
|
+
assert "A" in data
|
|
80
|
+
assert "B" in data
|
|
81
|
+
assert "C" in data
|
|
82
|
+
|
|
83
|
+
# Append item in-place into original list, then create a new list of unique values
|
|
84
|
+
uniquedata = data.append("C").unique()
|
|
85
|
+
|
|
86
|
+
# Assert that the original list now contains the appended value
|
|
87
|
+
assert len(data) == 4
|
|
88
|
+
assert data == ["A", "B", "C", "C"]
|
|
89
|
+
|
|
90
|
+
# Assert that the unique list contains only the unique values
|
|
91
|
+
assert len(uniquedata) == 3
|
|
92
|
+
assert uniquedata == ["A", "B", "C"]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Fluent Set
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
# The 'fluset' and 'fset' aliases can be used interchangeably with 'fluentset'
|
|
99
|
+
from fluently import fluentset, fluset, fset
|
|
100
|
+
|
|
101
|
+
# Create a new fluentset instance
|
|
102
|
+
data = fluentset(["A", "B", "C"])
|
|
103
|
+
|
|
104
|
+
# Assert that the set has the expected class identity, aliases and superclass
|
|
105
|
+
assert isinstance(data, fluentset)
|
|
106
|
+
assert isinstance(data, fluset)
|
|
107
|
+
assert isinstance(data, fset)
|
|
108
|
+
assert isinstance(data, set)
|
|
109
|
+
|
|
110
|
+
# Assert that the set has the expected length
|
|
111
|
+
assert data.length() == len(data) == 3
|
|
112
|
+
|
|
113
|
+
# Assert that the set has the expected contents
|
|
114
|
+
assert "A" in data
|
|
115
|
+
assert "B" in data
|
|
116
|
+
assert "C" in data
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Fluent Tuple
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
# The 'flutuple' and 'ftuple' aliases can be used interchangeably with 'fluenttuple'
|
|
123
|
+
from fluently import fluenttuple, flutuple, ftuple
|
|
124
|
+
|
|
125
|
+
# Create a new fluenttuple instance
|
|
126
|
+
data = fluenttuple(["A", "B", "C"])
|
|
127
|
+
|
|
128
|
+
# Assert that the set has the expected class identity, aliases and superclass
|
|
129
|
+
assert isinstance(data, fluenttuple)
|
|
130
|
+
assert isinstance(data, flutuple)
|
|
131
|
+
assert isinstance(data, ftuple)
|
|
132
|
+
assert isinstance(data, tuple)
|
|
133
|
+
|
|
134
|
+
# Assert that the set has the expected length
|
|
135
|
+
assert data.length() == len(data) == 3
|
|
136
|
+
|
|
137
|
+
# Assert that the set has the expected contents
|
|
138
|
+
assert "A" in data
|
|
139
|
+
assert "B" in data
|
|
140
|
+
assert "C" in data
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Classes & Methods
|
|
144
|
+
|
|
145
|
+
The Fluently library provides the following data type subclasses and each class offers
|
|
146
|
+
shorthand aliases that prefixes the superclass' name with `flu` or `f` to denote that
|
|
147
|
+
the class is its fluent variant. The aliases can be used interchangeably with the fully
|
|
148
|
+
qualified subclass names as they are direct aliases rather than further subclasses.
|
|
149
|
+
|
|
150
|
+
| Subclass | Superclass | Subclass Alias | Short Subclass Alias |
|
|
151
|
+
|-----------------|------------|----------------|----------------------|
|
|
152
|
+
| `fluentlist` | `list` | `flulist` | `flist` |
|
|
153
|
+
| `fluentset` | `set` | `fluset` | `fset` |
|
|
154
|
+
| `fluenttuple` | `tuple` | `flutuple` | `ftuple` |
|
|
155
|
+
|
|
156
|
+
The Fluently library classes can be used interchangeably with their superclasses where
|
|
157
|
+
one wishes to use a fluent chainable interface to interact with the container types.
|
|
158
|
+
The classes offer all the usual functionality that their superclasses offer, and all the
|
|
159
|
+
usual methods and interactions are available, in addition to the library provided fluent
|
|
160
|
+
methods as documented below. All methods marked with the link symbol, 🔗, can be chained.
|
|
161
|
+
|
|
162
|
+
#### Fluent List Methods
|
|
163
|
+
|
|
164
|
+
The `fluentlist` class provides the following methods in addition to the methods provided
|
|
165
|
+
by the `list` superclass:
|
|
166
|
+
|
|
167
|
+
* `length()` (`int`) – The `length()` method supports returning the total count of items
|
|
168
|
+
in the current list. The method returns the count as an `int` value, so does not allow
|
|
169
|
+
further chaining, but can be used as the last call on chain of other `fluentlist` methods
|
|
170
|
+
that do support chaining.
|
|
171
|
+
|
|
172
|
+
* `clone()` (`fluentlist`) – The `clone()` method supports creating a cloned copy of the
|
|
173
|
+
current list, that contains the same items, in a separate `fluentlist` instance.
|
|
174
|
+
|
|
175
|
+
* `prepend(item: object)` 🔗 (`fluentlist`) – The `prepend()` method supports prepending
|
|
176
|
+
the specified item to the start of the current list.
|
|
177
|
+
|
|
178
|
+
* `append(item: object)` 🔗 (`fluentlist`) – The `append()` method supports appending the
|
|
179
|
+
specified item to the end of the current list.
|
|
180
|
+
|
|
181
|
+
* `extend(iterable: object)` 🔗 (`fluentlist`) – The `extend()` method supports appending
|
|
182
|
+
the specified items from the specified `iterable` object to the end of the current list.
|
|
183
|
+
|
|
184
|
+
* `insert(index: int, item: object)` 🔗 (`fluentlist`) – The `insert()` method supports
|
|
185
|
+
appending the specified item into the current list at the specified `index` position.
|
|
186
|
+
The `index` must be in range of the current length of the list.
|
|
187
|
+
|
|
188
|
+
* `remove(item: object, raises: bool = True)` 🔗 (`fluentlist`) – The `remove()` method
|
|
189
|
+
supports removing the first occurrence of the specified item from the current list. If
|
|
190
|
+
the specified `item` does not exist in the list, and if the `raises` keyword argument
|
|
191
|
+
is set to its default value of `True`, a `ValueError` exception will be raised noting
|
|
192
|
+
the absence of the `item` value in the list. If `raises` is set to `False` no exception
|
|
193
|
+
will be raised, instead the error will be logged, visible via the standard `logging`
|
|
194
|
+
library if the log level is set to `ERROR` or higher.
|
|
195
|
+
|
|
196
|
+
* `removeall(item: object, raises: bool = True)` 🔗 (`fluentlist`) – The `removeall()`
|
|
197
|
+
method supports removing all occurrences of the specified item from the current list.
|
|
198
|
+
If the specified `item` does not exist in the list, and if the `raises` keyword argument
|
|
199
|
+
is set to its default value of `True`, a `ValueError` exception will be raised noting
|
|
200
|
+
the absence of the `item` value in the list. If `raises` is set to `False` no exception
|
|
201
|
+
will be raised, instead the error will be logged, visible via the standard `logging`
|
|
202
|
+
library if the log level is set to `ERROR` or higher.
|
|
203
|
+
|
|
204
|
+
* `discard(item: object)` 🔗 (`fluentlist`) – The `discard()` method supports removing
|
|
205
|
+
the first occurrence of the specified `item` from the current list if the item is present
|
|
206
|
+
in the list. No error is raised if the `item` does not exist in the list. Added for
|
|
207
|
+
consistency with sets.
|
|
208
|
+
|
|
209
|
+
* `clear()` 🔗 (`fluentlist`) – The `clear()` method supports clearing all of the items
|
|
210
|
+
from the current list.
|
|
211
|
+
|
|
212
|
+
* `repeat(count: int)` 🔗 (`fluentlist`) – The `repeat()` method supports repeating all
|
|
213
|
+
the items from the current list by appending the items in the list to the end of the list
|
|
214
|
+
in the order in which they were originally added to the list. The items will be repeated
|
|
215
|
+
according to the specified `count` value. The method extends the current list with the
|
|
216
|
+
repeated items rather than returning the repeated sequence as a new list.
|
|
217
|
+
|
|
218
|
+
* `reverse()` 🔗 (`fluentlist`) – The `reverse()` method supports reversing the order
|
|
219
|
+
of the items from the current list. The list is reversed in-place.
|
|
220
|
+
|
|
221
|
+
* `shuffle()` 🔗 (`fluentlist`) – The `shuffle()` method supports randomly shuffling all
|
|
222
|
+
of the items from the current list. The list is shuffled in-place.
|
|
223
|
+
|
|
224
|
+
* `slice(start: int, stop: int = None, step: int = 1)` 🔗 (`fluentlist`) – The `slice()`
|
|
225
|
+
method supports returning a slice of the items from the current list according to the
|
|
226
|
+
specified slice indices and step count. The method returns the slice within a new list;
|
|
227
|
+
it does not modify the original list.
|
|
228
|
+
|
|
229
|
+
* `take(index: int)` 🔗 (`fluentlist`) – The `take()` method supports returning a slice
|
|
230
|
+
of the items from the current list from the beginning of the list at index 0 to the stop
|
|
231
|
+
index as specified by the provided `index` argument. The method returns the slice within
|
|
232
|
+
a new list; it does not modify the original list.
|
|
233
|
+
|
|
234
|
+
* `drop(index: int)` 🔗 (`fluentlist`) – The `drop()` method supports returning a slice
|
|
235
|
+
of the items from the current list from the start index as specified by the provided
|
|
236
|
+
`index` argument until the end of the list. The method returns the slice within a new
|
|
237
|
+
list; it does not modify the original list.
|
|
238
|
+
|
|
239
|
+
* `swap(source: int, target: int)` 🔗 (`fluentlist`) – The `swap()` method supports
|
|
240
|
+
swapping the items in the list at the specified `source` and `target` indices with each
|
|
241
|
+
other. The items are swapped in-place, modifying the current list.
|
|
242
|
+
|
|
243
|
+
* `unique()` 🔗 (`fluentlist`) – The `unique()` method supports providing a list of the
|
|
244
|
+
unique items from the current list. The method returns a new list containing the unique
|
|
245
|
+
items found in the current list; the original current list is not modified.
|
|
246
|
+
|
|
247
|
+
* `count(item: object)` (`int`) – The `count()` method supports providing a count of the
|
|
248
|
+
number of times the specified `item` value appears in the current list. The method returns
|
|
249
|
+
the count as an `int` value, so does not allow further chaining, but can be used as the
|
|
250
|
+
last call on chain of other `fluentlist` methods that do support chaining.
|
|
251
|
+
|
|
252
|
+
* `contains(item: object)` (`bool`) – The `contains()` method supports returning whether
|
|
253
|
+
the specified `item` value appears in the current list at least once or not. The method
|
|
254
|
+
returns a `bool` value indicating the presence or absence of the specified `item` value,
|
|
255
|
+
so does not allow further chaining, but can be used as the last call on chain of other
|
|
256
|
+
`fluentlist` methods that do support chaining.
|
|
257
|
+
|
|
258
|
+
* `any(item: object)` (`bool`) – The `any()` method supports returning whether the current
|
|
259
|
+
list contains the specified `item` value at least once or not. As the method returns a
|
|
260
|
+
`bool` value, it does not allow further chaining, but can be used as the last call on
|
|
261
|
+
chain of other `fluentlist` methods that do support chaining.
|
|
262
|
+
|
|
263
|
+
* `all(item: object)` (`bool`) – The `all()` method supports returning whether the current
|
|
264
|
+
list solely contains the specified `item` value or not; that is for the `all()` method
|
|
265
|
+
to return `True`, the current list must only contain items that match the specified `item`
|
|
266
|
+
via the equality comparison `==` operator. As the method returns a `bool` value, it does
|
|
267
|
+
not allow further chaining, but can be used as the last call on chain of other `fluentlist`
|
|
268
|
+
methods that do support chaining.
|
|
269
|
+
|
|
270
|
+
* `map(function: callable)` 🔗 (`fluentlist`) – The `map()` method supports running the
|
|
271
|
+
specified `function` on each item in the current list. The method returns a new list
|
|
272
|
+
containing the result of running the `function` on each item in the current list rather
|
|
273
|
+
than modifying the current list in-place.
|
|
274
|
+
|
|
275
|
+
* `reduce(function: callable)` (`object`) – The `reduce()` method supports running the
|
|
276
|
+
specified `function` on each item in the current list, reducing the list down to a single
|
|
277
|
+
value, which the method returns upon completion. The method therefore does not support
|
|
278
|
+
chaining but can be as the last call on a chain of other `fluentlist` methods that do
|
|
279
|
+
support chaining.
|
|
280
|
+
|
|
281
|
+
* `sort(key: object = None, reversed: bool = False)` 🔗 (`fluentlist`) – The `sort()` method
|
|
282
|
+
supports sorting the current list in-place, according to any specified `key` and `reversed`
|
|
283
|
+
arguments. The contents of the current list will be updated to reflect the specified sort.
|
|
284
|
+
|
|
285
|
+
* `sorted(key: object = None, reversed: bool = False)` 🔗 (`fluentlist`) – The `sorted()`
|
|
286
|
+
method supports sorting the current list and returning the sorted items as a new list,
|
|
287
|
+
according to any specified `key` and `reversed` arguments.
|
|
288
|
+
|
|
289
|
+
* `filter(predicate: callable = None, **filters: dict[str, object])` 🔗 (`fluentlist`)
|
|
290
|
+
– The `filter()` method supports filtering the contents of the current list in the two
|
|
291
|
+
ways noted below, and returns the filtered results as a new list:
|
|
292
|
+
- filtering can be performed via a `predicate` callable method that takes as input the
|
|
293
|
+
current item as the list is iterated over, where the `predicate` must return `True` for
|
|
294
|
+
items that should remain in the output, and `False` otherwise;
|
|
295
|
+
- alternatively, filtering can be performed via one or more keyword arguments, excepting
|
|
296
|
+
the reserved `predicate` keyword, which define the names and values of object attributes
|
|
297
|
+
that the item objects held in the list must match to be included in the output. Each item
|
|
298
|
+
in the list will be inspected to see if has the specified attribute (as per the keyword
|
|
299
|
+
argument name) and if so, if that attribute also has a value matching the value of the
|
|
300
|
+
keyword argument; for item objects that both have all of the specified attributes with
|
|
301
|
+
matching values, they will be included in the new list created by the filtering call,
|
|
302
|
+
otherwise they will be omitted.
|
|
303
|
+
|
|
304
|
+
* `first(predicate: callable = None, **filters: dict[str, object])` (`fluentlist`) –
|
|
305
|
+
The `first()` method supports returning the first item of the current list. Optionally,
|
|
306
|
+
the contents of the list can first be filtered according to the specified `predicate`
|
|
307
|
+
or `filtering` keyword argument values (as per those passed to the `filter()` method),
|
|
308
|
+
and then the first matching item will be returned. If the list is either empty or there
|
|
309
|
+
are no matches according to the specified filtering arguments, the method will return
|
|
310
|
+
`None`. As the method returns the first value in the current list or `None` if the list
|
|
311
|
+
is empty, the method cannot be chained onto, but can be as the last call on a chain of
|
|
312
|
+
other `fluentlist` methods that do support chaining.
|
|
313
|
+
|
|
314
|
+
* `last(predicate: callable = None, **filters: dict[str, object])` (`fluentlist`) –
|
|
315
|
+
The `last()` method supports returning the last item of the current list. Optionally,
|
|
316
|
+
the contents of the list can last be filtered according to the specified `predicate`
|
|
317
|
+
or `filtering` keyword argument values (as per those passed to the `filter()` method),
|
|
318
|
+
and then the last matching item will be returned. If the list is either empty or there
|
|
319
|
+
are no matches according to the specified filtering arguments, the method will return
|
|
320
|
+
`None`. As the method returns the last value in the current list or `None` if the list
|
|
321
|
+
is empty, the method cannot be chained onto, but can be as the last call on a chain of
|
|
322
|
+
other `fluentlist` methods that do support chaining.
|
|
323
|
+
|
|
324
|
+
#### Fluent List Operator Overrides
|
|
325
|
+
|
|
326
|
+
The `fluentlist` class also supports several operator overrides which provide some useful
|
|
327
|
+
and convenient behaviours for lists as noted in the table below:
|
|
328
|
+
|
|
329
|
+
| Operator | Value Type | Method Equivalent | Notes |
|
|
330
|
+
|:--------:|:----------:|-------------------|----------------------------------------------|
|
|
331
|
+
| `+` | `list` | `append(...)` | Creates a new list and appends to that list. |
|
|
332
|
+
| `+=` | `list` | `append(...)` | Appends in-place, updating the current list. |
|
|
333
|
+
| `-` | `object` | `remove(...)` | Creates a new list and removes in that list. |
|
|
334
|
+
| `-=` | `object` | `remove(...)` | Removes in-place, updating the current list. |
|
|
335
|
+
| `*` | `int` | `repeat(...)` | Creates a new list and repeats to that list. |
|
|
336
|
+
| `*=` | `int` | `repeat(...)` | Repeats in-place, updating the current list. |
|
|
337
|
+
|
|
338
|
+
The `+` and `+=` operator overloads can be used as follows:
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
from fluently import fluentlist
|
|
342
|
+
|
|
343
|
+
numbers = fluentlist([1, 2, 3])
|
|
344
|
+
|
|
345
|
+
# Using the `+` operator overload returns a new list into which the items are added
|
|
346
|
+
newnumbers = numbers + [4, 5, 6]
|
|
347
|
+
|
|
348
|
+
assert newnumbers == [1, 2, 3, 4, 5, 6]
|
|
349
|
+
|
|
350
|
+
# The `+=` operator overload appends items, returning the updated original list
|
|
351
|
+
numbers += [4, 5, 6]
|
|
352
|
+
|
|
353
|
+
assert numbers == [1, 2, 3, 4, 5, 6]
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
The `-` and `-=` operator overloads can be used as follows:
|
|
357
|
+
|
|
358
|
+
```python
|
|
359
|
+
from fluently import fluentlist
|
|
360
|
+
|
|
361
|
+
numbers = fluentlist([1, 2, 3])
|
|
362
|
+
|
|
363
|
+
# The `-` operator overload returns a new list from which the item is removed
|
|
364
|
+
newnumbers = numbers - 3 # Remove the first occurrence of `3` from the list
|
|
365
|
+
|
|
366
|
+
assert newnumbers == [1, 2]
|
|
367
|
+
|
|
368
|
+
# The `-=` operator overload removes the item, returning the updated original list
|
|
369
|
+
numbers -= 3 # Remove the first occurrence of `3` from the list
|
|
370
|
+
|
|
371
|
+
assert numbers == [1, 2]
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
The `*` and `*=` operator overloads can be used as follows:
|
|
375
|
+
|
|
376
|
+
```python
|
|
377
|
+
from fluently import fluentlist
|
|
378
|
+
|
|
379
|
+
numbers = fluentlist([1, 2, 3])
|
|
380
|
+
|
|
381
|
+
# The `*` operator overload, returning a new list into which the items are repeated
|
|
382
|
+
newnumbers = numbers * 2
|
|
383
|
+
|
|
384
|
+
assert newnumbers == [1, 2, 3, 1, 2, 3]
|
|
385
|
+
|
|
386
|
+
# The `*=` operator overload to repeats items, returning the updated original list
|
|
387
|
+
numbers *= 2
|
|
388
|
+
|
|
389
|
+
assert numbers == [1, 2, 3, 1, 2, 3]
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### Fluent Set Methods
|
|
393
|
+
|
|
394
|
+
The `fluentset` class provides the following methods in addition to the methods provided
|
|
395
|
+
by the `set` superclass:
|
|
396
|
+
|
|
397
|
+
* `length()` (`int`) – The `length()` method supports returning the total count of items
|
|
398
|
+
in the current set. The method returns the count as an `int` value, so does not allow
|
|
399
|
+
further chaining, but can be used as the last call on chain of other `fluentset` methods
|
|
400
|
+
that do support chaining.
|
|
401
|
+
|
|
402
|
+
* `clone()` (`fluentset`) – The `clone()` method supports creating a cloned copy of the
|
|
403
|
+
current set, that contains the same items, in a separate `fluentset` instance.
|
|
404
|
+
|
|
405
|
+
* `add(item: object)` 🔗 (`fluentset`) – The `add()` method supports adding the specified
|
|
406
|
+
`item` to the current set, if a matching item has not already been added. This method
|
|
407
|
+
updates the current set in-place.
|
|
408
|
+
|
|
409
|
+
* `remove(item: object, raises: bool = True)` 🔗 (`fluentset`) – The `remove()` method
|
|
410
|
+
supports removing the specified `item` from the current set if the item is present in
|
|
411
|
+
the list. This method updates the current set in-place. If the item is not present, and
|
|
412
|
+
the optional `raises` keyword argument is set to its default of `True` then the method
|
|
413
|
+
will raise a `KeyError` exception will be raised noting the absence of the `item` value
|
|
414
|
+
in the set. If `raises` is set to `False` no exception will be raised, instead the error
|
|
415
|
+
will be logged, visible via the standard `logging` library if the log level is set to
|
|
416
|
+
`ERROR` or higher.
|
|
417
|
+
|
|
418
|
+
* `discard(item: object)` 🔗 (`fluentset`) – The `discard()` method supports removing
|
|
419
|
+
the specified `item` from the current set if the item is present in the list. No error
|
|
420
|
+
is raised if the `item` does not exist in the set.
|
|
421
|
+
|
|
422
|
+
* `clear()` 🔗 (`fluentset`) – The `clear()` method supports clearing all of the items
|
|
423
|
+
from the current set.
|
|
424
|
+
|
|
425
|
+
* `contains(item: object)` (`bool`) – The `contains()` method supports returning whether
|
|
426
|
+
the specified `item` value appears in the current set or not. The method returns a `bool`
|
|
427
|
+
value indicating the presence or absence of the specified `item` value, so does not allow
|
|
428
|
+
further chaining, but can be used as the last call on chain of other `fluentset` methods
|
|
429
|
+
that do support chaining.
|
|
430
|
+
|
|
431
|
+
#### Fluent Tuple Methods
|
|
432
|
+
|
|
433
|
+
The `fluenttuple` class provides the following methods in addition to the methods provided
|
|
434
|
+
by the `tuple` superclass:
|
|
435
|
+
|
|
436
|
+
* `length()` (`int`) – The `length()` method supports returning the total count of items
|
|
437
|
+
in the current tuple. The method returns the count as an `int` value, so does not allow
|
|
438
|
+
further chaining, but can be used as the last call on chain of other `fluenttuple` methods
|
|
439
|
+
that do support chaining.
|
|
440
|
+
|
|
441
|
+
* `clone()` (`fluenttuple`) – The `clone()` method supports creating a cloned copy of
|
|
442
|
+
the current tuple, that contains the same items, in a separate `fluenttuple` instance.
|
|
443
|
+
|
|
444
|
+
* `add(item: object)` 🔗 (`fluenttuple`) – The `add()` method supports appending the
|
|
445
|
+
specified `item` into a new tuple along with the values from the original tuple.
|
|
446
|
+
|
|
447
|
+
* `append(item: object)` 🔗 (`fluenttuple`) – The `append()` method supports appending
|
|
448
|
+
the specified `item` into a new tuple along with the values from the original tuple.
|
|
449
|
+
|
|
450
|
+
* `prepend(item: object)` 🔗 (`fluenttuple`) – The `append()` method supports prepending
|
|
451
|
+
the specified `item` into a new tuple along with the values from the original tuple.
|
|
452
|
+
|
|
453
|
+
* `remove(item: object, raises: bool = True)` 🔗 (`fluenttuple`) – The `remove()` method
|
|
454
|
+
supports removing the specified `item` from the current tuples values, returning the
|
|
455
|
+
resulting values as new tuple. If the item is not present, and the optional `raises`
|
|
456
|
+
keyword argument is tuple to its default of `True` then the method will raise a `ValueError`
|
|
457
|
+
exception will be raised noting the absence of the `item` value in the tuple. If `raises`
|
|
458
|
+
is tuple to `False` no exception will be raised, instead the error will be logged, visible
|
|
459
|
+
via the standard `logging` library if the log level is tuple to `ERROR` or higher.
|
|
460
|
+
|
|
461
|
+
* `discard(item: object)` 🔗 (`fluenttuple`) – The `discard()` method supports removing
|
|
462
|
+
the specified `item` from the current tuple if the item is present, returning the resulting
|
|
463
|
+
values as a new tuple. No error is raised if the `item` does not exist in the tuple.
|
|
464
|
+
|
|
465
|
+
* `clear()` 🔗 (`fluenttuple`) – The `clear()` method mimics clearing all of the items
|
|
466
|
+
from the current tuple, by returning a new empty `fluenttuple` instance.
|
|
467
|
+
|
|
468
|
+
* `repeat(count: int)` 🔗 (`fluenttuple`) – The `repeat()` method supports repeating all
|
|
469
|
+
the items from the current tuple by cloning the tuple values and appending the repeated item
|
|
470
|
+
values to the end of the new tuple, following the order in which they were originally defined.
|
|
471
|
+
The values are according to the specified `count` value. The method returns a new tuple.
|
|
472
|
+
|
|
473
|
+
* `reverse()` 🔗 (`fluenttuple`) – The `reverse()` method supports reversing the order
|
|
474
|
+
of the items from the current tuple into a new tuple.
|
|
475
|
+
|
|
476
|
+
* `shuffle()` 🔗 (`fluenttuple`) – The `shuffle()` method supports randomly shuffling all
|
|
477
|
+
of the items from the current tuple into a new tuple.
|
|
478
|
+
|
|
479
|
+
* `slice(start: int, stop: int = None, step: int = 1)` 🔗 (`fluenttuple`) – The `slice()`
|
|
480
|
+
method supports returning a slice of the items from the current tuple according to the
|
|
481
|
+
specified slice indices and step count. The method returns the slice within a new tuple;
|
|
482
|
+
it does not modify the original tuple.
|
|
483
|
+
|
|
484
|
+
* `take(index: int)` 🔗 (`fluenttuple`) – The `take()` method supports returning a slice
|
|
485
|
+
of the items from the current tuple from the beginning of the tuple at index 0 to the stop
|
|
486
|
+
index as specified by the provided `index` argument. The method returns the slice within
|
|
487
|
+
a new tuple; it does not modify the original tuple.
|
|
488
|
+
|
|
489
|
+
* `drop(index: int)` 🔗 (`fluenttuple`) – The `drop()` method supports returning a slice
|
|
490
|
+
of the items from the current tuple from the start index as specified by the provided
|
|
491
|
+
`index` argument until the end of the tuple. The method returns the slice within a new
|
|
492
|
+
tuple; it does not modify the original tuple.
|
|
493
|
+
|
|
494
|
+
* `swap(source: int, target: int)` 🔗 (`fluenttuple`) – The `swap()` method supports
|
|
495
|
+
swapping the items in the tuple at the specified `source` and `target` indices with each
|
|
496
|
+
other. The items are swapped into position within a new tuple, leaving the original untouched.
|
|
497
|
+
|
|
498
|
+
* `unique()` 🔗 (`fluenttuple`) – The `unique()` method supports providing a tuple of the
|
|
499
|
+
unique items from the current tuple. The method returns a new tuple containing the unique
|
|
500
|
+
items found in the current tuple; the original current tuple is not modified.
|
|
501
|
+
|
|
502
|
+
* `count(item: object)` (`int`) – The `count()` method supports providing a count of the
|
|
503
|
+
number of times the specified `item` value appears in the current tuple. The method returns
|
|
504
|
+
the count as an `int` value, so does not allow further chaining, but can be used as the
|
|
505
|
+
last call on chain of other `fluenttuple` methods that do support chaining.
|
|
506
|
+
|
|
507
|
+
* `contains(item: object)` (`bool`) – The `contains()` method supports returning whether
|
|
508
|
+
the specified `item` value appears in the current tuple at least once or not. The method
|
|
509
|
+
returns a `bool` value indicating the presence or absence of the specified `item` value,
|
|
510
|
+
so does not allow further chaining, but can be used as the last call on chain of other
|
|
511
|
+
`fluenttuple` methods that do support chaining.
|
|
512
|
+
|
|
513
|
+
* `any(item: object)` (`bool`) – The `any()` method supports returning whether the current
|
|
514
|
+
tuple contains the specified `item` value at least once or not. As the method returns a
|
|
515
|
+
`bool` value, it does not allow further chaining, but can be used as the last call on
|
|
516
|
+
chain of other `fluenttuple` methods that do support chaining.
|
|
517
|
+
|
|
518
|
+
* `all(item: object)` (`bool`) – The `all()` method supports returning whether the current
|
|
519
|
+
tuple solely contains the specified `item` value or not; that is for the `all()` method
|
|
520
|
+
to return `True`, the current tuple must only contain items that match the specified `item`
|
|
521
|
+
via the equality comparison `==` operator. As the method returns a `bool` value, it does
|
|
522
|
+
not allow further chaining, but can be used as the last call on chain of other `fluenttuple`
|
|
523
|
+
methods that do support chaining.
|
|
524
|
+
|
|
525
|
+
* `map(function: callable)` 🔗 (`fluenttuple`) – The `map()` method supports running the
|
|
526
|
+
specified `function` on each item in the current tuple. The method returns a new tuple
|
|
527
|
+
containing the result of running the `function` on each item in the current tuple rather
|
|
528
|
+
than modifying the current tuple in-place.
|
|
529
|
+
|
|
530
|
+
* `reduce(function: callable)` (`object`) – The `reduce()` method supports running the
|
|
531
|
+
specified `function` on each item in the current tuple, reducing the tuple down to a single
|
|
532
|
+
value, which the method returns upon completion. The method therefore does not support
|
|
533
|
+
chaining but can be as the last call on a chain of other `fluenttuple` methods that do
|
|
534
|
+
support chaining.
|
|
535
|
+
|
|
536
|
+
* `sort(key: object = None, reversed: bool = False)` 🔗 (`fluenttuple`) – The `sort()` method
|
|
537
|
+
supports sorting the current tuple in-place, according to any specified `key` and `reversed`
|
|
538
|
+
arguments. The contents of the current tuple will be updated to reflect the specified sort.
|
|
539
|
+
|
|
540
|
+
* `sorted(key: object = None, reversed: bool = False)` 🔗 (`fluenttuple`) – The `sorted()`
|
|
541
|
+
method supports sorting the current tuple and returning the sorted items as a new tuple,
|
|
542
|
+
according to any specified `key` and `reversed` arguments.
|
|
543
|
+
|
|
544
|
+
* `filter(predicate: callable = None, **filters: dict[str, object])` 🔗 (`fluenttuple`)
|
|
545
|
+
– The `filter()` method supports filtering the contents of the current tuple in the two
|
|
546
|
+
ways noted below, and returns the filtered results as a new tuple:
|
|
547
|
+
- filtering can be performed via a `predicate` callable method that takes as input the
|
|
548
|
+
current item as the tuple is iterated over, where the `predicate` must return `True` for
|
|
549
|
+
items that should remain in the output, and `False` otherwise;
|
|
550
|
+
- alternatively, filtering can be performed via one or more keyword arguments, excepting
|
|
551
|
+
the reserved `predicate` keyword, which define the names and values of object attributes
|
|
552
|
+
that the item objects held in the tuple must match to be included in the output. Each item
|
|
553
|
+
in the tuple will be inspected to see if has the specified attribute (as per the keyword
|
|
554
|
+
argument name) and if so, if that attribute also has a value matching the value of the
|
|
555
|
+
keyword argument; for item objects that both have all of the specified attributes with
|
|
556
|
+
matching values, they will be included in the new tuple created by the filtering call,
|
|
557
|
+
otherwise they will be omitted.
|
|
558
|
+
|
|
559
|
+
* `first(predicate: callable = None, **filters: dict[str, object])` (`fluenttuple`) –
|
|
560
|
+
The `first()` method supports returning the first item of the current tuple. Optionally,
|
|
561
|
+
the contents of the tuple can first be filtered according to the specified `predicate`
|
|
562
|
+
or `filtering` keyword argument values (as per those passed to the `filter()` method),
|
|
563
|
+
and then the first matching item will be returned. If the tuple is either empty or there
|
|
564
|
+
are no matches according to the specified filtering arguments, the method will return
|
|
565
|
+
`None`. As the method returns the first value in the current tuple or `None` if the tuple
|
|
566
|
+
is empty, the method cannot be chained onto, but can be as the last call on a chain of
|
|
567
|
+
other `fluenttuple` methods that do support chaining.
|
|
568
|
+
|
|
569
|
+
* `last(predicate: callable = None, **filters: dict[str, object])` (`fluenttuple`) –
|
|
570
|
+
The `last()` method supports returning the last item of the current tuple. Optionally,
|
|
571
|
+
the contents of the tuple can last be filtered according to the specified `predicate`
|
|
572
|
+
or `filtering` keyword argument values (as per those passed to the `filter()` method),
|
|
573
|
+
and then the last matching item will be returned. If the tuple is either empty or there
|
|
574
|
+
are no matches according to the specified filtering arguments, the method will return
|
|
575
|
+
`None`. As the method returns the last value in the current tuple or `None` if the tuple
|
|
576
|
+
is empty, the method cannot be chained onto, but can be as the last call on a chain of
|
|
577
|
+
other `fluenttuple` methods that do support chaining.
|
|
578
|
+
|
|
579
|
+
#### Fluent Tuple Operator Overrides
|
|
580
|
+
|
|
581
|
+
The `fluenttuple` class also supports several operator overrides which provide some useful
|
|
582
|
+
and convenient behaviours for tuples as noted in the table below:
|
|
583
|
+
|
|
584
|
+
| Operator | Value Type | Method Equivalent | Notes |
|
|
585
|
+
|:--------:|:----------:|-------------------|------------------------------------------------|
|
|
586
|
+
| `+` | `tuple` | `append(...)` | Creates a new tuple and appends to that tuple. |
|
|
587
|
+
| `+=` | `tuple` | `append(...)` | Appends in-place, updating the current tuple. |
|
|
588
|
+
| `-` | `object` | `remove(...)` | Creates a new tuple and removes in that tuple. |
|
|
589
|
+
| `-=` | `object` | `remove(...)` | Removes in-place, updating the current tuple. |
|
|
590
|
+
| `*` | `int` | `repeat(...)` | Creates a new tuple and repeats to that tuple. |
|
|
591
|
+
| `*=` | `int` | `repeat(...)` | Repeats in-place, updating the current tuple. |
|
|
592
|
+
|
|
593
|
+
The `+` and `+=` operator overloads can be used as follows:
|
|
594
|
+
|
|
595
|
+
```python
|
|
596
|
+
from fluently import fluenttuple
|
|
597
|
+
|
|
598
|
+
numbers = fluenttuple([1, 2, 3])
|
|
599
|
+
|
|
600
|
+
# The `+` operator overload returns a new tuple to which the items are added
|
|
601
|
+
newnumbers = numbers + (4, 5, 6)
|
|
602
|
+
|
|
603
|
+
assert newnumbers == (1, 2, 3, 4, 5, 6)
|
|
604
|
+
|
|
605
|
+
# The `+=` operator overload to append items, returning a new tuple
|
|
606
|
+
numbers += (4, 5, 6)
|
|
607
|
+
|
|
608
|
+
assert numbers == (1, 2, 3, 4, 5, 6)
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
The `-` and `-=` operator overloads can be used as follows:
|
|
612
|
+
|
|
613
|
+
```python
|
|
614
|
+
from fluently import fluenttuple
|
|
615
|
+
|
|
616
|
+
numbers = fluenttuple([1, 2, 3])
|
|
617
|
+
|
|
618
|
+
# The `-` operator overload returns a new tuple from which the item is removed
|
|
619
|
+
newnumbers = numbers - 3 # Remove the first occurrence of `3` from the tuple
|
|
620
|
+
|
|
621
|
+
assert newnumbers == (1, 2)
|
|
622
|
+
|
|
623
|
+
# The `-=` operator overload removes the item, returning a new tuple
|
|
624
|
+
numbers -= 3 # Remove the first occurrence of `3` from the tuple
|
|
625
|
+
|
|
626
|
+
assert numbers == (1, 2)
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
The `*` and `*=` operator overloads can be used as follows:
|
|
630
|
+
|
|
631
|
+
```python
|
|
632
|
+
from fluently import fluenttuple
|
|
633
|
+
|
|
634
|
+
numbers = fluenttuple([1, 2, 3])
|
|
635
|
+
|
|
636
|
+
# The `*` operator overload repeats the items, returning a new tuple
|
|
637
|
+
newnumbers = numbers * 2
|
|
638
|
+
|
|
639
|
+
assert newnumbers == (1, 2, 3, 1, 2, 3)
|
|
640
|
+
|
|
641
|
+
# The `*=` operator overload to repeats the items into a new tuple
|
|
642
|
+
numbers *= 2
|
|
643
|
+
|
|
644
|
+
assert numbers == (1, 2, 3, 1, 2, 3)
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Unit Tests
|
|
648
|
+
|
|
649
|
+
The Fluently library includes a suite of comprehensive unit tests which ensure that the
|
|
650
|
+
library functionality operates as expected. The unit tests were developed with and are
|
|
651
|
+
run via `pytest`.
|
|
652
|
+
|
|
653
|
+
To ensure that the unit tests are run within a predictable runtime environment where all of the necessary dependencies are available, a [Docker](https://www.docker.com) image is created within which the tests are run. To run the unit tests, ensure Docker and Docker Compose is [installed](https://docs.docker.com/engine/install/), 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:
|
|
654
|
+
|
|
655
|
+
```shell
|
|
656
|
+
$ docker compose build
|
|
657
|
+
$ docker compose run tests
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
To 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:
|
|
661
|
+
|
|
662
|
+
```shell
|
|
663
|
+
$ docker compose run tests -vv
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
See the documentation for [PyTest](https://docs.pytest.org/en/latest/) regarding available optional command line arguments.
|
|
667
|
+
|
|
668
|
+
### Copyright & License Information
|
|
669
|
+
|
|
670
|
+
Copyright © 2025 Daniel Sissman; licensed under the MIT License.
|