morphir-python 0.0.1__py3-none-any.whl

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.
Files changed (99) hide show
  1. morphir/__init__.py +14 -0
  2. morphir/ir/__init__.py +110 -0
  3. morphir/ir/access_controlled.py +15 -0
  4. morphir/ir/decorations.py +19 -0
  5. morphir/ir/diagnostics.py +105 -0
  6. morphir/ir/distribution.py +21 -0
  7. morphir/ir/document.py +37 -0
  8. morphir/ir/documented.py +11 -0
  9. morphir/ir/format_version.py +483 -0
  10. morphir/ir/fqname.py +9 -0
  11. morphir/ir/json.py +11 -0
  12. morphir/ir/literal.py +25 -0
  13. morphir/ir/meta.py +11 -0
  14. morphir/ir/migrate.py +1267 -0
  15. morphir/ir/module.py +17 -0
  16. morphir/ir/name.py +27 -0
  17. morphir/ir/package.py +15 -0
  18. morphir/ir/path.py +25 -0
  19. morphir/ir/qname.py +9 -0
  20. morphir/ir/ref.py +17 -0
  21. morphir/ir/type.py +37 -0
  22. morphir/ir/type_constraints.py +33 -0
  23. morphir/ir/type_def.py +19 -0
  24. morphir/ir/type_spec.py +25 -0
  25. morphir/ir/v3/__init__.py +64 -0
  26. morphir/ir/v3/_legacy_value.py +201 -0
  27. morphir/ir/v3/access_controlled.py +31 -0
  28. morphir/ir/v3/codec.py +1275 -0
  29. morphir/ir/v3/codec_v1.py +491 -0
  30. morphir/ir/v3/codec_v2.py +187 -0
  31. morphir/ir/v3/distribution.py +42 -0
  32. morphir/ir/v3/documented.py +13 -0
  33. morphir/ir/v3/fqname.py +30 -0
  34. morphir/ir/v3/literal.py +46 -0
  35. morphir/ir/v3/module.py +32 -0
  36. morphir/ir/v3/name.py +42 -0
  37. morphir/ir/v3/package.py +23 -0
  38. morphir/ir/v3/path.py +29 -0
  39. morphir/ir/v3/qname.py +16 -0
  40. morphir/ir/v3/type.py +126 -0
  41. morphir/ir/v3/value.py +235 -0
  42. morphir/ir/v4/__init__.py +160 -0
  43. morphir/ir/v4/access_controlled.py +17 -0
  44. morphir/ir/v4/annotation.py +75 -0
  45. morphir/ir/v4/codec.py +2161 -0
  46. morphir/ir/v4/decorations.py +88 -0
  47. morphir/ir/v4/distribution.py +56 -0
  48. morphir/ir/v4/document.py +69 -0
  49. morphir/ir/v4/documented.py +10 -0
  50. morphir/ir/v4/fqname.py +69 -0
  51. morphir/ir/v4/incompleteness.py +78 -0
  52. morphir/ir/v4/json.py +103 -0
  53. morphir/ir/v4/literal.py +51 -0
  54. morphir/ir/v4/meta.py +27 -0
  55. morphir/ir/v4/module.py +30 -0
  56. morphir/ir/v4/name.py +69 -0
  57. morphir/ir/v4/package.py +19 -0
  58. morphir/ir/v4/path.py +50 -0
  59. morphir/ir/v4/qname.py +34 -0
  60. morphir/ir/v4/ref.py +35 -0
  61. morphir/ir/v4/type.py +140 -0
  62. morphir/ir/v4/type_constraints.py +91 -0
  63. morphir/ir/v4/type_def.py +38 -0
  64. morphir/ir/v4/type_spec.py +64 -0
  65. morphir/ir/v4/value.py +480 -0
  66. morphir/ir/value.py +81 -0
  67. morphir/py.typed +0 -0
  68. morphir/sdk/__init__.py +110 -0
  69. morphir/sdk/_compare.py +187 -0
  70. morphir/sdk/aggregate.py +421 -0
  71. morphir/sdk/basics.py +504 -0
  72. morphir/sdk/char.py +110 -0
  73. morphir/sdk/decimal.py +311 -0
  74. morphir/sdk/dict.py +336 -0
  75. morphir/sdk/instant.py +118 -0
  76. morphir/sdk/int.py +86 -0
  77. morphir/sdk/key.py +522 -0
  78. morphir/sdk/list.py +356 -0
  79. morphir/sdk/local_date.py +436 -0
  80. morphir/sdk/local_time.py +267 -0
  81. morphir/sdk/maybe.py +135 -0
  82. morphir/sdk/number.py +237 -0
  83. morphir/sdk/regex.py +287 -0
  84. morphir/sdk/result.py +162 -0
  85. morphir/sdk/result_list.py +169 -0
  86. morphir/sdk/rule.py +103 -0
  87. morphir/sdk/set.py +214 -0
  88. morphir/sdk/stateful_app.py +49 -0
  89. morphir/sdk/string.py +427 -0
  90. morphir/sdk/tuple.py +43 -0
  91. morphir/sdk/uuid.py +209 -0
  92. morphir_python-0.0.1.dist-info/METADATA +269 -0
  93. morphir_python-0.0.1.dist-info/RECORD +99 -0
  94. morphir_python-0.0.1.dist-info/WHEEL +4 -0
  95. morphir_python-0.0.1.dist-info/entry_points.txt +2 -0
  96. morphir_python-0.0.1.dist-info/licenses/LICENSE +201 -0
  97. morphir_tools/__init__.py +13 -0
  98. morphir_tools/cli.py +223 -0
  99. morphir_tools/py.typed +0 -0
morphir/sdk/list.py ADDED
@@ -0,0 +1,356 @@
1
+ """Morphir.SDK.List: elm/core's List module plus the Morphir joins.
2
+
3
+ An Elm `List a` is an immutable Python `tuple[A, ...]`. Functions accept any
4
+ `Sequence` as input and always yield a tuple; no function mutates its input.
5
+ All functions take their arguments in Elm order, with the list last.
6
+
7
+ Many names in this module shadow Python built-ins (`all`, `any`, `filter`,
8
+ `map`, `range`, `sum`). Import the module with an alias, not the names:
9
+
10
+ >>> from morphir.sdk import list as List
11
+ >>> List.map(lambda n: n * 2, (1, 2, 3))
12
+ (2, 4, 6)
13
+ """
14
+
15
+ import builtins
16
+ import math
17
+ from typing import TYPE_CHECKING
18
+
19
+ from morphir.sdk import _compare
20
+ from morphir.sdk._compare import Comparable, Order
21
+ from morphir.sdk.maybe import Just, Maybe, Nothing
22
+
23
+ if TYPE_CHECKING:
24
+ from collections.abc import Callable, Sequence
25
+
26
+ __all__ = [
27
+ "List",
28
+ "all",
29
+ "any",
30
+ "append",
31
+ "concat",
32
+ "concat_map",
33
+ "cons",
34
+ "drop",
35
+ "filter",
36
+ "filter_map",
37
+ "foldl",
38
+ "foldr",
39
+ "head",
40
+ "indexed_map",
41
+ "inner_join",
42
+ "intersperse",
43
+ "is_empty",
44
+ "left_join",
45
+ "length",
46
+ "map",
47
+ "map2",
48
+ "map3",
49
+ "map4",
50
+ "map5",
51
+ "maximum",
52
+ "member",
53
+ "minimum",
54
+ "partition",
55
+ "product",
56
+ "range",
57
+ "repeat",
58
+ "reverse",
59
+ "singleton",
60
+ "sort",
61
+ "sort_by",
62
+ "sort_with",
63
+ "sum",
64
+ "tail",
65
+ "take",
66
+ "unzip",
67
+ ]
68
+
69
+ type List[A] = tuple[A, ...]
70
+ """An immutable list."""
71
+
72
+
73
+ # Create
74
+
75
+
76
+ def singleton[A](a: A) -> List[A]:
77
+ """Create a list with one element."""
78
+ return (a,)
79
+
80
+
81
+ def repeat[A](n: int, a: A) -> List[A]:
82
+ """Create a list with `n` copies of a value. A count below 1 yields `()`."""
83
+ return (a,) * n if n > 0 else ()
84
+
85
+
86
+ def range(low: int, high: int) -> List[int]:
87
+ """Create the list of integers from `low` to `high`, both included."""
88
+ return tuple(builtins.range(low, high + 1))
89
+
90
+
91
+ def cons[A](head: A, tail: Sequence[A]) -> List[A]:
92
+ """Add an element to the front of a list (Elm `::`)."""
93
+ return (head, *tail)
94
+
95
+
96
+ # Transform
97
+
98
+
99
+ def map[A, B](f: Callable[[A], B], xs: Sequence[A]) -> List[B]:
100
+ """Apply a function to every element of a list."""
101
+ return tuple(f(x) for x in xs)
102
+
103
+
104
+ def indexed_map[A, B](f: Callable[[int, A], B], xs: Sequence[A]) -> List[B]:
105
+ """Apply a function to every element and its index, which starts at 0."""
106
+ return tuple(f(index, x) for index, x in enumerate(xs))
107
+
108
+
109
+ def foldl[A, B](f: Callable[[A, B], B], initial: B, xs: Sequence[A]) -> B:
110
+ """Reduce a list from the left. The function gets the element first."""
111
+ accumulator = initial
112
+ for x in xs:
113
+ accumulator = f(x, accumulator)
114
+ return accumulator
115
+
116
+
117
+ def foldr[A, B](f: Callable[[A, B], B], initial: B, xs: Sequence[A]) -> B:
118
+ """Reduce a list from the right. The function gets the element first."""
119
+ accumulator = initial
120
+ for x in reversed(xs):
121
+ accumulator = f(x, accumulator)
122
+ return accumulator
123
+
124
+
125
+ def filter[A](predicate: Callable[[A], bool], xs: Sequence[A]) -> List[A]:
126
+ """Keep the elements that pass the test."""
127
+ return tuple(x for x in xs if predicate(x))
128
+
129
+
130
+ def filter_map[A, B](f: Callable[[A], Maybe[B]], xs: Sequence[A]) -> List[B]:
131
+ """Apply a function to every element and keep the `Just` values."""
132
+ return tuple(m.value for m in (f(x) for x in xs) if isinstance(m, Just))
133
+
134
+
135
+ # Utilities
136
+
137
+
138
+ def length[A](xs: Sequence[A]) -> int:
139
+ """Return the number of elements in a list."""
140
+ return len(xs)
141
+
142
+
143
+ def reverse[A](xs: Sequence[A]) -> List[A]:
144
+ """Reverse a list."""
145
+ return tuple(reversed(xs))
146
+
147
+
148
+ def member[A](a: A, xs: Sequence[A]) -> bool:
149
+ """Check that a list contains a value, by structural equality."""
150
+ return next((True for x in xs if _compare.equal(a, x)), False)
151
+
152
+
153
+ def all[A](predicate: Callable[[A], bool], xs: Sequence[A]) -> bool:
154
+ """Check that every element passes the test."""
155
+ return next((False for x in xs if not predicate(x)), True)
156
+
157
+
158
+ def any[A](predicate: Callable[[A], bool], xs: Sequence[A]) -> bool:
159
+ """Check that at least one element passes the test."""
160
+ return next((True for x in xs if predicate(x)), False)
161
+
162
+
163
+ def _extreme[A: Comparable](wanted: Order, xs: Sequence[A]) -> Maybe[A]:
164
+ if not xs:
165
+ return Nothing()
166
+ best = xs[0]
167
+ for x in xs[1:]:
168
+ if _compare.compare(x, best) is wanted:
169
+ best = x
170
+ return Just(best)
171
+
172
+
173
+ def maximum[A: Comparable](xs: Sequence[A]) -> Maybe[A]:
174
+ """Return the largest element, or `Nothing` for an empty list."""
175
+ return _extreme(Order.GT, xs)
176
+
177
+
178
+ def minimum[A: Comparable](xs: Sequence[A]) -> Maybe[A]:
179
+ """Return the smallest element, or `Nothing` for an empty list."""
180
+ return _extreme(Order.LT, xs)
181
+
182
+
183
+ def sum[N: (int, float)](xs: Sequence[N]) -> N | int:
184
+ """Return the sum of the elements. The sum of an empty list is 0."""
185
+ return builtins.sum(xs)
186
+
187
+
188
+ def product[N: (int, float)](xs: Sequence[N]) -> N | int:
189
+ """Return the product of the elements. The product of an empty list is 1."""
190
+ return math.prod(xs)
191
+
192
+
193
+ # Combine
194
+
195
+
196
+ def append[A](xs: Sequence[A], ys: Sequence[A]) -> List[A]:
197
+ """Put two lists together."""
198
+ return (*xs, *ys)
199
+
200
+
201
+ def concat[A](lists: Sequence[Sequence[A]]) -> List[A]:
202
+ """Concatenate many lists into one."""
203
+ return tuple(x for xs in lists for x in xs)
204
+
205
+
206
+ def concat_map[A, B](f: Callable[[A], Sequence[B]], xs: Sequence[A]) -> List[B]:
207
+ """Apply a function to every element and concatenate the lists it yields."""
208
+ return tuple(y for x in xs for y in f(x))
209
+
210
+
211
+ def intersperse[A](separator: A, xs: Sequence[A]) -> List[A]:
212
+ """Put a value between all the elements of a list."""
213
+ result: list[A] = []
214
+ for x in xs:
215
+ if result:
216
+ result.append(separator)
217
+ result.append(x)
218
+ return tuple(result)
219
+
220
+
221
+ def map2[A, B, R](f: Callable[[A, B], R], xs: Sequence[A], ys: Sequence[B]) -> List[R]:
222
+ """Combine two lists element by element; stop at the end of the shortest."""
223
+ return tuple(f(*args) for args in zip(xs, ys, strict=False))
224
+
225
+
226
+ def map3[A, B, C, R](
227
+ f: Callable[[A, B, C], R], xs: Sequence[A], ys: Sequence[B], zs: Sequence[C]
228
+ ) -> List[R]:
229
+ """Combine three lists element by element; stop at the end of the shortest."""
230
+ return tuple(f(*args) for args in zip(xs, ys, zs, strict=False))
231
+
232
+
233
+ def map4[A, B, C, D, R](
234
+ f: Callable[[A, B, C, D], R],
235
+ ws: Sequence[A],
236
+ xs: Sequence[B],
237
+ ys: Sequence[C],
238
+ zs: Sequence[D],
239
+ ) -> List[R]:
240
+ """Combine four lists element by element; stop at the end of the shortest."""
241
+ return tuple(f(*args) for args in zip(ws, xs, ys, zs, strict=False))
242
+
243
+
244
+ def map5[A, B, C, D, E, R](
245
+ f: Callable[[A, B, C, D, E], R],
246
+ vs: Sequence[A],
247
+ ws: Sequence[B],
248
+ xs: Sequence[C],
249
+ ys: Sequence[D],
250
+ zs: Sequence[E],
251
+ ) -> List[R]:
252
+ """Combine five lists element by element; stop at the end of the shortest."""
253
+ return tuple(f(*args) for args in zip(vs, ws, xs, ys, zs, strict=False))
254
+
255
+
256
+ # Sort
257
+
258
+
259
+ def sort[A: Comparable](xs: Sequence[A]) -> List[A]:
260
+ """Sort a list of comparable values from lowest to highest.
261
+
262
+ Raises:
263
+ TypeError: If the elements are not comparable with each other.
264
+ """
265
+ return tuple(sorted(xs, key=_compare.sort_key(_compare.compare)))
266
+
267
+
268
+ def sort_by[A, K: Comparable](f: Callable[[A], K], xs: Sequence[A]) -> List[A]:
269
+ """Sort a list by a derived comparable key. The sort is stable.
270
+
271
+ Raises:
272
+ TypeError: If the keys are not comparable with each other.
273
+ """
274
+ key = _compare.sort_key(_compare.compare)
275
+ return tuple(sorted(xs, key=lambda x: key(f(x))))
276
+
277
+
278
+ def sort_with[A](f: Callable[[A, A], Order], xs: Sequence[A]) -> List[A]:
279
+ """Sort a list with a custom comparison function. The sort is stable."""
280
+ return tuple(sorted(xs, key=_compare.sort_key(f)))
281
+
282
+
283
+ # Deconstruct
284
+
285
+
286
+ def is_empty[A](xs: Sequence[A]) -> bool:
287
+ """Check that a list is empty."""
288
+ return len(xs) == 0
289
+
290
+
291
+ def head[A](xs: Sequence[A]) -> Maybe[A]:
292
+ """Return the first element, or `Nothing` for an empty list."""
293
+ return Just(xs[0]) if xs else Nothing()
294
+
295
+
296
+ def tail[A](xs: Sequence[A]) -> Maybe[List[A]]:
297
+ """Return all elements but the first, or `Nothing` for an empty list."""
298
+ return Just(tuple(xs[1:])) if xs else Nothing()
299
+
300
+
301
+ def take[A](n: int, xs: Sequence[A]) -> List[A]:
302
+ """Take the first `n` elements of a list."""
303
+ return tuple(xs[:n]) if n > 0 else ()
304
+
305
+
306
+ def drop[A](n: int, xs: Sequence[A]) -> List[A]:
307
+ """Drop the first `n` elements of a list."""
308
+ return tuple(xs[n:]) if n > 0 else tuple(xs)
309
+
310
+
311
+ def partition[A](
312
+ predicate: Callable[[A], bool], xs: Sequence[A]
313
+ ) -> tuple[List[A], List[A]]:
314
+ """Split a list into the elements that pass the test and those that fail."""
315
+ passed: list[A] = []
316
+ failed: list[A] = []
317
+ for x in xs:
318
+ (passed if predicate(x) else failed).append(x)
319
+ return (tuple(passed), tuple(failed))
320
+
321
+
322
+ def unzip[A, B](pairs: Sequence[tuple[A, B]]) -> tuple[List[A], List[B]]:
323
+ """Split a list of pairs into a pair of lists."""
324
+ return (tuple(a for a, _ in pairs), tuple(b for _, b in pairs))
325
+
326
+
327
+ # Morphir additions to elm/core
328
+
329
+
330
+ def inner_join[A, B](
331
+ list_b: Sequence[B], on: Callable[[A, B], bool], list_a: Sequence[A]
332
+ ) -> List[tuple[A, B]]:
333
+ """Join two lists like an SQL inner join.
334
+
335
+ The result keeps the order of `list_a` and has one pair for each element of
336
+ `list_b` that matches.
337
+ """
338
+ return tuple((a, b) for a in list_a for b in list_b if on(a, b))
339
+
340
+
341
+ def left_join[A, B](
342
+ list_b: Sequence[B], on: Callable[[A, B], bool], list_a: Sequence[A]
343
+ ) -> List[tuple[A, Maybe[B]]]:
344
+ """Join two lists like an SQL left outer join.
345
+
346
+ The result keeps the order of `list_a`. An element with no match in `list_b`
347
+ yields one pair with `Nothing`.
348
+ """
349
+ result: list[tuple[A, Maybe[B]]] = []
350
+ for a in list_a:
351
+ matches = [b for b in list_b if on(a, b)]
352
+ if matches:
353
+ result.extend((a, Just(b)) for b in matches)
354
+ else:
355
+ result.append((a, Nothing()))
356
+ return tuple(result)