Skip to main content

Pre-commit hook to detect and fix non-ASCII Unicode characters

Project description

check-unicode

CI License: MIT Python 3.11+

A pre-commit hook to detect and fix non-ASCII Unicode characters in text files.

Catches smart quotes, em dashes, fancy spaces, dangerous invisible characters (Trojan Source bidi attacks, zero-width chars), and other copy-paste artifacts.

Installation

As a pre-commit hook

repos:
  - repo: https://github.com/mit-d/check-unicode
    rev: v0.6.0
    hooks:
      - id: check-unicode
      # or for auto-fix:
      - id: fix-unicode

Standalone

pip install check-unicode
check-unicode path/to/file.txt

Usage

check-unicode [OPTIONS] [FILES...]
Flag Description Default
--fix Replace known offenders with ASCII, exit 1 if changed off
--allow-range RANGE Allow a Unicode range (e.g. U+00A0-U+00FF). Repeat. none
--allow-codepoint CP Allow codepoints (e.g. U+00B0). Repeat/comma-sep. none
--allow-category CAT Allow Unicode category (e.g. Sc). Repeatable. none
--allow-printable Allow all printable chars (only flag invisibles) off
--allow-script SCRIPT Allow Unicode script (e.g. Latin). Repeatable. none
--check-confusables Detect mixed-script homoglyph/confusable characters off
--severity LEVEL error (exit 1) or warning (print, exit 0) error
--no-color Disable ANSI color auto-detect
--config FILE Path to TOML config auto-discover
-q / --quiet Summary only off
-V / --version Print version

What it catches

  • Smart quotes: \u201c \u201d \u2018 \u2019 and variants
  • Dashes: em dash \u2014, en dash \u2013, minus sign \u2212
  • Fancy spaces: non-breaking space, em space, thin space, etc.
  • Ellipsis: \u2026
  • Dangerous invisible characters (always flagged):
    • Bidi control (Trojan Source CVE-2021-42574): U+202A-202E, U+2066-2069
    • Zero-width: U+200B-200F, U+FEFF (mid-file), U+2060-2064, U+180E
    • Replacement character: U+FFFD
  • Confusable homoglyphs (with --check-confusables):
    • Mixed-script identifiers where minority-script chars look like Latin
    • Cyrillic/Greek/Armenian letters that visually resemble Latin letters
    • e.g. Cyrillic a (U+0430) mixed with Latin ccess_level

Auto-fix

--fix replaces known offenders with ASCII equivalents:

Unicode Replacement
Smart quotes ' or "
En/em dashes --
Minus sign -
Fancy spaces
Ellipsis ...

Dangerous invisible characters are never auto-fixed -- they require manual review.

Configuration

Create .check-unicode.toml or add to pyproject.toml:

[tool.check-unicode]
allow-codepoints = ["U+00B0", "U+2192"]
allow-ranges = ["U+00A0-U+00FF"]
allow-categories = ["Sc"]
allow-printable = true
allow-scripts = ["Latin", "Cyrillic"]
check-confusables = true
severity = "error"

Per-file overrides

Use [[tool.check-unicode.overrides]] to apply different settings per file pattern. Each entry requires a files key with a list of glob patterns and can set any of the options above.

Allow-lists (allow-codepoints, allow-ranges, allow-categories, allow-printable, allow-scripts) are additive -- they merge with the global config. severity and check-confusables replace the global value for matching files.

# Relax rules for documentation
[[tool.check-unicode.overrides]]
files = ["docs/*.md", "*.rst"]
allow-printable = true
severity = "warning"

# Allow non-Latin scripts in i18n files
[[tool.check-unicode.overrides]]
files = ["i18n/**"]
allow-scripts = ["Cyrillic", "Han"]
check-confusables = false

Output

path/to/file.txt:42:17: U+201C LEFT DOUBLE QUOTATION MARK [Ps]
  He said \u201chello\u201d to the crowd
          ^
Found 5 non-ASCII characters in 2 files (3 fixable, 1 dangerous)

Development

uv venv && uv sync --group dev
.venv/bin/pytest -v --cov
.venv/bin/ruff check src/ tests/
uvx ty check src/

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

check_unicode-0.6.0.tar.gz (26.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

check_unicode-0.6.0-py3-none-any.whl (25.4 kB view details)

Uploaded Python 3

File details

Details for the file check_unicode-0.6.0.tar.gz.

File metadata

  • Download URL: check_unicode-0.6.0.tar.gz
  • Upload date:
  • Size: 26.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for check_unicode-0.6.0.tar.gz
Algorithm Hash digest
SHA256 33ec600d93760309d1d15259e090346b4e5f3e2c8d4b3f63f7f94d65ec8530f3
MD5 fc5a158d126a9b9e8cc6aa56a5f08d60
BLAKE2b-256 2bde6a40967aa126f790785cce1f8a1435b384b701a2d85649933fed5f85d266

See more details on using hashes here.

Provenance

The following attestation bundles were made for check_unicode-0.6.0.tar.gz:

Publisher: release.yml on mit-d/check-unicode

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file check_unicode-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: check_unicode-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 25.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for check_unicode-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b81e7bd6d8b8716ebe9a23707c82ce7e95ee1411f4c35a5af921aa192d6d6b19
MD5 875118e1acf1bfe8b6b0d4115bdd9fe4
BLAKE2b-256 1b32d7c9e3a03f74f14e35e5cd3bb40c083b9a937b2f31182065cc32cc5e14b6

See more details on using hashes here.

Provenance

The following attestation bundles were made for check_unicode-0.6.0-py3-none-any.whl:

Publisher: release.yml on mit-d/check-unicode

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page