analitics

Pages

Sunday, December 29, 2024

Python 3.13.0 : Only the unstructured library in Fedora 41 ...

The unstructured library provides open-source components for ingesting and pre-processing images and text documents, such as PDFs, HTML, Word docs, and many more. The use cases of unstructured revolve around streamlining and optimizing the data processing workflow for LLMs. unstructured modular functions and connectors form a cohesive system that simplifies data ingestion and pre-processing, making it adaptable to different platforms and efficient in transforming unstructured data into structured outputs.
I used pip tool to install this python package:
mythcat@fedora:~$ pip install unstructured
Defaulting to user installation because normal site-packages is not writeable
Collecting unstructured
  Downloading unstructured-0.11.8-py3-none-any.whl.metadata (26 kB)
...
Successfully installed aiofiles-24.1.0 annotated-types-0.7.0 anyio-4.7.0 backoff-2.2.1 beautifulsoup4-4.12.3 chardet-5.2.0 click-8.1.8 cryptography-44.0.0 dataclasses-json-0.6.7 emoji-2.14.0 eval-type-backport-0.2.2 filetype-1.2.0 h11-0.14.0 httpcore-1.0.7 httpx-0.28.1 jsonpath-python-1.0.6 langdetect-1.0.9 marshmallow-3.23.2 mypy-extensions-1.0.0 nest-asyncio-1.6.0 nltk-3.9.1 pydantic-2.9.2 pydantic-core-2.23.4 pypdf-5.1.0 python-iso639-2024.10.22 python-magic-0.4.27 rapidfuzz-3.11.0 requests-toolbelt-1.0.0 sniffio-1.3.1 soupsieve-2.6 tabulate-0.9.0 tqdm-4.67.1 typing-extensions-4.12.2 typing-inspect-0.9.0 unstructured-0.11.8 unstructured-client-0.28.1 wrapt-1.17.0
But I got error on the unstructured-inference:
pip install unstructured-inference
Collecting unstructured-inference
...
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for onnx
Failed to build onnx
ERROR: ERROR: Failed to build installable wheels for some pyproject.toml based projects (onnx)
... and errors on unstructured[pdf]:
mythcat@fedora:~$ pip install unstructured[pdf]
...
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for onnx
Failed to build onnx
ERROR: ERROR: Failed to build installable wheels for some pyproject.toml based projects (onnx)

News : My GAME ENGINE is FINALLY DONE! (9 Years in the Making) - build with python.

... this is the cave engine project manager and if you don't know cave cave is a 3D easy to use ... python game engine for you to make games for computer Windows or Linux ... from GuilhermeTeres !

Monday, December 16, 2024

Python 3.12.8 : Install quil in Fedora 41.

The quil python package on Fedora 41 can be used with the 3.12.8 version of python :
Python 3.12.8 (main, Dec  6 2024, 00:00:00) [GCC 14.2.1 20240912 (Red Hat 14.2.1-3)] on linux
mythcat@localhost:~$ python3.12 -m pip install quil --user
First, install the python version then install the pip tool:
mythcat@localhost:~$ curl https://bootstrap.pypa.io/get-pip.py | python3.12 -
...
Installing collected packages: pip
Successfully installed pip-24.3.1
Next, install with the pip version:
mythcat@localhost:~$ python3.12 -m pip install quil --user
Collecting quil

Saturday, December 14, 2024

Python 3.13.0 : OpenCV - part 002.

The PyQt6 python package and Fedora works great. I tested today this source code with opencv, numpy, PyQt6 python packages.
I install opencv python package with dnf5 tool:
root@localhost:/home/mythcat# dnf5 install  python3-opencv.x86_64
The source code let you to open, change a image and save using sliders and a reset option.
This is the source code:
import sys
import cv2
import numpy as np
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QSlider, QFileDialog, QPushButton, QHBoxLayout
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtCore import Qt, pyqtSlot

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Real-Time Color Selection")
        self.setGeometry(100, 100, 1200, 800)

        # Create central widget and main layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # Create image label
        self.image_label = QLabel()
        main_layout.addWidget(self.image_label)

        # Initialize sliders
        self.lower_h = QSlider(Qt.Orientation.Horizontal)
        self.lower_s = QSlider(Qt.Orientation.Horizontal)
        self.lower_v = QSlider(Qt.Orientation.Horizontal)
        self.upper_h = QSlider(Qt.Orientation.Horizontal)
        self.upper_s = QSlider(Qt.Orientation.Horizontal)
        self.upper_v = QSlider(Qt.Orientation.Horizontal)

        # Set slider ranges
        for slider in [self.lower_h, self.upper_h]:
            slider.setRange(0, 179)
        for slider in [self.lower_s, self.lower_v, self.upper_s, self.upper_v]:
            slider.setRange(0, 255)

        # Set initial slider values
        self.lower_h.setValue(50)
        self.lower_s.setValue(100)
        self.lower_v.setValue(50)
        self.upper_h.setValue(130)
        self.upper_s.setValue(255)
        self.upper_v.setValue(255)

        # Connect sliders to update function
        self.lower_h.valueChanged.connect(self.update_hsv_range)
        self.lower_s.valueChanged.connect(self.update_hsv_range)
        self.lower_v.valueChanged.connect(self.update_hsv_range)
        self.upper_h.valueChanged.connect(self.update_hsv_range)
        self.upper_s.valueChanged.connect(self.update_hsv_range)
        self.upper_v.valueChanged.connect(self.update_hsv_range)

        # Create slider layouts with labels
        sliders_layout = QVBoxLayout()
        
        # Add slider pairs with labels
        slider_pairs = [
            ("Lower Hue", self.lower_h),
            ("Lower Saturation", self.lower_s),
            ("Lower Value", self.lower_v),
            ("Upper Hue", self.upper_h),
            ("Upper Saturation", self.upper_s),
            ("Upper Value", self.upper_v)
        ]

        for label_text, slider in slider_pairs:
            row_layout = QHBoxLayout()
            label = QLabel(label_text)
            label.setMinimumWidth(120)
            row_layout.addWidget(label)
            row_layout.addWidget(slider)
            sliders_layout.addLayout(row_layout)

        main_layout.addLayout(sliders_layout)

        # Add buttons
        button_layout = QHBoxLayout()
        
        self.reset_button = QPushButton("Reset Values")
        self.reset_button.clicked.connect(self.reset_values)
        button_layout.addWidget(self.reset_button)

        self.open_image_button = QPushButton("Open Image")
        self.open_image_button.clicked.connect(self.open_image)
        button_layout.addWidget(self.open_image_button)

        self.save_button = QPushButton("Save Image")
        self.save_button.clicked.connect(self.save_image)
        button_layout.addWidget(self.save_button)
        main_layout.addLayout(button_layout)

        # Process initial image
        self.process_image()

    def process_image(self):
        image_bgr = cv2.imread("image.png")
        if image_bgr is None:
            image_bgr = cv2.imread("default_image.png")
        
        self.image_bgr = image_bgr
        self.image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)

        # Create initial mask using current slider values
        lower_values = np.array([self.lower_h.value(), self.lower_s.value(), self.lower_v.value()])
        upper_values = np.array([self.upper_h.value(), self.upper_s.value(), self.upper_v.value()])
        
        mask_test = cv2.inRange(self.image_hsv, lower_values, upper_values)
        image_bgr_masked = cv2.bitwise_and(image_bgr, image_bgr, mask=mask_test)
        self.image_rgb = cv2.cvtColor(image_bgr_masked, cv2.COLOR_BGR2RGB)
        self.update_image()

    def update_image(self):
        height, width, channel = self.image_rgb.shape
        bytes_per_line = width * channel
        q_image = QImage(self.image_rgb.data, width, height, bytes_per_line, QImage.Format.Format_RGB888)
        pixmap = QPixmap.fromImage(q_image)
        self.image_label.setPixmap(pixmap.scaled(700, 500, Qt.AspectRatioMode.KeepAspectRatio))

    def update_hsv_range(self):
        lower_values = np.array([self.lower_h.value(), self.lower_s.value(), self.lower_v.value()])
        upper_values = np.array([self.upper_h.value(), self.upper_s.value(), self.upper_v.value()])
        mask_test = cv2.inRange(self.image_hsv, lower_values, upper_values)
        image_bgr_masked = cv2.bitwise_and(self.image_bgr, self.image_bgr, mask=mask_test)
        self.image_rgb = cv2.cvtColor(image_bgr_masked, cv2.COLOR_BGR2RGB)
        self.update_image()

    def reset_values(self):
        self.lower_h.setValue(50)
        self.lower_s.setValue(100)
        self.lower_v.setValue(50)
        self.upper_h.setValue(130)
        self.upper_s.setValue(255)
        self.upper_v.setValue(255)

    def open_image(self):
        filename, _ = QFileDialog.getOpenFileName(self, "Select Image File", "", "Image Files (*.png *.jpg *.jpeg)")
        if filename:
            self.image_bgr = cv2.imread(filename)
            if self.image_bgr is not None:
                self.image_hsv = cv2.cvtColor(self.image_bgr, cv2.COLOR_BGR2HSV)
                self.update_hsv_range()  # This will apply current filter and update display

    def save_image(self):
        filename, _ = QFileDialog.getSaveFileName(self, "Save Image", "", "PNG Files (*.png);;JPEG Files (*.jpg)")
        if filename:
            # Make sure filename has an extension
            if not filename.endswith(('.png', '.jpg', '.jpeg')):
                filename += '.png'
            # Convert and save
            output_image = cv2.cvtColor(self.image_rgb, cv2.COLOR_RGB2BGR)
            cv2.imwrite(filename, output_image)

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

Sunday, November 24, 2024

Python 3.13.0 : emoji symbols with PIL.

Today I want to use emoji symbols and I wrote this python script:
from PIL import Image, ImageDraw, ImageFont
import os

# Font size and image dimensions
font_size = 88
width = 640
height = 480

# Use Symbola.ttf from current directory
font_path = "Symbola.ttf"

# Create image
img = Image.new('RGB', (width, height), color='white')
draw = ImageDraw.Draw(img)

# Get font
font = ImageFont.truetype(font_path, font_size)

# Emoji matrix
emoji_matrix = [
    ['😀', '😁', '😂', '🤣', '😃'],
    ['😄', '😅', '😆', '😇', '😈'],
    ['😉', '😊', '😋', '😌', '😍'],
    ['😎', '😏', '😐', '😑', '😒']
]

# Calculate spacing
x_spacing = font_size + 10
y_spacing = font_size + 10

# Calculate starting position to center the grid
start_x = (width - (len(emoji_matrix[0]) * x_spacing)) // 2
start_y = (height - (len(emoji_matrix) * y_spacing)) // 2

# Draw emojis
for i, row in enumerate(emoji_matrix):
    for j, emoji in enumerate(row):
        x = start_x + (j * x_spacing)
        y = start_y + (i * y_spacing)
        draw.text((x, y), emoji, font=font, fill='black')

# Save the image
img.save('emoji_art.png')
print("Emoji art has been created successfully! Check emoji_art.png")
The result image named emoji_art.png is this:

Wednesday, November 20, 2024

Python 3.13.0 : generates multiple deformed polygonal shapes .

Today I created this source code in python that generates eight random convex polygons. The idea was to create sprites for a 2D game: snowballs, boulders, or similar objects... Obviously I also used Sonet 3.5 artificial intelligence. You can find the source code on the pagure account in fedora.
#!/usr/bin/env python3
"""
SVG Polygon Generator

This script generates multiple deformed polygonal shapes and saves them as separate SVG files.
Each polygon maintains convex properties while having controlled random deformations.

Features:
    - Generates 8 unique polygonal shapes
    - Controls deformation through radial and angular factors
    - Maintains convex properties
    - Exports each shape to a separate SVG file
    - Uses random colors for visual distinction

Usage:
    python generate_svgs.py

Output:
    Creates 8 SVG files named 'polygon_1.svg' through 'polygon_8.svg'
"""

from lxml import etree
import random
import math
from pathlib import Path


def create_svg_root():
    """Create and return a base SVG root element with standard attributes."""
    root = etree.Element("svg")
    root.set("width", "500")
    root.set("height", "500")
    root.set("xmlns", "http://www.w3.org/2000/svg")
    return root


def calculate_points(center_x: float, center_y: float, radius: float, 
                    num_sides: int, deform_factor: float) -> list:
    """
    Calculate polygon points with controlled deformation.

    Args:
        center_x: X coordinate of polygon center
        center_y: Y coordinate of polygon center
        radius: Base radius of the polygon
        num_sides: Number of polygon sides
        deform_factor: Maximum allowed deformation factor

    Returns:
        List of tuples containing (x, y) coordinates
    """
    points = []
    angle_step = 2 * math.pi / num_sides
    
    for i in range(num_sides):
        angle = i * angle_step
        radial_deform = random.uniform(-deform_factor, deform_factor)
        angular_deform = random.uniform(-deform_factor/2, deform_factor/2)
        
        modified_angle = angle + angular_deform
        modified_radius = radius * (1 + radial_deform)
        
        x = center_x + modified_radius * math.cos(modified_angle)
        y = center_y + modified_radius * math.sin(modified_angle)
        points.append((x, y))
    
    return points


def generate_deformed_shapes():
    """Generate multiple deformed polygons and save them to separate SVG files."""
    # Base parameters
    num_sides = 8
    center_x = 250
    center_y = 250
    base_radius = 150
    max_deformation = 0.15
    output_dir = Path("generated_polygons")
    
    # Create output directory if it doesn't exist
    output_dir.mkdir(exist_ok=True)

    for i in range(8):
        root = create_svg_root()
        points = calculate_points(center_x, center_y, base_radius, 
                                num_sides, max_deformation)
        
        path = etree.SubElement(root, "path")
        path_data = f"M {points[0][0]} {points[0][1]}"
        path_data += "".join(f" L {p[0]} {p[1]}" for p in points[1:])
        path_data += " Z"
        
        path.set("d", path_data)
        path.set("fill", "none")
        path.set("stroke", f"#{random.randint(0, 16777215):06X}")
        path.set("stroke-width", "2")
        path.set("opacity", "0.7")

        # Save individual SVG file
        output_file = output_dir / f"polygon_{i+1}.svg"
        tree = etree.ElementTree(root)
        tree.write(str(output_file), pretty_print=True, 
                  xml_declaration=True, encoding='utf-8')
    
    print(f"Generated {num_sides} polygons in {output_dir}")

if __name__ == "__main__":
    generate_deformed_shapes()

Monday, November 18, 2024

Python 3.13.0 : Tested TinyDB on Fedora 41.

Today I tested the TinyDB python package on Fedora 41 Linux distro:
TinyDB is a lightweight document oriented database optimized for your happiness :) It’s written in pure Python and has no external dependencies. The target are small apps that would be blown away by a SQL-DB or an external database server.
The documentation for this python package can be found on the official website.
The install on Fedora 14 distro can be done with pip tool:
pip install tinydb
This is the source code I tested:
from tinydb import TinyDB, Query
import datetime

# Create a TinyDB instance
db = TinyDB('my_database.json')

# Define a schema for our documents
UserSchema = {
    'name': str,
    'email': str,
    'age': int,
    'created_at': datetime.datetime
}# Insert some sample data
users = [
    {'name': 'John Doe', 'email': 'john@example.com', 'age': 30},
    {'name': 'Jane Smith', 'email': 'jane@example.com', 'age': 25},
    {'name': 'Bob Johnson', 'email': 'bob@example.com', 'age': 35}
]

for user in users:
    db.insert(user)

# Querying all users
print("\nQuerying all users:")
all_users = db.all()
for user in all_users:
    print(f"Name: {user['name']}, Email: {user['email']}, Age: {user['age']}")

# Filtering data
print("\nFidig users older than 28:")
older_than_28 = db.search(Query().age > 28)
for user in older_than_28:
    print(f"Name: {user['name']}, Email: {user['email']}, Age: {user['age']}")

# Updating data
print("\nUpdatig John Doe's age:")
db.update({'age': 31}, Query().name == 'John Doe')

# Deleting data
print("\nDeletig Jane Smith:")
doc_ids = [doc.doc_id for doc in db.search(Query().email == 'jane@example.com')]
if doc_ids:
    db.remove(doc_ids=doc_ids)
else:
    print("No document found with email 'jane@example.com'")

# Adding a new field
print("\nAddig a 'city' field to all users:")
for user in db.all():
    user['city'] = 'New York'
    db.update(user, doc_ids=[doc.doc_id for doc in db.search(Query().name == user['name'])])

# Sorting data
print("\nSorting users by age:")
sorted_users = sorted(db.all(), key=lambda x: x['age'])
for user in sorted_users:
    print(f"Name: {user['name']}, Email: {user['email']}, Age: {user['age']}")

# Getting document count
print("\nTotal number of users:", len(db.all()))

# Closing the database connection
db.close()
This is the result:
$ python test_001.py 

Querying all users:
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 30
Name: Jane Smith, Email: jane@example.com, Age: 25
Name: Bob Johnson, Email: bob@example.com, Age: 35

Fidig users older than 28:
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 30
Name: Bob Johnson, Email: bob@example.com, Age: 35

Updatig John Doe's age:

Deletig Jane Smith:

Addig a 'city' field to all users:

Sorting users by age:
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35

Total number of users: 22

Saturday, November 16, 2024

Python 3.13.0 : Test the gi python package on Fedora distro linux.

The gi (GObject Introspection) Python package is excellent! It provides Python bindings for GObject-based libraries like GTK, GLib, and Secret Service. It enables you to write native GNOME applications in Python and access system services seamlessly.
First, install these Fedora packages:
[mythcat@fedora ~]# dnf5 install python3-gobject libsecret-devel
...
Package "python3-gobject-3.48.2-3.fc41.x86_64" is already installed.
Package "libsecret-devel-0.21.4-3.fc41.x86_64" is already installed.
...
[mythcat@fedora ~]# dnf5 install gnome-shell gnome-keyring libsecret
...
I used this simple python source code to test the gi python package:
import gi

# Specify the version of Gio and Secret we want to use
gi.require_version('Gio', '2.0')
gi.require_version('Secret', '1')

from gi.repository import Gio, Secret, GLib

def check_schema(schema_name):
    try:
        Gio.Settings.new(schema_name)
        print(f"Schema '{schema_name}' is available")
        return True
    except GLib.GError as e:
        print(f"Schema '{schema_name}' is not installed: {str(e)}")
        return False

def store_secret():
    schema = Secret.Schema.new("org.example.Password",
        Secret.SchemaFlags.NONE,
        {
            "username": Secret.SchemaAttributeType.STRING,
        }
    )
    
    Secret.password_store_sync(schema, 
        {"username": "myuser"},
        Secret.COLLECTION_DEFAULT,
        "My secret item",
        "Hello, World!",
        None)
    
    print("Secret stored successfully")

def get_secret():
    schema = Secret.Schema.new("org.example.Password",
        Secret.SchemaFlags.NONE,
        {
            "username": Secret.SchemaAttributeType.STRING,
        }
    )
    
    password = Secret.password_lookup_sync(schema,
        {"username": "myuser"},
        None)
    
    if password is not None:
        print(f"Retrieved secret: {password}")
    else:
        print("No secret found")

if __name__ == "__main__":
    print("Starting secret operations...")
    store_secret()
    get_secret()
    print("Finished secret operations.")
The result is this:
$ python test_001.py 
Starting secret operations...
Secret stored successfully
Retrieved secret: Hello, World!
Finished secret operations.

Sunday, October 27, 2024

Python 3.13.0 : know this -OOt ?

Today, I follow the actions from NEMO the basic explorer files from linux and I found this: -OOt
This first source code:
#!/usr/bin/python3 -OOt
... this is new, and refers to Python compiler optimizations.
The -OOt par in the shebang line #!/usr/bin/python3 -OOt refers to Python compiler optimizations:
  1. -O: This flag enables basic optimizations. It tells the Python compiler to optimize constants and global variables.
  2. -O2: This flag enables more aggressive optimizations. It applies additional compiler passes to further optimize the code .
  3. -Ot: This flag optimizes for size. It reduces memory usage by eliminating unused variables and dead code.
So, -OOt combines three levels of optimization:
  • Basic optimization (-O)
  • More aggressive optimization (-O2)
  • Optimization for size (-Ot)

Friday, October 25, 2024

Python 3.13.0 : Testing ntplib on Fedora 42.

Today I tested the ntplib python package on Fedora 42 with the python 3.13.0 version.
This is the source code:
from ntplib import NTPClient
import socket
import os
import datetime

def sync_ntp_server(server_address='pool.ntp.org'):
    try:
        client = NTPClient()
        response = client.request(server_address)
        
        # Get the offset in seconds
        offset = response.offset
        
        # Calculate the drift rate (seconds per day)
        drift_rate = offset * 86400 / response.tx_time
        
        print(f"NTP synchronization successful. Offset: {offset:.2f} seconds")
        print(f"Drift rate: {drift_rate:.2f} seconds per day")
        
        # Apply the offset to the system clock
        os.system(f"date -s '@{response.tx_time}'")
        
        # Optionally, you can also apply the drift rate to the system clock
        # However, this is generally not recommended as it can lead to further drift
        # os.system(f"ntpdate -d {server_address}")
        
    except Exception as e:
        print(f"Error synchronizing NTP: {e}")

# Disable SELinux temporarily
os.system("setenforce 0")

# Sync with NTP server
sync_ntp_server()

# Print current system time after sync
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"Current system time after sync: {current_time}")
The result is output is in the romanian language but this is not a problem for programmers:
[mythcat@fedora network_python_tools]$ pip install ntplib
Defaulting to user installation because normal site-packages is not writeable
Collecting ntplib
  Downloading ntplib-0.4.0-py2.py3-none-any.whl.metadata (1.6 kB)
Downloading ntplib-0.4.0-py2.py3-none-any.whl (6.8 kB)
Installing collected packages: ntplib
Successfully installed ntplib-0.4.0
[mythcat@fedora network_python_tools]$ python ntplib_test_001.py 
...
NTP synchronization successful. Offset: -5.25 seconds
Drift rate: -0.00 seconds per day
date: nu se poate stabili data: Operație nepermisă
vineri 25 octombrie 2024, 22:24:13 +0300
Current system time after sync: 2024-10-25 22:24:19

Sunday, September 22, 2024

Python 3.13.0rc1 : ... pkg_resources is deprecated as an API .

I tried an old version of python script for upgrade all my ython packages on windows 10 with pkg_resources python package.
I got this error:
DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
... and this python script will upgrade all python packages
import subprocess

try:
    # Obține lista pachetelor învechite
    outdated_packages = subprocess.check_output(["pip", "list", "--outdated", "--format=columns"]).decode("utf-8")
    packages = [line.split()[0] for line in outdated_packages.splitlines()[2:]]
    
    if not packages:
        print("Toate pachetele sunt deja actualizate.")
    else:
        print("Pachete Python învechite: ", packages)
        
        # Actualizează fiecare pachet
        for package in packages:
            print("Actualizează pachetul: ", package)
            subprocess.check_call(["pip", "install", "--upgrade", package])
except subprocess.CalledProcessError as e:
    print("A apărut o eroare la rularea comenzii pip:", e)
except Exception as e:
    print("A apărut o eroare neașteptată:", e)

Saturday, September 21, 2024

Python 3.12.3 : 8in8 game project with pygame and agentpy - 001.

I started a game project with the python packages pygame and agentpy in the Fedora Linux distribution.
You can find it on my fedora pagure repo

Tuesday, September 17, 2024

Python 3.12.3 : PyGame, DuckDB and AgentPy on Fedora 42 linux distro.

Today I tested the installation of some python packages in the Fedora 42 Linux distribution. On the Windows 10 operating system I failed to install pygame because it was trying to build.

[mythcat@fedora ~]$ pip install duckdb --upgrade
Defaulting to user installation because normal site-packages is not writeable
Collecting duckdb
...
Installing collected packages: duckdb
Successfully installed duckdb-1.1.0
[mythcat@fedora ~]$ pip install pygame
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: pygame in ./.local/lib/python3.12/site-packages (2.5.2)
[mythcat@fedora ~]$ pip install agentpy
...
Installing collected packages: scipy, networkx, kiwisolver, joblib, fonttools, dill, cycler, contourpy, pandas, multiprocess, matplotlib, SALib, agentpy
Successfully installed SALib-1.5.1 agentpy-0.1.5 contourpy-1.3.0 cycler-0.12.1 dill-0.3.8 fonttools-4.53.1 joblib-1.4.2 kiwisolver-1.4.7 matplotlib-3.9.2 multiprocess-0.70.16 networkx-3.3 pandas-2.2.2 scipy-1.14.1

Saturday, September 14, 2024

Python 3.13.0rc1 : AgentPy python module ...

AgentPy is an open-source library for the development and analysis of agent-based models in Python.
The project can be found on the GitHub repo.
This can be install with the pip tool:
pip install agentpy
Collecting agentpy
...
Successfully installed SALib-1.5.1 agentpy-0.1.5 contourpy-1.3.0 cycler-0.12.1 dill-0.3.8 fonttools-4.53.1 
joblib-1.4.2 kiwisolver-1.4.7 matplotlib-3.9.2 multiprocess-0.70.16 networkx-3.3 packaging-24.1 
pillow-10.4.0 pyparsing-3.1.4 scipy-1.14.1
This is the source code:
import agentpy as ap
import matplotlib.pyplot as plt

# define Agent class
class RandomWalker(ap.Agent):
    def setup(self):
        self.position = [0, 0]

    def step(self):
        self.position += self.model.random.choice([[1, 0], [-1, 0], [0, 1], [0, -1]])

# define Model class
class RandomWalkModel(ap.Model):
    def setup(self):
        self.agents = ap.AgentList(self, self.p.agents, RandomWalker)
        self.agents.setup()

    def step(self):
        self.agents.step()

    def update(self):
        self.record('Positions', [agent.position for agent in self.agents])

    def end(self):
        positions = self.log['Positions']
        plt.figure()
        for pos in positions:
            plt.plot(*zip(*pos))
        plt.show()

# configuration and running 
parameters = {'agents': 5, 'steps': 20}
model = RandomWalkModel(parameters)
results = model.run()
The result is a simple graph with these output:
python test001.py
Matplotlib is building the font cache; this may take a moment.
Completed: 20 steps
Run time: 0:00:50.823483
Simulation finished

Monday, September 9, 2024

Python Qt6 : Use regular expression with PyQt6.

Today I tested a python source code with PyQt6.
This source code let you to clean the text by HTML tags and regular expression in realtime.
If you want to parse in realtime then check the Realtime and add the regular expresion in editbox.
This is the result:
This is the source code I used to parse realtime regular expresion on editbox
from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, QCheckBox, QLineEdit, QLabel
from PyQt6.QtGui import QTextDocument
from PyQt6.QtCore import Qt
import re

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("HTML Cleaner")

        self.text_edit = QTextEdit()
        self.clean_button = QPushButton("Clean HTML")
        self.transform_div_checkbox = QCheckBox("Transform 
tags") self.realtime_checkbox = QCheckBox("Realtime") self.regex_edit = QLineEdit() self.regex_edit.setPlaceholderText("Enter regex pattern") self.regex_edit.setEnabled(False) # Dezactivăm inițial top_layout = QHBoxLayout() top_layout.addWidget(self.clean_button) top_layout.addWidget(self.transform_div_checkbox) top_layout.addWidget(QLabel("Regex:")) top_layout.addWidget(self.regex_edit) top_layout.addWidget(self.realtime_checkbox) main_layout = QVBoxLayout() main_layout.addLayout(top_layout) main_layout.addWidget(self.text_edit) container = QWidget() container.setLayout(main_layout) self.setCentralWidget(container) self.clean_button.clicked.connect(self.clean_html) self.realtime_checkbox.stateChanged.connect(self.toggle_realtime) self.regex_edit.textChanged.connect(self.realtime_update) def clean_html(self): html_text = self.text_edit.toPlainText() clean_text = self.remove_html_tags(html_text) self.text_edit.setPlainText(clean_text) def remove_html_tags(self, text): # Remove CSS text = re.sub(r'.*?', '', text, flags=re.DOTALL) # Remove JavaScript text = re.sub(r'.*?', '', text, flags=re.DOTALL) # Remove HTML comments text = re.sub(r'', '', text, flags=re.DOTALL) # Transform
tags if checkbox is checked if self.transform_div_checkbox.isChecked(): text = re.sub(r']*>', '
', text) # Remove HTML tags but keep content clean = re.compile('<.*?>') text = re.sub(clean, '', text) # Remove empty lines text = re.sub(r'\n\s*\n', '\n', text) return text def toggle_realtime(self): if self.realtime_checkbox.isChecked(): self.regex_edit.setEnabled(True) # Activăm editbox-ul self.text_edit.textChanged.connect(self.realtime_update) else: self.regex_edit.setEnabled(False) # Dezactivăm editbox-ul self.text_edit.textChanged.disconnect(self.realtime_update) def realtime_update(self): if self.realtime_checkbox.isChecked(): html_text = self.text_edit.toPlainText() regex_pattern = self.regex_edit.text() if regex_pattern: try: html_text = re.sub(regex_pattern, '', html_text) except re.error: pass # Ignore regex errors self.text_edit.blockSignals(True) self.text_edit.setPlainText(html_text) self.text_edit.blockSignals(False) app = QApplication([]) window = MainWindow() window.show() app.exec()

Saturday, September 7, 2024

News : Python and the Intel's NPU Acceleration Library.

You can find the Intel's NPU Acceleration Library on this GitHub repo with Python code samples.

News : Python in Visual Studio Code – September 2024 Release

We’re excited to announce the September 2024 release of the Python and Jupyter extensions for Visual Studio Code!
This release includes the following announcements:
Django unit test support
Go to definition from inlay hints with Pylance
If you’re interested, you can check the full list of improvements in our changelogs for the Python, Jupyter and Pylance extensions.
Read more on the offcial website.

Friday, September 6, 2024

Python 3.12.4 : DuckDB operate in in-memory mode.

DuckDB aims to automatically achieve high performance by using well-chosen default configurations and having a forgiving architecture. Of course, there are still opportunities for tuning the system for specific workloads. The Performance Guide's page contain guidelines and tips for achieving good performance when loading and processing data with DuckDB.
DuckDB can operate in in-memory mode. In most clients, this can be activated by passing the special value :memory: as the database file or omitting the database file argument.
You can use with python or another programming language.
I used Python 3.13.0rc1 version and pip tool ...
pip install duckdb --upgrade
Collecting duckdb
...
Installing collected packages: duckdb
Successfully installed duckdb-1.0.0
I created a python script :
python test_memory_duckdb_sqlite_db.py
[]
[('table', 'users', 'users', 0, 'CREATE TABLE users(id BIGINT PRIMARY KEY, first_name VARCHAR, last_name VARCHAR, occupation VARCHAR, hobby VARCHAR, year_of_birth BIGINT, age BIGINT);')]
This is the source code I used:
import duckdb

# Conectare la baza de date în memorie
con = duckdb.connect(database=':memory:')

# Instalează extensia sqlite
con.execute("INSTALL sqlite")

# Încarcă extensia sqlite
con.execute("LOAD sqlite")

# Verifică dacă extensia este încărcată
result = con.execute("SELECT * FROM sqlite_master").fetchall()
print(result)

# Conectare la baza de date pe disc
con_disk = duckdb.connect(database='sqlite_database.db', read_only=False)

# Instalează extensia sqlite pentru baza de date pe disc
con_disk.execute("INSTALL sqlite")

# Încarcă extensia sqlite pentru baza de date pe disc
con_disk.execute("LOAD sqlite")

# Verifică dacă extensia este încărcată pentru baza de date pe disc
result_disk = con_disk.execute("SELECT * FROM sqlite_master").fetchall()
print(result_disk)

Wednesday, September 4, 2024

Python 3.13.0rc1 : Use faker with build pandas and PyQt6.

In this tutorial I will show you how I build pandas and use faker and PyQt6.
The faker python module is a powerful library designed to generate fake data, which is particularly useful for testing, filling databases, and creating realistic-looking sample data.
I used python version 3.13.0rc1 and I install with pip tool faker and the pandas and PyQt6 is build with pip tool.
pip install faker
Collecting faker
...
Installing collected packages: six, python-dateutil, faker
Successfully installed faker-28.1.0 python-dateutil-2.9.0.post0 six-1.16.0
The pandas installation fail first time then today works, maybe comes with fixes ...
pip install pandas
...
Successfully built pandas
Installing collected packages: pytz, tzdata, pandas
Successfully installed pandas-2.2.2 pytz-2024.1 tzdata-2024.1
Let's try one example to see how this works, I used copilot from microsoft to generate this first source code:
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow, QTableView
from PyQt6.QtCore import Qt, QAbstractTableModel
import pandas as pd
from faker import Faker

# Generăm date false folosind Faker
fake = Faker()
data = {
    'Name': [fake.name() for _ in range(100)],
    'Address': [fake.address() for _ in range(100)],
    'Email': [fake.email() for _ in range(100)],
    'IP Address': [fake.ipv4() for _ in range(100)]  # Adăugăm adresa IP
}

# Creăm un DataFrame Pandas
df = pd.DataFrame(data)

# Definim un model pentru QTableView
class PandasModel(QAbstractTableModel):
    def __init__(self, df):
        super().__init__()
        self._df = df

    def rowCount(self, parent=None):
        return len(self._df)

    def columnCount(self, parent=None):
        return self._df.shape[1]

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if index.isValid():
            if role == Qt.ItemDataRole.DisplayRole:
                return str(self._df.iloc[index.row(), index.column()])
        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                return self._df.columns[section]
            else:
                return str(section)
        return None

# Aplicatia PyQt6
app = QApplication(sys.argv)
window = QMainWindow()
view = QTableView()

# Setăm modelul pentru QTableView
model = PandasModel(df)
view.setModel(model)

# Configurăm fereastra principală
window.setCentralWidget(view)
window.resize(800, 600)
window.show()

# Rulăm aplicația
sys.exit(app.exec())

Monday, September 2, 2024

Python Qt6 : Two sliders

I used the Python 3.13.0rc1 version and PyQt6 6.7.1 version.
This is the source code:
import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QSlider
from PyQt6.QtCore import Qt

class SliderWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Two Slideres")
        self.setGeometry(100, 100, 640, 200)

        layout = QVBoxLayout()

        self.slider_max = QSlider(Qt.Orientation.Horizontal)
        self.slider_max.setMinimum(0)
        self.slider_max.setMaximum(100)
        self.slider_max.setValue(100)
        self.slider_max.valueChanged.connect(self.update_min_slider)

        self.slider_min = QSlider(Qt.Orientation.Horizontal)
        self.slider_min.setMinimum(0)
        self.slider_min.setMaximum(100)
        self.slider_min.setValue(0)
        self.slider_min.valueChanged.connect(self.update_max_slider)

        layout.addWidget(self.slider_max)
        layout.addWidget(self.slider_min)

        self.setLayout(layout)

    def update_min_slider(self, value):
        self.slider_min.blockSignals(True)
        self.slider_min.setValue(100 - value)
        self.slider_min.blockSignals(False)

    def update_max_slider(self, value):
        self.slider_max.blockSignals(True)
        self.slider_max.setValue(100 - value)
        self.slider_max.blockSignals(False)

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

Sunday, September 1, 2024

Python 3.13.0rc1 : Test MSBuild with PyQt6.

The goal of this tutorial is to test the build process of the Python package.
Installing the PyQt6 python module may come with the build error.
In this case, MS Build is installed from the official website, and then other necessary Python modules can be installed depending on the files needed to build the PyQt6 package.
pip install --upgrade setuptools
pip install msvc-runtime
ERROR: Could not find a version that satisfies the requirement msvc-runtime (from versions: none)
ERROR: No matching distribution found for msvc-runtime
pip install pyqt6
Collecting pyqt6
  Using cached PyQt6-6.7.1-cp38-abi3-win_amd64.whl.metadata (2.1 kB)
...
Successfully built PyQt6-sip
Installing collected packages: PyQt6-Qt6, PyQt6-sip, pyqt6
Successfully installed PyQt6-Qt6-6.7.2 PyQt6-sip-13.8.0 pyqt6-6.7.1
This process uses a lot of files and MSBuild needs some Gb free on the hard disk.

Saturday, August 31, 2024

Python 3.13.0rc1 : Using pydoc python module.

This is default python module.
You can find pydoc - documentation.
Simple use of this python module for example: sys python module to see the documentation.
PythonProjects\test_pydoc>python -m pydoc sys
Using the w argument willcreate a HTML file with the documentation.
In this example will be sys.html, because is sys python module.
PythonProjects\test_pydoc>python -m pydoc -w sys
wrote sys.html
Best feature is search by word and show the result as python modules, in this case will show a list ...
PythonProjects\test_pydoc>python -m pydoc -k url
nturl2path - Convert a NT pathname to a file URL and vice versa.
test_sqlite3: testing with SQLite version 3.45.3
test.test_urllib - Regression tests for what was in Python 2's "urllib" module
test.test_urllib2
test.test_urllib2_localnet
test.test_urllib2net
Share the documentation with an server, in this case is set to localhost:
\PythonProjects\test_pydoc>python -m pydoc -p 1234
Server ready at http://localhost:1234/
Server commands: [b]rowser, [q]uit
You can create your python module script named test.py formated and then use pydoc.
"""
my python module
====
This is documentation
"""
def test():
"""
Function test
"""
    print("test")
Use this to show the text from your python source script module:
python -m pydoc test
PythonProjects\test_pydoc>python -m pydoc test
Help on module test:

NAME
    test

FILE
...

Thursday, August 29, 2024

News : ... august 2024

... news for Python users and developers.
Python 3.12.5 released, see the official webpage.
... new Python 3.13.0 release candidate 1 released, you can read on this webpage.
the last one: Announcing Python Software Foundation Fellow Members for Q1 2024! from this webpage.
About the releases, I can say that all kinds of improvements are coming, I liked that they made the shell more interactive.

Monday, August 19, 2024

Python 3.12.1 : Web server with SQLite database using flask - update.

Update with new URL with params, see the first tutorial:
from flask import Flask, request, jsonify, render_template_string
import sqlite3
from datetime import datetime

app = Flask(__name__)

# Clasa pentru serverul SQL
class SQLiteServer:
    def __init__(self, db_name):
        self.db_name = db_name
        self.init_db()

    def init_db(self):
        conn = sqlite3.connect(self.db_name)
        c = conn.cursor()
        c.execute('''
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY,
                first_name TEXT,
                last_name TEXT,
                occupation TEXT,
                hobby TEXT,
                year_of_birth INTEGER,
                age INTEGER
            )
        ''')
        conn.commit()
        conn.close()

    def calculate_age(self, year_of_birth):
        # Adjust year_of_birth if only two digits are provided
        if len(str(year_of_birth)) == 2:
            if year_of_birth > int(str(datetime.now().year)[-2:]):
                year_of_birth += 1900
            else:
                year_of_birth += 2000
        current_year = datetime.now().year
        return current_year - year_of_birth

    def add_user(self, first_name, last_name, occupation, hobby, year_of_birth):
        age = self.calculate_age(year_of_birth)
        conn = sqlite3.connect(self.db_name)
        c = conn.cursor()
        c.execute('''
            INSERT INTO users (first_name, last_name, occupation, hobby, year_of_birth, age)
            VALUES (?, ?, ?, ?, ?, ?)
        ''', (first_name, last_name, occupation, hobby, year_of_birth, age))
        conn.commit()
        conn.close()

    def get_users(self):
        conn = sqlite3.connect(self.db_name)
        c = conn.cursor()
        c.execute("SELECT * FROM users")
        users = c.fetchall()
        conn.close()
        return users
    def get_users_jsonify():
        conn = sqlite3.connect('sqlite_database.db')
        c = conn.cursor()
        c.execute("SELECT * FROM users")
        users = c.fetchall()
        conn.close()
        return jsonify(users)

# Clasa pentru serverul web
class WebServer:
    def __init__(self, sqlite_server):
        self.sqlite_server = sqlite_server

    def run(self):
        app.run(debug=True)
    #   adauga user si buton de redirect la pagina users
    @app.route('/')
    def index():
        users = sqlite_server.get_users()
        return render_template_string('''
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>Flask website for testing cypress with sqlite</title>
            </head>
            <body>
                <h2>Add User</h2>
                <form action="/add_user" method="post">
                    First Name: <input type="text" name="first_name"><br>
                    Last Name: <input type="text" name="last_name"><br>
                    Occupation: <input type="text" name="occupation"><br>
                    Hobby: <input type="text" name="hobby"><br>
                    Year of Birth: <input type="text" name="year_of_birth"><br>
                    <input type="submit" value="Add User">
                </form>
                <a href="http://127.0.0.1:5000/users"><button type="button">Show Users</button></a>
            </body>
            </html>
        ''', users=users)
    @app.route('/add_user', methods=['POST'])
    def add_user():
        first_name = request.form['first_name']
        last_name = request.form['last_name']
        occupation = request.form['occupation']
        hobby = request.form['hobby']
        year_of_birth = int(request.form['year_of_birth'])
        sqlite_server.add_user(first_name, last_name, occupation, hobby, year_of_birth)
        return 'User added successfully! <a href="/">Go back</a>'
    @app.route('/users', methods=['GET'])
    def get_users():
        query_type = request.args.get('query_type', 'simple')
        
        conn = sqlite3.connect('sqlite_database.db')
        c = conn.cursor()
        
        try:
            c.execute('SELECT name FROM sqlite_master WHERE type="table" AND name="users"')
            if not c.fetchone():
                return jsonify({"error": "Table 'users' does not exist"})

            if query_type == 'advanced':
                # Advanced query logic
                first_name = request.args.get('first_name')
                last_name = request.args.get('last_name')
                occupation = request.args.get('occupation')
                hobby = request.args.get('hobby')
                year_of_birth = request.args.get('year_of_birth')

                query = 'SELECT * FROM users WHERE 1=1'
                params = []
                # Exemple query simple 
                # Basic query: /users
                # Simple query: /users?query_type=simple for simple selection
                # Addvanced query: /users?query_type=advanced&first_name=John&occupation=Engineer for advanced querying
                # Advanced query with name search: /users?query_type=advanced&first_name=John&last_name=Doe
                # Query by occupation: /users?query_type=advanced&occupation=Engineer
                # Query by hobby: /users?query_type=advanced&hobby=Reading
                # Query by year of birth: /users?query_type=advanced&year_of_birth=1990

                if first_name:
                    query += ' AND first_name LIKE ?'
                    params.append(f'%{first_name}%')
                if last_name:
                    query += ' AND last_name LIKE ?'
                    params.append(f'%{last_name}%')
                if occupation:
                    query += ' AND occupation LIKE ?'
                    params.append(f'%{occupation}%')
                if hobby:
                    query += ' AND hobby LIKE ?'
                    params.append(f'%{hobby}%')
                if year_of_birth:
                    query += ' AND year_of_birth = ?'
                    params.append(year_of_birth)

                # Query by minimum age: /users?query_type=advanced&min_age=30
                # Query by maximum age: /users?query_type=advanced&max_age=50
                # Query with ordering: /users?query_type=advanced&order_by=last_name
                # Query with limit: /users?query_type=advanced&limit=10
                # Combined query: /users?query_type=advanced&first_name=John&occupation=Engineer&min_age=25&order_by=year_of_birth&limit=5          
                # Additional advanced query options
                for param, value in request.args.items():
                    match param:
                        case 'min_age':
                            query += ' AND (? - year_of_birth) >= ?'
                            params.extend([datetime.now().year, int(value)])
                        case 'max_age':
                            query += ' AND (? - year_of_birth) <= ?'
                            params.extend([datetime.now().year, int(value)])
                        case 'order_by':
                            query += f' ORDER BY {value}'
                        case 'limit':
                            query += ' LIMIT ?'
                            params.append(int(value))
                c.execute(query, params)
            else:
                # Simple query logic
                c.execute('SELECT * FROM users')

            users = c.fetchall()
        except sqlite3.OperationalError as e:
            return jsonify({"error": str(e)})
        finally:
            conn.close()
        
        return jsonify(users)

# Instanțierea serverului SQL și a serverului web
sqlite_server = SQLiteServer('sqlite_database.db')
web_server = WebServer(sqlite_server)

if __name__ == '__main__':
    web_server.run()

Wednesday, August 14, 2024

Python 3.12.1 : Web server with SQLite database using flask.

This python surce script can be used to start a web server with an SQLite server.
For example, you can use this to test with javascript on sql server, see next image:
This is the source code:
from flask import Flask, request, jsonify, render_template_string
import sqlite3
from datetime import datetime

app = Flask(__name__)

# Clasa pentru serverul SQL
class SQLServer:
    def __init__(self, db_name):
        self.db_name = db_name
        self.init_db()

    def init_db(self):
        conn = sqlite3.connect(self.db_name)
        c = conn.cursor()
        c.execute('''
            CREATE TABLE IF NOT EXISTS users (
                id INTEGER PRIMARY KEY,
                first_name TEXT,
                last_name TEXT,
                occupation TEXT,
                hobby TEXT,
                year_of_birth INTEGER,
                age INTEGER
            )
        ''')
        conn.commit()
        conn.close()

    def calculate_age(self, year_of_birth):
        # Adjust year_of_birth if only two digits are provided
        if len(str(year_of_birth)) == 2:
            if year_of_birth > int(str(datetime.now().year)[-2:]):
                year_of_birth += 1900
            else:
                year_of_birth += 2000
        current_year = datetime.now().year
        return current_year - year_of_birth

    def add_user(self, first_name, last_name, occupation, hobby, year_of_birth):
        age = self.calculate_age(year_of_birth)
        conn = sqlite3.connect(self.db_name)
        c = conn.cursor()
        c.execute('''
            INSERT INTO users (first_name, last_name, occupation, hobby, year_of_birth, age)
            VALUES (?, ?, ?, ?, ?, ?)
        ''', (first_name, last_name, occupation, hobby, year_of_birth, age))
        conn.commit()
        conn.close()

    def get_users(self):
        conn = sqlite3.connect(self.db_name)
        c = conn.cursor()
        c.execute("SELECT * FROM users")
        users = c.fetchall()
        conn.close()
        return users

# Clasa pentru serverul web
class WebServer:
    def __init__(self, sql_server):
        self.sql_server = sql_server

    def run(self):
        app.run(debug=True)

    @app.route('/')
    def index():
        users = sql_server.get_users()
        return render_template_string('''
            <h1>Users</h1>
            <ul>
                {% for user in users %}
                    <li>{{ user[1] }} {{ user[2] }} - {{ user[3] }} - {{ user[4] }} - {{ user[5] }} ({{ user[6] }} years old)</li>
                {% endfor %}
            </ul>
            <h2>Add User</h2>
            <form action="/add_user" method="post">
                First Name: <input type="text" name="first_name"><br>
                Last Name: <input type="text" name="last_name"><br>
                Occupation: <input type="text" name="occupation"><br>
                Hobby: <input type="text" name="hobby"><br>
                Year of Birth: <input type="text" name="year_of_birth"><br>
                <input type="submit" value="Add User">
            </form>
        ''', users=users)

    @app.route('/add_user', methods=['POST'])
    def add_user():
        first_name = request.form['first_name']
        last_name = request.form['last_name']
        occupation = request.form['occupation']
        hobby = request.form['hobby']
        year_of_birth = int(request.form['year_of_birth'])
        sql_server.add_user(first_name, last_name, occupation, hobby, year_of_birth)
        return 'User added successfully! <a href="/">Go back</a>'

# Instanțierea serverului SQL și a serverului web
sql_server = SQLServer('example.db')
web_server = WebServer(sql_server)

if __name__ == '__main__':
    web_server.run()

Saturday, August 3, 2024

Blender 3D and python scripting - part 029.

This is a simple Blender 3D script that render images from myimage_000 to myimage_035 around object named Cube.
The script can be changed with any object and any steps for 0 to 360 degree.
import bpy
import math
# Set the object that the camera will orbit around
#target_object = bpy.data.objects["MyObject"]

# Create a new empty object
empty = bpy.data.objects.new("Empty", None)

# Set the empty object's location to the origin point
empty.location = (0, 0, 0)

# Set the starting position for the camera
camera = bpy.data.objects["Camera"]

# Set the number of degrees to rotate the camera around the object
degrees = 360

# Set the distance that the camera should be from the object
distance = 7.6

# Set the speed at which the camera should orbit
speed = 10

# Set the direction in which the camera should orbit (1 for clockwise, -1 for counter-clockwise)
direction = 1

# Set the camera to track the object
bpy.ops.object.select_all(action="DESELECT")
camera.select_set(True)

# Set the distance to origin point
camera.location = (-distance, 0, 0)
bpy.context.view_layer.objects.active = camera

# Remove all constraints from the object "Cube"
bpy.data.objects['Cube'].select_get()
bpy.context.view_layer.objects.active = bpy.data.objects['Cube']
bpy.ops.object.constraints_clear()

# Add a track to constraint to the object and set it
bpy.ops.object.constraint_add(type="TRACK_TO")
bpy.ops.object.track_set(type="TRACKTO")

# Set the target object as the tracking target
bpy.data.objects['Cube'].select_get()
bpy.context.view_layer.objects.active = bpy.data.objects['Cube']

# Select the file image format
bpy.context.scene.render.image_settings.file_format = 'PNG'

# Animate the camera orbiting around the object
for frame in range(0, 36):
    # Set the current frame
    bpy.context.scene.frame_set(frame)

    # Calculate the new position for the camera based on its distance from the object
    x = distance * math.sin(math.radians(frame*speed*direction))
    y = distance * math.cos(math.radians(frame*speed*direction))
    camera.location = (x,y,0)
    # Set the output path for the rendered image
    bpy.context.scene.render.filepath = "C:\\tmp\\myimage_" + str(frame).zfill(3) + ".png"
    # Render the frame and save it to the output file
    bpy.ops.render.render(write_still=True)

Sunday, July 14, 2024

The Zen of Python ...

... see the The Zen of Python, with this source code import this:
python
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun  6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Sunday, July 7, 2024

Python 3.12.1 : testing with ollama - part 001.

You need to download the ollama from the official website.
This allow you to use commands on the console: ollama --help into new command shell.
Use the pip tool to install ollma python package:
pip install ollama
Collecting ollama
  Downloading ollama-0.2.1-py3-none-any.whl.metadata (4.2 kB)
...
Installing collected packages: httpx, ollama
  Attempting uninstall: httpx
    Found existing installation: httpx 0.26.0
    Uninstalling httpx-0.26.0:
      Successfully uninstalled httpx-0.26.0
Successfully installed httpx-0.27.0 ollama-0.2.1
This command will install llama3
ollama run llama3
Let's see a basic python script with mistral model:
import ollama
from rich.console import Console
console = Console()
print(ollama.pull("mistral"))
#with console.pager(styles=True):
#	console.print(ollama.show("mistral"))
with console.pager(styles=True):
	console.print(ollama.list())
Another python script with llama3 model:
import ollama

stream = ollama.chat(
    model='llama3',
    messages=[{'role': 'user', 'content': 'Tell me the sizes of Earth?'}],
    stream=True,
)

for chunk in stream:
  print(chunk['message']['content'], end='', flush=True)
The result is this:
What a great question!

The size of Earth can be measured in various ways, depending on what aspect you're interested in. Here are some common sizes and dimensions of our planet ...

Python 3.12.1 : Check proxies on network.

Simple example about how to check proxies in network ...
import socket

# Get IP 
hostname = socket.gethostname()
workstation_ip = socket.gethostbyname(hostname)
#print("workstation_ip : ", workstation_ip )

# Put your IP's proxies from network
proxy_ips = ["192.168.1.1", "192.168.1.2", "192.168.1.3"]

# check IP proxy
if workstation_ip in proxy_ips:
    print("Is a proxy on network")
else:
    print("Not network proxy")
pip install sockschain
Collecting sockschain
  Downloading sockschain-1.0.0-py3-none-any.whl.metadata (10 kB)
...
Installing collected packages: sockschain
Successfully installed sockschain-1.0.0
Example with sockschain python module:
import socket
import sockschain as socks

# Enable debugging
def DEBUG(msg):
  print (msg)

socks.DEBUG = DEBUG
# This would have set proxies using the standard environment variables:
socks.usesystemdefaults()

# Configure a default chain
chain = [
  'tor://localhost:9050/', # First hop is Tor,
  'tor://localhost:8080/', # 8080 port,
  'ssl://proxy.example.com:8443/', # SSL to proxy.example.com
  'http://user:pass@proxy.example.com/' # ... try auth to an HTTP proxy
]
socks.setdefaultproxy() # Clear the default chain
for hop in chain:
   socks.adddefaultproxy(*socks.parseproxy(hop))

# Configure alternate routes (no proxy for localhost)
socks.setproxy('localhost', socks.PROXY_TYPE_NONE)
socks.setproxy('127.0.0.1', socks.PROXY_TYPE_NONE)
... the result is:
python socket_web.py Routes are: {'localhost': [(0, None, None, True, None, None, None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)], '': [(0, None, None, True, None, None, None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)], '': [(0, None, None, True, None, None, None)], '*': [(7, 'localhost', 9050, True, None, None, None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)], '': [(0, None, None, True, None, None, None)], '*': [(7, 'localhost', 9050, True, None, None, None), (7, 'localhost', 8080, True, None, None, None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)], '': [(0, None, None, True, None, None, None)], '*': [(7, 'localhost', 9050, True, None, None, None), (7, 'localhost', 8080, True, None, None, None), (4, 'proxy.example.com', 8443, True, None, None, ['proxy.example.com'])]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)], '': [(0, None, None, True, None, None, None)], '*': [(7, 'localhost', 9050, True, None, None, None), (7, 'localhost', 8080, True, None, None, None), (4, 'proxy.example.com', 8443, True, None, None, ['proxy.example.com']), (3, 'proxy.example.com', 8080, False, 'user', 'pass', None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)], '': [(0, None, None, True, None, None, None)], '*': [(7, 'localhost', 9050, True, None, None, None), (7, 'localhost', 8080, True, None, None, None), (4, 'proxy.example.com', 8443, True, None, None, ['proxy.example.com']), (3, 'proxy.example.com', 8080, False, 'user', 'pass', None)]} Routes are: {'localhost': [(0, None, None, True, None, None, None)], 'localhost.localdomain': [(0, None, None, True, None, None, None)], '127.0.0.1': [(0, None, None, True, None, None, None)], '': [(0, None, None, True, None, None, None)], '*': [(7, 'localhost', 9050, True, None, None, None), (7, 'localhost', 8080, True, None, None, None), (4, 'proxy.example.com', 8443, True, None, None, ['proxy.example.com']), (3, 'proxy.example.com', 8080, False, 'user', 'pass', None)]}

Tuesday, July 2, 2024

Python 3.12.1 : Ursina python game engine - part 002 .

This is the second tutorial with ursina, because now I use Python version 3.12.1 and Ursina comes with version 7.0.0 .
The install is easy with the pip tool.
pip install ursina
Collecting ursina
...
Installing collected packages: panda3d, screeninfo, panda3d-simplepbr, panda3d-gltf, ursina
Successfully installed panda3d-1.10.14 panda3d-gltf-1.2.0 panda3d-simplepbr-0.12.0 screeninfo-0.8.1 ursina-7.0.0
About Ursina you can read more on the official website.
Platforms:
  • Windows
  • Linux
  • Mac (not officially supported, but will most likely work)
I tested with samples from the GitHub project and works well.
from ursina import *

app = Ursina(size=(1280,720))

physics_entities = []
class PhysicsEntity(Entity):
    def __init__(self, model='cube', collider='box', **kwargs):
        super().__init__(model=model, collider=collider, **kwargs)
        physics_entities.append(self)

    def update(self):
        if self.intersects():
            self.stop()
            return

        self.velocity = lerp(self.velocity, Vec3(0), time.dt)
        self.velocity += Vec3(0,-1,0) * time.dt * 5
        self.position += (self.velocity + Vec3(0,-4,0)) * time.dt


    def stop(self):
        self.velocity = Vec3(0,0,0)
        if self in physics_entities:
            physics_entities.remove(self)

    def on_destroy(self):
        self.stop()


    def throw(self, direction, force):
        pass

from ursina.shaders import lit_with_shadows_shader
Entity.default_shader = lit_with_shadows_shader
DirectionalLight().look_at(Vec3(1,-1,-1))

ground = Entity(model='plane', scale=32, texture='white_cube', texture_scale=Vec2(32), collider='box')

from ursina.prefabs.first_person_controller import FirstPersonController
player = FirstPersonController()

def input(key):
    if key == 'left mouse down':
        e = PhysicsEntity(model='cube', color=color.azure, velocity=Vec3(0), position=player.position+Vec3(0,1.5,0)+player.forward, collider='sphere')
        e.velocity = (camera.forward + Vec3(0,.5,0)) * 10
        # physics_entities.append(e)

Sky()
app.run()

Tuesday, June 25, 2024

Blender 3D and python scripting - part 028.

A simple script for Blender 4.0.0 version with Bright Pencil material, see the output image:
This is the source code:
import bpy
import random

# fix an active object before changing mode
if bpy.context.view_layer.objects.active is None:
    # If there is no active object, set the first object in the scene as active
    if len(bpy.context.scene.objects) > 0:
        bpy.context.view_layer.objects.active = bpy.context.scene.objects[0]
    else:
        print("There are no objects in the scene to set as active.")

# set the mode
bpy.ops.object.mode_set(mode='OBJECT')

# set camera from the scene
cam_ob = bpy.context.scene.camera

# if is a camera in the scene and set it as active object
if cam_ob is None:
    print("There is no camera in the scene.")
elif cam_ob.type == 'CAMERA':
    # Set the camera as active object
    bpy.context.view_layer.objects.active = cam_ob
    print("The camera has been set as active object.")
else:
    print(f"The object {cam_ob.type} is set as a camera, but it is not of type 'CAMERA'.")

# set data for the ink brush
gpencil = bpy.data.grease_pencils.new("Bright Pencil")

# make material for the ink brush
if "Bright Material" in bpy.data.materials.keys():
    gp_mat = bpy.data.materials["Bright Material"]
else:
    gp_mat = bpy.data.materials.new("Bright Material")

if not gp_mat.is_grease_pencil:
    bpy.data.materials.create_gpencil_data(gp_mat)
    bpy.context.object.active_material.grease_pencil.color = (0, 0, 1, 1)


# set the object for the ink brush 
if "Bright Pencil" not in bpy.data.objects:
    gp_data = bpy.data.objects.new("Bright Pencil", gpencil)
    bpy.context.scene.collection.objects.link(gp_data)
# if it does not already exist in the scene
else:
    gp_data = bpy.data.objects["Bright Pencil"]

# assign material for drawing 
if gp_mat.name not in gp_data.data.materials:
    gp_data.data.materials.append(gp_mat)

# define a function to create random lines
def create_random_strokes(num_strokes, max_width):
    # Set the active object and mode
    bpy.context.view_layer.objects.active = gp_data
    bpy.ops.object.mode_set(mode='PAINT_GPENCIL')

    # get or create layer and set it as active
    if gpencil.layers and gpencil.layers.active:
        layer = gpencil.layers.active
    else:
        layer = gpencil.layers.new('my_test_layer', set_active=True)
    # set layer as active
    gpencil.layers.active = layer

    # get or create frame and set it as active using change_frame() method
    if layer.frames and layer.active_frame:
        frame = layer.active_frame
    else:
        frame = layer.frames.new(1)

    for _ in range(num_strokes):
        stroke = frame.strokes.new()
        stroke.line_width = int(random.uniform(1.0, max_width))
        stroke.points.add(count=3)
        for point in stroke.points:
            point.co = (random.uniform(-1.0, 1.0), random.uniform(-1.0, 1.0), 0.0)

# this function with desired parameters
create_random_strokes(num_strokes=10, max_width=16.0)

# return to original mode
bpy.ops.object.mode_set(mode='OBJECT')

Wednesday, June 5, 2024

News : JAX in 100 Seconds by Fireship!

JAX is a Python library similar to NumPy for scientific computing and linear algebra, but designed to run on accelerators like Cuda-based GPUs and Google's TPUs.

Blender 3D and python scripting - part 027.

Is more easy to create your player character based on the armature.
The next step is to add more animation and export to your game engine ...
Based on this issue - blender.stackexchange website, I tested to today and works very well:
Let's see the source code:
import bpy
import mathutils 
from mathutils import Vector 
from math import *

class ArmatureMenu(bpy.types.Menu):
    bl_label = "Mesh 2 Armature Menu"
    bl_idname = "OBJECT_MT_Mesh_From_Armature"

    def draw(self, context):
        layout = self.layout
        layout.operator("wm.mesh_from_armature", text="Pyramid").mesh_type = 'Pyramid' # from here
        layout.operator("wm.mesh_from_armature", text="Tapered").mesh_type = 'Tapered' # from here
        layout.operator("wm.mesh_from_armature", text="Box").mesh_type = 'Box' # from here

def CreateMesh(self, meshType):

    obj = bpy.context.active_object

    if obj == None:
        self.report({"ERROR"}, "No selection" )
    elif obj.type != 'ARMATURE':
        self.report({"ERROR"}, "Armature expected" )
    else:
        processArmature( bpy.context, obj, meshType = meshType )

#Create the base object from the armature
def meshFromArmature( arm ):
    name = arm.name + "_mesh"
    meshData = bpy.data.meshes.new( name + "Data" )
    meshObj = bpy.data.objects.new( name, meshData )
    meshObj.matrix_world = arm.matrix_world.copy()
    return meshObj

#Create the bone geometry (vertices and faces)
def boneGeometry( l1, l2, x, z, baseSize, l1Size, l2Size, base, meshType ):
    
    if meshType == 'Tapered':
        print(meshType)
        x1 = x * baseSize * l1Size 
        z1 = z * baseSize * l1Size

        x2 = x * baseSize * l2Size 
        z2 = z * baseSize * l2Size
    elif meshType == 'Box':
        print(meshType)
        lSize = (l1Size + l2Size) / 2
        x1 = x * baseSize * lSize 
        z1 = z * baseSize * lSize

        x2 = x * baseSize * lSize 
        z2 = z * baseSize * lSize

    else: # default to Pyramid
        print(meshType)
        x1 = x * baseSize * l1Size 
        z1 = z * baseSize * l1Size

        x2 = Vector( (0, 0, 0) )
        z2 = Vector( (0, 0, 0) )

    verts = [
        l1 - x1 + z1,
        l1 + x1 + z1,
        l1 - x1 - z1,
        l1 + x1 - z1,
        l2 - x2 + z2,
        l2 + x2 + z2,
        l2 - x2 - z2,
        l2 + x2 - z2
        ] 

    faces = [
        (base+3, base+1, base+0, base+2),
        (base+6, base+4, base+5, base+7),
        (base+4, base+0, base+1, base+5),
        (base+7, base+3, base+2, base+6),
        (base+5, base+1, base+3, base+7),
        (base+6, base+2, base+0, base+4)
        ]

    return verts, faces

#Process the armature, goes through its bones and creates the mesh
def processArmature(context, arm, genVertexGroups = True, meshType = 'Pyramid'):
    print("processing armature {0} {1}".format(arm.name, meshType) )

    #Creates the mesh object
    meshObj = meshFromArmature( arm )
    context.collection.objects.link( meshObj )

    verts = []
    edges = []
    faces = []
    vertexGroups = {}

    bpy.ops.object.mode_set(mode='EDIT')

    try:
        #Goes through each bone
        for editBone in [b for b in arm.data.edit_bones if b.use_deform]:
            boneName = editBone.name
            # print( boneName )
            poseBone = arm.pose.bones[boneName]

            #Gets edit bone informations
            editBoneHead = editBone.head
            editBoneTail = editBone.tail
            editBoneVector = editBoneTail - editBoneHead
            editBoneSize = editBoneVector.dot( editBoneVector )
            editBoneRoll = editBone.roll
            editBoneX = editBone.x_axis
            editBoneZ = editBone.z_axis
            editBoneHeadRadius = editBone.head_radius
            editBoneTailRadius = editBone.tail_radius

            #Creates the mesh data for the bone
            baseIndex = len(verts)
            baseSize = sqrt( editBoneSize )
            newVerts, newFaces = boneGeometry( editBoneHead, editBoneTail, editBoneX, editBoneZ, baseSize, editBoneHeadRadius, editBoneTailRadius, baseIndex, meshType )

            verts.extend( newVerts )
            faces.extend( newFaces )

            #Creates the weights for the vertex groups
            vertexGroups[boneName] = [(x, 1.0) for x in range(baseIndex, len(verts))]

        #Assigns the geometry to the mesh
        meshObj.data.from_pydata(verts, edges, faces)

    except:
        bpy.ops.object.mode_set(mode='OBJECT')
    else:
        bpy.ops.object.mode_set(mode='OBJECT')

    #Assigns the vertex groups
    if genVertexGroups:
        for name, vertexGroup in vertexGroups.items():
            groupObject = meshObj.vertex_groups.new(name=name)
            for (index, weight) in vertexGroup:
                groupObject.add([index], weight, 'REPLACE')

    #Creates the armature modifier
    modifier = meshObj.modifiers.new('ArmatureMod', 'ARMATURE')
    modifier.object = arm
    modifier.use_bone_envelopes = False
    modifier.use_vertex_groups = True

    meshObj.data.update()

    return meshObj

class MeshFromArmatureOperator(bpy.types.Operator):
    bl_idname = "wm.mesh_from_armature"
    bl_label  = "MeshFromArmatureOperator"

    mesh_type : bpy.props.StringProperty(name="mesh_type")

    def execute(self, context):
        print('The mesh type is', self.mesh_type)
        CreateMesh(self, self.mesh_type)
        return {'FINISHED'}

def register():
    bpy.utils.register_class( ArmatureMenu )
    bpy.utils.register_class( MeshFromArmatureOperator )


def unregister():
    bpy.utils.unregister_class( ArmatureMenu )
    bpy.utils.unregister_class( MeshFromArmatureOperator )


if __name__ == "__main__":
    register()

    # The menu can also be called from scripts
    bpy.ops.wm.call_menu(name='OBJECT_MT_Mesh_From_Armature')
The result of this running script using a mixamo animation is this:

Monday, May 27, 2024

Python 3.10.7 : Krita and python - part 001.

Here is a Python script for Krita that will help you read the Python functions of a document.
Open a new document, create a python script, and add the source code. Use the main menu Tools - Scripts - Ten Scripts to choose the place where the script exists and the combination of keys for execution.
This is the source code:
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QTreeWidget, QTreeWidgetItem, QTextEdit
from krita import *

class LayerContentDialog(QWidget):
    def __init__(self, content):
        super().__init__()
        self.setWindowTitle("Conținutul preluat cu dir():")
        self.setGeometry(100, 100, 800, 600)

        main_layout = QVBoxLayout()

        tree_widget = QTreeWidget()
        tree_widget.setHeaderLabels(["Nume", "Tip"])
        self.add_items_recursive(tree_widget, content)
        main_layout.addWidget(tree_widget)

        close_button = QPushButton("Închide")
        close_button.clicked.connect(self.close)
        main_layout.addWidget(close_button)

        self.setLayout(main_layout)

    def add_items_recursive(self, tree_widget, items, parent_item=None):
        for item in items:
            if isinstance(item, str):
                if parent_item:
                    item_widget = QTreeWidgetItem(parent_item, [item, type(getattr(doc, item)).__name__])
                    help_text = "\n".join(dir(getattr(doc, item)))
                    item_widget.addChild(QTreeWidgetItem([help_text]))
                else:
                    item_widget = QTreeWidgetItem(tree_widget, [item, type(getattr(doc, item)).__name__])
                    help_text = "\n".join(dir(getattr(doc, item)))
                    item_widget.addChild(QTreeWidgetItem([help_text]))
            elif isinstance(item, type):
                parent = QTreeWidgetItem(tree_widget, [item.__name__, "Modul"])
                self.add_items_recursive(tree_widget, dir(item), parent)

doc = Krita.instance().activeDocument()
layerContents = dir(doc)

dialog = LayerContentDialog(layerContents)
dialog.show()
The result for this script is this:
You can use the main menu Tools - Scripts - Scripter to write, test, save, and run the source code.

Sunday, April 28, 2024

News : New Django Builder online tool.

Django builder is free to use, and a personal project worked on in my spare time.
Any donations are very much appreciated.
If you want to, feel free to donate using the BitCoin address or PayPal link below.
Here is a new online tool that allows you to create projects with the Django framework and manage them more easily. It comes with different versions of Django, you can include channels and HTMX.
I don't see a command line to manage the project...

Saturday, April 20, 2024

Python 3.12.1 : Using the subprocess python module - part 001.

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:
See the official webpage for Python verison 3.12.3 same like version 3.12.1 I used.
Let's see two examples with this python module:
First script will get output of net users command and will parse all into a list:
import subprocess

def find_users():
    try:
        result = subprocess.run(["net", "users"], capture_output=True, text=True)
        users = result.stdout.splitlines()      
        # define list content         
        user_list = []
        for line in users[4:-2]:  # inser only some rows 
            #print(line) #only users        
            user = line.split()
            user_list += user
        # print the right result
        print(user_list)
    except Exception as e:
        print(f"Error : {str(e)}")

# run find_users
find_users()
The result is this:
python test_001.py
['Administrator', 'catafest', 'DefaultAccount', 'Guest', 'WDAGUtilityAccount']
This source code will show data from tasklist and will print result of this ... :
import subprocess

def find_processes():
    try:
        result = subprocess.run(['tasklist', '/v'], capture_output=True, text=True)
        output_lines = result.stdout.splitlines()

        for line in output_lines[3:]:
            columns = line.split()
            #print(columns)
            #if len(columns) >= 8 and columns[9] == 'N/A':
            if len(columns) >= 8 and columns[0] == 'tasklist.exe':
                print(line)
    except Exception as e:
        print(f"A apărut o eroare la găsirea proceselor suspendate: {str(e)}")

find_processes()
The result will be like this:
python test_pid_003.py
tasklist.exe 8348 Console 1 10,304 K Unknown DESKTOP-mycomputer 0:00:00 N/A

Friday, April 19, 2024

Python 3.10.12 : Colab quantum circuits with qiskit - part 046.

I've added another introductory example to my GitHub repository with Google Colab notebooks on how to use quantum circuits with the Python package called qiskit and the IBM Quantum Platform.
I used the IBM Quantum Platform and it provides an A.P.I symbol so that it can be used with the source code.
You can find this notebook at this catafest_061.ipynb repo file.

Thursday, April 18, 2024

Python 3.12.3 : python and Federated Message Bus in Fedora Linux Distro.

A few days ago I tested this functionality named Federated Message Bus of the Linux distribution called Fedora.
Federated Message Bus is a library built on ZeroMQ using the PyZMQ Python bindings. fedmsg aims to make it easy to connect services together using ZeroMQ publishers and subscribers.
You can use this python package named fedmsg to use this functionality ...
This is the source code :
import fedmsg
from fedmsg import *

import os
# Set the routing_nitpicky flag to True
os.environ['FEDMSG_ROUTING_NITPICKY'] = 'True'


config = fedmsg.config.load_config([],None)
config['mute'] = True
config['timeout'] = 0

for name, endpoint, topic, msg in fedmsg.tail_messages(**config):
    print ("name ", name)
This is the result :
[mythcat@fedora FedoraMessaging]$ python fedmsg_001.py
No routing policy defined for "org.fedoraproject.prod.copr.build.start" but routing_nitpicky is False so the message is being treated as authorized.
name  fedora-infrastructure
No routing policy defined for "org.fedoraproject.prod.copr.chroot.start" but routing_nitpicky is False so the message is being treated as authorized.
name  fedora-infrastructure
No routing policy defined for "org.fedoraproject.prod.github.check_run" but routing_nitpicky is False so the message is being treated as authorized.
name  fedora-infrastructure
No routing policy defined for "org.fedoraproject.prod.github.pull_request_review" but routing_nitpicky is False so the message is being treated as authorized.
name  fedora-infrastructure
No routing policy defined for "org.fedoraproject.prod.github.pull_request_review_comment" but routing_nitpicky is False so the message is being treated as authorized.
name  fedora-infrastructure ... 

Tuesday, April 16, 2024

Python 3.12.1 : aiohttp python package - part 001.

This python package named aiohttp provides asynchronous HTTP client and server functionality.
You can find more about this pytho package on the GitHub repo and the official page.
The last time I wrote about this python package was on Thursday, July 9, 2020 in this source code tutorial titled Python 3.8.3 : About aiohttp python package.
A few days ago I tested two python scripts that use this python packet.
One script makes a benchmark and the other uses cookie technology as a test.
Here is the script that makes the benchmark...
import timeit
from http import cookies

from yarl import URL

from aiohttp import CookieJar

def filter_large_cookie_jar():
    """Filter out large cookies from the cookie jar."""
    jar = CookieJar()
    c = cookies.SimpleCookie()
    domain_url = URL("http://maxagetest.com/")
    other_url = URL("http://otherurl.com/")

    for i in range(5000):
        cookie_name = f"max-age-cookie{i}"
        c[cookie_name] = "any"
        c[cookie_name]["max-age"] = 60
        c[cookie_name]["domain"] = "maxagetest.com"
    jar.update_cookies(c, domain_url)
    assert len(jar) == 5000
    assert len(jar.filter_cookies(domain_url)) == 5000
    assert len(jar.filter_cookies(other_url)) == 0

    filter_domain = timeit.timeit(lambda: jar.filter_cookies(domain_url), number=1000)
    filter_other_domain = timeit.timeit(
        lambda: jar.filter_cookies(other_url), number=1000
    )
    print(f"filter_domain: {filter_domain}")
    print(f"filter_other_domain: {filter_other_domain}")

filter_large_cookie_jar()
Here is the result obtained...
python test_bench_001.py
filter_domain: 59.85247729999901
filter_other_domain: 0.042927300000883406
Is more easier to understand code on how to use a cookie with this Python package using the httpbin website.
httpbin.org is a simple HTTP request and response service. It provides an easy way to test and inspect various aspects of HTTP communication.
Let's see the source code:
import asyncio
import aiohttp

async def main():
    urls = [
        'http://httpbin.org/cookies/set?test=ok',
    ]

    async with aiohttp.ClientSession(cookie_jar=aiohttp.CookieJar()) as s:
        for url in urls:
            async with s.get(url) as r:
                print('JSON:', await r.json())

        cookies = s.cookie_jar.filter_cookies('http://httpbin.org')
        for key, cookie in cookies.items():
            print(f'Key: "{cookie.key}", Value: "{cookie.value}"')

if __name__ == '__main__':
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        pass
The result of this running is this ...
python test_cookie_001.py
JSON: {'cookies': {'test': 'ok'}}
Key: "test", Value: "ok"

Friday, April 12, 2024

Python 3.12.1 : NiceGUI - UI framework over internet.

NiceGUI is an easy-to-use, Python-based UI framework, which shows up in your web browser. You can create buttons, dialogs, Markdown, 3D scenes, plots and much more.
The project can be found on this GitHub repo.
pip install nicegui
Collecting nicegui
  Downloading nicegui-1.4.21-py3-none-any.whl.metadata (9.4 kB)
...
Successfully installed aiofiles-23.2.1 aiohttp-3.9.4 aiosignal-1.3.1 bidict-0.23.1 docutils-0.19 fastapi-0.109.2 
frozenlist-1.4.1 httptools-0.6.1 ifaddr-0.2.0 markdown2-2.4.13 multidict-6.0.5 nicegui-1.4.21 orjson-3.10.0 
pscript-0.7.7 python-engineio-4.9.0 python-multipart-0.0.9 python-socketio-5.11.2 simple-websocket-1.0.0 
starlette-0.36.3 uvicorn-0.29.0 vbuild-0.8.2 watchfiles-0.21.0 websockets-12.0 yarl-1.9.4
The default demo example from the official webpage works fine.
This is the source code I used.
from nicegui import ui
from nicegui.events import ValueChangeEventArguments

def show(event: ValueChangeEventArguments):
    name = type(event.sender).__name__
    ui.notify(f'{name}: {event.value}')

ui.button('Button', on_click=lambda: ui.notify('Click'))
with ui.row():
    ui.checkbox('Checkbox', on_change=show)
    ui.switch('Switch', on_change=show)
ui.radio(['A', 'B', 'C'], value='A', on_change=show).props('inline')
with ui.row():
    ui.input('Text input', on_change=show)
    ui.select(['One', 'Two'], value='One', on_change=show)
ui.link('And many more...', '/documentation').classes('mt-8')

ui.run()
I run with the python and you can see is visible in many places:
python test_001.py
NiceGUI ready to go on http://localhost:8080, http://x.x.x.x:8080, and http://x.x.x.x:8080
The result is this:
You can find a lot of examples on the official GitHub repo.

Thursday, April 4, 2024

News : SciPy 1.13.0 new release.

SciPy 1.13.0 is the culmination of 3 months of hard work. This out-of-band release aims to support NumPy 2.0.0, and is backwards compatible to NumPy 1.22.4. The version of OpenBLAS used to build the PyPI wheels has been increased to 0.3.26.dev.
This release requires Python 3.9+ and NumPy 1.22.4 or greater.
For running on PyPy, PyPy3 6.0+ is required.
This release can be found on the official GitHub repo.
python -m pip install --upgrade pip
Requirement already satisfied: pip in c:\python312\lib\site-packages (24.0)
...
python -m pip install --upgrade matplotlib
Collecting matplotlib
  Downloading matplotlib-3.8.4-cp312-cp312-win_amd64.whl.metadata (5.9 kB)
...
Successfully installed contourpy-1.2.1 cycler-0.12.1 fonttools-4.50.0 kiwisolver-1.4.5 matplotlib-3.8.4
...
python -m pip install --upgrade scipy
Collecting scipy
  Downloading scipy-1.13.0-cp312-cp312-win_amd64.whl.metadata (60 kB)
...
Successfully installed scipy-1.13.0
I tested the interpolate.Akima1DInterpolator changes with the default python script and works well:
import numpy as np
from scipy.interpolate import Akima1DInterpolator

import matplotlib.pyplot as plt
fig, ax = plt.subplots()

x = np.linspace(1, 7, 7)
y = np.array([-1, -1, -1, 0, 1, 1, 1])
xs = np.linspace(min(x), max(x), num=100)
y_akima = Akima1DInterpolator(x, y, method="akima")(xs)
y_makima = Akima1DInterpolator(x, y, method="makima")(xs)


ax.plot(x, y, "o", label="data")
ax.plot(xs, y_akima, label="akima")
ax.plot(xs, y_makima, label="makima")

ax.set_title('Fruit supply by kind and color')
ax.legend(title='Fruit color')

plt.show()
about Akima piecewise cubic Hermite interpolation.
Akima interpolator Fit piecewise cubic polynomials, given vectors x and y. The interpolation method by Akima uses a continuously differentiable sub-spline built from piecewise cubic polynomials. The resultant curve passes through the given data points and will appear smooth and natural.
The result of this source code is this: