analitics

Pages

Wednesday, July 8, 2026

Python Qt : Script for Game Engine projects.

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

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

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

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

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

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

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

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

        total_size = 0
        gd_size = 0
        media_size = 0

        tree_lines = []

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

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

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

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

            except Exception:
                pass

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

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

        report_text = "\n".join(report_lines)

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

        self.finished.emit(report_text)

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

        self.folder_path = None
        self.worker = None

        central = QWidget()
        layout = QVBoxLayout(central)

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

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

        self.setCentralWidget(central)

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

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

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

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

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

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

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

Tuesday, July 7, 2026

Python Qt : simple tool to convert any source code to html area development.

Today. I will show this simple idea to convert any source code for html tag code with PyQt6.
The source code of this tool is not very big.I don't share because can be simple or you can customize as you want starting with any artificial intelligence and is more easy for you.
I used this on my blogger area, let's see the result for a simple example source code Google Apps Script from Gemini AI to html source code with div , pre and code html tags included in the result:

Python Qt : simple tool for audio dialogue in game development

Today, this script tool is a small desktop tool that lets you visually synchronize spoken audio with written dialogue. You load an audio file and the program generates a waveform so you can click or drag to select exact time ranges. At the same time, you select the matching text, and the tool creates timestamped dialogue segments.
Each segment includes a dialog ID, start time, end time, and the associated text. Segments appear in a list, can be played individually, deleted, or tested in a separate window where each dialog ID becomes a playback button. This makes it easy to verify timing and structure.
The entire project—audio path, full text, and all segments—can be saved or loaded as a JSON file. Older JSON formats containing only segments are automatically converted. The final JSON is ready for use in game engines like Godot or Unity for precise voice‑over playback.
I used artificial intelligence to fix some issues, this is the result:

Monday, July 6, 2026

Tools : TraceFlow artificial intelligence for python tasks.

This tool with artificial intelligence can help with python programming tasks.
TraceFlow captures crashes, traces every variable, and streams an AI-powered fix — all inside VSCode. No context switching. No guessing.
Perfect for trying out TraceFlow on personal projects.
  • 5 analysis per day
  • Crash detection & variable tracing
  • AI root cause explanation
  • One-click fix apply
  • Call stack inspection
  • Module & function level analysis

Sunday, July 5, 2026

Python 3.10.11 : python library-skills for your artificial intelligence.

The Python package library-skills is a lightweight command‑line toolkit designed to help developers build, test, and validate modular AI “skills.” These skills are small, self‑contained units of logic that can be executed independently or integrated into larger AI agents. The package focuses on simplicity, portability, and clear structure, making it useful for developers who want to experiment with tool‑calling systems or create custom capabilities for AI workflows.
A skill typically consists of a JSON descriptor and a Python function. The JSON file defines the skill’s name, description, and input schema, while the Python file contains the actual execution logic. This separation ensures that skills remain easy to document, validate, and reuse across different projects. With library-skills, developers can quickly inspect a skill’s schema, run it with custom input, or verify that its output matches the expected structure.
The command‑line interface provided by the package allows users to list installed skills, execute them directly, and validate input files without writing additional code. This makes the development cycle faster and more predictable. Instead of manually wiring functions together, developers can rely on a consistent interface that handles loading, parsing, and execution.
One of the main advantages of library-skills is its role in AI agent development. Modern agents often rely on tool‑calling, where the AI selects and triggers external functions based on user intent. Skills created with this package can be easily integrated into such agents, providing clear schemas and predictable behavior. This helps ensure that AI systems remain reliable, debuggable, and easy to extend.
Overall, library-skills is a practical utility for anyone building structured AI tools. It encourages clean design, modularity, and transparency, making it a valuable addition to Python environments focused on AI experimentation and agent development.
Let's install this python package.
python -m pip install library-skills
Collecting library-skills
  Downloading library_skills-0.0.19-py3-none-any.whl.metadata (5.4 kB)
