analitics

Pages

Showing posts with label python3. Show all posts
Showing posts with label python3. Show all posts

Monday, October 26, 2026

News : PyTorch Conference 2026 with new products and integrations, native PyTorch stack for Google TPUs

Today at PyTorch Conference 2026, we announced a range of new products and integrations designed to help you run PyTorch effectively on Google Cloud or in your own infrastructure. Notably, TorchTPU, our native PyTorch stack for Google TPUs, is now available as open source on GitHub. With TorchTPU, TPUs join GPUs and CPUs as a native option for PyTorch. You can now train, serve, and deploy models on TPUs using the tools you already rely on, including vLLM, SGLang, llm-d, TorchTitan, Ray, TorchRec, Hugging Face, LiteRT. Ultimately, this provides our customers choice across a broad range of workload-optimized computing options including TPUs, GPUs, and CPUs, with a consistent, open software and operational model across the full portfolio.
This project provides a PyTorch backend for Google's Tensor Processing Units (TPUs), enabling users to run PyTorch models and operations on TPU devices. It includes custom ATen kernels for various PyTorch operations, a compilation cache for optimizing execution, and examples for distributed training and model inference.

Thursday, October 8, 2026

News : Python 3.15 PEP's.

Python 3.15 brings significant improvements across performance, core features, and developer tools. The startup time is now much faster thanks to explicit lazy imports, and the experimental JIT compiler provides a 7 to 12 percent speed boost depending on your operating system. The update introduces new built-in types like frozendict and sentinel, and officially makes UTF-8 the default text encoding. For developers, the standard library now includes better error messages, more console colors, and a new high-frequency profiling tool called Tachyon to help measure and optimize code performance. The type hinting system is more flexible, and there are major updates to the C API. Most notably, it includes a stable ABI for free-threaded builds, which is a massive step forward for running efficient multi-threaded Python code without the Global Interpreter Lock. Additionally, official macOS installers now include free-threading support by default, Windows 64-bit binaries use a more optimized tail-calling interpreter, and frame pointers are enabled by default for easier system-level debugging. This specific Release Candidate 3 is a surprise extra release added to fix a few last-minute bugs related to the new lazy imports before the final version is launched.
  • PEP 810: Explicit lazy imports for faster startup times
  • PEP 814: Add frozendict built-in type
  • PEP 661: Add sentinel built-in type
  • PEP 798: Unpacking in comprehensions
  • PEP 686: Python now uses UTF-8 as the default encoding
  • PEP 829: Package startup configuration files
  • PEP 799: Tachyon: High frequency statistical sampling profiler / A dedicated profiling package
  • PEP 728: TypedDict with typed extra items
  • PEP 747: Annotating type forms with TypeForm
  • PEP 800: Disjoint bases in the type system
  • PEP 803, 820, 793: Stable ABI for free-threaded builds and related C API
  • PEP 782: A new PyBytesWriter C API to create a Python bytes object
  • PEP 788: Protection against finalization in the C API
  • PEP 831: Frame pointers are enabled by default for improved system-level observability
  • PEP 790: 3.15 release schedule

tkinter : analyze stock market data for a chosen ticker symbol

This Python script creates a mobile-friendly graphical application using Tkinter to analyze stock market data for a chosen ticker symbol, such as NVDA. When you launch the app, it presents a user interface with input fields to type a stock symbol and select a time frame, like one month, six months, or one year. Upon clicking the Load button, the script sends a direct web request to Yahoo Finance. It uses a custom user browser agent header to fetch accurate raw historical market price data, avoiding network blocking or API failures on mobile Python environments. Once the raw data is downloaded, the script converts the response into a structured Pandas dataframe containing daily open, high, low, close, and volume values. It then automatically computes several key technical market indicators. It calculates 20-day and 50-day Simple Moving Averages to show price trends over time. It computes Bollinger Bands to illustrate price volatility boundaries, and it calculates the Relative Strength Index over 14 days to identify overbought or oversold market conditions. At the top of the interface, the app displays text cards showing the latest stock price, current RSI value, and moving averages. Below these metrics, it renders two interactive charts using Matplotlib embedded directly into Tkinter. The upper chart plots the stock closing price alongside the moving averages and Bollinger Bands shading. The lower chart plots the RSI line with dashed horizontal benchmark lines at values 30 and 70. In short, this script serves as a lightweight, real-time stock dashboard that fetches financial market data, calculates essential technical indicators, and visualizes price action clearly on mobile screens.
Let's see the source code:
import tkinter as tk
from tkinter import ttk, messagebox
import pandas as pd
import numpy as np
import requests
from datetime import datetime, timedelta

import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

class FinancialDashboardApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Market Indicators Dashboard")
        self.root.geometry("480x800")

        # --- Controls Frame (Top) ---
        control_frame = ttk.LabelFrame(root, text=" Parametrii Simbol ")
        control_frame.pack(fill="x", padx=10, pady=5)

        ttk.Label(control_frame, text="Ticker:").grid(row=0, column=0, padx=5, pady=5)
        self.ticker_entry = ttk.Entry(control_frame, width=8)
        self.ticker_entry.insert(0, "NVDA")
        self.ticker_entry.grid(row=0, column=1, padx=5, pady=5)

        ttk.Label(control_frame, text="Perioadă:").grid(row=0, column=2, padx=5, pady=5)
        self.period_cb = ttk.Combobox(control_frame, values=["1mo", "3mo", "6mo", "1y"], width=6)
        self.period_cb.set("6mo")
        self.period_cb.grid(row=0, column=3, padx=5, pady=5)

        fetch_btn = ttk.Button(control_frame, text="Încarcă", command=self.load_data)
        fetch_btn.grid(row=0, column=4, padx=5, pady=5)

        # --- Info Cards Frame (Middle) ---
        self.info_frame = ttk.LabelFrame(root, text=" Date & Indicatori ")
        self.info_frame.pack(fill="x", padx=10, pady=5)

        self.lbl_price = ttk.Label(self.info_frame, text="Preț: -", font=("Helvetica", 10, "bold"))
        self.lbl_price.grid(row=0, column=0, sticky="w", padx=10, pady=2)

        self.lbl_rsi = ttk.Label(self.info_frame, text="RSI (14): -")
        self.lbl_rsi.grid(row=0, column=1, sticky="w", padx=10, pady=2)

        self.lbl_sma20 = ttk.Label(self.info_frame, text="SMA 20: -")
        self.lbl_sma20.grid(row=1, column=0, sticky="w", padx=10, pady=2)

        self.lbl_sma50 = ttk.Label(self.info_frame, text="SMA 50: -")
        self.lbl_sma50.grid(row=1, column=1, sticky="w", padx=10, pady=2)

        # --- Matplotlib Canvas Frame (Bottom) ---
        self.plot_frame = ttk.Frame(root)
        self.plot_frame.pack(fill="both", expand=True, padx=10, pady=5)

        self.fig = Figure(figsize=(5, 6), dpi=90)
        self.ax1 = self.fig.add_subplot(211) # Subplot Preț + SMA / Bollinger
        self.ax2 = self.fig.add_subplot(212, sharex=self.ax1) # Subplot RSI

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.plot_frame)
        self.canvas.get_tk_widget().pack(fill="both", expand=True)

        self.load_data()

    def fetch_yahoo_data(self, symbol, range_str):
        """Descarcă date brute din Yahoo v8 API simulând un browser desktop."""
        url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}?range={range_str}&interval=1d"
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
        }
        
        response = requests.get(url, headers=headers, timeout=10)
        if response.status_code != 200:
            return pd.DataFrame()

        data = response.json()
        result = data['chart']['result'][0]
        timestamps = result['timestamp']
        quote = result['indicators']['quote'][0]

        df = pd.DataFrame({
            'Open': quote['open'],
            'High': quote['high'],
            'Low': quote['low'],
            'Close': quote['close'],
            'Volume': quote['volume']
        }, index=pd.to_datetime(timestamps, unit='s'))

        df.dropna(subset=['Close'], inplace=True)
        return df

    def calculate_indicators(self, df):
        # 1. Simple Moving Averages (SMA)
        df['SMA_20'] = df['Close'].rolling(window=20).mean()
        df['SMA_50'] = df['Close'].rolling(window=50).mean()

        # 2. Bollinger Bands
        std20 = df['Close'].rolling(window=20).std()
        df['BB_Upper'] = df['SMA_20'] + (std20 * 2)
        df['BB_Lower'] = df['SMA_20'] - (std20 * 2)

        # 3. RSI (14 zile)
        delta = df['Close'].diff()
        gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
        rs = gain / loss
        df['RSI'] = 100 - (100 / (1 + rs))

        return df

    def load_data(self):
        ticker_symbol = self.ticker_entry.get().strip().upper()
        period = self.period_cb.get()

        if not ticker_symbol:
            messagebox.showerror("Eroare", "Introduceți un ticker valid.")
            return

        try:
            # Preluare date prin request HTTP direct
            df = self.fetch_yahoo_data(ticker_symbol, period)

            if df.empty:
                messagebox.showwarning("Atenție", f"Nu s-au găsit date pentru tickerul '{ticker_symbol}'. Verificați conexiunea la internet sau simbolul introduse.")
                return

            df = self.calculate_indicators(df)

            curr_price = df['Close'].iloc[-1]
            last_rsi = df['RSI'].iloc[-1] if not pd.isna(df['RSI'].iloc[-1]) else 0.0
            last_sma20 = df['SMA_20'].iloc[-1] if not pd.isna(df['SMA_20'].iloc[-1]) else 0.0
            last_sma50 = df['SMA_50'].iloc[-1] if not pd.isna(df['SMA_50'].iloc[-1]) else 0.0

            # Actualizare etichete UI
            self.lbl_price.config(text=f"Preț: {curr_price:.2f} USD")
            self.lbl_rsi.config(text=f"RSI (14): {last_rsi:.2f}")
            self.lbl_sma20.config(text=f"SMA 20: {last_sma20:.2f}")
            self.lbl_sma50.config(text=f"SMA 50: {last_sma50:.2f}")

            # Generare grafice
            self.plot_charts(df, ticker_symbol)

        except Exception as e:
            messagebox.showerror("Eroare", f"A apărut o eroare la procesare:\n{e}")

    def plot_charts(self, df, ticker_symbol):
        self.ax1.clear()
        self.ax2.clear()

        # Grafic 1: Preț, SMA 20, SMA 50 și Benzi Bollinger
        self.ax1.plot(df.index, df['Close'], label='Close', color='black', linewidth=1.2)
        self.ax1.plot(df.index, df['SMA_20'], label='SMA 20', color='blue', linestyle='--', alpha=0.7)
        self.ax1.plot(df.index, df['SMA_50'], label='SMA 50', color='orange', linestyle='--', alpha=0.7)
        self.ax1.plot(df.index, df['BB_Upper'], label='BB Upper', color='gray', linestyle=':', alpha=0.5)
        self.ax1.plot(df.index, df['BB_Lower'], label='BB Lower', color='gray', linestyle=':', alpha=0.5)
        self.ax1.fill_between(df.index, df['BB_Lower'], df['BB_Upper'], color='gray', alpha=0.1)

        self.ax1.set_title(f"{ticker_symbol} - Preț & Indicatori", fontsize=10)
        self.ax1.legend(loc="upper left", fontsize=7)
        self.ax1.grid(True, linestyle=':', alpha=0.6)

        # Grafic 2: RSI cu nivelurile 30 și 70
        self.ax2.plot(df.index, df['RSI'], label='RSI (14)', color='purple')
        self.ax2.axhline(70, color='red', linestyle='--', alpha=0.6)   # Overbought
        self.ax2.axhline(30, color='green', linestyle='--', alpha=0.6) # Oversold
        self.ax2.set_ylim(0, 100)
        self.ax2.set_title("RSI (14)", fontsize=9)
        self.ax2.grid(True, linestyle=':', alpha=0.6)

        self.fig.autofmt_xdate(rotation=30)
        self.fig.tight_layout()
        self.canvas.draw()

if __name__ == "__main__":
    root = tk.Tk()
    app = FinancialDashboardApp(root)
    root.mainloop()

Tuesday, October 6, 2026

News : How fast is Python 3.15? by Miguel Grinberg.

The article “How fast is Python 3.15?” provides a detailed performance analysis of the upcoming CPython release, focusing on benchmark‑driven comparisons across standard CPython, the new JIT compiler, and the free‑threaded (no‑GIL) build. Using two deterministic workloads—recursive Fibonacci and bubble sort—the author evaluates Python 3.15 in both single‑threaded and multi‑threaded execution modes, generating a clear performance profile relevant for developers, performance engineers, and technical SEO audiences researching Python speed improvements.
In single‑threaded Fibonacci, Python 3.15 shows incremental gains over Python 3.14, continuing the trend of small but consistent optimizations introduced after the major jump in Python 3.11. The standout result is the Python 3.15 JIT, which delivers a 1.20× speedup over standard CPython. This marks the first release where the JIT consistently outperforms the interpreter in this benchmark. PyPy remains significantly faster, achieving 5.5× the speed of CPython 3.15, while Rust demonstrates extreme performance at 77× faster, reinforcing the gap between dynamic and compiled languages.
The single‑threaded bubble‑sort benchmark confirms the same pattern: Python 3.15 is slightly faster than 3.14, but the JIT build provides a substantial 1.28× improvement. Node.js surpasses PyPy in this specific workload, highlighting how algorithmic characteristics influence interpreter performance. Free‑threaded CPython remains slower in single‑thread mode due to concurrency‑related overhead, which is expected.
The multi‑threaded benchmarks reveal the most important performance evolution. Standard CPython continues to scale poorly because of the Global Interpreter Lock (GIL), and Python 3.15 is marginally slower than 3.14 in multi‑threaded Fibonacci. PyPy also suffers from GIL‑related limitations.
However, free‑threaded Python 3.15 demonstrates a major breakthrough: in multi‑threaded Fibonacci, it achieves a 4.5× speedup compared to standard CPython, matching and stabilizing the gains introduced in Python 3.14 FT. This confirms that the no‑GIL architecture is maturing and becoming a viable option for CPU‑bound parallel workloads. The JIT build maintains its advantage even under multi‑threading, showing consistent performance improvements across all categories.
From a technical SEO perspective, the article positions Python 3.15 as a release focused on predictable single‑threaded optimizations, significant JIT compiler progress, and high‑impact concurrency improvements through the free‑threaded runtime. These advancements make Python 3.15 a strategically important version for developers targeting performance‑critical applications, parallel computing, and future no‑GIL migration paths.
See the full article on the official blog.

thinter : manage python scripts !!!

Today, this simple manager for python scripts with autodetect python modules and add to description for each script with Claude AI.
See the source code:
# -*- coding: utf-8 -*-
import os
import re
import ast
import sys
import json
import hashlib
import subprocess
import tkinter as tk
from tkinter import ttk, messagebox
import tkinter.font as tkfont
DEFAULT_ROOT = "/storage/emulated/0/Download"
CATALOG_NAME = ".scripts_catalog.json"
FONT_SIZE = 10
try:
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
except NameError:
    BASE_DIR = os.getcwd()
STD = getattr(sys, "stdlib_module_names", None)
if STD is None:
    STD = set((
        "__future__ abc argparse array ast asyncio base64 bisect bz2 calendar cmd code codecs collections "
        "configparser contextlib copy csv ctypes curses dataclasses datetime decimal difflib email enum "
        "fnmatch fractions ftplib functools gc getopt getpass gettext glob gzip hashlib heapq hmac html http "
        "imaplib importlib inspect io itertools json locale logging lzma math mimetypes msvcrt multiprocessing "
        "operator optparse os pathlib pdb pickle platform pprint profile queue random re readline sched secrets "
        "select shelve shutil signal smtplib socket sqlite3 ssl stat statistics string struct subprocess sys "
        "tarfile telnetlib tempfile textwrap threading time timeit tkinter traceback turtle types typing "
        "unittest urllib uuid warnings weakref webbrowser winreg xml zipfile zlib"
    ).split())
ALIASES = {
    "PIL": "Pillow", "cv2": "opencv-python", "yt_dlp": "yt-dlp", "bs4": "beautifulsoup4",
    "sklearn": "scikit-learn", "yaml": "PyYAML", "dotenv": "python-dotenv", "serial": "pyserial",
    "win32api": "pywin32", "win32com": "pywin32", "Crypto": "pycryptodome", "skimage": "scikit-image",
    "dateutil": "python-dateutil", "OpenGL": "PyOpenGL", "bpy": "bpy (Blender)",
}
def safe(text):
    return str(text).encode("utf-8", "replace").decode("utf-8")
