analitics

Pages

Tuesday, December 30, 2025

Python Qt6 : video processing and background remover and sprites tool

It seems that the intrusion blocked my python and pip tool in command ... but I managed to create a tool with the python modules I had installed that would automatically remove my background and create sprites after a crop selection ... here's what it looks like with the character from the Easter project.
pyqt5 python video tool
... and result with crop and remove the green color from background:

Tuesday, December 23, 2025

Python Qt6 : testing local web server with PyQt versus Ollama.

This Python program creates a PyQt6 GUI that measures latency for a given URL.
It runs a background thread that repeatedly sends HTTP requests and calculates two values:
The results are sent back to the GUI using Qt signals and displayed live without freezing the interface.
  • HTTP latency (time for the request to complete)
  • Thread latency (total duration of one worker cycle)
See the result in this screenshot:

Wednesday, December 17, 2025

Python Qt6 : Run Visual Studio Code directly from RAM using ImDisk and python.

I built a small tool using Python + PyQt6 that lets me run Visual Studio Code directly from a RAM Disk for maximum speed and minimal SSD wear.
The setup uses ImDisk Toolkit to automatically create a 6 GB RAM Disk (drive O:).
The tool then copies VS Code into RAM and launches it instantly through a simple graphical interface with three buttons:
  • Create RAM Disk
  • Copy VS Code to RAM
  • Launch VS Code from RAM
This method provides much faster startup times and a smoother workflow, making it a great performance boost for Windows users.

News : Reporting a security issue - good practice.

This is how the python solve a security issue:
We take security very seriously and ask that you follow our security policy carefully.
If you've identified a security issue with a project hosted on PyPI.
Login to your PyPI account, then visit the project's page on PyPI. At the bottom of the sidebar, click Report project as malware. Supply the following details in the form:
  • A URL to the project in question
  • An explanation of what makes the project a security issue
  • A link to the problematic lines in the project's distributions via inspector.pypi.io
Important! If you believe you've identified a security issue with PyPI, DO NOT report the issue in any public forum, including (but not limited to):
  • Our GitHub issue tracker
  • Official or unofficial chat channels
  • Official or unofficial mailing lists

Monday, December 15, 2025

Python Qt6 : ... tool for testing fonts.

Today I created a small Python script with PyQt6 using artificial intelligence. It is a tool that takes a folder of fonts, allows to select their size, displays the font size in pixels for Label text from the Godot engine and downloads only the selection of fonts that I like. I have not tested it to see the calculations with Godot, but it seems functional...

Saturday, December 13, 2025

Python Qt6 : ... search custom data in files with python and PyQt6.

The other day I noticed that I can't find what I worked on in the past, some files were blocked... Another task was blocking the artificial intelligence due to the number of uses. I could have used artificial intelligence to open old projects and ask where what I worked on is, but it would be a risk to waste my queries. Since I always use a specific signature when working on separate projects and the backup is distributed on storage that is always filling up, I created a simple script that would search for my custom with custom files, custom content and output a spreader with them. Here is the result of a 310-line source code script, obviously created with artificial intelligence.

Wednesday, December 10, 2025

Python 3.13.0 : ... simple script for copilot history.

NOTES: I have been using artificial intelligence since it appeared, it is obviously faster and more accurate, I recommend using testing on larger projects.
This python script will take the database and use to get copilot history and save to file copilot_conversations.txt :
import os
import sqlite3
import datetime
import requests
from bs4 import BeautifulSoup
import shutil

# Locația tipică pentru istoricul Edge (Windows)
edge_history_path = os.path.expanduser(
    r"~\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default\\History"
)

# Copiem fișierul History în folderul curent
def copy_history_file(src_path, dst_name="edge_history_copy.db"):
    if not os.path.exists(src_path):
        print("Nu am găsit istoricul Edge.")
        return None
    dst_path = os.path.join(os.getcwd(), dst_name)
    try:
        shutil.copy(src_path, dst_path)
        print(f"Am copiat baza de date în {dst_path}")
        return dst_path
    except Exception as e:
        print(f"Eroare la copiere: {e}")
        return None

def extract_copilot_links(db_path):
    conn = sqlite3.connect(db_path)
    cursor = conn.cursor()

    cursor.execute("""
        SELECT url, title, last_visit_time
        FROM urls
        WHERE url LIKE '%copilot%'
    """)

    results = []
    for url, title, last_visit_time in cursor.fetchall():
        ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds=last_visit_time)
        results.append({
            "url": url,
            "title": title,
            "last_visit": ts.strftime("%Y-%m-%d %H:%M:%S")
        })

    conn.close()
    return results

def fetch_conversation(url):
    try:
        resp = requests.get(url)
        if resp.status_code == 200:
            soup = BeautifulSoup(resp.text, "html.parser")
            texts = soup.get_text(separator="\n", strip=True)
            return texts
        else:
            return f"Eroare acces {url}: {resp.status_code}"
    except Exception as e:
        return f"Eroare acces {url}: {e}"

if __name__ == "__main__":
    copy_path = copy_history_file(edge_history_path)
    if copy_path:
        chats = extract_copilot_links(copy_path)
        if chats:
            with open("copilot_conversations.txt", "w", encoding="utf-8") as f:
                for chat in chats:
                    content = fetch_conversation(chat["url"])
                    f.write(f"=== Conversație: {chat['title']} ({chat['last_visit']}) ===\n")
                    f.write(content)
                    f.write("\n\n")
            print("Am salvat conversațiile în copilot_conversations.txt")
        else:
            print("Nu am găsit conversații Copilot în istoricul Edge.")

Saturday, December 6, 2025

News : Python 3.14.1 and Python 3.13.10 are now available!

... these are good news from 2 december 2025:
Python 3.14.1 is the first maintenance release of 3.14, containing around 558 bugfixes, build improvements and documentation changes since 3.14.0.
Python 3.13.10 is the tenth maintenance release of 3.13, containing around 300 bugfixes, build improvements and documentation changes since 3.13.9.
Read more on the official blogger.

Friday, December 5, 2025

Python Qt6 : ... data generator tool for a custom format file.

Today I finished a data generator tool for a custom format for a game. The idea is that PyQt6 is versatile and very useful for a developer. This tool generates data in the 2D area of a screen and saves them in a defined format, in this case a position and a size for a text ...
Here is the class for custom range selection sliders.
class RangeSlider(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._min, self._max = 0, 1000
        self._start, self._end = 0, 1000
        self._dragging = None
        self.setMinimumHeight(24)

    def setRange(self, minimum, maximum):
        self._min, self._max = minimum, maximum
        self._start, self._end = minimum, maximum
        self.update()

    def setStart(self, val):
        self._start = max(self._min, min(val, self._end))
        self.update()

    def setEnd(self, val):
        self._end = min(self._max, max(val, self._start))
        self.update()

    def start(self): return self._start
    def end(self): return self._end

    def _pos_to_val(self, x):
        w = self.width()
        ratio = max(0, min(x, w)) / w if w else 0
        return int(self._min + ratio*(self._max-self._min))

    def _val_to_pos(self, val):
        w = self.width()
        return int((val-self._min)/(self._max-self._min)*w) if self._max>self._min else 0

    def mousePressEvent(self, e):
        x = e.position().x()
        sx, ex = self._val_to_pos(self._start), self._val_to_pos(self._end)
        self._dragging = "start" if abs(x-sx)<abs(x-ex) else "end"
        self.mouseMoveEvent(e)

    def mouseMoveEvent(self, e):
        if self._dragging:
            val = self._pos_to_val(int(e.position().x()))
            if self._dragging=="start": self.setStart(val)
            else: self.setEnd(val)

    def mouseReleaseEvent(self,e): self._dragging=None

    def paintEvent(self,e):
        p=QPainter(self); rect=self.rect()
        sx,ex=self._val_to_pos(self._start),self._val_to_pos(self._end)
        p.fillRect(rect,QColor(220,220,220))
        p.fillRect(QRect(QPoint(sx,0),QPoint(ex,rect.height())),QColor(100,200,100,120))
        p.setBrush(QColor(50,120,200)); p.setPen(Qt.PenStyle.NoPen)
        p.drawEllipse(QPoint(sx,rect.center().y()),6,6)
        p.drawEllipse(QPoint(ex,rect.center().y()),6,6)

Thursday, December 4, 2025

News : the pythononline online tool for python users.

Wednesday, December 3, 2025

Python 3.13.0 : ... playwright - part 001.

Playwright for Python is a modern automation library that allows developers to control browsers like Chromium, Firefox, and WebKit. It is widely used for testing, scraping, and simulating real user interactions.
The package provides an asynchronous API, enabling fast and reliable automation. Developers can launch browsers, navigate to pages, fill forms, click buttons, and capture results with minimal code.
In practice, Playwright is useful for tasks such as automated testing, repetitive searches, data collection, and simulating human-like browsing behavior across multiple browsers.
The example script demonstrates how to open Firefox, navigate to Google, perform a series of searches, scroll the page, and pause between actions to mimic natural user activity.
Additionally, the script saves each search query into a text file, creating a simple log of performed searches. This shows how Playwright can combine browser automation with file handling for practical workflows.
I used the pip tool then I install the playwright:
pip install playwright
playwright install
Let's see the script:
import asyncio
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.firefox.launch(headless=False)
        context = await browser.new_context()
        page = await context.new_page()

        await page.goto("https://www.google.com")

        queries = [
            "python automation",
            "playwright tutorial",
            "google search automation"
        ]

        with open("results.txt", "w", encoding="utf-8") as f:
            for q in queries:
                # Fill search box
                await page.fill("textarea[name='q']", q)
                await page.press("textarea[name='q']", "Enter")
                await page.wait_for_load_state("domcontentloaded")

                # Scroll + pause
                await page.evaluate("window.scrollBy(0, document.body.scrollHeight)")
                await page.wait_for_timeout(3000)

                # Extract search results (titles + links)
                results = await page.query_selector_all("h3")
                f.write(f"\nResults for: {q}\n")
                for r in results[:5]:  # primele 5 rezultate
                    title = await r.inner_text()
                    link_el = await r.evaluate_handle("node => node.parentElement")
                    link = await link_el.get_attribute("href")
                    f.write(f"- {title} ({link})\n")

                print(f"Saved results for: {q}")

        await browser.close()

asyncio.run(main())
Then I run with this command:
python google_search_test_001.py
Saved results for: python automation
Saved results for: playwright tutorial
Saved results for: google search automation
Need to click to accept on browser ... , and some basic result on results.txt file:

Results for: python automation

Results for: playwright tutorial
- Playwright: Fast and reliable end-to-end testing for modern ... 

Sunday, November 30, 2025

News : the xonsh shell language and command prompt.

Xonsh is a modern, full-featured and cross-platform python shell. The language is a superset of Python 3.6+ with additional shell primitives that you are used to from Bash and IPython. It works on all major systems including Linux, OSX, and Windows. Xonsh is meant for the daily use of experts and novices.
The install is easy with pip tool:
python -m pip install 'xonsh[full]'

Python 3.13.0 : mitmproxy - part 001.

Mitmproxy is an interactive, open‑source proxy tool that lets you intercept, inspect, and modify HTTP and HTTPS traffic in real time. It acts as a "man‑in‑the‑middle" between your computer and the internet, making it possible to debug, test, or analyze how applications communicate online.
Why Python?
  • Mitmproxy is built in Python and exposes a powerful addon API
  • You can write custom scripts to automate tasks and traffic manipulation
  • Block or rewrite requests and responses with flexible logic
  • Inject headers or simulate server responses for testing
  • Integrate with other Python tools for advanced automation
  • Intercept and inspect HTTP and HTTPS traffic in real time
  • Modify requests and responses dynamically with Python scripts
  • Block specific hosts or URLs to prevent unwanted connections
  • Inject custom headers into outgoing requests for debugging or control
  • Rewrite response bodies (HTML, JSON, text) using regex or custom logic
  • Log and save traffic flows for later analysis and replay
  • Simulate server responses to test client behavior offline
  • Automate testing of web applications and APIs with scripted rules
  • Monitor performance metrics such as latency and payload size
  • Integrate with other Python tools for advanced automation and analysis
  • Use a trusted root certificate to decrypt and modify HTTPS traffic securely
Let's install:
pip install mitmproxy
Let's see the python script:
# addon.py
from mitmproxy import http
from mitmproxy import ctx
import re

BLOCKED_HOSTS = {
    "hyte.com",
    "ads.example.org",
}

REWRITE_RULES = [
    # Each rule: (pattern, replacement, content_type_substring)
    (re.compile(rb"Hello World"), b"Salut lume", "text/html"),
    (re.compile(rb"tracking", re.IGNORECASE), b"observare", "text"),
]

ADD_HEADERS = {
    "X-Debug-Proxy": "mitm",
    "X-George-Tool": "true",
}

class GeorgeProxy:
    def __init__(self):
        self.rewrite_count = 0

    def load(self, loader):
        ctx.log.info("GeorgeProxy addon loaded.")

    def request(self, flow: http.HTTPFlow):
        # Block specific hosts early
        host = flow.request.host
        if host in BLOCKED_HOSTS:
            flow.response = http.Response.make(
                403,
                b"Blocked by GeorgeProxy",
                {"Content-Type": "text/plain"}
            )
            ctx.log.warn(f"Blocked request to {host}")
            return

        # Add custom headers to outgoing requests
        for k, v in ADD_HEADERS.items():
            flow.request.headers[k] = v

        ctx.log.info(f"REQ {flow.request.method} {flow.request.url}")

    def response(self, flow: http.HTTPFlow):
        # Only process text-like contents
        ctype = flow.response.headers.get("Content-Type", "").lower()
        raw = flow.response.raw_content

        if raw and any(t in ctype for t in ["text", "html", "json"]):
            new_content = raw
            for pattern, repl, t in REWRITE_RULES:
                if t in ctype:
                    new_content, n = pattern.subn(repl, new_content)
                    self.rewrite_count += n

            if new_content != raw:
                flow.response.raw_content = new_content
                # Update Content-Length only if present
                if "Content-Length" in flow.response.headers:
                    flow.response.headers["Content-Length"] = str(len(new_content))
                ctx.log.info(f"Rewrote content ({ctype}); total matches: {self.rewrite_count}")

        ctx.log.info(f"RESP {flow.response.status_code} {flow.request.url}")

addons = [GeorgeProxy()]
Let's run it:
mitmdump -s addon.py
[21:46:04.435] Loading script addon.py
[21:46:04.504] GeorgeProxy addon loaded.
[21:46:04.506] HTTP(S) proxy listening at *:8080.
[21:46:18.547][127.0.0.1:52128] client connect
[21:46:18.593] REQ GET http://httpbin.org/get
[21:46:18.768][127.0.0.1:52128] server connect httpbin.org:80 (52.44.182.178:80)
[21:46:18.910] RESP 200 http://httpbin.org/get
127.0.0.1:52128: GET http://httpbin.org/get
              << 200 OK 353b
[21:46:19.019][127.0.0.1:52128] client disconnect
[21:46:19.021][127.0.0.1:52128] server disconnect httpbin.org:80 (52.44.182.178:80)
Let's see the result:
curl -x http://127.0.0.1:8080 http://httpbin.org/get
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "Proxy-Connection": "Keep-Alive",
    "User-Agent": "curl/8.13.0",
    "X-Amzn-Trace-Id": "Root=1-692c9f0b-7eaf43e61f276ee62b089933",
    "X-Debug-Proxy": "mitm",
    "X-George-Tool": "true"
  },
  "origin": "84.117.220.94",
  "url": "http://httpbin.org/get"
}
This means
The request successfully went through mitmproxy running on 127.0.0.1:8080. Your addon worked: it injected the custom headers (X-Debug-Proxy, X-George-Tool). The httpbin.org echoed back the request details, showing exactly what the server received.

Python 3.13.0 : Tornado - part 001.

Python Tornado is a high‑performance web framework and asynchronous networking library designed for extreme scalability and real‑time applications. Its standout capability is handling tens of thousands of simultaneous connections efficiently, thanks to non‑blocking I/O.
This is an open source project actively maintained and available on tornadoweb.org.

Python Tornado – Key Capabilities

  • Massive Concurrency: Tornado can scale to tens of thousands of open connections without requiring huge numbers of threads.
  • Non‑blocking I/O: Its asynchronous design makes it ideal for apps that need to stay responsive under heavy load.
  • WebSockets Support: Built‑in support for WebSockets enables real‑time communication between clients and servers.
  • Long‑lived Connections: Perfect for long polling, streaming, or chat applications where connections remain open for extended periods.
  • Coroutines & Async/Await: Tornado integrates tightly with Python’s asyncio, allowing developers to write clean asynchronous code using coroutines.
  • Versatile Use Cases: Beyond web apps, Tornado can act as an HTTP client/server, handle background tasks, or integrate with other services.
Tornado setup: The script creates a web server using the Tornado framework, listening on port 8888.
Route definition: A single route /form is registered, handled by the FormHandler class.
GET request: When you visit http://localhost:8888/form, the server responds with an HTML page (form.html) that contains a simple input form.
POST request: When the form is submitted, the post() method retrieves the value of the name field using self.get_argument("name").
Response: The server then sends back a personalized message
Let's see the script:
import tornado.ioloop
import tornado.web
import os

class FormHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("form.html")  # Render an HTML form

    def post(self):
        name = self.get_argument("name")
        self.write(f"Hello, {name}!")

def make_app():
    return tornado.web.Application([
        (r"/form", FormHandler),
    ],
    template_path=os.path.join(os.path.dirname(__file__), "templates")  # <-- aici
    )

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print("Server pornit pe http://localhost:8888/form")
    tornado.ioloop.IOLoop.current().start()

Monday, November 3, 2025

News : DjangoCon Europe 2026!

We’re excited to share that DjangoCon Europe returns in 2026 — this time in the historic and sun-soaked city of Athens, Greece 🇬🇷, with three days of talks from April 15–17, 2026!
This is the 18th edition of the Conference and it is organized by a team made up of Django practitioners from all levels. We welcome people from all over the world.
Our conference seeks to educate and develop new skills, best practices, and ideas for the benefit of attendees, developers, speakers, and everyone in our global Django Community, not least those watching the talks online.
This year it will take place in the beautiful city of Athens. Don't miss the chance to join us for three days of talks, workshops, and sprints.
Read more abot this event on the official webpage.

News : Hyperflask - web stack on top of Python !

The goal of the Hyperflask stack is to provide a single unified web stack, built on top of Python and proven technologies, where all components have been designed to work together seamlessly.
It intends to provide solo devs and small teams a solution that allows them to build and operate a website/web app with minimal boilerplate and overhead. All the focus can go to work on the actual product.
Read more on the official website.

Thursday, October 30, 2025

Python 3.13.0 : xAI A.P.I. with regional endpoint on xai_sdk python package.

Grok is a family of Large Language Models (LLMs) developed by xAI.
Inspired by the Hitchhiker's Guide to the Galaxy, Grok is a maximally truth-seeking AI that provides insightful, unfiltered truths about the universe.
xAI offers an API for developers to programmatically interact with our Grok models. The same models power our consumer facing services such as Grok.com, the iOS and Android apps, as well as Grok in X experience.
If you want to use a regional endpoint, you need to specify the endpoint url when making request with SDK. In xAI SDK, this is specified through the api_host parameter.
Is not free models available for xAI A.P.I.
See this example from the official website:
import os

from xai_sdk import Client
from xai_sdk.chat import user

client = Client(
api_key=os.getenv("XAI_API_KEY"),
api_host="us-east-1.api.x.ai" # Without the https://
)

chat = client.chat.create(model="grok-4")
chat.append(user("What is the meaning of life?"))

completion = chat.sample()

Thursday, October 23, 2025

Python 3.13.0 : OneByteRadar - pymem python package.

Today, I found this GitHub project about how to write to exe files with python programming language
The author say:
CS:GO radar hack achieved by patching one byte of game memory. Written in Python 3.
I don't test it, but good to know how can use these python modules.
The pymem Python library that allows you to interact with the memory of running Windows processes.
  • Reading and writing memory values of other processes
  • Scanning memory for byte patterns
  • Allocating and freeing memory inside another process
  • Accessing modules (DLLs) loaded by a process
  • This is often used in game hacking, automation, or debugging tools.
NOTE: I used artificial intelligence to write this simple example, it is more productive in programs with more complex syntax, but the basics of programming must be known...
Let's see one example with edge browser open:
import pymem
import pymem.process
import re

# Open the Edge process (make sure it's running)
pm = pymem.Pymem("msedge.exe")

# Get the main module of the process
module = pymem.process.module_from_name(pm.process_handle, "msedge.exe")
base = module.lpBaseOfDll
size = module.SizeOfImage

# Read the module's memory
data = pm.read_bytes(base, size)

# Search for a test pattern (generic example)
pattern = re.search(rb'\x48\x89\x5C\x24\x08\x57\x48\x83', data)

if pattern:
    address = base + pattern.start()
    print(f"Pattern found at: {hex(address)}")

    # Read 8 bytes from the found address
    raw = pm.read_bytes(address, 8)
    print("Raw bytes:", raw)

    # Interpret the bytes as a little-endian integer
    value = int.from_bytes(raw, byteorder='little')
    print("Integer value:", value)

    # Write a new value (e.g., 12345678)
    new_value = (12345678).to_bytes(8, byteorder='little')
    pm.write_bytes(address, new_value, 8)
    print("Value overwritten with 12345678.")

else:
    print("Pattern not found.")

# Close the process handle
pm.close_process()
What is that patern:
pattern = re.search(rb'\x48\x89\x5C\x24\x08\x57\x48\x83', data)
These bytes correspond to x86-64 assembly instructions. For example:

48 89 5C 24 08 → mov [rsp+8], rbx
57 → push rdi
48 83 → the start of an instruction like add/sub/cmp with a 64-bit operand
This sequence is typical for the prologue of a function in compiled C++ code — saving registers to the stack.
This is a simple example, you don't see anything in edge because is just one search and one overwritten:
python pymem_exemple_002.py
Pattern found at: 0x7ff7180cb3d5
Raw bytes: b'H\x89\\$\x08WH\x83'
Integer value: 9459906709773125960
Value overwritten with 12345678.
You replaced those 8 bytes with the integer 12345678, encoded as: 4E 61 BC 00 00 00 00 00 (in hex)
This corrupts the original instruction, which may crash Edge or cause undefined behavior.
Not crash, maybe my edge browser use protections (ASLR, DEP, CFG) that can make modification unstable.
--------
1. ASLR (Address Space Layout Randomization)
2. DEP (Data Execution Prevention)
3. CFG (Control Flow Guard)

Wednesday, October 22, 2025

Tuesday, October 21, 2025

Python 3.12.12 : Google colab example - satellite sentinel-2-l2a.

Tested today, location my home, this is the result of satellite sentinel-2-l2a - octomber 2025.

Monday, October 20, 2025

Python Qt6 : tool for remove duplicate files ...

Today I created a Python script with PyQt6 that allows me to remove duplicate files based on three ways of selecting the type of duplicate.
The script also makes an estimate of the execution time...
Because the source code is relatively simple and can be very easily reconstructed with the help of artificial intelligence, I am not adding it to the posts.
Here is what the application looks like with PyQt6.

Saturday, October 18, 2025

Blender 3D : ... simple clothing addon.

Today, I created a simple clothing addon with a two-mesh coat. The addon adds everything needed for the simulation including material types for the clothes.

Python Qt6 : tool for cutting images ...

Today I made a script that allows adding custom horizontal and vertical sliders to an image and, depending on the custom distance between them, cuts the image into squares of different sizes.

Python Qt6 : tool for renaming files with creation date .

Since this hacking and the crashes... I've always taken screenshots... Today I created a small script that takes files from a folder and renames them with the creation date in this format...yyyyMMdd_HHmmss .
... obviously artificial intelligence helped me.
This is the source code :
import sys
import os
import shutil
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QFileDialog, QMessageBox
from PyQt6.QtCore import QDateTime

class FileRenamer(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Redenumire fișiere cu dată și index")
        self.setGeometry(100, 100, 400, 150)

        layout = QVBoxLayout()

        self.button = QPushButton("Selectează folderul și redenumește fișierele")
        self.button.clicked.connect(self.rename_files)
        layout.addWidget(self.button)

        self.setLayout(layout)

    def rename_files(self):
        folder = QFileDialog.getExistingDirectory(self, "Selectează folderul")
        if not folder:
            return

        files = [f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))]
        files.sort()  # Sortează pentru consistență

        for index, filename in enumerate(files, start=1):
            old_path = os.path.join(folder, filename)
            try:
                creation_time = os.path.getctime(old_path)
                dt = QDateTime.fromSecsSinceEpoch(int(creation_time))
                date_str = dt.toString("yyyyMMdd_HHmmss")
                ext = os.path.splitext(filename)[1]
                new_name = f"{date_str}_{index:03d}{ext}"
                new_path = os.path.join(folder, new_name)

                # Evită suprascrierea fișierelor existente
                if not os.path.exists(new_path):
                    shutil.move(old_path, new_path)
            except Exception as e:
                QMessageBox.critical(self, "Eroare", f"Eroare la fișierul {filename}:\n{str(e)}")
                continue

        QMessageBox.information(self, "Succes", "Fișierele au fost redenumite cu succes!")

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

Friday, October 17, 2025

Python 3.12.12 : Google colab example of satellite detecting edges .

Simple colab project with google satellite detecting ...
I used these python packages:
%pip install segment-geospatial
%pip install leafmap
%pip install samgeo
%pip install localtileserver
%pip install fiona
This is the result:

Thursday, October 16, 2025

News : Google DeepMind and Google Colab - part 001.

Today I tested Google DeepMind and Google Colab.
You can see my simple test on Suceava area ...

Monday, October 13, 2025

News : What’s new in Python 3.14.

... this news is old from five days ago .
Python 3.14 is the latest stable release of the Python programming language, with a mix of changes to the language, the implementation, and the standard library.

Saturday, October 11, 2025

Python 3.8.5 : ... online python tool

You can found this good online tool for simple python programming. See the result with version and python modules used into this online tool.
Versiunea de Python: 3.8.5 (default, Jul 20 2020, 23:11:29) 
[GCC 9.3.0]

Module instalate:
- webencodings (0.5.1)
- urllib3 (1.25.9)
- toml (0.10.1)
- six (1.15.0)
- setuptools (47.0.0)
- retrying (1.3.3)
- requests (2.23.0)
- pytz (2020.1)
- pytoml (0.1.21)
- python-dateutil (2.8.1)
- pyparsing (2.4.7)
- progress (1.5)
- pip (20.1.1)
- pep517 (0.8.2)
- pandas (1.1.0)
- packaging (20.4)
- ordered-set (4.0.1)
- numpy (1.19.1)
- msgpack (1.0.0)
- lockfile (0.12.2)
- idna (2.9)
- html5lib (1.0.1)
- distro (1.5.0)
- distlib (0.3.0)
- contextlib2 (0.6.0)
- colorama (0.4.3)
- chardet (3.0.4)
- certifi (2020.4.5.1)
- CacheControl (0.12.6)
- appdirs (1.4.4)


** Process exited - Return Code: 0 **

Tuesday, October 7, 2025

Python 3.15 : PEP 810 - Explicit lazy imports

Python’s import system could be in for its biggest change in years.
Lazy imports are controlled, in the sense that deferred loading is only triggered by the importing code itself.
This avoids shifting responsibility onto downstream users and prevents accidental surprises in library behavior.
The new explicit lazy import mechanism enhances security by deferring module initialization until runtime, thereby minimizing the attack surface and preventing premature execution of potentially vulnerable or malicious code during application startup.

Saturday, October 4, 2025

Friday, September 26, 2025

Python Qt6 : tool for game development with PNG images.

Today, I worked with art artificial intelligence, to create tool for my game development.
I used python and PyQt6 and this tool help me to remove border, resize, split, rename and save images as PNG file type for Godot game engine.

Wednesday, September 24, 2025

Python 3.10.7 : Krita and python - part 002.

A simple source code to export PNG file for Godot game engine as Texture2D .
from krita import *
from PyQt5.QtWidgets import QAction, QMessageBox
import os

class ExportGodotPNG(Extension):
    def __init__(self, parent):
        super().__init__(parent)

    def setup(self):
        pass

    def export_png(self):
        # Get the active document
        doc = Krita.instance().activeDocument()
        if not doc:
            QMessageBox.warning(None, "Error", "No document open! Please open a document and try again.")
            return

        # Create an InfoObject for PNG export
        info = InfoObject()
        info.setProperty("alpha", True)  # Keep alpha channel for transparency
        info.setProperty("compression", 0)  # No compression for maximum quality
        info.setProperty("interlaced", False)  # Disable interlacing
        info.setProperty("forceSRGB", True)  # Force sRGB for Godot compatibility

        # Build the output file path
        if doc.fileName():
            base_path = os.path.splitext(doc.fileName())[0]
        else:
            base_path = os.path.join(os.path.expanduser("~"), "export_godot")
        output_file = base_path + "_godot.png"

        # Export the document as PNG
        try:
            doc.exportImage(output_file, info)
            # Show success message with brief usage info
            QMessageBox.information(None, "Success", 
                f"Successfully exported as PNG for Godot: {output_file}\n\n"
                "This PNG has no compression, alpha channel support, and sRGB for Godot compatibility. "
                "To use in Godot, import the PNG and adjust texture settings as needed."
            )
        except Exception as e:
            QMessageBox.critical(None, "Error", f"Export failed: {str(e)}")

    def createActions(self, window):
        # Create only the export action in Tools > Scripts
        action_export = window.createAction("export_godot_png", "Export Godot PNG", "tools/scripts")
        action_export.triggered.connect(self.export_png)

# Register the plugin
Krita.instance().addExtension(ExportGodotPNG(Krita.instance()))

Thursday, September 18, 2025

Blender 3D : ... addon add all materials from folder.

This is a simple addon for Blender 3D version 3.6.x version.
The addon search recursive all blend files from one folder and take all materials.
Let's see the script:
bl_info = {
    "name": "Append Materials from Folder",
    "author": "Grok",
    "version": (1, 2),
    "blender": (3, 0, 0),
    "location": "View3D > Sidebar > Append Materials",
    "description": "Select a folder and append all materials from .blend files recursively",
    "category": "Import-Export",
}

import bpy
import os
from bpy.types import Operator, Panel, PropertyGroup
from bpy.props import StringProperty, PointerProperty

class AppendMaterialsProperties(PropertyGroup):
    folder_path: StringProperty(
        name="Folder Path",
        description="Path to the folder containing .blend files",
        default="",
        maxlen=1024,
        subtype='DIR_PATH'
    )

class APPEND_OT_materials_from_folder(Operator):
    bl_idname = "append.materials_from_folder"
    bl_label = "Append Materials from Folder"
    bl_options = {'REGISTER', 'UNDO'}
    bl_description = "Append all materials from .blend files in the selected folder and subfolders"

    def execute(self, context):
        props = context.scene.append_materials_props
        folder_path = props.folder_path

        # Normalize path to avoid issues with slashes
        folder_path = os.path.normpath(bpy.path.abspath(folder_path))
        if not folder_path or not os.path.isdir(folder_path):
            self.report({'ERROR'}, f"Invalid or no folder selected: {folder_path}")
            return {'CANCELLED'}

        self.report({'INFO'}, f"Scanning folder: {folder_path}")
        blend_files_found = 0
        materials_appended = 0
        errors = []

        # Walk recursively through the folder
        for root, dirs, files in os.walk(folder_path):
            self.report({'INFO'}, f"Checking folder: {root}")
            for file in files:
                if file.lower().endswith('.blend'):
                    blend_files_found += 1
                    blend_path = os.path.join(root, file)
                    self.report({'INFO'}, f"Found .blend file: {blend_path}")
                    try:
                        # Open the .blend file to inspect materials
                        with bpy.data.libraries.load(blend_path, link=False) as (data_from, data_to):
                            if data_from.materials:
                                data_to.materials = data_from.materials
                                materials_appended += len(data_from.materials)
                                self.report({'INFO'}, f"Appended {len(data_from.materials)} materials from: {blend_path}")
                            else:
                                self.report({'WARNING'}, f"No materials found in: {blend_path}")
                    except Exception as e:
                        errors.append(f"Failed to process {blend_path}: {str(e)}")
                        self.report({'WARNING'}, f"Error in {blend_path}: {str(e)}")

        # Final report
        if blend_files_found == 0:
            self.report({'WARNING'}, f"No .blend files found in {folder_path} or its subfolders!")
        else:
            self.report({'INFO'}, f"Found {blend_files_found} .blend files, appended {materials_appended} materials.")
        if errors:
            self.report({'WARNING'}, f"Encountered {len(errors)} errors: {'; '.join(errors)}")

        return {'FINISHED'}

class VIEW3D_PT_append_materials(Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Append Materials"
    bl_label = "Append Materials from Folder"

    def draw(self, context):
        layout = self.layout
        props = context.scene.append_materials_props
        layout.prop(props, "folder_path")
        layout.operator("append.materials_from_folder", text="Append Materials")

def register():
    bpy.utils.register_class(AppendMaterialsProperties)
    bpy.utils.register_class(APPEND_OT_materials_from_folder)
    bpy.utils.register_class(VIEW3D_PT_append_materials)
    bpy.types.Scene.append_materials_props = PointerProperty(type=AppendMaterialsProperties)

def unregister():
    bpy.utils.unregister_class(VIEW3D_PT_append_materials)
    bpy.utils.unregister_class(APPEND_OT_materials_from_folder)
    bpy.utils.unregister_class(AppendMaterialsProperties)
    del bpy.types.Scene.append_materials_props

if __name__ == "__main__":
    register()

Wednesday, September 17, 2025

News : ... 2025 election for the PSF Board

The 2025 election for the PSF Board :
  • Abigail Dogbe
  • Jannis Leidel
  • Sheena O’Connell
  • Simon Willison

Monday, September 8, 2025

Python 3.13.0 : Script for python modules then installs them - updated with fix.

This script scans a folder full of .py files Python scripts, identifies all the external modules they import, filters out built-in ones, writes the installable ones to a requirements.txt file, and then installs them using pip—in parallel threads for speed.
I use the copilot and some comments are into my language, but I tested and works well:
NOTE: I updated with detection python modules based "from" and another issue: check if python module is instaled and step over that python module ...
This script will try to install many python modules, I can update to be better with these issues:
...some modules are default , some scripts are from another area, see Blender 3D with bpy python modules, some packages comes with same modules, this can be soleved with defined lists with unique items.
import subprocess
import sys
import os
import shutil
import importlib.util
import re
import concurrent.futures
from typing import List, Tuple, Set

class ModuleManager:
    def __init__(self):
        self.modules: Set[str] = set()
        self.pip_path = self._get_pip_path()

    def _get_pip_path(self) -> str:
        possible_path = os.path.join(sys.exec_prefix, "Scripts", "pip.exe")
        return shutil.which("pip") or (possible_path if os.path.exists(possible_path) else None)

    def extract_imports_from_file(self, file_path: str) -> List[Tuple[str, str]]:
        imports = []
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                for line in file:
                    # Detect 'import module'
                    import_match = re.match(r'^\s*import\s+([a-zA-Z0-9_]+)(\s+as\s+.*)?$', line)
                    if import_match:
                        module = import_match.group(1)
                        imports.append((module, line.strip()))
                        continue
                    
                    # Detect 'from module import ...'
                    from_match = re.match(r'^\s*from\s+([a-zA-Z0-9_]+)\s+import\s+.*$', line)
                    if from_match:
                        module = from_match.group(1)
                        imports.append((module, line.strip()))
        except FileNotFoundError:
            print(f"❌ Fișierul {file_path} nu a fost găsit.")
        except Exception as e:
            print(f"❌ Eroare la citirea fișierului {file_path}: {e}")
        return imports

    def scan_directory_for_py_files(self, directory: str = '.') -> List[str]:
        py_files = []
        for root, _, files in os.walk(directory):
            for file in files:
                if file.endswith('.py'):
                    py_files.append(os.path.join(root, file))
        return py_files

    def collect_unique_modules(self, directory: str = '.') -> None:
        py_files = self.scan_directory_for_py_files(directory)
        all_imports = []
        with concurrent.futures.ThreadPoolExecutor() as executor:
            future_to_file = {executor.submit(self.extract_imports_from_file, file_path): file_path for file_path in py_files}
            for future in concurrent.futures.as_completed(future_to_file):
                imports = future.result()
                all_imports.extend(imports)
        
        for module, _ in all_imports:
            self.modules.add(module)

    def is_module_installed(self, module: str) -> bool:
        return importlib.util.find_spec(module) is not None

    def run_pip_install(self, module: str) -> bool:
        if not self.pip_path:
            print(f"❌ Nu am găsit pip pentru {module}.")
            return False
        try:
            subprocess.check_call([self.pip_path, "install", module])
            print(f"✅ Pachetul {module} a fost instalat cu succes.")
            return True
        except subprocess.CalledProcessError as e:
            print(f"❌ Eroare la instalarea pachetului {module}: {e}")
            return False

    def check_and_install_modules(self) -> None:
        def process_module(module):
            print(f"\n🔎 Verific dacă {module} este instalat...")
            if self.is_module_installed(module):
                print(f"✅ {module} este deja instalat.")
            else:
                print(f"📦 Instalez {module}...")
                self.run_pip_install(module)
                # Re-verifică după instalare
                if self.is_module_installed(module):
                    print(f"✅ {module} funcționează acum.")
                else:
                    print(f"❌ {module} nu funcționează după instalare.")

        with concurrent.futures.ThreadPoolExecutor() as executor:
            executor.map(process_module, self.modules)

def main():
    print("🔍 Verific pip...")
    manager = ModuleManager()
    if manager.pip_path:
        print(f"✅ Pip este disponibil la: {manager.pip_path}")
    else:
        print("⚠️ Pip nu este disponibil.")
        return

    directory = sys.argv[1] if len(sys.argv) > 1 else '.'
    print(f"\n📜 Scanez directorul {directory} pentru fișiere .py...")
    manager.collect_unique_modules(directory)
    
    if not manager.modules:
        print("⚠️ Nu s-au găsit module în importuri.")
        return
    
    print(f"\nModule unice detectate: {', '.join(manager.modules)}")
    manager.check_and_install_modules()

if __name__ == "__main__":
    main()

Saturday, August 30, 2025

Python Qt6 : ... management of installations and build python package.

Yesterday I created a small project for managing Python packages and building a new package based on added modules. I only tested the local installations of various Python versions and the creation of a new package, but it worked.
python catafest_build_package_001.py
🔍 Verificare module standard...
[✓] Modul standard 'json' este disponibil.
[✓] Modul standard 'subprocess' este disponibil.
[✓] Modul standard 'platform' este disponibil.
[✓] Modul standard 'datetime' este disponibil.
[✓] Modul standard 'os' este disponibil.
[✓] Modul standard 'sys' este disponibil.

📦 Verificare și instalare module pip...
[✓] Modulul 'PyQt6' este deja instalat.
[✓] Modulul 'build' este deja instalat.
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
  - wheel
...

Python 3.13.0 : Predicted XAU/USD with torch.

Testing the torch python package
import torch
import torch.nn as nn
import numpy as np

data = np.array([
    [1800.5, 1810.0, 1795.0, 1000, 1805.2],
    [1805.2, 1815.0, 1800.0, 1200, 1812.8],
    [1812.8, 1820.0, 1808.0, 1100, 1810.5],
    [1810.5, 1818.0, 1805.0, 1300, 1825.0],
    [1825.0, 1830.0, 1815.0, 1400, 1820.3],
    [1820.3, 1828.0, 1810.0, 1250, 1835.7]
])

X, y = torch.tensor(data[:, :4], dtype=torch.float32), torch.tensor(data[:, 4], dtype=torch.float32)
model = nn.Sequential(nn.Linear(4, 6), nn.ReLU(), nn.Linear(6, 4), nn.ReLU(), nn.Linear(4, 1))
optimizer = torch.optim.Adam(model.parameters())
loss_fn = nn.MSELoss()
for _ in range(3000):
    optimizer.zero_grad()
    y_pred = model(X).squeeze()
    loss = loss_fn(y_pred, y)
    loss.backward()
    optimizer.step()
prediction = model(torch.tensor([[1830.0, 1840.0, 1825.0, 1150]], dtype=torch.float32))
print("Predicted XAU/USD closing price:", round(prediction.item(), 2))
The result is :
python torch_001.py
Predicted XAU/USD closing price: 1819.57

Python 3.13.0 : Predicted XAU/USD with tensorflow.

This is the source code :
import tensorflow as tf
import numpy as np

data = np.array([
    [1800.5, 1810.0, 1795.0, 1000, 1805.2],
    [1805.2, 1815.0, 1800.0, 1200, 1812.8],
    [1812.8, 1820.0, 1808.0, 1100, 1810.5],
    [1810.5, 1818.0, 1805.0, 1300, 1825.0],
    [1825.0, 1830.0, 1815.0, 1400, 1820.3],
    [1820.3, 1828.0, 1810.0, 1250, 1835.7]
])

X, y = data[:, :4], data[:, 4]
model = tf.keras.Sequential([
    tf.keras.layers.Dense(6, activation='relu', input_shape=(4,)),
    tf.keras.layers.Dense(4, activation='relu'),
    tf.keras.layers.Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.fit(X, y, epochs=3000, verbose=0)
prediction = model.predict(np.array([[1830.0, 1840.0, 1825.0, 1150]]))
print("Predicted XAU/USD closing price:", round(prediction[0][0], 2))
The result is :
python tf_001.py
2025-08-30 21:11:13.966066: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.
C:\Python313\Lib\site-packages\google\protobuf\runtime_version.py:98: UserWarning: Protobuf gencode version 5.28.3 is exactly one major version older than the runtime version 6.31.1 at tensorflow/core/framework/attr_value.proto. Please update the gencode to avoid compatibility violations in the next runtime release.
...
Predicted XAU/USD closing price: 2.9

Wednesday, August 27, 2025

Python 3.13.0 : Predicted XAU/USD with MLPRegressor.

Testing the MLPRegressor from sklearn python package:
from sklearn.neural_network import MLPRegressor
import numpy as np

data = np.array([
    [1800.5, 1810.0, 1795.0, 1000, 1805.2],
    [1805.2, 1815.0, 1800.0, 1200, 1812.8],
    [1812.8, 1820.0, 1808.0, 1100, 1810.5],
    [1810.5, 1818.0, 1805.0, 1300, 1825.0],
    [1825.0, 1830.0, 1815.0, 1400, 1820.3],
    [1820.3, 1828.0, 1810.0, 1250, 1835.7]
])

X, y = data[:, :4], data[:, 4]
model = MLPRegressor(hidden_layer_sizes=(6, 4), max_iter=3000)
model.fit(X, y)

prediction = model.predict([[1830.0, 1840.0, 1825.0, 1150]])
print("Predicted XAU/USD closing price:", round(prediction[0], 2))
The answer is: Predicted XAU/USD closing price: 1836.68

Thursday, August 21, 2025

Python Qt6 : Use python with ffmpeg tool ...

If you download a video from youtube with high resolution using a tool as yt-dlp then you can get two files with video and audio content:
... one with be with .f401.mp4 and another with .f251-9.webm and using the ffmpeg tool you can create one .mp4 file with both audio and video content.
Let's see a source code with python and PyQt6 module to search into D:\Software folder and create the mp4 file.

import os
import subprocess
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QPushButton,
    QListWidget, QMessageBox
)
# fisier download : yt-dlp.exe -vU https://www.youtube.com/watch?v=xxxxxx -f bestvideo*+bestaudio/best
FOLDER_PATH = r"D:\Software"

class FFmpegMerger(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Combinare Video + Audio cu FFmpeg")
        self.resize(600, 400)

        self.layout = QVBoxLayout()
        self.file_list = QListWidget()
        self.process_button = QPushButton("Prelucrează în MP4")

        self.layout.addWidget(self.file_list)
        self.layout.addWidget(self.process_button)
        self.setLayout(self.layout)

        self.process_button.clicked.connect(self.process_files)

        self.populate_file_list()

    def populate_file_list(self):
        files = os.listdir(FOLDER_PATH)
        video_files = [f for f in files if f.endswith(".f401.mp4")]
        audio_files = [f for f in files if f.endswith(".f251-9.webm")]

        base_names = set(f.split(".f401.mp4")[0] for f in video_files)
        candidates = []

        for base in base_names:
            audio_name = f"{base}.f251-9.webm"
            output_name = f"{base}.mp4"
            if audio_name in audio_files and output_name not in files:
                candidates.append(base)

        for name in candidates:
            self.file_list.addItem(name)

    def process_files(self):
        for i in range(self.file_list.count()):
            base = self.file_list.item(i).text()
            video_path = os.path.join(FOLDER_PATH, f"{base}.f401.mp4")
            audio_path = os.path.join(FOLDER_PATH, f"{base}.f251-9.webm")
            output_path = os.path.join(FOLDER_PATH, f"{base}.mp4")

            cmd = [
                "ffmpeg",
                "-i", video_path,
                "-i", audio_path,
                "-c:v", "copy",
                "-c:a", "aac",
                "-strict", "experimental",
                output_path
            ]

            try:
                subprocess.run(cmd, check=True)
            except subprocess.CalledProcessError as e:
                QMessageBox.critical(self, "Eroare", f"Eroare la procesarea {base}: {e}")
                return

        QMessageBox.information(self, "Succes", "Toate fișierele au fost prelucrate cu succes!")

if __name__ == "__main__":
    app = QApplication([])
    window = FFmpegMerger()
    window.show()
    app.exec()

Sunday, August 17, 2025

News : Django Hijack

Log in and work on behalf of other users without having to know their credentials.
With Django Hijack, admins can impersonate and work on behalf of other users without having to know their credentials.
Comes with two versions available: v2.x and v3.x. The last v3.x provides a security first design, easy integration, customisation, out-of-the-box Django admin support and dark-mode. It is a complete rewrite and all former APIs are broken.

Monday, July 21, 2025

News : The geoai-py - part 001.

A powerful Python package for integrating Artificial Intelligence with geospatial data analysis and visualization
GeoAI bridges the gap between AI and geospatial analysis, providing tools for processing, analyzing, and visualizing geospatial data using advanced machine learning techniques. Whether you're working with satellite imagery, LiDAR point clouds, or vector data, GeoAI offers intuitive interfaces to apply cutting-edge AI models.
Today , I tested this python package named geoai-py. I used the pip tool:
pip install geoai-py
Successfully installed Flask-Caching-2.3.1 MarkupSafe-3.0.2 PySocks-1.7.1 PyYAML-6.0.2 absl-py-2.3.1 aenum-3.1.16 affine-2.4.0 aiohappyeyeballs-2.6.1 aiohttp-3.12.14 aiosignal-1.4.0 albucore-0.0.24 albumentations-2.0.8 aniso8601-10.0.1 annotated-types-0.7.0 antlr4-python3-runtime-4.9.3 anyio-4.9.0 anywidget-0.9.18 argon2-cffi-25.1.0 argon2-cffi-bindings-21.2.0 arrow-1.3.0 asttokens-3.0.0 beautifulsoup4-4.13.4 bitsandbytes-0.46.1 bleach-6.2.0 blinker-1.9.0 bqplot-0.12.45 branca-0.8.1 buildingregulariser-0.2.2 cachelib-0.13.0 cachetools-6.1.0 cffi-1.17.1 click-8.2.1 click-plugins-1.1.1.2 cligj-0.7.2 color-operations-0.2.0 comm-0.2.2 contextily-1.6.2 contourpy-1.3.2 cycler-0.12.1 datasets-4.0.0 decorator-5.2.1 defusedxml-0.7.1 dill-0.3.8 docstring-parser-0.17.0 duckdb-1.3.2 einops-0.8.1 eval-type-backport-0.2.2 ever-beta-0.5.1 executing-2.2.0 fastjsonschema-2.21.1 filelock-3.18.0 fiona-1.10.1 flask-3.1.1 flask-cors-6.0.1 flask-restx-1.3.0 folium-0.20.0 fonttools-4.59.0 fqdn-1.5.1 frozenlist-1.7.0 fsspec-2025.3.0 gdown-5.2.0 geoai-py-0.9.0 geographiclib-2.0 geojson-3.2.0 geopandas-1.1.1 geopy-2.4.1 gitdb-4.0.12 gitpython-3.1.44 grpcio-1.73.1 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 huggingface_hub-0.33.4 hydra-core-1.3.2 importlib-resources-6.5.2 ipyevents-2.0.2 ipyfilechooser-0.6.0 ipyleaflet-0.20.0 ipython-9.4.0 ipython-pygments-lexers-1.1.1 ipytree-0.2.2 ipyvue-1.11.2 ipyvuetify-1.11.3 ipywidgets-8.1.7 isoduration-20.11.0 itsdangerous-2.2.0 jedi-0.19.2 jinja2-3.1.6 joblib-1.5.1 jsonargparse-4.40.0 jsonnet-0.21.0 jsonpointer-3.0.0 jupyter-client-8.6.3 jupyter-core-5.8.1 jupyter-events-0.12.0 jupyter-leaflet-0.20.0 jupyter-server-2.16.0 jupyter-server-proxy-4.4.0 jupyter-server-terminals-0.5.3 jupyterlab-pygments-0.3.0 jupyterlab_widgets-3.0.15 kiwisolver-1.4.8 kornia-0.8.1 kornia_rs-0.1.9 leafmap-0.48.6 lightly-1.5.21 lightly_utils-0.0.2 lightning-2.5.2 lightning-utilities-0.14.3 localtileserver-0.10.6 mapclassify-2.10.0 maplibre-0.3.4 markdown-3.8.2 markdown-it-py-3.0.0 matplotlib-3.10.3 matplotlib-inline-0.1.7 mdurl-0.1.2 mercantile-1.2.1 mistune-3.1.3 morecantile-6.2.0 multidict-6.6.3 multiprocess-0.70.16 narwhals-1.48.0 nbclient-0.10.2 nbconvert-7.16.6 nbformat-5.10.4 numexpr-2.11.0 omegaconf-2.3.0 opencv-python-headless-4.12.0.88 overrides-7.7.0 overturemaps-0.15.0 pandas-2.3.1 pandocfilters-1.5.1 parso-0.8.4 planetary-computer-1.0.0 plotly-6.2.0 prettytable-3.16.0 prometheus-client-0.22.1 prompt_toolkit-3.0.51 propcache-0.3.2 psygnal-0.14.0 pure-eval-0.2.3 pyarrow-21.0.0 pycparser-2.22 pydantic-2.11.7 pydantic-core-2.33.2 pygments-2.19.2 pyogrio-0.11.0 pyparsing-3.2.3 pyproj-3.7.1 pystac-1.13.0 pystac-client-0.9.0 python-box-7.3.2 python-dateutil-2.9.0.post0 python-dotenv-1.1.1 python-json-logger-3.3.0 pytorch_lightning-2.5.2 pytz-2025.2 pywin32-311 pywinpty-2.0.15 pyzmq-27.0.0 rasterio-1.4.3 regex-2024.11.6 rfc3339-validator-0.1.4 rfc3986-validator-0.1.1 rich-14.0.0 rio-cogeo-5.4.2 rio-tiler-7.8.1 rioxarray-0.19.0 rtree-1.4.0 safetensors-0.5.3 scikit-learn-1.7.1 scooby-0.10.1 segmentation-models-pytorch-0.5.0 send2trash-1.8.3 sentry-sdk-2.33.0 server-thread-0.3.0 shapely-2.1.1 simpervisor-1.0.0 simsimd-6.5.0 six-1.17.0 smmap-5.0.2 sniffio-1.3.1 soupsieve-2.7 stack_data-0.6.3 stringzilla-3.12.5 tensorboard-2.20.0 tensorboard-data-server-0.7.2 tensorboardX-2.6.4 terminado-0.18.1 threadpoolctl-3.6.0 timm-1.0.17 tinycss2-1.4.0 tokenizers-0.21.2 torch-2.7.1 torchange-0.0.1 torchgeo-0.7.1 torchinfo-1.8.0 torchmetrics-1.7.4 torchvision-0.22.1 tornado-6.5.1 traitlets-5.14.3 traittypes-0.2.1 transformers-4.53.2 types-python-dateutil-2.9.0.20250708 typeshed-client-2.8.2 typing-inspection-0.4.1 tzdata-2025.2 uri-template-1.3.0 uvicorn-0.35.0 wandb-0.21.0 wcwidth-0.2.13 webcolors-24.11.1 webencodings-0.5.1 websocket-client-1.8.0 werkzeug-3.1.3 whitebox-2.3.6 whiteboxgui-2.3.0 widgetsnbextension-4.0.14 xarray-2025.7.1 xxhash-3.5.0 xyzservices-2025.4.0 yarl-1.20.1
Let's see my testing python example:
>>> import geoai
>>> dir(geoai)
['AgricultureFieldDelineator', 'Any', 'AutoConfig', 'AutoModelForMaskGeneration', 
'AutoModelForMaskedImageModeling', 'AutoProcessor', 'BoundingBox', 'BuildingFootprintExtractor',
 'CLIPSegForImageSegmentation', 'CLIPSegProcessor', 'CLIPSegmentation', 'CarDetector', 
'ChangeDetection', 'CustomDataset', 'DetectionResult', 'Dict', 'ET', 'GroundedSAM', 'Image', 
'Iterable', 'List', 'Map', 'MapLibre', 'MultiPolygon', 'NonGeoDataset', 'ObjectDetector', 
'Optional', 'OrderedDict', 'ParkingSplotDetector', 'Path', 'Polygon', 'RandomRotation', 
'ShipDetector', 'SolarPanelDetector', 'Tuple', 'Union', 'Window', '__author__', 
'__builtins__', '__cached__', '__doc__', '__email__', '__file__', '__loader__', '__name__', 
'__package__', '__path__', '__spec__', '__version__', 'adaptive_regularization', 
'add_geometric_properties', 'analyze_vector_attributes', 'batch_vector_to_raster', 'bbox_to_xy',
 'box', 'boxes_to_vector', 'calc_stats', 'change_detection', 'classify', 'classify_image', 
'classify_images', 'clip_raster_by_bbox', 'coords_to_xy', 'create_overview_image', 
'create_split_map', 'create_vector_data', 'csv', 'cv2', 'dataclass', 'deeplabv3_resnet50', 
'dict_to_image', 'dict_to_rioxarray', 'download', 'download_file', 'download_model_from_hf', 
'download_naip', 'download_overture_buildings', 'download_pc_stac_item', 'edit_vector_data', 
'export_geotiff_tiles', 'export_geotiff_tiles_batch', 'export_tiles_to_geojson', 
'export_training_data', 'extract', 'extract_building_stats', 'fasterrcnn_resnet50_fpn_v2', 
'fcn_resnet50', 'features', 'geoai', 'geojson_to_coords', 'geojson_to_xy', 'get_device', 
'get_instance_segmentation_model', 'get_model_config', 'get_model_input_channels', 
'get_overture_data', 'get_raster_info', 'get_raster_info_gdal', 'get_raster_resolution', 
'get_raster_stats', 'get_vector_info', 'get_vector_info_ogr', 'glob', 'gpd', 'hf', 
'hf_hub_download', 'hybrid_regularization', 'image_segmentation', 'inspect_pth_file', 
'install_package', 'instance_segmentation', 'instance_segmentation_batch', 
'instance_segmentation_inference_on_geotiff', 'json', 'leafmap', 'logging', 'maplibregl', 
'mapping', 'mask_generation', 'maskrcnn_resnet50_fpn', 'masks_to_vector', 'math', 
'mosaic_geotiffs', 'ndimage', 'np', 'object_detection', 'object_detection_batch', 'orthogonalize',
 'os', 'pc_collection_list', 'pc_item_asset_list', 'pc_stac_download', 'pc_stac_search', 'pd', 
'pipeline', 'plot_batch', 'plot_images', 'plot_masks', 'plot_performance_metrics', 
'plot_prediction_comparison', 'plt', 'print_raster_info', 'print_vector_info', 'raster_to_vector',
 'raster_to_vector_batch', 'rasterio', 'read_pc_item_asset', 'read_raster', 'read_vector', 
'region_groups', 'regularization', 'regularize', 'requests', 'rotate', 'rowcol_to_xy', 'rxr', 
'segment', 'semantic_segmentation', 'semantic_segmentation_batch', 'set_proj_lib_path', 'shape', 
'show', 'stack_bands', 'subprocess', 'sys', 'temp_file_path', 'time', 'torch', 'torchgeo', 'tqdm',
 'train', 'train_MaskRCNN_model', 'train_classifier', 'train_instance_segmentation_model', 
'train_segmentation_model', 'transform_bounds', 'try_common_architectures', 'utils', 
'vector_to_geojson', 'vector_to_raster', 'view_image', 'view_pc_item', 'view_pc_items', 
'view_raster', 'view_vector', 'view_vector_interactive', 'visualize_vector_by_attribute', 
'warnings', 'write_colormap', 'xr']

Sunday, July 13, 2025

Python Qt6 : simple celtic knots tool with SVG file format.

Today, I try to create SVG file with an celtic knot design tool.
I used random values from -360 up to 360 for for Twist 1, Twist 2, and Twist 3 sliders.
The basic function is this, is created by artificial intelligence and not works very well.
        # Generate star polygon vertices
        points_cw = []
        points_ccw = []
        for i in range(steps):
            t = 2 * math.pi * i / steps
            r = outer_radius if i % 2 == 0 else inner_radius
            x_cw = center[0] + r * math.cos(t)
            y_cw = center[1] + r * math.sin(t)
            x_ccw = center[0] + r * math.cos(-t + math.pi / max(lobes, 1))
            y_ccw = center[1] + r * math.sin(-t + math.pi / max(lobes, 1))
            points_cw.append((x_cw, y_cw))
            points_ccw.append((x_ccw, y_ccw))
See one random example with this tool:

Saturday, July 12, 2025

Python Qt6 : simple merge sprites images with unittest feature.

Today, I created one python tool script with the artificial intelligence to merge sprites images.
I used the artificial intelligence to add unittest to create default images with PIL to test the result.
You can select your folder , select the align of merge features or test with unittest button.
This is the result and works well:
import os
import unittest
from PIL import Image, ImageDraw, ImageFont, ImageQt
import shutil
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog, QLabel, QVBoxLayout, QWidget, QComboBox
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt
import sys

def create_test_image(path, size, number):
    img = Image.new('RGBA', size, (255, 255, 255, 255))
    draw = ImageDraw.Draw(img)
    # Simplified to just draw the number with a basic color background
    draw.rectangle((0, 0, size[0], size[1]), fill=(0, 100 * number % 255, 0, 255))
    try:
        font = ImageFont.load_default()
    except:
        font = None
    draw.text((size[0]//2-5, size[1]//2-5), str(number), fill=(255, 255, 255, 255), font=font)
    img.save(path, 'PNG')

def merge_sprites(folder_path, output_horizontal, output_vertical):
    images = [Image.open(os.path.join(folder_path, f)) for f in os.listdir(folder_path) if f.endswith(('.png', '.jpg', '.jpeg'))]
    
    if not images:
        return None, None
    
    width, height = images[0].size
    
    # Horizontal merge
    total_width = width * len(images)
    horizontal_image = Image.new('RGBA', (total_width, height))
    for i, img in enumerate(images):
        horizontal_image.paste(img, (i * width, 0))
    horizontal_image.save(output_horizontal, 'PNG')
    
    # Vertical merge
    total_height = height * len(images)
    vertical_image = Image.new('RGBA', (width, total_height))
    for i, img in enumerate(images):
        vertical_image.paste(img, (0, i * height))
    vertical_image.save(output_vertical, 'PNG')
    
    return horizontal_image, vertical_image

class TestSpriteMerger(unittest.TestCase):
    def setUp(self):
        self.test_folder = 'test_images'
        self.size = (50, 20)
        os.makedirs(self.test_folder, exist_ok=True)
        for i in range(3):
            create_test_image(os.path.join(self.test_folder, f'test_{i+1}.png'), self.size, i+1)
    
    def test_merge_horizontal(self):
        output_h = 'test_merged_horizontal.png'
        output_v = 'test_merged_vertical.png'
        h_img, _ = merge_sprites(self.test_folder, output_h, output_v)
        
        self.assertIsNotNone(h_img, "Horizontal merge failed")
        self.assertEqual(h_img.size, (self.size[0] * 3, self.size[1]))
    
    def test_merge_vertical(self):
        output_h = 'test_merged_horizontal.png'
        output_v = 'test_merged_vertical.png'
        _, v_img = merge_sprites(self.test_folder, output_h, output_v)
        
        self.assertIsNotNone(v_img, "Vertical merge failed")
        self.assertEqual(v_img.size, (self.size[0], self.size[1] * 3))
    
    def tearDown(self):
        if os.path.exists(self.test_folder):
            shutil.rmtree(self.test_folder)
        for f in ['test_merged_horizontal.png', 'test_merged_vertical.png']:
            if os.path.exists(f):
                os.remove(f)

class SpriteMergerApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Sprite Merger")
        self.setGeometry(100, 100, 800, 600)
        
        self.folder_path = ""
        
        layout = QVBoxLayout()
        
        self.select_button = QPushButton("Select Folder")
        self.select_button.clicked.connect(self.select_folder)
        layout.addWidget(self.select_button)
        
        self.merge_type = QComboBox()
        self.merge_type.addItems(["Horizontal", "Vertical"])
        layout.addWidget(self.merge_type)
        
        self.process_button = QPushButton("Process Selected Folder")
        self.process_button.clicked.connect(self.process_folder)
        layout.addWidget(self.process_button)
        
        self.test_button = QPushButton("Run Unit Test")
        self.test_button.clicked.connect(self.run_unit_test)
        layout.addWidget(self.test_button)
        
        self.result_label = QLabel("No image processed")
        layout.addWidget(self.result_label)
        
        self.image_label = QLabel()
        layout.addWidget(self.image_label)
        
        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)
    
    def select_folder(self):
        self.folder_path = QFileDialog.getExistingDirectory(self, "Select Sprite Folder")
        self.result_label.setText(f"Selected: {self.folder_path}")
    
    def process_folder(self):
        if not self.folder_path:
            self.result_label.setText("Please select a folder first")
            return
        h_img, v_img = merge_sprites(self.folder_path, 'merged_horizontal.png', 'merged_vertical.png')
        selected_type = self.merge_type.currentText()
        
        img = h_img if selected_type == "Horizontal" else v_img
        if img:
            pixmap = QPixmap.fromImage(ImageQt.ImageQt(img))
            self.image_label.setPixmap(pixmap.scaled(700, 500, aspectRatioMode=Qt.AspectRatioMode.KeepAspectRatio))
            self.result_label.setText(f"{selected_type} merge completed")
        else:
            self.result_label.setText(f"{selected_type} merge failed")
    
    def run_unit_test(self):
        suite = unittest.TestLoader().loadTestsFromTestCase(TestSpriteMerger)
        result = unittest.TextTestRunner().run(suite)
        
        test_folder = 'test_images'
        os.makedirs(test_folder, exist_ok=True)
        for i in range(3):
            create_test_image(os.path.join(test_folder, f'test_{i+1}.png'), (50, 20), i+1)
        
        h_img, v_img = merge_sprites(test_folder, 'test_merged_horizontal.png', 'test_merged_vertical.png')
        selected_type = self.merge_type.currentText()
        
        img = h_img if selected_type == "Horizontal" else v_img
        if img:
            pixmap = QPixmap.fromImage(ImageQt.ImageQt(img))
            self.image_label.setPixmap(pixmap.scaled(700, 500, aspectRatioMode=Qt.AspectRatioMode.KeepAspectRatio))
            self.result_label.setText(f"Unit tests: {result.testsRun} run, {len(result.failures)} failed, showing {selected_type.lower()} merge")
        else:
            self.result_label.setText(f"Unit tests: {result.testsRun} run, {len(result.failures)} failed, merge failed")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = SpriteMergerApp()
    window.show()
    sys.exit(app.exec())

Sunday, July 6, 2025

Python 3.13.5 : keras and torch and tensorflow on python version 3.13.5 !

I am not very satisfied with the security of the system in this area, I have noticed intrusions when I was at the Vodafone provider and now I am on mobile and they persist. I should improve my software and hardware protection and restart the system, but I have the impression that it won't help much considering the hacking capabilities that exist.
For now, I'm sticking with this solution, because it's quite good for simple tests with the Python language.
Today I will show you that the involvement of developers is somewhat lagging behind, and this can be seen from the analysis of the development progression across versions of the Python language, as it is not easy to implement in newer versions. Some packages, although important, are not available in newer versions.Today I will show you that the involvement of developers is somewhat lagging behind, and this can be seen from the analysis of the development progression across versions of the Python language, as it is not easy to implement in newer versions. Some packages, although important, are not available in newer versions. Let's see these python packages:
Keras is a deep learning API designed for human beings, not machines. Keras focuses on debugging speed, code elegance & conciseness, maintainability, and deployability. When you choose Keras, your codebase is smaller, more readable, easier to iterate on.
... read more on the official website.
pip install --upgrade keras
Collecting keras
  Downloading keras-3.10.0-py3-none-any.whl.metadata (6.0 kB)
...
Successfully installed absl-py-2.3.0 h5py-3.14.0 keras-3.10.0 ml-dtypes-0.5.1 namex-0.1.0 optree-0.16.0
TensorFlow does not support Python 3.13 as of July 2025; it supports Python 3.9–3.11. To use Keras with TensorFlow, downgrade to Python 3.11, and this install will comes with:
pip install tensorflow
ERROR: Could not find a version that satisfies the requirement tensorflow (from versions: none)
ERROR: No matching distribution found for tensorflow
You can use the torch python package:
pip install torch
Collecting torch
...
Successfully installed filelock-3.18.0 fsspec-2025.5.1 mpmath-1.3.0 sympy-1.14.0 torch-2.7.1
... during the test with these packages in running it seems that I have errors. I believe that those who develop Python didn't really have a strategy regarding the protection of installed packages because I've found all sorts of junk packages that can be installed with pip or from GitHub.

Saturday, July 5, 2025

Python 3.13.5 : the groq tested with basic example !

About groq you can find on the official Grok website .
Today I tested the groq A.P.I. with the basic example :
import os

from groq import Groq

client = Groq(
    api_key="gsk_..."
)

chat_completion = client.chat.completions.create(
    messages=[
        {
            "role": "user",
            "content": "explain what groq is",
        }
    ],
    model="llama-3.3-70b-versatile",
)

print(chat_completion.choices[0].message.content)
The result of : "explain what groq is" is that :
Groq is a relatively new and innovative technology company that focuses on developing high-performance, artificial intelligence (AI) computing hardware and software solutions. Founded in 2016 by Jonathan Ross, a former Google engineer, Groq aims to provide faster, more efficient, and scalable AI computing capabilities to various industries. Groq's primary product is a tensor processing unit (TPU) chip designed specifically for machine learning (ML) and deep learning (DL) workloads. This TPU is optimized for high-performance, low-latency, and low-power consumption, making it suitable for applications that require rapid processing of vast amounts of data, such as: 1. **Computer Vision**: Image and video recognition, object detection, and tracking. 2. **Natural Language Processing (NLP)**: Text analysis, sentiment analysis, and language translation. 3. **Speech Recognition**: Voice command processing and speech-to-text applications. Groq's innovative architecture and design philosophy are centered around the following key aspects: 1. **High-Bandwidth Memory**: Groq's TPU features high-bandwidth memory, which enables fast data transfer and processing. 2. **Scalable Architecture**: The TPU is designed to scale horizontally, allowing for easy expansion to meet growing computational demands. 3. **Low-Latency**: Groq's architecture minimizes latency, ensuring fast response times and real-time processing capabilities. 4. **Software-Defined**: The TPU is software-defined, allowing for flexibility and customization to support a wide range of AI applications and frameworks. Groq's technology has the potential to accelerate AI adoption in various industries, including: 1. **Autonomous Vehicles**: Enhanced computer vision and sensor processing for safer and more efficient autonomous driving. 2. **Healthcare**: Faster medical image analysis and diagnosis, as well as improved personalized medicine and treatment planning. 3. **Financial Services**: Enhanced risk analysis, portfolio optimization, and fraud detection using AI-powered systems. While Groq is still a relatively new company, its innovative approach to AI computing has garnered significant attention and interest from the tech industry, investors, and potential customers. As AI continues to transform various aspects of our lives, Groq's technology is poised to play a significant role in shaping the future of artificial intelligence and machine learning.

Wednesday, July 2, 2025

Python Qt6 : ... simple resize image files.

I like the combination of Python development and the inclusion of the PyQt6 module. It is very fast and stable and allows me to create all sorts of tools to use.
Today I will show you another handy script that allows you to read all the image files from a folder and, depending on the selections: height, length, and/or aspect ratio, resize them and then place them in a folder created specifically for the resulting images.
Here is how the script looks, I clearly used artificial intelligence and it didn't take more than a few minutes, my evaluation, testing, and rearranging the interface took longer ...
import sys
import os
from datetime import datetime
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QFileDialog, QLineEdit, QCheckBox, QLabel, QMessageBox
from PyQt6.QtCore import Qt
from PIL import Image

class ResizeApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Image Resizer")
        self.setGeometry(100, 100, 400, 200)

        layout = QVBoxLayout()
        central_widget = QWidget()
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

        self.folder_button = QPushButton("Select Folder")
        self.folder_button.clicked.connect(self.select_folder)
        layout.addWidget(self.folder_button)

        self.width_edit = QLineEdit("800")
        self.width_edit.setPlaceholderText("Width (px)")
        layout.addWidget(QLabel("Width:"))
        layout.addWidget(self.width_edit)

        self.height_edit = QLineEdit("600")
        self.height_edit.setPlaceholderText("Height (px)")
        layout.addWidget(QLabel("Height:"))
        layout.addWidget(self.height_edit)

        self.aspect_ratio = QCheckBox("Maintain Aspect Ratio")
        self.aspect_ratio.setChecked(True)
        layout.addWidget(self.aspect_ratio)

        self.resize_button = QPushButton("Resize Images")
        self.resize_button.clicked.connect(self.resize_images)
        layout.addWidget(self.resize_button)

        self.folder_path = ""

    def select_folder(self):
        self.folder_path = QFileDialog.getExistingDirectory(self, "Select Image Folder")
        if self.folder_path:
            self.folder_button.setText(f"Selected: {os.path.basename(self.folder_path)}")

    def resize_images(self):
        if not self.folder_path:
            QMessageBox.warning(self, "Error", "Please select a folder.")
            return

        try:
            width = int(self.width_edit.text())
            height = int(self.height_edit.text())
        except ValueError:
            QMessageBox.warning(self, "Error", "Please enter valid width and height.")
            return

        if width <= 0 or height <= 0:
            QMessageBox.warning(self, "Error", "Width and height must be positive.")
            return

        date_str = datetime.now().strftime("%d%m%y_%H%M")
        aspect_str = "asp_on" if self.aspect_ratio.isChecked() else "asp_off"
        output_folder = os.path.join(self.folder_path, f"resized_{date_str}_{height}_{aspect_str}")
        os.makedirs(output_folder, exist_ok=True)

        for file_name in os.listdir(self.folder_path):
            if file_name.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
                image_path = os.path.join(self.folder_path, file_name)
                try:
                    with Image.open(image_path) as img:
                        if self.aspect_ratio.isChecked():
                            img.thumbnail((width, height), Image.Resampling.LANCZOS)
                        else:
                            img = img.resize((width, height), Image.Resampling.LANCZOS)
                        output_path = os.path.join(output_folder, f"resized_{date_str}_{height}_{aspect_str}_{file_name}")
                        img.save(output_path)
                except Exception as e:
                    QMessageBox.warning(self, "Error", f"Failed to process {file_name}: {str(e)}")

        QMessageBox.information(self, "Success", f"Images resized and saved to {output_folder}!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ResizeApp()
    window.show()
    sys.exit(app.exec())

Tuesday, July 1, 2025

Python 3.13.5 : use the jupyterlab, notebook and voila - part 001.

JupyterLab is the latest web-based interactive development environment for notebooks, code, and data. Its flexible interface allows users to configure and arrange workflows in data science, scientific computing, computational journalism, and machine learning. A modular design invites extensions to expand and enrich functionality.
Let's test with these python modules: jupyterlab, notebook and voila.
First, I install with pip tool the jupyterlab python module:
pip install jupyterlab
Collecting jupyterlab
...
Successfully installed anyio-4.9.0 argon2-cffi-25.1.0 argon2-cffi-bindings-21.2.0 arrow-1.3.0 asttokens-3.0.0 async-lru-2.0.5
attrs-25.3.0 babel-2.17.0 bleach-6.2.0 cffi-1.17.1 comm-0.2.2 debugpy-1.8.14 defusedxml-0.7.1 executing-2.2.0 
fastjsonschema-2.21.1 fqdn-1.5.1 h11-0.16.0 httpcore-1.0.9 httpx-0.28.1 ipykernel-6.29.5 ipython-9.4.0 
ipython-pygments-lexers-1.1.1 isoduration-20.11.0 jedi-0.19.2 json5-0.12.0 jsonpointer-3.0.0 jsonschema-4.24.0 
jsonschema-specifications-2025.4.1 jupyter-client-8.6.3 jupyter-core-5.8.1 jupyter-events-0.12.0 jupyter-lsp-2.2.5 
jupyter-server-2.16.0 jupyter-server-terminals-0.5.3 jupyterlab-4.4.4 jupyterlab-pygments-0.3.0 jupyterlab-server-2.27.3 
matplotlib-inline-0.1.7 mistune-3.1.3 nbclient-0.10.2 nbconvert-7.16.6 nbformat-5.10.4 nest-asyncio-1.6.0 notebook-shim-0.2.4
overrides-7.7.0 pandocfilters-1.5.1 parso-0.8.4 platformdirs-4.3.8 prometheus-client-0.22.1 prompt_toolkit-3.0.51 
psutil-7.0.0 pure-eval-0.2.3 pycparser-2.22 python-json-logger-3.3.0 pywin32-310 pywinpty-2.0.15 pyyaml-6.0.2 pyzmq-27.0.0
referencing-0.36.2 rfc3339-validator-0.1.4 rfc3986-validator-0.1.1 rpds-py-0.26.0 send2trash-1.8.3 sniffio-1.3.1 
stack_data-0.6.3 terminado-0.18.1 tinycss2-1.4.0 tornado-6.5.1 traitlets-5.14.3 types-python-dateutil-2.9.0.20250516 
uri-template-1.3.0 wcwidth-0.2.13 webcolors-24.11.1 webencodings-0.5.1 websocket-client-1.8.0
Next, the install of the notebook python module
pip install notebook
Collecting notebook
...
Installing collected packages: notebook
Successfully installed notebook-7.4.4
This python package named voila will help us to use online graphic user interfaces:
pip install voila
Collecting voila
...
Successfully installed voila-0.5.8 websockets-15.0.1
The voila package need to work with ipywidgets python package:
pip install ipywidgets
Collecting ipywidgets
...
Successfully installed ipywidgets-8.1.7 jupyterlab_widgets-3.0.15 widgetsnbextension-4.0.14
Let's start the jupiter tool with this command:
jupyter notebook
I used an default python example with a slider:
import ipywidgets as widgets
from IPython.display import display

slider = widgets.IntSlider(value=5, min=0, max=10)
display(slider)
This command will start the web with the slider using the voila command:
voila test.ipynb
The result is this:

Friday, June 27, 2025

Python 3.13.5 : the manim python module - part 001.

I used this package few days ago and now I wrote about how can used it.
Update the new release of pip is available: 25.0.1 -> 25.1.1 , run this command:
python.exe -m pip install --upgrade pip
The documentation can be found on the official website.
pip install manim
Collecting manim
  Downloading manim-0.19.0-py3-none-any.whl.metadata (11 kB)
...
Successfully installed Pillow-11.2.1 Pygments-2.19.1 audioop-lts-0.2.1 av-13.1.0 beautifulsoup4-4.13.4 click-8.2.1 cloup-3.0.7 colorama-0.4.6 decorator-5.2.1 glcontext-3.0.0 isosurfaces-0.1.2 manim-0.19.0 manimpango-0.6.0 mapbox-earcut-1.0.3 markdown-it-py-3.0.0 mdurl-0.1.2 moderngl-5.12.0 moderngl-window-3.1.1 networkx-3.5 numpy-2.3.0 pycairo-1.28.0 pydub-0.25.1 pyglet-2.1.6 pyglm-2.8.2 rich-14.0.0 scipy-1.15.3 screeninfo-0.8.1 skia-pathops-0.8.0.post2 soupsieve-2.7 srt-3.5.3 svgelements-1.9.6 tqdm-4.67.1 typing-extensions-4.14.0 watchdog-6.0.0
Let's see how can be used to see the help area:
python.exe -m manim render --help
Manim Community v0.19.0

Usage: python -m manim render ...
Let's use this source code:
from manim import *

class AdvancedAnimation(Scene):
    def construct(self):
        # Scene 1: Introduction
        title = Text("Advanced Animation with Manim").scale(0.76)
        self.play(FadeIn(title))
        self.wait(2)

        # Scene 2: Custom Animation
        circle = Circle().set_fill(color=BLUE, opacity=0.5)
        square = Square().set_fill(color=RED, opacity=0.5)
        self.add(circle, square)
        self.play(
            Rotate(circle, angle=TAU),
            Rotate(square, angle=-TAU),
            run_time=2,
            rate_func=linear
        )
        self.wait()

        # Scene 3: Text Animation
        text = Text("This is a custom text animation", font_size=40).to_edge(UP)
        self.play(Write(text), run_time=2)
        self.wait()

        # Scene 4: Shapes Manipulation
        triangle = Triangle().shift(RIGHT * 2)
        self.play(GrowFromCenter(triangle), run_time=1.5)
        self.wait()

        # Scene 5: Transition to next scene
        self.play(Uncreate(triangle), FadeOut(text))

        # Scene 6: Final Animation
        final_text = Text("This is the end of our animation", font_size=50).to_edge(DOWN)
        self.play(FadeIn(final_text), run_time=1.5)
        self.wait(2)

# Run the animation
AdvancedAnimation()
Use this command to render:
python.exe -m manim render manim_test_001.py AdvancedAnimation -p
AdvancedAnimation -p
Manim Community v0.19.0

[06/27/25 19:52:43] INFO     Animation 0 : Partial movie file      scene_file_writer.py:588
                             written in
                             'D:\PythonProjects\manim_projects\med
                             ia\videos\manim_test_001\1080p60\part
                             ial_movie_files\AdvancedAnimation\397
                             7891868_355746014_223132457.mp4'
...
[06/27/25 19:53:56] INFO     Previewed File at:                             file_ops.py:237
                             'D:\PythonProjects\manim_projects\media\videos
                             \manim_test_001\1080p60\AdvancedAnimation.mp4'
The result comes with many files, see this 1080p60 video result:

Python Qt6 : ... simple processing file.

Today I will show you an simple python script with PyQt6.
This script ai build using the artificial inteligence and I tested will process your files by slections : copy to another folder , zip all selected and delete all selected.
import sys
import os
import re
import shutil
import zipfile
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QPushButton, QListWidget, QFileDialog, QMessageBox, QDialog, QLabel)
from PyQt6.QtCore import Qt

class CriteriaDialog(QDialog):
    def __init__(self, folder, parent=None):
        super().__init__(parent)
        self.setWindowTitle(f"Processing Folder: {folder}")
        self.layout = QVBoxLayout(self)
        self.layout.addWidget(QLabel(f"Selected folder: {folder}"))
        self.ok_button = QPushButton("OK")
        self.ok_button.clicked.connect(self.accept)
        self.layout.addWidget(self.ok_button)

class DuplicateFinder(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Duplicate File Finder")
        self.setGeometry(100, 100, 600, 400)
        
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)
        
        self.file_list = QListWidget()
        self.file_list.setSelectionMode(QListWidget.SelectionMode.MultiSelection)
        self.layout.addWidget(self.file_list)
        
        button_layout = QHBoxLayout()
        self.select_button = QPushButton("Select Folder")
        self.select_button.clicked.connect(self.select_folder)
        button_layout.addWidget(self.select_button)
        
        self.copy_button = QPushButton("Copy To")
        self.copy_button.clicked.connect(self.copy_files)
        button_layout.addWidget(self.copy_button)
        
        self.zip_button = QPushButton("Zip All")
        self.zip_button.clicked.connect(self.zip_files)
        button_layout.addWidget(self.zip_button)
        
        self.delete_button = QPushButton("Delete All")
        self.delete_button.clicked.connect(self.delete_files)
        button_layout.addWidget(self.delete_button)
        
        self.layout.addLayout(button_layout)
        
        self.files = []
        self.selected_folder = ""
        
    def select_folder(self):
        folder = QFileDialog.getExistingDirectory(self, "Select Folder")
        if folder:
            self.selected_folder = folder
            dialog = CriteriaDialog(folder, self)
            if dialog.exec():
                self.files = []
                self.file_list.clear()
                self.scan_folder(folder)
                self.find_duplicates()
            
    def scan_folder(self, folder):
        for root, _, files in os.walk(folder):
            for file in files:
                file_path = os.path.join(root, file)
                self.files.append({
                    'path': file_path,
                    'name': os.path.basename(file_path),
                    'size': os.path.getsize(file_path),
                    'extension': os.path.splitext(file_path)[1]
                })
                
    def find_duplicates(self):
        duplicates = self.find_by_similar_name()
        self.display_duplicates(duplicates)
        
    def find_by_similar_name(self):
        duplicates = []
        name_groups = {}
        pattern = r'(.+?)(?:[\s_-]*\d{3,}|[\s_-]*\d{1,2}|_)?(?:\.\w+)?$'
        
        for file in self.files:
            match = re.match(pattern, file['name'])
            if match:
                base_name = match.group(1)
                if base_name in name_groups:
                    name_groups[base_name].append(file)
                else:
                    name_groups[base_name] = [file]
        
        for base_name, files in name_groups.items():
            if len(files) > 1:
                duplicates.extend(files)
                
        return duplicates
    
    def display_duplicates(self, duplicates):
        self.file_list.clear()
        for file in duplicates:
            self.file_list.addItem(file['path'])
            
    def copy_files(self):
        if not self.file_list.selectedItems():
            QMessageBox.warning(self, "Warning", "No files selected!")
            return
        dest_folder = QFileDialog.getExistingDirectory(self, "Select Destination Folder")
        if dest_folder:
            for item in self.file_list.selectedItems():
                file_path = item.text()
                dest_path = os.path.join(dest_folder, os.path.basename(file_path))
                shutil.copy2(file_path, dest_path)
            QMessageBox.information(self, "Success", "Files copied!")
            
    def zip_files(self):
        if not self.file_list.selectedItems():
            QMessageBox.warning(self, "Warning", "No files selected!")
            return
        zip_path = QFileDialog.getSaveFileName(self, "Save Zip File", "", "Zip Files (*.zip)")[0]
        if zip_path:
            with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
                for item in self.file_list.selectedItems():
                    file_path = item.text()
                    zipf.write(file_path, os.path.basename(file_path))
            QMessageBox.information(self, "Success", "Files zipped!")
        
    def delete_files(self):
        if not self.file_list.selectedItems():
            QMessageBox.warning(self, "Warning", "No files selected!")
            return
        reply = QMessageBox.question(self, "Confirm", "Delete selected files?",
                                  QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
        if reply == QMessageBox.StandardButton.Yes:
            for item in self.file_list.selectedItems():
                os.remove(item.text())
            self.file_list.clear()
            QMessageBox.information(self, "Success", "Files deleted!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = DuplicateFinder()
    window.show()
    sys.exit(app.exec())