...
Successfully installed library-skills-0.0.19 rich-toolkit-0.20.1 tomli-2.4.1
Let's make the first run:
library-skills.exe

 context
Project root               c:\lucru\PythonProjects
Target Python environment  not found

 Warning:  No target Python environment with site-packages or node_modules was found. Run from a
project root after installing dependencies, for example with 'uv sync' for Python or 'npm install' for
Node.js.

No installed or discovered skills found.
Copy the Library Skills tool skill into the project so agents know how to update, repair, and check
managed skills?
■ Copy Library Skills tool skill into the project so agents know how to update, repair, and check
managed skills? Copy Library Skills tool skill

 Target     Status               Path
 universal  tool skill: missing  .agents\skills\library-skills
 Copied:  library-skills (universal) -> .agents\skills\library-skills
Now you can create skills for your artificial intelligence:
Create a folder with two files:
my_skill/
    skill.json
    skill.py
First file named skill.json:
{
    "name": "hello_skill",
    "description": "Returnează un mesaj simplu",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"}
        },
        "required": ["name"]
    }
}
The second file named skill.py
def run(input):
    name = input["name"]
    return {"message": f"Salut, {name}!"}
Run the skill into your folder:
library-skills run my_skill --input '{"name": "Catalin"}'
See the schema:
library-skills schema my_skill
Validate the input:
library-skills validate my_skill input.json
List the skills:
library-skills list
This is all you need for a default basic skill with the library-skills.

Python 3.10.11 : CVSS (Common Vulnerability Scoring System) with cvss python package.

This Python package contains CVSS v2, v3 and v4 computation utilities and interactive calculator (for v2 and v3 only) compatible with Python 3. CVSS (Common Vulnerability Scoring System) is an standardized method for rating the severity of security issues on a scale from 0 (no impact) to 10 (critical).
Let's install the cvss python package.
python -m pip install cvss
Collecting cvss
  Downloading cvss-3.6-py2.py3-none-any.whl.metadata (3.8 kB)
Downloading cvss-3.6-py2.py3-none-any.whl (31 kB)
Installing collected packages: cvss
  WARNING: The script cvss_calculator.exe is installed in 'C:\python-3_10_11\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed cvss-3.6
How this works:
NVD Database (online)
        |
        |  JSON feed
        v
Python script ----> parses CVE + CVSS vector
        |
        |  uses cvss library
        v
Scores vulnerabilities (Base, Temporal, Environmental)
        |
        |  inserts results
        v
Your local database (SQL)
        |
        v
Dashboard / API / Alerts 
Simple code source example :
#!/usr/bin/env python3

# Demonstrates how to score a CVSS vector using the open-source "cvss" library.
# Validation and error handling included.

from cvss import CVSS3  # CVSS2, CVSS3, CVSS4 are available
import sys

def score_cvss_vector(vector: str):
    """
    Validates and scores a CVSS3 vector string.
    Returns scores and severities.
    """
    if not isinstance(vector, str) or not vector.strip():
        raise ValueError("Vector must be a non-empty string.")

    try:
        c = CVSS3(vector)
    except Exception as e:
        raise ValueError(f"Invalid CVSS3 vector: {e}")

    return c.clean_vector(), c.scores(), c.severities()

def main():
    if len(sys.argv) != 2:
        print("Usage: python cvss_score.py '<CVSS3_VECTOR>'")
        print("Example:")
        print("python main.py 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H'")
        sys.exit(1)

    vector = sys.argv[1]

    try:
        clean_v, scores, severity = score_cvss_vector(vector)
        print("Input vector:", vector)
        print("Normalized vector:", clean_v)
        print("Scores:", scores)
        print("Severity:", severity)
    except ValueError as e:
        print("Error:", e)
        sys.exit(1)

if __name__ == "__main__":
    main()
The result is this:
python main.py CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Input vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Normalized vector: CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Scores: (9.8, 9.8, 9.8)
Severity: ('Critical', 'Critical', 'Critical')
Another source code with examples:
#!/usr/bin/env python3
# Requires: pip install cvss

from cvss import CVSS3

# Example vulnerabilities (safe, educational)
vulns = [
    {
        "language": "Python",
        "title": "Unsafe eval usage",
        "description": "Code that executes user-provided input using eval().",
        "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N"
    },
    {
        "language": "C#",
        "title": "Insecure deserialization",
        "description": "BinaryFormatter deserialization of untrusted data.",
        "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
    },
    {
        "language": "Godot Engine",
        "title": "Unvalidated file path access",
        "description": "Loading files from paths provided by the user without validation.",
        "cvss_vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N"
    }
]

def analyze_vulnerabilities(vuln_list):
    for v in vuln_list:
        print("\n====================================")
        print("Language:", v["language"])
        print("Issue:", v["title"])
        print("Description:", v["description"])
        print("CVSS Vector:", v["cvss_vector"])

        try:
            cv = CVSS3(v["cvss_vector"])
            base, temp, env = cv.scores()
            sev_base, sev_temp, sev_env = cv.severities()

            print("Base Score:", base, "-", sev_base)
            print("Temporal Score:", temp, "-", sev_temp)
            print("Environmental Score:", env, "-", sev_env)

        except Exception as e:
            print("Invalid CVSS vector:", e)

if __name__ == "__main__":
    analyze_vulnerabilities(vulns)
This is the result:
python main_002.py

====================================
Language: Python
Issue: Unsafe eval usage
Description: Code that executes user-provided input using eval().
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N
Base Score: 8.1 - High
Temporal Score: 8.1 - High
Environmental Score: 8.1 - High

====================================
Language: C#
Issue: Insecure deserialization
Description: BinaryFormatter deserialization of untrusted data.
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Base Score: 9.8 - Critical
Temporal Score: 9.8 - Critical
Environmental Score: 9.8 - Critical

====================================
Language: Godot Engine
Issue: Unvalidated file path access
Description: Loading files from paths provided by the user without validation.
CVSS Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
Base Score: 4.4 - Medium
Temporal Score: 4.4 - Medium
Environmental Score: 4.4 - Medium

Python 3.10.11 : Show the CVE's results with opencve token.

Today, this simple source code use token from opencve.io - website to show CVE's results.
import requests

API_URL = "https://app.opencve.io/api/cve"
TOKEN = "opc_org.<token_id>.<secret>"

headers = {
    "Authorization": f"Bearer {TOKEN}",
    "Accept": "application/json",
}

params = {
    "vendor": "microsoft",
    "cvss": "critical",
    "page": 1,
}

resp = requests.get(API_URL, headers=headers, params=params)
data = resp.json()

for cve in data["results"]:
    print(cve["cve_id"], cve["description"])
This is the result:
python main_001.py
CVE-2026-58289 Access of resource using incompatible type ('type confusion') in Microsoft Edge (Chromium-based) allows an unauthorized attacker to execute code over a network.
CVE-2026-45499 Server-side request forgery (ssrf) in Azure OpenAI allows an authorized attacker to elevate privileges over a network.
CVE-2026-41106 Url redirection to untrusted site ('open redirect') in M365 Copilot allows an unauthorized attacker to elevate privileges over a network.
CVE-2026-57100 Server-side request forgery (ssrf) in Microsoft Entra Provisioning Service (SyncFabric) allows an authorized attacker to elevate privileges over a network.
CVE-2026-54130 Missing authentication for critical function in M365 Copilot allows an unauthorized attacker to disclose information over a network.
CVE-2026-48584 Execution with unnecessary privileges in Azure Synapse allows an authorized attacker to elevate privileges over a network.
CVE-2026-45480 Improper authentication in Azure Active Directory allows an unauthorized attacker to elevate privileges over a network.
CVE-2025-62821 Microsoft HEIF Image Extensions 1.2.22.0 has an out-of-bounds read because CHEIFItemInfoEntry_GetDataSize can return success while leaving the reported data size as 0. This causes a caller to make a 1-byte allocation. Later, CopyPixels computes copy_size = stride * abs(roi_height) but does not check the source buffer length before a memmove call.
CVE-2026-47647 Improper access control in Microsoft Dynamics 365 allows an authorized attacker to elevate privileges over a network.
CVE-2026-48582 Missing authorization in Microsoft Exchange Online allows an authorized attacker to elevate privileges over a network.

Saturday, July 4, 2026

Python Qt : simple uninstall and reinstall all packages.

This Python program creates a small desktop application using PyQt6. Its purpose is to show all Python packages installed in your environment and then uninstall and reinstall them. The interface has a button to load the list of installed packages, a list widget to display them, a button to start the reinstall process, and a progress bar to show how far the process has gone.
When you press Load Installed Packages, the program runs the command pip list --format=freeze and reads all installed packages. It extracts only the package names and displays them in the GUI list.
When you press Uninstall + Reinstall All, the program goes through each package one by one. For every package, it runs pip uninstall -y package to remove it, and then pip install package to install it again. The progress bar updates after each package so you can see the progress.
The important detail is that the program does not use threads. All operations run in the main GUI thread. Because of this, the window may freeze or stop responding while uninstalling and reinstalling packages. This is normal behavior for PyQt6 applications that perform long tasks without threading. Let's see the source code:
import sys
import subprocess
from PyQt6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QPushButton,
    QListWidget, QProgressBar, QMessageBox
)
from PyQt6.QtCore import Qt

def get_installed_packages():
    result = subprocess.run(
        [sys.executable, "-m", "pip", "list", "--format=freeze"],
        capture_output=True, text=True
    )
    lines = result.stdout.strip().split("\n")
    pkgs = [line.split("==")[0] for line in lines if "==" in line]
    return pkgs

def uninstall_package(pkg):
    subprocess.run([sys.executable, "-m", "pip", "uninstall", "-y", pkg])

def install_package(pkg):
    subprocess.run([sys.executable, "-m", "pip", "install", pkg])

class PipReinstaller(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Reinstall All Python Packages")

        layout = QVBoxLayout()

        self.btn_load = QPushButton("Load Installed Packages")
        self.btn_load.clicked.connect(self.load_packages)
        layout.addWidget(self.btn_load)

        self.list = QListWidget()
        layout.addWidget(self.list)

        self.btn_reinstall = QPushButton("Uninstall + Reinstall All")
        self.btn_reinstall.clicked.connect(self.reinstall_all)
        layout.addWidget(self.btn_reinstall)

        self.progress = QProgressBar()
        layout.addWidget(self.progress)

        self.setLayout(layout)

    def load_packages(self):
        self.list.clear()
        pkgs = get_installed_packages()
        for p in pkgs:
            self.list.addItem(p)

    def reinstall_all(self):
        pkgs = [self.list.item(i).text() for i in range(self.list.count())]

        if not pkgs:
            QMessageBox.warning(self, "Warning", "No packages loaded.")
            return

        total = len(pkgs)
        self.progress.setValue(0)

        for idx, pkg in enumerate(pkgs):
            uninstall_package(pkg)
            install_package(pkg)

            percent = int((idx + 1) / total * 100)
            self.progress.setValue(percent)

        QMessageBox.information(self, "Done", "All packages reinstalled.")

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

Wednesday, July 1, 2026

News : FastAPI new changes , now supports router dependencies ...

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.
FastAPI's router.frontend() now also supports router dependencies (e.g. add cookie auth to a router, and a frontend at /admin). Handle the cookie auth in FastAPI, and let the frontend do its client-side routing (e.g. TanStack Router with React).

Python 3.10.11 : fix python store bad open with powershell.

Today, this powershell source code will fix the python command when start the windows store.
This is the powershell source code:

# Run first 
# Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# --- Create Form ---
$form = New-Object System.Windows.Forms.Form
$form.Text = "Python Path Fixer"
$form.Size = New-Object System.Drawing.Size(500, 300)
$form.StartPosition = 'CenterScreen'

# --- Label & Path Input ---
$label = New-Object System.Windows.Forms.Label
$label.Text = "Python Directory:"
$label.Location = New-Object System.Drawing.Point(10, 20)
$label.AutoSize = $true
$form.Controls.Add($label)

$txtPath = New-Object System.Windows.Forms.TextBox
$txtPath.Location = New-Object System.Drawing.Point(10, 45)
$txtPath.Size = New-Object System.Drawing.Size(460, 20)
$txtPath.Text = "C:\PythonInstall" 
$form.Controls.Add($txtPath)

# --- Log Box ---
$txtLog = New-Object System.Windows.Forms.TextBox
$txtLog.Multiline = $true
$txtLog.ScrollBars = 'Vertical'
$txtLog.Location = New-Object System.Drawing.Point(10, 80)
$txtLog.Size = New-Object System.Drawing.Size(460, 130)
$txtLog.ReadOnly = $true
$form.Controls.Add($txtLog)

# --- Fix Button ---
$btnFix = New-Object System.Windows.Forms.Button
$btnFix.Text = "Check and Fix Path"
$btnFix.Location = New-Object System.Drawing.Point(10, 220)
$btnFix.Size = New-Object System.Drawing.Size(460, 30)

$btnFix.Add_Click({
    $pythonFolder = $txtPath.Text
    $pythonExe = Join-Path $pythonFolder "python.exe"
    
    $txtLog.Text = "Checking: $pythonExe`r`n"
    
    if (Test-Path $pythonExe) {
        $txtLog.AppendText("[+] Python found. Updating PATH...`r`n")
        
        $currentPath = [Environment]::GetEnvironmentVariable("Path", "User")
        $pathParts = $currentPath -split ";" | Where-Object { $_ -ne $pythonFolder -and $_ -ne "" }
        $newPath = "$pythonFolder;" + ($pathParts -join ";")
        
        [Environment]::SetEnvironmentVariable("Path", $newPath, "User")
        
        $txtLog.AppendText("[OK] Priority set successfully!`r`nPlease restart your terminal.")
    } else {
        $txtLog.AppendText("[ERROR] python.exe not found in the specified directory!")
    }
})
$form.Controls.Add($btnFix)

[void]$form.ShowDialog()

Friday, June 26, 2026

News : PEP 661 – Sentinel Values.

About the sentinel object you can read on the official website :
The sentinel objects should behave as expected by a sentinel object: When compared using the is operator, it should always be considered identical to itself but never to any other object. Creating a sentinel object should be a simple, straightforward one-liner. It should be simple to define as many distinct sentinel values as needed. The sentinel objects should have a clear and short repr. It should be possible to use clear type signatures for sentinels. The sentinel objects should behave correctly after copying, and sentinels should have predictable behavior when pickled and unpickled. Such sentinels should work when using CPython 3.x and PyPy3, and ideally also with other implementations of Python. As simple and straightforward as possible, in implementation and especially in use. Avoid this becoming one more special thing to learn when learning Python. It should be easy to find and use when needed, and obvious enough when reading code that one would normally not feel a need to look up its documentation
Let's see one default example:
from typing import assert_type

MISSING = sentinel('MISSING')

def foo(value: int | MISSING) -> None:
    if value is MISSING:
        assert_type(value, MISSING)
    else:
        assert_type(value, int)

Python : The Story of Python and how it took over the world | Python: The Documentary.

Thursday, June 25, 2026

News : Python 3.15.0 beta 3 is here!

Python 3.15 is still in development. This release, 3.15.0b3, is the third of four planned beta releases, containing around 195 bugfixes, build improvements and documentation changes from 86 contributors since 3.15.0b2.
Beta release previews are intended to give the wider community the opportunity to test new features and bug fixes and to prepare their projects to support the new feature release.