python-corekit 0.4.1__py3-none-any.whl → 0.5.0__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.
corekit/utils/coercion.py CHANGED
@@ -6,17 +6,36 @@ empty value rather than raising. Use them at boundaries where the input is
6
6
  genuinely unknown -- an API payload, a config value, a scraped field -- and a
7
7
  crash would be worse than a default.
8
8
 
9
+ These are thin wrappers around ``corekit.utils.parsers``. Extraction logic lives
10
+ there once; here we only fix the fallback to the type's empty value so the
11
+ return type is guaranteed.
12
+
9
13
  The tradeoff is real: ``safe_int("banana")`` is ``0``, indistinguishable from a
10
- genuine zero. Where telling those apart matters, parse explicitly instead.
14
+ genuine zero. Where telling those apart matters, call the parser directly and
15
+ inspect ``ParsedValue.success``, or pass a sentinel ``default``.
11
16
  """
12
17
 
13
- import json
14
- from datetime import date, datetime
15
18
  from typing import Any
16
19
 
17
- from corekit.utils.text import list_to_english
18
-
19
- __all__ = ["safe_dict", "safe_float", "safe_int", "safe_list", "safe_string", "safe_tuple"]
20
+ from corekit.utils.parsers import (
21
+ parse_dict,
22
+ parse_float,
23
+ parse_int,
24
+ parse_list,
25
+ parse_set,
26
+ parse_string,
27
+ parse_tuple,
28
+ )
29
+
30
+ __all__ = [
31
+ "safe_dict",
32
+ "safe_float",
33
+ "safe_int",
34
+ "safe_list",
35
+ "safe_set",
36
+ "safe_string",
37
+ "safe_tuple",
38
+ ]
20
39
 
21
40
 
22
41
  def safe_string(item: Any, pretty: bool = False) -> str:
@@ -27,54 +46,21 @@ def safe_string(item: Any, pretty: bool = False) -> str:
27
46
  list instead -- ``"a, b, c"``, or ``"key: value, ..."`` for a mapping --
28
47
  which reads better in a notification than raw JSON.
29
48
  """
30
- if isinstance(item, bytes):
31
- item = item.decode("utf-8", errors="ignore")
32
- if isinstance(item, str):
33
- return item.strip()
34
- # bool is a subclass of int, so both land here and render as "True"/"1".
35
- if isinstance(item, (int, float)):
36
- return str(item)
37
- if isinstance(item, (list, tuple, set, dict)):
38
- if pretty:
39
- if isinstance(item, dict):
40
- return list_to_english([f"{key}: {value}" for key, value in item.items()])
41
- return list_to_english([safe_string(element) for element in item])
42
- return json.dumps(item)
43
- if isinstance(item, (date, datetime)):
44
- return item.isoformat()
45
- return ""
49
+ return parse_string(item, pretty=pretty, default="").value
46
50
 
47
51
 
48
52
  def safe_int(item: Any) -> int:
49
53
  """
50
54
  Convert anything to an int, or ``0`` if it will not convert.
51
55
  """
52
- if isinstance(item, int):
53
- return item
54
- if isinstance(item, bytes):
55
- item = item.decode("utf-8", errors="ignore")
56
- if isinstance(item, (float, str)):
57
- try:
58
- return int(item)
59
- except ValueError:
60
- return 0
61
- return 0
56
+ return parse_int(item, default=0).value
62
57
 
63
58
 
64
59
  def safe_float(item: Any) -> float:
65
60
  """
66
61
  Convert anything to a float, or ``0.0`` if it will not convert.
67
62
  """
68
- if isinstance(item, float):
69
- return item
70
- if isinstance(item, bytes):
71
- item = item.decode("utf-8", errors="ignore")
72
- if isinstance(item, (int, str)):
73
- try:
74
- return float(item)
75
- except ValueError:
76
- return 0.0
77
- return 0.0
63
+ return parse_float(item, default=0.0).value
78
64
 
79
65
 
80
66
  def safe_list(item: Any) -> list[Any]:
@@ -84,13 +70,7 @@ def safe_list(item: Any) -> list[Any]:
84
70
  A mapping yields its values. A string is *not* treated as a collection --
85
71
  exploding it into characters is almost never what the caller meant.
86
72
  """
87
- if isinstance(item, list):
88
- return item
89
- if isinstance(item, (tuple, set)):
90
- return list(item)
91
- if isinstance(item, dict):
92
- return list(item.values())
93
- return []
73
+ return parse_list(item, default=[]).value
94
74
 
95
75
 
96
76
  def safe_tuple(item: Any) -> tuple[Any, ...]:
@@ -100,19 +80,25 @@ def safe_tuple(item: Any) -> tuple[Any, ...]:
100
80
  A mapping yields its values. A string is *not* treated as a collection --
101
81
  exploding it into characters is almost never what the caller meant.
102
82
  """
103
- if isinstance(item, tuple):
104
- return item
105
- if isinstance(item, (list, set)):
106
- return tuple(item)
107
- if isinstance(item, dict):
108
- return tuple(item.values())
109
- return ()
83
+ return parse_tuple(item, default=()).value
84
+
85
+
86
+ def safe_set(item: Any) -> set[Any]:
87
+ """
88
+ Convert a collection to a set, or ``set()`` for anything else.
89
+
90
+ A mapping yields its values. A string is *not* treated as a collection --
91
+ exploding it into characters is almost never what the caller meant.
92
+ Unhashable elements yield ``set()``.
93
+ """
94
+ return parse_set(item, default=set()).value
110
95
 
111
96
 
112
97
  def safe_dict(item: Any) -> dict[str, Any]:
113
98
  """
114
99
  Return the mapping unchanged, or ``{}`` for anything else.
100
+
101
+ Also accepts objects that expose ``to_dict``, ``model_dump``, or ``dict``,
102
+ and falls back to ``__dict__`` when present.
115
103
  """
116
- if isinstance(item, dict):
117
- return item
118
- return {}
104
+ return parse_dict(item, default={}).value
@@ -7,10 +7,29 @@ once. Built for JSON from somewhere you do not control, where any level may be
7
7
  missing or the wrong type.
8
8
  """
9
9
 
10
- from copy import deepcopy
11
- from typing import Any, Callable
10
+ from __future__ import annotations
12
11
 
13
- __all__ = ["MultiMatch", "attr_or_key", "keygetter", "repeated_get", "split_list"]
12
+ import inspect
13
+ from collections.abc import AsyncIterable, AsyncIterator, Iterable, Mapping
14
+ from copy import deepcopy
15
+ from typing import Any, Awaitable, Callable, Iterator, Literal
16
+
17
+ __all__ = [
18
+ "MultiMatch",
19
+ "aiterator",
20
+ "attr_or_key",
21
+ "iterator",
22
+ "keygetter",
23
+ "kv_string",
24
+ "repeated_get",
25
+ "split_list",
26
+ ]
27
+
28
+ WhereSeq = Callable[[Any], bool]
29
+ WhereMap = Callable[[Any, Any], bool]
30
+ AsyncWhereSeq = Callable[[Any], bool | Awaitable[bool]]
31
+ AsyncWhereMap = Callable[[Any, Any], bool | Awaitable[bool]]
32
+ IteratorMode = Literal["keys", "values", "items"]
14
33
 
15
34
  KEY_SEPARATOR = "."
16
35
 
@@ -40,6 +59,120 @@ def attr_or_key(obj: Any, name: str) -> Any:
40
59
  return getattr(obj, name, None)
41
60
 
42
61
 
62
+ def _mapping_item(key: Any, value: Any, mode: IteratorMode) -> Any:
63
+ if mode == "values":
64
+ return value
65
+ if mode == "items":
66
+ return key, value
67
+ return key
68
+
69
+
70
+ def iterator(
71
+ obj: Iterable[Any] | Mapping[Any, Any] | None = None,
72
+ *,
73
+ mode: IteratorMode = "keys",
74
+ where: WhereSeq | WhereMap | None = None,
75
+ compact: bool = False,
76
+ ) -> Iterator[Any]:
77
+ """
78
+ Iterate an iterable or mapping, optionally filtered.
79
+
80
+ Non-mappings ignore ``mode`` and yield elements. Mappings yield keys,
81
+ values, or items according to ``mode`` (default ``keys``).
82
+
83
+ ``compact=True`` skips ``None`` items, or mapping entries whose **value**
84
+ is ``None``. ``where`` is a sync predicate: one argument for iterables,
85
+ ``(key, value)`` for mappings — the entry is filtered, then ``mode``
86
+ selects what is yielded.
87
+
88
+ ``None`` yields nothing.
89
+ """
90
+ if obj is None:
91
+ return
92
+
93
+ if isinstance(obj, Mapping):
94
+ for key, value in obj.items():
95
+ if compact and value is None:
96
+ continue
97
+ if where is not None and not where(key, value): # type: ignore[call-arg, arg-type]
98
+ continue
99
+ yield _mapping_item(key, value, mode)
100
+ return
101
+
102
+ for item in obj:
103
+ if compact and item is None:
104
+ continue
105
+ if where is not None and not where(item): # type: ignore[call-arg, arg-type]
106
+ continue
107
+ yield item
108
+
109
+
110
+ async def aiterator(
111
+ obj: AsyncIterable[Any] | Iterable[Any] | Mapping[Any, Any] | None = None,
112
+ *,
113
+ mode: IteratorMode = "keys",
114
+ where: AsyncWhereSeq | AsyncWhereMap | None = None,
115
+ compact: bool = False,
116
+ ) -> AsyncIterator[Any]:
117
+ """
118
+ Async counterpart to ``iterator``.
119
+
120
+ Accepts async iterables, sync iterables, and mappings. ``where`` may be
121
+ sync or async; mapping predicates still receive ``(key, value)``. Use with
122
+ ``async for``.
123
+ """
124
+ if obj is None:
125
+ return
126
+
127
+ async def _allow_mapping(_key: Any, _value: Any) -> bool:
128
+ if where is None:
129
+ return True
130
+ result = where(_key, _value) # type: ignore[call-arg, arg-type]
131
+ if inspect.isawaitable(result):
132
+ result = await result
133
+ return bool(result)
134
+
135
+ async def _allow_item(_item: Any) -> bool:
136
+ if where is None:
137
+ return True
138
+ result = where(_item) # type: ignore[call-arg, arg-type]
139
+ if inspect.isawaitable(result):
140
+ result = await result
141
+ return bool(result)
142
+
143
+ if isinstance(obj, Mapping):
144
+ for key, value in obj.items():
145
+ if compact and value is None:
146
+ continue
147
+ if not await _allow_mapping(key, value):
148
+ continue
149
+ yield _mapping_item(key, value, mode)
150
+ return
151
+
152
+ if isinstance(obj, AsyncIterable):
153
+ async for item in obj:
154
+ if compact and item is None:
155
+ continue
156
+ if not await _allow_item(item):
157
+ continue
158
+ yield item
159
+ return
160
+
161
+ for item in obj:
162
+ if compact and item is None:
163
+ continue
164
+ if not await _allow_item(item):
165
+ continue
166
+ yield item
167
+
168
+
169
+ def kv_string(key: str, value: Any, sep: str = ": ", prefix: str = "") -> str:
170
+ """
171
+ Format a key-value pair into a string.
172
+ """
173
+ return f"{prefix}{key}{sep}{value}"
174
+
175
+
43
176
  class MultiMatch(dict[str, Any]):
44
177
  """
45
178
  The result of a path step that matched more than one key.
@@ -0,0 +1,205 @@
1
+ """
2
+ Flexible parsers with caller-controlled fallbacks.
3
+
4
+ Each helper attempts to extract the target type and returns a ``ParsedValue``
5
+ carrying both the result and a ``success`` flag. On failure the ``value`` is
6
+ whatever ``default`` the caller supplied (``None`` unless overridden).
7
+
8
+ These are the extraction layer. For a guaranteed target type with that type's
9
+ empty value as the fallback, use the ``safe_*`` wrappers in
10
+ ``corekit.utils.coercion``.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import json
16
+ from datetime import date, datetime
17
+ from typing import Any, NamedTuple
18
+
19
+ from corekit.utils.text import list_to_english
20
+
21
+ __all__ = [
22
+ "ParsedValue",
23
+ "parse_dict",
24
+ "parse_float",
25
+ "parse_int",
26
+ "parse_list",
27
+ "parse_set",
28
+ "parse_string",
29
+ "parse_tuple",
30
+ ]
31
+
32
+
33
+ class ParsedValue(NamedTuple):
34
+ """Outcome of a parse attempt."""
35
+
36
+ value: Any
37
+ success: bool
38
+
39
+ @classmethod
40
+ def ok(cls, value: Any) -> ParsedValue:
41
+ return cls(value=value, success=True)
42
+
43
+ @classmethod
44
+ def error(cls, value: Any) -> ParsedValue:
45
+ return cls(value=value, success=False)
46
+
47
+
48
+ def parse_string(
49
+ item: Any,
50
+ *,
51
+ pretty: bool = False,
52
+ strip: bool = True,
53
+ default: Any = None,
54
+ ) -> ParsedValue:
55
+ """
56
+ Extract a string rendering of ``item``, or ``default`` if there is none.
57
+
58
+ Collections become JSON by default. With ``pretty`` they become an English
59
+ list instead -- ``"a, b, c"``, or ``"key: value, ..."`` for a mapping --
60
+ which reads better in a notification than raw JSON.
61
+ """
62
+
63
+ def _clean(text: str) -> str:
64
+ return text.strip() if strip else text
65
+
66
+ def _parse_collection(collection: Any) -> str:
67
+ if pretty:
68
+ if isinstance(collection, dict):
69
+ return list_to_english([f"{key}: {value}" for key, value in collection.items()])
70
+ return list_to_english(
71
+ [parse_string(element, pretty=pretty, strip=strip, default="").value for element in collection]
72
+ )
73
+ return json.dumps(collection)
74
+
75
+ if isinstance(item, bytes):
76
+ item = item.decode("utf-8", errors="ignore")
77
+ if isinstance(item, str):
78
+ return ParsedValue.ok(_clean(item))
79
+ # bool is a subclass of int, so both land here and render as "True"/"1".
80
+ if isinstance(item, (int, float)):
81
+ return ParsedValue.ok(str(item))
82
+ if isinstance(item, (list, tuple, set, dict)):
83
+ return ParsedValue.ok(_parse_collection(item))
84
+ if isinstance(item, (date, datetime)):
85
+ return ParsedValue.ok(item.isoformat())
86
+ return ParsedValue.error(default)
87
+
88
+
89
+ def parse_int(item: Any, *, default: Any = None) -> ParsedValue:
90
+ """
91
+ Extract an int from ``item``, or ``default`` if it will not convert.
92
+ """
93
+ if isinstance(item, bool):
94
+ return ParsedValue.ok(int(item))
95
+ if isinstance(item, int):
96
+ return ParsedValue.ok(item)
97
+ if isinstance(item, bytes):
98
+ item = item.decode("utf-8", errors="ignore")
99
+ if isinstance(item, (float, str)):
100
+ try:
101
+ return ParsedValue.ok(int(item))
102
+ except (TypeError, ValueError):
103
+ return ParsedValue.error(default)
104
+ return ParsedValue.error(default)
105
+
106
+
107
+ def parse_float(item: Any, *, default: Any = None) -> ParsedValue:
108
+ """
109
+ Extract a float from ``item``, or ``default`` if it will not convert.
110
+ """
111
+ if isinstance(item, bool):
112
+ return ParsedValue.ok(float(item))
113
+ if isinstance(item, float):
114
+ return ParsedValue.ok(item)
115
+ if isinstance(item, bytes):
116
+ item = item.decode("utf-8", errors="ignore")
117
+ if isinstance(item, (int, str)):
118
+ try:
119
+ return ParsedValue.ok(float(item))
120
+ except (TypeError, ValueError):
121
+ return ParsedValue.error(default)
122
+ return ParsedValue.error(default)
123
+
124
+
125
+ def parse_list(item: Any, *, default: Any = None) -> ParsedValue:
126
+ """
127
+ Extract a list from a collection, or ``default`` for anything else.
128
+
129
+ A mapping yields its values. A string is *not* treated as a collection --
130
+ exploding it into characters is almost never what the caller meant.
131
+ """
132
+ if isinstance(item, list):
133
+ return ParsedValue.ok(item)
134
+ if isinstance(item, (tuple, set)):
135
+ return ParsedValue.ok(list(item))
136
+ if isinstance(item, dict):
137
+ return ParsedValue.ok(list(item.values()))
138
+ return ParsedValue.error(default)
139
+
140
+
141
+ def parse_tuple(item: Any, *, default: Any = None) -> ParsedValue:
142
+ """
143
+ Extract a tuple from a collection, or ``default`` for anything else.
144
+
145
+ A mapping yields its values. A string is *not* treated as a collection --
146
+ exploding it into characters is almost never what the caller meant.
147
+ """
148
+ if isinstance(item, tuple):
149
+ return ParsedValue.ok(item)
150
+ if isinstance(item, (list, set)):
151
+ return ParsedValue.ok(tuple(item))
152
+ if isinstance(item, dict):
153
+ return ParsedValue.ok(tuple(item.values()))
154
+ return ParsedValue.error(default)
155
+
156
+
157
+ def parse_set(item: Any, *, default: Any = None) -> ParsedValue:
158
+ """
159
+ Extract a set from a collection, or ``default`` for anything else.
160
+
161
+ A mapping yields its values. A string is *not* treated as a collection --
162
+ exploding it into characters is almost never what the caller meant.
163
+ Unhashable elements fail the conversion and yield ``default``.
164
+ """
165
+ if isinstance(item, set):
166
+ return ParsedValue.ok(item)
167
+ if isinstance(item, (list, tuple)):
168
+ try:
169
+ return ParsedValue.ok(set(item))
170
+ except TypeError:
171
+ return ParsedValue.error(default)
172
+ if isinstance(item, dict):
173
+ try:
174
+ return ParsedValue.ok(set(item.values()))
175
+ except TypeError:
176
+ return ParsedValue.error(default)
177
+ return ParsedValue.error(default)
178
+
179
+
180
+ def parse_dict(item: Any, *, default: Any = None) -> ParsedValue:
181
+ """
182
+ Extract a mapping from ``item``, or ``default`` if none is available.
183
+
184
+ Accepts a ``dict`` directly, then common dump protocols (``to_dict``,
185
+ ``model_dump``, ``dict``), then a plain ``__dict__``.
186
+ """
187
+ if isinstance(item, dict):
188
+ return ParsedValue.ok(item)
189
+
190
+ for method_name in ("to_dict", "model_dump", "dict"):
191
+ method = getattr(item, method_name, None)
192
+ if not callable(method):
193
+ continue
194
+ try:
195
+ result = method()
196
+ except Exception:
197
+ continue
198
+ if isinstance(result, dict):
199
+ return ParsedValue.ok(result)
200
+
201
+ namespace = getattr(item, "__dict__", None)
202
+ if isinstance(namespace, dict):
203
+ return ParsedValue.ok(namespace)
204
+
205
+ return ParsedValue.error(default)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-corekit
3
- Version: 0.4.1
4
- Summary: Shared foundations for Python projects: logging, benchmarking, registries, FastAPI application and routers, SQL statements and migrations, background tasks, ETL, and LLM chat/tool primitives
3
+ Version: 0.5.0
4
+ Summary: Shared foundations for Python projects: logging, benchmarking, registries, FastAPI application and routers, SQL statements and migrations, background tasks, ETL, LLM chat/tool primitives, and HTML scraping
5
5
  Author: Steven Jacobsen
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/stevejaker/corekit
@@ -23,6 +23,7 @@ Requires-Dist: sqlmodel<0.1,>=0.0.16
23
23
  Requires-Dist: SQLAlchemy<3,>=2.0
24
24
  Requires-Dist: redis<7,>=5.0
25
25
  Requires-Dist: httpx<1,>=0.27
26
+ Requires-Dist: selectolax<1,>=0.3
26
27
  Requires-Dist: docker<8,>=7.0
27
28
  Requires-Dist: PyYAML<7,>=6.0
28
29
  Requires-Dist: dill<0.5,>=0.3.8
@@ -347,13 +348,13 @@ class GithubClient(BaseApiClient):
347
348
  return "https://api.github.com"
348
349
 
349
350
  response = GithubClient().get("/users/octocat")
350
- response.data["login"]
351
+ response.data.login
351
352
  ```
352
353
 
353
- Retries 429 and 5xx with exponential backoff. Every response is a
354
- `BaseApiResponse`, so a non-JSON error page leaves `data` empty rather than
355
- raising. The same methods are awaitable inside a running event loop:
356
- `await client.get(...)`.
354
+ Retries 429 and 5xx with exponential backoff. ``BaseHttpClient`` returns a
355
+ ``BaseHttpResponse`` (text + metadata); ``BaseApiClient`` adds structured
356
+ ``data`` from JSON (``None`` when the body is not JSON). The same methods are
357
+ awaitable inside a running event loop: `await client.get(...)`.
357
358
 
358
359
  ## Serialization
359
360
 
@@ -22,7 +22,7 @@ corekit/connections/registry.py,sha256=BR04dGthcGCtON2MxNsl-TlhRgbRlvGj0RLymDFBk
22
22
  corekit/connections/redis/__init__.py,sha256=BsWLZNqpKAqIoreHGLEtftnMqVw-ESK8jbexDAughag,174
23
23
  corekit/connections/redis/connection.py,sha256=H6r5WsDfXFgIQlp6vq3rKjp-oBFQoE5h_YaJXZEvHIs,9850
24
24
  corekit/connections/sql/__init__.py,sha256=WRBcQ9draDQSooYi4k4peWyuRTgSyEk_WwOYYOAN9K4,882
25
- corekit/connections/sql/connection.py,sha256=PvLhYXMmq6JneshWhoUb2WD2usGH7uOA9H_ZufybKgQ,12318
25
+ corekit/connections/sql/connection.py,sha256=1ieLXssO2lyFZD9Uf_5wyM5TJmdEqYl8RzR2fMTJTlg,12410
26
26
  corekit/connections/sql/query.py,sha256=8s5atIssmN2l9FCL2IHnIQqwxOk0fA_mPNh36koLhoE,233
27
27
  corekit/connections/sql/table.py,sha256=C7_QCRPd7C1JeH7aIByUBVWsx5qiEOFavWOo6c72djM,3125
28
28
  corekit/connections/sql/fields/__init__.py,sha256=2I-TCsvi321yQhesKNZgY1T77FtATZ6o7pw0MNHtbAo,184
@@ -94,12 +94,19 @@ corekit/files/base.py,sha256=Ca2bhdlwntHh425PedaUG-UW2fEFZsPCss_3f7REsAE,4022
94
94
  corekit/files/enum.py,sha256=mcrQXcp-AizTAp4VoaVMLj9zu5D81XXMsnZwZqe6fz0,597
95
95
  corekit/files/json.py,sha256=pRYLKNjeVmkDQsgtjBboFFY5Ljx1Pwa3MFEeQBc4o-g,909
96
96
  corekit/files/toml.py,sha256=YFRwghMapbCRSl7srqcI7IhqaTQDyO56XRasGMu_Aug,1273
97
- corekit/http/__init__.py,sha256=pDSzU3w8ZHMdcnZ1XCR_KWEGRSlIhy-K_jT5qH_T2Y4,1681
98
- corekit/http/api.py,sha256=L4iZ9TdCQH3klKWxIxFE3bEQzqMTDOwy-HKrvHXwsbI,784
99
- corekit/http/client.py,sha256=IEXZGd-4-zaQmkKXOIlTyLrFKWaJd6uDxu14o5-u9z4,7997
97
+ corekit/html/__init__.py,sha256=25xsrlhaWREDuGpWc6xnN-Mbir7AsCnzjjQODJ58XVo,535
98
+ corekit/html/client.py,sha256=59eTlvJh9QFiPQ7HFHEhju9UkoEpS5YafinxFI5w7Q0,664
99
+ corekit/html/models.py,sha256=zxN3mSAuTQ0GE27Gxa3ptcp_EAmm5tlBUzwMovDevLU,357
100
+ corekit/html/parser.py,sha256=blSEBl5clbx_dOBPKu0S45_MiRjLSa7LeGpGc8opdWA,10300
101
+ corekit/html/scraper.py,sha256=af3UHf8LZuE4tEYr_MHo-h9FF6b8PQUtoTmlzSFR3FE,4366
102
+ corekit/html/settings.py,sha256=Xalz1Zg9wHyPhlzfIwsFE23aOE6woShHJLNEHg4mCWE,6951
103
+ corekit/html/state.py,sha256=McWmvu7y4qR0M2mSnjPAFtnAow9sv-nWHzolJQlvbyk,1534
104
+ corekit/http/__init__.py,sha256=S3FlvpBjYoLrFaMY7OTQLMM6d7etaDRJP53_4aPuKZk,1723
105
+ corekit/http/api.py,sha256=WiBfv3tTifxUuvoj3rGqZxCPm2L8z3N_F7hvmLuzprM,3027
106
+ corekit/http/client.py,sha256=CONO9z5CGVh5H99yCYnNjPMUYe8G8FFzbeBhusLbBSw,7217
100
107
  corekit/http/exceptions.py,sha256=etkKN6rgnhENctO7YNvaRAKsctK0PXKCxAe15l6mNwY,4252
101
108
  corekit/http/exponential_backoff.py,sha256=5jjGTspX_BC9aBKPr5Y5dNhJqXesmljsjJoQ6i2d4_I,3180
102
- corekit/http/response.py,sha256=rOcUEgPYxfmKXfGO5fQsMA8q4YJof8dNNGBf-nb7l8k,2375
109
+ corekit/http/response.py,sha256=t_nGIwA-uyuQlJBGMgxbodCNjRnqc1xUcxMsbEXeMBM,3415
103
110
  corekit/http/status.py,sha256=rZ-cdliG9EAvWMTzvxjqjipRkZRc6RgSzcBY4Kewdg0,2377
104
111
  corekit/http/stream.py,sha256=lkERyCXz5amOWzoE-b12iftf3l_G-ghwSvN1lL5lUio,3257
105
112
  corekit/jobs/__init__.py,sha256=vsv8o23ApT6MlOwOq-AFYeQW2NT1kjyvu89A5CL2PsY,880
@@ -107,13 +114,13 @@ corekit/jobs/registry.py,sha256=cco6884eVuIYHEtSv6P62MICFjX-QhuSZIFkEJcQi_M,2557
107
114
  corekit/jobs/runner.py,sha256=VyiTrQJT-E8-XuNBh8s1QgLJkKhkpBq_398Fs_03Kow,3321
108
115
  corekit/jobs/task.py,sha256=tqr-QaQSHyfPjbyZscM5i-YgT-fl58cpd2FVxevtG_E,6112
109
116
  corekit/llm/__init__.py,sha256=Qa-5V2cG4aH98b0nLY2tMx0G7uhoWhcaaZ7JY1dJjcA,3217
110
- corekit/llm/client.py,sha256=bO2o21ntKdGNjcWOoEv4ew2QQD7-HQ6Hsn01Zf_5a1I,6441
117
+ corekit/llm/client.py,sha256=X-dkizlps-ndhDzcImBfLDDWaoPdwMin7bf58QU2fdQ,6519
111
118
  corekit/llm/enum.py,sha256=WyikZcEt17Rnj5jFS6o2ENXIdBBFB-NFjdCKDVtIToc,2582
112
119
  corekit/llm/events.py,sha256=gEj3HpXLndCoPLF3C5jn-Gv5N1K6EPosR7bc5DaHwz4,2202
113
120
  corekit/llm/messages.py,sha256=KomU69Kjfgif0fMXrbEr9VsQ_RpcFjgsE2S0ThC2SIA,5070
114
121
  corekit/llm/protocols.py,sha256=ahCZwR3vQiB6LqaarTBGc5VSbe5mtb9vDLoLcOTmL_k,1770
115
122
  corekit/llm/streaming.py,sha256=fiQdJMHDrMBSF5hDMCqcQ3WulrOyoQ67N-c3Chb00Sg,4319
116
- corekit/llm/wire.py,sha256=3OTD0Cj3ewbBqCqdrqAs06gXQrxmNPI7LYsvBnO9zws,6024
123
+ corekit/llm/wire.py,sha256=GbK7nF27YryNIDe1uOG_3RR-er3BFvULhVy73DiGgE0,6308
117
124
  corekit/llm/prompts/__init__.py,sha256=9z8UwMqkh11MNcrom8hNZjugXq1MVF_EpPkRfF72zNA,544
118
125
  corekit/llm/prompts/enum.py,sha256=OYTd-riG70HiGoBVxJpA1_FttyGR-ITsEojHfHjDKdk,1219
119
126
  corekit/llm/prompts/exceptions.py,sha256=BX7VvngByXfSf3UGKAnFAPOytJrYukdEN_gVKYIfypc,546
@@ -122,7 +129,7 @@ corekit/llm/prompts/template.py,sha256=dgKje-v4R3JN3SPsDBjGm4zdohEsGRTgpbv1bvaOT
122
129
  corekit/llm/tools/__init__.py,sha256=3hoiam1oatawk9k8-pcY63JoywiOh3EoM7TvkW00nMY,527
123
130
  corekit/llm/tools/base.py,sha256=Mby2M3WA4nKgkmOpQwJWvKHGXlaZU62EGlHQUxsL_wk,3309
124
131
  corekit/llm/tools/detection.py,sha256=R3jMxJwOdMzyTo9DISi_yYx1zEHUJJ6AN61bHkvO3zM,3292
125
- corekit/llm/tools/loop.py,sha256=kpzNMmFEDV-QwY-ja6WHyGKfKyl9v4Ih7RovFoajofU,9200
132
+ corekit/llm/tools/loop.py,sha256=x7zlfYgeiXbtgna3IIczKkh5PK9fY2SfUpBOle21Dtw,9381
126
133
  corekit/llm/tools/registry.py,sha256=dkIucONGsmaw-cgTNIIV2WDVGAF45twOHrvTvavs4X4,3362
127
134
  corekit/log_monitor/__init__.py,sha256=uuXTQdI8EMeFbdt69G-2K8dKh5Nt-h9SzBEsOGcu0lo,371
128
135
  corekit/log_monitor/constants.py,sha256=8nzIzU3Qit9h7_stZLWW1Q_0DTnYglw_j5bQUsF586g,230
@@ -142,13 +149,13 @@ corekit/observability/timing/timer.py,sha256=rBGYYnBq-1E85Om37dkbPM9wKsXsltyeWeA
142
149
  corekit/registry/__init__.py,sha256=R67Jssr06Eyx2u5AbX1omm2LziWvwS_Sd7fExnNv9CM,681
143
150
  corekit/registry/ordered.py,sha256=_KS4mWzmLgFvODW2M0_ugxZIBW_dKhwwxrVrtNqLMfs,2506
144
151
  corekit/registry/registry.py,sha256=t1iwzxgvd-iyLIf_5wahg_P7eN9V1oumpupkAqi2GdQ,5601
145
- corekit/schemas/__init__.py,sha256=Qty0EM2XlbvUgnk-JU2IRaE6_Kclocw6QqKyaD-CbZg,369
152
+ corekit/schemas/__init__.py,sha256=4EK7QNWP16U6ZKno_ZKTDfgSflc9W2PFMPskc0kvSdw,470
146
153
  corekit/schemas/enum.py,sha256=gLc44kIXRfpDFkV51JoN4KT1CU92hnb529rd1b88fBM,2033
147
154
  corekit/schemas/types.py,sha256=AWIxZHXUiUjJRZjmOhAdCq3RIsRzL-Fy7RvYy4i5Ozo,1347
148
155
  corekit/schemas/version.py,sha256=InWtfKf0iyfu_eBLaFm_QNwkSjpgKc1jGJZeWYjQQUc,1753
149
156
  corekit/schemas/dataclasses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
157
  corekit/schemas/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
- corekit/schemas/models/arbitrary.py,sha256=L2Uqxo_twPAmzoly3Lyo5rzYhDzReSB_U-oAuRgWubg,396
158
+ corekit/schemas/models/arbitrary.py,sha256=ik8V9Pm2X3eKv1vUp3IF5v3c6gDqoyisSBnen63-Pcc,1681
152
159
  corekit/schemas/models/date_models.py,sha256=UOlSLVsWqgr_jnHfxVRgSl4nVVdfbe6zPBYveOgRcIg,399
153
160
  corekit/schemas/pydantic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
161
  corekit/schemas/pydantic/fields.py,sha256=ScP2ZQCR2qTWaqwjKl7lGvkTGSIeQBJ0yeNs79E47AA,1175
@@ -157,18 +164,19 @@ corekit/serialization/enum.py,sha256=pzHuAIXeonEF7-jyN1uYddJk-xvmQGuymDf1U6RWR5w
157
164
  corekit/serialization/pickle_file.py,sha256=dudKIxR8ueT3wx_IBxHJeoqnFeP1rT7dlTb_PXlSkd8,2251
158
165
  corekit/serialization/serializable.py,sha256=viF3ZCKRJ90hk6m4lbqIfo6ifsY2c4sXr4xZrn1Yz-Q,1999
159
166
  corekit/serialization/serializer.py,sha256=XlGE1Rq8M55Jl2a4F5MkvDcba2VI7lrh0v9kwL0DWG8,6617
160
- corekit/utils/__init__.py,sha256=xOHqpsAipQbkCLurKOYBSQ8RJyHULfoeEKPXqudNWH4,1827
161
- corekit/utils/coercion.py,sha256=Aq63jrxQYg1ooWUFXHff2uepB_LoHm1izao8_3xkzEU,3650
162
- corekit/utils/collections.py,sha256=cn7Bzh67utzBi7UO4FfjWrjDun05ye5_rTscwfWcmwo,4475
167
+ corekit/utils/__init__.py,sha256=lNdmVmQBUFckkCIjzxYLHpLe06rudXS9t_evVEv-le4,2419
168
+ corekit/utils/coercion.py,sha256=lnAdPuY7Hha81of1I8oPIu6C8ow6JqWWpuF1sPX17Ek,3084
169
+ corekit/utils/collections.py,sha256=4ieN3r44Y1DPoJQYpoXn8mL_nTKd5i9GjAoBOMXwd40,8335
163
170
  corekit/utils/ids.py,sha256=BVniaYqewM-EosDxcJAT_S_7T9C1c5X8nsaVGs5up34,1731
171
+ corekit/utils/parsers.py,sha256=b7bCaMd7_VKaFnin6vn3v1Eol_Z0vvr3vjDO4ro5ycI,6628
164
172
  corekit/utils/payload.py,sha256=T7EgdVU0S5h8MAzvQsmkfRPMatWqUbxjHL9hmZdM9ho,3882
165
173
  corekit/utils/raise_exc.py,sha256=cz7ljc6ZW90AGQussKuANN8PLsDLUhl-E8FZ0Ipsw-0,175
166
174
  corekit/utils/text.py,sha256=0322DdZGuDGEagTyejuda6QT1jbbxNIO6loC-_AGml0,2311
167
175
  corekit/utils/time.py,sha256=-iPaETXcgDu7J39Kwe938JyZKhPVjl6a572BBqsqcDQ,2215
168
176
  corekit/utils/validators.py,sha256=_HVKo3y264KGNaZ-1RyM1x46VPvu7XKcQkrHWDC9uxs,340
169
177
  corekit/utils/void.py,sha256=eXDb2QynuguiSgHGJLdgE08MuRnxBdYebRdMD7s1m9o,178
170
- python_corekit-0.4.1.dist-info/licenses/LICENSE,sha256=357LYxbxAQZ95q5cV-8JK6j-KNgiE6AteRodjEsm-kE,1072
171
- python_corekit-0.4.1.dist-info/METADATA,sha256=M24uRb1as-03LHKgbGhDIFJeQ30Z3mEO84EfCj_GNIE,15084
172
- python_corekit-0.4.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
173
- python_corekit-0.4.1.dist-info/top_level.txt,sha256=SDK4o8BoaI47E9tPbiNCbbWoc2y6N_wCjwnIEfr-GWI,8
174
- python_corekit-0.4.1.dist-info/RECORD,,
178
+ python_corekit-0.5.0.dist-info/licenses/LICENSE,sha256=357LYxbxAQZ95q5cV-8JK6j-KNgiE6AteRodjEsm-kE,1072
179
+ python_corekit-0.5.0.dist-info/METADATA,sha256=GFJChQrVckK79FiPnCddTLGr36xpxik6BqrtAjskE_A,15185
180
+ python_corekit-0.5.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
181
+ python_corekit-0.5.0.dist-info/top_level.txt,sha256=SDK4o8BoaI47E9tPbiNCbbWoc2y6N_wCjwnIEfr-GWI,8
182
+ python_corekit-0.5.0.dist-info/RECORD,,