glitchlings 0.4.0__cp312-cp312-win_amd64.whl → 0.4.2__cp312-cp312-win_amd64.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 glitchlings might be problematic. Click here for more details.
- glitchlings/__init__.py +26 -17
- glitchlings/__main__.py +0 -1
- glitchlings/_zoo_rust.cp312-win_amd64.pyd +0 -0
- glitchlings/compat.py +215 -0
- glitchlings/config.py +136 -19
- glitchlings/dlc/_shared.py +68 -0
- glitchlings/dlc/huggingface.py +26 -41
- glitchlings/dlc/prime.py +64 -101
- glitchlings/lexicon/__init__.py +26 -19
- glitchlings/lexicon/_cache.py +104 -0
- glitchlings/lexicon/graph.py +18 -39
- glitchlings/lexicon/metrics.py +1 -8
- glitchlings/lexicon/vector.py +29 -67
- glitchlings/lexicon/wordnet.py +39 -30
- glitchlings/main.py +9 -13
- glitchlings/util/__init__.py +18 -4
- glitchlings/util/adapters.py +27 -0
- glitchlings/zoo/__init__.py +21 -14
- glitchlings/zoo/_ocr_confusions.py +1 -3
- glitchlings/zoo/_rate.py +1 -4
- glitchlings/zoo/_sampling.py +0 -1
- glitchlings/zoo/_text_utils.py +1 -5
- glitchlings/zoo/adjax.py +0 -2
- glitchlings/zoo/core.py +185 -56
- glitchlings/zoo/jargoyle.py +9 -14
- glitchlings/zoo/mim1c.py +11 -10
- glitchlings/zoo/redactyl.py +5 -8
- glitchlings/zoo/reduple.py +3 -1
- glitchlings/zoo/rushmore.py +2 -8
- glitchlings/zoo/scannequin.py +5 -4
- glitchlings/zoo/typogre.py +3 -7
- glitchlings/zoo/zeedub.py +2 -2
- {glitchlings-0.4.0.dist-info → glitchlings-0.4.2.dist-info}/METADATA +68 -4
- glitchlings-0.4.2.dist-info/RECORD +42 -0
- glitchlings-0.4.0.dist-info/RECORD +0 -38
- {glitchlings-0.4.0.dist-info → glitchlings-0.4.2.dist-info}/WHEEL +0 -0
- {glitchlings-0.4.0.dist-info → glitchlings-0.4.2.dist-info}/entry_points.txt +0 -0
- {glitchlings-0.4.0.dist-info → glitchlings-0.4.2.dist-info}/licenses/LICENSE +0 -0
- {glitchlings-0.4.0.dist-info → glitchlings-0.4.2.dist-info}/top_level.txt +0 -0
glitchlings/zoo/jargoyle.py
CHANGED
|
@@ -9,9 +9,11 @@ from glitchlings.lexicon import Lexicon, get_default_lexicon
|
|
|
9
9
|
try: # pragma: no cover - optional WordNet dependency
|
|
10
10
|
from glitchlings.lexicon.wordnet import (
|
|
11
11
|
WordNetLexicon,
|
|
12
|
+
)
|
|
13
|
+
from glitchlings.lexicon.wordnet import (
|
|
12
14
|
dependencies_available as _lexicon_dependencies_available,
|
|
13
|
-
ensure_wordnet as _lexicon_ensure_wordnet,
|
|
14
15
|
)
|
|
16
|
+
from glitchlings.lexicon.wordnet import ensure_wordnet as _lexicon_ensure_wordnet
|
|
15
17
|
except Exception: # pragma: no cover - triggered when nltk unavailable
|
|
16
18
|
WordNetLexicon = None # type: ignore[assignment]
|
|
17
19
|
|
|
@@ -33,7 +35,6 @@ ensure_wordnet = _lexicon_ensure_wordnet
|
|
|
33
35
|
|
|
34
36
|
def dependencies_available() -> bool:
|
|
35
37
|
"""Return ``True`` when a synonym backend is accessible."""
|
|
36
|
-
|
|
37
38
|
if _lexicon_dependencies_available():
|
|
38
39
|
return True
|
|
39
40
|
|
|
@@ -58,7 +59,6 @@ _VALID_POS: tuple[PartOfSpeech, ...] = ("n", "v", "a", "r")
|
|
|
58
59
|
|
|
59
60
|
def _split_token(token: str) -> tuple[str, str, str]:
|
|
60
61
|
"""Split a token into leading punctuation, core word, and trailing punctuation."""
|
|
61
|
-
|
|
62
62
|
match = re.match(r"^(\W*)(.*?)(\W*)$", token)
|
|
63
63
|
if not match:
|
|
64
64
|
return "", token, ""
|
|
@@ -70,23 +70,18 @@ def _normalize_parts_of_speech(
|
|
|
70
70
|
part_of_speech: PartOfSpeechInput,
|
|
71
71
|
) -> NormalizedPartsOfSpeech:
|
|
72
72
|
"""Coerce user input into a tuple of valid WordNet POS tags."""
|
|
73
|
-
|
|
74
73
|
if isinstance(part_of_speech, str):
|
|
75
74
|
lowered = part_of_speech.lower()
|
|
76
75
|
if lowered == "any":
|
|
77
76
|
return _VALID_POS
|
|
78
77
|
if lowered not in _VALID_POS:
|
|
79
|
-
raise ValueError(
|
|
80
|
-
"part_of_speech must be one of 'n', 'v', 'a', 'r', or 'any'"
|
|
81
|
-
)
|
|
78
|
+
raise ValueError("part_of_speech must be one of 'n', 'v', 'a', 'r', or 'any'")
|
|
82
79
|
return (cast(PartOfSpeech, lowered),)
|
|
83
80
|
|
|
84
81
|
normalized: list[PartOfSpeech] = []
|
|
85
82
|
for pos in part_of_speech:
|
|
86
83
|
if pos not in _VALID_POS:
|
|
87
|
-
raise ValueError(
|
|
88
|
-
"part_of_speech entries must be one of 'n', 'v', 'a', or 'r'"
|
|
89
|
-
)
|
|
84
|
+
raise ValueError("part_of_speech entries must be one of 'n', 'v', 'a', or 'r'")
|
|
90
85
|
if pos not in normalized:
|
|
91
86
|
normalized.append(pos)
|
|
92
87
|
if not normalized:
|
|
@@ -118,6 +113,7 @@ def substitute_random_synonyms(
|
|
|
118
113
|
"""Replace words with random lexicon-driven synonyms.
|
|
119
114
|
|
|
120
115
|
Parameters
|
|
116
|
+
----------
|
|
121
117
|
- text: Input text.
|
|
122
118
|
- rate: Max proportion of candidate words to replace (default 0.01).
|
|
123
119
|
- part_of_speech: WordNet POS tag(s) to target. Accepts "n", "v", "a", "r",
|
|
@@ -134,6 +130,7 @@ def substitute_random_synonyms(
|
|
|
134
130
|
- Replacement positions chosen via rng.sample.
|
|
135
131
|
- Synonyms sourced through the lexicon; the default backend derives
|
|
136
132
|
deterministic subsets per word and part-of-speech using the active seed.
|
|
133
|
+
|
|
137
134
|
"""
|
|
138
135
|
effective_rate = resolve_rate(
|
|
139
136
|
rate=rate,
|
|
@@ -168,7 +165,7 @@ def substitute_random_synonyms(
|
|
|
168
165
|
# Split but keep whitespace separators so we can rebuild easily
|
|
169
166
|
tokens = re.split(r"(\s+)", text)
|
|
170
167
|
|
|
171
|
-
# Collect
|
|
168
|
+
# Collect candidate word indices (even positions are words because separators are kept)
|
|
172
169
|
candidate_indices: list[int] = []
|
|
173
170
|
candidate_metadata: dict[int, CandidateInfo] = {}
|
|
174
171
|
for idx, tok in enumerate(tokens):
|
|
@@ -296,9 +293,7 @@ class Jargoyle(Glitchling):
|
|
|
296
293
|
current_lexicon.reseed(self.seed)
|
|
297
294
|
else:
|
|
298
295
|
if hasattr(self, "_external_lexicon_original_seed"):
|
|
299
|
-
original_seed = getattr(
|
|
300
|
-
self, "_external_lexicon_original_seed", None
|
|
301
|
-
)
|
|
296
|
+
original_seed = getattr(self, "_external_lexicon_original_seed", None)
|
|
302
297
|
current_lexicon.reseed(original_seed)
|
|
303
298
|
elif canonical == "lexicon" and isinstance(value, Lexicon):
|
|
304
299
|
if getattr(self, "_initializing", False):
|
glitchlings/zoo/mim1c.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
from collections.abc import Collection
|
|
2
1
|
import random
|
|
2
|
+
from collections.abc import Collection
|
|
3
3
|
from typing import Literal
|
|
4
4
|
|
|
5
5
|
from confusable_homoglyphs import confusables
|
|
6
6
|
|
|
7
|
-
from .core import AttackOrder, AttackWave, Glitchling
|
|
8
7
|
from ._rate import resolve_rate
|
|
8
|
+
from .core import AttackOrder, AttackWave, Glitchling
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def swap_homoglyphs(
|
|
@@ -21,16 +21,21 @@ def swap_homoglyphs(
|
|
|
21
21
|
"""Replace characters with visually confusable homoglyphs.
|
|
22
22
|
|
|
23
23
|
Parameters
|
|
24
|
+
----------
|
|
24
25
|
- text: Input text.
|
|
25
26
|
- rate: Max proportion of eligible characters to replace (default 0.02).
|
|
26
|
-
- classes: Restrict replacements to these Unicode script classes (default
|
|
27
|
+
- classes: Restrict replacements to these Unicode script classes (default
|
|
28
|
+
["LATIN", "GREEK", "CYRILLIC"]). Use "all" to allow any.
|
|
27
29
|
- banned_characters: Characters that must never appear as replacements.
|
|
28
30
|
- seed: Optional seed if `rng` not provided.
|
|
29
31
|
- rng: Optional RNG; overrides seed.
|
|
30
32
|
|
|
31
33
|
Notes
|
|
32
|
-
|
|
34
|
+
-----
|
|
35
|
+
- Only replaces characters present in ``confusables.confusables_data`` with
|
|
36
|
+
single-codepoint alternatives.
|
|
33
37
|
- Maintains determinism by shuffling candidates and sampling via the provided RNG.
|
|
38
|
+
|
|
34
39
|
"""
|
|
35
40
|
effective_rate = resolve_rate(
|
|
36
41
|
rate=rate,
|
|
@@ -46,9 +51,7 @@ def swap_homoglyphs(
|
|
|
46
51
|
classes = ["LATIN", "GREEK", "CYRILLIC"]
|
|
47
52
|
|
|
48
53
|
target_chars = [char for char in text if char.isalnum()]
|
|
49
|
-
confusable_chars = [
|
|
50
|
-
char for char in target_chars if char in confusables.confusables_data
|
|
51
|
-
]
|
|
54
|
+
confusable_chars = [char for char in target_chars if char in confusables.confusables_data]
|
|
52
55
|
clamped_rate = max(0.0, effective_rate)
|
|
53
56
|
num_replacements = int(len(confusable_chars) * clamped_rate)
|
|
54
57
|
done = 0
|
|
@@ -57,9 +60,7 @@ def swap_homoglyphs(
|
|
|
57
60
|
for char in confusable_chars:
|
|
58
61
|
if done >= num_replacements:
|
|
59
62
|
break
|
|
60
|
-
options = [
|
|
61
|
-
o["c"] for o in confusables.confusables_data[char] if len(o["c"]) == 1
|
|
62
|
-
]
|
|
63
|
+
options = [o["c"] for o in confusables.confusables_data[char] if len(o["c"]) == 1]
|
|
63
64
|
if classes != "all":
|
|
64
65
|
options = [opt for opt in options if confusables.alias(opt) in classes]
|
|
65
66
|
if banned_set:
|
glitchlings/zoo/redactyl.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import re
|
|
2
1
|
import random
|
|
2
|
+
import re
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from ._rate import resolve_rate
|
|
@@ -32,24 +32,22 @@ def _python_redact_words(
|
|
|
32
32
|
"""Redact random words by replacing their characters.
|
|
33
33
|
|
|
34
34
|
Parameters
|
|
35
|
+
----------
|
|
35
36
|
- text: Input text.
|
|
36
37
|
- replacement_char: The character to use for redaction (default FULL_BLOCK).
|
|
37
38
|
- rate: Max proportion of words to redact (default 0.05).
|
|
38
39
|
- merge_adjacent: If True, merges adjacent redactions across intervening non-word chars.
|
|
39
40
|
- rng: RNG used for sampling decisions.
|
|
40
41
|
- unweighted: When True, sample words uniformly instead of by length.
|
|
42
|
+
|
|
41
43
|
"""
|
|
42
44
|
tokens = split_preserving_whitespace(text)
|
|
43
45
|
word_tokens = collect_word_tokens(tokens)
|
|
44
46
|
if not word_tokens:
|
|
45
|
-
raise ValueError(
|
|
46
|
-
"Cannot redact words because the input text contains no redactable words."
|
|
47
|
-
)
|
|
47
|
+
raise ValueError("Cannot redact words because the input text contains no redactable words.")
|
|
48
48
|
|
|
49
49
|
population = [token.index for token in word_tokens]
|
|
50
|
-
weights = [
|
|
51
|
-
1.0 if unweighted else float(token.core_length) for token in word_tokens
|
|
52
|
-
]
|
|
50
|
+
weights = [1.0 if unweighted else float(token.core_length) for token in word_tokens]
|
|
53
51
|
|
|
54
52
|
clamped_rate = max(0.0, min(rate, 1.0))
|
|
55
53
|
raw_quota = len(population) * clamped_rate
|
|
@@ -105,7 +103,6 @@ def redact_words(
|
|
|
105
103
|
unweighted: bool = False,
|
|
106
104
|
) -> str:
|
|
107
105
|
"""Redact random words by replacing their characters."""
|
|
108
|
-
|
|
109
106
|
effective_rate = resolve_rate(
|
|
110
107
|
rate=rate,
|
|
111
108
|
legacy_value=redaction_rate,
|
glitchlings/zoo/reduple.py
CHANGED
|
@@ -21,14 +21,17 @@ def _python_reduplicate_words(
|
|
|
21
21
|
"""Randomly reduplicate words in the text.
|
|
22
22
|
|
|
23
23
|
Parameters
|
|
24
|
+
----------
|
|
24
25
|
- text: Input text.
|
|
25
26
|
- rate: Max proportion of words to reduplicate (default 0.05).
|
|
26
27
|
- rng: RNG used for sampling decisions.
|
|
27
28
|
- unweighted: When True, sample words uniformly instead of length-weighted.
|
|
28
29
|
|
|
29
30
|
Notes
|
|
31
|
+
-----
|
|
30
32
|
- Preserves spacing and punctuation by tokenizing with separators.
|
|
31
33
|
- Deterministic when run with a fixed seed or via Gaggle.
|
|
34
|
+
|
|
32
35
|
"""
|
|
33
36
|
tokens = split_preserving_whitespace(text)
|
|
34
37
|
word_tokens = collect_word_tokens(tokens)
|
|
@@ -77,7 +80,6 @@ def reduplicate_words(
|
|
|
77
80
|
Falls back to the Python implementation when the optional Rust
|
|
78
81
|
extension is unavailable.
|
|
79
82
|
"""
|
|
80
|
-
|
|
81
83
|
effective_rate = resolve_rate(
|
|
82
84
|
rate=rate,
|
|
83
85
|
legacy_value=reduplication_rate,
|
glitchlings/zoo/rushmore.py
CHANGED
|
@@ -21,7 +21,6 @@ def _python_delete_random_words(
|
|
|
21
21
|
unweighted: bool = False,
|
|
22
22
|
) -> str:
|
|
23
23
|
"""Delete random words from the input text while preserving whitespace."""
|
|
24
|
-
|
|
25
24
|
effective_rate = max(rate, 0.0)
|
|
26
25
|
if effective_rate <= 0.0:
|
|
27
26
|
return text
|
|
@@ -37,15 +36,11 @@ def _python_delete_random_words(
|
|
|
37
36
|
if not weighted_tokens:
|
|
38
37
|
return text
|
|
39
38
|
|
|
40
|
-
allowed_deletions = min(
|
|
41
|
-
len(weighted_tokens), math.floor(len(weighted_tokens) * effective_rate)
|
|
42
|
-
)
|
|
39
|
+
allowed_deletions = min(len(weighted_tokens), math.floor(len(weighted_tokens) * effective_rate))
|
|
43
40
|
if allowed_deletions <= 0:
|
|
44
41
|
return text
|
|
45
42
|
|
|
46
|
-
mean_weight = sum(weight for _, weight, _ in weighted_tokens) / len(
|
|
47
|
-
weighted_tokens
|
|
48
|
-
)
|
|
43
|
+
mean_weight = sum(weight for _, weight, _ in weighted_tokens) / len(weighted_tokens)
|
|
49
44
|
|
|
50
45
|
deletions = 0
|
|
51
46
|
for index, weight, token in weighted_tokens:
|
|
@@ -88,7 +83,6 @@ def delete_random_words(
|
|
|
88
83
|
|
|
89
84
|
Uses the optional Rust implementation when available.
|
|
90
85
|
"""
|
|
91
|
-
|
|
92
86
|
effective_rate = resolve_rate(
|
|
93
87
|
rate=rate,
|
|
94
88
|
legacy_value=max_deletion_rate,
|
glitchlings/zoo/scannequin.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import re
|
|
2
1
|
import random
|
|
2
|
+
import re
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from ._ocr_confusions import load_confusion_table
|
|
6
|
-
from .core import Glitchling, AttackWave, AttackOrder
|
|
7
6
|
from ._rate import resolve_rate
|
|
7
|
+
from .core import AttackOrder, AttackWave, Glitchling
|
|
8
8
|
|
|
9
9
|
try:
|
|
10
10
|
from glitchlings._zoo_rust import ocr_artifacts as _ocr_artifacts_rust
|
|
@@ -21,17 +21,20 @@ def _python_ocr_artifacts(
|
|
|
21
21
|
"""Introduce OCR-like artifacts into text.
|
|
22
22
|
|
|
23
23
|
Parameters
|
|
24
|
+
----------
|
|
24
25
|
- text: Input text to corrupt.
|
|
25
26
|
- rate: Max proportion of eligible confusion matches to replace (default 0.02).
|
|
26
27
|
- seed: Optional seed if `rng` not provided.
|
|
27
28
|
- rng: Optional RNG; overrides seed.
|
|
28
29
|
|
|
29
30
|
Notes
|
|
31
|
+
-----
|
|
30
32
|
- Uses a curated set of common OCR confusions (rn↔m, cl↔d, O↔0, l/I/1, etc.).
|
|
31
33
|
- Collects all non-overlapping candidate spans in reading order, then samples
|
|
32
34
|
a subset deterministically with the provided RNG.
|
|
33
35
|
- Replacements can change length (e.g., m→rn), so edits are applied from left
|
|
34
36
|
to right using precomputed spans to avoid index drift.
|
|
37
|
+
|
|
35
38
|
"""
|
|
36
39
|
if not text:
|
|
37
40
|
return text
|
|
@@ -107,7 +110,6 @@ def ocr_artifacts(
|
|
|
107
110
|
|
|
108
111
|
Prefers the Rust implementation when available.
|
|
109
112
|
"""
|
|
110
|
-
|
|
111
113
|
if not text:
|
|
112
114
|
return text
|
|
113
115
|
|
|
@@ -164,7 +166,6 @@ class Scannequin(Glitchling):
|
|
|
164
166
|
return {"type": "ocr", "error_rate": float(rate)}
|
|
165
167
|
|
|
166
168
|
|
|
167
|
-
|
|
168
169
|
scannequin = Scannequin()
|
|
169
170
|
|
|
170
171
|
|
glitchlings/zoo/typogre.py
CHANGED
|
@@ -4,9 +4,9 @@ import math
|
|
|
4
4
|
import random
|
|
5
5
|
from typing import Any, Optional
|
|
6
6
|
|
|
7
|
-
from .core import Glitchling, AttackWave, AttackOrder
|
|
8
|
-
from ._rate import resolve_rate
|
|
9
7
|
from ..util import KEYNEIGHBORS
|
|
8
|
+
from ._rate import resolve_rate
|
|
9
|
+
from .core import AttackOrder, AttackWave, Glitchling
|
|
10
10
|
|
|
11
11
|
try:
|
|
12
12
|
from glitchlings._zoo_rust import fatfinger as _fatfinger_rust
|
|
@@ -64,9 +64,7 @@ def _python_eligible_idx(s: str, i: int) -> bool:
|
|
|
64
64
|
return left_ok and right_ok
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
def _python_draw_eligible_index(
|
|
68
|
-
rng: random.Random, s: str, max_tries: int = 16
|
|
69
|
-
) -> Optional[int]:
|
|
67
|
+
def _python_draw_eligible_index(rng: random.Random, s: str, max_tries: int = 16) -> Optional[int]:
|
|
70
68
|
n = len(s)
|
|
71
69
|
if n == 0:
|
|
72
70
|
return None
|
|
@@ -151,7 +149,6 @@ def fatfinger(
|
|
|
151
149
|
max_change_rate: float | None = None,
|
|
152
150
|
) -> str:
|
|
153
151
|
"""Introduce character-level "fat finger" edits with a Rust fast path."""
|
|
154
|
-
|
|
155
152
|
effective_rate = resolve_rate(
|
|
156
153
|
rate=rate,
|
|
157
154
|
legacy_value=max_change_rate,
|
|
@@ -230,4 +227,3 @@ typogre = Typogre()
|
|
|
230
227
|
|
|
231
228
|
|
|
232
229
|
__all__ = ["Typogre", "typogre"]
|
|
233
|
-
|
glitchlings/zoo/zeedub.py
CHANGED
|
@@ -3,9 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
import math
|
|
4
4
|
import random
|
|
5
5
|
from collections.abc import Sequence
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
|
-
from .core import Glitchling, AttackWave, AttackOrder
|
|
8
8
|
from ._rate import resolve_rate
|
|
9
|
+
from .core import AttackOrder, AttackWave, Glitchling
|
|
9
10
|
|
|
10
11
|
try:
|
|
11
12
|
from glitchlings._zoo_rust import inject_zero_widths as _inject_zero_widths_rust
|
|
@@ -77,7 +78,6 @@ def insert_zero_widths(
|
|
|
77
78
|
characters: Sequence[str] | None = None,
|
|
78
79
|
) -> str:
|
|
79
80
|
"""Inject zero-width characters between non-space character pairs."""
|
|
80
|
-
|
|
81
81
|
effective_rate = resolve_rate(
|
|
82
82
|
rate=rate,
|
|
83
83
|
legacy_value=None,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: glitchlings
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Monsters for your language games.
|
|
5
5
|
Author: osoleve
|
|
6
6
|
License: Apache License
|
|
@@ -239,6 +239,16 @@ Provides-Extra: dev
|
|
|
239
239
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
240
240
|
Requires-Dist: hypothesis>=6.140.0; extra == "dev"
|
|
241
241
|
Requires-Dist: numpy<=2.0,>=1.24; extra == "dev"
|
|
242
|
+
Requires-Dist: mkdocs>=1.6.0; extra == "dev"
|
|
243
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "dev"
|
|
244
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == "dev"
|
|
245
|
+
Requires-Dist: mkdocstrings-python>=1.10.0; extra == "dev"
|
|
246
|
+
Requires-Dist: interrogate>=1.5.0; extra == "dev"
|
|
247
|
+
Requires-Dist: black>=24.4.0; extra == "dev"
|
|
248
|
+
Requires-Dist: isort>=5.13.0; extra == "dev"
|
|
249
|
+
Requires-Dist: ruff>=0.6.0; extra == "dev"
|
|
250
|
+
Requires-Dist: mypy>=1.8.0; extra == "dev"
|
|
251
|
+
Requires-Dist: pre-commit>=3.8.0; extra == "dev"
|
|
242
252
|
Dynamic: license-file
|
|
243
253
|
|
|
244
254
|
#
|
|
@@ -338,10 +348,66 @@ They're horrible little gremlins, but they're not _unreasonable_.
|
|
|
338
348
|
|
|
339
349
|
Keyboard warriors can challenge them directly via the `glitchlings` command:
|
|
340
350
|
|
|
351
|
+
<!-- BEGIN: CLI_USAGE -->
|
|
341
352
|
```bash
|
|
342
353
|
# Discover which glitchlings are currently on the loose.
|
|
343
354
|
glitchlings --list
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
```text
|
|
358
|
+
Typogre — scope: Character, order: early
|
|
359
|
+
Mim1c — scope: Character, order: last
|
|
360
|
+
Jargoyle — scope: Word, order: normal
|
|
361
|
+
Adjax — scope: Word, order: normal
|
|
362
|
+
Reduple — scope: Word, order: normal
|
|
363
|
+
Rushmore — scope: Word, order: normal
|
|
364
|
+
Redactyl — scope: Word, order: normal
|
|
365
|
+
Scannequin — scope: Character, order: late
|
|
366
|
+
Zeedub — scope: Character, order: last
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
# Review the full CLI contract.
|
|
371
|
+
glitchlings --help
|
|
372
|
+
```
|
|
344
373
|
|
|
374
|
+
```text
|
|
375
|
+
usage: glitchlings [-h] [-g SPEC] [-s SEED] [-f FILE] [--sample] [--diff]
|
|
376
|
+
[--list] [-c CONFIG]
|
|
377
|
+
[text]
|
|
378
|
+
|
|
379
|
+
Summon glitchlings to corrupt text. Provide input text as an argument, via
|
|
380
|
+
--file, or pipe it on stdin.
|
|
381
|
+
|
|
382
|
+
positional arguments:
|
|
383
|
+
text Text to corrupt. If omitted, stdin is used or --sample
|
|
384
|
+
provides fallback text.
|
|
385
|
+
|
|
386
|
+
options:
|
|
387
|
+
-h, --help show this help message and exit
|
|
388
|
+
-g SPEC, --glitchling SPEC
|
|
389
|
+
Glitchling to apply, optionally with parameters like
|
|
390
|
+
Typogre(rate=0.05). Repeat for multiples; defaults to
|
|
391
|
+
all built-ins.
|
|
392
|
+
-s SEED, --seed SEED Seed controlling deterministic corruption order
|
|
393
|
+
(default: 151).
|
|
394
|
+
-f FILE, --file FILE Read input text from a file instead of the command
|
|
395
|
+
line argument.
|
|
396
|
+
--sample Use the included SAMPLE_TEXT when no other input is
|
|
397
|
+
provided.
|
|
398
|
+
--diff Show a unified diff between the original and corrupted
|
|
399
|
+
text.
|
|
400
|
+
--list List available glitchlings and exit.
|
|
401
|
+
-c CONFIG, --config CONFIG
|
|
402
|
+
Load glitchlings from a YAML configuration file.
|
|
403
|
+
```
|
|
404
|
+
<!-- END: CLI_USAGE -->
|
|
405
|
+
|
|
406
|
+
Run `python docs/build_cli_reference.py` whenever you tweak the CLI so the README stays in sync with the actual output. The script executes the commands above and replaces the block between the markers automatically.
|
|
407
|
+
|
|
408
|
+
Prefer inline tweaks? You can still configure glitchlings directly in the shell:
|
|
409
|
+
|
|
410
|
+
```bash
|
|
345
411
|
# Run Typogre against the contents of a file and inspect the diff.
|
|
346
412
|
glitchlings -g typogre --file documents/report.txt --diff
|
|
347
413
|
|
|
@@ -355,8 +421,6 @@ echo "Beware LLM-written flavor-text" | glitchlings -g mim1c
|
|
|
355
421
|
glitchlings --config experiments/chaos.yaml "Let slips the glitchlings of war"
|
|
356
422
|
```
|
|
357
423
|
|
|
358
|
-
Use `--help` for a complete breakdown of available options, including support for parameterised glitchlings via `-g "Name(arg=value, ...)"` to mirror the Python API.
|
|
359
|
-
|
|
360
424
|
Attack configurations live in plain YAML files so you can version-control experiments without touching code:
|
|
361
425
|
|
|
362
426
|
```yaml
|
|
@@ -420,7 +484,7 @@ _How can a computer need reading glasses?_
|
|
|
420
484
|
|
|
421
485
|
### Zeedub
|
|
422
486
|
|
|
423
|
-
|
|
487
|
+
_Watch your step around here._
|
|
424
488
|
|
|
425
489
|
> _**Invisible Ink.**_ Zeedub slips zero-width codepoints between non-space character pairs, forcing models to reason about text whose visible form masks hidden glyphs.
|
|
426
490
|
>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
glitchlings/__init__.py,sha256=PggQt66bImHyWBggz5CTTFvB19P7iOCMjp2uncvcgXA,1177
|
|
2
|
+
glitchlings/__main__.py,sha256=nB7btO_T4wBFOcyawfWpjEindVrUfTqqV5hdeeS1HT8,128
|
|
3
|
+
glitchlings/_zoo_rust.cp312-win_amd64.pyd,sha256=_J4R5tA4q8CesIZ-K-3OJybUoy-NM_-kmHyo5-GE9vU,2103808
|
|
4
|
+
glitchlings/compat.py,sha256=qba3_W4W5edy9_hoPkekBRNhYy34eG2yCdyWaNrbxeg,7042
|
|
5
|
+
glitchlings/config.py,sha256=USnSw5-HO0ghsuwbmEvimZ4acU2EeNChB6RPlBFj4hc,13013
|
|
6
|
+
glitchlings/config.toml,sha256=EOEqKUwPygOv7MuEuExil5ZQfwKV1H2hU-Z5aBKQ440,111
|
|
7
|
+
glitchlings/main.py,sha256=JDgfHPDhRvZVb7bYQAFGHTRxH8yGNlgStlBqv-y5Thk,10444
|
|
8
|
+
glitchlings/dlc/__init__.py,sha256=IHD-GGhVFb7SVzErvf2YCJkOR4wGo0nFHXkn_daMvS8,146
|
|
9
|
+
glitchlings/dlc/_shared.py,sha256=i66HyJJiHpR0mug7zmfmxB17Vs3CSqBTsk5CuVaLDk0,2040
|
|
10
|
+
glitchlings/dlc/huggingface.py,sha256=Ym8dTArb-43AnCyukOO1m66iAbs8al9YkIWB3rGdhTk,2657
|
|
11
|
+
glitchlings/dlc/prime.py,sha256=KY3so8WOwksbsKhZXfWorsZSYvIdPiUtc8e9apHabkM,8861
|
|
12
|
+
glitchlings/lexicon/__init__.py,sha256=N1G-0xL-dkjRECEhLE1j7BrpBW6evqtjmcG5kiAczTM,6442
|
|
13
|
+
glitchlings/lexicon/_cache.py,sha256=cQCO-dizyClUz8FU8xyaeaJDBxqwrDo6v3YyJ-MQfp0,4052
|
|
14
|
+
glitchlings/lexicon/graph.py,sha256=00HQEbjNVXuBkgCyQy-ru6BB9GHDKiSJXv1TIillXRw,10339
|
|
15
|
+
glitchlings/lexicon/metrics.py,sha256=TZAafSKgHpUS4h6vCuhTKGsvu_fru9kMqsXqLID6BTM,4734
|
|
16
|
+
glitchlings/lexicon/vector.py,sha256=6QDQB2LAjRu1dZwlGYhkkdHyGv9UO79jUbf6KEtjvac,20243
|
|
17
|
+
glitchlings/lexicon/wordnet.py,sha256=YoEOMSIPrkrIORR3wMnPftKJLYh5PBQ7PTNrzZGchxg,6504
|
|
18
|
+
glitchlings/lexicon/data/default_vector_cache.json,sha256=fLT-v1sgF0lv88aPwOP23br9azrjeAkJ1ft6OgPlMeM,741
|
|
19
|
+
glitchlings/util/__init__.py,sha256=Q5lkncOaM6f2eJK3HAtZyxpCjGnekCpwPloqasS3JDo,4869
|
|
20
|
+
glitchlings/util/adapters.py,sha256=mFhPlE8JaFuO_C-3_aqhgwkqa6isV8Y2ifqVh3Iv9JM,720
|
|
21
|
+
glitchlings/zoo/__init__.py,sha256=EljxDKxbl6E4hTuC7Ul98dsp-FvJ2nXQTvD5LoWToWc,5271
|
|
22
|
+
glitchlings/zoo/_ocr_confusions.py,sha256=pPlvJOoan3ouwwGt8hATcO-9luIrGJl0vwUqssUMXD8,1236
|
|
23
|
+
glitchlings/zoo/_rate.py,sha256=o7B9_EfadjshSGLH0B5BHgj1J0OJWVCSXkEE8hljmxc,522
|
|
24
|
+
glitchlings/zoo/_sampling.py,sha256=AAPLObjqKrmX882TX8hdvPHReBOcv0Z4pUuW6AxuGgU,1640
|
|
25
|
+
glitchlings/zoo/_text_utils.py,sha256=LqCa33E-Qxbk6N5AVfxEmAz6C2u7_mCF0xPT9-404A8,2854
|
|
26
|
+
glitchlings/zoo/adjax.py,sha256=Rx8PxK9MBecaSXHJv7rXzWL2uP1QTdNuO2XohPZ61uo,3657
|
|
27
|
+
glitchlings/zoo/core.py,sha256=OE3zZYtyqlQoJkycxl5ZOG52Rxqi05Hd4rr2CAGUhrw,19929
|
|
28
|
+
glitchlings/zoo/jargoyle.py,sha256=fnSXlHlOlVFNKUP44V1TyXFmDYAt1dm1tV2dGL8hCFU,11773
|
|
29
|
+
glitchlings/zoo/mim1c.py,sha256=GqUMErVAVcqMAZjx4hhJ0Af25CxA0Aorv3U_fTqLZek,3546
|
|
30
|
+
glitchlings/zoo/ocr_confusions.tsv,sha256=S-IJEYCIXYKT1Uu7Id8Lnvg5pw528yNigTtWUdnMv9k,213
|
|
31
|
+
glitchlings/zoo/redactyl.py,sha256=0xGFuygN-vCsNplm3UddzFf2pWqvl7RShUFyXNdSzJ4,5627
|
|
32
|
+
glitchlings/zoo/reduple.py,sha256=lpKNqpSk-gzLKryxvobuikTpG3uOXZqPntyxmeeuPhg,4390
|
|
33
|
+
glitchlings/zoo/rushmore.py,sha256=_jU78_q_iJAWffjfq24WwQ2teyQ4brKOFoOU4IZnM7k,4459
|
|
34
|
+
glitchlings/zoo/scannequin.py,sha256=INTZlzskkXPy8zz6O19DBAbyRLQxvFK0AYhwjLfY7Ec,5055
|
|
35
|
+
glitchlings/zoo/typogre.py,sha256=zXvZX8V_0yDmEaLheWKBRa9vCEnSc9TiekYUqZITx0w,6889
|
|
36
|
+
glitchlings/zoo/zeedub.py,sha256=0k7IuTWXbMt5B-1IOwzGk29EvHZNkxyEQUlZloIcrOc,5006
|
|
37
|
+
glitchlings-0.4.2.dist-info/licenses/LICENSE,sha256=EFEP1evBfHaxsMTBjxm0sZVRp2wct8QLvHE1saII5FI,11538
|
|
38
|
+
glitchlings-0.4.2.dist-info/METADATA,sha256=9h2Wc3BbR0pm6d-_AfOcMvTJFL06cVuQFw43d2BVYns,31312
|
|
39
|
+
glitchlings-0.4.2.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101
|
|
40
|
+
glitchlings-0.4.2.dist-info/entry_points.txt,sha256=kGOwuAsjFDLtztLisaXtOouq9wFVMOJg5FzaAkg-Hto,54
|
|
41
|
+
glitchlings-0.4.2.dist-info/top_level.txt,sha256=VHFNBrLjtDwPCYXbGKi6o17Eueedi81eNbR3hBOoST0,12
|
|
42
|
+
glitchlings-0.4.2.dist-info/RECORD,,
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
glitchlings/__init__.py,sha256=onTBFM_ih4O1E1ntZaNaFxiMcD5NtCGc4TaX276sgNk,867
|
|
2
|
-
glitchlings/__main__.py,sha256=pqNe1C9hMf8pap4oh6x6yo2h4Nsa2RFSaMWHfGtNXj0,130
|
|
3
|
-
glitchlings/_zoo_rust.cp312-win_amd64.pyd,sha256=yuHypdVdmcEzqbRRrSsGD9w1vgSTYJOyOW83zKCi1WE,2071040
|
|
4
|
-
glitchlings/config.py,sha256=P6qMJdHrvZYAIUj7NXxrpEKcv6lDy8Eo4toWu3ctsHs,8043
|
|
5
|
-
glitchlings/config.toml,sha256=EOEqKUwPygOv7MuEuExil5ZQfwKV1H2hU-Z5aBKQ440,111
|
|
6
|
-
glitchlings/main.py,sha256=sKdUk4trBS-yNbEAOwdTXldg87TSPwnSAr_inecj4bE,10442
|
|
7
|
-
glitchlings/dlc/__init__.py,sha256=IHD-GGhVFb7SVzErvf2YCJkOR4wGo0nFHXkn_daMvS8,146
|
|
8
|
-
glitchlings/dlc/huggingface.py,sha256=PIesnDIEvyJxj1IuLw2P9nVPTr4Nv81XM7w2axfyhkA,3029
|
|
9
|
-
glitchlings/dlc/prime.py,sha256=b5CE1qDl5MxZjTudlKrqMsmSGxXNKZ16krqPyrr2nK8,9569
|
|
10
|
-
glitchlings/lexicon/__init__.py,sha256=kCQ0_Dbh39gQNVeL2PAC-8ByUOXyK0mnHZmsJ9x70z0,5854
|
|
11
|
-
glitchlings/lexicon/graph.py,sha256=mQ-EA-q_EIqGrWezB-hFtU8iohabFYYI3W3KE-pHOP4,10836
|
|
12
|
-
glitchlings/lexicon/metrics.py,sha256=zwd3vm9-pUQbSywORXgHyHCfAjIJs8S5rPNQ70UYgUo,4768
|
|
13
|
-
glitchlings/lexicon/vector.py,sha256=b_mlYjwn3mCyOHrdlPdfwqBaB25jSBMZNNyvmK0Kb0g,20894
|
|
14
|
-
glitchlings/lexicon/wordnet.py,sha256=OrI5L3K3wYddVw66JmvokirqxDvZangKWC7VXYimVi0,5834
|
|
15
|
-
glitchlings/lexicon/data/default_vector_cache.json,sha256=fLT-v1sgF0lv88aPwOP23br9azrjeAkJ1ft6OgPlMeM,741
|
|
16
|
-
glitchlings/util/__init__.py,sha256=GoyQuHTfGRkHzuZwJji6QWSiGd_LHa9QiyjjEpBFW7E,4679
|
|
17
|
-
glitchlings/zoo/__init__.py,sha256=AQu2Z0ECuzQDXwM_DbGaNzkcjLu8WptJS17sh6WTyyA,4975
|
|
18
|
-
glitchlings/zoo/_ocr_confusions.py,sha256=W59Aa5MBDwRF65f8GV-6XwGAmlR5Uk7pa5qvHvhIYdY,1252
|
|
19
|
-
glitchlings/zoo/_rate.py,sha256=EYUWXYyR2IK0zYBWyBOlnUjDxU32JE9mZTZeodVx5CA,548
|
|
20
|
-
glitchlings/zoo/_sampling.py,sha256=UK-XmEERjtY7nLaWDp81yktuZ_K80Un-9tvj4MjsHcg,1642
|
|
21
|
-
glitchlings/zoo/_text_utils.py,sha256=YxV069L8c0YSn5iCp72Dv8XCdfhbcFeBrbMoBeKIDns,2862
|
|
22
|
-
glitchlings/zoo/adjax.py,sha256=G2diAEsQ8T4mjFCcTeiGzLF0261n7LjLyW5HyVCy3R4,3661
|
|
23
|
-
glitchlings/zoo/core.py,sha256=sK3F1OVifbzQFsDrG-pQIImcGP7YfccwTfbqFTJi8Fc,14622
|
|
24
|
-
glitchlings/zoo/jargoyle.py,sha256=yRSVRKHdnaUfZMDJ6miBhRQpPHfYK9iD2DCYMp-7Dec,11807
|
|
25
|
-
glitchlings/zoo/mim1c.py,sha256=3ddNOzWgLABuEOh5T98Xk439ejx-YHGI7ErXET03Crc,3537
|
|
26
|
-
glitchlings/zoo/ocr_confusions.tsv,sha256=S-IJEYCIXYKT1Uu7Id8Lnvg5pw528yNigTtWUdnMv9k,213
|
|
27
|
-
glitchlings/zoo/redactyl.py,sha256=P2YYo1V_u62WIj8zqgDpbzDsreGx2I77BJ0RkdCKhXU,5651
|
|
28
|
-
glitchlings/zoo/reduple.py,sha256=w90xQWQKwkY3tItk8S20emDQy4FLDbee9rrPyh_ffpg,4363
|
|
29
|
-
glitchlings/zoo/rushmore.py,sha256=amAk44TIQBN4rU1c-W1g7I6WForGJMGxNb8uaa8Zfaw,4495
|
|
30
|
-
glitchlings/zoo/scannequin.py,sha256=TJyNYTTIB7rxZH3XKIETy0YVf4EjsMgGWYmYaxH9jxU,5030
|
|
31
|
-
glitchlings/zoo/typogre.py,sha256=j7LuAyYLrP6LjmCm8Jwi_wPxhTAP_TmWbt5pQrOvFZk,6901
|
|
32
|
-
glitchlings/zoo/zeedub.py,sha256=J8F1XZeCMQVVtzWwNiFhOeogjBt1BsOtqrnDjlwUcl8,4984
|
|
33
|
-
glitchlings-0.4.0.dist-info/licenses/LICENSE,sha256=EFEP1evBfHaxsMTBjxm0sZVRp2wct8QLvHE1saII5FI,11538
|
|
34
|
-
glitchlings-0.4.0.dist-info/METADATA,sha256=84RCkkFpmUjS7sLda_e7UAuUuJe8JLGxNDRpTpK5Ofc,28872
|
|
35
|
-
glitchlings-0.4.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101
|
|
36
|
-
glitchlings-0.4.0.dist-info/entry_points.txt,sha256=kGOwuAsjFDLtztLisaXtOouq9wFVMOJg5FzaAkg-Hto,54
|
|
37
|
-
glitchlings-0.4.0.dist-info/top_level.txt,sha256=VHFNBrLjtDwPCYXbGKi6o17Eueedi81eNbR3hBOoST0,12
|
|
38
|
-
glitchlings-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|