tingle
Spider-sense for refactoring: you know that tingle — the itch that says the codebase isn't right yet. This tool puts a number on it, so you can watch it drop.
Code metrics for the era of constant refactoring.
tingle measures things you want to shrink (or watch) while refactoring a
codebase: ignored lint rules, inline # noqa / # type: ignore comments,
uses of a legacy class during a strangler-fig migration, lines of code in a
package that should disappear.
It runs once, prints the numbers, and stores nothing. To watch a number over months, the metrics-history action records a point per commit that lands and publishes a chart of them.
📖 Documentation: https://tingle.fancysnake.dev/
Install
$ pip install tingle
Quick start
$ tingle init # starter tingle.toml
$ tingle add regex_count '#\s*noqa' # add a metric from the CLI
$ tingle add toml_list_length tool.ruff.lint.ignore --name ruff-ignores
$ tingle # interactive mode (on a terminal)
$ tingle stat # summary table
$ tingle stat --json # machine-readable output
$ tingle stat --diff # impact of the current branch
$ tingle report # every occurrence, file:line
$ tingle report --diff # what the branch added/removed
$ tingle report --group linting # one group, or --metric NAME
Metrics are declared in tingle.toml (or a [tool.tingle] section in
pyproject.toml):
[ranges.python]
include = ["src/**/*.py", "tests/**/*.py"]
default = true
[[metrics]]
name = "noqa-comments"
type = "regex_count"
pattern = '#\s*noqa'
You can count regex matches, uses of a Python symbol, entries in a TOML or INI list (this is how you count ignored lint rules), files, and lines. See the metric types.
What it does
Three things, in rising order of opinion:
- Measure.
tingle statcounts what you told it to count and prints the numbers. Metric values never affect the exit code — tingle measures, it does not judge. - Attribute.
tingle stat --diffmeasures only what the current branch changed, against the merge-base with a base branch, so commits that landed on the base after you branched don't pollute your numbers. - Judge.
tingle checkis the CI gate: the same branch measurement, but it exits 1 if the branch made things worse, so a pull request that takes on debt fails the build.
$ tingle check
noqa-comment (regex_count): +2
+ src/api/views.py:23
+ src/api/views.py:41
$ echo $?
1
Documentation
- Configuration —
tingle.toml, ranges, groups. - Metric types — what you can count, and the limits of each counter.
- Branch impact — how
--diffattributes changes to your branch. - CI gate — failing the build on new debt.
- History — recording a point per commit and publishing a chart per group, like tingle's own.
- CLI reference — every command and flag.
Development
Python 3.11–3.14 are supported (CI runs the full matrix). The project uses mise + Poetry.
$ mise install
$ poetry install
$ mise run test:py # tests
$ mise run lint:py # ruff, mypy, pylint, import-linter
$ mise run docs:serve # preview the docs site
See contributing for the GLIMPSE source layout and the layer contracts.
License
MIT.
Release files for tingle 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tingle-0.5.0.tar.gz | 67.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tingle-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 153.3 kB
Release files / tingle-0.5.0.tar.gz
| Download URL | tingle-0.5.0.tar.gz |
|---|---|
| Size | 67.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b027f2513f0ee4f54385172290919baea7ecd76a07bc0ffc401cc67ab3d5b74d
|
|
BLAKE2b-256 checksum How to use checksums |
cc3a16b3f11badd5fd925b15c147c93a5d0c3425d71e097c823607a2f714e499
|
| 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 Aug 16, 2026.
Transparency logRelease files / tingle-0.5.0-py3-none-any.whl
| Download URL | tingle-0.5.0-py3-none-any.whl |
|---|---|
| Size | 85.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4d1bbc2bc9fd759dbd5c7809cbed663ab2a1ffc7441fdce4517f99538b7f4496
|
|
BLAKE2b-256 checksum How to use checksums |
9e95191fb19a2beeb6e04f6e2d3b73055de835b0daa0868d756acdface30188d
|
| 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 Aug 16, 2026.
Transparency log