Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: ArabicReshaper.reshape() got an unexpected keyword argument 'support_ligatures' on Windows despite correct setup #98

Open
mr-haeri opened this issue Feb 4, 2025 · 0 comments

Comments

@mr-haeri
Copy link

mr-haeri commented Feb 4, 2025

I am encountering a persistent TypeError: ArabicReshaper.reshape() got an unexpected keyword argument 'support_ligatures' error when running my Python script on Windows, despite having arabic-reshaper version 3.0.0 installed in a virtual environment. I have tried numerous troubleshooting steps, but the issue remains unresolved.

Environment:

Operating System: Windows 11, 64-bit
Python Version: Python 3.10.9
arabic-reshaper Version: 3.0.0 (Verified with pip show arabic-reshaper)
IDE: VS Code
Virtual Environment: quran_env (Created using virtualenv and activated before running the script)

Steps to Reproduce:

Activate the virtual environment quran_env.
Run the video.py script (code provided below).
Code (video.py):

import os
import re
from moviepy.editor import *
from moviepy.video.tools.subtitles import SubtitlesClip
from PIL import Image, ImageFont, ImageDraw
import arabic_reshaper
from bidi.algorithm import get_display
import numpy
import importlib

# Force reload arabic_reshaper module
importlib.reload(arabic_reshaper)

# Settings
VIDEO_DIR = "video"
QURAN_DIR = "Quran"
FONT_ARABIC = "me_quran.ttf"  # Replace with your Arabic font path
FONT_FARSI = "Yekan Bakh.ttf"  # Replace with your Farsi font path
FONT_SIZE_ARABIC = 48
FONT_SIZE_FARSI = 36
TEXT_COLOR = "white"
BACKGROUND_COLOR = "black"
FRAME_RATE = 24
VIDEO_WIDTH = 1280
VIDEO_HEIGHT = 720
CRF_VALUE = 18
AUDIO_CODEC = "aac"
VIDEO_CODEC = "libx264"
BORDER_COLOR = "gray"
BORDER_WIDTH = 5

def create_rounded_rectangle(width, height, color, border_width, border_color):
    radius = 30
    img = Image.new('RGBA', (width, height), color)
    draw = ImageDraw.Draw(img)
    draw.ellipse((0, 0, 2 * radius, 2 * radius), fill=border_color)
    draw.ellipse((width - 2 * radius, 0, width, 2 * radius), fill=border_color)
    draw.ellipse((0, height - 2 * radius, 2 * radius, height), fill=border_color)
    draw.ellipse((width - 2 * radius, height - 2 * radius, width, height), fill=border_color)
    draw.rectangle((radius, 0, width - radius, height), fill=border_color)
    draw.rectangle((0, radius, width, height - radius), fill=border_color)
    draw.rectangle((border_width, border_width, width - border_width, height - border_width), fill=color)
    return img

