analitics

Pages

Showing posts with label modules. Show all posts
Showing posts with label modules. Show all posts

Saturday, February 8, 2025

Python 3.13.0rc1 : Testing python with Ollama local install.

I was very busy with development and testing for about two weeks and my laptop was stuck and I was working hard... Today I managed to test local background clipping on my laptop with a local Ollama installation separated by a Python module but with processing from the Python script. I also used Microsoft's Copilot artificial intelligence for python and it works well even though it is not theoretically specialized in development. The source code is quite large but the result is very good and fast:
import subprocess
import os
import json
from PIL import Image, ImageOps

class OllamaProcessor:
    def __init__(self, config_file):
        self.config_file = config_file
        self.model_methods = self.load_config()

    def load_config(self):
        try:
            with open(self.config_file, 'r') as file:
                config = json.load(file)
            print("Configuration loaded successfully.")
            return config
        except FileNotFoundError:
            print(f"Configuration file {self.config_file} not found.")
            raise
        except json.JSONDecodeError:
            print(f"Error decoding JSON from the configuration file {self.config_file}.")
            raise

    def check_ollama(self):
        try:
            result = subprocess.run(["ollama", "--version"], capture_output=True, text=True, check=True)
            print("Ollama is installed. Version:", result.stdout)
        except subprocess.CalledProcessError as e:
            print("Ollama is not installed or not found in PATH. Ensure it's installed and accessible.")
            raise
... 
Here is the result obtained after finishing running in the command line:
python ollama_test_001.py
Configuration file ollama_config.json created successfully.
Configuration loaded successfully.
Ollama is installed. Version: ollama version is 0.5.7

Available models: ['NAME']
pulling manifest
pulling 170370233dd5... 100% ▕██████████████▏ 4.1 GB
pulling 72d6f08a42f6... 100% ▕██████████████▏ 624 MB
pulling 43070e2d4e53... 100% ▕██████████████▏  11 KB
pulling c43332387573... 100% ▕██████████████▏   67 B
pulling ed11eda7790d... 100% ▕██████████████▏   30 B
pulling 7c658f9561e5... 100% ▕██████████████▏  564 B
verifying sha256 digest
writing manifest
success
Model llava pulled successfully for method process_images_in_folder.
Some "Command failed ..." but the result is cutting well and it has transparency !

Thursday, January 30, 2025

Blender 3D and python scripting - part 032.

Today I created an addon for Blender version 4.3.2 that allows me to select two folders to render 3D objects from the first folder and add 512px samples with these renderings to the second folder.
This is what the addon installed in Blender 3D looks like:
Here's what the source code of this addon looks like:
bl_info = {
    "name": "3D File Renderer by catafest",
    "blender": (4, 3, 2),
    "category": "Object",
    "author": "Catalin George Festila\n"
              "nicknames: catafest and mythcat\n"
              "country: Romania\n"
              "mail: catafest [at] yahoo.com",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D > UI > 3D File Renderer",
    "description": "Addon for rendering 3D files",
    "warning": "",
    "doc_url": "https://github.com/catafest",
    "tracker_url": "https://github.com/catafest/issues",
    "support": "COMMUNITY",
}

import bpy
import os

class FileRendererProperties(bpy.types.PropertyGroup):
    input_directory: bpy.props.StringProperty(
        name="Input Directory",
        description="Directory containing 3D files",
        default="",
        maxlen=1024,
        subtype='DIR_PATH'
    )
    output_directory: bpy.props.StringProperty(
        name="Output Directory",
        description="Directory to save rendered images",
        default="",
        maxlen=1024,
        subtype='DIR_PATH'
    )

class RENDER_OT_files(bpy.types.Operator):
    bl_idname = "render.files"
    bl_label = "Start render 3D files for all files"
    
    def execute(self, context):
        input_directory = context.scene.file_renderer_props.input_directory
        output_directory = context.scene.file_renderer_props.output_directory
        
        if not input_directory or not output_directory:
            self.report({'ERROR'}, "Input and Output directories must be set.")
            return {'CANCELLED'}
        
        if not os.path.exists(output_directory):
            os.makedirs(output_directory)
        
        def render_file(file_path, output_path):
            try:
                bpy.ops.wm.read_factory_settings(use_empty=True)
                ext = os.path.splitext(file_path)[1].lower()
                if ext == ".glb":
                    bpy.ops.import_scene.gltf(filepath=file_path)
                elif ext == ".obj":
                    bpy.ops.import_scene.obj(filepath=file_path)
                elif ext == ".fbx":
                    bpy.ops.import_scene.fbx(filepath=file_path)
                else:
                    raise ValueError("Unsupported file format")
                
                bpy.ops.object.camera_add(location=(0, -3, 1.5), rotation=(1.1, 0, 0))
                camera = bpy.context.scene.objects['Camera']
                bpy.context.scene.camera = camera
                bpy.ops.object.light_add(type='POINT', location=(0, -3, 3))
                light = bpy.context.view_layer.objects.active
                light.data.energy = 1000
                
                bpy.context.scene.render.resolution_x = 512
                bpy.context.scene.render.resolution_y = 512
                bpy.context.scene.render.filepath = output_path
                bpy.ops.render.render(write_still=True)
            except Exception as e:
                # Generate a red image with "BAD FILE" text using Blender
                bpy.ops.wm.read_factory_settings(use_empty=True)
                bpy.ops.mesh.primitive_plane_add(size=2)
                plane = bpy.context.active_object
                mat = bpy.data.materials.new(name="BadFileMaterial")
                mat.diffuse_color = (1, 0, 0, 1)  # Red
                plane.data.materials.append(mat)
                
                # Add "BAD FILE" text
                bpy.ops.object.text_add(location=(0, 0, 0.1))
                text_obj = bpy.context.active_object
                text_obj.data.body = "BAD FILE"
                text_obj.data.size = 0.5
                text_obj.data.align_x = 'CENTER'
                text_obj.data.align_y = 'CENTER'
                text_obj.rotation_euler = (1.5708, 0, 0)
                
                # Set camera and light
                bpy.ops.object.camera_add(location=(0, -3, 1.5), rotation=(1.1, 0, 0))
                camera = bpy.context.scene.objects['Camera']
                bpy.context.scene.camera = camera
                bpy.ops.object.light_add(type='POINT', location=(0, -3, 3))
                light = bpy.context.view_layer.objects.active
                light.data.energy = 1000
                
                bpy.context.scene.render.resolution_x = 512
                bpy.context.scene.render.resolution_y = 512
                bpy.context.scene.render.filepath = output_path
                bpy.ops.render.render(write_still=True)
        
        for filename in os.listdir(input_directory):
            if filename.lower().endswith((".glb", ".obj", ".fbx")):
                file_path = os.path.join(input_directory, filename)
                output_path = os.path.join(output_directory, os.path.splitext(filename)[0] + ".png")
                render_file(file_path, output_path)
        
        self.report({'INFO'}, "Rendering of files is complete.")
        return {'FINISHED'}

class ABOUT_OT_dialog(bpy.types.Operator):
    bl_idname = "wm.about_dialog"
    bl_label = "About this addon"
    
    def execute(self, context):
        return context.window_manager.invoke_props_dialog(self)
    
    def draw(self, context):
        layout = self.layout
        layout.label(text="3D File Renderer by catafest")
        layout.label(text="Author: Catalin George Festila")
        layout.label(text="Nicknames: catafest and mythcat")
        layout.label(text="Country: Romania")
        layout.label(text="Email: catafest [at] yahoo.com")
        layout.operator("wm.url_open", text="LinkedIn").url = "https://www.linkedin.com/in/c%C4%83t%C4%83lin-george-fe%C8%99til%C4%83-05780a67"
        layout.operator("wm.url_open", text="Author Site").url = "https://sites.google.com/view/festila-george-catalin"
        layout.operator("wm.url_open", text="catafest GitHub").url = "https://github.com/catafest"
        layout.operator("wm.url_open", text="catafest-work GitHub").url = "https://github.com/catafest-work"

