Browse Source

initial commit

Médéric Hurier 4 months ago
commit
3ee41a1491
17 changed files with 606 additions and 0 deletions
  1. 15
    0
      .gitignore
  2. 1
    0
      .python-version
  3. 1
    0
      LICENSE.txt
  4. 16
    0
      Makefile
  5. 1
    0
      README.md
  6. 13
    0
      devs/Makefile
  7. 2
    0
      devs/requirements.txt
  8. 462
    0
      gampy/__init__.py
  9. 6
    0
      hooks/Makefile
  10. 3
    0
      hooks/pre-commit
  11. 16
    0
      packages/Makefile
  12. 2
    0
      packages/requirements.txt
  13. 0
    0
      requirements.txt
  14. 41
    0
      setup.py
  15. 9
    0
      shells/Makefile
  16. 16
    0
      shells/ipython.py
  17. 2
    0
      shells/requirements.txt

+ 15
- 0
.gitignore View File

@@ -0,0 +1,15 @@
1
+.tox
2
+.env
3
+dist/
4
+build/
5
+.venv/
6
+.cache/
7
+*.py[cod]
8
+*.zipapp/
9
+.coverage
10
+*.egg-info/
11
+__pycache__/
12
+.hypothesis/
13
+.mypy_cache/
14
+.pytest_cache/
15
+.ipynb_checkpoints/

+ 1
- 0
.python-version View File

@@ -0,0 +1 @@
1
+3.7.0

+ 1
- 0
LICENSE.txt View File

@@ -0,0 +1 @@
1
+EUPL-1.2

+ 16
- 0
Makefile View File

@@ -0,0 +1,16 @@
1
+MKFILES = $(wildcard */Makefile)
2
+
3
+.venv:
4
+	python -m venv .venv --clear
5
+
6
+init: .venv
7
+	@for MK in ${MKFILES}; do make --no-print-directory -f $$MK init-$$(dirname $$MK); done
8
+
9
+clean:
10
+	@for MK in ${MKFILES}; do make --no-print-directory -f $$MK clean-$$(dirname $$MK); done
11
+
12
+commit: .venv
13
+	@set -e; \
14
+	for MK in ${MKFILES}; do make --no-print-directory -f $$MK commit-$$(dirname $$MK); done
15
+
16
+include */Makefile

+ 1
- 0
README.md View File

@@ -0,0 +1 @@
1
+# gampy

+ 13
- 0
devs/Makefile View File

@@ -0,0 +1,13 @@
1
+init-devs: .venv
2
+	.venv/bin/pip install -e .
3
+	.venv/bin/pip install '.[devs]'
4
+
5
+clean-devs:
6
+	find . -name '*~' -exec rm -f {} +
7
+	find . -name '*.pyc' -exec rm -f {} +
8
+	find . -name '*.pyo' -exec rm -f {} +
9
+	find . -name '*.egg' -exec rm -f {} +
10
+	find . -name '*.egg-info' -exec rm -fr {} +
11
+	find . -name '__pycache__' -exec rm -fr {} +
12
+
13
+commit-devs: ;

+ 2
- 0
devs/requirements.txt View File

@@ -0,0 +1,2 @@
1
+pip>=18
2
+setuptools>=40

+ 462
- 0
gampy/__init__.py View File

