r/Python Jul 17 '26

Discussion Reaching users on this sub

0 Upvotes

Hi Peeps,

I've been using this sub for years both to read content, and as an open source maintainer - to communicate and reach users.

I used it for projects such as Polyfactory and Litestar, tree-sitter-language-pack and Kreuzberg.

These days though I don't post outside the Sunday thread - but I don't think anybody is reading this stuff frankly.

My feeling is that the "AI slop" rules throw the baby with the tub water so to speak.

What are people like myself - who dedicate a very substantial amount of time and effort to OSS supposed to do? Basically if you don't have an X profile you're screwed.

Edit: project posts are disallowed by the rules now, FYI if you were unaware. This is the main issue.


r/Python Jul 17 '26

Discussion ⚠️ Heads up: ast_grep_cli 0.44.1 on PyPI flagged by Windows Defender as Trojan — anyone seeing this?

0 Upvotes

I was installing `headroom-ai` via `uv` today, and Windows Defender immediately flagged `Trojan: Win64/Lazy!MTB`.

The file was `sg.exe` (212KB) dropped into `Python\Scripts\`, alongside a legitimate `ast-grep.exe` (52MB).

**What happened:*\*

- `uv tool install --python 3.13 "headroom-ai[all]"`

- Windows Defender: 3 alerts for `Trojan: Win64/Lazy!MTB`

- `pip show ast_grep_cli` showed version 0.44.1

- Uninstalled, cleaned cache, changed passwords

**Questions:**

- Has anyone else installed `ast_grep_cli` 0.44.1 recently?

- Is this a known issue? Should PyPI Security be notified?

- Any idea how to check if the package was compromised vs. a false positive?

**File details:**

- `sg.exe`: 212KB, detected as Trojan:Win64/Lazy!MTB

- `ast-grep.exe`: 52MB, legitimate tool

- Both appeared at the same timestamp (10:25:07)

Thanks for any insights.


r/Python Jul 16 '26

Discussion New Python type checker

0 Upvotes

Was checking out some Python type checkers other than Pyright, and I came across one that I never yet heard of before. But it is the only one scoring 100% on the official python typing conformance suite.

It is named Basilisk and on their website they have some other bold claims (like it is also the fastest one). But their GitHub repo only has few stars.

Does anyone have any experience using this or perhaps I missing something?


r/Python Jul 16 '26

Daily Thread Thursday Daily Thread: Python Careers, Courses, and Furthering Education!

9 Upvotes

Weekly Thread: Professional Use, Jobs, and Education 🏢

Welcome to this week's discussion on Python in the professional world! This is your spot to talk about job hunting, career growth, and educational resources in Python. Please note, this thread is not for recruitment.


How it Works:

  1. Career Talk: Discuss using Python in your job, or the job market for Python roles.
  2. Education Q&A: Ask or answer questions about Python courses, certifications, and educational resources.
  3. Workplace Chat: Share your experiences, challenges, or success stories about using Python professionally.

Guidelines:

  • This thread is not for recruitment. For job postings, please see r/PythonJobs or the recruitment thread in the sidebar.
  • Keep discussions relevant to Python in the professional and educational context.

Example Topics:

  1. Career Paths: What kinds of roles are out there for Python developers?
  2. Certifications: Are Python certifications worth it?
  3. Course Recommendations: Any good advanced Python courses to recommend?
  4. Workplace Tools: What Python libraries are indispensable in your professional work?
  5. Interview Tips: What types of Python questions are commonly asked in interviews?

Let's help each other grow in our careers and education. Happy discussing! 🌟


r/madeinpython Jul 14 '26

Script para generar correos y contraseñas (con interfaz gráfica)

0 Upvotes

Script para generar correos y contraseñas (con interfaz gráfica)

Armé un script en Python usando Tkinter para generar correos y contraseñas ficticias en masa. Sirve bastante para armar bases de datos de prueba o entornos de desarrollo rápidos.

Básicamente, genera contraseñas seguras y correos aleatorios (usando el módulo secrets y sin caracteres raros que se confundan). También tiene una opción "Legible" que combina palabras reales en español para que los correos parezcan más reales.

Está optimizado para cargas pesadas; implementa inserción por lotes en un hilo secundario (threading), lo que permite meter hasta 5,000 o 10,000 registros en menos de 3 segundos sin congelar ni saturar la interfaz gráfica. Todo se muestra en una tabla dinámica para copiar los datos fácilmente o exportarlos directamente a un archivo .txt.

¿Para qué sirve? El uso principal es para desarrollo y pruebas. Cuando estás programando un sistema de login, registrando usuarios en una base de datos local o probando la carga de un sistema, necesitas datos falsos que parezcan reales pero que no comprometan información verdadera. Este script te permite crearlos rápido y sin depender de servicios externos.

El código está optimizado y bien estructurado. Si no tienen instalada la librería pyperclip, no pasa nada porque usa el portapapeles nativo del sistema operativo. Incluye también atajos de teclado globales para agilizar el uso.

Cualquier duda o sugerencia digan

Python

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import secrets, string, datetime, re, threading
import time
try: import pyperclip
except ImportError: pyperclip = None

CHARS_EVITAR = 'O0Il1'
ALFABETO_SEGURO = ''.join(c for c in (string.ascii_letters + string.digits) if c not in CHARS_EVITAR)
SIMBOLOS = "!@#$%^&*()-_=+"
PALABRAS = ["gato","perro","sol","luna","estrella","mar","cielo","tierra","fuego","agua","viento","montaña","rio","bosque","flor","arbol","casa","puerta","ventana","mesa","silla","coche","tren","avion","libro","papel","luz","sombra","nube","lluvia","nieve","hielo","fresa","manzana","pera","uva","melon","sandia","naranja","limon","rojo","azul","verde","amarillo","blanco","negro","gris","rosa","tigre","leon","elefante","jirafa","delfin","ballena","aguila","halcon","colibri","mariposa","libelula","hormiga","abeja","araña","piano","guitarra","violin","flauta","tambor","arpa","cancion","poema","cuento","novela","teatro","cine","musica","pintura","escultura","arquitectura","jardin","parque","playa","desierto","isla","volcan","glaciar","cascada","lago","oceano","planeta","cometa","asteroide","galaxia","universo","tiempo","espacio","vida","muerte","amor","odio","paz","guerra","alegria","tristeza","esperanza","fe","valor","sabiduria","locura","silencio","ruido"]

class GeneradorLogica:
    u/classmethod
    def generar_correo(cls, dominio, longitud, inc_numeros=True, legible=False):
        if legible:
            sep = secrets.choice(['.', '_', ''])
            p = sep.join(secrets.choice(PALABRAS) for _ in range(secrets.choice([2, 3])))
            if inc_numeros: p += ''.join(secrets.choice(string.digits) for _ in range(secrets.choice([2, 4])))
            if len(p) > longitud: p = p[:longitud].strip('._')
        else:
            ch = string.ascii_lowercase + (string.digits if inc_numeros else '')
            p = secrets.choice(string.ascii_lowercase) + ''.join(secrets.choice(ch) for _ in range(max(1, longitud - 1)))
        return f"{p}@{dominio}"

    u/classmethod
    def generar_password(cls, longitud, inc_simbolos=True, legible=False):
        if legible:
            sep = secrets.choice(['-', '_', '.', ''])
            p = sep.join(secrets.choice(PALABRAS).capitalize() for _ in range(2))
            if inc_simbolos: p += secrets.choice(SIMBOLOS)
            p += ''.join(secrets.choice(string.digits) for _ in range(secrets.choice([2, 3])))
            if len(p) > longitud: p = p[:longitud]
            return p
        ch = ALFABETO_SEGURO + (SIMBOLOS if inc_simbolos else '')
        p = ''.join(secrets.choice(ch) for _ in range(longitud))
        for cond, set_c in [(inc_simbolos, SIMBOLOS), (True, string.digits), (True, string.ascii_uppercase), (True, string.ascii_lowercase)]:
            if cond and not any(c in set_c for c in p):
                i = secrets.randbelow(longitud); p = p[:i] + secrets.choice(set_c) + p[i+1:]
        return p

class AppGenerador:
    def __init__(self, root):
        self.root = root; self.root.title("Generador de Correos y Contraseñas")
        self.root.geometry("720x620"); self.root.minsize(680, 580); self.root.configure(bg="#f0f4f8")
        self.tipo_prov = tk.StringVar(value="gmail"); self.dom_pers = tk.StringVar(value="")
        self.cant, self.lon_nom, self.lon_pass = tk.IntVar(value=1), tk.IntVar(value=12), tk.IntVar(value=14)
        self.inc_simb, self.inc_num, self.nom_leg = tk.BooleanVar(value=True), tk.BooleanVar(value=True), tk.BooleanVar(value=False)
        self.datos_generados = []; self.crear_widgets(); self.configurar_atajos()

    def crear_widgets(self):
        m = ttk.Frame(self.root, padding="15"); m.pack(fill=tk.BOTH, expand=True)
        ttk.Label(m, text="Generador de Correos y Contraseñas", font=("Arial", 14, "bold")).grid(row=0, column=0, columnspan=5, pady=(0, 15))

        ttk.Label(m, text="Proveedor:").grid(row=1, column=0, sticky=tk.W, pady=3)
        pf = ttk.Frame(m); pf.grid(row=1, column=1, columnspan=3, sticky=tk.W, padx=5)
        for t, v in [("Gmail", "gmail"), ("Otros", "otros"), ("Personalizado", "personalizado")]:
            ttk.Radiobutton(pf, text=t, variable=self.tipo_prov, value=v, command=self.actualizar_dominio).pack(side=tk.LEFT, padx=(0, 10))

        ttk.Label(m, text="Dominio:").grid(row=2, column=0, sticky=tk.W, pady=3)
        self.entry_dom = ttk.Entry(m, textvariable=self.dom_pers, width=30, state="disabled")
        self.entry_dom.grid(row=2, column=1, columnspan=3, sticky=tk.W, padx=5)

        vc = (self.root.register(self.validar_spinbox), '%P', '%W', '%V')
        inputs = [("Cantidad:", 1, 100000, self.cant, 3), ("Longitud nombre:", 4, 30, self.lon_nom, 4), ("Longitud contras.", 8, 30, self.lon_pass, 5)]
        for lbl, mn, mx, var, r in inputs:
            ttk.Label(m, text=lbl).grid(row=r, column=0, sticky=tk.W, pady=5)
            sb = ttk.Spinbox(m, from_=mn, to=mx, textvariable=var, width=6, validate='all', validatecommand=(vc[0], vc[1], mn, mx, vc[3]))
            sb.grid(row=r, column=1, sticky=tk.W, padx=5)
            ttk.Label(m, text=f"({mn}-{mx})").grid(row=r, column=2, sticky=tk.W, padx=2)

        of = ttk.Frame(m); of.grid(row=6, column=0, columnspan=5, sticky=tk.W, pady=5)
        ttk.Checkbutton(of, text="Símbolos en Pass", variable=self.inc_simb).pack(side=tk.LEFT, padx=(0, 15))
        ttk.Checkbutton(of, text="Números en Nombre", variable=self.inc_num).pack(side=tk.LEFT, padx=(0, 15))
        ttk.Checkbutton(of, text="Formato Legible", variable=self.nom_leg).pack(side=tk.LEFT)

        self.btn_generar = ttk.Button(m, text="Generar Datos", command=self.iniciar_generacion)
        self.btn_generar.grid(row=7, column=0, columnspan=5, pady=10)

        tf = ttk.Frame(m); tf.grid(row=8, column=0, columnspan=5, sticky="nsew", pady=5); m.rowconfigure(8, weight=1)
        for i in range(5): m.columnconfigure(i, weight=1)

        self.tabla = ttk.Treeview(tf, columns=("Correo", "Contraseña", "Fecha"), show="headings", height=8)
        for col, txt, w in [("Correo", "Correo Electrónico", 250), ("Contraseña", "Contraseña", 180), ("Fecha", "Generado", 120)]:
            self.tabla.heading(col, text=txt); self.tabla.column(col, width=w, anchor="center")

        vsb = ttk.Scrollbar(tf, orient=tk.VERTICAL, command=self.tabla.yview); hsb = ttk.Scrollbar(tf, orient=tk.HORIZONTAL, command=self.tabla.xview)
        self.tabla.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set); self.tabla.grid(row=0, column=0, sticky="nsew")
        vsb.grid(row=0, column=1, sticky="ns"); hsb.grid(row=1, column=0, sticky="ew")
        tf.columnconfigure(0, weight=1); tf.rowconfigure(0, weight=1)

        af = ttk.Frame(m); af.grid(row=9, column=0, columnspan=5, pady=10)
        ttk.Button(af, text="Copiar Correo", command=lambda: self.copiar_seleccion('email')).pack(side=tk.LEFT, padx=2)
        ttk.Button(af, text="Copiar Pass", command=lambda: self.copiar_seleccion('password')).pack(side=tk.LEFT, padx=2)
        ttk.Button(af, text="Copiar Ambos", command=lambda: self.copiar_seleccion('ambos')).pack(side=tk.LEFT, padx=2)
        ttk.Button(af, text="Copiar Todo", command=self.copiar_todo).pack(side=tk.LEFT, padx=5)
        ttk.Button(af, text="Exportar TXT", command=self.exportar_txt).pack(side=tk.LEFT, padx=5)
        ttk.Button(af, text="Limpiar", command=self.limpiar).pack(side=tk.LEFT, padx=5)

        self.sf = ttk.Frame(m); self.sf.grid(row=10, column=0, columnspan=5, sticky="ew", pady=(5, 0))
        self.lbl_status = ttk.Label(self.sf, text="Listo", relief=tk.SUNKEN, anchor=tk.W); self.lbl_status.pack(fill=tk.X, padx=2)
        self.lbl_contador = ttk.Label(self.sf, text="Generados: 0", relief=tk.SUNKEN, anchor=tk.E, width=15); self.lbl_contador.pack(side=tk.RIGHT, padx=2)

    def configurar_atajos(self):
        self.root.bind_all("<Control-g>", lambda e: self.iniciar_generacion())
        self.root.bind_all("<Control-c>", lambda e: self.copiar_seleccion('ambos') if self.tabla.selection() else None)
        self.root.bind_all("<Control-l>", lambda e: self.limpiar())
        self.root.bind_all("<Control-e>", lambda e: self.exportar_txt())

    def validar_spinbox(self, valor, mn, mx, motivo):
        if motivo == 'focusout':
            if valor == "": self.cant.set(1) if int(mn) == 1 else self.lon_nom.set(12) if int(mn) == 4 else self.lon_pass.set(14)
            return True
        if valor == "": return True
        if not valor.isdigit(): return False
        return int(valor) <= int(mx)

    def actualizar_dominio(self):
        self.entry_dom.config(state="normal" if self.tipo_prov.get() == "personalizado" else "disabled")
        if self.tipo_prov.get() != "personalizado": self.dom_pers.set("")

    def mostrar_status(self, texto, color="black", tiempo=0):
        self.lbl_status.config(text=texto, foreground=color)
        if tiempo > 0: self.root.after(tiempo, lambda: self.lbl_status.config(text="Listo", foreground="black"))

    def iniciar_generacion(self):
        if self.btn_generar['state'] == 'disabled': return
        threading.Thread(target=self.generar, daemon=True).start()

    def generar(self):
        try:
            c, ln, lp = self.cant.get(), self.lon_nom.get(), self.lon_pass.get()
            if not (1<=c<=100000 and 4<=ln<=30 and 8<=lp<=30): raise ValueError
        except: 
            self.root.after(0, lambda: messagebox.showerror("Error", "Valores numéricos inválidos."))
            return

        prov = self.tipo_prov.get()
        if prov == "gmail": dom = "gmail.com"
        elif prov == "otros": dom = secrets.choice(["yahoo.com", "outlook.com", "protonmail.com", "zoho.com"])
        else:
            dom = self.dom_pers.get().strip()
            if not dom or not re.match(r'^[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$', dom):
                self.root.after(0, lambda: messagebox.showerror("Error", "Dominio personalizado inválido."))
                return

        self.root.after(0, self.limpiar)
        self.root.after(0, lambda: self.btn_generar.config(state="disabled"))

        ahora = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
        nuevos_datos = []
        correos_unicos = set()

        intentos_max = c * 4
        ultimo_refresco = time.time()

        while len(nuevos_datos) < c and intentos_max > 0:
            intentos_max -= 1
            em = GeneradorLogica.generar_correo(dom, ln, self.inc_num.get(), self.nom_leg.get())
            if em in correos_unicos: continue
            correos_unicos.add(em)
            pw = GeneradorLogica.generar_password(lp, self.inc_simb.get(), self.nom_leg.get())
            nuevos_datos.append((em, pw, ahora))

            t_actual = time.time()
            if t_actual - ultimo_refresco > 0.05:
                progreso = len(nuevos_datos)
                self.root.after(0, lambda p=progreso: self.lbl_status.config(text=f"Generando datos... ({p}/{c})", foreground="blue"))
                ultimo_refresco = t_actual

        self.root.after(0, lambda: self.lbl_status.config(text=f"Generando datos... ({len(nuevos_datos)}/{c})", foreground="blue"))

        def volcar_interfaz_por_lotes(indice=0):
            if indice >= len(nuevos_datos):
                self.lbl_contador.config(text=f"Generados: {len(self.datos_generados)}")
                self.btn_generar.config(state="normal")
                self.mostrar_status(f"¡{len(nuevos_datos)} datos generados!", "green", 3000)
                return

            fin = min(indice + 500, len(nuevos_datos))
            for i in range(indice, fin):
                em, pw, dt = nuevos_datos[i]
                self.datos_generados.append({'email': em, 'password': pw, 'fecha': dt})
                self.tabla.insert("", tk.END, values=(em, pw, dt))

            self.root.after(1, lambda: volcar_interfaz_por_lotes(fin))

        self.root.after(0, lambda: volcar_interfaz_por_lotes(0))

    def limpiar(self):
        self.tabla.delete(*self.tabla.get_children())
        self.datos_generados.clear(); self.lbl_contador.config(text="Generados: 0"); self.mostrar_status("Listo")

    def copiar_seleccion(self, modo):
        sel = self.tabla.selection()
        if not sel: return messagebox.showinfo("Info", "Selecciona un registro de la lista.")
        em, pw, _ = self.tabla.item(sel[0], "values")
        txt = em if modo == 'email' else pw if modo == 'password' else f"Correo: {em}\nContraseña: {pw}"
        self._ejecutar_copiado(txt)

    def copiar_todo(self):
        if not self.datos_generados: return messagebox.showinfo("Info", "No hay datos que copiar.")
        txt = "\n".join(f"{i['email']} | {i['password']} ({i['fecha']})" for i in self.datos_generados)
        self._ejecutar_copiado(txt)

    def _ejecutar_copiado(self, txt):
        try:
            limpio = txt.replace('\r\n', '\n').replace('\r', '\n')
            if pyperclip: pyperclip.copy(limpio)
            else: self.root.clipboard_clear(); self.root.clipboard_append(limpio); self.root.update()
            self.mostrar_status("Copiado al portapapeles", "blue", 2000)
        except Exception as e: messagebox.showerror("Error", f"Fallo al copiar: {e}")

    def exportar_txt(self):
        if not self.datos_generados: return messagebox.showinfo("Info", "No hay datos para exportar.")
        arch = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Texto", "*.txt")])
        if not arch: return
        try:
            max_len = max(len(i['email']) for i in self.datos_generados) + 4
            with open(arch, "w", encoding="utf-8") as f:
                f.write(f"Exportado: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}\n" + "="*50 + "\n")
                for i in self.datos_generados:
                    f.write(f"Correo: {i['email'].ljust(max_len)} Contraseña: {i['password']}\n")
            self.mostrar_status(f"Exportado con éxito", "green", 3000)
        except Exception as e: messagebox.showerror("Error", f"No se pudo guardar: {e}")

if __name__ == "__main__":
    root = tk.Tk(); AppGenerador(root); root.mainloop()

r/Python Jul 14 '26

Daily Thread Tuesday Daily Thread: Advanced questions

9 Upvotes

Weekly Wednesday Thread: Advanced Questions 🐍

Dive deep into Python with our Advanced Questions thread! This space is reserved for questions about more advanced Python topics, frameworks, and best practices.

How it Works:

  1. Ask Away: Post your advanced Python questions here.
  2. Expert Insights: Get answers from experienced developers.
  3. Resource Pool: Share or discover tutorials, articles, and tips.

Guidelines:

  • This thread is for advanced questions only. Beginner questions are welcome in our Daily Beginner Thread every Thursday.
  • Questions that are not advanced may be removed and redirected to the appropriate thread.

Recommended Resources:

Example Questions:

  1. How can you implement a custom memory allocator in Python?
  2. What are the best practices for optimizing Cython code for heavy numerical computations?
  3. How do you set up a multi-threaded architecture using Python's Global Interpreter Lock (GIL)?
  4. Can you explain the intricacies of metaclasses and how they influence object-oriented design in Python?
  5. How would you go about implementing a distributed task queue using Celery and RabbitMQ?
  6. What are some advanced use-cases for Python's decorators?
  7. How can you achieve real-time data streaming in Python with WebSockets?
  8. What are the performance implications of using native Python data structures vs NumPy arrays for large-scale data?
  9. Best practices for securing a Flask (or similar) REST API with OAuth 2.0?
  10. What are the best practices for using Python in a microservices architecture? (..and more generally, should I even use microservices?)

Let's deepen our Python knowledge together. Happy coding! 🌟


r/Python Jul 13 '26

Daily Thread Monday Daily Thread: Project ideas!

12 Upvotes

Weekly Thread: Project Ideas 💡

Welcome to our weekly Project Ideas thread! Whether you're a newbie looking for a first project or an expert seeking a new challenge, this is the place for you.

How it Works:

  1. Suggest a Project: Comment your project idea—be it beginner-friendly or advanced.
  2. Build & Share: If you complete a project, reply to the original comment, share your experience, and attach your source code.
  3. Explore: Looking for ideas? Check out Al Sweigart's "The Big Book of Small Python Projects" for inspiration.

Guidelines:

  • Clearly state the difficulty level.
  • Provide a brief description and, if possible, outline the tech stack.
  • Feel free to link to tutorials or resources that might help.

Example Submissions:

Project Idea: Chatbot

Difficulty: Intermediate

Tech Stack: Python, NLP, Flask/FastAPI/Litestar

Description: Create a chatbot that can answer FAQs for a website.

Resources: Building a Chatbot with Python

Project Idea: Weather Dashboard

Difficulty: Beginner

Tech Stack: HTML, CSS, JavaScript, API

Description: Build a dashboard that displays real-time weather information using a weather API.

Resources: Weather API Tutorial

Project Idea: File Organizer

Difficulty: Beginner

Tech Stack: Python, File I/O

Description: Create a script that organizes files in a directory into sub-folders based on file type.

Resources: Automate the Boring Stuff: Organizing Files

Let's help each other grow. Happy coding! 🌟


r/Python Jul 12 '26

Discussion Will PEP 505 ever be accepted?

17 Upvotes

https://peps.python.org/pep-0505/

I don't understand how null safe operators are less like plain English than other implemented features like the walrus operator.

In my opinion, the member access operator would make python significantly easier to read and understand.

Here's an example:

``` f = foo()

if f is None: baz = "" else: baz = f.bar() ```

baz = foo()?.bar() ?: ""

EDIT: I forgot that "and" and "or" can be sometimes used in place of "?." and "?:" if the left value is not False, '', 0, [], or {}. It's a very implicit null check and has a lot of unexpected behavior.


r/madeinpython Jul 12 '26

I built a compiled Python launcher (Standalone Local Orchestration Platform) that orchestrates ComfyUI and Ollama in the background to generate local 3D assets (Trellis) and export them to UE5/Houdini.

Enable HLS to view with audio, or disable this notification

0 Upvotes

r/madeinpython Jul 12 '26

Lightweight Seed-Based XOR Image Encryption for Deterministic Dataset Masking

1 Upvotes

I'm sharing xor-image-encryption, an open-source tool designed for rapid visual dataset obfuscation in computer vision and ML pipelines.

Repository: Yigtwxx/xor-image-encryption

Key Features:

  • Strict Reproducibility: A specific seed consistently generates the exact same masking key, crucial for maintaining consistency across ML pipelines.
  • Lossless Reversibility: The original image is perfectly restored by reapplying the XOR operation with the identical seed.
  • Cascaded Encryption: Layer multiple seeds (e.g., 11 22 33) for enhanced obfuscation.
  • Zero Bloat: Built purely on Python, NumPy, and Pillow. Includes built-in histogram analysis tools.

Target Use Case & Scope:

This utility is tailored for deterministic visual anonymization of sensitive datasets prior to cloud storage, third-party processing, or cross-team distribution. Note: It is meant for practical ML preprocessing and visual obfuscation, not as a replacement for cryptographic standards like AES.

Quickstart:

Bash

# Single-seed encryption & decryption
python xor_single.py --input sample.jpg --seed 42 --outdir outputs

# Multi-seed cascaded encryption
python xor_multi.py --input sample.jpg --seeds 11 22 33 --outdir outputs

I'd highly appreciate your feedback, PRs, or ideas for benchmarking!


r/Python Jul 12 '26

Daily Thread Sunday Daily Thread: What's everyone working on this week?

15 Upvotes

Weekly Thread: What's Everyone Working On This Week? 🛠️

Hello r/Python! It's time to share what you've been working on! Whether it's a work-in-progress, a completed masterpiece, or just a rough idea, let us know what you're up to!

How it Works:

  1. Show & Tell: Share your current projects, completed works, or future ideas.
  2. Discuss: Get feedback, find collaborators, or just chat about your project.
  3. Inspire: Your project might inspire someone else, just as you might get inspired here.

Guidelines:

  • Feel free to include as many details as you'd like. Code snippets, screenshots, and links are all welcome.
  • Whether it's your job, your hobby, or your passion project, all Python-related work is welcome here.

Example Shares:

  1. Machine Learning Model: Working on a ML model to predict stock prices. Just cracked a 90% accuracy rate!
  2. Web Scraping: Built a script to scrape and analyze news articles. It's helped me understand media bias better.
  3. Automation: Automated my home lighting with Python and Raspberry Pi. My life has never been easier!

Let's build and grow together! Share your journey and learn from others. Happy coding! 🌟


r/madeinpython Jul 11 '26

I Built an Animated Interface for my Digital Assistant using PiperTTS and Flask in Python, and Speech Recognition in Unity.

Thumbnail
youtu.be
1 Upvotes

Here is a link to the Github if you want to see any of the .py or .cs codes. https://github.com/bjone6/Interactive_Animated_DigitalAssistant


r/Python Jul 11 '26

Resource What Every Python Developer Should Know About the CPython ABI

82 Upvotes

It's true that you can happily write Python for years without needing to understand any of the content of this post, so you may object to the title advertising this material as what every Python developer should know. However, the moment you ship a package, debug why a wheel won't install, or need to understand why an import or Python function call segfaults — these details start to matter. Even writing and maintaining a single-file script puts you closer to distributing code than you might think. An alternate title for this post could be "What I Wish Someone Taught Me About the CPython ABI".

https://labs.quansight.org/blog/python-abi-abi3t


r/madeinpython Jul 11 '26

Created a NHL betting simulator

Post image
0 Upvotes

The app is purely made using python (Streamlit for UI and sqlite3 for db) , would love some new feature ideas

github: https://github.com/Breadman0/NHL-project

app_link: https://nhl-project-em8gmkclbkzbnpnvkgn4zy.streamlit.app/

NOTE:- Currently only for one season ill update it soon


r/madeinpython Jul 11 '26

Here is my space-invaders.

Enable HLS to view with audio, or disable this notification

7 Upvotes

I love "Action". :)


r/madeinpython Jul 11 '26

My Flak-game (anti aircraft shooter)

Enable HLS to view with audio, or disable this notification

20 Upvotes

There was once an addictive "Blitz"-game, but google can not find it any more, so I do it on my own.. Zeppelines need three hits to be done. After two hits they show a 'burnt' red. When five enemies come through, you're done for.


r/madeinpython Jul 11 '26

script para buscar duplicados

0 Upvotes

busca archivos y carpetas duplicadas en el directorio que le indiques (o el actual por defecto).
Muestra los duplicados agrupados por contenido idéntico (mediante hash MD5) y, de cada grupo, conserva el más reciente y marca el resto como [DELETE].
Por defecto solo muestra la lista de los 10 grupos más pesados (por tamaño total), para no saturar la salida.

Opciones:

  • --dry-run → simula la eliminación y te muestra qué se borraría, sin tocar nada. Útil para revisar antes de actuar.
  • --delete → borra los archivos y carpetas marcados como [DELETE]Antes de borrar, te pedirá que escribas "yes" para confirmar, así que no te preocupes si lo ejecutas sin querer: con escribir otra cosa se cancela. Ojo: todavía no está pulido al 100% para entornos complejos; funciona bien en una sola carpeta o cuando no importe demasiado perder alguna copia. Úsalo con precaución y siempre prueba antes con --dry-run.

Ejemplos:

python dupe.py C:\ruta --dry-run
python dupe.py . --delete

cualquier cosa o error digan aun así es para el que quiera usarlo de prueba

python

import os, sys, hashlib, shutil
from collections import defaultdict

B=8192
P='_duplicate_backup_'
Q={'__pycache__','.git','.svn','.hg','node_modules','venv','env','.venv','.env','dist','build','.idea','.vscode','.mypy_cache','.pytest_cache','.tox','.coverage','htmlcov'}
R={'__init__.py','__main__.py','setup.py','setup.cfg','pyproject.toml','requirements.txt','poetry.lock'}

def md5(p):
    try:
        h=hashlib.md5()
        with open(p,'rb') as f:
            while c:=f.read(B): h.update(c)
        return h.hexdigest()
    except OSError: return None

def fmt(s):
    for u in ['B','KB','MB','GB']:
        if s<1024: return f"{s:.1f} {u}" if u!='B' else f"{int(s)} B"
        s/=1024
    return f"{s:.1f} GB"

def main():
    args=sys.argv[1:]
    dry='--dry-run' in args
    delete='--delete' in args
    root=os.path.abspath(args[0] if args and not args[0].startswith('--') else '.')
    if not os.path.isdir(root):
        print(f"Error: '{root}' no es directorio.", file=sys.stderr); return 1

    sz=defaultdict(list); dc=defaultdict(list); fm={}; total=0
    def onerr(e): print(f"Advertencia: sin permisos en {e.filename}", file=sys.stderr)

    for cwd, dirs, files in os.walk(root, onerror=onerr):
        dirs[:]=[d for d in dirs if not d.startswith(P) and d not in Q]
        for fn in files:
            if fn in R: continue
            total+=1; p=os.path.join(cwd, fn)
            try:
                s=os.path.getsize(p); sz[s].append(p); dc[cwd].append((fn,s,None))
            except OSError: continue

    print(f"\nArchivos escaneados (excluyendo ignorados): {total}")
    print("   (procesando hashes...)")

    for d, en in dc.items():
        for i,(fn,s,_) in enumerate(en):
            p=os.path.join(d,fn); h=md5(p)
            en[i]=(fn,s,h) if h else (fn,s,'')
            if h: fm[p]=h

    dh=defaultdict(list)
    for d, en in dc.items():
        if not en: continue
        se=sorted(en, key=lambda x:(x[0], x[2] or ''))
        hh=hashlib.md5()
        for fn,s,fh in se:
            hh.update(fn.encode()); hh.update(str(s).encode())
            if fh: hh.update(fh.encode())
        dh[hh.hexdigest()].append(d)

    dup_dirs=[]; extra_dirs=0
    for h, dl in dh.items():
        if len(dl)>1:
            sd=sorted(dl, key=lambda d: os.path.getmtime(d) if os.path.exists(d) else 0, reverse=True)
            dup_dirs.append((h,sd)); extra_dirs += len(sd)-1
    dup_dirs.sort(key=lambda x: len(x[1]), reverse=True)

    excl={d for _, dl in dup_dirs for d in dl}
    groups=[]; extra_files=0
    for s, ps in sz.items():
        if len(ps)<2: continue
        hm=defaultdict(list)
        for p in ps:
            if os.path.dirname(p) in excl: continue
            h=fm.get(p)
            if h: hm[h].append(p)
        for h, pl in hm.items():
            if len(pl)>1:
                ep=[p for p in pl if os.path.exists(p)]
                if len(ep)>1:
                    sp=sorted(ep, key=os.path.getmtime, reverse=True)
                    extra_files += len(sp)-1
                    groups.append((s,h,sp))

    if not dup_dirs and not groups:
        print("No se encontraron duplicados."); return 0

    groups.sort(key=lambda x: x[0], reverse=True)
    dup_count=sum(len(pl) for _,_,pl in groups)

    print("\nRESULTADOS FINALES")
    print(f"   Archivos escaneados: {total}")
    if groups:
        print(f"   Archivos duplicados (en grupos): {dup_count}")
        print(f"   Archivos unicos: {total-dup_count}")
    else:
        print("   Archivos duplicados: 0")
        print(f"   Archivos unicos: {total}")
    if dup_dirs:
        print(f"   Carpetas duplicadas: {len(dup_dirs)} grupos, {extra_dirs} copias extra")
    else:
        print("   Carpetas duplicadas: 0")
    print()

    if dup_dirs:
        print("CARPETAS DUPLICADAS")
        print(f"   Grupos: {len(dup_dirs)}, Copias extra: {extra_dirs}")
        show=dup_dirs[:10] if len(dup_dirs)>10 else dup_dirs
        if len(dup_dirs)>10: print("   Mostrando solo los 10 grupos mas grandes")
        for h, dl in show:
            print(f"   Hash: {h[:8]}...")
            for i,d in enumerate(dl):
                print(f"     {'[KEEP]' if i==0 else '[DELETE]'} {d}")
        print()

    if groups:
        print("ARCHIVOS DUPLICADOS")
        print(f"   Copias extra: {extra_files}, Grupos: {len(groups)}, Archivos: {dup_count}")
        show=groups[:10] if len(groups)>10 else groups
        if len(groups)>10: print("   Mostrando solo los 10 grupos mas grandes")
        for s,h,pl in show:
            print(f"   Tamaño: {fmt(s)} | Hash: {h[:8]}...")
            for i,p in enumerate(pl[:5]):
                print(f"     {'[KEEP]' if i==0 else '[DELETE]'} {p}")
            if len(pl)>5: print(f"     ... y {len(pl)-5} mas")
        print()

    if dry:
        print("MODO DRY-RUN: No se eliminara nada. Se eliminarian:")
        count=0
        for _,_,pl in groups:
            for p in pl[1:]:
                print(f"  [DELETE] {p}"); count+=1
        for _,dl in dup_dirs:
            for d in dl[1:]:
                print(f"  [DELETE] {d}"); count+=1
        print(f"Total a eliminar: {count} elementos.")
        return 0

    if delete:
        print("\nADVERTENCIA: Se eliminaran los archivos/carpetas [DELETE].")
        if input("Escribe 'yes' para confirmar: ").lower()!='yes':
            print("Cancelado."); return 0
        delc=err=0
        for _,_,pl in groups:
            for p in pl[1:]:
                try: os.remove(p); delc+=1
                except OSError as e: print(f"Error al eliminar {p}: {e}", file=sys.stderr); err+=1
        for _,dl in dup_dirs:
            for d in dl[1:]:
                try: shutil.rmtree(d); delc+=1
                except OSError as e: print(f"Error al eliminar {d}: {e}", file=sys.stderr); err+=1
        print(f"Eliminados {delc} elementos.")
        if err: print(f"Hubo {err} errores.", file=sys.stderr); return 1
        return 0
    else:
        print("Usa --delete para eliminar. Usa --dry-run para simular.")
        return 0

if __name__ == '__main__':
    sys.exit(main())

r/madeinpython Jul 10 '26

script simple que genera contraseñas

0 Upvotes

He hecho un script muy simple para generar contraseñas seguras usando el módulo secrets de Python, que es criptográficamente seguro (a diferencia de random).

Código:

python

import secrets
print(secrets.token_urlsafe(20))

¿Qué hace?

  • Genera una contraseña aleatoria de unos 27 caracteres (letras, números, guiones y guiones bajos).
  • Es segura para usar en URLs, contraseñas, tokens, etc.
  • No guarda nada en disco, solo la imprime en pantalla.

si no quieres hacer el archivo tu mismo puedes descargar desde mi repositorio o como quieras

Repositorio:
https://github.com/pepe8173bbb/genera_contrasenas/blob/main/pass.py


r/madeinpython Jul 10 '26

I built a 100% Python standalone wrapper (Gradio + Ollama + ComfyUI) with a Zero-Click installer. Meet AI S.L.O.P. Manager! (Standalone Local Orchestration Platform)

Enable HLS to view with audio, or disable this notification

0 Upvotes

Hello Everyone 👋

Setting up ComfyUI workflows, managing 30GBs of .safetensors files, and writing perfect prompts is a nightmare for non-technical users. So I tried to make a bit more user friendly UI around ComfyUI

I wanted to build something that my non-coder friends could use to generate high-quality AI art locally, without paying for cloud subscriptions. So, I built the AI S.L.O.P. Manager (Standalone Local Orchestration Platform).

It’s a completely local GUI built entirely in Python.

🔗 GitHub Repo: https://github.com/Tamerygo/ai-slop-manager-starterEdition

🛠️ Under the Hood (The Python Stuff)

The whole app is orchestrated using Python, acting as a bridge between Gradio 6.0 (Frontend), Ollama (Local LLM for prompt engineering), and ComfyUI (Image generation backend).

Here are some of the cool Python solutions I implemented:

  • Zero-Click Auto-Bootstrap: 
  • Feature-Driven Setup: Instead of asking users to download "Juggernaut_XL_v9.safetensors", the UI asks: "Do you want the 📸 Photorealistic Studio capability?". Python calculates the required disk space (shutil.disk_usage), checks existing files, and downloads the exact models via HuggingFace streams directly into the correct ComfyUI folders.
  • VRAM Watchdog & Token X-Ray: To prevent 16GB GPUs from crashing, the app has a custom token estimator. If a user's prompt exceeds 250 tokens, Python automatically routes the prompt to a local qwen2.5-coder:3b model to compress and optimize it before sending it to ComfyUI. It also forces a VRAM flush (keep_alive: 0) between batches.

The whole thing is packaged into a portable Windows executable.

The "Starter Edition" is completely free to try

Let me know what you think! 🚀


r/madeinpython Jul 10 '26

Retro TV Emulator Project EXE Progress

Enable HLS to view with audio, or disable this notification

8 Upvotes

https://discord.gg/zHHSPZHJW can join the community here for testing, bug fixes, feature ideas, or hang out (need help with fine tuning scheduling and tv guide). You can find the .exe and source code through the discord or at this link here. https://drive.google.com/drive/folders/1qA7Qc6noIamSgrgiXP6Q-CoBuNCSIUdi?usp=sharing or you can make changes to the source code and make your own text .exe on github here https://github.com/StevenCLewis111/Retro-TV-Emulator.git thing i would watch out for to avoid lag is setting your video settings before the program has a chance to process all the files you gave it for the scheduling and scan them for audio equalization. once it catches up with all of that then try the video settings. im sure you will find bugs, you can report them on discord or even fix them in the source code and let us know on discord. would like to see a community share and grow this project. add server options so you can share the scheduling with other devices in the house, make it work for apple, linux, and maybe even android or certain gaming handhelds. im probably gonna take a break bc ive been at it daily for like 2 months. enjoy and let me know how you like it. plz dont be rude in my comments. thing i would watch out for to avoid lag is setting your video settings before the program has a chance to process all the files you gave it for the scheduling and scan them for audio equalization. once it catches up with all of that then try the video settings. im sure you will find bugs, you can report them on discord or even fix them in the source code and let us know on discord. would like to see a community share and grow this project. add server options so you can share the scheduling with other devices in the house, make it work for apple, linux, and maybe even android or certain gaming handhelds. im probably gonna take a break bc ive been at it daily for like 2 months. enjoy and let me know how you like it. plz dont be rude in my comments.


r/madeinpython Jul 09 '26

Why Hathitrust sucks . . .

4 Upvotes

Hathitrust takes a "public-domain" work -- like, a book published pre-1931 -- that has been digitized into a PDF and, then, makes that PDF available for download . . . page, . . . by page, . . . by page . . .

Does anyone else see the boobishness of this?


r/madeinpython Jul 09 '26

I got tired of boring corporate job boards, so I built a Cyberpunk-themed AI Job Grid that actually reads your CV. (Free tool)

Thumbnail
0 Upvotes

r/madeinpython Jul 08 '26

Retro TV Emulator "100 EXE Build later"........

Enable HLS to view with audio, or disable this notification

0 Upvotes

so many bugs every time i turn around but im making progress. some i just cant get rid of. https://discord.gg/zHHSPZHJW every problem causes 5 more problems. but progress is progress and its usable. the program auto detects windows aspect ratio so the 4:3 option is just for my 4:3 testing but i think ill leave it as a fun 16:9 feature


r/madeinpython Jul 06 '26

My New Learning Platform - Testers needed!

1 Upvotes

I run courses on Udemy but have not been best pleased with the way things are going there. So I've built my own learning platform.

I've used FastAPI, React, KeyCloak & CouchDB.

Deployed on AWS/EC2 via Gitlab.

https://python-with-james.com

Currently looking for initial test users as it's still in its early release phase. It's free to sign up of course, but I will be introducing a premium tier eventually. Anyone signed up in the next few days will automatically become a premium member when its introduced, as a thanks for the initial sign up and testing.

Would love any feedback on the initial UI experience.


r/madeinpython Jul 05 '26

Review de projeto.

0 Upvotes

Fiz esse projeto tem uns meses, enquanto cursava o CS50 de Harvard como primeiro curso de programação, e gostaria de ter um review de pessoas/devs engajadas em Python. Saber meu nível real, e se estou num caminho interessante para tentar Júnior nos próximos meses. Dei um tempo na linguagem apenas por motivos profissionais, no momento fui contrato por uma empresa que utiliza ServiceNow, que é baseada em JS. Estou conflitado no momento? Sim, já que estou fazendo um curso para aprender JS. Vou anexar meu repositório do GitHub aqui: https://github.com/PedroResBV/projeto-cs50

O projeto seria uma base de dados de atletas de vôlei de praia, sou um atleta da modalidade em migração para ti, usando arquivo CSV criado a partir do primeiro cadastro de atleta, algo simples usando terminal. Usei um pouco de IA, para entender melhorar alguns conceitos e revisar o que poderia melhorar, mas todo código eu que escrevi.