class FileRendererPanel(bpy.types.Panel):
    bl_label = "3D File Renderer by catafest"
    bl_idname = "OBJECT_PT_file_renderer"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'File Renderer'
    
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        file_renderer_props = scene.file_renderer_props
        
        layout.prop(file_renderer_props, "input_directory")
        layout.prop(file_renderer_props, "output_directory")
        
        # Styling the render button
        render_button = layout.operator("render.files", text="Start render 3D files for all files")
        
        layout.separator()
        
        layout.operator("wm.about_dialog", text="About this addon")

def register():
    bpy.utils.register_class(FileRendererProperties)
    bpy.utils.register_class(RENDER_OT_files)
    bpy.utils.register_class(ABOUT_OT_dialog)
    bpy.utils.register_class(FileRendererPanel)
    bpy.types.Scene.file_renderer_props = bpy.props.PointerProperty(type=FileRendererProperties)

def unregister():
    bpy.utils.unregister_class(FileRendererProperties)
    bpy.utils.unregister_class(RENDER_OT_files)
    bpy.utils.unregister_class(ABOUT_OT_dialog)
    bpy.utils.unregister_class(FileRendererPanel)
    del bpy.types.Scene.file_renderer_props

if __name__ == "__main__":
    register()

Tuesday, January 28, 2025

Blender 3D and python scripting - part 031.

This python script for blender will select vertrices based on boolean ...
This is the result with Blender version 4.3 :
This is the python script:
import bpy, bmesh

obj = bpy.context.active_object
me = obj.data

bpy.ops.object.mode_set(mode = 'EDIT') 
bpy.ops.mesh.select_mode(type="VERT")


bm = bmesh.from_edit_mesh(obj.data)
selected = [False,False,True,True,True,True,True,True]
verts = [vert for vert in bpy.context.active_object.data.vertices if vert.select]
all = [vert for vert in bpy.context.active_object.data.vertices]
print("selected:",len(verts))
print("all:",len(all))
bpy.ops.object.mode_set(mode = 'OBJECT')
me.vertices.foreach_set(
"select",
selected
)
bpy.ops.object.mode_set(mode = 'EDIT')

Thursday, January 23, 2025

Blender 3D and python scripting - part 030.

Today I will show a python script for Blender 3D that create an 3D object and one material.
This is the final result of this python script:
This is the python script:
# give Python access to Blender's functionality
import bpy

# extend Python's math functionality
import math


# extend Python functionality to generate random numbers
import random


def partially_clean_the_scene():
    # select all object in the scene
    bpy.ops.object.select_all(action="SELECT")

    # delete all selected objects in the scene
    bpy.ops.object.delete()

    # make sure we remove data that was connected to the objects we just deleted
    bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)


def create_noise_mask(material):
    """Add a set of nodes to create a noise mask using:
    * Texture Coordinate node
    * Mapping node
    * Noise Texture node
    * Color Ramp node
    """
    node_location_x_step = 300
    node_location_x = -node_location_x_step

    # create a Color Ramp node
    # https://docs.blender.org/api/current/bpy.types.ShaderNodeValToRGB.html
    color_ramp_node = material.node_tree.nodes.new(type="ShaderNodeValToRGB")
    color_ramp_node.color_ramp.elements[0].position = 0.45
    color_ramp_node.color_ramp.elements[1].position = 0.5
    color_ramp_node.location.x = node_location_x
    node_location_x -= node_location_x_step

    # create a Noise Texture node
    # https://docs.blender.org/api/current/bpy.types.ShaderNodeTexNoise.html#bpy.types.ShaderNodeTexNoise
    noise_texture_node = material.node_tree.nodes.new(type="ShaderNodeTexNoise")
    noise_texture_node.inputs["Scale"].default_value = random.uniform(1.0, 20.0)
    noise_texture_node.location.x = node_location_x
    node_location_x -= node_location_x_step

    # create a Mapping node
    # https://docs.blender.org/api/current/bpy.types.ShaderNodeMapping.html#bpy.types.ShaderNodeMapping
    mapping_node = material.node_tree.nodes.new(type="ShaderNodeMapping")
    mapping_node.inputs["Rotation"].default_value.x = math.radians(random.uniform(0.0, 360.0))
    mapping_node.inputs["Rotation"].default_value.y = math.radians(random.uniform(0.0, 360.0))
    mapping_node.inputs["Rotation"].default_value.z = math.radians(random.uniform(0.0, 360.0))
    mapping_node.location.x = node_location_x
    node_location_x -= node_location_x_step

    # create a Texture Coordinate node
    texture_coordinate_node = material.node_tree.nodes.new(type="ShaderNodeTexCoord")
    texture_coordinate_node.location.x = node_location_x

    # connect the nodes
    # https://docs.blender.org/api/current/bpy.types.NodeTree.html#bpy.types.NodeTree
    # https://docs.blender.org/api/current/bpy.types.NodeLinks.html#bpy.types.NodeLinks
    material.node_tree.links.new(noise_texture_node.outputs["Color"], color_ramp_node.inputs["Fac"])
    material.node_tree.links.new(mapping_node.outputs["Vector"], noise_texture_node.inputs["Vector"])
    material.node_tree.links.new(texture_coordinate_node.outputs["Generated"], mapping_node.inputs["Vector"])

    return color_ramp_node


def create_material(name):
    # create new material
    material = bpy.data.materials.new(name=name)
    # enable creating a material via nodes
    material.use_nodes = True

    # get a reference to the Principled BSDF shader node
    principled_bsdf_node = material.node_tree.nodes["Principled BSDF"]

    # set the base color of the material
    principled_bsdf_node.inputs["Base Color"].default_value = (0.8, 0.120827, 0.0074976, 1)

    # set the metallic value of the material
    principled_bsdf_node.inputs["Metallic"].default_value = 1.0

    color_ramp_node = create_noise_mask(material)

    material.node_tree.links.new(color_ramp_node.outputs["Color"], principled_bsdf_node.inputs["Roughness"])

    return material

def add_mesh():
    # create an ico sphere
    bpy.ops.mesh.primitive_ico_sphere_add(subdivisions=5)
    # shade smooth
    bpy.ops.object.shade_smooth()
    # get reference to mesh object
    mesh_obj = bpy.context.active_object

    return mesh_obj

def main():

    partially_clean_the_scene()

    name = "my_generated_material"
    material = create_material(name)

    mesh_obj = add_mesh()

    # apply the material to the mesh object
    mesh_obj.data.materials.append(material)

main()

Tuesday, January 7, 2025

Python 3.13.0rc1 : Simple convert all webp files from folder.

Today, a simple script is used to convert WEBP to PNG files from a defined folder.
The script reads a folder path for each WEBP file that is opened and saved as a PNG file.
import os
import sys
from PIL import Image

def convert_webp_to_png(directory):
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(".webp"):
                webp_path = os.path.join(root, file)
                png_path = os.path.splitext(webp_path)[0] + ".png"
                with Image.open(webp_path) as img:
                    img.save(png_path, "PNG")
                print(f"webp to png file: {webp_path} -> {png_path}")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("How to use: python convert.py path_to_folder_with_webp_files")
        sys.exit(1)

    directory = sys.argv[1]
    if not os.path.isdir(directory):
        print(f"{directory} folder is not valid.")
        sys.exit(1)

    convert_webp_to_png(directory)
    print("Finished !")

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)

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

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