[Rust] 06 FLTK-RS : ランチャーアプリ製作 PyO3によるPythonモジュール導入

[M1 Mac, Big Sur 11.6.7, Rust 1.62.0]

Rustコードから引数なしのPythonスクリプトを実行できるようにしました。Python/C API経験者であればそんなに難しくないでしょう。

RustではPyO3ライブラリを使います。PyO3公式サイトを読めば、スクリプト埋め込みや複数スクリプトなど様々なPythonの使い方が分かります。

with_gilのgilはGlobal interpreter lockの略であり、Pythonインタプリタへのアクセスができるようになります。

C++やObjective-Cよりも導入方法が簡単で驚きです。これならPythonを使うのであればC言語系ではなくRustにしますね。以前はセキュリティ面で課題を抱えていたと聞きますが、PyO3の開発陣はすごいなと素直に思いました。

Python→C/C++の流れからPython→RustのようにC/C++をスルーするユーザーが今後増えていくのではないでしょうか。またRustの記事を書く方の中にはC/C++を知らない方もいるということを認識しておく必要があります。

いつも思うのですが、プログラミングに関する記事を書く場合はWindowsなのかLinuxなのかMacOSなのか、バージョンと合わせて明記していただきたいものです。

use fltk::{app, prelude::*, button::*, window::Window, group::{Group}};
use pyo3::prelude::*;

// PhotoSorting.py内のphotosorting関数を使用
fn pythonmodule() -> PyResult<()> {
    Python::with_gil(|py| {
        let mymodule = PyModule::import(py, "PhotoSorting")?;
        let response:i32 = mymodule.getattr("photosorting")?.call0()?.extract()?;
        println!("{}", response);
        Ok(())
    })
}

fn main() {
    let app = app::App::default();
    let mut window = Window::new(100, 100, 360, 190, "Tool Launcher");
    
    let  grp = Group::new(15, 15, 285 , 160, "");
    let mut _btn1= RadioRoundButton::new(15, 15, 140, 20, "PhotoSorting");
    _btn1.set(true);
    let mut _btn2= RadioRoundButton::new(15, 50, 140, 20, "");
    let mut _btn3= RadioRoundButton::new(15, 85, 140, 20, "");
    let mut _btn4= RadioRoundButton::new(15, 120, 140, 20, "");
    let mut _btn5= RadioRoundButton::new(15, 155, 140, 20, "");
    let mut _btn6= RadioRoundButton::new(160, 15, 140, 20, "");
    let mut _btn7= RadioRoundButton::new(160, 50, 140, 20, "");
    let mut _btn8= RadioRoundButton::new(160, 85, 140, 20, "");
    let mut _btn9= RadioRoundButton::new(160, 120, 140, 20, "");
    let mut _btn10= RadioRoundButton::new(160, 155, 140, 20, "");
    grp.end();

    let mut _btn = Button::new(300, 15, 50, 25, "実行");
    _btn.set_callback(move |_| {
        let _onoff1 = _btn1.value();let _onoff2 = _btn2.value();let _onoff3 = _btn3.value();
        let _onoff4 = _btn4.value();let _onoff5 = _btn5.value();let _onoff6 = _btn6.value();
        let _onoff7 = _btn7.value();let _onoff8 = _btn8.value();let _onoff9 = _btn9.value();
        let _onoff10 = _btn10.value();

        if _onoff1 == true{
            println!("onoff1");
            pythonmodule();
        }
    });

    window.end();
    window.show();
    app.run().unwrap();
}
[dependencies.pyo3]
version = "0.16.5"
features = ["auto-initialize"]

参考サイト

[Python]333 pngファイルを単色で塗りつぶす / Pillow

[M1 Mac, Big Sur 11.6.7, Python 3.10.4]

単色アイコンの色を変えるために関数を作成しました。

これで単色であれば一々Adobe XDを立ち上げアイコンを作らなくて済みます。

for文の内容を変えれば特定の色だけ変更することも可能です。

Pythonならスケッチ感覚でコーディングできるので本当に楽ですね。

from PIL import Image
import numpy as np

def color_convert(path,red,green,blue,name="color"):
    # pngファイルの色情報を読み込む [red, green, blue, alpha]
    img_array = np.array(Image.open(path))

    # 全画素のRGB値を変更
    for row in img_array:
        for pixel in row:
            np.put(pixel,0,red)
            np.put(pixel,1,green)
            np.put(pixel,2,blue)
                
    img = Image.fromarray(img_array)

    new_filename0 = path.split("/")[:-1]
    new_filename = '/'.join(new_filename0) + "/" + name + ".png"
    img.save(new_filename)
        
    return 0

if __name__ == '__main__':
    path = "umemurasaki.png"
    color_convert(path,173,255,47,"greenyellow")

[Obj-C] 16 GUIアプリ : MakefileをCMakeLists.txtへ移植

[M1 Mac, Big Sur 11.6.5, no Xcode]

MakefileをCMakeLists.txtへ移植しました。

CMakeが作成したMakefileがどういったコマンドを実行しているのか分からないので気が進まなかったのですが、非XCode環境で開発を進めるにはどうも避けられないためやむなく着手しました。

自製Makefileでは認識していた -lpython3.10がリンク時に見つからないというエラーへの対策でだいぶ時間を取られました。出力をよく読むとビルドの時にはちゃんと認識していたので、そのライブラリパスをtarget_link_librariesのところに書いたらうまくいきました。CMakeは案外融通の効かないところがあるようです。

いちいちbuildディレクトリに潜るのは面倒なのでプロジェクトフォルダのルートからMakefileでCMakeを実行するというちょっとややこしいけど楽なやり方で進めています。make allコマンド一発でCMakeを経てappファイルまで作ってくれます。

自製Makefileで作成したappファイルはボタン押下時に落ちてしまいましたが、今回のappファイルはクラッシュしません。これは全く期待していなかったのでうれしい限りです。

C++からわざわざObjective-Cへ移植したかいがありました。

ビルド時に-lpython3.10を認識しているが、リンク形成ではエラーになる。
cmake_minimum_required(VERSION 3.1)

# Project
Project(XlsxConvertor VERSION 1.0.0)
find_library(COREFOUNDATION CoreFoundation)
find_library(COCOA Cocoa)

# Info.plist
set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION})
set(MACOSX_BUNDLE_COPYRIGHT "Copyright (C) 2022")
set(MACOSX_BUNDLE_INFO_STRING "Convert tool for XLSX")

# XlsxConvertor
add_executable(${PROJECT_NAME}
    MACOSX_BUNDLE
    ./src/XlsxConvertor.m
    ./src/process.m
    ./include/process.h)

set(INCDIR ./include)
set(INCDIR ${INCDIR} /Library/Frameworks/Python.framework/Versions/3.10/include/python3.10)
include_directories(${INCDIR})

set(LIBDIR /Library/Frameworks/Python.framework/Versions/3.10/lib)
link_directories(${LIBDIR})

set(LIBS dl)
set(LIBS ${LIBS} /Library/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib)

target_link_libraries(${PROJECT_NAME}
    ${COREFOUNDATION}
    ${COCOA}
    ${LIBS})
# CMakeを経てappファイル作成(アイコン登録含む)

TARGET = XlsxConvertor

