analitics

Pages

Showing posts with label package. Show all posts
Showing posts with label package. Show all posts

Thursday, October 8, 2026

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

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()

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 []
        ...

Monday, September 21, 2026

tkinter : simple marshmallow demo.

About the marshmallow package
  • It checks if your data has the correct fields.
  • It verifies that each field has the right type.
  • It helps you validate JSON before using it.
  • It can convert Python data into clean JSON.
About your this source code:
  • It loads the marshmallow package when the app starts.
  • It reads the JSON you type in the input box.
  • It tries to convert that text into Python data.
  • It validates the data using your marshmallow schema.
  • It shows the result or the error directly in the output box.
  • It does not use print or message boxes.
Why this tool is useful
  • You can test JSON visually.
  • You can see validation errors instantly.
  • You avoid console output.
  • You keep everything inside the GUI.
Let's see the sourve code:
import json
import tkinter as tk
from tkinter import ttk

# ------------------ Package Load Test ------------------

try:
    from marshmallow import Schema, fields, ValidationError
    package_status = "Package marshmallow loaded successfully."
except Exception as e:
    package_status = "PACKAGE LOAD ERROR: " + str(e)


# ------------------ Marshmallow Schema ------------------

class PersonSchema(Schema):
    full_name = fields.Str(required=True)
    city = fields.Str(required=True)
    birth_date = fields.Date(required=True)
    nicknames = fields.List(fields.Str(), required=True)


schema = PersonSchema()


# ------------------ Tkinter UI ------------------

def process_json():
    raw = editor.get("1.0", tk.END).strip()

    output.delete("1.0", tk.END)

    # Step 1: package status
    output.insert(tk.END, package_status + "\n\n")

    # Step 2: show raw JSON
    output.insert(tk.END, "RAW JSON RECEIVED:\n" + raw + "\n\n")

    # Step 3: JSON parsing
    try:
        data = json.loads(raw)
        output.insert(tk.END, "JSON PARSED OK.\n\n")
    except Exception as e:
        output.insert(tk.END, "JSON ERROR:\n" + str(e))
        return

    # Step 4: Marshmallow validation
    try:
        result = schema.dump(data)
        output.insert(tk.END, "SCHEMA VALIDATION OK.\n\n")
    except ValidationError as e:
        output.insert(tk.END, "SCHEMA ERROR:\n" + json.dumps(e.messages, indent=2))
        return

    # Step 5: Final result
    output.insert(tk.END, "FINAL RESULT:\n" + json.dumps(result, indent=2))


root = tk.Tk()
root.title("Marshmallow Diagnostic Full Output")
root.geometry("750x550")

frm = ttk.Frame(root, padding=10)
frm.pack(fill="both", expand=True)

ttk.Label(frm, text="JSON Input:").pack(anchor="w")

editor = tk.Text(frm, height=14, width=90)
editor.pack(fill="x")

editor.insert(
    tk.END,
    json.dumps(
        {
            "full_name": "Catalin George Festila",
            "city": "Falticeni",
            "birth_date": "1976-03-07",
            "nicknames": ["catafest", "mythcat"]
        },
        indent=2
    )
)

ttk.Button(frm, text="Run", command=process_json).pack(pady=10)

ttk.Label(frm, text="Output:").pack(anchor="w")

output = tk.Text(frm, height=14, width=90)
output.pack(fill="both", expand=True)

root.mainloop()

Saturday, September 12, 2026

News : Real-Time Stock & ETF Analyzer in using tvscreener and Tkinter and pydroid3.

