Streaming library for disinformation detection in multilingual text streams
Project description
disinfolib
Потокова Python-бібліотека для виявлення й моніторингу дезінформації у багатомовних текстових потоках.
from disinfolib import TextAnalyzer
analyzer = TextAnalyzer()
result = analyzer.analyze("Вороги знищать усіх! Небезпека для кожного!")
print(result.score) # 0.72
print(result.is_disinformation) # True
print(result.technique_names) # ["appeal_to_fear", "loaded_language"]
Зміст
- Навіщо бібліотека, а не сервер
- Як встановити
- Quickstart
- Аналіз одного тексту
- Потоковий моніторинг
- Джерела даних
- Збереження результатів
- Моніторинг та алерти
- Prometheus-метрики
- Конфігурація
- Підтримувані мови та техніки
- Власні детектори та джерела
- Системні вимоги
- Приклади
Навіщо бібліотека, а не сервер
Більшість інструментів аналізу тексту — це окремі HTTP-сервіси. Вони вимагають розгортання, підтримки, мережі між вашим кодом і сервісом. disinfolib — це бібліотека: ви просто викликаєте функцію Python.
| Аспект | Окремий сервер | disinfolib (бібліотека) |
|---|---|---|
| Запуск | python server.py + curl |
import disinfolib |
| Інтеграція | HTTP-запити з обробкою помилок | Виклик методу Python |
| Затримка | Мережа + HTTP overhead | Пряма функція (~мс) |
| Розгортання | Docker/Kubernetes | pip install disinfolib |
| Масштабування | Окремий сервер | У вашому процесі |
| Залежності | Запущений сервер | Тільки pip-пакети |
Якщо вам все ж потрібен HTTP API — examples/rest_api_server.py показує як обернути бібліотеку у FastAPI за ~100 рядків коду.
Як встановити
Крок 1. Переконайтеся що Python встановлено
Відкрийте термінал (cmd або PowerShell на Windows, Terminal на macOS/Linux) і виконайте:
python --version
Має вивести Python 3.11.x або вище. Якщо Python не встановлено — завантажте з python.org.
Крок 2. Створіть віртуальне середовище (рекомендовано)
Що таке віртуальне середовище? Це ізольована папка де встановлюються пакети для вашого проекту — вони не конфліктують з системними пакетами.
# Створити середовище (виконати один раз)
python -m venv venv
# Активувати (Windows)
venv\Scripts\activate
# Активувати (macOS/Linux)
source venv/bin/activate
Після активації ви побачите (venv) перед рядком введення — це означає що середовище активне.
Крок 3. Встановіть бібліотеку
З публічного PyPI:
# Базовий — rule-based детектор, без ML
pip install disinfolib
# З RSS-підтримкою
pip install "disinfolib[rss]"
# З ML-детектором (завантажує PyTorch + mDeBERTa ~2-3 ГБ)
pip install "disinfolib[ml]"
# З Telegram
pip install "disinfolib[telegram]"
# Все разом
pip install "disinfolib[all]"
З приватного репозиторію GitHub:
Якщо бібліотека розповсюджується через приватний GitHub-репозиторій, pip встановлює її безпосередньо з Git. Для доступу потрібен персональний токен (PAT).
# Базове
pip install "git+https://ВАШ_ТОКЕН@github.com/SKPdeveloper/disinfolib.git"
# З ML-детектором
pip install "disinfolib[ml] @ git+https://ВАШ_ТОКЕН@github.com/SKPdeveloper/disinfolib.git"
# Конкретна версія
pip install "git+https://ВАШ_ТОКЕН@github.com/SKPdeveloper/disinfolib.git@v1.0.0"
Щоб не зберігати токен у коді — використовуйте змінну середовища:
# Зберегти токен (один раз)
export GITHUB_TOKEN=ВАШ_ТОКЕН # macOS/Linux
$env:GITHUB_TOKEN = "ВАШ_ТОКЕН" # Windows PowerShell
# Встановити
pip install "git+https://$GITHUB_TOKEN@github.com/SKPdeveloper/disinfolib.git"
Перевірка встановлення
python -c "import disinfolib; print(disinfolib.__version__)"
Має вивести: 1.0.0
Перевірте які детектори доступні:
python -c "from disinfolib import TextAnalyzer; a = TextAnalyzer(); print(a.detector_names)"
Якщо встановлено тільки базову версію — виведе ['rule_based'].
Якщо встановлено з [ml] — виведе ['rule_based', 'ml'].
Quickstart
Мінімальний приклад — скопіюйте в будь-який .py файл:
from disinfolib import TextAnalyzer
# Створюємо аналізатор
analyzer = TextAnalyzer()
# Аналізуємо текст
result = analyzer.analyze("Вороги знищать усіх! Небезпека для кожного!")
# Результат
print(f"Score: {result.score:.2f}")
print(f"Дезінформація: {result.is_disinformation}")
print(f"Мова: {result.language}")
print(f"Техніки: {result.technique_names}")
Запустіть:
python my_script.py
Очікуваний вивід:
Score: 0.72
Дезінформація: True
Мова: uk
Техніки: ['appeal_to_fear', 'loaded_language']
Аналіз одного тексту
Базовий аналіз
from disinfolib import TextAnalyzer
analyzer = TextAnalyzer()
result = analyzer.analyze("Текст для аналізу")
Що повертає result
| Поле | Тип | Опис | Приклад |
|---|---|---|---|
result.score |
float |
Оцінка від 0.0 до 1.0 | 0.72 |
result.is_disinformation |
bool |
True якщо score >= threshold | True |
result.language |
str |
Виявлена мова (ISO 639-1) | "uk" |
result.techniques |
List |
Техніки пропаганди | [PropagandaTechnique.APPEAL_TO_FEAR] |
result.technique_names |
List[str] |
Назви технік | ["appeal_to_fear"] |
result.found_markers |
List[str] |
Знайдені маркери | ["небезпека", "загроза"] |
result.confidence |
float |
Впевненість (0.0–1.0) | 0.68 |
result.detector_scores |
Dict |
Score кожного детектора | {"rule_based": 0.85} |
Вказати мову явно
# Якщо мова відома заздалегідь — зазначте її для швидшого і точнішого аналізу
result = analyzer.analyze(text, language="uk")
Аналіз кількох текстів
texts = [
"Перший текст для аналізу",
"Другий текст — зовсім інший",
"Вороги знищать усіх!",
]
results = analyzer.analyze_batch(texts)
for text, result in zip(texts, results):
print(f"[{result.score:.2f}] {text[:40]}")
Порогове значення
За замовчуванням threshold = 0.35. Тексти з score >= 0.35 вважаються дезінформацією.
from disinfolib import TextAnalyzer, DisinfoConfig
# Підвищений поріг — менше спрацьовувань
config = DisinfoConfig(threshold=0.50)
analyzer = TextAnalyzer(config=config)
Коли підвищувати поріг? Якщо отримуєте забагато хибних спрацьовувань (нейтральні тексти класифікуються як дезінформація).
Коли знижувати поріг? Якщо хочете виявляти навіть слабко маніпулятивні тексти.
Потоковий моніторинг
DisinfoBroker — основний клас для роботи з потоками даних. Ви підключаєте джерела, і він безперервно аналізує всі вхідні повідомлення.
Синхронний потік
from disinfolib import DisinfoBroker
broker = DisinfoBroker()
broker.add_source("rss", urls=[
"https://www.pravda.com.ua/rss/",
"https://rss.unian.net/site/news_ukr.rss",
])
# Ітеруємо по результатам аналізу
for event in broker.stream():
if event.is_disinformation:
print(f"[{event.score:.2f}] {event.title}")
print(f" Джерело: {event.source_name}")
print(f" URL: {event.url}")
broker.stream() — це Python-генератор. Він блокує виконання і повертає один результат за раз.
Підписки на події
Замість того щоб перебирати результати у циклі, можна підписатися на конкретні події:
broker = DisinfoBroker()
broker.add_source("rss", urls=["https://example.com/rss"])
@broker.on("detection") # Тільки коли виявлено дезінформацію
def on_detect(event):
send_telegram_alert(event.title, event.score)
@broker.on("result") # Кожне повідомлення (незалежно від результату)
def on_all(event):
log_to_file(event)
@broker.on("error") # Помилки (неробочий URL, тощо)
def on_error(exc):
print(f"Помилка: {exc}")
broker.start() # Запускає обробку у фоновому потоці
broker.wait() # Чекає до завершення (або Ctrl+C)
Асинхронний потік (для FastAPI, aiohttp тощо)
import asyncio
from disinfolib import DisinfoBroker
async def monitor():
broker = DisinfoBroker()
broker.add_source("rss", urls=["https://example.com/rss"])
async for event in broker.astream():
if event.is_disinformation:
await send_notification(event)
asyncio.run(monitor())
Джерела даних
RSS / Atom стрічки
from disinfolib import RSSSource
# Одноразовий прохід (one_shot=True)
source = RSSSource(
urls=["https://example.com/rss"],
one_shot=True, # Прочитати і зупинитися
language_hint="uk", # Підказка мови, якщо всі статті однією мовою
)
# Постійний моніторинг (polling кожні 5 хвилин)
source = RSSSource(
urls=["https://example.com/rss"],
one_shot=False,
poll_interval=300, # секунди
)
broker.add_source(source)
# Або коротко:
broker.add_source("rss", urls=["https://example.com/rss"])
Що вміє RSSSource:
- Автоматично прибирає HTML-теги з контенту
- Дедублікує записи (SHA-256 хеш від url+title+content)
- Підтримує RSS 2.0 та Atom
Файлові джерела (для тестування та replay)
from disinfolib import FileSource
# JSONL файл (один JSON-об'єкт на рядок)
broker.add_source(FileSource("data/messages.jsonl"))
# CSV файл
broker.add_source(FileSource("data/news.csv"))
# Зі списку записів у пам'яті
records = [
{"id": "1", "text": "Перший текст", "language": "uk"},
{"id": "2", "text": "Другий текст", "language": "uk"},
]
broker.add_source(FileSource.from_records(records, source_id="my_data"))
# Нескінченний repeat (для тестів навантаження)
broker.add_source(FileSource.from_records(records, repeat=True))
Підтримувані формати: .jsonl, .json, .csv, .txt, .zip (архів із підтримуваними файлами)
Telegram
# Потрібно: pip install "disinfolib[telegram]"
from disinfolib import TelegramSource
source = TelegramSource(
api_id=12345678, # З my.telegram.org
api_hash="abc123...", # З my.telegram.org
channels=["@channel1", "@channel2"],
mode="realtime", # або "history" для читання архіву
)
broker.add_source(source)
Apache Kafka
# Потрібно: pip install "disinfolib[kafka]"
from disinfolib import KafkaSource
source = KafkaSource(
bootstrap_servers=["localhost:9092"],
topics=["news.raw", "social.posts"],
group_id="disinfolib",
)
broker.add_source(source)
Кілька джерел одночасно
broker = DisinfoBroker()
broker.add_source("rss", urls=["https://pravda.com.ua/rss/"])
broker.add_source("rss", urls=["https://unian.net/rss/"])
broker.add_source(FileSource("historical_data.jsonl"))
# Всі джерела працюють паралельно
for event in broker.stream():
print(f"[{event.source_name}] {event.title}")
Збереження результатів
SQLite (рекомендовано)
from disinfolib import DisinfoBroker, SQLiteStorage
broker = DisinfoBroker()
broker.add_source("rss", urls=["https://example.com/rss"])
broker.add_storage(SQLiteStorage("results.db"))
for event in broker.stream():
pass # Результати автоматично записуються в БД
Чому SQLite, а не PostgreSQL? SQLite — це файл, не потрібен окремий сервер. Для більшості задач аналізу новин достатньо. Для великих навантажень (>100 записів/сек) — реалізуйте власний BaseStorage з PostgreSQL.
Що зберігається: message_id, collected_at, source_id, source_name, title, url, score, is_disinformation, techniques (JSON), found_markers (JSON), language, text (перші 500 символів).
# Запити до БД
storage = SQLiteStorage("results.db")
# Кількість записів
print(storage.count())
# Останні 20 результатів
rows = storage.query(limit=20)
# Тільки дезінформація
rows = storage.query(only_disinformation=True)
# Статистика
stats = storage.stats()
print(stats["disinformation_rate"]) # 0.142
print(stats["by_source"]) # {"rss_pravda": {...}}
CSV
from disinfolib import CSVStorage
# Файл відкривається у режимі append — нові рядки додаються
storage = CSVStorage("results.csv")
broker.add_storage(storage)
Файл зберігається в кодуванні UTF-8 з BOM — Excel відкриває правильно без проблем з кирилицею.
У пам'яті (для тестів)
from disinfolib import InMemoryStorage
storage = InMemoryStorage(max_size=1000) # Зберігає останні 1000 записів
broker.add_storage(storage)
# Після обробки
print(storage.count())
print(storage.disinformation_rate)
results = storage.results # List[StreamResult]
Моніторинг та алерти
Статистика потоку
from disinfolib import StatsTracker
tracker = StatsTracker()
broker.add_monitor(tracker)
# Після обробки кількох повідомлень:
stats = tracker.get_stats()
print(f"Оброблено: {stats.total_processed}")
print(f"Виявлено дезінформації: {stats.disinformation_count}")
print(f"Частка: {stats.disinformation_rate:.1%}")
print(f"Середній score: {stats.avg_score:.2f}")
# По джерелах
for source, data in stats.by_source.items():
print(f" {source}: {data['total']} повідомлень, rate={data['rate']:.2%}")
# По техніках
for technique, count in sorted(stats.by_technique.items(), key=lambda x: -x[1]):
print(f" {technique}: {count}")
Алерти при перевищенні порогів
from disinfolib import AlertManager, AlertRule
manager = AlertManager(check_every=10) # Перевіряти кожні 10 повідомлень
# Правило: більше 30% дезінформації
manager.add_rule(AlertRule(
name="high_rate",
condition=lambda stats: stats.disinformation_rate > 0.30,
handler=lambda alert: print(f"УВАГА: {alert.message}"),
severity="warning",
cooldown=600.0, # Не спрацьовувати частіше ніж раз на 10 хв
message="Частка дезінформації перевищила 30%",
))
# Правило з динамічним повідомленням
manager.add_rule(AlertRule(
name="critical_rate",
condition=lambda stats: stats.disinformation_rate > 0.60,
handler=lambda alert: send_telegram(f"Критично: {alert.message}"),
severity="critical",
cooldown=300.0,
message=lambda stats: f"Критична частка: {stats.disinformation_rate:.1%} (з {stats.total_processed} повідомлень)",
))
broker.add_monitor(manager)
# Після роботи
for alert in manager.history:
print(f"[{alert.severity}] {alert.rule_name}: {alert.message}")
Prometheus-метрики
from disinfolib import DisinfoMetrics
metrics = DisinfoMetrics()
broker.add_monitor(metrics)
# Отримати текст у форматі Prometheus:
print(metrics.to_prometheus_text())
Приклад виводу:
# HELP disinfolib_messages_processed_total Total messages processed by disinfolib
# TYPE disinfolib_messages_processed_total counter
disinfolib_messages_processed_total 1500.0
# HELP disinfolib_disinformation_detected_total Total messages classified as disinformation
# TYPE disinfolib_disinformation_detected_total counter
disinfolib_disinformation_detected_total 213.0
# TYPE disinfolib_disinformation_rate gauge
disinfolib_disinformation_rate 0.142
disinfolib_messages_by_source_total{source="rss_pravda"} 800
disinfolib_messages_by_source_total{source="rss_unian"} 700
Інтеграція з FastAPI
from fastapi import FastAPI, Response
from disinfolib import DisinfoMetrics
metrics = DisinfoMetrics()
app = FastAPI()
@app.get("/metrics")
def get_metrics():
return Response(
content=metrics.to_prometheus_text(),
media_type="text/plain; version=0.0.4",
)
Конфігурація
Через код
from disinfolib import DisinfoConfig, TextAnalyzer
config = DisinfoConfig(
threshold=0.35, # Поріг класифікації (за замовч. 0.35)
languages=["uk", "ru", "en"], # Підтримувані мови
auto_detect_language=True, # Автодетекція через langdetect
detectors=["rule_based", "ml", "ai"], # За замовч. всі три активні
stream_buffer_size=100, # Розмір черги між джерелами та аналізатором
log_level="WARNING", # "DEBUG", "INFO", "WARNING", "ERROR"
)
analyzer = TextAnalyzer(config=config)
Детектори: як вони працюють разом
За замовчуванням увімкнені всі три детектори. Кожен аналізує текст незалежно, результати об'єднуються зваженим усередненням.
| Детектор | Вага | Що робить | Що потрібно |
|---|---|---|---|
rule_based |
1.0 | Шукає маркери за YAML-словниками (uk/ru/en), 23 техніки | Нічого |
ml |
1.3 | Zero-shot класифікація через mDeBERTa-v3 — розуміє контекст | pip install disinfolib[ml] |
ai |
1.5 | Аналіз через Gemini/OpenAI — найточніший | ai_api_key у конфігурації |
Детектор що повернув 0.0 — абстентується: він не входить у знаменник і не знижує загальний score. Це означає що відсутність ML або AI не штрафує результат — вони просто не беруть участі у підрахунку.
Якщо ml не встановлено або ai_api_key не вказано — відповідний детектор тихо пропускається без помилок і warnings.
Через YAML-файл
Створіть файл disinfolib.yaml:
threshold: 0.40
languages:
- uk
- en
auto_detect_language: true
detectors:
- rule_based
- ml
- ai
stream_buffer_size: 200
log_level: WARNING
Завантажте:
config = DisinfoConfig.from_yaml("disinfolib.yaml")
Через змінні середовища
Всі параметри можна задати через змінні середовища з префіксом DISINFOLIB_:
export DISINFOLIB_THRESHOLD=0.40
export DISINFOLIB_LOG_LEVEL=DEBUG
export DISINFOLIB_AI_API_KEY=your_key_here
config = DisinfoConfig.from_env()
Підтримувані мови та техніки
Мови
| Код | Мова | Маркерів | Детектор |
|---|---|---|---|
uk |
Українська | 330+ | Rule-based + ML |
ru |
Російська | 330+ | Rule-based + ML |
en |
Англійська | 150+ | Rule-based + ML |
| інші | — | — | ML (mDeBERTa, multilingual) |
Техніки пропаганди (23 шт.)
| Код | Назва | Приклад маркеру |
|---|---|---|
appeal_to_fear |
Апеляція до страху | "небезпека для кожного" |
loaded_language |
Емоційно забарвлена мова | "жахливий", "кошмарний" |
name_calling |
Наклеювання ярликів | образливі характеристики |
dehumanization |
Дегуманізація | відмова в людяності |
exaggeration |
Перебільшення | "знищать усіх" |
whataboutism |
Вотабаутизм | "а що щодо..." |
black_white |
Чорно-біле мислення | "або з нами, або проти нас" |
bandwagon |
Апеляція до більшості | "всі знають що..." |
appeal_to_authority |
Апеляція до авторитету | — |
false_causality |
Хибна причинність | — |
glittering_generalities |
Блискучі узагальнення | "свобода", "справедливість" (без контексту) |
absolute_judgment |
Абсолютні судження | "завжди", "ніколи", "всі" |
slogans |
Гасла | короткі повторювані фрази |
flag_waving |
Апеляція до патріотизму | — |
doubt_seeding |
Сіяння сумнівів | "кажуть що...", "деякі вважають..." |
repetition |
Повторення | — |
state_propaganda |
Держпропаганда | офіційна риторика |
manipulative_pattern |
Маніпулятивний шаблон | — |
emotional_punctuation |
Емоційна пунктуація | !!!, ... |
caps_abuse |
Зловживання капслоком | УВАГА ВСІМ |
cult_of_personality |
Культ особистості | — |
defeat_euphemisms |
Евфемізми поразки | "відступ на заздалегідь підготовлені позиції" |
silencing_dissent |
Замовчування інакодумства | — |
Детальний опис кожної техніки: docs/techniques.md
Власні детектори та джерела
Власний детектор
from disinfolib import BaseDetector
from disinfolib.analysis.detectors.base import DetectorResult
class MyDetector(BaseDetector):
name = "my_detector"
weight = 0.3 # Вага в ensemble
def detect(self, text: str, language: str) -> DetectorResult:
score = 0.8 if "небезпека" in text.lower() else 0.0
return DetectorResult(score=score, techniques=[], found_markers=[])
analyzer = TextAnalyzer()
analyzer.add_detector(MyDetector())
Власне джерело
from disinfolib.sources.base import BaseSource
from disinfolib.models.message import RawMessage
from typing import Iterator
class MySource(BaseSource):
source_type = "custom"
def __iter__(self) -> Iterator[RawMessage]:
for item in fetch_my_data():
yield self._make_message(text=item["content"], title=item["title"])
broker.add_source(MySource(source_id="my_api"))
Повна документація: docs/extending.md
Системні вимоги
| Компонент | Вимога |
|---|---|
| Python | 3.11 або вище |
| ОС | Windows, macOS, Linux |
| RAM (базовий) | ~50 МБ |
| RAM (з ML) | ~2 ГБ (модель mDeBERTa) |
| Диск (базовий) | ~10 МБ |
| Диск (з ML) | ~3 ГБ (PyTorch + модель) |
Залежності за варіантом встановлення
| Варіант | Додаткові залежності | Коли використовувати |
|---|---|---|
pip install disinfolib |
— | Rule-based аналіз, мінімальні ресурси |
disinfolib[rss] |
feedparser, httpx | Моніторинг RSS/Atom стрічок |
disinfolib[ml] |
transformers, torch (~3 ГБ) | Точніший аналіз через ML |
disinfolib[telegram] |
telethon | Моніторинг Telegram-каналів |
disinfolib[kafka] |
kafka-python | Отримання даних з Apache Kafka |
disinfolib[ai] |
httpx | Аналіз через Gemini/OpenRouter API |
disinfolib[all] |
всі вище | Максимальний функціонал |
Приклади
| Файл | Що демонструє |
|---|---|
examples/basic_analysis.py |
Аналіз одного тексту, batch аналіз |
examples/stream_monitoring.py |
Потоковий моніторинг з кількох джерел |
examples/ml_analysis.py |
ML та AI детектори |
examples/rest_api_server.py |
FastAPI сервер поверх disinfolib |
Запуск прикладу:
# Переконайтеся що venv активоване
python examples/basic_analysis.py
Оригінальність та академічна база
disinfolib — це оригінальна розробка, написана з нуля. Бібліотека не є форком, копією або похідним твором жодного існуючого відкритого проекту.
Академічні джерела технік
Класифікація пропагандистських технік у бібліотеці ґрунтується на загальновідомих академічних та аналітичних框架:
| Джерело | Рік | Що використано |
|---|---|---|
| Institute for Propaganda Analysis (IPA) | 1937 | Базова типологія 7 технік: name-calling, glittering generalities, transfer, testimonial, plain folks, card stacking, bandwagon |
| Jacques Ellul, "Propagandes" | 1962 | Класифікація інтеграційної та агітаційної пропаганди, концепція соціологічної пропаганди |
| NATO Strategic Communications Centre of Excellence | 2014–2024 | Сучасна таксономія інформаційних операцій, визначення деhumanzation та whataboutism |
| EU DisinfoLab / EUvsDisinfo | 2015–2024 | Операційні визначення дезінформації, відмінність від пропаганди |
| Renée DiResta, "Computational Propaganda" | 2018 | Автоматизоване поширення наративів |
Ці джерела є публічними академічними та аналітичними матеріалами. Бібліотека реалізує власну інтерпретацію цих концепцій у вигляді програмного коду — мовні патерни, алгоритми, архітектура та реалізація є оригінальними.
Використані відкриті компоненти
Бібліотека використовує сторонні пакети згідно з їхніми ліцензіями:
| Компонент | Ліцензія | Використання |
|---|---|---|
| PyTorch | BSD-3 | Основа для ML-детектора |
| Hugging Face Transformers | Apache 2.0 | Zero-shot класифікація |
| mDeBERTa-v3-base-mnli-xnli (Moritz Laurer) | MIT | NLI модель для детекції технік |
| Pydantic | MIT | Конфігурація та моделі даних |
| feedparser | MIT | Парсинг RSS |
| langdetect | Apache 2.0 | Визначення мови тексту |
| trafilatura | Apache 2.0 | Витяг тексту з веб-сторінок |
Жоден з цих компонентів не є частиною кодової бази disinfolib — вони є залежностями, що встановлюються окремо.
Ліцензія
MIT License — вільне використання, модифікація та розповсюдження з обов'язковим збереженням тексту ліцензії.
Дивіться файл LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file disinfolib-1.0.0.tar.gz.
File metadata
- Download URL: disinfolib-1.0.0.tar.gz
- Upload date:
- Size: 137.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0893b0948255d33aebfa8d4a418c8c9aaf230415f3527bc8da9da9ba82192f06
|
|
| MD5 |
d9b387ba1448fb2f36484ac704baa678
|
|
| BLAKE2b-256 |
47248319c6f644bde8952f7d22cf266e93655f6d69c6113c9013017d1ba9a461
|
File details
Details for the file disinfolib-1.0.0-py3-none-any.whl.
File metadata
- Download URL: disinfolib-1.0.0-py3-none-any.whl
- Upload date:
- Size: 116.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a2b2f5c87d765a8eb24027438917e546e9932bec046ad84901e888367940c4f
|
|
| MD5 |
422e04e472cdf0a40bbc7da87259cd31
|
|
| BLAKE2b-256 |
84a5c4ac0f69cce8f03ab36d75625cbe9824c1161c423c70685800bdf852936a
|