@@ -0,0 +1,462 @@
1
+# from typing import Callable, Iterable
2
+
3
+
4
+# class Error(Exception):
5
+#     """Base class for errors."""
6
+
7
+#     pass
8
+
9
+
10
+# class DefinitionError(Error):
11
+#     """Error during program definition."""
12
+
13
+#     pass
14
+
15
+
16
+# class ExecutionError(Error):
17
+#     """Error during program execution."""
18
+
19
+#     pass
20
+
21
+
22
+# class Program(object):
23
+#     """Program as a sequence of steps."""
24
+
25
+#     def __init__(self, *steps):
26
+#         """Initialize the program steps."""
27
+#         self.steps = steps  # trigger setter
28
+
29
+#     # PROPERTY
30
+
31
+#     @property
32
+#     def steps(self):
33
+#         """Return the program steps."""
34
+#         return self._steps
35
+
36
+#     @steps.setter
37
+#     def steps(self, steps):
38
+#         """Append steps to the program."""
39
+#         self._steps = []
40
+
41
+#         for s in steps:
42
+#             # fill blanks
43
+#             if len(s) == 1:
44
+#                 step = (s[0], list(), dict())
45
+#             elif len(s) == 2:
46
+#                 step = (s[0], s[1], dict())
47
+#             elif len(s) == 3:
48
+#                 step = (s[0], s[1], s[2])
49
+#             else:
50
+#                 raise DefinitionError(
51
+#                     f"The number of step arguments should be between 1 and 3. Got: {len(steps)}"
52
+#                 )
53
+
54
+#             # validate steps
55
+#             if not isinstance(step[0], Callable):
56
+#                 raise DefinitionError(
57
+#                     f"The first step argument should be Callable. Got: {type(step[0]).__name__}"
58
+#                 )
59
+#             elif not isinstance(step[1], Iterable):
60
+#                 raise DefinitionError(
61
+#                     f"The second step argument should be Iterable. Got: {type(step[1]).__name__}"
62
+#                 )
63
+#             elif not isinstance(step[2], Iterable):
64
+#                 raise DefinitionError(
65
+#                     f"The third step argument should be Iterable. Got: {type(step[2]).__name__}"
66
+#                 )
67
+
68
+#             self._steps.append(step)
69
+
70
+#     # FORMAT
71
+
72
+#     def __str__(self):
73
+#         """Return a string from the program steps."""
74
+
75
+#         def fmt(step):
76
+#             f, args, kwargs = step
77
+
78
+#             strf = f.__name__
79
+#             strargs = [str(x) for x in args]
80
+#             strkwargs = [f"{k}={v}" for k, v in kwargs.items()]
81
+
82
+#             return f"{strf}({', '.join(strargs + strkwargs) })"
83
+
84
+#         return "\n".join(map(fmt, self.steps))
85
+
86
+#     def __repr__(self):
87
+#         """Return a representation of the program steps."""
88
+#         return str(self.steps)
89
+
90
+#     # ALGEBRA
91
+
92
+#     def __add__(self, other):
93
+#         """Combine program steps."""
94
+#         return self.__class__(self.steps + other.steps)
95
+
96
+#     def __sub__(self, other):
97
+#         """Filter program steps."""
98
+#         steps = []
99
+
100
+#         for s in self.steps:
101
+#             if s not in other:
102
+#                 steps.append(s)
103
+
104
+#         return self.__class__(steps)
105
+
106
+#     def __mul__(self, n):
107
+#         """Duplicate program steps."""
108
+#         return self.__class__(self._steps * 2)
109
+
110
+#     def __matmul__(self, g):
111
+#         """Compose program functions."""
112
+#         return self.__class__((g(f), args, kwargs) for f, args, kwargs in self.steps)
113
+
114
+#     def __truediv__(self, n):
115
+#         """Chunk steps in smaller programs."""
116
+#         chunk = []
117
+
118
+#         for i, s in enumerate(self.steps, 1):
119
+#             chunk.append(s)
120
+
121
+#             if i % n == 0:
122
+#                 yield self.__class__(*chunk)
123
+#                 chunk.clear()
124
+
125
+#     def __floordiv__(self, n):
126
+#         """Chunk all steps in smaller programs."""
127
+#         chunk = []
128
+
129
+#         for i, x in enumerate(self.steps, 1):
130
+#             chunk.append(x)
131
+
132
+#             if i % n == 0:
133
+#                 yield self.__class__(*chunk)
134
+#                 chunk.clear()
135
+
136
+#         if chunk:
137
+#             yield self.__class__(*chunk)
138
+
139
+#     def __mod__(self, other):
140
+#         """Alternate program steps."""
141
+#         gen = it.chain.from_iterable(it.zip_longest(self.steps, other.steps))
142
+
143
+#         steps = [s for s in gen if s is not None]
144
+
145
+#         return self.__class__(steps)
146
+
147
+#     def __pow__(self, other):
148
+#         pass
149
+
150
+#     def __lshift__(self, n):
151
+#         """Shift program steps to the left."""
152
+#         return self.__class__(self.steps[n:] + self.steps[:n])
153
+
154
+#     def __rshift__(self, n):
155
+#         """Shift program steps to the right."""
156
+#         return self.__class__(self.steps[-n:] + self.steps[:-n])
157
+
158
+#     def __and__(self, other):
159
+#         """Intersect program steps."""
160
+#         steps = []
161
+
162
+#         for s in self.steps:
163
+#             if s in other:
164
+#                 steps.append(s)
165
+
166
+#         return self.__class__(steps)
167
+
168
+#     def __xor__(self, other):
169
+#         """Symmetric program steps."""
170
+#         return (self + other) - (self & other)
171
+
172
+#     def __or__(self, other):
173
+#         pass
174
+
175
+#     # INPLACE
176
+
177
+#     def __iadd__(self, other):
178
+#         """Combine program steps."""
179
+#         self._steps += other.steps
180
+
181
+#     def __isub__(self, other):
182
+#         """Filter program steps."""
183
+#         steps = []
184
+
185
+#         for s in self.steps:
186
+#             if s not in other:
187
+#                 steps.append(s)
188
+
189
+#         self._steps = steps
190
+
191
+#     def __imul__(self, n):
192
+#         """Duplicate program steps"""
193
+#         self._steps = self.steps * n
194
+
195
+#     def __imatmul__(self, g):
196
+#         """Combine program functions."""
197
+#         self._steps = [(g(f), args, kwargs) for f, args, kwargs in self.steps]
198
+
199
+#     def __imod__(self, other):
200
+#         """Alternate program steps."""
201
+#         gen = it.chain.from_iterable(it.zip_longest(self.steps, other.steps))
202
+
203
+#         self._steps = [s for s in gen if s is not None]
204
+
205
+#     def __ipow__(self, other):
206
+#         pass
207
+
208
+#     def __ilshift__(self, n):
209
+#         """Shift program steps to the left."""
210
+#         self._steps = self.steps[n:] + self.steps[:n]
211
+
212
+#     def __irshift__(self, n):
213
+#         """Shift program steps to the right."""
214
+#         self.steps = self.steps[-n:] + self.steps[:-n]
215
+
216
+#     def __iand__(self, other):
217
+#         """Intersect program steps."""
218
+#         steps = []
219
+
220
+#         for s in self.steps:
221
+#             if s in other:
222
+#                 steps.append(s)
223
+
224
+#         self._steps = steps
225
+
226
+#     def __ixor__(self, other):
227
+#         """Symmetric program steps."""
228
+#         self._steps = (self ^ other).steps
229
+
230
+#     def __ior__(self, other):
231
+#         pass
232
+
233
+#     # CONTEXT
234
+
235
+#     def __enter__(self):
236
+#         """Return the program steps."""
237
+#         return self.steps
238
+
239
+#     def __exit__(self, exc_type, exc_value, traceback):
240
+#         """Update the program steps."""
241
+#         self.steps = self._steps  # trigger setter
242
+
243
+#     # CALLABLE
244
+#     def __call__(self, state, control=None):
245
+#         """Execute program steps."""
246
+#         try:
247
+#             for step in self.steps:
248
+#                 if control is not None:
249
+#                     step, state = control(step, state)
250
+
251
+#                 f, args, kwargs = step
252
+#                 state = f(*args, **kwargs)
253
+
254
+#             return state
255
+#         except Exception as err:
256
+#             raise ExecutionError() from err
257
+
258
+#     # CONVERTER
259
+
260
+#     def __bool__(self):
261
+#         """Return True if program is not empty."""
262
+#         return len(self.steps) > 0
263
+
264
+#     # COLLECTION
265
+
266
+#     def __len__(self):
267
+#         """Return the number of steps."""
268
+#         return len(self.steps)
269
+
270
+#     def __iter__(self):
271
+#         """Iterate over the program steps."""
272
+#         return iter(self.steps)
273
+
274
+#     def __reversed__(self):
275
+#         """Reverse the steps of the program."""
276
+#         return self.__init__(*reversed(self.steps))
277
+
278
+#     def __getitem__(self, n):
279
+#         """Return the n step of the program."""
280
+#         return self.steps[n]
281
+
282
+#     def __delitem__(self, n):
283
+#         """Delete the n step of the program."""
284
+#         del self.steps[n]
285
+
286
+#     def __setitem__(self, n, step):
287
+#         """Change the n step of the program."""
288
+#         self.steps[n] = step
289
+
290
+#     def __contains__(self, step):
291
+#         """Return True if step exists in the program."""
292
+#         return step in self.steps
293
+
294
+#     # COMPARABLE
295
+
296
+#     def __lt__(self, other):
297
+#         """Compare the program lengths with <."""
298
+#         return len(self) < len(other)
299
+
300
+#     def __le__(self, other):
301
+#         """Compare the program lengths with <=."""
302
+#         return len(self) <= len(other)
303
+
304
+#     def __eq__(self, other):
305
+#         """Compare the program lengths with ==."""
306
+#         return len(self) == len(other)
307
+
308
+#     def __ne__(self, other):
309
+#         """Compare the program lengths with !=."""
310
+#         return len(self) != len(other)
311
+
312
+#     def __ge__(self, other):
313
+#         """Compare the program lengths with >=."""
314
+#         return len(self) >= len(other)
315
+
316
+#     def __gt__(self, other):
317
+#         """Compare the program lengths with >."""
318
+#         return len(self) > len(other)
319
+
320
+
321
+# # promise to store state
322
+# # append f as args
323
+
324
+
325
+# # def optional(default):
326
+# #     def decorator(f):
327
+# #         @wraps(f)
328
+# #         def decorated(*args, **kwargs):
329
+# #             state = f(*args, **kwargs)
330
+
331
+# #             if state is None:
332
+# #                 return default
333
+
334
+# #         return decorated
335
+
336
+# #     return decorator
337
+
338
+
339
+# # def Except(on=Exception):
340
+# #     def except_(f, args, kwargs, state):
341
+# #         if issubclass(state, on):
342
+# #             return state
343
+
344
+# #         try:
345
+# #             state = f(*args, **kwargs)
346
+# #         except on as ex:
347
+# #             return ex
348
+
349
+# #     return except_
350
+
351
+# # class Pipe(Program):
352
+# #     FIRST = 0
353
+# #     LAST = -1
354
+
355
+# #     def __init__(self, *steps, n=FIRST):
356
+# #         super().__init__(*steps, {"n": n})
357
+
358
+# #     def __call__(self, state=None):
359
+# #         """Call the program and inject state"""
360
+# #         for f, args, kwargs in self.steps:
361
+# #             args_ = args.copy()
362
+
363
+# #             if self.n < 0:
364
+# #                 args_.append(state)
365
+# #             else:
366
+# #                 args_.insert(self.n, state)
367
+
368
+# #             return f(*args_, **kwargs)
369
+
370
+
371
+# # class Block(Program):
372
+# #     def __call__(self, state=None):
373
+# #         """Call the program and ignore state"""
374
+# #         for f, args, kwargs in self.steps:
375
+# #             return f(*args, **kwargs)
376
+
377
+
378
+# # def Context():
379
+# #     pass
380
+
381
+
382
+# # def Capture():
383
+# #     # capture stdout/stderr
384
+# #     pass
385
+
386
+
387
+# # def Memoize():
388
+# #     pass
389
+
390
+
391
+# # def Log():
392
+# #     pass
393
+
394
+
395
+# # def Pre(do):
396
+# #     def pre(f, args, kwargs, state):
397
+# #         pre(f, args, kwargs, state)
398
+
399
+# #         return f(args, kwargs, state)
400
+
401
+# #     return pre
402
+
403
+
404
+# # def Post(do):
405
+# #     def post(f, args, kwargs, state):
406
+# #         state = f(args, kwargs, state)
407
+# #         do(f, args, kwargs, state)
408
+
409
+# #         return state
410
+
411
+# #     return post
412
+
413
+
414
+# # # Cache: cache f/args
415
+
416
+# # # Cat: (list monad)
417
+
418
+# # # Lazy: convert to gen
419
+
420
+# # # Watch: pre/post fn
421
+
422
+# # # Strict: convert to list
423
+
424
+# # # Ident: imperative style
425
+
426
+# # # Do: independent actions
427
+
428
+# # # On: perform on object
429
+
430
+# # # Pipe: (->, ->>, as->)
431
+
432
+# # # Resource: use context lib
433
+
434
+# # # Context: pass dict
435
+
436
+# # # Delay / Future
437
+
438
+# # # Parallel
439
+
440
+# # # Partial / Compose
441
+
442
+
443
+# # def run(prog, state=None):
444
+# #     for f, args, kwargs in prog.steps:
445
+# #         state = f(*args, **kwargs)
446
+
447
+
448
+# # def opt(prog, state=None, default=0):
449
+# #     for f, args, kwargs in prog.steps:
450
+# #         state = f(*args, **kwargs)
451
+
452
+# #         if state is None:
453
+# #             state = default
454
+
455
+
456
+# # prog = Program((print, [0]))
457
+
458
+# # with prog as steps:
459
+# #     steps.append((print, [1, 2]))
460
+# #     steps.append((print, [3, 4]))
461
+
462
+# # run(prog)

