|
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