The tvscreener is a lightweight Python library designed to extract and analyze real-time financial data directly from TradingView's API without requiring paid API keys or complex authentication. It provides quick access to technical indicators, fundamental metrics, historical performance, and volume data for international stocks and ETFs. Explore the source code and documentation on the official tvscreener GitHub repository. The script provides a desktop interface (Tkinter GUI) powered by tvscreener logic to query market data on demand. This allow to choose a ticker symbol from the dropdown list (such as GOOGL, NVDA, AAPL, or ETFs like VUAA). Clicking Check triggers a background HTTP request without freezing the user interface, while displaying real-time progress via the progress bar. The script formats the API response into four core metric categories: Performance, Technical Indicators, Fundamentals, and Volume and Liquidity. Clicking Copy transfers the complete output directly to your system clipboard for quick sharing or note-taking.

Tuesday, August 25, 2026

tkinter : three algorithms for yahoo market with pydroid 3.

The script retrieves historical closing-price data for NVDA and VUAA.AS directly from Yahoo Finance.
First tab displays a candlestick chart for the selected time range. Two Simple Moving Averages are calculated automatically; their periods adapt to the chosen interval (for example SMA 5/10 on short ranges and SMA 50/200 on longer ones) and are shown in the legend. Clear dates appear on the horizontal axis.
Its second tab, ML Predictions, focuses on statistical modelling. The downloaded series is fitted with three algorithms: ordinary linear regression, polynomial regression (degree adjustable by the user), and a Random Forest regressor. All four lines—the original prices plus the three model outputs—are plotted on a single chart. Clear calendar dates appear on the horizontal axis, and an enlarged legend identifies each curve. Loading feedback is shown while data are fetched. The tab therefore converts raw Yahoo price history into immediate visual comparisons of linear, non-linear and ensemble trend estimates.

Monday, August 24, 2026

tkinter : python manager with pydroid 3.

The script is a lightweight package manager for Pydroid 3, built with Tkinter, designed to help you inspect, back up, and restore your Python environment on Android. It reads all installed packages using importlib.metadata, which works reliably in Pydroid 3, and displays them in a scrollable text area. A Check button scans the environment and lists every package with its version, while a Copy button places that list into the clipboard for quick sharing or documentation. The Save function opens a dialog and writes all detected packages into a Requirements.txt file, typically stored in the Download folder, allowing you to preserve the exact state of your environment. The Load function opens a file dialog, reads a requirements file, compares each entry with the currently installed packages, and installs only the missing or outdated ones using pip. Every operation updates a progress bar so you can see how many items have been processed. Overall, the script acts as a practical tool for backing up, restoring, and synchronizing Python packages on Pydroid 3, where traditional virtual environments and desktop-style package managers are not available.

Sunday, August 16, 2026

tkinter : test colorchooser script on pydroid 3.

Learn how to use the Python Tkinter colorchooser module to create interactive graphical interfaces. This simple script opens a native color picker dialog and instantly updates your application interface based on user selection.
How the Python script functions:
The colorchooser module is imported to launch the native system palette window.
The askcolor function runs when triggered and waits for user input.
The script extracts the returned HEX color code from the selection.
The main window background and label text update immediately with the chosen color.
This lightweight code provides a simple way to add dynamic customization to desktop applications without installing external libraries.
Let's see the source code:
import tkinter as tk
from tkinter import colorchooser

def choose_color():
    # Opens the color picker dialog and returns a tuple: ((R, G, B), "#HEX")
    color = colorchooser.askcolor(title="Choose a Background Color")
    
    # Check if the user selected a color (didn't click Cancel)
    if color[1]: 
        hex_code = color[1]
        root.config(bg=hex_code)
        label_color.config(text=f"HEX Code: {hex_code}", bg=hex_code)

# Create the main window
root = tk.Tk()
root.title("Tkinter Colorchooser Example")
root.geometry("300x200")

# Button to trigger the color chooser dialog
btn_choose = tk.Button(root, text="Select Color", command=choose_color)
btn_choose.pack(pady=30)

# Label to display the chosen HEX code
label_color = tk.Label(root, text="No color selected", font=("Arial", 12))
label_color.pack(pady=10)

root.mainloop()

Thursday, August 13, 2026

tkinter : simple tool for converting source code for blogger.

