omlish 0.0.0.dev493__py3-none-any.whl → 0.0.0.dev506__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.

Potentially problematic release.


This version of omlish might be problematic. Click here for more details.

Files changed (55) hide show
  1. omlish/CODESTYLE.md +345 -0
  2. omlish/README.md +2 -2
  3. omlish/__about__.py +6 -4
  4. omlish/_check.cc +209 -0
  5. omlish/check.py +11 -0
  6. omlish/dataclasses/__init__.py +4 -0
  7. omlish/dataclasses/impl/concerns/frozen.py +4 -1
  8. omlish/dataclasses/tools/replace.py +27 -0
  9. omlish/dispatch/functions.py +1 -1
  10. omlish/formats/json/stream/lexing.py +13 -5
  11. omlish/formats/json/stream/parsing.py +1 -1
  12. omlish/inject/README.md +430 -0
  13. omlish/inject/__init__.py +1 -0
  14. omlish/inject/_dataclasses.py +64 -64
  15. omlish/inject/eagers.py +0 -4
  16. omlish/inject/elements.py +4 -0
  17. omlish/inject/helpers/late.py +1 -1
  18. omlish/inject/helpers/managed.py +27 -24
  19. omlish/inject/impl/injector.py +7 -22
  20. omlish/inject/impl/inspect.py +0 -8
  21. omlish/inject/impl/origins.py +1 -0
  22. omlish/inject/impl/privates.py +2 -6
  23. omlish/inject/impl/providers.py +0 -4
  24. omlish/inject/impl/scopes.py +14 -18
  25. omlish/inject/inspect.py +9 -0
  26. omlish/inject/multis.py +0 -3
  27. omlish/inject/scopes.py +7 -5
  28. omlish/io/buffers.py +35 -8
  29. omlish/lang/__init__.py +8 -0
  30. omlish/lang/classes/simple.py +2 -1
  31. omlish/lang/iterables.py +6 -0
  32. omlish/lang/objects.py +13 -0
  33. omlish/lang/outcomes.py +1 -1
  34. omlish/lang/recursion.py +1 -1
  35. omlish/lang/sequences.py +33 -0
  36. omlish/lifecycles/_dataclasses.py +18 -18
  37. omlish/lifecycles/injection.py +4 -4
  38. omlish/lite/maybes.py +7 -0
  39. omlish/lite/typing.py +15 -0
  40. omlish/logs/all.py +11 -0
  41. omlish/logs/base.py +3 -3
  42. omlish/logs/bisync.py +99 -0
  43. omlish/marshal/_dataclasses.py +32 -32
  44. omlish/specs/jmespath/_dataclasses.py +38 -38
  45. omlish/specs/jsonschema/keywords/_dataclasses.py +24 -24
  46. omlish/typedvalues/_collection.cc +500 -0
  47. omlish/typedvalues/collection.py +159 -62
  48. omlish/typedvalues/generic.py +5 -4
  49. omlish/typedvalues/values.py +6 -0
  50. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/METADATA +9 -7
  51. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/RECORD +55 -50
  52. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/WHEEL +0 -0
  53. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/entry_points.txt +0 -0
  54. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/licenses/LICENSE +0 -0
  55. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,500 @@
1
+ // @omlish-cext
2
+ // @omlish-llm-author "claude-sonnet-4-5-20250929"
3
+ #define PY_SSIZE_T_CLEAN
4
+ #include "Python.h"
5
+ #include "structmember.h"
6
+
7
+ #include <memory>
8
+ #include <unordered_map>
9
+ #include <variant>
10
+ #include <vector>
11
+
12
+ //
13
+
14
+ #define _MODULE_NAME "_collection"
15
+ #define _PACKAGE_NAME "omlish.typedvalues"
16
+ #define _MODULE_FULL_NAME _PACKAGE_NAME "." _MODULE_NAME
17
+
18
+ typedef struct collection_state {
19
+ PyObject *typed_value_type;
20
+ PyObject *unique_typed_value_type;
21
+ PyObject *duplicate_error_type;
22
+ } collection_state;
23
+
24
+ static inline collection_state * get_collection_state(PyObject *module)
25
+ {
26
+ void *state = PyModule_GetState(module);
27
+ assert(state != NULL);
28
+ return (collection_state *)state;
29
+ }
30
+
31
+ //
32
+
33
+ // Helper struct to track unique typed values during processing
34
+ struct UniqueInfo {
35
+ PyObject *unique_tv_cls; // The unique class (borrowed from map key)
36
+ PyObject *tv; // The typed value (borrowed from args)
37
+ size_t idx; // Index in unique_lst when added
38
+ };
39
+
40
+ using TmpItem = std::variant<PyObject*, std::unique_ptr<UniqueInfo>>;
41
+
42
+ PyDoc_STRVAR(init_typed_values_collection_doc,
43
+ "init_typed_values_collection(*tvs, override=False, check_type=None)\n"
44
+ "\n"
45
+ "Initialize a typed values collection.\n"
46
+ "\n"
47
+ "Returns a tuple of (tuple, dict, dict2) where:\n"
48
+ "- tuple: ordered sequence of typed values\n"
49
+ "- dict: mapping of type -> typed value or tuple of typed values\n"
50
+ "- dict2: extended dict including instance types for unique values");
51
+
52
+ static PyObject * init_typed_values_collection(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
53
+ {
54
+ collection_state *state = get_collection_state(module);
55
+
56
+ // Parse arguments
57
+ bool override = false;
58
+ PyObject *check_type = nullptr;
59
+
60
+ // Handle keyword arguments
61
+ Py_ssize_t nkwargs = kwnames ? PyTuple_GET_SIZE(kwnames) : 0;
62
+
63
+ for (Py_ssize_t i = 0; i < nkwargs; i++) {
64
+ PyObject *key = PyTuple_GET_ITEM(kwnames, i);
65
+ PyObject *value = args[nargs + i];
66
+ const char *key_str = PyUnicode_AsUTF8(key);
67
+
68
+ if (key_str == nullptr) {
69
+ return nullptr;
70
+ }
71
+
72
+ if (strcmp(key_str, "override") == 0) {
73
+ int override_result = PyObject_IsTrue(value);
74
+ if (override_result == -1) {
75
+ return nullptr;
76
+ }
77
+ override = override_result;
78
+ } else if (strcmp(key_str, "check_type") == 0) {
79
+ check_type = value;
80
+ } else {
81
+ PyErr_Format(PyExc_TypeError, "unexpected keyword argument: %s", key_str);
82
+ return nullptr;
83
+ }
84
+ }
85
+
86
+ // If no positional arguments, return empty tuple and dicts
87
+ if (nargs == 0) {
88
+ PyObject *empty_tuple = PyTuple_New(0);
89
+ if (empty_tuple == nullptr) {
90
+ return nullptr;
91
+ }
92
+
93
+ PyObject *empty_dict = PyDict_New();
94
+ if (empty_dict == nullptr) {
95
+ Py_DECREF(empty_tuple);
96
+ return nullptr;
97
+ }
98
+
99
+ PyObject *empty_dict2 = PyDict_New();
100
+ if (empty_dict2 == nullptr) {
101
+ Py_DECREF(empty_tuple);
102
+ Py_DECREF(empty_dict);
103
+ return nullptr;
104
+ }
105
+
106
+ PyObject *result = PyTuple_Pack(3, empty_tuple, empty_dict, empty_dict2);
107
+ Py_DECREF(empty_tuple);
108
+ Py_DECREF(empty_dict);
109
+ Py_DECREF(empty_dict2);
110
+ return result;
111
+ }
112
+
113
+ // Temporary storage
114
+ std::vector<TmpItem> tmp_lst;
115
+ tmp_lst.reserve(nargs);
116
+
117
+ // Map from unique type to list of typed values
118
+ std::unordered_map<PyObject*, std::vector<PyObject*>> unique_dct;
119
+
120
+ struct UniqueKeysCleaner {
121
+ std::unordered_map<PyObject*, std::vector<PyObject*>> &map;
122
+ ~UniqueKeysCleaner() { for (auto &pair : map) Py_DECREF(pair.first); }
123
+ } keys_cleaner{unique_dct};
124
+
125
+ // Process each typed value
126
+ for (Py_ssize_t i = 0; i < nargs; i++) {
127
+ PyObject *tv = args[i];
128
+
129
+ // Check type if requested
130
+ if (check_type != nullptr && check_type != Py_None) {
131
+ int result = PyObject_IsInstance(tv, check_type);
132
+ if (result == -1) {
133
+ return nullptr;
134
+ }
135
+ if (!result) {
136
+ PyErr_SetObject(PyExc_TypeError, tv);
137
+ return nullptr;
138
+ }
139
+ }
140
+
141
+ // Check if it's a UniqueTypedValue
142
+ int is_unique = PyObject_IsInstance(tv, state->unique_typed_value_type);
143
+ if (is_unique == -1) {
144
+ return nullptr;
145
+ }
146
+
147
+ if (is_unique) {
148
+ // Get the _unique_typed_value_cls attribute
149
+ PyObject *unique_tv_cls = PyObject_GetAttrString(tv, "_unique_typed_value_cls");
150
+ if (unique_tv_cls == nullptr) {
151
+ return nullptr;
152
+ }
153
+
154
+ // Check for duplicates if not override
155
+ if (!override) {
156
+ auto it = unique_dct.find(unique_tv_cls);
157
+ if (it != unique_dct.end() && !it->second.empty()) {
158
+ // Duplicate found - raise error
159
+ PyObject *old_tv = it->second[0];
160
+
161
+ // Create DuplicateUniqueTypedValueError
162
+ PyObject *error = PyObject_CallFunction(
163
+ state->duplicate_error_type,
164
+ "OOO",
165
+ unique_tv_cls,
166
+ tv,
167
+ old_tv
168
+ );
169
+
170
+ Py_DECREF(unique_tv_cls);
171
+
172
+ if (error == nullptr) {
173
+ return nullptr;
174
+ }
175
+
176
+ PyErr_SetObject(state->duplicate_error_type, error);
177
+ Py_DECREF(error);
178
+ return nullptr;
179
+ }
180
+ }
181
+
182
+ // Add to unique_dct
183
+ // Use insert to avoid reference leak: if key already exists, we need to decref the new reference
184
+ auto insertion = unique_dct.insert({unique_tv_cls, std::vector<PyObject*>()});
185
+ if (!insertion.second) {
186
+ // Key already existed, decref the newly acquired reference
187
+ Py_DECREF(unique_tv_cls);
188
+ }
189
+ std::vector<PyObject*> &unique_lst = insertion.first->second;
190
+ unique_lst.push_back(tv);
191
+
192
+ // Add to tmp_lst using make_unique
193
+ // unique_ptr automatically handles deletion, variant handles moves
194
+ tmp_lst.emplace_back(std::make_unique<UniqueInfo>(UniqueInfo{
195
+ unique_tv_cls, // Borrowed from map
196
+ tv,
197
+ unique_lst.size()
198
+ }));
199
+
200
+ } else {
201
+ // Check if it's a TypedValue
202
+ int is_typed_value = PyObject_IsInstance(tv, state->typed_value_type);
203
+ if (is_typed_value == -1) {
204
+ return nullptr;
205
+ }
206
+
207
+ if (!is_typed_value) {
208
+ PyErr_SetObject(PyExc_TypeError, tv);
209
+ return nullptr;
210
+ }
211
+
212
+ // Non-unique typed value
213
+ tmp_lst.emplace_back(tv);
214
+ }
215
+ }
216
+
217
+ // Build output structures
218
+ PyObject *lst = PyList_New(0);
219
+ if (lst == nullptr) {
220
+ return nullptr;
221
+ }
222
+
223
+ PyObject *tmp_dct = PyDict_New();
224
+ if (tmp_dct == nullptr) {
225
+ Py_DECREF(lst);
226
+ return nullptr;
227
+ }
228
+
229
+ // Process tmp_lst to build output list and tmp_dct
230
+ for (auto &item : tmp_lst) {
231
+ // Check if item holds unique_ptr<UniqueInfo>
232
+ if (auto *uniq_ptr_wrapper = std::get_if<std::unique_ptr<UniqueInfo>>(&item)) {
233
+ UniqueInfo *info = uniq_ptr_wrapper->get();
234
+
235
+ // Look up the vector now (after all insertions are done, no more rehashing)
236
+ auto it = unique_dct.find(info->unique_tv_cls);
237
+ assert(it != unique_dct.end());
238
+
239
+ // Last-in-wins: only include if this is the last one
240
+ if (info->idx == it->second.size()) {
241
+ // Add to output list
242
+ if (PyList_Append(lst, info->tv) == -1) {
243
+ Py_DECREF(lst);
244
+ Py_DECREF(tmp_dct);
245
+ return nullptr;
246
+ }
247
+
248
+ // Add to tmp_dct (scalar value for unique types)
249
+ if (PyDict_SetItem(tmp_dct, info->unique_tv_cls, info->tv) == -1) {
250
+ Py_DECREF(lst);
251
+ Py_DECREF(tmp_dct);
252
+ return nullptr;
253
+ }
254
+ }
255
+ } else {
256
+ // Must be PyObject*
257
+ PyObject *tv = std::get<PyObject*>(item);
258
+
259
+ // Add to output list
260
+ if (PyList_Append(lst, tv) == -1) {
261
+ Py_DECREF(lst);
262
+ Py_DECREF(tmp_dct);
263
+ return nullptr;
264
+ }
265
+
266
+ // Add to tmp_dct (accumulating list for non-unique types)
267
+ PyObject *tv_type = (PyObject *)Py_TYPE(tv);
268
+ PyObject *existing = PyDict_GetItem(tmp_dct, tv_type); // Borrowed reference
269
+
270
+ if (existing == nullptr) {
271
+ // Check if an error occurred during lookup
272
+ if (PyErr_Occurred()) {
273
+ Py_DECREF(lst);
274
+ Py_DECREF(tmp_dct);
275
+ return nullptr;
276
+ }
277
+
278
+ // Create new list
279
+ PyObject *new_list = PyList_New(0);
280
+ if (new_list == nullptr) {
281
+ Py_DECREF(lst);
282
+ Py_DECREF(tmp_dct);
283
+ return nullptr;
284
+ }
285
+
286
+ if (PyList_Append(new_list, tv) == -1) {
287
+ Py_DECREF(new_list);
288
+ Py_DECREF(lst);
289
+ Py_DECREF(tmp_dct);
290
+ return nullptr;
291
+ }
292
+
293
+ if (PyDict_SetItem(tmp_dct, tv_type, new_list) == -1) {
294
+ Py_DECREF(new_list);
295
+ Py_DECREF(lst);
296
+ Py_DECREF(tmp_dct);
297
+ return nullptr;
298
+ }
299
+
300
+ Py_DECREF(new_list);
301
+ } else {
302
+ // Append to existing list
303
+ if (PyList_Append(existing, tv) == -1) {
304
+ Py_DECREF(lst);
305
+ Py_DECREF(tmp_dct);
306
+ return nullptr;
307
+ }
308
+ }
309
+ }
310
+ }
311
+
312
+ // Convert list to tuple
313
+ PyObject *result_tuple = PyList_AsTuple(lst);
314
+ Py_DECREF(lst);
315
+ if (result_tuple == nullptr) {
316
+ Py_DECREF(tmp_dct);
317
+ return nullptr;
318
+ }
319
+
320
+ // Build dct: convert lists to tuples
321
+ PyObject *dct = PyDict_New();
322
+ if (dct == nullptr) {
323
+ Py_DECREF(result_tuple);
324
+ Py_DECREF(tmp_dct);
325
+ return nullptr;
326
+ }
327
+
328
+ PyObject *key, *value;
329
+ Py_ssize_t pos = 0;
330
+
331
+ while (PyDict_Next(tmp_dct, &pos, &key, &value)) {
332
+ if (PyList_Check(value)) {
333
+ PyObject *tuple_value = PyList_AsTuple(value);
334
+ if (tuple_value == nullptr) {
335
+ Py_DECREF(result_tuple);
336
+ Py_DECREF(tmp_dct);
337
+ Py_DECREF(dct);
338
+ return nullptr;
339
+ }
340
+
341
+ if (PyDict_SetItem(dct, key, tuple_value) == -1) {
342
+ Py_DECREF(tuple_value);
343
+ Py_DECREF(result_tuple);
344
+ Py_DECREF(tmp_dct);
345
+ Py_DECREF(dct);
346
+ return nullptr;
347
+ }
348
+
349
+ Py_DECREF(tuple_value);
350
+ } else {
351
+ // Scalar value (unique type)
352
+ if (PyDict_SetItem(dct, key, value) == -1) {
353
+ Py_DECREF(result_tuple);
354
+ Py_DECREF(tmp_dct);
355
+ Py_DECREF(dct);
356
+ return nullptr;
357
+ }
358
+ }
359
+ }
360
+
361
+ Py_DECREF(tmp_dct);
362
+
363
+ // Build dct2: dct + unique values keyed by instance type
364
+ PyObject *dct2 = PyDict_Copy(dct);
365
+ if (dct2 == nullptr) {
366
+ Py_DECREF(result_tuple);
367
+ Py_DECREF(dct);
368
+ return nullptr;
369
+ }
370
+
371
+ // Add unique values by their instance type
372
+ pos = 0;
373
+ while (PyDict_Next(dct, &pos, &key, &value)) {
374
+ // Check if value is a UniqueTypedValue (not a tuple)
375
+ if (!PyTuple_Check(value)) {
376
+ int is_unique = PyObject_IsInstance(value, state->unique_typed_value_type);
377
+ if (is_unique == -1) {
378
+ Py_DECREF(result_tuple);
379
+ Py_DECREF(dct);
380
+ Py_DECREF(dct2);
381
+ return nullptr;
382
+ }
383
+
384
+ if (is_unique) {
385
+ PyObject *value_type = (PyObject *)Py_TYPE(value);
386
+ if (PyDict_SetItem(dct2, value_type, value) == -1) {
387
+ Py_DECREF(result_tuple);
388
+ Py_DECREF(dct);
389
+ Py_DECREF(dct2);
390
+ return nullptr;
391
+ }
392
+ }
393
+ }
394
+ }
395
+
396
+ // Build final result
397
+ PyObject *result = PyTuple_Pack(3, result_tuple, dct, dct2);
398
+ Py_DECREF(result_tuple);
399
+ Py_DECREF(dct);
400
+ Py_DECREF(dct2);
401
+
402
+ return result;
403
+ }
404
+
405
+ //
406
+
407
+ PyDoc_STRVAR(collection_doc, "Native C++ implementations for omlish.typedvalues.collection");
408
+
409
+ static int collection_exec(PyObject *module)
410
+ {
411
+ collection_state *state = get_collection_state(module);
412
+
413
+ // Import TypedValue
414
+ PyObject *values_module = PyImport_ImportModule("omlish.typedvalues.values");
415
+ if (values_module == nullptr) {
416
+ return -1;
417
+ }
418
+
419
+ state->typed_value_type = PyObject_GetAttrString(values_module, "TypedValue");
420
+ if (state->typed_value_type == nullptr) {
421
+ Py_DECREF(values_module);
422
+ return -1;
423
+ }
424
+
425
+ state->unique_typed_value_type = PyObject_GetAttrString(values_module, "UniqueTypedValue");
426
+ Py_DECREF(values_module);
427
+ if (state->unique_typed_value_type == nullptr) {
428
+ return -1;
429
+ }
430
+
431
+ // Import DuplicateUniqueTypedValueError
432
+ PyObject *collection_module = PyImport_ImportModule("omlish.typedvalues.collection");
433
+ if (collection_module == nullptr) {
434
+ return -1;
435
+ }
436
+
437
+ state->duplicate_error_type = PyObject_GetAttrString(collection_module, "DuplicateUniqueTypedValueError");
438
+ Py_DECREF(collection_module);
439
+ if (state->duplicate_error_type == nullptr) {
440
+ return -1;
441
+ }
442
+
443
+ return 0;
444
+ }
445
+
446
+ static int collection_traverse(PyObject *module, visitproc visit, void *arg)
447
+ {
448
+ collection_state *state = get_collection_state(module);
449
+ Py_VISIT(state->typed_value_type);
450
+ Py_VISIT(state->unique_typed_value_type);
451
+ Py_VISIT(state->duplicate_error_type);
452
+ return 0;
453
+ }
454
+
455
+ static int collection_clear(PyObject *module)
456
+ {
457
+ collection_state *state = get_collection_state(module);
458
+ Py_CLEAR(state->typed_value_type);
459
+ Py_CLEAR(state->unique_typed_value_type);
460
+ Py_CLEAR(state->duplicate_error_type);
461
+ return 0;
462
+ }
463
+
464
+ static void collection_free(void *module)
465
+ {
466
+ collection_clear((PyObject *)module);
467
+ }
468
+
469
+ static PyMethodDef collection_methods[] = {
470
+ {"init_typed_values_collection", (PyCFunction)(void(*)(void))init_typed_values_collection, METH_FASTCALL | METH_KEYWORDS, init_typed_values_collection_doc},
471
+ {NULL, NULL, 0, NULL}
472
+ };
473
+
474
+ static struct PyModuleDef_Slot collection_slots[] = {
475
+ {Py_mod_exec, (void *) collection_exec},
476
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
477
+ {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED},
478
+ {0, NULL}
479
+ };
480
+
481
+ static struct PyModuleDef collection_module = {
482
+ .m_base = PyModuleDef_HEAD_INIT,
483
+ .m_name = _MODULE_NAME,
484
+ .m_doc = collection_doc,
485
+ .m_size = sizeof(collection_state),
486
+ .m_methods = collection_methods,
487
+ .m_slots = collection_slots,
488
+ .m_traverse = collection_traverse,
489
+ .m_clear = collection_clear,
490
+ .m_free = collection_free,
491
+ };
492
+
493
+ extern "C" {
494
+
495
+ PyMODINIT_FUNC PyInit__collection(void)
496
+ {
497
+ return PyModuleDef_Init(&collection_module);
498
+ }
499
+
500
+ }