|
1 | 1 | # types-linq
|
2 | 2 |
|
3 |
| - [](https://pypi.org/project/types-linq/) [](https://github.com/cleoold/types-linq/actions?query=workflow%3Apytest) [](https://codecov.io/gh/cleoold/types-linq) |
| 3 | + [](https://pypi.org/project/types-linq/) [](https://github.com/cleoold/types-linq/actions?query=workflow%3Apytest) [](https://codecov.io/gh/cleoold/types-linq) [](https://types-linq.readthedocs.io/en/latest/?badge=latest) |
4 | 4 |
|
5 |
| -This is an attempt to implement linq methods seen in .NET ([link](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=net-5.0)). Currently WIP. |
| 5 | +types-linq is a lightweight Python library that attempts to implement LinQ (Language Integrated Query) features seen in .NET languages. |
6 | 6 |
|
7 |
| -Goal: |
8 |
| -* Incorporates Enumerable method specs as precise as possible |
9 |
| -* Handles infinite streams (generators) smoothly like in _SICP_ |
10 |
| - * Deferred evaluations |
11 |
| -* Detailed typing support |
12 |
| -* Honours collections.abc interfaces |
13 |
| - |
14 |
| -## Install |
15 |
| - |
16 |
| -To install this library on your computer, do: |
17 |
| -```sh |
18 |
| -$ git clone https://github.com/cleoold/types-linq && cd types-linq |
19 |
| -$ pip install . |
20 |
| -# or |
21 |
| -$ python setup.py install |
22 |
| -``` |
23 |
| -Or install from pypi: |
24 |
| -```sh |
25 |
| -$ pip install types-linq -U |
26 |
| -``` |
27 |
| - |
28 |
| -## Dev |
29 |
| -Execute the following commands (or something similar) to run the test cases: |
30 |
| -```sh |
31 |
| -# optionally set up venv |
32 |
| -$ python -m venv |
33 |
| -$ ./scripts/activate |
34 |
| - |
35 |
| -$ pip install pytest |
36 |
| -$ python -m pytest |
37 |
| -``` |
38 |
| - |
39 |
| -## Examples |
40 |
| - |
41 |
| -The usage is simple if you know about the interfaces in .NET as this library provides almost the exact methods. |
42 |
| - |
43 |
| -### [Grouping](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.groupjoin) & Transforming lists |
44 |
| -```py |
45 |
| -from typing import NamedTuple |
46 |
| -from types_linq import Enumerable as En |
47 |
| - |
48 |
| - |
49 |
| -class AnswerSheet(NamedTuple): |
50 |
| - subject: str |
51 |
| - score: int |
52 |
| - name: str |
53 |
| - |
54 |
| -students = ['Jacque', 'Franklin', 'Romeo'] |
55 |
| -papers = [ |
56 |
| - AnswerSheet(subject='Calculus', score=78, name='Jacque'), |
57 |
| - AnswerSheet(subject='Calculus', score=98, name='Romeo'), |
58 |
| - AnswerSheet(subject='Algorithms', score=59, name='Romeo'), |
59 |
| - AnswerSheet(subject='Mechanics', score=93, name='Jacque'), |
60 |
| - AnswerSheet(subject='E & M', score=87, name='Jacque'), |
61 |
| -] |
62 |
| - |
63 |
| -query = En(students) \ |
64 |
| - .order_by(lambda student: student) \ |
65 |
| - .group_join(papers, |
66 |
| - lambda student: student, |
67 |
| - lambda paper: paper.name, |
68 |
| - lambda student, papers: { |
69 |
| - 'student': student, |
70 |
| - 'papers': papers.order_by(lambda paper: paper.subject) \ |
71 |
| - .select(lambda paper: { |
72 |
| - 'subject': paper.subject, |
73 |
| - 'score': paper.score, |
74 |
| - }).to_list(), |
75 |
| - 'gpa': papers.average2(lambda paper: paper.score, None), |
76 |
| - } |
77 |
| - ) |
78 |
| - |
79 |
| -for obj in query: |
80 |
| - print(obj) |
81 |
| - |
82 |
| -# output: |
83 |
| -# {'student': 'Franklin', 'papers': [], 'gpa': None} |
84 |
| -# {'student': 'Jacque', 'papers': [{'subject': 'E & M', 'score': 87}, {'subject': 'Mechanics', 'score': 93}, {'subject': 'Calculus', 'score': 78}], 'gpa': 86.0} |
85 |
| -# {'student': 'Romeo', 'papers': [{'subject': 'Algorithms', 'score': 59}, {'subject': 'Calculus', 'score': 98}], 'gpa': 78.5} |
86 |
| -``` |
87 |
| - |
88 |
| -### Working with generators |
89 |
| -```py |
90 |
| -import random |
91 |
| -from types_linq import Enumerable as En |
92 |
| - |
93 |
| -def toss_coins(): |
94 |
| - while True: |
95 |
| - yield random.choice(('Head', 'Tail')) |
96 |
| - |
97 |
| -times_head = En(toss_coins()).take(5) \ # [:5] also works |
98 |
| - .count(lambda r: r == 'Head') |
99 |
| - |
100 |
| -print(f'You tossed 5 times with {times_head} HEADs!') |
101 |
| - |
102 |
| -# possible output: |
103 |
| -# You tossed 5 times with 2 HEADs! |
104 |
| -``` |
105 |
| - |
106 |
| -### Also querying stream output |
107 |
| -Mixing with builtin iterable type objects. |
108 |
| -```py |
109 |
| -import sys, subprocess |
110 |
| -from types_linq import Enumerable as En |
111 |
| - |
112 |
| -proc = subprocess.Popen('kubectl logs -f my-pod', shell=True, stdout=subprocess.PIPE) |
113 |
| -stdout = iter(proc.stdout.readline, b'') |
114 |
| - |
115 |
| -query = En(stdout).where(lambda line: line.startswith(b'CRITICAL: ')) \ |
116 |
| - .select(lambda line: line[10:].decode()) |
117 |
| - |
118 |
| -for line in query: |
119 |
| - sys.stdout.write(line) |
120 |
| - sys.stdout.flush() |
121 |
| - |
122 |
| -# whatever. |
123 |
| -``` |
| 7 | +Usage, guide and API references are in the [documentation](https://types-linq.readthedocs.io/en/latest/) page. |
0 commit comments