This tool helps you safely prepare source code for publishing on Blogger. You paste your code, press the convert button, and the app instantly transforms it into a format that displays correctly without being interpreted or altered by the platform. It keeps your code clean, readable, and protected. After conversion, you can copy the final result and insert it directly into your blog. It’s a fast and reliable solution for developers who want to share code snippets online.
import html
import tkinter as tk
from tkinter import ttk, messagebox

def paste_from_clipboard():
    try:
        text_input.insert(tk.INSERT, root.clipboard_get())
    except Exception:
        try:
            text_input.focus_set()
            text_input.event_generate("<<Paste>>")
        except Exception:
            pass

def process_code():
    raw_code = text_input.get("1.0", tk.END).strip()
    if not raw_code:
        return

    try:
        # 1. Escapam caracterele speciale HTML (<, >, &, ")
        escaped_code = html.escape(raw_code)

        # 2. Includem codul convertit in structura div -> pre -> code
        formatted_result = f"<div><pre><code>{escaped_code}</code></pre></div>"

        # 3. Afisam rezultatul
        text_output.config(state=tk.NORMAL)
        text_output.delete("1.0", tk.END)
        text_output.insert(tk.END, formatted_result)
        text_output.config(state=tk.DISABLED)
    except Exception as e:
        messagebox.showerror("Eroare", f"A aparut o eroare la conversie: {e}")

def copy_to_clipboard():
    cleaned_text = text_output.get("1.0", tk.END).strip()
    if cleaned_text:
        try:
            root.clipboard_clear()
            root.clipboard_append(cleaned_text)
            messagebox.showinfo("OK", "Copiat in clipboard!")
        except Exception as e:
            messagebox.showerror("Eroare", f"Nu s-a putut copia: {e}")

def clear_all():
    text_input.delete("1.0", tk.END)
    text_output.config(state=tk.NORMAL)
    text_output.delete("1.0", tk.END)
    text_output.config(state=tk.DISABLED)

# Constructie Interfata
root = tk.Tk()
root.title("Code Escaper for Blogger")
root.geometry("400x600")

# Input
lbl1 = ttk.Label(root, text="1. Cod Sursa de Convertit:")
lbl1.pack(anchor="w", padx=10, pady=(10, 0))

frame_btns = ttk.Frame(root)
frame_btns.pack(fill=tk.X, padx=10, pady=5)

btn_paste = ttk.Button(frame_btns, text="Lipeste (Paste)", command=paste_from_clipboard)
btn_paste.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))

btn_clear = ttk.Button(frame_btns, text="Sterge", command=clear_all)
btn_clear.pack(side=tk.RIGHT)

text_input = tk.Text(root, height=8)
text_input.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

# Procesare
btn_process = ttk.Button(root, text="Converteste pentru Blogger", command=process_code)
btn_process.pack(fill=tk.X, padx=10, pady=5)

# Output
lbl2 = ttk.Label(root, text="2. Rezultat de pus in Blogger:")
lbl2.pack(anchor="w", padx=10, pady=(5, 0))

text_output = tk.Text(root, height=8, state=tk.DISABLED)
text_output.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

btn_copy = ttk.Button(root, text="Copiaza Rezultatul", command=copy_to_clipboard)
btn_copy.pack(fill=tk.X, padx=10, pady=(5, 10))

root.mainloop()

Monday, August 10, 2026

tkinter : clean html source code with pydroid 3.

This script is an automated HTML cleaner designed to optimize web content for SEO, specifically tailored for HTML code generated by Blogger image uploads. By removing inline style attributes, CSS style blocks, and class parameters, it cleans clutter to improve the code-to-text ratio, enhancing page loading speed-a key ranking factor.
It strips anchor tags while preserving their internal content, eliminating unwanted external links or internal link equity leaks.
By keeping only structural tags like div and img, it produces lightweight, clean HTML markup that search engine crawlers can index and parse easily.
Let's see the source code:
import tkinter as tk
from tkinter import ttk, messagebox
from bs4 import BeautifulSoup

def paste_from_clipboard():
    try:
        text_input.insert(tk.INSERT, root.clipboard_get())
    except Exception:
        try:
            text_input.focus_set()
            text_input.event_generate("<<Paste>>")
        except Exception:
            pass

def process_html():
    raw_html = text_input.get("1.0", tk.END).strip()
    if not raw_html:
        return

    try:
        soup = BeautifulSoup(raw_html, "html.parser")

        # 1. Eliminare completă tag-uri style și script
        for tag in soup.find_all(["style", "script"]):
            tag.decompose()

        # 2. Eliminare ancore (<a>) și păstrare conținut
        for a_tag in soup.find_all("a"):
            a_tag.unwrap()

        # 3. Eliminare atribute 'style' și 'class' de pe TOATE elementele
        attributes_to_remove = ["style", "class"]
        for tag in soup.find_all(True):
            for attr in attributes_to_remove:
                if attr in tag.attrs:
                    del tag.attrs[attr]

        cleaned_html = str(soup)

        text_output.config(state=tk.NORMAL)
        text_output.delete("1.0", tk.END)
        text_output.insert(tk.END, cleaned_html)
        text_output.config(state=tk.DISABLED)
    except Exception as e:
        messagebox.showerror("Eroare", f"A aparut o eroare la procesare: {e}")

def copy_to_clipboard():
    cleaned_text = text_output.get("1.0", tk.END).strip()
    if cleaned_text:
        try:
            root.clipboard_clear()
            root.clipboard_append(cleaned_text)
            messagebox.showinfo("OK", "Copiat in clipboard!")
        except Exception as e:
            messagebox.showerror("Eroare", f"Nu s-a putut copia: {e}")

def clear_all():
    text_input.delete("1.0", tk.END)
    text_output.config(state=tk.NORMAL)
    text_output.delete("1.0", tk.END)
    text_output.config(state=tk.DISABLED)

# Constructie Interfata
root = tk.Tk()
root.title("HTML Cleaner")
root.geometry("400x600")

# Input
lbl1 = ttk.Label(root, text="1. Sursa HTML:")
lbl1.pack(anchor="w", padx=10, pady=(10, 0))

frame_btns = ttk.Frame(root)
frame_btns.pack(fill=tk.X, padx=10, pady=5)

btn_paste = ttk.Button(frame_btns, text="Lipeste (Paste)", command=paste_from_clipboard)
btn_paste.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))

btn_clear = ttk.Button(frame_btns, text="Sterge", command=clear_all)
btn_clear.pack(side=tk.RIGHT)

text_input = tk.Text(root, height=8)
text_input.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

# Procesare
btn_process = ttk.Button(root, text="Proceseaza HTML", command=process_html)
btn_process.pack(fill=tk.X, padx=10, pady=5)

# Output
lbl2 = ttk.Label(root, text="2. Rezultat Curatat:")
lbl2.pack(anchor="w", padx=10, pady=(5, 0))

text_output = tk.Text(root, height=8, state=tk.DISABLED)
text_output.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

btn_copy = ttk.Button(root, text="Copiaza Rezultatul", command=copy_to_clipboard)
btn_copy.pack(fill=tk.X, padx=10, pady=(5, 10))

root.mainloop()

Sunday, August 9, 2026

tkinter : Acode.log Viewer and Clipboard Tool on Pydroid 3

This Python script creates a clean graphical user interface (GUI) using Tkinter, specifically designed to run inside Pydroid 3 on Android devices. Its main purpose is to automatically locate, open, and display the content of the Acode.log file generated by the popular Acode code editor app.
The program checks several common storage paths used by both the free and paid versions of Acode. Once the log file is found, the full content is loaded into a scrollable text area with horizontal and vertical scrollbars for easy reading of long log files. The complete file path, file size in KB, and total number of lines are shown clearly in the status bar at the bottom of the window.
Users can interact with the application through a simple File menu that includes three essential options: Reload (to refresh the log content), Copy All (to copy the entire log text to the system clipboard with one click), and Exit. Keyboard shortcuts (Ctrl+R, Ctrl+C, Ctrl+Q) are also supported for faster operation. The script handles missing files and read errors gracefully, displaying clear status messages and helpful guidance when the log cannot be located or accessed. It uses UTF-8 encoding with error replacement to ensure special characters do not break the display.
Ideal for Android developers and Acode users who need a fast, lightweight way to inspect application logs directly on their device without leaving the Pydroid 3 environment. The pure Tkinter interface requires no external libraries, making it fully compatible with Pydroid 3 out of the box.
Let's see the source code:
import tkinter as tk
from tkinter import scrolledtext, messagebox, ttk
import os

# Possible paths for Acode.log (paid + free version)
POSSIBLE_PATHS = [
    "/storage/emulated/0/Android/data/com.foxdebug.acode/files/Acode.log",
    "/storage/emulated/0/Android/data/com.foxdebug.acode.free/files/Acode.log",
    "/storage/emulated/0/Android/data/com.foxdebug.acode/files/logs/Acode.log",
    "/storage/emulated/0/Android/data/com.foxdebug.acode.free/files/logs/Acode.log",
    "/sdcard/Android/data/com.foxdebug.acode/files/Acode.log",
    "/sdcard/Android/data/com.foxdebug.acode.free/files/Acode.log",
]

class AcodeLogViewer:
    def __init__(self, root):
        self.root = root
        self.root.title("Acode.log Viewer - Pydroid 3")
        self.root.geometry("900x650")
        self.root.minsize(600, 400)

        self.found_path = None
        self.file_content = ""

        self.create_menu()
        self.create_widgets()
        self.search_and_load()

    def create_menu(self):
        """Create the main application menu."""
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)

        # File menu
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=file_menu)
        file_menu.add_command(label="Reload", command=self.search_and_load, accelerator="Ctrl+R")
        file_menu.add_command(label="Copy All", command=self.copy_to_clipboard, accelerator="Ctrl+C")
        file_menu.add_separator()
        file_menu.add_command(label="Exit", command=self.root.quit, accelerator="Ctrl+Q")

        # Keyboard shortcuts
        self.root.bind("", lambda e: self.search_and_load())
        self.root.bind("", lambda e: self.copy_to_clipboard())
        self.root.bind("", lambda e: self.root.quit())

    def create_widgets(self):
        # Text area with scrollbars
        text_frame = ttk.Frame(self.root, padding=8)
        text_frame.pack(fill=tk.BOTH, expand=True)

        self.text_area = scrolledtext.ScrolledText(
            text_frame,
            wrap=tk.NONE,
            font=("Courier New", 10),
            state=tk.DISABLED
        )
        self.text_area.pack(fill=tk.BOTH, expand=True)

        # Horizontal scrollbar
        h_scroll = ttk.Scrollbar(text_frame, orient=tk.HORIZONTAL, command=self.text_area.xview)
        h_scroll.pack(fill=tk.X)
        self.text_area.configure(xscrollcommand=h_scroll.set)

        # Status bar – displays the found file path
        self.status_var = tk.StringVar(value="Ready.")
        status_bar = ttk.Label(
            self.root,
            textvariable=self.status_var,
            relief=tk.SUNKEN,
            anchor=tk.W,
            padding=(6, 3)
        )
        status_bar.pack(fill=tk.X, side=tk.BOTTOM)

    def search_and_load(self):
        self.found_path = None
        self.file_content = ""

        for path in POSSIBLE_PATHS:
            if os.path.isfile(path):
                self.found_path = path
                break

        if self.found_path is None:
            self.status_var.set("Acode.log file not found in the known locations.")
            self.display_text(
                "The Acode.log file could not be located.\n\n"
                "Please verify that the Acode application has already generated the log "
                "and that Pydroid 3 has storage access permissions."
            )
            return

        try:
            with open(self.found_path, "r", encoding="utf-8", errors="replace") as f:
                self.file_content = f.read()

            size_kb = len(self.file_content.encode("utf-8")) / 1024
            lines = len(self.file_content.splitlines())

            # Full path + additional information in the status bar
            self.status_var.set(
                f"{self.found_path}  •  {size_kb:.1f} KB  •  {lines} lines"
            )
            self.display_text(self.file_content)

        except Exception as e:
            self.status_var.set(f"Error reading file: {self.found_path}")
            self.display_text(f"Unable to read the file:\n{str(e)}")

    def display_text(self, content):
        self.text_area.config(state=tk.NORMAL)
        self.text_area.delete("1.0", tk.END)
        self.text_area.insert(tk.END, content)
        self.text_area.config(state=tk.DISABLED)
        self.text_area.see("1.0")

    def copy_to_clipboard(self):
        if not self.file_content:
            messagebox.showwarning("Clipboard", "There is no content to copy.")
            return

        try:
            self.root.clipboard_clear()
            self.root.clipboard_append(self.file_content)
            self.root.update()
            self.status_var.set(f"Content copied • {self.found_path or 'N/A'}")
            messagebox.showinfo("Clipboard", "The entire log content has been copied to the clipboard.")
        except Exception as e:
            messagebox.showerror("Clipboard Error", f"Unable to copy to clipboard:\n{str(e)}")


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

