flpit 0.2.0.dev2__tar.gz → 0.2.1__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.
- flpit-0.2.0.dev2/README.md → flpit-0.2.1/PKG-INFO +88 -1
- flpit-0.2.0.dev2/PKG-INFO → flpit-0.2.1/README.md +64 -21
- {flpit-0.2.0.dev2 → flpit-0.2.1}/pyproject.toml +12 -4
- {flpit-0.2.0.dev2 → flpit-0.2.1}/src/flpit/__init__.py +29 -3
- {flpit-0.2.0.dev2 → flpit-0.2.1}/src/flpit/core/linq.py +148 -39
- flpit-0.2.1/src/flpit/csv.py +333 -0
- flpit-0.2.1/src/flpit/json.py +694 -0
- flpit-0.2.1/src/flpit/task.py +1873 -0
- {flpit-0.2.0.dev2 → flpit-0.2.1}/.gitignore +0 -0
- {flpit-0.2.0.dev2 → flpit-0.2.1}/LICENSE +0 -0
- {flpit-0.2.0.dev2 → flpit-0.2.1}/src/flp/__init__.py +0 -0
- {flpit-0.2.0.dev2 → flpit-0.2.1}/src/flpit/core/__init__.py +0 -0
- {flpit-0.2.0.dev2 → flpit-0.2.1}/src/flpit/flp.py +0 -0
- {flpit-0.2.0.dev2 → flpit-0.2.1}/src/flpit/py.typed +0 -0
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: flpit
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Fluent LINQ for Python — flip your iterables
|
|
5
|
+
Project-URL: Homepage, https://github.com/riemar/flpit
|
|
6
|
+
Project-URL: Repository, https://github.com/riemar/flpit
|
|
7
|
+
Project-URL: Issues, https://github.com/riemar/flpit/issues
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: fluent,generators,iterable,lazy-evaluation,linq,pipeline,pyrefly,type-safe
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Requires-Dist: msgspec>=0.22.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
1
25
|
# FlpIt
|
|
2
26
|
|
|
3
27
|
> **Fluent LINQ for Python — LINQ semantics, Python-native execution**
|
|
@@ -130,6 +154,52 @@ print(list(backend_engineers))
|
|
|
130
154
|
# ['Alice']
|
|
131
155
|
```
|
|
132
156
|
|
|
157
|
+
## JSON Serialization
|
|
158
|
+
|
|
159
|
+
FlpIt provides typed JSON serialization and deserialization through `flpit.json.JsonConvert`,
|
|
160
|
+
backed by [`msgspec`](https://github.com/jcrist/msgspec).
|
|
161
|
+
|
|
162
|
+
It supports dataclasses, nested models, generic containers, configurable property naming, and explicit field metadata.
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from dataclasses import dataclass
|
|
166
|
+
from typing import Annotated
|
|
167
|
+
|
|
168
|
+
from flpit import FlpList
|
|
169
|
+
from flpit.json import JProp, JIgnore, JsonConvert
|
|
170
|
+
|
|
171
|
+
@dataclass
|
|
172
|
+
class Person:
|
|
173
|
+
first_name: str
|
|
174
|
+
internal_id: Annotated[str, JProp("id")]
|
|
175
|
+
password: Annotated[str, JIgnore] = ""
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
person = Person("Ada", "usr-42", "secret")
|
|
179
|
+
raw = JsonConvert.serialize(person, Person)
|
|
180
|
+
# {"firstName":"Ada","id":"usr-42"}
|
|
181
|
+
|
|
182
|
+
people_json = """
|
|
183
|
+
[
|
|
184
|
+
{"firstName": "Ada", "id": "usr-42"},
|
|
185
|
+
{"firstName": "Grace", "id": "usr-43"}
|
|
186
|
+
]
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
people: FlpList[Person] = FlpList.from_json(people_json, Person)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Mapping and conversion
|
|
193
|
+
|
|
194
|
+
- **Naming policies:** Configure automatic property naming with `JsonSerializerOptions`. The default is camel case.
|
|
195
|
+
- **Explicit metadata:** `JProp` assigns a specific JSON property name, `JIgnore` excludes a field, and `JInclude` explicitly includes otherwise excluded underscore-prefixed fields.
|
|
196
|
+
- **Serialization options:** Control default-value omission and whether unknown JSON fields are accepted or rejected.
|
|
197
|
+
- **Typed collections:** Pass the complete target type, such as `list[Person]`, so nested and generic values can be decoded against the intended schema.
|
|
198
|
+
|
|
199
|
+
For large outputs, `JsonConvert.serialize_to()` writes a JSON array to a file-like stream without first materializing the entire serialized document.
|
|
200
|
+
|
|
201
|
+
By default, deserialization returns instances of the requested model type. Setting `native=True` opts into the generated `msgspec.Struct` representation instead, trading the original model type for the native representation and its performance characteristics.
|
|
202
|
+
|
|
133
203
|
## 🔬 LINQ Semantics, Python Runtime
|
|
134
204
|
|
|
135
205
|
`flpit` deliberately separates the two:
|
|
@@ -325,6 +395,21 @@ to_list ← terminal materialization
|
|
|
325
395
|
|
|
326
396
|
Operations such as `order_by()` necessarily materialize their input internally to establish ordering.
|
|
327
397
|
|
|
398
|
+
## ⚙️ Task Runtime
|
|
399
|
+
|
|
400
|
+
FlpIt includes a lightweight, `asyncio`-free task runtime for scheduling and coordinating concurrent work, with synchronous callables executed through a bounded worker pool.
|
|
401
|
+
|
|
402
|
+
Key features:
|
|
403
|
+
|
|
404
|
+
- **Task scheduling:** `Task.run()` schedules coroutines, awaitables, and synchronous callables.
|
|
405
|
+
- **Task coordination:** `Task.when_all()` waits for all tasks while preserving input order; `Task.when_any()` returns the first completed task; `Task.collect()` yields tasks as they complete.
|
|
406
|
+
- **Cancellation:** `CancellationToken` and `CancellationTokenSource` support cooperative cancellation, cancellation callbacks, timeouts, and linked cancellation tokens.
|
|
407
|
+
- **Resource management:** Configure worker capacity and pending background-work limits, handle queue saturation explicitly, and shut down the process-wide runtime with an observable shutdown report.
|
|
408
|
+
|
|
409
|
+
The runtime starts lazily and manages its own lifecycle. It is deliberately not an `asyncio` compatibility layer; cancellation of running synchronous functions is cooperative.
|
|
410
|
+
|
|
411
|
+
See the [Task Runtime examples](https://github.com/riemar/flpit/tree/main/examples/task) for usage examples.
|
|
412
|
+
|
|
328
413
|
## ⚙️ Installation
|
|
329
414
|
|
|
330
415
|
```bash
|
|
@@ -349,16 +434,18 @@ Distributed under the MIT License. See `LICENSE` for more information.
|
|
|
349
434
|
| ├── test_all.py | 80 |
|
|
350
435
|
| ├── test_any.py | 90 |
|
|
351
436
|
| ├── test_average.py | 572 |
|
|
437
|
+
| ├── test_concat.py | 64 |
|
|
352
438
|
| ├── test_count.py | 37 |
|
|
353
439
|
| ├── test_generic_list.py | 95 |
|
|
354
440
|
| ├── test_last.py | 29 |
|
|
355
441
|
| ├── test_order_by.py | 100 |
|
|
356
442
|
| ├── test_order_descending_by.py | 45 |
|
|
443
|
+
| ├── test_skip.py | 75 |
|
|
357
444
|
| ├── test_sum.py | 134 |
|
|
358
445
|
| ├── test_take.py | 39 |
|
|
359
446
|
| ├── test_then_by.py | 40 |
|
|
360
447
|
| └── test_then_descending_by.py | 34 |
|
|
361
448
|
----------------------------------------------------------------
|
|
362
|
-
| GRAND TOTALS |
|
|
449
|
+
| GRAND TOTALS | 1434 |
|
|
363
450
|
================================================================
|
|
364
451
|
```
|
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: flpit
|
|
3
|
-
Version: 0.2.0.dev2
|
|
4
|
-
Summary: Fluent LINQ for Python — flip your iterables
|
|
5
|
-
License: MIT
|
|
6
|
-
License-File: LICENSE
|
|
7
|
-
Keywords: fluent,generators,iterable,lazy-evaluation,linq,pipeline,pyrefly,type-safe
|
|
8
|
-
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Classifier: Intended Audience :: Developers
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
-
Classifier: Typing :: Typed
|
|
18
|
-
Requires-Python: >=3.11
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
|
|
21
1
|
# FlpIt
|
|
22
2
|
|
|
23
3
|
> **Fluent LINQ for Python — LINQ semantics, Python-native execution**
|
|
@@ -150,6 +130,52 @@ print(list(backend_engineers))
|
|
|
150
130
|
# ['Alice']
|
|
151
131
|
```
|
|
152
132
|
|
|
133
|
+
## JSON Serialization
|
|
134
|
+
|
|
135
|
+
FlpIt provides typed JSON serialization and deserialization through `flpit.json.JsonConvert`,
|
|
136
|
+
backed by [`msgspec`](https://github.com/jcrist/msgspec).
|
|
137
|
+
|
|
138
|
+
It supports dataclasses, nested models, generic containers, configurable property naming, and explicit field metadata.
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from dataclasses import dataclass
|
|
142
|
+
from typing import Annotated
|
|
143
|
+
|
|
144
|
+
from flpit import FlpList
|
|
145
|
+
from flpit.json import JProp, JIgnore, JsonConvert
|
|
146
|
+
|
|
147
|
+
@dataclass
|
|
148
|
+
class Person:
|
|
149
|
+
first_name: str
|
|
150
|
+
internal_id: Annotated[str, JProp("id")]
|
|
151
|
+
password: Annotated[str, JIgnore] = ""
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
person = Person("Ada", "usr-42", "secret")
|
|
155
|
+
raw = JsonConvert.serialize(person, Person)
|
|
156
|
+
# {"firstName":"Ada","id":"usr-42"}
|
|
157
|
+
|
|
158
|
+
people_json = """
|
|
159
|
+
[
|
|
160
|
+
{"firstName": "Ada", "id": "usr-42"},
|
|
161
|
+
{"firstName": "Grace", "id": "usr-43"}
|
|
162
|
+
]
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
people: FlpList[Person] = FlpList.from_json(people_json, Person)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Mapping and conversion
|
|
169
|
+
|
|
170
|
+
- **Naming policies:** Configure automatic property naming with `JsonSerializerOptions`. The default is camel case.
|
|
171
|
+
- **Explicit metadata:** `JProp` assigns a specific JSON property name, `JIgnore` excludes a field, and `JInclude` explicitly includes otherwise excluded underscore-prefixed fields.
|
|
172
|
+
- **Serialization options:** Control default-value omission and whether unknown JSON fields are accepted or rejected.
|
|
173
|
+
- **Typed collections:** Pass the complete target type, such as `list[Person]`, so nested and generic values can be decoded against the intended schema.
|
|
174
|
+
|
|
175
|
+
For large outputs, `JsonConvert.serialize_to()` writes a JSON array to a file-like stream without first materializing the entire serialized document.
|
|
176
|
+
|
|
177
|
+
By default, deserialization returns instances of the requested model type. Setting `native=True` opts into the generated `msgspec.Struct` representation instead, trading the original model type for the native representation and its performance characteristics.
|
|
178
|
+
|
|
153
179
|
## 🔬 LINQ Semantics, Python Runtime
|
|
154
180
|
|
|
155
181
|
`flpit` deliberately separates the two:
|
|
@@ -345,6 +371,21 @@ to_list ← terminal materialization
|
|
|
345
371
|
|
|
346
372
|
Operations such as `order_by()` necessarily materialize their input internally to establish ordering.
|
|
347
373
|
|
|
374
|
+
## ⚙️ Task Runtime
|
|
375
|
+
|
|
376
|
+
FlpIt includes a lightweight, `asyncio`-free task runtime for scheduling and coordinating concurrent work, with synchronous callables executed through a bounded worker pool.
|
|
377
|
+
|
|
378
|
+
Key features:
|
|
379
|
+
|
|
380
|
+
- **Task scheduling:** `Task.run()` schedules coroutines, awaitables, and synchronous callables.
|
|
381
|
+
- **Task coordination:** `Task.when_all()` waits for all tasks while preserving input order; `Task.when_any()` returns the first completed task; `Task.collect()` yields tasks as they complete.
|
|
382
|
+
- **Cancellation:** `CancellationToken` and `CancellationTokenSource` support cooperative cancellation, cancellation callbacks, timeouts, and linked cancellation tokens.
|
|
383
|
+
- **Resource management:** Configure worker capacity and pending background-work limits, handle queue saturation explicitly, and shut down the process-wide runtime with an observable shutdown report.
|
|
384
|
+
|
|
385
|
+
The runtime starts lazily and manages its own lifecycle. It is deliberately not an `asyncio` compatibility layer; cancellation of running synchronous functions is cooperative.
|
|
386
|
+
|
|
387
|
+
See the [Task Runtime examples](https://github.com/riemar/flpit/tree/main/examples/task) for usage examples.
|
|
388
|
+
|
|
348
389
|
## ⚙️ Installation
|
|
349
390
|
|
|
350
391
|
```bash
|
|
@@ -369,16 +410,18 @@ Distributed under the MIT License. See `LICENSE` for more information.
|
|
|
369
410
|
| ├── test_all.py | 80 |
|
|
370
411
|
| ├── test_any.py | 90 |
|
|
371
412
|
| ├── test_average.py | 572 |
|
|
413
|
+
| ├── test_concat.py | 64 |
|
|
372
414
|
| ├── test_count.py | 37 |
|
|
373
415
|
| ├── test_generic_list.py | 95 |
|
|
374
416
|
| ├── test_last.py | 29 |
|
|
375
417
|
| ├── test_order_by.py | 100 |
|
|
376
418
|
| ├── test_order_descending_by.py | 45 |
|
|
419
|
+
| ├── test_skip.py | 75 |
|
|
377
420
|
| ├── test_sum.py | 134 |
|
|
378
421
|
| ├── test_take.py | 39 |
|
|
379
422
|
| ├── test_then_by.py | 40 |
|
|
380
423
|
| └── test_then_descending_by.py | 34 |
|
|
381
424
|
----------------------------------------------------------------
|
|
382
|
-
| GRAND TOTALS |
|
|
425
|
+
| GRAND TOTALS | 1434 |
|
|
383
426
|
================================================================
|
|
384
427
|
```
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flpit"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "Fluent LINQ for Python — flip your iterables"
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
7
|
license = { text = "MIT" }
|
|
8
8
|
keywords = ["linq", "fluent", "iterable", "pipeline", "lazy-evaluation", "pyrefly", "type-safe", "generators"]
|
|
9
9
|
classifiers = [
|
|
@@ -11,14 +11,21 @@ classifiers = [
|
|
|
11
11
|
"Intended Audience :: Developers",
|
|
12
12
|
"License :: OSI Approved :: MIT License",
|
|
13
13
|
"Programming Language :: Python :: 3",
|
|
14
|
-
"Programming Language :: Python :: 3.11",
|
|
15
14
|
"Programming Language :: Python :: 3.12",
|
|
16
15
|
"Programming Language :: Python :: 3.13",
|
|
17
16
|
"Programming Language :: Python :: 3.14",
|
|
17
|
+
"Programming Language :: Python :: 3.15",
|
|
18
18
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
19
19
|
"Typing :: Typed"
|
|
20
20
|
]
|
|
21
|
-
dependencies = [
|
|
21
|
+
dependencies = [
|
|
22
|
+
"msgspec>=0.22.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://github.com/riemar/flpit"
|
|
27
|
+
Repository = "https://github.com/riemar/flpit"
|
|
28
|
+
Issues = "https://github.com/riemar/flpit/issues"
|
|
22
29
|
|
|
23
30
|
[dependency-groups]
|
|
24
31
|
dev = [
|
|
@@ -28,6 +35,7 @@ dev = [
|
|
|
28
35
|
"pyright>=1.1.414",
|
|
29
36
|
"pytest-benchmark>=5.3.0",
|
|
30
37
|
"mypy>=2.4.0",
|
|
38
|
+
"httpx>=0.28.1",
|
|
31
39
|
]
|
|
32
40
|
|
|
33
41
|
|
|
@@ -5,33 +5,59 @@ from __future__ import annotations
|
|
|
5
5
|
from importlib.metadata import version
|
|
6
6
|
__version__ = version("flpit")
|
|
7
7
|
|
|
8
|
-
import builtins
|
|
9
|
-
from typing import Iterable as _Iterable, TypeVar
|
|
10
|
-
|
|
11
8
|
from flpit import flp
|
|
12
9
|
from flpit.core.linq import (
|
|
13
10
|
FlpIt,
|
|
14
11
|
FlpList,
|
|
15
12
|
Grouping,
|
|
16
13
|
OrderedIt,
|
|
14
|
+
|
|
15
|
+
#====================
|
|
16
|
+
# InvalidOperationException
|
|
17
|
+
#====================
|
|
18
|
+
InvalidOperationError,
|
|
17
19
|
EmptySequenceError,
|
|
18
20
|
NoMatchError,
|
|
19
21
|
MultipleElementsError,
|
|
20
22
|
MultipleMatchesError,
|
|
23
|
+
|
|
24
|
+
#====================
|
|
25
|
+
# ArgumentExceptions
|
|
26
|
+
#====================
|
|
27
|
+
ArgumentError,
|
|
28
|
+
ArgumentNullError,
|
|
21
29
|
SourceNoneError,
|
|
22
30
|
PredicateNoneError,
|
|
31
|
+
CollectionNoneError,
|
|
32
|
+
SelectorNoneError,
|
|
33
|
+
SecondNoneError,
|
|
34
|
+
ArgumentOutOfRangeError,
|
|
35
|
+
ArgumentNonNegError,
|
|
36
|
+
ArgumentOutOfBoundsError
|
|
23
37
|
)
|
|
24
38
|
|
|
25
39
|
__all__ = [
|
|
40
|
+
"flp",
|
|
26
41
|
"FlpIt",
|
|
27
42
|
"FlpList",
|
|
28
43
|
"Grouping",
|
|
29
44
|
"OrderedIt",
|
|
45
|
+
|
|
46
|
+
"InvalidOperationError",
|
|
30
47
|
"EmptySequenceError",
|
|
31
48
|
"NoMatchError",
|
|
32
49
|
"MultipleElementsError",
|
|
33
50
|
"MultipleMatchesError",
|
|
51
|
+
|
|
52
|
+
"ArgumentError",
|
|
53
|
+
"ArgumentNullError",
|
|
34
54
|
"SourceNoneError",
|
|
35
55
|
"PredicateNoneError",
|
|
56
|
+
"CollectionNoneError",
|
|
57
|
+
"SelectorNoneError",
|
|
58
|
+
"SecondNoneError",
|
|
59
|
+
"ArgumentOutOfRangeError",
|
|
60
|
+
"ArgumentNonNegError",
|
|
61
|
+
"ArgumentOutOfBoundsError",
|
|
36
62
|
]
|
|
37
63
|
|