Python examples

These examples use the upcoming 0.9.0 API; see Installation. Each example includes its own imports and data. Reuse a configured detector across calls.

Validate a required English field

from typing import Optional
from pygarble import EnsembleDetector

detector = EnsembleDetector(max_input_length=10_000)

def validate_english_field(text: str) -> Optional[str]:
    if not text.strip():
        return "Enter some English text."
    if len(text) > 10_000:
        return "Use at most 10,000 characters."
    if detector.predict(text):
        return "Please review this text; it does not pass the English checks."
    return None

assert validate_english_field("Hello world") is None
assert validate_english_field("") == "Enter some English text."
assert validate_english_field("asdfghjkl") is not None

Use this policy for fields that expect English. Non-English text may be meaningful and still fail these checks. Rare words and names may also require review.

Partition a dataset for review

from pygarble import EnsembleDetector

texts = ["Hello world", "asdfghjkl", "Please review this text"]
detector = EnsembleDetector()
decisions = detector.predict(texts)
flagged = [text for text, bad in zip(texts, decisions) if bad]
remaining = [text for text, bad in zip(texts, decisions) if not bad]
assert flagged == ["asdfghjkl"]
assert len(remaining) == 2

For larger sources, submit lists in caller-controlled chunks. The returned lists are materialized, and input validation covers each submitted batch.

Export explanations as JSON

import json
from dataclasses import asdict
from pygarble import GarbleDetector, Strategy

text = "Please review qxzjkwpvm before delivery."
result = GarbleDetector(Strategy.LOCAL_ANOMALY).analyze(text)
assert result.garbled is True
assert any(text[s.start:s.end] == "qxzjkwpvm" for s in result.spans)
payload = json.dumps(asdict(result), ensure_ascii=False)
assert json.loads(payload)["status"] == "garbled"

asdict includes spans under each signal. result.spans is a convenience property combining those spans, not an additional serialized dataclass field. Offsets use Python string indices, not byte offsets; the end is exclusive.

Check encoding independently of language

from pygarble import EnsembleDetector

detector = EnsembleDetector(profile="corruption")
texts = ["नमस्ते दुनिया", "Café au lait", "Café au lait", "hello\x00world"]
assert detector.predict(texts) == [False, False, True, True]

This detects selected artifacts; it does not repair encoding or certify that all possible encoding problems have been found.

Configure members independently

from pygarble import EnsembleDetector, Strategy

detector = EnsembleDetector(
    strategies=[Strategy.MARKOV_CHAIN, Strategy.WORD_ANOMALY],
    voting="weighted",
    weights=[0.7, 0.3],
    threshold=0.5,
    strategy_kwargs={
        Strategy.MARKOV_CHAIN: {"min_length": 4},
        Strategy.WORD_ANOMALY: {"min_word_length": 6},
    },
    allowlist=["syzygy"],
)
assert detector.predict("syzygy") is False

A custom strategy list defaults to majority voting unless overridden. Validate thresholds and weights against representative inputs; they are policy choices, not calibrated confidence levels.