Skip to main content

kalja

kalja is a small, dependency-free Python library for text mutation and human-input fuzzing.

It generates deliberately imperfect text for testing systems such as search, fuzzy matching, forms, parsers, typo correction, normalization, and NLP pipelines.

kalja provides Finnish-focused defaults, including a Finnish desktop keyboard layout, while also supporting US QWERTY and custom keyboard layouts.

Installation

pip install kalja

kalja requires Python 3.10 or later.

Quick start

import kalja

result = kalja.mutate(
    "Missä te olette?",
    intensity=0.5,
    seed=42,
)

print(result)

mutate() applies a combination of supported mutation operations to the input text.

Providing a seed makes the result reproducible:

first = kalja.mutate(
    "Missä te olette?",
    intensity=0.7,
    seed=42,
)

second = kalja.mutate(
    "Missä te olette?",
    intensity=0.7,
    seed=42,
)

assert first == second

Generating variants

Use variants() to generate multiple mutated versions of the same input:

import kalja

results = kalja.variants(
    "Voinko varata ajan huomiselle?",
    count=10,
    intensity=0.7,
    seed=42,
)

for result in results:
    print(result)

count controls the number of generated results.

Variants are not guaranteed to be unique. At low intensities or with short inputs, multiple mutation passes may produce the same output.

Mutation intensity

The high-level mutate() and variants() APIs use an intensity value between 0.0 and 1.0.

kalja.mutate(text, intensity=0.0)
kalja.mutate(text, intensity=0.5)
kalja.mutate(text, intensity=1.0)

Intensity is a relative fuzzing level, not a direct probability.

Internally, kalja scales the configured mutation rates:

effective rate = maximum rate × intensity

This means intensity=1.0 enables kalja's full configured mutation rates. It does not mean that every character will be mutated.

At intensity=0.0, all mutation rates are zero and the original text is returned unchanged.

Keyboard layouts

kalja includes Finnish and US desktop keyboard layouts.

Finnish desktop is the default:

import kalja

result = kalja.mutate(
    "Missä te olette?",
    layout=kalja.FI_DESKTOP,
    seed=42,
)

US QWERTY can be selected explicitly:

result = kalja.mutate(
    "Where are you?",
    layout=kalja.US_DESKTOP,
    seed=42,
)

Keyboard-error mutations use physical key positions to select nearby keys.

The included layouts are:

  • kalja.FI_DESKTOP — Finnish desktop QWERTY
  • kalja.US_DESKTOP — US desktop QWERTY

Keyboard coordinates are approximate and are intended for neighboring-key mutation rather than exact physical keyboard simulation.

Low-level mutations

kalja also exposes individual mutation operations when precise control is needed.

Keyboard errors

Replace characters with neighboring keys:

result = kalja.keyboard_error(
    "Oulu 90100",
    rate=0.1,
    seed=42,
)

A different layout can be supplied:

result = kalja.keyboard_error(
    "hello world",
    rate=0.1,
    layout=kalja.US_DESKTOP,
    seed=42,
)

Character transposition

Randomly swap adjacent characters:

result = kalja.transpose_chars(
    "kalja",
    rate=0.05,
    seed=42,
)

Character omission

Randomly remove characters:

result = kalja.drop_chars(
    "kalja",
    rate=0.02,
    seed=42,
)

Character repetition

Randomly duplicate characters:

result = kalja.repeat_chars(
    "kalja",
    rate=0.02,
    seed=42,
)

Spacing

Randomly remove existing spaces or insert new spaces:

result = kalja.mutate_spacing(
    "Missä te olette?",
    rate=0.02,
    seed=42,
)

Casing

Randomly flip the case of characters with distinct upper- and lowercase forms:

result = kalja.mutate_casing(
    "Olen Oulussa",
    rate=0.02,
    seed=42,
)

Punctuation

Randomly omit or duplicate existing punctuation:

result = kalja.mutate_punctuation(
    "Missä olet?",
    rate=0.02,
    seed=42,
)

Rates

Low-level mutation functions use rate rather than intensity.

A rate is the probability associated with that specific mutation operation:

kalja.drop_chars(
    "abcdef",
    rate=0.1,
    seed=42,
)

Here, each character has a 0.1 probability of being dropped.

This differs from the high-level intensity parameter, which scales several mutation rates at once.

Configurable mutator

For more control, use Mutator directly:

import kalja

mutator = kalja.Mutator(
    keyboard_error_rate=0.08,
    transposition_rate=0.04,
    omission_rate=0.02,
    repetition_rate=0.03,
    spacing_rate=0.02,
    casing_rate=0.01,
    punctuation_rate=0.02,
    layout=kalja.FI_DESKTOP,
    seed=42,
)

result = mutator.mutate("Olen täysin kunnossa.")

A Mutator owns its own pseudorandom number generator.

Repeated calls advance that generator:

first = mutator.mutate("Missä te olette?")
second = mutator.mutate("Missä te olette?")

The two results may differ.

Recreating a Mutator with the same configuration and seed reproduces the same sequence of results.

kalja does not modify Python's process-global random state.

Command-line interface

kalja includes a command-line interface.

Mutate text directly:

kalja "Missä te olette?"

Control mutation intensity:

kalja --intensity 0.7 "Missä te olette?"

Use a seed for reproducible output:

kalja --intensity 0.7 --seed 42 "Missä te olette?"

Generate multiple variants:

kalja --count 5 --intensity 0.7 --seed 42 "Missä te olette?"

Select the US keyboard layout:

kalja --layout us "Where are you?"

The Finnish layout is the default:

kalja --layout fi "Missä te olette?"

kalja can also read text from standard input:

echo "Missä te olette?" | kalja --intensity 0.7 --seed 42

Run the built-in help for all options:

kalja --help

Use cases

kalja can be used to generate imperfect inputs for testing:

  • search and autocomplete
  • fuzzy matching
  • typo-tolerant systems
  • form handling
  • text normalization
  • parsers
  • chat applications
  • NLP pipelines
  • validation logic
  • test fixtures and fuzz tests

For example, a search system can be tested against several mutated versions of a query:

import kalja

queries = kalja.variants(
    "ravintola oulu",
    count=20,
    intensity=0.6,
    seed=42,
)

for query in queries:
    test_search(query)

Unicode and Finnish text

kalja works with Python Unicode strings and supports Finnish characters such as:

ä ö å Ä Ö Å

The Finnish desktop layout includes these characters when generating neighboring-key substitutions.

kalja currently operates on Python string characters rather than Unicode grapheme clusters. Combining character sequences may therefore be treated as multiple mutation units.

Limitations

kalja is a mechanical text mutation and fuzzing library. It is not a linguistic model of how people make mistakes.

In particular:

  • keyboard geometry is approximate
  • Finnish and US desktop layouts are currently included
  • AltGr combinations are not modeled
  • dead-key composition is not modeled
  • mobile keyboard geometry is not modeled
  • Unicode grapheme clusters are not treated as atomic units
  • generated mutations are not guaranteed to represent realistic human errors
  • generated variants are not guaranteed to be unique

These constraints are intentional: kalja aims to provide small, deterministic, understandable mutation primitives suitable for testing.

Development

Install the development environment with uv:

uv sync

Run the test suite:

uv run pytest

Run linting:

uv run ruff check .

Check formatting:

uv run ruff format --check .

Run type checking:

uv run mypy src

Run coverage:

uv run pytest --cov=kalja --cov-report=term-missing

License

kalja is licensed under the GNU General Public License v3.0 or later (GPL-3.0-or-later). See the LICENSE file for details.

Release files for kalja 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kalja 0.1.0
File Size Uploaded
kalja-0.1.0.tar.gz 26.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for kalja 0.1.0
File Interpreter ABI Platform
kalja-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 48.1 kB

Release files / kalja-0.1.0.tar.gz

Download URL kalja-0.1.0.tar.gz
Size 26.1 kB
Tags Source
SHA-256 checksum
How to use checksums
8f1036c420c7d5f4b3ff56b36d7b30d191711e67e6dac9c447f603a3cc1481e1
BLAKE2b-256 checksum
How to use checksums
80cee9b53120d81eeafa29a6e466bdf4bf728fca9900cba240dca811f0192a42
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / kalja-0.1.0-py3-none-any.whl

Download URL kalja-0.1.0-py3-none-any.whl
Size 22.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d2abe423b809776a89f5e74e686d31056371338e71c1bc0f912014839163ab70
BLAKE2b-256 checksum
How to use checksums
bc8a802abbb292f73645c768d3f0b13c5af1b472028dcc33f93ad52f2f7aef91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page