def read_json(path):
    try:
        with open(path, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return None
def is_local(mod, full, root_folder):
    root_n = os.path.normpath(root_folder)
    cur = os.path.normpath(os.path.dirname(full))
    while True:
        is_root = (cur == root_n)
        if os.path.isfile(os.path.join(cur, mod + ".py")):
            return True
        if not is_root and os.path.isdir(os.path.join(cur, mod)):
            return True
        if is_root or len(cur) <= len(root_n):
            return False
        cur = os.path.dirname(cur)
def analyze(full, root_folder):
    try:
        with open(full, "r", encoding="utf-8", errors="replace") as f:
            text = f.read(300000)
    except OSError:
        return "Libs: nu pot citi fișierul"
    mods = []
    try:
        for node in ast.walk(ast.parse(text)):
            if isinstance(node, ast.Import):
                for a in node.names:
                    mods.append(a.name.split(".")[0])
            elif isinstance(node, ast.ImportFrom):
                if node.module and node.level == 0:
                    mods.append(node.module.split(".")[0])
    except (SyntaxError, ValueError):
        pattern = r"^\s*(?:from\s+([A-Za-z_]\w*)[\w.]*\s+import\s|import\s+([A-Za-z_]\w*))"
        for m in re.finditer(pattern, text, re.M):
            mods.append(m.group(1) or m.group(2))
    libs = []
    for m in mods:
        if m in STD or is_local(m, full, root_folder):
            continue
        name = ALIASES.get(m, m)
        if name not in libs:
            libs.append(name)
    libs.sort(key=str.lower)
    return "Libs: " + (", ".join(libs) if libs else "doar biblioteca standard")
class App:
    def __init__(self, root):
        self.root = root
        root.title("Python Scripts Manager")
        root.geometry("900x600")
        self.scripts = []
        self.files = {}
        self.root_folder = ""
        self.font = tkfont.Font(family="Arial", size=FONT_SIZE)
        style = ttk.Style()
        style.configure("Treeview", font=self.font, rowheight=self.font.metrics("linespace") + 14)
        style.configure("Treeview.Heading", font=(self.font.actual("family"), FONT_SIZE, "bold"))
        top = tk.Frame(root)
        top.pack(fill="x", padx=6, pady=4)
        tk.Label(top, text="Folder:").pack(side="left")
        self.path_var = tk.StringVar(value=DEFAULT_ROOT)
        tk.Entry(top, textvariable=self.path_var, font=self.font).pack(side="left", fill="x", expand=True, padx=4)
        tk.Button(top, text="Scan", command=self.load_scripts).pack(side="left")
        search = tk.Frame(root)
        search.pack(fill="x", padx=6)
        tk.Label(search, text="Caută:").pack(side="left")
        self.search_var = tk.StringVar()
        self.search_var.trace_add("write", lambda *a: self.refresh_table())
        tk.Entry(search, textvariable=self.search_var, font=self.font).pack(side="left", fill="x", expand=True, padx=4)
        frame = tk.Frame(root)
        frame.pack(fill="both", expand=True, padx=6, pady=4)
        self.tree = ttk.Treeview(frame, columns=("name", "rel", "desc"), show="headings", selectmode="browse")
        self.tree.heading("name", text="Script")
        self.tree.heading("rel", text="Path relativ")
        self.tree.heading("desc", text="Descriere")
        self.tree.column("name", width=180)
        self.tree.column("rel", width=300)
        self.tree.column("desc", width=300)
        self.tree.tag_configure("auto", foreground="gray")
        vsb = ttk.Scrollbar(frame, orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(frame, orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
        self.tree.grid(row=0, column=0, sticky="nsew")
        vsb.grid(row=0, column=1, sticky="ns")
        hsb.grid(row=1, column=0, sticky="ew")
        frame.rowconfigure(0, weight=1)
        frame.columnconfigure(0, weight=1)
        self.tree.bind("", lambda e: self.open_detail())
        btns = tk.Frame(root)
        btns.pack(fill="x", padx=6, pady=4)
        tk.Button(btns, text="Run", command=self.run_script, bg="#2196F3", fg="white", width=8).pack(side="left", padx=2)
        tk.Button(btns, text="Copy path", command=self.copy_path, width=8).pack(side="left", padx=2)
        tk.Button(btns, text="Detalii", command=self.open_detail, width=8).pack(side="left", padx=2)
        tk.Button(btns, text="Auto toate", command=self.auto_all, width=8).pack(side="left", padx=2)
        self.status = tk.Label(root, text="Ready", anchor="w")
        self.status.pack(fill="x", padx=6, pady=2)
        self.load_scripts()
    def primary_file(self):
        return os.path.join(self.root_folder, CATALOG_NAME)
    def fallback_file(self):
        h = hashlib.md5(self.root_folder.encode("utf-8", "replace")).hexdigest()[:8]
        return os.path.join(BASE_DIR, "catalog_" + h + ".json")
    def save_catalog(self):
        payload = {"version": 1, "root": self.root_folder, "files": self.files}
        for path in (self.primary_file(), self.fallback_file()):
            try:
                with open(path, "w", encoding="utf-8") as f:
                    json.dump(payload, f, indent=2, ensure_ascii=False)
                return path
            except OSError:
                continue
        messagebox.showerror("Eroare", "Nu pot salva catalogul.")
        return None
    def load_scripts(self):
        folder = self.path_var.get().strip()
        if not os.path.isdir(folder):
            messagebox.showerror("Eroare", "Folder inexistent:\n" + safe(folder))
            return
        self.root_folder = folder
        data = read_json(self.primary_file()) or read_json(self.fallback_file()) or {}
        old = data.get("files", {})
        found = []
        for dirpath, dirs, files in os.walk(folder):
            dirs[:] = [d for d in dirs if d != "__pycache__"]
            for file in files:
                if file.endswith(".py"):
                    full = os.path.join(dirpath, file)
                    rel = os.path.relpath(full, folder).replace("\\", "/")
                    found.append((file, rel, full))
        found.sort(key=lambda s: s[1].lower())
        found_rels = set(s[1] for s in found)
        orphans = {r: e for r, e in old.items() if r not in found_rels and e.get("desc")}
        new_files = {}
        for name, rel, full in found:
            try:
                st = os.stat(full)
                size, mtime = st.st_size, int(st.st_mtime)
            except OSError:
                size, mtime = 0, 0
            entry = old.get(rel)
            if entry is None:
                entry = {"desc": ""}
                for orel, oe in list(orphans.items()):
                    if os.path.basename(orel) == name and oe.get("size") == size:
                        entry = {"desc": oe.get("desc", ""), "auto": oe.get("auto", "")}
                        del orphans[orel]
                        break
            entry = dict(entry)
            entry["size"] = size
            entry["mtime"] = mtime
            new_files[rel] = entry
        new_files.update(orphans)
        self.files = new_files
        self.scripts = found
        saved = self.save_catalog()
        self.refresh_table()
        if saved:
            self.status.config(text=str(len(found)) + " scripturi | catalog: " + safe(saved))
    def refresh_table(self):
        q = self.search_var.get().strip().lower()
        self.tree.delete(*self.tree.get_children())
        shown = 0
        for i, (name, rel, full) in enumerate(self.scripts):
            entry = self.files.get(rel, {})
            desc = entry.get("desc", "")
            auto = entry.get("auto", "")
            text = desc if desc else ("~ " + auto if auto else "")
            if q and q not in name.lower() and q not in rel.lower() and q not in text.lower():
                continue
            tags = ("auto",) if (not desc and auto) else ()
            self.tree.insert("", "end", iid=str(i), values=(safe(name), safe(rel), safe(text)), tags=tags)
            shown += 1
        if q:
            self.status.config(text=str(shown) + " din " + str(len(self.scripts)) + " scripturi")
    def selected(self):
        sel = self.tree.selection()
        if not sel:
            messagebox.showinfo("Info", "Selectează un script din listă.")
            return None
        return int(sel[0])
    def open_detail(self):
        idx = self.selected()
        if idx is None:
            return
        name, rel, full = self.scripts[idx]
        entry = self.files.setdefault(rel, {})
        win = tk.Toplevel(self.root)
        win.title("Detalii")
        win.transient(self.root)
        w = max(self.root.winfo_width(), 320)
        win.geometry(str(w) + "x" + str(max(self.root.winfo_height() // 2, 280)))
        tk.Label(win, text=safe(rel), wraplength=w - 20, justify="left", anchor="w").pack(fill="x", padx=8, pady=4)
        bar = tk.Frame(win)
        bar.pack(fill="x", padx=8)
        box = tk.Text(win, wrap="word", height=8, font=self.font)
        box.pack(fill="both", expand=True, padx=8, pady=6)
        box.insert("1.0", entry.get("desc") or entry.get("auto", ""))
        def do_auto():
            if box.get("1.0", "end").strip():
                if not messagebox.askyesno("Auto detect", "Înlocuiesc textul din câmp?", parent=win):
                    return
            info = analyze(full, self.root_folder)
            entry["auto"] = info
            box.delete("1.0", "end")
            box.insert("1.0", info)
        def do_update():
            entry["desc"] = box.get("1.0", "end").strip()
            self.save_catalog()
            self.refresh_table()
            win.destroy()
        tk.Button(bar, text="Auto detect", command=do_auto, width=10).pack(side="left", padx=2)
        tk.Button(bar, text="Update", command=do_update, bg="#4CAF50", fg="white", width=8).pack(side="left", padx=2)
        tk.Button(bar, text="Închide", command=win.destroy, width=8).pack(side="left", padx=2)
        win.grab_set()
    def auto_all(self):
        total = len(self.scripts)
        if not total:
            return
        if not messagebox.askyesno("Auto toate", "Regenerez Libs pentru " + str(total) + " scripturi?\nDescrierile tale nu se modifică."):
            return
        for n, (name, rel, full) in enumerate(self.scripts, 1):
            self.files.setdefault(rel, {})["auto"] = analyze(full, self.root_folder)
            if n % 5 == 0:
                self.status.config(text="Analiză " + str(n) + "/" + str(total))
                self.root.update_idletasks()
        self.save_catalog()
        self.refresh_table()
        self.status.config(text="Libs generat pentru " + str(total) + " scripturi")
    def run_script(self):
        idx = self.selected()
        if idx is None:
            return
        full = self.scripts[idx][2]
        try:
            subprocess.Popen([sys.executable, full], cwd=os.path.dirname(full))
            self.status.config(text="Rulat: " + safe(os.path.basename(full)))
        except Exception as e:
            messagebox.showerror("Eroare", "Eroare la rulare:\n" + safe(e))
    def copy_path(self):
        idx = self.selected()
        if idx is None:
            return
        full = self.scripts[idx][2]
        self.root.clipboard_clear()
        self.root.clipboard_append(full)
        self.status.config(text="Copiat: " + safe(full))
if __name__ == "__main__":
    root = tk.Tk()
    App(root)
    root.mainloop()

Python 3.13.13 : Exemple with random and string.

See this source code:
import random
import string

# Generate a random password of length 10
def generate_password(length):
    characters = string.ascii_letters + string.digits + string.punctuation
    return ''.join(random.choices(characters, k=length))


password = generate_password(10)
print(password)

Sunday, October 4, 2026

tkinter : PyTorch and Keras on pydroid3.

Today, simple python script with pytorch and keras on android pydroid application.
This script is a Tkinter graphical application designed to test and verify PyTorch and Keras packages in Pydroid 3. Right at launch, it tracks execution time down to milliseconds and displays the installed package versions in a status panel. All diagnostics run on a background thread to keep the user interface responsive. For PyTorch, the script tests matrix inversion, automatic gradient calculations using Autograd, data processing through a neural network linear layer, and eigenvalue decomposition. For Keras, the script verifies building a Sequential model with dense layers, compiling and training it on synthetic data for 3 epochs, and running a final prediction to confirm end-to-end execution.
This is the result of the running python script:
Let's see the source code:
import os
import time
import threading
import tkinter as tk
from tkinter import ttk, scrolledtext

# Set Keras backend to torch
os.environ["KERAS_BACKEND"] = "torch"

class AppCheck(tk.Tk):
    def __init__(self):
        self.start_time = time.time()
        
        super().__init__()
        self.title("PyTorch & Keras Inspector")
        self.geometry("480x600")
        
        self.style = ttk.Style(self)
        self.style.theme_use('clam')
        
        self.create_widgets()
        
        # Log UI startup time
        ui_ready = self.get_elapsed_str()
        self.log(f"{ui_ready} Tkinter UI initialized")
        
        # Initial package check
        self.check_initial_imports()

    def get_elapsed_str(self):
        """Returns elapsed time in MM:SS.mmm format without brackets."""
        elapsed = time.time() - self.start_time
        minutes = int(elapsed // 60)
        seconds = int(elapsed % 60)
        millis = int((elapsed - int(elapsed)) * 1000)
        return f"+{minutes:02d}:{seconds:02d}.{millis:03d}"

    def create_widgets(self):
        # Status Frame
        self.info_frame = ttk.LabelFrame(self, text=" Package Status ")
        self.info_frame.pack(fill="x", padx=8, pady=4)

        self.lbl_torch = ttk.Label(self.info_frame, text="PyTorch: Checking...", font=("Helvetica", 9))
        self.lbl_torch.pack(anchor="w", padx=8, pady=2)

        self.lbl_keras = ttk.Label(self.info_frame, text="Keras: Checking...", font=("Helvetica", 9))
        self.lbl_keras.pack(anchor="w", padx=8, pady=2)

        # Run Tests Button
        self.btn_run = ttk.Button(self, text="Run Full Test Suite", command=self.start_tests_thread)
        self.btn_run.pack(pady=6)

        # Console Log Header
        ttk.Label(self, text="Execution Log:", font=("Helvetica", 9, "bold")).pack(anchor="w", padx=8)
        
        # Font size reduced to 7 to fit ~10% more content line-by-line
        self.txt_log = scrolledtext.ScrolledText(self, height=25, font=("Courier", 7))
        self.txt_log.pack(fill="both", expand=True, padx=8, pady=4)

    def log(self, message):
        """Helper to append text to the log window."""
        self.txt_log.insert(tk.END, message + "\n")
        self.txt_log.see(tk.END)

    def check_initial_imports(self):
        t_str = self.get_elapsed_str()
        self.log(f"{t_str} Checking imports...")
        
        # Check PyTorch
        try:
            import torch
            self.lbl_torch.config(text=f"PyTorch: v{torch.__version__}", foreground="green")
            self.log(f"{self.get_elapsed_str()} PyTorch v{torch.__version__} loaded successfully")
        except ImportError as e:
            self.lbl_torch.config(text="PyTorch: Not installed", foreground="red")
            self.log(f"{self.get_elapsed_str()} PyTorch import error: {e}")

        # Check Keras
        try:
            import keras
            self.lbl_keras.config(text=f"Keras: v{keras.__version__}", foreground="green")
            self.log(f"{self.get_elapsed_str()} Keras v{keras.__version__} loaded successfully")
        except ImportError as e:
            self.lbl_keras.config(text="Keras: Not installed", foreground="red")
            self.log(f"{self.get_elapsed_str()} Keras import error: {e}")

    def start_tests_thread(self):
        self.btn_run.config(state="disabled")
        threading.Thread(target=self.run_tests, daemon=True).start()

    def run_tests(self):
        self.log(f"\n{self.get_elapsed_str()} STARTING FULL TEST SUITE")

        # PYTORCH TESTS
        try:
            import torch
            
            # Test 1: Matrix Inverse
            self.log(f"{self.get_elapsed_str()} PyTorch Test 1/4 Matrix Operations")
            A = torch.tensor([[2.0, 1.0], [1.0, 4.0]])
            A_inv = torch.inverse(A)
            self.log(f"   Inverted matrix output:")
            for row in A_inv.numpy():
                self.log(f"   {row}")

            # Test 2: Autograd
            self.log(f"{self.get_elapsed_str()} PyTorch Test 2/4 Autograd Gradient Calculation")
            x = torch.tensor([3.0], requires_grad=True)
            y = x**3 + 2*x
            y.backward()
            self.log(f"   dy/dx at x=3 (expected 29.0): {x.grad.item()}")

            # Test 3: Linear Layer
            self.log(f"{self.get_elapsed_str()} PyTorch Test 3/4 Neural Network Linear Layer")
            lin = torch.nn.Linear(3, 1)
            inp = torch.randn(2, 3)
            out = lin(inp)
            self.log(f"   Output tensor shape: {out.shape}")

            # Test 4: Eigenvalues
            self.log(f"{self.get_elapsed_str()} PyTorch Test 4/4 Eigenvalue Decomposition")
            e_vals = torch.linalg.eigvals(A)
            self.log(f"   Eigenvalues: {e_vals.numpy()}")

        except Exception as e:
            self.log(f"{self.get_elapsed_str()} PyTorch Test Failed: {str(e)}")
            
        # KERAS TESTS
        try:
            import keras
            import numpy as np
            
            # Test 1: Sequential Model Creation
            self.log(f"{self.get_elapsed_str()} Keras Test 1/3 Building Sequential Model")
            model = keras.Sequential([
                keras.layers.Input(shape=(4,)),
                keras.layers.Dense(8, activation="relu"),
                keras.layers.Dense(1, activation="sigmoid")
            ])
            self.log(f"   Model created successfully with {model.count_params()} parameters")

            # Test 2: Model Compilation & Training
            self.log(f"{self.get_elapsed_str()} Keras Test 2/3 Model Compilation and Training")
            model.compile(optimizer="adam", loss="binary_crossentropy")
            
            X_train = np.random.random((32, 4))
            y_train = np.random.randint(2, size=(32, 1))
            
            history = model.fit(X_train, y_train, epochs=3, batch_size=16, verbose=0)
            final_loss = history.history['loss'][-1]
            self.log(f"   3 epochs training completed. Final loss: {final_loss:.4f}")

            # Test 3: Inference / Prediction
            self.log(f"{self.get_elapsed_str()} Keras Test 3/3 Model Prediction")
            X_test = np.random.random((2, 4))
            preds = model.predict(X_test, verbose=0)
            self.log(f"   Prediction results shape: {preds.shape}")
            for pred in preds:
                self.log(f"   Output probabilities: {pred}")

        except Exception as e:
            self.log(f"{self.get_elapsed_str()} Keras Test Failed: {str(e)}")

        self.log(f"\n{self.get_elapsed_str()} TEST SUITE COMPLETED SUCCESSFULLY")
        self.btn_run.config(state="normal")

if __name__ == "__main__":
    app = AppCheck()
    app.mainloop()

Friday, October 2, 2026

Python 3.13.16 : React frontend and python on Reflex Cloud.

Today, this simple test with artificial intelligence from reflex chat bot show how good and fast can be with one simple task.
Reflex compiles to a React frontend and a Starlette backend—the ASGI server that powers FastAPI. A familiar web stack, accessible to every Python developer. pandas, SQLAlchemy, scikit-learn, ...
After I ask to create a simple G.U.I. interface with all features from reflex, the chat bot result is this:
I built a one-page interactive playground that shows how a React-powered interface responds to Python state. Visitors can try five demos: a counter with event history, live preview controls, form validation, a searchable collection, and a dialog and toast.
Size: about 1,150 lines of Python across the page, four component modules, and four state modules. The integration section describes possibilities; it does not claim that external services are connected.
The interaction tests passed, and the page renders in the browser. I don’t have a reliable elapsed-time measurement for the build, so I can’t give an accurate creation time.
... the time of build was 4 minutes ...
Reflex comes with free features:
  • Publish 1 app on Reflex Cloud
  • Limited free usage for AI generation and hosting
  • Refills periodically
  • Public apps and public GitHub repos
  • App code download and file editing
  • Public sign-in with Reflex Auth
  • Managed database
See the result online : this webpage.

Tuesday, September 29, 2026

Python 3.13.13 : using webz.io with python.

The webz.io can be used with python:
import requests

response = requests.get(
    "https://api.webz.io/api/news?token=YOUR-TOKEN&q=%28category%3A%22economy%2C+business+and+finance%22+OR+category
    %3A%22war%2C+conflict+and+unrest%22+OR+category%3A%22science+and+technology%22+OR+category%3A%22disaster+and+accident%22
    +OR+category%3A%22environment%22+
    OR+category%3A%22labor%22%29&sort=crawled&ts=1790410006113&format=json&size=10&
    webz_reporter=true&includeSyndicated=false&allowNewsHistory=false",
    headers={"Accept": "application/json"},
)
print(response.json())

Monday, September 28, 2026

tkinter : testing RapidFuzz.

RapidFuzz is a fast and powerful Python library used for fuzzy string matching and similarity scoring. It is designed as a drop-in, high-performance alternative to the popular fuzzywuzzy library, offering significantly faster execution speeds because its core algorithms are implemented in C++ (via pybind11).
​What Can RapidFuzz Do?
​Calculate String Similarity:
It measures how similar two strings are using various mathematical distances (such as Levenshtein distance, Hamming distance, Jaro-Winkler, and Normalized Similarity metrics), returning a score typically ranging from 0 (completely different) to 100 (exact match).
​Smart Search & Extraction (process module):
You can query a list of items (such as filenames, database records, or user inputs) and instantly extract the best matches, even if the user query contains typos, misspellings, or partial words.
​Data Cleaning & Deduplication:
It helps clean messy datasets by grouping entries that represent the same entity despite slight spelling variations (e.g., matching "John Smith" with "Jon Smith").
​Lightweight & Efficient:
Unlike heavy deep learning frameworks, RapidFuzz has minimal dependencies and runs smoothly across different environments—making it ideal for desktop applications, servers, and mobile development environments like Pydroid 3.

Sunday, September 27, 2026

tkinter : fast image tool on pydroid3.

Today, one simple example fast tool for images:
Let's see this start source code:
# -*- coding: utf-8 -*-
"""Image Editor - consistent GUI sizes (Pydroid / Android)"""
import os
import shutil
import zipfile
from datetime import datetime
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, font as tkfont
from PIL import Image, ImageTk, ImageOps, ImageEnhance
VALID_EXTS = (".png", ".jpg", ".jpeg", ".bmp", ".webp", ".gif", ".tiff", ".tif")
def get_android_start_dir():
    candidates = [
        "/storage/emulated/0", "/sdcard",
        "/storage/emulated/0/Download", "/sdcard/Download",
        "/storage/emulated/0/DCIM", "/sdcard/DCIM",
        "/storage/emulated/0/Pictures", "/sdcard/Pictures",
        os.path.expanduser("\~"), "/",
    ]
    for path in candidates:
        if os.path.isdir(path) and os.access(path, os.R_OK):
            return path
    return os.getcwd()
...

Saturday, September 26, 2026

tkinter : basic portfolio for market with simulations ...

Today, one simple script tool for market. this allow to set one portofolio and use with simulations.
Let'see some screenshots:
The basic intro source code ...
import datetime
import json
import threading
import urllib.request
import tkinter as tk
from tkinter import ttk, messagebox

import matplotlib
matplotlib.use("TkAgg")
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


def fetch_yahoo_history(symbol, period_years=1):
    """Descarcă istoricul zilnic de pe Yahoo Finance."""
    end_date = int(datetime.datetime.now().timestamp())
    start_date = int((datetime.datetime.now() - datetime.timedelta(days=365 * period_years)).timestamp())
    
    url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}?period1={start_date}&period2={end_date}&interval=1d"
    req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
    
    try:
        with urllib.request.urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode("utf-8"))
            result = data["chart"]["result"][0]
            timestamps = result["timestamp"]
            closes = result["indicators"]["quote"][0]["close"]
            
            history = []
            for ts, cl in zip(timestamps, closes):
                if cl is not None:
                    dt = datetime.datetime.fromtimestamp(ts)
                    history.append((dt, float(cl)))
            return history
    except Exception as e:
        print(f"Eroare la descărcare {symbol}: {e}")
        return []
        ...

Thursday, September 24, 2026

News : OpenAI python library released.

The OpenAI Python library provides convenient access to the OpenAI REST API from any Python 3.10+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by HTTPX2.

Tuesday, July 28, 2026

Python : djxi Django library .

djxi is a Django library that eliminates the HTMX scattering problem: it bundles URL patterns, view logic, and HTML template sections for a feature into a single DXEndpointBattery class, keeping all related code in one place.

Monday, July 27, 2026

Python : KivyMD on pydroid android I.D.E.

This Python script is a cross-platform mobile application built with KivyMD, a Material Design framework extension for Python's Kivy library. It combines a declarative user interface layout defined via Kivy Language (KV string) with Python event handling to create an interactive task management dashboard tailored for Android environments like Pydroid 3.

Saturday, July 25, 2026

Python : simple educational planisphere

This Python script functions as an educational planisphere designed for telescope observation. Instead of taking a live snapshot of the current sky (where most events would be hidden below the horizon during the day or off-season), it calculates and displays the expected positions of major astronomical events through late 2026—such as meteor shower radiants and NEO asteroid flybys—relative to Fălticeni, Romania (47.46^\circ\text{ N}, 26.30^\circ\text{ E}).
Oriented with North at the top, the code converts equatorial coordinates (Right Ascension and Declination) into local horizon coordinates (Azimuth and Altitude). It then projects these targets onto a 2D polar plot, indicating the cardinal direction (N, E, S, W) to point your telescope and labeling each event with its peak date and estimated rise time, before automatically exporting the chart as a high-resolution PNG image to your device's Download folder.
Let's see source code:
import os
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime, timezone

def draw_and_save_sky_map():
    # Coordonate Fălticeni, România
    LAT = 47.46
    LON = 26.30

    # Calendarul evenimentelor până la sfârșitul anului 2026
    events = [
        {
            'name': 'Perseide (Vârf)',
            'date_str': '12 Aug',
            'rise_time': '22:00',
            'ra': 3.07, 'dec': 58.0,
            'color': '#00ffcc', 'marker': '*'
        },
        {
            'name': 'Orionide (Vârf)',
            'date_str': '21 Oct',
            'rise_time': '23:30',
            'ra': 6.34, 'dec': 16.0,
            'color': '#ff9900', 'marker': '*'
        },
        {
            'name': 'Leonide (Vârf)',
            'date_str': '17 Noi',
            'rise_time': '00:15',
            'ra': 10.2, 'dec': 22.0,
            'color': '#ff3366', 'marker': '*'
        },
        {
            'name': 'Geminide (Vârf)',
            'date_str': '13 Dec',
            'rise_time': '20:30',
            'ra': 7.46, 'dec': 33.0,
            'color': '#ffff00', 'marker': '*'
        },
        {
            'name': 'Asteroid NEO 2026',
            'date_str': 'Toamnă 2026',
            'rise_time': '21:00',
            'ra': 14.5, 'dec': 10.0,
            'color': '#ff00ff', 'marker': 's'
        }
    ]

    # Calcul Timp Sidereal Local (LST)
    now_utc = datetime.now(timezone.utc)
    j2000_epoch = datetime(2000, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
    days_since_j2000 = (now_utc - j2000_epoch).total_seconds() / 86400.0
    lst = (18.697374558 + 24.06570982441908 * days_since_j2000 + LON / 15.0) % 24

    # Creare grafic Matplotlib (Polar)
    fig = plt.figure(figsize=(8, 8), facecolor='#0b0d17')
    ax = fig.add_subplot(111, polar=True, facecolor='#05070f')

    # Orientare fixă: NORDUL SUS (0°)
    ax.set_theta_zero_location('N') 
    ax.set_theta_direction(-1)      
    ax.set_rlim(0, 90)              
    ax.set_yticklabels([])

    lat_rad = np.radians(LAT)

    for item in events:
        ha = (lst - item['ra']) * 15.0
        ha_rad = np.radians(ha)
        dec_rad = np.radians(item['dec'])

        sin_alt = np.sin(dec_rad) * np.sin(lat_rad) + np.cos(dec_rad) * np.cos(lat_rad) * np.cos(ha_rad)
        alt = np.degrees(np.arcsin(np.clip(sin_alt, -1.0, 1.0)))

        if alt <= 5:
            alt = 35.0  

        cos_az = (np.sin(dec_rad) - np.sin(lat_rad) * sin_alt) / (np.cos(lat_rad) * np.sin(np.arccos(sin_alt)))
        az = np.degrees(np.arccos(np.clip(cos_az, -1.0, 1.0)))
        if np.sin(ha_rad) > 0:
            az = 360 - az

        theta = np.radians(az)
        r = 90 - alt

        ax.plot(theta, r, marker=item['marker'], markersize=12, color=item['color'])
        label_text = f"{item['name']}\n[{item['date_str']}]\nRăsare ~{item['rise_time']}"
        ax.text(theta, r + 7, label_text, color=item['color'], 
                fontsize=7.5, ha='center', fontweight='bold')

    cardinals = [('NORD (0°)', 0), ('EST (90°)', 90), ('SUD (180°)', 180), ('VEST (270°)', 270)]
    for label, angle in cardinals:
        ax.text(np.radians(angle), 102, label, color='white', fontsize=9, fontweight='bold', ha='center', va='center')

    ax.set_title("HARTĂ EVENIMENTE ASTRONOMICE 2026 (Aug - Dec)\nLocație: Fălticeni | Orientare: Nordul Sus\n", 
                 color='white', fontsize=9, pad=15)

    ax.grid(color='#1a233a', linestyle=':', linewidth=0.8)
    plt.tight_layout()

    # --- SALVARE IMAGINE ÎN FOLDERUL DOWNLOAD ---
    download_path = "/sdcard/Download"
    
    # Alternativă în caz că calea /sdcard nu este mapată la fel pe unele versiuni de Android
    if not os.path.exists(download_path):
        download_path = os.path.expanduser("~/storage/downloads")

    file_name = f"harta_astronomica_2026_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
    full_path = os.path.join(download_path, file_name)

    try:
        plt.savefig(full_path, dpi=300, facecolor=fig.get_facecolor(), edgecolor='none')
        print(f" Imaginea a fost salvată cu succes la:\n{full_path}")
    except Exception as e:
        print(f" Eroare la salvarea fișierului: {e}")

    plt.show()

if __name__ == "__main__":
    draw_and_save_sky_map()

Tuesday, July 21, 2026

Python 3.10.11 : testing default example with the pyui-0.1.0 python module.

A declarative, cross-platform GUI framework (ala SwiftUI) written in Python using SDL2. It provides tools and libraries that enable developers to create and manage user interfaces for desktop apps.
You need to install the pyui python module and the SDK with the pip tool.
python -m pip install pyui
Collecting pyui
  Downloading pyui-0.1.0-py3-none-any.whl.metadata (893 bytes)
Collecting PySDL2>=0.9.7 (from pyui)
  Downloading PySDL2-0.9.17-py3-none-any.whl.metadata (3.8 kB)
Downloading pyui-0.1.0-py3-none-any.whl (6.0 MB)
   ---------------------------------------- 6.0/6.0 MB 6.0 MB/s  0:00:01
Downloading PySDL2-0.9.17-py3-none-any.whl (583 kB)
   ---------------------------------------- 583.1/583.1 kB 2.1 MB/s  0:00:00
Installing collected packages: PySDL2, pyui
Successfully installed PySDL2-0.9.17 pyui-0.1.0
python -m pip install pysdl2-dll
Collecting pysdl2-dll
  Downloading pysdl2_dll-2.32.10-py2.py3-none-win_amd64.whl.metadata (4.7 kB)
Downloading pysdl2_dll-2.32.10-py2.py3-none-win_amd64.whl (4.1 MB)
   ---------------------------------------- 4.1/4.1 MB 4.1 MB/s  0:00:01
Installing collected packages: pysdl2-dll
Successfully installed pysdl2-dll-2.32.10
Let's see the default example with one grid.
Let's see the source code:
import pyui

class ItemGridView(pyui.View):
    def content(self):
        yield pyui.ScrollView(axis=self.axis)(
            pyui.Grid(num=self.num, size=self.size, axis=self.axis, flex=self.flex)(
                pyui.ForEach(
                    range(self.item_count),
                    lambda num: (
                        pyui.Rectangle()(pyui.Text(num + 1).color(255, 255, 255))
                        .background(120, 120, 120)
                        .radius(5)
                        .animate()
                    ),
                )
            )
        )

class GridTest(pyui.View):
    axis = pyui.State(default=1)
    item_count = pyui.State(int, default=50)
    size = pyui.State(default=100)
    num = pyui.State(default=4)
    size_or_num = pyui.State(default=0)
    flex = pyui.State(default=False)

    def content(self):
        if self.size_or_num.value == 0:
            size = None
            num = self.num.value
        else:
            size = self.size.value
            num = None
        yield pyui.HStack(alignment=pyui.Alignment.LEADING)(
            pyui.VStack(alignment=pyui.Alignment.LEADING)(
                pyui.Text("Axis"),
                pyui.SegmentedButton(self.axis)(
                    pyui.Text(pyui.Axis.HORIZONTAL.name),
                    pyui.Text(pyui.Axis.VERTICAL.name),
                ),
                pyui.HStack(
                    pyui.Text("Number of items"),
                    pyui.Spacer(),
                    pyui.Text(self.item_count.value)
                    .color(128, 128, 128)
                    .priority("high"),
                ),
                pyui.Slider(self.item_count, maximum=200),
                pyui.Text("Fill rows/columns by"),
                pyui.SegmentedButton(self.size_or_num)(
                    pyui.Text("Number"),
                    pyui.Text("Size"),
                ),
                pyui.HStack(
                    pyui.Text("Items per row/column"),
                    pyui.Spacer(),
                    pyui.Text(self.num.value).color(128, 128, 128).priority("high"),
                ),
                pyui.Slider(self.num, minimum=1, maximum=10).disable(
                    self.size_or_num.value == 1
                ),
                pyui.HStack(
                    pyui.Text("Item size"),
                    pyui.Spacer(),
                    pyui.Text(self.size.value).color(128, 128, 128).priority("high"),
                ),
                pyui.Slider(self.size, minimum=50, maximum=200).disable(
                    self.size_or_num.value == 0
                ),
                pyui.Toggle(self.flex, label="Adjust size to fit").disable(
                    self.size_or_num.value == 0
                ),
            )
            .padding(10)
            .size(width=300),
            ItemGridView(
                item_count=self.item_count.value,
                size=size,
                num=num,
                axis=self.axis.value,
                flex=self.flex.value,
            ),
        )

if __name__ == "__main__":
    app = pyui.Application("io.temp.GridTest")
    app.window("Grid Tester", GridTest())
    app.run()

Saturday, July 18, 2026

Python Qt : testing Browserless.io feature ...

The provided PyQt6 application is a desktop tool that allows a user to input any website address and instantly obtain a full‑page screenshot of that site using the Browserless.io cloud rendering service; the program begins by creating a simple graphical interface composed of a text field for entering a URL, a button that triggers the screenshot process, and a display area where the resulting image is shown, all arranged vertically for clarity and ease of use. When the user presses the button, the application reads the typed URL, constructs a request to the Browserless screenshot API using the user’s authentication token, and sends a JSON payload instructing Browserless to load the page and capture it in full, not just the visible viewport. Browserless processes the request by launching a headless Chromium instance, navigating to the specified website, rendering the page completely—including dynamic content—and returning a PNG image representing the entire scrollable webpage. The application receives this binary PNG data through an HTTP response, converts it into a QPixmap object, and displays it directly inside the PyQt window, effectively turning the GUI into a live screenshot viewer. This design allows developers to visually inspect websites without embedding a browser engine locally, relying instead on Browserless’s remote infrastructure to handle rendering, JavaScript execution, and screenshot generation. The code is intentionally minimal, focusing on clarity and functionality: it uses only standard PyQt widgets, avoids unnecessary complexity, and demonstrates how to integrate cloud‑based browser automation into a Python desktop application. The result is a lightweight tool that can preview websites, capture full‑page screenshots, and serve as a foundation for more advanced features such as zooming, saving images, asynchronous loading, or automated website testing workflows.
This script was created with copilot artificial intelligence, and tested by me.
import sys
import requests
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QPushButton, QLabel
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt

# PUNE TOKEN-UL TAU AICI, CA STRING
BROWSERLESS_TOKEN = "fill_TOKEN_official__website"

class BrowserlessViewer(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Browserless Web Screenshot Viewer")
        self.resize(900, 700)

        layout = QVBoxLayout(self)

        self.url_edit = QLineEdit()
        self.url_edit.setPlaceholderText("Introdu adresa web...")
        layout.addWidget(self.url_edit)

        self.btn = QPushButton("Generează Screenshot")
        self.btn.clicked.connect(self.take_screenshot)
        layout.addWidget(self.btn)

        self.canvas = QLabel()
        self.canvas.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(self.canvas)

    def take_screenshot(self):
        url = self.url_edit.text().strip()
        if not url:
            return

        api_url = f"https://chrome.browserless.io/screenshot?token={BROWSERLESS_TOKEN}"

        payload = {
            "url": url,
            "options": {
                "fullPage": True
            }
        }

        try:
            r = requests.post(api_url, json=payload)
            r.raise_for_status()

            pixmap = QPixmap()
            pixmap.loadFromData(r.content)
            self.canvas.setPixmap(pixmap)

        except Exception as e:
            print("Eroare:", e)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    viewer = BrowserlessViewer()
    viewer.show()
    sys.exit(app.exec())

Wednesday, July 8, 2026

Python Qt : Script for Game Engine projects.

Simple python example script for Godot Engine projects.
This script allows you to see how big is the project, size of media files, size of scripting files, lines of source code and more:
import sys
import os
import pathlib
import datetime
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout,
    QPushButton, QTextEdit, QProgressBar, QFileDialog, QMessageBox
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal

def human_size(num_bytes: int) -> str:
    units = ["B", "KB", "MB", "GB", "TB"]
    size = float(num_bytes)
    for unit in units:
        if size < 1024.0:
            return f"{size:.2f} {unit}"
        size /= 1024.0
    return f"{size:.2f} PB"

class FolderStatsWorker(QThread):
    progress = pyqtSignal(int)
    finished = pyqtSignal(str)

    def __init__(self, folder_path: str):
        super().__init__()
        self.folder_path = folder_path

    def run(self):
        base = pathlib.Path(self.folder_path)

        all_files = []
        for root, dirs, files in os.walk(base):
            for name in files:
                all_files.append(pathlib.Path(root) / name)

        total_files = len(all_files)
        gd_files = []
        media_files = []
        total_lines_gd = 0

        media_exts = {
            ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp",
            ".ogg", ".wav", ".mp3", ".flac",
            ".mp4", ".mkv", ".avi", ".webm",
            ".md"
        }

        total_size = 0
        gd_size = 0
        media_size = 0

        tree_lines = []

        # Build tree view
        for root, dirs, files in os.walk(base):
            rel_root = pathlib.Path(root).relative_to(base)
            indent_level = len(rel_root.parts)
            indent = "    " * indent_level
            tree_lines.append(f"{indent}{rel_root if rel_root.parts else base.name}/")
            for name in files:
                tree_lines.append(f"{indent}    {name}")

        for idx, f in enumerate(all_files):
            try:
                stat = f.stat()
                total_size += stat.st_size
                ext = f.suffix.lower()

                if ext == ".gd":
                    gd_files.append(f)
                    gd_size += stat.st_size
                    try:
                        txt = f.read_text(encoding="utf-8", errors="ignore")
                        if txt:
                            total_lines_gd += txt.count("\n") + 1
                    except Exception:
                        pass

                if ext in media_exts:
                    media_files.append(f)
                    media_size += stat.st_size

            except Exception:
                pass

            if total_files > 0:
                self.progress.emit(int((idx + 1) * 100 / total_files))

        report_lines = []
        report_lines.append(f"Folder: {self.folder_path}")
        report_lines.append("")
        report_lines.append("=== Summary ===")
        report_lines.append(f"Total files: {total_files}")
        report_lines.append(f"Total .gd files: {len(gd_files)}")
        report_lines.append(f"Total media files (incl. .md): {len(media_files)}")
        report_lines.append(f"Total lines in .gd files: {total_lines_gd}")
        report_lines.append("")
        report_lines.append(f"Total size: {human_size(total_size)}")
        report_lines.append(f"Total .gd size: {human_size(gd_size)}")
        report_lines.append(f"Total media size: {human_size(media_size)}")
        report_lines.append("")
        report_lines.append("=== Tree ===")
        report_lines.extend(tree_lines)

        report_text = "\n".join(report_lines)

        # Save report
        now = datetime.datetime.now()
        ts = now.strftime("%Y%m%d_%H%M%S")
        folder_name = base.name
        report_name = f"{folder_name}_{ts}.txt"
        report_path = base / report_name
        try:
            report_path.write_text(report_text, encoding="utf-8")
        except Exception:
            pass

        self.finished.emit(report_text)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Godot Project Stats")
        self.setFixedSize(640, 480)

        self.folder_path = None
        self.worker = None

        central = QWidget()
        layout = QVBoxLayout(central)

        self.btn_open = QPushButton("Open Folder")
        self.btn_process = QPushButton("Process")
        self.progress = QProgressBar()
        self.progress.setRange(0, 100)
        self.text = QTextEdit()
        self.text.setReadOnly(True)

        layout.addWidget(self.btn_open)
        layout.addWidget(self.btn_process)
        layout.addWidget(self.progress)
        layout.addWidget(self.text)

        self.setCentralWidget(central)

        self.btn_open.clicked.connect(self.open_folder)
        self.btn_process.clicked.connect(self.start_processing)

    def open_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "Select Godot Project Folder")
        if folder:
            self.folder_path = folder
            self.text.clear()
            self.text.append(f"Selected folder:\n{folder}")

    def start_processing(self):
        if not self.folder_path:
            QMessageBox.warning(self, "No folder", "Please select a folder first.")
            return

        if self.worker is not None and self.worker.isRunning():
            QMessageBox.information(self, "Processing", "Already processing.")
            return

        self.progress.setValue(0)
        self.text.append("\nProcessing...")

        self.worker = FolderStatsWorker(self.folder_path)
        self.worker.progress.connect(self.progress.setValue)
        self.worker.finished.connect(self.on_finished)
        self.worker.start()

    def on_finished(self, report_text: str):
        self.text.clear()
        self.text.append(report_text)
        self.progress.setValue(100)
def main():
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec())
if __name__ == "__main__":
    main()