def create_verse_image(arabic_text, farsi_text, verse_number):
    reshaped_arabic = arabic_reshaper.reshape(arabic_text, support_ligatures=True)
    bidi_arabic = get_display(reshaped_arabic)
    reshaped_farsi = arabic_reshaper.reshape(farsi_text)
    bidi_farsi = get_display(reshaped_farsi)
    arabic_font = ImageFont.truetype(FONT_ARABIC, FONT_SIZE_ARABIC)
    farsi_font = ImageFont.truetype(FONT_FARSI, FONT_SIZE_FARSI)
    arabic_text_bbox = arabic_font.getbbox(bidi_arabic)
    farsi_text_bbox = farsi_font.getbbox(bidi_farsi)
    arabic_text_width = arabic_text_bbox[2] - arabic_text_bbox[0]
    arabic_text_height = arabic_text_bbox[3] - arabic_text_bbox[1]
    farsi_text_width = farsi_text_bbox[2] - farsi_text_bbox[0]
    farsi_text_height = farsi_text_bbox[3] - farsi_text_bbox[1]
    max_text_width = max(arabic_text_width, farsi_text_width)
    padding = 20
    border_image = create_rounded_rectangle(
        max_text_width + 2 * padding,
        arabic_text_height + farsi_text_height + 3 * padding,
        BACKGROUND_COLOR,
        BORDER_WIDTH,
        BORDER_COLOR
    )
    img = Image.new("RGBA", (VIDEO_WIDTH, VIDEO_HEIGHT), (0, 0, 0, 0))
    img.paste(border_image, ((VIDEO_WIDTH - border_image.width) // 2, (VIDEO_HEIGHT - border_image.height) // 2), border_image)
    draw = ImageDraw.Draw(img)
    x_arabic = (VIDEO_WIDTH - arabic_text_width) // 2
    y_arabic = (VIDEO_HEIGHT - (arabic_text_height + farsi_text_height + padding)) // 2
    draw.text((x_arabic, y_arabic), bidi_arabic, font=arabic_font, fill=TEXT_COLOR)
    x_farsi = (VIDEO_WIDTH - farsi_text_width) // 2
    y_farsi = y_arabic + arabic_text_height + padding
    draw.text((x_farsi, y_farsi), bidi_farsi, font=farsi_font, fill=TEXT_COLOR)
    verse_number_font = ImageFont.truetype(FONT_FARSI, 24)
    verse_number_text = arabic_reshaper.reshape(str(verse_number))
    verse_number_text = get_display(verse_number_text)
    verse_number_bbox = verse_number_font.getbbox(verse_number_text)
    verse_number_width = verse_number_bbox[2] - verse_number_bbox[0]
    verse_number_height = verse_number_bbox[3] - verse_number_bbox[1]
    draw.text((VIDEO_WIDTH - verse_number_width - 20, VIDEO_HEIGHT - verse_number_height - 20),
              verse_number_text, font=verse_number_font, fill=TEXT_COLOR)
    return img


def create_surah_video(surah_path, surah_number):
    surah_name = os.path.basename(surah_path)
    audio_files = sorted([f for f in os.listdir(surah_path) if f.endswith(".mp3")], key=lambda x: int(x.split('.')[0]))
    mate_file = os.path.join(surah_path, "mate.txt")
    tarjomeh_file = os.path.join(surah_path, "Tarjomeh.txt")

    try:
        with open(mate_file, "r", encoding="utf-8") as f_arabic, open(tarjomeh_file, "r", encoding="utf-8") as f_farsi:
            arabic_lines = [line.strip() for line in f_arabic if line.strip()]
            farsi_lines = [line.strip() for line in f_farsi if line.strip()]
    except FileNotFoundError:
        print(f"Error: mate.txt or Tarjomeh.txt not found in {surah_name}")
        return

    if len(arabic_lines) != len(farsi_lines) or len(arabic_lines) != len(audio_files):
        print(f"Error: Number of lines in mate.txt, Tarjomeh.txt, or audio files do not match in {surah_name}")
        print(f"Arabic lines: {len(arabic_lines)}, Farsi lines: {len(farsi_lines)}, Audio files: {len(audio_files)}")
        return

    clips = []
    for i, audio_file in enumerate(audio_files):
        verse_number = i + 1
        arabic_text = arabic_lines[i].strip()
        farsi_text = farsi_lines[i].strip()
        audio_path = os.path.join(surah_path, audio_file)

        try:
            audio_clip = AudioFileClip(audio_path)
            image = create_verse_image(arabic_text, farsi_text, verse_number)
            img_clip = ImageClip(
                img=numpy.array(image),
                duration=audio_clip.duration
            ).set_audio(audio_clip)

            img_clip = img_clip.fadein(0.5).fadeout(0.5)
            clips.append(img_clip)
        except Exception as e:
            print(f"Error processing verse {verse_number} in {surah_name}: {e}")
            return

    final_clip = concatenate_videoclips(clips)
    output_filename = os.path.join(VIDEO_DIR, f"Surah_{surah_number:03}_HD.mp4")
    final_clip.write_videofile(
        output_filename,
        fps=FRAME_RATE,
        codec=VIDEO_CODEC,
        audio_codec=AUDIO_CODEC,
        ffmpeg_params=["-crf", str(CRF_VALUE)]
    )
    print(f"Video created successfully: {output_filename}")

def main():
    if not os.path.exists(VIDEO_DIR):
        os.makedirs(VIDEO_DIR)

    surah_folders = sorted([d for d in os.listdir(QURAN_DIR) if os.path.isdir(os.path.join(QURAN_DIR, d)) and d.startswith("Surah_")], key=lambda x: int(x.split('_')[1]))

    for surah_folder in surah_folders:
        surah_number = int(surah_folder.split('_')[1])
        surah_path = os.path.join(QURAN_DIR, surah_folder)
        create_surah_video(surah_path, surah_number)


if __name__ == "__main__":
    main()

Expected Behavior:

The script should run without errors and generate video files for each Surah in the Quran, with Arabic text rendered correctly, including diacritics (ligatures).

Actual Behavior:

The script throws the following error:

Error processing verse 1 in Surah_1: ArabicReshaper.reshape() got an unexpected keyword argument 'support_ligatures' Error processing verse 1 in Surah_2: ArabicReshaper.reshape() got an unexpected keyword argument 'support_ligatures' ...

Troubleshooting Steps Taken:

Uninstalled and reinstalled arabic-reshaper multiple times.
Closed and reopened the terminal.
Reactivated the virtual environment.
Used importlib.reload(arabic_reshaper) to force reloading the module.
Tried running the script with py video.py and python -S video.py.
Verified that the correct python and pip are being used from within the virtual environment using where python and where pip.
Checked for conflicting packages using pipdeptree. No conflicts found.
Temporarily disabled other Python installations by modifying the PATH environment variable.
The issue is not reproducible in a fresh virtual environment on a different machine running a different OS (e.g., Linux), suggesting a system-specific or configuration-specific issue.
Tried to use arabic_reshaper.shape() instead of reshape(), but got a similar error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant