🚫 BadWords
High-performance profanity filter for Python, Rust, and JavaScript (WebAssembly)
with multilingual support and evasion detection.
Installation • Quick Start • Options • Benchmarks • ML scoring • Languages • Evasion Detection • Migration • Documentation
📖 Description
BadWords cleans up user-generated content. Unlike plain keyword matching it normalizes text first — NFKC, case folding, confusable characters, homoglyphs and cyrillic/latin transliteration — and then looks the result up in a dictionary of 20330 entries across 25 languages (16981 of them distinct), with optional fuzzy, phrase and substring matching on top.
Architecture: the engine is Rust. Python gets it through PyO3 with the GIL released around every call, JavaScript through WebAssembly, and Rust projects can depend on the core directly. All three share one set of word lists and one language registry.
📦 Installation
Requirements
- Python: 3.10+
- Rust (if you use the crate): 1.78+
PyPI
pip install badwords-py
From GitHub
pip install git+https://github.com/FlacSy/badwords.git
Cargo / npm
cargo add badwords-core
npm install badwords-wasm
⚡ Quick Start
from badwords import ProfanityFilter
p = ProfanityFilter()
p.init(languages=["en", "ru"]) # or p.init() for all 25
p.is_profane("hello world") # False
p.is_profane("sonofabitch") # True
# Censoring keeps everything that is not part of a match,
# including the punctuation attached to the word.
p.censor("hey shit, ok") # "hey ****, ok"
# find() says what matched, where, and in which language.
for m in p.find("what a shitty, damn mess"):
print(m.matched_text, m.start, m.end, m.word, m.language, m.kind)
Your own words and a whitelist
p.add_words(["spam_link_v1", "scam_bot_99"])
p.add_whitelist(["assessment"]) # never reported, whatever the rules say
p.word_count() # entries in the dictionary
p.contains_word("x") # after normalization
Many texts at once
One call into Rust instead of many, with the GIL released for the whole batch:
p.is_profane_many(["hello", "sonofabitch", "fine"]) # [False, True, False]
p.find_many(texts) # list[list[Match]]
p.censor_many(texts, "*") # list[str]
🎛 Options
Every call takes an Options; without one the filter's default is used. Each field is off by default, because each detector trades false negatives for false positives.
from badwords import Options, ProfanityFilter
p = ProfanityFilter()
p.init(["en"], options=Options(collapse_repeats=True)) # default for this filter
p.is_profane("text", Options(match_threshold=0.9)) # just this call
| Field | Type | Default | What it does |
|---|---|---|---|
match_threshold |
float |
1.0 |
Similarity a fuzzy match needs. 1.0 is exact only. |
match_mode |
"token" / "substring" |
"token" |
Substring also matches entries inside a longer word. |
split_on_punctuation |
bool |
False |
Also test the pieces a token splits into: you.shit. |
collapse_repeats |
bool |
False |
Also test with repeated letters collapsed: shiiit, ffuck. |
leetspeak |
bool |
False |
Read digits as letters: sh1t. |
phrases |
bool |
True |
Match multi-word entries across consecutive words. |
min_substring_len |
int |
6 |
In substring mode, ignore entries shorter than this. |
max_matches |
int / None |
None |
Stop after this many matches. |
Options.aggressive() turns on every detector at threshold 0.9 in substring mode. It is a starting point for measurement, not a recommended default — see the false-positive table below.
Each match is a frozen dataclass:
| Field | Description |
|---|---|
word |
The dictionary entry that matched, as written in the word list. |
matched_text |
The matched slice, always equal to text[start:end]. |
start, end |
Byte offsets into the original text. |
language |
Language the entry came from, or None for words you added. |
score |
Similarity; 1.0 for anything but a fuzzy match. |
kind |
exact, fuzzy, leet, collapsed, substring or phrase. |
🧩 Evasion Detection
Normalization is always on: hеllo with a Cyrillic е, decorative Unicode, diacritics and mixed scripts all fold to the same form before lookup. The rest is opt-in:
from badwords import Options, ProfanityFilter
p = ProfanityFilter()
p.init(["en"])
strict = Options(split_on_punctuation=True, collapse_repeats=True, leetspeak=True)
p.is_profane("shiiit") # False
p.is_profane("shiiit", strict) # True — collapse_repeats
p.is_profane("you.shit", strict) # True — split_on_punctuation
p.is_profane("wh0re", strict) # True — leetspeak
Some leet spellings are in the word lists as literal entries — sh1t and a55
ship in en — so they match without leetspeak at all. The flag is for the
spellings nobody wrote down.
What each detector costs
Measured against 73302 clean words from /usr/share/dict/american-english with all 25 languages loaded. cargo run --release -p badwords-core --bin fp_report --features substring reproduces the table, and tests/false_positives.rs fails the build if the budgets regress.
| Mode | False positives | Rate |
|---|---|---|
| default (exact) | 0 | 0.000% |
split_on_punctuation |
0 | 0.000% |
collapse_repeats |
0 | 0.000% |
leetspeak |
0 | 0.000% |
match_threshold=0.95 |
591 | 0.806% |
match_threshold=0.90 |
5521 | 7.532% |
substring, min_substring_len=6 |
274 | 0.374% |
substring, min_substring_len=7 |
78 | 0.106% |
Options.aggressive() |
5658 | 7.719% |
The three character-level detectors are free of false positives on that corpus; fuzzy matching and substring mode are not. Substring is more expensive here than it will be for most users, because a short entry in one language occurs inside ordinary words of another — with English alone the rate at the default length is 0.150%.
⏱ Benchmarks
| CPU | RAM | OS |
|---|---|---|
| Intel® Core™ i7-10700KF @ 3.80GHz (8C/16T) | 32 GB DDR4 3200MHz | Ubuntu 24.04.2 LTS |
en + ru loaded, default options (exact matching), release builds.
Rust — criterion, make bench-rust:
| Benchmark | Median |
|---|---|
is_profane, clean text |
9.6 µs |
is_profane, text with a match |
1.6 µs |
censor |
3.1 µs |
is_profane_many, 5 texts |
12.6 µs |
find_into, caller-owned scratch |
9.7 µs |
find, substring mode |
5.3 µs |
find, match_threshold=0.9 |
184 µs |
Python — pytest-benchmark medians, make bench-python:
| Benchmark | Median |
|---|---|
is_profane, clean text |
9.0 µs |
is_profane, text with a match |
4.0 µs |
censor |
4.2 µs |
find, clean text |
9.1 µs |
is_profane_many, 5 texts |
15.5 µs |
| the same 5 texts, one call each | 21.2 µs |
is_profane, match_threshold=0.9 |
18.2 µs |
Two things the numbers show. A match is cheaper than clean text, because matching stops at the first hit while clean text is normalized to the end. And the batch API is worth using: five texts in one call cost 15.5 µs against 21.2 µs one at a time, since the GIL is released once instead of five times.
vs glin-profanity
Rule-based mode, en+ru, same texts through each library's own API.
Run: make bench-compare (needs pip install glin-profanity). BadWords is
timed over 50,000 iterations, glin-profanity over 1,000.
| Scenario | BadWords | glin-profanity 3.3.0 |
|---|---|---|
| Clean text (43 chars) | 10.3 µs | 4316 µs |
| Bad word (8 chars) | 3.0 µs | 886 µs |
| Censor | 3.1 µs | 1401 µs |
| 5 texts | 17.8 µs (one batch call) | 9798 µs (five calls) |
Roughly 300–550×, which is what a Rust core buys against a pure-Python one.
ML mode
The optional model is XLM-RoBERTa, INT8-quantized, run through ONNX Runtime — no torch on the inference path. 100 iterations each, same machine.
| Scenario | BadWords ML | glin-profanity (transformer) |
|---|---|---|
| Clean text (43 chars) | 6.8 ms | 27.9 ms |
| Bad word (8 chars) | 5.1 ms | 26.4 ms |
| 5 texts | 12.2 ms (2.4 ms/text, batched) | 130.0 ms |
Cost scales with length, not just count: these are short texts, and a 400-character comment filling the 128-token window costs several times more — the held-out evaluation, on comments up to 400 characters, averages about 48 ms per text. Batch what you can.
Model timings are indicative. Repeated runs on this machine varied by up to 2x with whatever else it was doing, while the ratio to glin's transformer held at roughly 4x across every run. Rule-based numbers are far steadier, within about 15%.
A model call is three orders of magnitude more expensive than a rule call — see ML scoring for what to do about that.
🤖 ML scoring
pip install "badwords-py[ml]" # onnxruntime + transformers, no torch
The rules answer "is this word in the dictionary". The model answers "how toxic is this text, and in what way" — seven independent probabilities, not a single verdict:
from badwords.ml import ToxicityPredictor
predictor = ToxicityPredictor()
scores = predictor.predict_scores("you are a worthless idiot")
scores.toxicity # 0.97
scores["insult"] # 0.92
scores.strongest() # ("toxicity", 0.97)
scores.above(0.5) # [("toxicity", 0.97), ("insult", 0.92)]
scores.as_dict() # every axis
| Axis | What it means |
|---|---|
toxicity |
Overall. This is the axis a single number comes from. |
severe_toxicity |
Toxic enough that annotators agreed strongly. Rare. |
obscene |
Obscene language. |
threat |
A threat of violence. |
insult |
Directed at a person. |
identity_attack |
Aimed at a group or identity. |
sexual_explicit |
Sexually explicit content. |
The axis names come from the model's own config, so a model you train yourself with a different label set stays usable.
Quality
Measured on 10,000 held-out rows — civil_comments and toxic_conversations
test splits, filtered against every row training touched. make ml-evaluate
reproduces it. AUC is threshold-free; "best F1" comes with the threshold that
reaches it, because one threshold does not fit seven axes of very different
rarity.
| Axis | AUC | Average precision | Best F1 | at threshold |
|---|---|---|---|---|
toxicity |
0.977 | 0.978 | 0.923 | 0.20 |
insult |
0.957 | 0.915 | 0.843 | 0.30 |
identity_attack |
0.966 | 0.628 | 0.630 | 0.30 |
sexual_explicit |
0.969 | 0.647 | 0.619 | 0.30 |
threat |
0.972 | 0.531 | 0.571 | 0.30 |
obscene |
0.955 | 0.596 | 0.570 | 0.40 |
severe_toxicity |
— | — | — | — |
Measured on the INT8 model, the one the release ships: quantizing costs about 0.3 points of AUC against fp32.
Read AUC and average precision together. Every axis ranks well, but the rare
ones — threat is 1% of rows — have far lower average precision, which is
what you feel in practice: at a useful precision their recall is modest. Treat
toxicity as the axis to decide on and the narrow ones as the reason to show
("blocked, reads as a threat"), not as triggers of their own.
severe_toxicity has no row in the test set where a majority of annotators
agreed, so there is nothing to score it against at all.
The narrow axes are supervised by English civil_comments alone; overall
toxicity is supervised by every source. Rebalancing the training mix towards
Russian lifted toxicity (0.906 → 0.923 F1) and cost the narrow axes several
points — English rows in the mix were halved to make room.
Quality in Russian
English and Russian are measured separately, because they behave differently.
1000 rows each: the English ones from the held-out split above, the Russian
ones from AlexSham/Toxic_Russian_Comments.
| English | Russian | |
|---|---|---|
| AUC | 0.971 | 0.997 |
| Best F1 | 0.900 @0.25 | 0.976 @0.15 |
| At the 0.3 default (P / R / F1) | 0.931 / 0.865 / 0.897 | 0.978 / 0.968 / 0.973 |
| Rules alone (P / R / F1) | 0.873 / 0.274 / 0.417 | 0.969 / 0.502 / 0.661 |
Two things are worth reading off this. The rules behave differently per language — 50% recall in Russian against 27% in English, because Russian profanity is lexical and a dictionary catches it, while English toxicity is more often built from ordinary words. And the model's thresholds now sit close together (0.25 and 0.15), which one default can serve; an earlier English-heavy training mix put them at 0.30 and 0.70, and no single default could.
The Russian figure is in-domain: the model trained on other rows of that same corpus. Read it as "good on Russian of this kind", not as a cross-corpus guarantee.
Neither half replaces the other. The dictionary cannot see toxicity built out
of ordinary words, which is most of it in English; the model has no notion of
the project-specific words you add to the dictionary yourself, and no interest
in matching them exactly. That is what HybridFilter is for.
Rules first, model second
from badwords.ml import HybridFilter
hybrid = HybridFilter(languages=["en", "ru"])
result = hybrid.check("you are a worthless waste of oxygen")
result.is_profane # True
result.decided_by # "model" — no dictionary entry to go on
result.scores # every axis
result.rule_score # what the rules made of it
A certain dictionary hit answers immediately and never reaches the model; everything else does, text the rules found nothing in included. Treating "the rules saw nothing" as "clean" is what makes a hybrid score worse than the model it wraps.
The model is downloaded on first use, not on construction — download_model()
warms the cache deliberately, and BADWORDS_ML_PATH points at your own.
From Rust
[dependencies]
badwords-ml = "3"
use badwords_ml::ToxicityModel;
let model = ToxicityModel::open_located()?; // BADWORDS_ML_PATH or the shared cache
let scores = model.predict("you are an idiot")?;
scores.toxicity(); // 0.94
scores.get("insult"); // Some(0.93)
scores.above(0.5); // [("toxicity", 0.94), ("insult", 0.93)]
HybridFilter is there too, with the same semantics as the Python one. The
crate reads the same model directory the Python package downloads, so the two
languages score identically — the only difference is batch padding, worth a few
hundredths on an INT8 model.
Requires Rust 1.88 (ort's own minimum); badwords-core still builds on 1.78.
🌍 Supported Languages
25 languages, keyed by ISO 639-1 where one exists. Entry counts as shipped:
| Code | Language | Entries | Code | Language | Entries |
|---|---|---|---|---|---|
pl |
Polish | 6974 | id |
Indonesian | 236 |
ru |
Russian | 3905 | cs |
Czech | 217 |
uk |
Ukrainian | 2109 | da |
Danish | 207 |
tr |
Turkish | 1031 | es_419 |
Spanish (Latin America) | 184 |
en |
English | 796 | sv |
Swedish | 181 |
el |
Greek | 591 | th |
Thai | 172 |
es |
Spanish | 584 | ro |
Romanian | 145 |
it |
Italian | 409 | pt_br |
Portuguese (Brazil) | 121 |
nl |
Dutch | 342 | no |
Norwegian | 92 |
ko |
Korean | 341 | fi |
Finnish | 303 |
fr |
French | 295 | ja |
Japanese | 290 |
hu |
Hungarian | 286 | pt |
Portuguese | 271 |
de |
German | 248 |
p.available_languages() # every language that could be loaded
p.loaded_languages() # the ones actually loaded, as canonical codes
p.load_languages(["de"]) # add to what is already loaded
p.unload_languages(["de"])
Pre-3.0 codes
The old codes still work as aliases: cz→cs, du→nl, gr→el, po→pt, sp→es, tu→tr, ua→uk.
Four of them collide with a real ISO 639-1 language and emit a DeprecationWarning:
| Old | Now | Why |
|---|---|---|
br |
pt_br |
br is Breton in ISO; this list is Brazilian Portuguese. |
in |
id |
in is a retired code for Indonesian. |
lt |
es_419 |
lt is Lithuanian in ISO; this list is Latin-American Spanish. |
sw |
sv |
sw is Swahili in ISO; this list is Swedish. |
🚀 Full Integration Example
from badwords import Options, ProfanityFilter
MODERATION = Options(
split_on_punctuation=True,
collapse_repeats=True,
leetspeak=True,
)
def monitor_chat() -> None:
p = ProfanityFilter()
p.init(["en", "ru", "de"], options=MODERATION)
# Project-specific words, and words that must never be flagged.
p.add_words(["spam_link_v1", "scam_bot_99"])
p.add_whitelist(["assessment"])
user_input = "Hey! Check out this cr4p"
matches = p.find(user_input)
if matches:
reason = ", ".join(f"{m.word} ({m.kind})" for m in matches)
print(f"Message blocked: {reason}")
print("Shown instead:", p.censor(user_input))
else:
print("Message accepted")
if __name__ == "__main__":
monitor_chat()
🦀 Rust API (badwords-core)
Published on crates.io:
[dependencies]
badwords-core = "3"
use badwords_core::{Options, ProfanityFilter};
let mut filter = ProfanityFilter::builder()
.embedded() // word lists compiled into the crate
.languages(["en", "ru"]) // or .all_languages()
.build()?;
let opts = Options::new();
filter.is_profane("hello world", opts); // false
filter.censor("hey shit, ok", '*', opts); // "hey ****, ok"
for m in filter.find("what a shitty, damn mess", opts) {
println!("{:?} at {}..{} ({:?})", m.matched_text, m.start, m.end, m.kind);
}
filter.add_words(&["custombad"]);
filter.add_whitelist(&["assessment"]);
find_first short-circuits on the first match, and find_into reuses caller-owned Scratch and output buffers so a hot loop allocates nothing.
Crate features
| Feature | Default | What it adds |
|---|---|---|
fs-resources |
✅ | Load word lists from a directory at runtime. |
embedded-data |
✅ | Normalization tables and the language registry compiled in. |
embedded-words |
✅ | Every word list compiled in (~250 KB). |
embedded-words-min |
English and Russian only (~82 KB), for WebAssembly. | |
substring |
MatchMode::Substring via Aho-Corasick. |
Examples: cargo run --example rust_basic, rust_chat_moderation, rust_specific_languages.
🌐 WebAssembly (JavaScript / TypeScript)
The same Rust code compiled for the browser and Node.js, with English and Russian built in.
npm install badwords-wasm
import init, { ProfanityFilter } from 'badwords-wasm';
await init(); // browser build only
const filter = new ProfanityFilter();
filter.isProfane('hello'); // false
filter.censor('hey shit, ok', '*'); // "hey ****, ok"
filter.find('what a shitty mess'); // [{ word, matchedText, start, end, language, score, kind }]
filter.addWords(['spam_link']);
filter.addWhitelist(['assessment']);
Options are a plain object, reusable and checked — an unknown key is an error rather than a silently disabled detector:
filter.isProfane('sh1t', { leetspeak: true, collapseRepeats: true });
filter.setOptions({ matchThreshold: 0.9 }); // default for later calls
Match and MatchOptions are real TypeScript interfaces in the generated .d.ts. filterText, isBad and getLanguages still work and are marked @deprecated.
Optional languages (npm)
npm install badwords-wasm @badwords/languages
import de from '@badwords/languages/de';
import uk from '@badwords/languages/uk';
filter.addWords(de);
filter.addWords(uk);
Available: cs, da, de, el, en, es, es_419, fi, fr, hu, id, it, ja, ko, nl, no, pl, pt, pt_br, ro, ru, sv, th, tr, uk, plus the pre-3.0 codes as aliases. See @badwords/languages.
Build from source
cargo install wasm-pack
make wasm # browser -> rust/badwords-wasm/pkg-web/
make wasm-nodejs # Node.js -> rust/badwords-wasm/pkg-node/
Examples: examples/wasm/browser/, examples/wasm/node/ (JavaScript and TypeScript).
🔀 Migrating from 2.x
Everything from 2.x still works and still behaves identically — the deprecated paths are checked against 8736 recorded 2.3.1 responses. They warn, so the move can be gradual.
| 2.x | 3.0 |
|---|---|
p.filter_text(text) |
p.is_profane(text) |
p.filter_text(text, replace_character="*") |
p.censor(text, "*") |
p.filter_text(text, match_threshold=0.95) |
p.is_profane(text, Options(match_threshold=0.95)) |
p.get_all_languages() |
p.loaded_languages() / p.available_languages() |
ProfanityFilter::new(dir, ..) (Rust) |
ProfanityFilter::builder()…build()? |
filter.isBad(text) (JS) |
filter.isProfane(text) |
Two behaviour changes worth knowing about:
- Censoring keeps punctuation.
censor("hey shit, ok")returns"hey ****, ok"; 2.x returned"hey ***** ok"because it replaced the whole whitespace-delimited token.filter_textkeeps the old behaviour. - Multi-word entries match now. They could not before, so phrases in the shipped lists never fired. Phrase matching needs two or more consecutive words, so it cannot produce a single-word false positive; turn it off with
Options(phrases=False).
🔧 Building from source
Requires Rust, Python and maturin.
python -m venv .venv && source .venv/bin/activate
pip install maturin
make develop # debug build, installed into the venv
make test # rust + python + wasm
make bench # criterion + pytest-benchmark
make develop mirrors rust/badwords-core/resources/ into python/badwords/resource/ first; make check-resources verifies the mirror, and CI fails if it drifts.
📚 Documentation
Full documentation (Python, Rust, JavaScript) with examples and API reference: badwords.flacsy.dev (EN / RU).
🤝 Contributing
See CONTRIBUTING.md. Word-list changes have their own checklist there — every entry needs a source, and the false-positive budget is enforced by CI.
📄 License
Distributed under the MIT License. See LICENSE for more information.
Word lists incorporate material from LDNOOBW (CC BY 4.0) and washyourmouthoutwithsoap (MIT); see NOTICE and rust/badwords-core/resources/words/SOURCES.md.
Metadata
Release files for badwords-py 3.0.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 | |
|---|---|---|---|
| badwords_py-3.0.0.tar.gz | 227.4 kB | Details |
Built distributions (wheels)
Total release size: 20.2 MB
Release files / badwords_py-3.0.0.tar.gz
| Download URL | badwords_py-3.0.0.tar.gz |
|---|---|
| Size | 227.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
77b2f3e65cf31e8edeccd50780c56fce04e19bd0a9d95ce3d0b502b6ae12487e
|
|
BLAKE2b-256 checksum How to use checksums |
a9e6b9a182ac03d0982640f156482e34d07c5ca0ade4f1f9a3f3116033c50119
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / badwords_py-3.0.0-cp313-cp313-win_amd64.whl
| Download URL | badwords_py-3.0.0-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 686.6 kB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
6aa7418c00bae6053be1ec975536fdd948fd2f84c1e206055e03618019c130b8
|
|
BLAKE2b-256 checksum How to use checksums |
4cd34c1e1443d24d7ac9fa42fb8e9471b3464002ca3fc05e6ea8219dd1ba4a7a
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl
| Download URL | badwords_py-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.13 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
51bcb1012f63f42fdb38e021842c02018bb75294b9e13ea8115b31b3793713d8
|
|
BLAKE2b-256 checksum How to use checksums |
c3d0e56894958e9d05b5af7d20423b42f7b1e4b3be0b397420bf991f6e6bbda1
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | badwords_py-3.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 859.2 kB |
| Tags | CPython 3.13 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
584e4aaf8d4a77f3b19141e22d59d510f8a348f6401601a818f38a7007a2f779
|
|
BLAKE2b-256 checksum How to use checksums |
50b483f9f19bcd8171f2c30db0a9a9509bbeda834aff707ba4239b5596f8f8fe
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | badwords_py-3.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 815.0 kB |
| Tags | CPython 3.13 Linux glibc 2.17+ ARM64 |
|
SHA-256 checksum How to use checksums |
fcccd04089edaea0cf43d709f67362b9fcf28264d5377795b95ebeb745b26627
|
|
BLAKE2b-256 checksum How to use checksums |
136a6a94a71008338394551d62e5395d5184bf3f3f420c252adcb9d44f9dbd34
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp313-cp313-macosx_11_0_arm64.whl
| Download URL | badwords_py-3.0.0-cp313-cp313-macosx_11_0_arm64.whl |
|---|---|
| Size | 759.0 kB |
| Tags | CPython 3.13 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
410a3e010b2e69b7fa7f14586e2456602d59da83fce24cc38f52e85a8969ee3d
|
|
BLAKE2b-256 checksum How to use checksums |
5173ee79803f49fd689403c59563e6ec4346fb1a4f9ec4f72fba8ded25e2dc04
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp313-cp313-macosx_10_12_x86_64.whl
| Download URL | badwords_py-3.0.0-cp313-cp313-macosx_10_12_x86_64.whl |
|---|---|
| Size | 797.3 kB |
| Tags | CPython 3.13 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
62cfc1c29df02fe1fce0bb665432021916afc3cd2cd75c4e295cb162732cb13d
|
|
BLAKE2b-256 checksum How to use checksums |
cdb8b31fa47f8d0c33bb8cfa3f7f53f1d7c91bbe87e6fb208244658ca8442377
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp312-cp312-win_amd64.whl
| Download URL | badwords_py-3.0.0-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 687.0 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
2586298d445463fdd6486567c9ba2fbe2b7fdf25ce457a0b601c301384740b8a
|
|
BLAKE2b-256 checksum How to use checksums |
ff5f37ff335676ddf9568329272094cf2bfcfcf6712c2924038f0b678411f926
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl
| Download URL | badwords_py-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
cb6d23eb4d46ac1bbff80651d7f3aba32f6f33d12b634d26ac3d5b3c59321d77
|
|
BLAKE2b-256 checksum How to use checksums |
76c23efd0fa29f4f0df578d0a78b7dde1c323a9b0146c9c7ba450bb172e7e242
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | badwords_py-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 859.7 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
52002884179429e616cad304cc79f0f8909560bc50d794afa756bec95d26db5e
|
|
BLAKE2b-256 checksum How to use checksums |
93ac71bed1ee6f5560890be9cd5e1cdd000d4babdddf69ac142474aad7a1ab41
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | badwords_py-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 815.3 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 |
|
SHA-256 checksum How to use checksums |
9f0bcf07b26801d5105a6fecccb488759e8c7b9ba0ff08ebfd103b52c4ff49f0
|
|
BLAKE2b-256 checksum How to use checksums |
03ddfe9200b0fc081e57f10d8b38f68290c517de7425d32da9c64decdb0017a0
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp312-cp312-macosx_11_0_arm64.whl
| Download URL | badwords_py-3.0.0-cp312-cp312-macosx_11_0_arm64.whl |
|---|---|
| Size | 759.4 kB |
| Tags | CPython 3.12 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
d7244849bce8853157c28c18f94dcda1e0fc14e27da7e83890d6f847c68d0286
|
|
BLAKE2b-256 checksum How to use checksums |
947dce73dd2a5cc205315e23e4141ce4928b916f23ecea68a3ca4f635f2aa570
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl
| Download URL | badwords_py-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl |
|---|---|
| Size | 798.0 kB |
| Tags | CPython 3.12 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
2a083e35829755e7fa829582d365f910ead8e5a433e9ab997b3161fca03c13ce
|
|
BLAKE2b-256 checksum How to use checksums |
037329b7461d1fa6420fed311fbce1841c3c3e6dd87f16c0155b2b2e6a89346a
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp311-cp311-win_amd64.whl
| Download URL | badwords_py-3.0.0-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 687.1 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
97630170eb7a3c65979ddb18644b878fa198f489ace95e87eb19e6efd421faeb
|
|
BLAKE2b-256 checksum How to use checksums |
b037273d8e22fab078c6f162b707a8bcf463031800ed2192135ff1413149fe53
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl
| Download URL | badwords_py-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.11 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
7d7a7f1e039f7b3e8e25dba765479466ea9e67e3a7cdff0fa7363b8cb4077af7
|
|
BLAKE2b-256 checksum How to use checksums |
507bf3f44ef5d306a4adea26d7ac7f324aecbf013542a29c3c3dcdf8156f83bd
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | badwords_py-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 859.0 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
29677cb44065afdb97a5b1ab780b170e8404366a5f889fd553e0bce08a2fadda
|
|
BLAKE2b-256 checksum How to use checksums |
334508710231960a8ad22c92fef569336835b8cf923ee1f3dd11d14faa24c145
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | badwords_py-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 815.8 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ ARM64 |
|
SHA-256 checksum How to use checksums |
bf06eaf05cb4d733cb35123aef22f8b3535dae6c9bb54e00895ad50d28c0c047
|
|
BLAKE2b-256 checksum How to use checksums |
cc8a214ac5831187c033f85c733f04d3096e31bb0cca005c6b97f35adb876404
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | badwords_py-3.0.0-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 759.3 kB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
10e01b4aff837c96b6e702282bf97ec8da21f5e628f57641d058bd2709c7e349
|
|
BLAKE2b-256 checksum How to use checksums |
9e31c0bd5c0291d1268313b382e3b85351f710c7e965aea41e27bdbb9fd06c44
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl
| Download URL | badwords_py-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl |
|---|---|
| Size | 798.6 kB |
| Tags | CPython 3.11 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
3692abffce691acffb396681b6c59f9dc4cf2e98dd3c6943a0cea044760787fd
|
|
BLAKE2b-256 checksum How to use checksums |
ada81a66c5345ff2613a6e7b92930390fcff1dfc1edcfed9e2af209c6e135b6f
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp310-cp310-win_amd64.whl
| Download URL | badwords_py-3.0.0-cp310-cp310-win_amd64.whl |
|---|---|
| Size | 687.0 kB |
| Tags | CPython 3.10 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
05377ce2f8e19935a08b1951ebd9097d9a31f5d2d0dc68f328b2e4c793557d35
|
|
BLAKE2b-256 checksum How to use checksums |
4ead30112c9d47257133ee6377af80628a386d4b4929384ffa3c45ae8b6319ce
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp310-cp310-musllinux_1_2_x86_64.whl
| Download URL | badwords_py-3.0.0-cp310-cp310-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 |
|
SHA-256 checksum How to use checksums |
b642bd4608829d194d13162ff61087434a22e9bdb55855bdc14628d895c2dc02
|
|
BLAKE2b-256 checksum How to use checksums |
38cf9d5f202e47be15de922bfd5d736b6bcff0fcde46a82d88c5727461812476
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | badwords_py-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 859.1 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
d36ccae6fb8aef9ddfc912298e0db0fa9d9b8796bebdc69f603c5539c55702cd
|
|
BLAKE2b-256 checksum How to use checksums |
1b1d2bbd9bf2e6af7efee35f65e8d66f9b62e5bfb9bb110c9e5d084f51d14e71
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | badwords_py-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 816.0 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 |
|
SHA-256 checksum How to use checksums |
fa9efd78ff7332955d904508a013d8a91609a871706ebbf058233176b11c58c9
|
|
BLAKE2b-256 checksum How to use checksums |
d493f06a008a7e88e5c2122ca01ca3210672ec5d6ed23237b23aa8681824fbb9
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp310-cp310-macosx_11_0_arm64.whl
| Download URL | badwords_py-3.0.0-cp310-cp310-macosx_11_0_arm64.whl |
|---|---|
| Size | 759.7 kB |
| Tags | CPython 3.10 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
7aefa344fe58d0111abc180ee968990f15ac4dd9f5b78a1a01d3016e5a693a31
|
|
BLAKE2b-256 checksum How to use checksums |
cd5fe1d61890a9930f49548d37323b2f06a88ee5035c779d320c4aa7c35df8bb
|
| 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 4, 2026.
Transparency logRelease files / badwords_py-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl
| Download URL | badwords_py-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl |
|---|---|
| Size | 797.9 kB |
| Tags | CPython 3.10 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
c9f8e9772f44e0cea80eb1ffa49a8f2a53216de543c78a2f4d5a5f51ae862052
|
|
BLAKE2b-256 checksum How to use checksums |
6fd50f53d4eed513e64dcdde01ba791bbc3008e1cd8e3a1c732c276d23a7d570
|
| 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 4, 2026.
Transparency log