+ 6
- 0
hooks/Makefile View File

@@ -0,0 +1,6 @@
1
+init-hooks:
2
+	git config --global core.hooksPath hooks/
3
+
4
+clean-hooks: ;
5
+
6
+commit-hooks: ;

+ 3
- 0
hooks/pre-commit View File

@@ -0,0 +1,3 @@
1
+#!/bin/sh
2
+
3
+make commit

+ 16
- 0
packages/Makefile View File

@@ -0,0 +1,16 @@
1
+.PHONY: package upload
2
+
3
+init-packages: .venv
4
+	.venv/bin/pip install '.[packages]'
5
+
6
+clean-packages:
7
+	rm -rf build/lib/
8
+	rm -rf dist/*.whl
9
+
10
+commit-packages: package;
11
+
12
+package: .venv clean-packages
13
+	.venv/bin/python setup.py bdist_wheel --universal
14
+
15
+upload: package
16
+	.venv/bin/twine upload -r pypi dist/*.whl

+ 2
- 0
packages/requirements.txt View File

@@ -0,0 +1,2 @@
1
+twine
2
+wheel

+ 0
- 0
requirements.txt View File


+ 41
- 0
setup.py View File

@@ -0,0 +1,41 @@
1
+#!/usr/bin/env python
2
+
3
+import os
4
+import glob
5
+import setuptools  # type: ignore
6
+
7
+root = os.path.abspath(os.path.dirname(__file__))
8
+
9
+
10
+def requires(requirements="requirements.txt"):
11
+    path = os.path.join(root, requirements)
12
+
13
+    with open(path, "r") as f:
14
+        return f.read().splitlines()
15
+
16
+
17
+info = dict(
18
+    name="gampy",
19
+    version="0.0.0",
20
+    license="EUPL-1.2",
21
+    author="Médéric Hurier",
22
+    author_email="dev@fmind.me",
23
+    description="General Abstract Meta Programming",
24
+    long_description_content_type="text/markdown",
25
+    long_description=open("README.md", "r").read(),
26
+    url="https://git.fmind.me/fmind/gampy",
27
+    packages=["gampy"],
28
+    keywords="general abstract meta programming",
29
+    classifiers=[
30
+        "Development Status :: 3 - Alpha",
31
+        "Programming Language :: Python :: 3",
32
+    ],
33
+    extras_require={
34
+        os.path.dirname(f): requires(f) for f in glob.glob("*/requirements.txt")
35
+    },
36
+    python_requires=">=3.7.0",
37
+    install_requires=requires(),
38
+)
39
+
40
+if __name__ == "__main__":
41
+    setuptools.setup(**info)

+ 9
- 0
shells/Makefile View File

@@ -0,0 +1,9 @@
1
+init-shells: .venv
2
+	.venv/bin/pip install '.[shells]'
3
+
4
+clean-shells: ;
5
+
6
+commit-shells: ;
7
+
8
+shell: .venv
9
+	.venv/bin/ipython --config='shells/ipython.py'

+ 16
- 0
shells/ipython.py View File

@@ -0,0 +1,16 @@
1
+# Configuration file for ipython.
2
+
3
+from traitlets.config import get_config
4
+
5
+c = get_config()
6
+
7
+c.TerminalIPythonApp.force_interact = True
8
+
9
+c.TerminalInteractiveShell.colors = "Linux"
10
+c.TerminalInteractiveShell.editing_mode = "vi"
11
+c.TerminalInteractiveShell.confirm_exit = False
12
+
13
+c.InteractiveShellApp.extensions = ["autoreload"]
14
+c.InteractiveShellApp.exec_lines = ["%autoreload 2"]
15
+
16
+c.TerminalInteractiveShell.extra_open_editor_shortcuts = True

+ 2
- 0
shells/requirements.txt View File

@@ -0,0 +1,2 @@
1
+ipdb
2
+ipython