.PHONY : all
all:
	rm -rf build/*
	cd /projects/XlsxConvertor09/build && cmake .. && make
	mkdir ./build/$(TARGET).app/Contents/Resources
	cp ./images/XlsxConvertor.icns ./build/$(TARGET).app/Contents/Resources
	plutil -replace 'CFBundleIconFile' -string "XlsxConvertor.icns" ./build/$(TARGET).app/Contents/Info.plist

[Obj-C] 15 GUIアプリ : CSVファイルをxlsxファイルやリストに変換

[M1 Mac, Big Sur 11.6.5, no Xcode]

Pythonのライブラリであるpandasやcsvを使って、CSVファイルをxlsxファイルやリストに変換しました。リストへの変換はちょっとした小技が必要です。

これで基本的な機能の実装は完了しました。あとはファイルのドラッグ&ドロップや例外処理について書いていきます。

<該当箇所のみ>

import openpyxl, csv

def csv_to_xlsx(path):
    # xlsxファイル名作成
    xlsx_path = path.split('.')[0] + '.xlsx'
    
    df = pd.read_csv(path)
    df.to_excel(xlsx_path, encoding='utf-8', index = False, header = False)

    return "csv_to_xlsx sccess"

def csv_to_list(path):
    # csvファイルを読み込みリスト化
    with open(path, encoding='utf-8-sig') as f:
        reader = csv.reader(f)
        l = [row for row in reader]

    # ネストになっているため平滑化
    csv_list = [e for ele in l for e in ele]
        
    return str(csv_list)

[Obj-C] 14 GUIアプリ : NumPyでリストをcsvファイル化

[M1 Mac, Big Sur 11.6.5, no Xcode]

PythonのライブラリNumPyでリストをcsvファイル化できるようにしました。

様々な方法がありますが、入れ子になったリストに対応できるNumPyを選択しました。

コードは以下の通りです。

<該当箇所のみ>
#include <Cocoa/Cocoa.h>
#include "process.h"

NSString* result;
NSString* path;
NSString* list;
Convert* convert;

- (IBAction) OnButton1Click:(id)sender {
	onoff_XlsxToList = radioButton_a1.state; 
	onoff_XlsxToCsv = radioButton_a2.state; 
	onoff_ListToXlsx = radioButton_b1.state; 
	onoff_ListToCsv = radioButton_b2.state; 
	onoff_CsvToXlsx = radioButton_c1.state; 
	onoff_CsvToList = radioButton_c2.state;

	if (radioButton_a1.state == 1){
		rbtn_num = 1;
	} else if (radioButton_a2.state == 1){
		rbtn_num = 2;
	} else if (radioButton_b1.state == 1){
		rbtn_num = 3;
	} else if (radioButton_b2.state == 1){
		rbtn_num = 4;
	} else if (radioButton_c1.state == 1){
		rbtn_num = 5;
	} else {
		rbtn_num = 6;
	}

	NSLog(@"%d",rbtn_num);

	switch (rbtn_num){
	case 1:
	case 2:
	case 5:
	case 6:
		path = [textBox1 stringValue];
		convert = [[Convert alloc] init];
		result = [convert ConvertFunc:path number:rbtn_num];
		[textview setString:result];
		break;
	case 3:
	case 4:
		list = [textBox2 stringValue];
		convert = [[Convert alloc] init];
		result = [convert ConvertFunc:list number:rbtn_num];
		[textview setString:result];
		break;
	}
		
}
<該当箇所のみ>

import numpy as np

def list_to_csv(list):
    home = os.path.expanduser('~')
    file = home + '/Desktop/ltoc.csv'
    
    new_list = eval(list)
    np.savetxt(file, new_list, delimiter =",",fmt ='% s')
    
    return "list_to_csv success"

[Obj-C] 13 GUIアプリ : リストをxlsxファイル化

[M1 Mac, Big Sur 11.6.5, no Xcode]

Pythonのライブラリopenpyxlを使って、リストをxlsxファイルに変換できるようにしました。デスクトップにtest.xlsxとして作成されます。

コードは以下の通りです。

#include <Cocoa/Cocoa.h>
#include "process.h"
#include </Library/Frameworks/Python.framework/Versions/3.10/include/python3.10/Python.h>

@implementation Convert

- (NSString *)ConvertFunc:(NSString *)path number:(int)num {
    switch (num) {
    case 1:{
        Py_Initialize();
        // pyファイルの指定
        PyObject* myModuleString = PyUnicode_FromString((char*)"xlsx_convert");

        // pyファイルのモジュール化
        PyObject* myModule = PyImport_Import(myModuleString);

        // pyファイル内の関数を指定
        PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"xlsx_to_list");

        // 関数の引数を設定
        PyObject* args = PyTuple_Pack(1,PyUnicode_FromString((char *) [path UTF8String]));

        // 関数を実行し戻り値をPyObjectとして取得
        PyObject* myResult = PyObject_CallObject(myFunction,args);

        // PyObjectをconst char*に変換
        const char* result = PyUnicode_AsUTF8(myResult);
        NSString* result_ns = [NSString stringWithCString: result encoding:NSUTF8StringEncoding];

        NSLog(@"%@",result_ns);

        return result_ns;
        Py_FinalizeEx();
        break;
    }
    case 2:{
        Py_Initialize();

        PyObject* myModuleString = PyUnicode_FromString((char*)"xlsx_convert");
        PyObject* myModule = PyImport_Import(myModuleString);
        PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"xlsx_to_csv");
        PyObject* args = PyTuple_Pack(1,PyUnicode_FromString((char *) [path UTF8String]));
        PyObject* myResult = PyObject_CallObject(myFunction,args);
        const char* result = PyUnicode_AsUTF8(myResult);
        NSString* result_ns = [NSString stringWithCString: result encoding:NSUTF8StringEncoding];

        return result_ns;
        Py_FinalizeEx();
        break;
    }           
    case 3:{
        Py_Initialize();

        PyObject* myModuleString = PyUnicode_FromString((char*)"xlsx_convert");
        PyObject* myModule = PyImport_Import(myModuleString);
        PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"list_to_xlsx");
        PyObject* args = PyTuple_Pack(1,PyUnicode_FromString((char *) [path UTF8String]));
        PyObject* myResult = PyObject_CallObject(myFunction,args);
        const char* result = PyUnicode_AsUTF8(myResult);
        NSString* result_ns = [NSString stringWithCString: result encoding:NSUTF8StringEncoding];

        return result_ns;
        Py_FinalizeEx();
        break;
    }
    case 4:
        return @"case 4";
        break;
    case 5:
        return @"case 5";
        break;
    case 6:
        return @"case 6";
        break;
    default:
        return @"default";
        break;
    }

}
@end
import openpyxl, os
import pandas as pd

def xlsx_to_list(path):
    wb = openpyxl.load_workbook(path)
    ws = wb.worksheets[0]

    color_name = []
    color_code = []
    for cell in ws['A']:
        color_name.append(cell.value)
        color_code.append(cell.fill.fgColor.rgb)
        
    return str(color_name)

def xlsx_to_csv(path):
    # csvファイル名作成
    csv_path = path.split('.')[0] + '.csv'
    
    wb = openpyxl.load_workbook(path)
    ws = wb.worksheets[0]
    df = pd.DataFrame(ws.values)
    
    df.to_csv(csv_path, index = False, header = None)

    return "xlsx_to_csv success"
    
def list_to_xlsx(list):
    home = os.path.expanduser('~')
    file = home + '/Desktop/test.xlsx'
    
    wb = openpyxl.Workbook()
    ws = wb.worksheets[0]

    # 引数の文字列をリスト化
    new_list = eval(list)
    
    num = 0
    for i in range(1,1 +1):
        for j in range(1,len(new_list) +1):
            ws.cell(row = j, column = i).value = new_list[num]
            num = num + 1

    wb.save(file)
    
    return "list_to_xlsx success"

[Obj-C] 12 GUIアプリ : pandasでxlsx to csv

[M1 Mac, Big Sur 11.6.5, no Xcode]

Pythonのライブラリpandasとopenpyxlを使ってExcelファイルをCSVファイルに変換しました。

コードは以下の通りです。

#include <Cocoa/Cocoa.h>
#include "process.h"
#include </Library/Frameworks/Python.framework/Versions/3.10/include/python3.10/Python.h>

@implementation Convert

- (NSString *)ConvertFunc:(NSString *)path number:(int)num {
    switch (num) {
    case 1:{
        Py_Initialize();
        // pyファイルの指定
        PyObject* myModuleString = PyUnicode_FromString((char*)"xlsx_convert");

        // pyファイルのモジュール化
        PyObject* myModule = PyImport_Import(myModuleString);

        // pyファイル内の関数を指定
        PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"xlsx_to_list");

        // 関数の引数を設定
        PyObject* args = PyTuple_Pack(1,PyUnicode_FromString((char *) [path UTF8String]));

        // 関数を実行し戻り値をPyObjectとして取得
        PyObject* myResult = PyObject_CallObject(myFunction,args);

        // PyObjectをconst char*に変換
        const char* result = PyUnicode_AsUTF8(myResult);
        NSString* result_ns = [NSString stringWithCString: result encoding:NSUTF8StringEncoding];

        NSLog(@"%@",result_ns);

        return result_ns;
        Py_FinalizeEx();
        break;
    }
    case 2:{
        Py_Initialize();

        PyObject* myModuleString = PyUnicode_FromString((char*)"xlsx_convert");
        PyObject* myModule = PyImport_Import(myModuleString);
        PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"xlsx_to_csv");
        PyObject* args = PyTuple_Pack(1,PyUnicode_FromString((char *) [path UTF8String]));
        PyObject* myResult = PyObject_CallObject(myFunction,args);
        const char* result = PyUnicode_AsUTF8(myResult);
        NSString* result_ns = [NSString stringWithCString: result encoding:NSUTF8StringEncoding];

        return result_ns;
        Py_FinalizeEx();
        break;
    }      
    case 3:
        return @"case 3";
        break;
    case 4:
        return @"case 4";
        break;
    case 5:
        return @"case 5";
        break;
    case 6:
        return @"case 6";
        break;
    default:
        return @"default";
        break;
    }

}
@end
import openpyxl
import pandas as pd

def xlsx_to_list(path):
    wb = openpyxl.load_workbook(path)
    ws = wb.worksheets[0]

    color_name = []
    color_code = []
    for cell in ws['A']:
        color_name.append(cell.value)
        color_code.append(cell.fill.fgColor.rgb)
        
    return str(color_name)

def xlsx_to_csv(path):
    # csvファイル名作成
    csv_path = path.split('.')[0] + '.csv'
    
    wb = openpyxl.load_workbook(path)
    ws = wb.worksheets[0]
    df = pd.DataFrame(ws.values)
    
    df.to_csv(csv_path, index = False, header = None)

    return "xlsx_to_csv success"

[Obj-C] 08 GUIアプリ : Python/C APIの使用

[M1 Mac, Big Sur 11.6.5, no Xcode]

C++(FLTK)からObjective-Cへの移植がほぼ完了しました。実行ファイル作成までたどり着きました。

Excelファイルを読み込み、A列のセル値をリスト化して出力する機能を実装しています。使用しているライブラリはopenpyxlです。

あてにしていたPyObjCはどうやらPythonからCocoaなどのフレームワークやライブラリを利用するという目的で作られたものであり、Python/C APIをアレンジしたものではないことが分かってきました。冷静に考えればApple系開発者がそこまでするメリットはあまりないですね。

せっかくなのでPython/C APIで実装しましたが、appファイルを作成して実行してもC++と同様に落ちてしまうでしょう。試しにC++で作成したappファイル内にある実行ファイルを入れ替えるとNGでした。

Objective-Cは細かいところになると機能の少なさを露呈するものの外観のまとまりはいいので、コンソール付きのCocoaアプリとして残りの機能も実装しようと思います。

@interface Xlsx : NSObject

- (NSString *)XlsxToList:(NSString *)path;

@end
#include <Cocoa/Cocoa.h>
#include "process.h"
#include </Library/Frameworks/Python.framework/Versions/3.10/include/python3.10/Python.h>

@implementation Xlsx

- (NSString *)XlsxToList:(NSString *)path{

    Py_Initialize();

    // pyファイルの指定
    PyObject* myModuleString = PyUnicode_FromString((char*)"test");

    // pyファイルのモジュール化
    PyObject* myModule = PyImport_Import(myModuleString);

    // pyファイル内の関数を指定
    PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"xlsx_to_list");

    // 関数の引数を設定
    PyObject* args = PyTuple_Pack(1,PyUnicode_FromString((char *) [path UTF8String]));

    // 関数を実行し戻り値をPyObjectとして取得
    PyObject* myResult = PyObject_CallObject(myFunction,args);

    // PyObjectをconst char*へ変換
    const char* result = PyUnicode_AsUTF8(myResult);

    // NSStringへ変換
    NSString* result_ns = [NSString stringWithCString: result encoding:NSUTF8StringEncoding];

    return result_ns;

    Py_FinalizeEx();    

}
@end
#include <Cocoa/Cocoa.h>
#include "process.h"

<該当箇所のみ>

- (IBAction) OnButton1Click:(id)sender {
	NSString* path = [textBox1 stringValue];

	Xlsx* test = [[Xlsx alloc] init];
	NSString* result = [test XlsxToList:path];
	[textview setString:result];
}

[C++] 63 FLTK : xlsx変換アプリ / appファイルの不具合3

[M1 Mac, Big Sur 11.6.5, Python 3.10.4]

デバッグ用コードを走らせ、実行内容をチェックしました。

sysPath 6個に対してGetPath 3個となっており、pathを追加できていないだけでなく数も合っていません。

つまりsys.pathとPython/C APIのmodule search pathは一致しないということが判明しました。集合で表現するとmodule search path ⊂ sys.pathになります。

module search pathの設定がPy_SetPath()やPYTHONPATH以外の方法でできないとなると、これ以上の追究は厳しくなります。

#define PY_SSIZE_T_CLEAN
#include "process.h"
#include </Library/Frameworks/Python.framework/Versions/3.10/include/python3.10/Python.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>

#define PATH L"/Python/library/python_module:/Library/Frameworks/Python.framework/Versions/3.10/lib/python310.zip:/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10:/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/lib-dynload"

using std::string;

string XlsxToList(const char* path) {
    // Py_SetPath(PATH);

    Py_Initialize();
	
	// PyObject* sysPath = PySys_GetObject("path");
	PyObject* sys = PyImport_ImportModule( "sys" );
	PyObject* sysPath = PyObject_GetAttrString( sys, "path" );
	std::cout << "追加前path数 " << PyList_Size(sysPath) << std::endl;
	std::cout << "PyObject* sysPath通過" << std::endl;

	PyObject* module_path = PyUnicode_FromString("/Python/library/python_module");
	std::cout << "PyObject* module_path通過" << std::endl;
	
	int append_bool = PyList_Append(sysPath, module_path);
	std::cout << "PyList_Append通過" << std::endl;
	std::cout << append_bool << std::endl;

	std::cout << "追加後path数 " << PyList_Size(sysPath) << std::endl;

	// 	module search pathを出力し、パスの内容と個数を確認
	std::wcout << Py_GetPath() << std::endl;

    // pyファイルのモジュール化
    PyObject* myModule = PyImport_ImportModule((char*)"test");
	std::cout << "myModule通過" << std::endl;

	const char* function = "xlsx_to_list";
	int attr_bool = PyObject_HasAttrString(myModule,function);
	std::cout << "attr_bool通過" << std::endl;
	std::cout << attr_bool << std::endl;
    
    // pyファイル内の関数を指定 ここでエラー発生
    PyObject* myFunction = PyObject_GetAttrString(myModule,function);
    
    // 関数の引数を設定
    PyObject* args = PyTuple_Pack(1,PyUnicode_FromString(path));
    
    // 関数を実行し戻り値をPyObjectとして取得
    PyObject* myResult = PyObject_CallObject(myFunction,args);
    
    
    // PyObjectをconst char*に変換
    const char* result = PyUnicode_AsUTF8(myResult);

    std::cout << result << std::endl;

    return result;

    Py_FinalizeEx();
    
}
--------------------------------------------------
出力
--------------------------------------------------
追加前path数 5
PyObject* sysPath通過
PyObject* module_path通過
PyList_Append通過
0
追加後path数 6
/Library/Frameworks/Python.framework/Versions/3.10/lib/python310.zip:/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10:/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/lib-dynload
myModule通過
attr_bool通過
0
Segmentation fault: 11

[C++] 62 FLTK : xlsx変換アプリ / appファイルの不具合2

[M1 Mac, Big Sur 11.6.5, Python 3.10.4]

sys.pathをPy_SetPathで強制的に書き換えたところ、実行ファイルの方も動かなくなりました。力技が過ぎたようです。

sys.pathの文字列が全く同じでもメモリアドレスが変わったためにEXC_BAD_ACCESSになっているのでしょうか。

appファイルについてはこれで完全にお手上げとなりました。実行ファイルでアプリを完成させる目処は立っていますが、言語を変更してObjective-Cで同じアプリを作るかどうか迷っています。

#define PY_SSIZE_T_CLEAN
#include "process.h"
#include </Library/Frameworks/Python.framework/Versions/3.10/include/python3.10/Python.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>

#define PATH L"/Python/library/python_module:/Library/Frameworks/Python.framework/Versions/3.10/lib/python310.zip:/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10:/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/lib-dynload"

using std::string;

string XlsxToList(const char* path) {
    
    // sys.pathの書き換え
    Py_SetPath(PATH);

    Py_Initialize();

    // sys.pathの確認
    std::wcout << Py_GetPath() << std::endl;

    // pyファイルのモジュール化
    PyObject* myModule = PyImport_ImportModule((char*)"test");
    
    // pyファイル内の関数を指定 今度は実行ファイルにてここでエラー発生
    const char* function = "xlsx_to_list";
    PyObject* myFunction = PyObject_GetAttrString(myModule,function);
    
    // 関数の引数を設定
    PyObject* args = PyTuple_Pack(1,PyUnicode_FromString(path));
    
    // 関数を実行し戻り値をPyObjectとして取得
    PyObject* myResult = PyObject_CallObject(myFunction,args);
    
    // PyObjectをconst char*に変換
    const char* result = PyUnicode_AsUTF8(myResult);

    std::cout << result << std::endl;

    return result;

    Py_FinalizeEx();
    
}