dask🟠 Масштабирование: от одного ядра до всего кластера.🟠 Совместимый синтаксис: DataFrame, Array, ML API аналогичны знакомым библиотекам.🟠 Отличается удобством и гибкостью: можно начать с локальных расчётов, а затем перенести тот же код в прод.🟠 Используется крупными компаниями: Walmart, Nvidia, NASA, Capital One и другими.
🟠 Открытый исходник, активное развитие, последний релиз был в феврале 2024.
pip install dask[complete]
(пакет с зависимостями для полного функционала — параллельные файловые системы, SQL, ML и др.)
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2
Plumbum🟠 Shell-like синтаксис: ls | grep[".py"] > "out.txt"🟠 Работа с удалёнными машинами через SSH🟠 Локальные команды и алиасы🟠 Безопаснее и удобнее, чем os.system или subprocess
pip install plumbum
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤5👍2🔥2
requests, PyPDF2, openai, schedule, argparse🟠 Загружает PDF-отчёты с защищённого сайта (при необходимости авторизация)🟠 Извлекает текст из PDF (PyPDF2)🟠 Отправляет текст в OpenAI для резюмирования🟠 Сохраняет итоговую структуру: date, summary, key_points, risk_section в JSON🟠 Автоматически запускается каждую неделю по расписанию (schedule)
python weekly_report.py --url https://example.com/reports/weekly.pdf \
--schedule "every Monday" --output report.json
import requests, PyPDF2, openai, schedule, time, argparse, json
from io import BytesIO
def fetch_pdf(url):
resp = requests.get(url)
resp.raise_for_status()
return BytesIO(resp.content)
def extract_text(pdf_stream):
reader = PyPDF2.PdfReader(pdf_stream)
return "\n".join(page.extract_text() or "" for page in reader.pages)
def summarize(text):
resp = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "system", "content": "You summarize professionally."},
{"role": "user", "content": text}],
)
return resp.choices[0].message.content.strip()
def job(url, output):
pdf = fetch_pdf(url)
text = extract_text(pdf)
summary = summarize(text)
data = {"url": url, "summary": summary, "timestamp": time.strftime("%Y-%m-%d")}
with open(output, "a", encoding="utf-8") as f:
f.write(json.dumps(data, ensure_ascii=False) + "\n")
print("✅ Report summarized")
def main(args):
schedule.every().monday.do(job, args.url, args.output)
print("🚀 Scheduler started")
while True:
schedule.run_pending()
time.sleep(60)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument('--url', required=True, help='URL PDF отчёта')
p.add_argument('--schedule', default='every Monday')
p.add_argument('--output', default='weekly_reports.json')
args = p.parse_args()
openai.api_key = args.openai_key or os.getenv("OPENAI_API_KEY")
main(args)
pip install requests PyPDF2 openai schedule
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤10🔥4👍2
✅ Слушай книгу по частям без потери места✅ Удобно для изучающих язык — возвращаться на нужный момент✅ Повтор занятий и лекций✅ Прост в использовании и работает офлайн
import pygame
import time
import os
import json
AUDIO_FILE = "audiobook.mp3"
PROGRESS_FILE = "progress.json"
pygame.mixer.init()
pygame.mixer.music.load(AUDIO_FILE)
# Загрузка позиции
if os.path.exists(PROGRESS_FILE):
with open(PROGRESS_FILE) as f:
data = json.load(f)
position = data.get(AUDIO_FILE, 0)
print(f"▶️ Продолжаем с {round(position, 2)} сек")
else:
position = 0
pygame.mixer.music.play(start=position)
try:
while pygame.mixer.music.get_busy():
time.sleep(1)
except KeyboardInterrupt:
current_pos = pygame.mixer.music.get_pos() / 1000 + position
with open(PROGRESS_FILE, "w") as f:
json.dump({AUDIO_FILE: current_pos}, f)
print(f"\n⏸️ Остановлено на {round(current_pos, 2)} сек. Позиция сохранена.")
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3🔥2😁2
peewee
🟠 Очень простой и понятный синтаксис🟠 Поддержка миграций (pwiz, playhouse.migrate)🟠 Поддерживает связи (ForeignKey, ManyToMany)🟠 Есть расширения (playhouse) для кэша, сигналов, миграций и др.
pip install peewee
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
import os
def bulk_rename(folder_path, old_name_part, new_name_part):
if not os.path.isdir(folder_path):
raise NotADirectoryError(f"Путь «{folder_path}» не найден")
for filename in os.listdir(folder_path):
if old_name_part in filename:
new_filename = filename.replace(old_name_part, new_name_part)
old_full = os.path.join(folder_path, filename)
new_full = os.path.join(folder_path, new_filename)
# Пропускаем, если имена совпадают
if old_full == new_full:
print(f"Пропущено (имена совпадают): {filename}")
continue
try:
os.rename(old_full, new_full)
print(f"Переименовано: {filename} → {new_filename}")
except OSError as e:
print(f"Ошибка при переименовании {filename}: {e}")
if __name__ == "__main__":
folder = '/path/to/your/folder'
bulk_rename(folder, 'old_part', 'new_part')
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍1
molecule 🟠 Поддержка Docker, Vagrant, Podman, EC2 и других драйверов🟠 Интеграция с Ansible, Testinfra, Goss🟠 Автоматические проверки, линтинг и CI🟠 Подходит для TDD в инфраструктуре
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍1
Rich-click🟠 Улучшает UX CLI-приложений без переписывания кода🟠 Делает утилиты выглядящими профессионально сразу🟠 Полезен для инструментов разработчика, DevOps-скриптов, Open Source🟠 Минимальные усилия → максимальный эффект
pip install rich-click
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2🔥2
testinfra 🟠 Пишется на Python, использует pytest🟠 Проверка состояния системы: файлов, пакетов, сервисов🟠 Работает через SSH, Docker, локально и др.🟠 Идеален для DevOps, CI/CD, Ansible и Molecule
pip install testinfra
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4🔥3
requests, argparse, os, re🟠 Получает список ссылок на видео YouTube🟠 Извлекает video ID с помощью регулярных выражений🟠 Загружает максимальную по доступности миниатюру (maxresdefault.jpg или hqdefault.jpg)🟠 Сохраняет в указанную директорию со стандартным именем
python yt_thumb_downloader.py --urls video_urls.txt --dir thumbnails
import requests
import argparse
import os
import re
YOUTUBE_THUMB_URL = "https://img.youtube.com/vi/{}/maxresdefault.jpg"
FALLBACK_URL = "https://img.youtube.com/vi/{}/hqdefault.jpg"
ID_PATTERN = r"(?:v=|youtu\.be/)([A-Za-z0-9_-]{11})"
def extract_id(url):
m = re.search(ID_PATTERN, url)
return m.group(1) if m else None
def download_thumb(video_id, save_dir):
url = YOUTUBE_THUMB_URL.format(video_id)
r = requests.get(url)
if r.status_code != 200:
url = FALLBACK_URL.format(video_id)
r = requests.get(url)
if r.status_code == 200:
path = os.path.join(save_dir, f"{video_id}.jpg")
with open(path, "wb") as f:
f.write(r.content)
print(f"✅ Downloaded {path}")
else:
print(f"❌ Failed thumbnail for {video_id}")
def main(urls_file, save_dir):
os.makedirs(save_dir, exist_ok=True)
with open(urls_file, encoding="utf-8") as f:
for line in f:
url = line.strip()
vid = extract_id(url)
if vid:
download_thumb(vid, save_dir)
else:
print(f"❌ Can't extract ID from {url}")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--urls", required=True, help="Файл со ссылками YouTube")
p.add_argument("--dir", required=True, help="Папка для сохранения")
args = p.parse_args()
main(args.urls, args.dir)
pip install requests
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤7🔥5👍4
vault-cli🟠 Чтение/запись секретов через Python или CLI🟠 Поддержка Vault API (v1)🟠 Можно использовать в CI/CD пайплайнах🟠 Конфигурация через YAML/ENV-переменные
pip install vault-cli
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3🔥2
subprocess, boto3, os, time🟠 Выполняет mysqldump через subprocess🟠 Архивирует папку или файл дампа в .tar.gz с таймстампом🟠 Загружает архив в указанный S3‑бакет через boto3🟠 Обрабатывает ошибки доступа и отсутствия файла🟠 Удобен для cron‑запусков и CI/CD интеграции
python backup_mysql_s3.py \
--host localhost --user root --password pwd \
--db mydatabase --bucket my-s3-bucket --dest backups/
import subprocess, boto3, time, os
from botocore.exceptions import NoCredentialsError
def dump_db(host, user, password, db, out_file):
cmd = [
"mysqldump", "-h", host, "-u", user, f"-p{password}", db
]
with open(out_file, "wb") as f:
subprocess.run(cmd, stdout=f, check=True)
def archive(src, dest_dir):
ts = time.strftime("%Y%m%d%H%M%S")
archive_name = os.path.join(dest_dir, f"backup_{ts}.tar.gz")
subprocess.run(["tar", "-czf", archive_name, src], check=True)
return archive_name
def upload_s3(file_path, bucket, key=None):
s3 = boto3.client("s3")
if key is None:
key = os.path.basename(file_path)
try:
s3.upload_file(file_path, bucket, key)
print(f"✅ Backup uploaded to s3://{bucket}/{key}")
except FileNotFoundError:
print("❌ File not found:", file_path)
except NoCredentialsError:
print("❌ AWS credentials are missing")
def main(args):
os.makedirs(args.dest, exist_ok=True)
dump_file = os.path.join(args.dest, f"{args.db}.sql")
dump_db(args.host, args.user, args.password, args.db, dump_file)
archive_path = archive(dump_file, args.dest)
upload_s3(archive_path, args.bucket)
if __name__ == "__main__":
import argparse
p = argparse.ArgumentParser()
p.add_argument("--host", required=True)
p.add_argument("--user", required=True)
p.add_argument("--password", required=True)
p.add_argument("--db", required=True)
p.add_argument("--bucket", required=True)
p.add_argument("--dest", default=".")
args = p.parse_args()
main(args)
pip install boto3
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🔥1
ArviZ🟠 Unified InferenceData: Структурированный способ организации posteriors, предсказаний, наблюдений и логов в одном объекте.🟠 Расширенные визуализации: traceplots, diagnostics (R-hat, ESS), posterior_predictive checks через Matplotlib и Bokeh.🟠 Интеграция с популярными инструментами: поддержка PyMC, Pyro, Stan и xarray.🟠 Поддержка аналитики Bayes-моделей: summarization, posterior checks, model comparison и diagnostics удобны и понятны.🟠 Открытый проект, активно развивается, лицензия Apache 2.0.
pip install arviz
🧑💻 Пример использования:
import arviz as az
import pymc as pm
with pm.Model() as model:
α = pm.Normal("α", 0, 1)
β = pm.Normal("β", 0, 1)
σ = pm.HalfNormal("σ", 1)
μ = α + β * pm.Data("x", [1,2,3,4,5])
y = pm.Normal("y", μ, σ, observed=[1.2,1.9,2.8,4.1,4.9])
idata = pm.sample(return_inferencedata=True)
# Cводка результатов
print(az.summary(idata, var_names=["α", "β", "σ"]))
# Трассировка параметров и автокорреляции
az.plot_trace(idata, var_names=["α", "β"])
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥3👍2
PyPDF2, argparse, os🟠 Ищет все файлы .pdf в указанной директории🟠 Объединяет их в порядке сортировки по имени в единственный PDF🟠 Сохраняет итоговое объединение в указанное имя файла🟠 Полезен для сбора статей, отчетов, документов или презентаций
python pdf_merger.py --input-dir ./pdfs --output merged_all.pdf
import os
import argparse
from PyPDF2 import PdfMerger
def merge_pdfs(input_dir, output_file):
merger = PdfMerger()
pdf_files = sorted([
f for f in os.listdir(input_dir)
if f.lower().endswith('.pdf')
])
for pdf in pdf_files:
path = os.path.join(input_dir, pdf)
merger.append(path)
print(f"✅ Appended: {pdf}")
merger.write(output_file)
merger.close()
print(f"📄 Merged into: {output_file}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Bulk PDF Merger")
parser.add_argument('--input-dir', required=True, help='Папка с PDF')
parser.add_argument('--output', required=True, help='Имя итогового PDF')
args = parser.parse_args()
merge_pdfs(args.input_dir, args.output)
pip install PyPDF2
🟠 Компиляция серии отчетов или документов в единый PDF-файл🟠 Автоматизация сборки документации🟠 Удобное решение для подготовки больших PDF из множества файлов
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🔥5
Nuitka🟠 Преобразует Python-файлы в C-код, затем компилирует в нативные бинарники (используя gcc, clang или MinGW)🟠 Поддерживает большинство современных возможностей языка: аннотации типов, итераторы, вызовы, конструкции управления и пр.🟠 Оптимизации на этапе компиляции: константное сворачивание, прогноз вызова встроенных функций, вывод неизменных типов — ускорение до 1.5–2× по сравнению с CPython🟠 Можно собирать в standalone-приложения — готовые исполняемые файлы выдаются без зависимости от Python-установки у пользователя🟠 Активно развивается: последняя версия 2.6.9 вышла 28 марта 2025 года
pip install nuitka
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤14👍7
requests, json, time, argparse🟠 Принимает адрес API, интервал опроса и файл логов🟠 Делает HTTP GET-запрос и записывает метрики ответа: timestamp, статус-код, latency, тело JSON🟠 Удобен для отслеживания изменений или ошибок в API🟠 Основан на практиках логгирования API-метрик и best practices в мониторинге REST-служб
python api_logger.py --url https://api.example.com/data --interval 60 --output api_log.jsonl
import requests, json, time, argparse
def log_response(url, interval, out_file):
with open(out_file, 'a', encoding='utf-8') as f:
while True:
try:
start = time.time()
r = requests.get(url, timeout=15)
latency = round((time.time() - start) * 1000, 2)
entry = {
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"status_code": r.status_code,
"latency_ms": latency,
"response": r.json() if 'application/json' in r.headers.get('Content-Type', '') else r.text
}
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
print(f"Logged at {entry['timestamp']}: {r.status_code}, {latency}ms")
except Exception as e:
print(f"Error fetching {url}: {e}")
time.sleep(interval)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="API Response Logger")
parser.add_argument("--url", required=True, help="API endpoint to log")
parser.add_argument("--interval", type=int, default=60, help="Polling interval in seconds")
parser.add_argument("--output", required=True, help="JSONL output file for logs")
args = parser.parse_args()
log_response(args.url, args.interval, args.output)
pip install requests
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍4🔥3😁1
Loguru🟠 Логирование "из коробки" — минимум настроек🟠 Цветной вывод, ротация файлов, асинхронность🟠 Автоматический вывод tracebacks и ошибок🟠 Удобный .add() для настройки логов
pip install loguru
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥3
Pillow, numpy, argparse🟠 Загружает изображение любого поддерживаемого формата🟠 Конвертирует в градации серого🟠 Делит изображение на сетку и заменяет среднюю яркость каждой ячейки ASCII‑символом (@, #, . и пр.)🟠 Сохраняет ASCII-арт в файл или выводит на экран🟠 Включает CLI‑интерфейс для настройки ширины и дискреты яркости.
python ascii_art.py --input image.jpg --width 80 --output ascii.txt --detailed
import os
import argparse
from PIL import Image
import numpy as np
GSCALE_SIMPLE = "@%#*+=-:. "
GSCALE_EXTENDED = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~i!lI;:,\"^`'. "
def avg_brightness(tile):
return np.array(tile).mean()
def image_to_ascii(image_path, cols=80, more_levels=False):
image = Image.open(image_path).convert('L')
W, H = image.size
scale = 0.43 # поправка на соотношение символов в терминале
w = W / cols
h = w / scale
rows = int(H / h)
print(f"[ASCII] Рисунок: cols={cols}, rows={rows}")
ascii_img = []
gs = GSCALE_EXTENDED if more_levels else GSCALE_SIMPLE
levels = len(gs)
for row in range(rows):
y1 = int(row * h)
y2 = int((row + 1) * h) if row < rows - 1 else H
line = ""
for col in range(cols):
x1 = int(col * w)
x2 = int((col + 1) * w) if col < cols - 1 else W
tile = image.crop((x1, y1, x2, y2))
brightness = avg_brightness(tile)
idx = int(brightness * (levels - 1) / 255)
line += gs[idx]
ascii_img.append(line)
return ascii_img
def main():
parser = argparse.ArgumentParser(description="ASCII Art Image Converter")
parser.add_argument('--input', required=True, help='Путь к изображению')
parser.add_argument('--width', '-w', type=int, default=80, help='Ширина в символах')
parser.add_argument('--output', '-o', help='Выходной .txt файл (по умолчанию — stdout)')
parser.add_argument('--detailed', action='store_true',
help='Использовать мелкую градацию (GSCALE_EXTENDED)')
args = parser.parse_args()
art = image_to_ascii(args.input, cols=args.width, more_levels=args.detailed)
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
f.write('\n'.join(art))
print(f"✅ Сохранено в {args.output}")
else:
print()
print('\n'.join(art))
if __name__ == "__main__":
main()
pip install pillow numpy
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤12🔥4
Ansible Runner🟠 Позволяет интегрировать Ansible в Python-приложения🟠 Удобен для CI/CD, web-интерфейсов, API-сервисов🟠 Поддерживает запуск playbook, roles, adhoc-команд🟠 Управляет входными/выходными данными (stdout, artifacts)8
pip install ansible-runner
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍4
Скрипт, который сканирует список субдоменов, пытается определить уязвимые поддомены для takeover-а (например, Heroku, AWS S3, GitHub Pages и др.):
dns.resolver (из dnspython), requests, argparse, concurrent.futures🟠 Считывает субдомены из файла или принимает через CLI🟠 Разрешает CNAME- или A-записи DNS🟠 Если найден CNAME, сканирует по известным сигнатурам (“No such app”, “doesn’t exist”, “There isn’t a GitHub Pages site here” и др.) в HTTP-ответах🟠 Параллельно обрабатывает сотни запросов через ThreadPoolExecutor — что ускоряет проверку🟠 Помечает потенциально уязвимые хосты и сохраняет их в отчёт takeover_report.txt
python takeover_check.py --input subs.txt --dns-server 8.8.8.8 --timeout 5
#!/usr/bin/env python3
import argparse, re, requests
from dns import resolver, exception
from concurrent.futures import ThreadPoolExecutor
TAKEOVER_SIGNS = {
"heroku": re.compile(r'no such app', re.I),
"s3": re.compile(r'(NoSuchBucket|The specified bucket does not exist)', re.I),
"github": re.compile(r"There isn't a GitHub Pages site here", re.I),
"azure": re.compile(r'No DNS record found for', re.I),
}
def find_cname(host, nameserver, timeout):
res = resolver.Resolver()
res.nameservers = [nameserver]
res.timeout = timeout
res.lifetime = timeout
try:
answers = res.resolve(host, 'CNAME')
return str(answers[0].target).rstrip('.')
except (resolver.NoAnswer, resolver.NXDOMAIN):
return None
except exception.DNSException:
return None
def check_takeover(host, cname, timeout):
if not cname:
return None
url = f"http://{host}"
try:
r = requests.get(url, timeout=timeout)
html = r.text
for provider, pattern in TAKEOVER_SIGNS.items():
if pattern.search(html):
return (provider, r.status_code, len(html))
except requests.RequestException:
pass
return None
def process(host, nameserver, timeout):
cname = find_cname(host, nameserver, timeout)
suspect = check_takeover(host, cname, timeout)
return host, cname, suspect
def main(args):
heads = f"# Subdomain Takeover Scan Report: {args.input}"
print(heads)
with open(args.input) as f:
hosts = [h.strip() for h in f if h.strip()]
report = []
with ThreadPoolExecutor(max_workers=args.threads) as pool:
for host, cname, res in pool.map(lambda h: process(h, args.nameserver, args.timeout), hosts):
if res:
provider, code, size = res
msg = f"⚠️ {host} → potential {provider} takeover (cname: {cname}, code: {code}, size: {size})"
print(msg)
report.append(msg)
if report:
with open("takeover_report.txt", "w") as f:
f.write(heads + "\n\n" + "\n".join(report))
print(f"\n✅ Найдено потенциальных уязвимостей: {len(report)}. Сохранил в takeover_report.txt")
else:
print("\n✅ Уязвимых поддоменов не найдено.")
if __name__ == "__main__":
cli = argparse.ArgumentParser(description="Subdomain Takeover Checker")
cli.add_argument("--input", "-i", required=True, help="Файл со списком субдоменов, один домен на строку")
cli.add_argument("--dns-server", default="8.8.8.8", help="DNS сервер для запросов (по умолчанию: Google)")
cli.add_argument("--timeout", type=float, default=4.0, help="Таймаут DNS и HTTP")
cli.add_argument("--threads", type=int, default=50, help="Параллельность (подъем числа при больших wordlists)")
args = cli.parse_args()
main(args)
#скрипты
Please open Telegram to view this post
VIEW IN TELEGRAM
2❤5🔥2
Compare‑Dicts‑Lib (compare_dicts_lib)🟠 Поддержка вложенных структур, списков и match-патчинг по "id"🟠 Простое сравнение: compare_dicts(new, old) возвращает только изменения🟠 Флаг detailed=True — показывает тип изменений, старое и новое значение🟠 Параметры: ignore_keys=[…], strict_type_checking=False🟠 Можно применять diff через apply_diff(...) прямо к данным🟠 Не требует сторонних зависимостей, лицензия MIT, Python 3.7+ поддерживается
pip install compare-dicts-lib
#библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥4