hypernix 0.45.0__tar.gz → 0.45.2__tar.gz
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.
- {hypernix-0.45.0 → hypernix-0.45.2}/PKG-INFO +1 -1
- {hypernix-0.45.0 → hypernix-0.45.2}/pyproject.toml +1 -1
- {hypernix-0.45.0 → hypernix-0.45.2}/setup.cfg +1 -1
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/__init__.py +1 -1
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/pans.py +86 -19
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_kitchen_v044.py +106 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/.github/workflows/build.yml +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/.github/workflows/ci.yml +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/.github/workflows/public-release.yml +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/.github/workflows/release.yml +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/LICENSE +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/MANIFEST.in +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/README.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/examples/custom_arch.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/examples/quickstart.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/examples/run_hypernix.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/examples/train_hypernix_0_1_5_evaluator.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/examples/train_hypernix_1_5_gtx1080.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/examples/upload_to_hub.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/pytest.ini +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/ruff.toml +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/scripts/install_deps.sh +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/scripts/quantize_i7_7660u.sh +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/setup.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/__main__.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/arch.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/blender.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/cli.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/coffee_maker.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/convert.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/deps.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/doctor.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/download.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/espresso_maker.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/fetcher.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/food_processor.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/freezer.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/generate.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/industrial_range.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/instant_pot.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/mediocre_fridge.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/microwave.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/nano_nano.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/new_fridge.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/new_range.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/old_fridge.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/old_oven.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/old_range.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/pressure_cooker.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/py.typed +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/quantize.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/sink.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/smoke_alarm.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/smoker.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/table.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/toaster.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/train.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix/upload.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/src/hypernix.egg-info/SOURCES.txt +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_alarms_and_presets.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_arch_mapping.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_cli_integration.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_deps_and_windows.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_fetcher.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_freezer.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_fridges.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_kitchen_v045.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_new_archs_v035.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_old_oven.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_ranges.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_snapshot_roundtrip.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/tests/test_v031_chat_and_archs.py +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Alarms.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Architectures.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/CLI.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Freezer.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Fridges.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Home.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Kitchen.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Ovens.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Pascal.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Quantization.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Ranges.md +0 -0
- {hypernix-0.45.0 → hypernix-0.45.2}/wiki/Training.md +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hypernix"
|
|
7
|
-
version = "0.45.
|
|
7
|
+
version = "0.45.2"
|
|
8
8
|
description = "Download and quantize the HyperNix PyTorch model to GGUF (fp32/fp16/Q8_0/Q6_K/Q4_K_M)."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -25,6 +25,7 @@ import re
|
|
|
25
25
|
from collections.abc import Iterable, Iterator
|
|
26
26
|
from dataclasses import dataclass, field
|
|
27
27
|
from pathlib import Path
|
|
28
|
+
from typing import Any, ClassVar
|
|
28
29
|
|
|
29
30
|
_WS_RE = re.compile(r"[ \t]+")
|
|
30
31
|
_MULTINEWLINE_RE = re.compile(r"\n{3,}")
|
|
@@ -37,10 +38,41 @@ _MULTINEWLINE_RE = re.compile(r"\n{3,}")
|
|
|
37
38
|
@dataclass
|
|
38
39
|
class Pan:
|
|
39
40
|
"""Abstract pan. Subclasses override :meth:`cook` (one line in,
|
|
40
|
-
zero-or-one line out) or :meth:`iter` (full iterator override).
|
|
41
|
+
zero-or-one line out) or :meth:`iter` (full iterator override).
|
|
42
|
+
|
|
43
|
+
``name`` is deliberately a :class:`ClassVar` rather than a
|
|
44
|
+
``@dataclass`` field — it's a human-readable label used in
|
|
45
|
+
``__repr__`` / logs, not state. Making it a field exposed it as
|
|
46
|
+
the *second positional argument* of every subclass, which meant
|
|
47
|
+
``Skillet("file.txt", "instruct")`` silently set ``name="instruct"``
|
|
48
|
+
instead of ``mode="instruct"`` and left the caller confused.
|
|
49
|
+
|
|
50
|
+
Every pan accepts two *keyword-only* length caps:
|
|
51
|
+
|
|
52
|
+
* ``max_chars`` — hard per-line character cap. Longer lines are
|
|
53
|
+
truncated (not split).
|
|
54
|
+
* ``context_length`` — convenience for training-script callers.
|
|
55
|
+
Treated as an approximate token budget and converted to
|
|
56
|
+
``max_chars = context_length * 4`` (a reasonable English-BPE
|
|
57
|
+
heuristic). Takes precedence over ``max_chars`` when both are
|
|
58
|
+
set. For precise chunking by tokens / chars use
|
|
59
|
+
:mod:`hypernix.food_processor` (``SliceBlade`` / ``ShredBlade``)
|
|
60
|
+
instead.
|
|
61
|
+
"""
|
|
41
62
|
|
|
42
63
|
source: Path | str | Iterable[str]
|
|
43
|
-
|
|
64
|
+
max_chars: int | None = field(default=None, kw_only=True)
|
|
65
|
+
context_length: int | None = field(default=None, kw_only=True)
|
|
66
|
+
name: ClassVar[str] = "Pan"
|
|
67
|
+
|
|
68
|
+
# Rough chars-per-token ratio for English BPE tokenizers. Only
|
|
69
|
+
# used when ``context_length`` is set and ``max_chars`` is not.
|
|
70
|
+
_CHARS_PER_TOKEN: ClassVar[int] = 4
|
|
71
|
+
|
|
72
|
+
def _effective_max_chars(self) -> int | None:
|
|
73
|
+
if self.context_length is not None:
|
|
74
|
+
return self.context_length * self._CHARS_PER_TOKEN
|
|
75
|
+
return self.max_chars
|
|
44
76
|
|
|
45
77
|
def _source_lines(self) -> Iterator[str]:
|
|
46
78
|
if isinstance(self.source, (str, Path)):
|
|
@@ -55,10 +87,14 @@ class Pan:
|
|
|
55
87
|
return line
|
|
56
88
|
|
|
57
89
|
def iter(self) -> Iterator[str]:
|
|
90
|
+
cap = self._effective_max_chars()
|
|
58
91
|
for raw in self._source_lines():
|
|
59
92
|
out = self.cook(raw)
|
|
60
|
-
if out is
|
|
61
|
-
|
|
93
|
+
if out is None:
|
|
94
|
+
continue
|
|
95
|
+
if cap is not None and len(out) > cap:
|
|
96
|
+
out = out[:cap]
|
|
97
|
+
yield out
|
|
62
98
|
|
|
63
99
|
def __iter__(self) -> Iterator[str]:
|
|
64
100
|
return self.iter()
|
|
@@ -74,7 +110,7 @@ class FryingPan(Pan):
|
|
|
74
110
|
through. Useful when the input is already clean (already-formatted
|
|
75
111
|
corpora, pre-tokenized chunks)."""
|
|
76
112
|
|
|
77
|
-
name: str = "FryingPan"
|
|
113
|
+
name: ClassVar[str] = "FryingPan"
|
|
78
114
|
|
|
79
115
|
def cook(self, line: str) -> str | None:
|
|
80
116
|
return line.rstrip()
|
|
@@ -90,7 +126,7 @@ class SaucePan(Pan):
|
|
|
90
126
|
strip leading/trailing whitespace. Standard mild cleaning for
|
|
91
127
|
scraped or OCR'd text."""
|
|
92
128
|
|
|
93
|
-
name: str = "SaucePan"
|
|
129
|
+
name: ClassVar[str] = "SaucePan"
|
|
94
130
|
|
|
95
131
|
def cook(self, line: str) -> str | None:
|
|
96
132
|
line = _WS_RE.sub(" ", line.strip())
|
|
@@ -111,10 +147,10 @@ class Skillet(Pan):
|
|
|
111
147
|
replies on the following line (or in a separate corpus).
|
|
112
148
|
"""
|
|
113
149
|
|
|
114
|
-
name: str = "Skillet"
|
|
115
150
|
mode: str = "chat" # "chat" | "instruct"
|
|
116
151
|
user_tag: str = "<USER>"
|
|
117
152
|
assistant_tag: str = "<ASSISTANT>"
|
|
153
|
+
name: ClassVar[str] = "Skillet"
|
|
118
154
|
|
|
119
155
|
def cook(self, line: str) -> str | None:
|
|
120
156
|
line = line.strip()
|
|
@@ -133,11 +169,15 @@ class Skillet(Pan):
|
|
|
133
169
|
class GrillPan(Pan):
|
|
134
170
|
"""High direct heat. SaucePan-style cleaning plus deduplication
|
|
135
171
|
(SHA1 hash set) and a minimum length filter. Safe on arbitrary
|
|
136
|
-
web-scraped text: collapses boilerplate, drops single-word lines.
|
|
172
|
+
web-scraped text: collapses boilerplate, drops single-word lines.
|
|
173
|
+
|
|
174
|
+
``_seen`` is internal dedupe state and is not part of the public
|
|
175
|
+
``__init__`` signature.
|
|
176
|
+
"""
|
|
137
177
|
|
|
138
|
-
name: str = "GrillPan"
|
|
139
178
|
min_chars: int = 8
|
|
140
|
-
|
|
179
|
+
name: ClassVar[str] = "GrillPan"
|
|
180
|
+
_seen: set[str] = field(default_factory=set, repr=False, init=False)
|
|
141
181
|
|
|
142
182
|
def cook(self, line: str) -> str | None:
|
|
143
183
|
line = _WS_RE.sub(" ", line.strip())
|
|
@@ -162,13 +202,14 @@ class Wok(Pan):
|
|
|
162
202
|
small corpora where order-randomization matters and you can afford
|
|
163
203
|
the memory."""
|
|
164
204
|
|
|
165
|
-
name: str = "Wok"
|
|
166
205
|
seed: int = 0
|
|
167
206
|
reverse_ratio: float = 0.0
|
|
207
|
+
name: ClassVar[str] = "Wok"
|
|
168
208
|
|
|
169
209
|
def iter(self) -> Iterator[str]:
|
|
170
210
|
# Pre-clean with SaucePan semantics.
|
|
171
211
|
rng = random.Random(self.seed)
|
|
212
|
+
cap = self._effective_max_chars()
|
|
172
213
|
buffer: list[str] = []
|
|
173
214
|
for raw in self._source_lines():
|
|
174
215
|
line = _WS_RE.sub(" ", raw.strip())
|
|
@@ -176,10 +217,14 @@ class Wok(Pan):
|
|
|
176
217
|
buffer.append(line)
|
|
177
218
|
rng.shuffle(buffer)
|
|
178
219
|
for line in buffer:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
220
|
+
out = (
|
|
221
|
+
" ".join(reversed(line.split()))
|
|
222
|
+
if self.reverse_ratio > 0 and rng.random() < self.reverse_ratio
|
|
223
|
+
else line
|
|
224
|
+
)
|
|
225
|
+
if cap is not None and len(out) > cap:
|
|
226
|
+
out = out[:cap]
|
|
227
|
+
yield out
|
|
183
228
|
|
|
184
229
|
|
|
185
230
|
# ---------------------------------------------------------------------------
|
|
@@ -195,7 +240,29 @@ TIERS: dict[str, type[Pan]] = {
|
|
|
195
240
|
}
|
|
196
241
|
|
|
197
242
|
|
|
198
|
-
def pick_pan(tier: str, source: Path | str | Iterable[str], **kwargs:
|
|
199
|
-
"""Return a pan instance by tier name (``"frying-pan"``..``"wok"``).
|
|
200
|
-
|
|
201
|
-
|
|
243
|
+
def pick_pan(tier: str, source: Path | str | Iterable[str], **kwargs: Any) -> Pan:
|
|
244
|
+
"""Return a pan instance by tier name (``"frying-pan"``..``"wok"``).
|
|
245
|
+
|
|
246
|
+
Raises :class:`ValueError` if ``tier`` is unknown (with the list of
|
|
247
|
+
valid tiers in the message) or if ``**kwargs`` contains a keyword
|
|
248
|
+
the selected pan doesn't accept (with the list of valid kwargs).
|
|
249
|
+
"""
|
|
250
|
+
key = tier.lower().replace("_", "-")
|
|
251
|
+
if key not in TIERS:
|
|
252
|
+
raise ValueError(
|
|
253
|
+
f"unknown pan tier {tier!r}; valid tiers are: {sorted(TIERS)}"
|
|
254
|
+
)
|
|
255
|
+
cls = TIERS[key]
|
|
256
|
+
try:
|
|
257
|
+
return cls(source=source, **kwargs)
|
|
258
|
+
except TypeError as exc:
|
|
259
|
+
# Re-raise with a message that lists the keywords the tier
|
|
260
|
+
# actually accepts — the raw dataclass message ("unexpected
|
|
261
|
+
# keyword argument 'X'") doesn't say what *is* accepted.
|
|
262
|
+
import inspect
|
|
263
|
+
valid = [p for p in inspect.signature(cls).parameters if p != "source"]
|
|
264
|
+
raise ValueError(
|
|
265
|
+
f"{cls.__name__} rejected an argument ({exc}). "
|
|
266
|
+
f"Valid keyword arguments for {cls.__name__} (besides "
|
|
267
|
+
f"'source'): {valid}"
|
|
268
|
+
) from exc
|
|
@@ -89,6 +89,112 @@ def test_pick_pan_factory() -> None:
|
|
|
89
89
|
assert isinstance(p, pans.Pan)
|
|
90
90
|
|
|
91
91
|
|
|
92
|
+
# Regression: second positional arg used to silently bind to `name`
|
|
93
|
+
# (inherited from Pan.__init__), so ``Skillet(src, "instruct")`` would
|
|
94
|
+
# set ``name="instruct"`` and leave ``mode="chat"``. `name` is now a
|
|
95
|
+
# ClassVar, so positional arg #2 is the first real field on each pan.
|
|
96
|
+
|
|
97
|
+
def test_skillet_second_positional_is_mode_not_name() -> None:
|
|
98
|
+
from hypernix import pans
|
|
99
|
+
|
|
100
|
+
s = pans.Skillet(["hi"], "instruct")
|
|
101
|
+
assert s.mode == "instruct"
|
|
102
|
+
assert s.name == "Skillet" # unchanged — name is a ClassVar
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_grill_pan_second_positional_is_min_chars() -> None:
|
|
106
|
+
from hypernix import pans
|
|
107
|
+
|
|
108
|
+
g = pans.GrillPan(["hello", "world", "hi", "hello"], 4)
|
|
109
|
+
assert g.min_chars == 4
|
|
110
|
+
# "hi" (2 chars) dropped; second "hello" dropped as duplicate.
|
|
111
|
+
assert list(g) == ["hello", "world"]
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_grill_pan_seen_is_not_in_init_signature() -> None:
|
|
115
|
+
import inspect
|
|
116
|
+
|
|
117
|
+
from hypernix import pans
|
|
118
|
+
|
|
119
|
+
params = inspect.signature(pans.GrillPan).parameters
|
|
120
|
+
assert "_seen" not in params
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_pick_pan_unknown_tier_gives_useful_error() -> None:
|
|
124
|
+
import pytest
|
|
125
|
+
|
|
126
|
+
from hypernix import pans
|
|
127
|
+
|
|
128
|
+
with pytest.raises(ValueError, match="unknown pan tier"):
|
|
129
|
+
pans.pick_pan("microwave-pan", source=["x"])
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_pick_pan_bad_kwarg_lists_valid_ones() -> None:
|
|
133
|
+
import pytest
|
|
134
|
+
|
|
135
|
+
from hypernix import pans
|
|
136
|
+
|
|
137
|
+
with pytest.raises(ValueError, match="Skillet rejected"):
|
|
138
|
+
pans.pick_pan("skillet", source=["x"], min_chars=16)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Regression: v0.45 shipped without a context_length / max_chars knob,
|
|
142
|
+
# so a training script calling ``FryingPan(context_length=256)`` got
|
|
143
|
+
# a bare TypeError. Every pan now accepts both as keyword-only fields.
|
|
144
|
+
|
|
145
|
+
def test_frying_pan_accepts_context_length() -> None:
|
|
146
|
+
from hypernix import pans
|
|
147
|
+
|
|
148
|
+
long_line = "x" * 10_000
|
|
149
|
+
out = list(pans.FryingPan(source=[long_line], context_length=256))
|
|
150
|
+
# context_length=256 → max_chars = 256 * 4 = 1024.
|
|
151
|
+
assert len(out[0]) == 1024
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_pan_max_chars_truncates() -> None:
|
|
155
|
+
from hypernix import pans
|
|
156
|
+
|
|
157
|
+
long_line = "x" * 10_000
|
|
158
|
+
out = list(pans.SaucePan(source=[long_line], max_chars=500))
|
|
159
|
+
assert len(out[0]) == 500
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_pan_context_length_wins_over_max_chars() -> None:
|
|
163
|
+
from hypernix import pans
|
|
164
|
+
|
|
165
|
+
long_line = "x" * 10_000
|
|
166
|
+
out = list(pans.FryingPan(
|
|
167
|
+
source=[long_line], max_chars=99, context_length=50,
|
|
168
|
+
))
|
|
169
|
+
# ctx=50 → 50 * 4 = 200, not 99.
|
|
170
|
+
assert len(out[0]) == 200
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_pan_length_cap_is_noop_when_unset() -> None:
|
|
174
|
+
from hypernix import pans
|
|
175
|
+
|
|
176
|
+
line = "x" * 10_000
|
|
177
|
+
out = list(pans.FryingPan(source=[line]))
|
|
178
|
+
assert len(out[0]) == 10_000
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_wok_honors_context_length() -> None:
|
|
182
|
+
from hypernix import pans
|
|
183
|
+
|
|
184
|
+
lines = ["x" * 10_000, "y" * 10_000]
|
|
185
|
+
out = list(pans.Wok(source=lines, seed=0, context_length=64))
|
|
186
|
+
# 64 * 4 = 256
|
|
187
|
+
assert all(len(s) <= 256 for s in out)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_pick_pan_forwards_context_length() -> None:
|
|
191
|
+
from hypernix import pans
|
|
192
|
+
|
|
193
|
+
src = ["abcd " * 1000]
|
|
194
|
+
pan = pans.pick_pan("grill-pan", source=src, context_length=64)
|
|
195
|
+
assert all(len(s) <= 256 for s in pan)
|
|
196
|
+
|
|
197
|
+
|
|
92
198
|
# ---------------------------------------------------------------------------
|
|
93
199
|
# microwave
|
|
94
200
|
# ---------------------------------------------------------------------------
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|