Monday, August 3, 2026

tkinter : simple rss feeds reader on pydroid 3.

Today, this is a simple rss feeds reader with tkinter on pydroid I.D.E. android. The source code is very simple and get feeds from web. See the result:
import tkinter as tk
from tkinter import messagebox, ttk
import webbrowser
import feedparser

RSS_URL = "https://blog.python.org/feeds/posts/default"

article_links = []


def clean_text(text):
    """Converts text to basic ASCII to strip non-supported Android Tkinter characters."""
    if not text:
        return ""
    # Encodes to ASCII ignoring emojis, special quotes, and unsupported byte sequences
    clean = text.encode("ascii", "ignore").decode("ascii")
    # Removes extra whitespace and linebreaks
    return " ".join(clean.split())


def load_feed():
    global article_links

    listbox.delete(0, tk.END)
    article_links.clear()

    status_label.config(text="Fetching articles...", foreground="blue")
    root.update()

    try:
        feed = feedparser.parse(RSS_URL)

        if not feed.entries:
            status_label.config(text="No articles found.", foreground="red")
            return

        for entry in feed.entries:
            title_raw = entry.get("title", "Untitled")
            title = clean_text(title_raw)
            link = entry.get("link", "")

            listbox.insert(tk.END, title)
            article_links.append(link)

        status_label.config(
            text=f"Loaded {len(feed.entries)} articles!", foreground="green"
        )

    except Exception as e:
        status_label.config(text="Connection error!", foreground="red")
        messagebox.showerror("Error", f"Failed to load feed:\n{e}")


def open_link(event):
    try:
        index = listbox.curselection()[0]
        url = article_links[index]
        if url:
            webbrowser.open(url)
    except IndexError:
        pass


# --- GUI Setup ---
root = tk.Tk()
root.title("Python Foundation RSS Reader")
root.geometry("600x800")

title_label = ttk.Label(
    root, text="Python Software Foundation Blog", font=("Helvetica", 14, "bold")
)
title_label.pack(pady=10)

refresh_btn = ttk.Button(root, text="Refresh", command=load_feed)
refresh_btn.pack(pady=5)

status_label = ttk.Label(
    root, text="Connecting...", font=("Helvetica", 10)
)
status_label.pack(pady=5)

frame = ttk.Frame(root)
frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL)

listbox = tk.Listbox(
    frame,
    font=("Helvetica", 11),
    selectbackground="#007ACC",
    selectforeground="white",
    activestyle="none",
    yscrollcommand=scrollbar.set,
    bd=1,
    relief="solid",
)

scrollbar.config(command=listbox.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

listbox.bind("<>", open_link)

root.after(500, load_feed)
root.mainloop()

Saturday, August 1, 2026

tkinter : tau package on pydroid 3

Today, I test the tau python package with tkinter on pydroid3 on my phone.
/div>
Let's see the source code;
div>
import os
import platform
import subprocess
import sys
import tkinter as tk
from tkinter import ttk

def get_android_prop(prop_name):
    """Citește o proprietate de sistem Android folosind comanda getprop."""
    try:
        val = (
            subprocess.check_output(f"getprop {prop_name}", shell=True, text=True)
            .strip()
        )
        return val if val else "N/A"
    except Exception:
        return "Indisponibil"


def get_system_info():
    """Colectează informații extinse despre telefon și modulul Tau."""
    # 1. Verificare modul Tau
    tau_info = "Neinstalat"
    try:
        import tau

        tau_info = getattr(tau, "__version__", "Instalat (fără __version__)")
    except ImportError:
        tau_info = "Pachetul 'tau-ai' nu este instalat"

    # 2. Preluare date extinse Android
    model = get_android_prop("ro.product.model")
    brand = get_android_prop("ro.product.brand")
    manufacturer = get_android_prop("ro.product.manufacturer")
    android_version = get_android_prop("ro.build.version.release")
    sdk_version = get_android_prop("ro.build.version.sdk")
    device_board = get_android_prop("ro.product.board")
    hardware = get_android_prop("ro.hardware")

    info = {
        "Versiune Tau": tau_info,
        "Producător": f"{manufacturer.capitalize()} ({brand.capitalize()})",
        "Model Telefon": model,
        "Versiune Android": f"Android {android_version} (API {sdk_version})",
        "Placă / Hardware": f"{device_board} / {hardware}",
        "Arhitectură CPU": platform.machine(),
        "Sistem Python": f"{platform.system()} {platform.release()}",
        "Versiune Python": sys.version.split()[0],
    }
    return info


def main():
    root = tk.Tk()
    root.title("Tau & Detalii Android")
    root.geometry("420x560")
    root.configure(bg="#212121")

    title = tk.Label(
        root,
        text="Informații Dispozitiv & Tau",
        font=("Helvetica", 15, "bold"),
        fg="#00E676",
        bg="#212121",
        pady=12,
    )
    title.pack()

    # Zonă de text pentru date
    text_area = tk.Text(
        root,
        font=("Courier", 10),
        bg="#303030",
        fg="#FFFFFF",
        padx=10,
        pady=10,
        relief=tk.FLAT,
    )
    text_area.pack(fill=tk.BOTH, expand=True, padx=15, pady=5)

    # Inserare date în fereastră
    info_data = get_system_info()
    text_content = "=== SPECIFICAȚII TELEFON & APP ===\n\n"
    for key, value in info_data.items():
        text_content += f"• {key}:\n  {value}\n\n"

    text_area.insert(tk.END, text_content)
    text_area.config(state=tk.DISABLED)

    # Buton de închidere
    btn_close = tk.Button(
        root,
        text="Închide",
        font=("Helvetica", 11, "bold"),
        bg="#FF5252",
        fg="white",
        activebackground="#FF1744",
        activeforeground="white",
        command=root.destroy,
        pady=8,
    )
    btn_close.pack(fill=tk.X, padx=15, pady=15)
    root.mainloop()
if __name__ == "__main__":
    main()

Thursday, July 30, 2026

tkinter : mini rss for NVDA

Today, I started new post with tkinter label. This is a demo real with pydroid3 android application to get data from rss and show me NVDA and more.
The tkinter package (“Tk interface”) is the standard Python interface to the Tcl/Tk GUI toolkit. Both Tk and tkinter are available on most Unix platforms, including macOS, as well as on Windows systems.

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.