ボールを蹴りたいシステムエンジニア

ボール蹴りが大好きなシステムエンジニア、ボールを蹴る時間確保の為に時間がある時には勉強する。

pythonでExcelをマークダウン形式に変換

ライブラリMarkItDownをインストール

pip install markitdown -q
pip install markitdown[xlsx]

pythonコード

#!/usr/bin/env python3
"""
エクセルファイルをマークダウン形式に変換するスクリプト

使用方法:
python excel_to_markdown.py <エクセルファイルパス> [出力ファイルパス]

例:
python excel_to_markdown.py data.xlsx
python excel_to_markdown.py data.xlsx output.md
"""

import argparse
import os
import sys
from pathlib import Path
from typing import Optional

try:
from markitdown import MarkItDown
except ImportError:
print("エラー: markitdownライブラリがインストールされていません。")
print("以下のコマンドでインストールしてください:")
print("pip install markitdown")
sys.exit(1)


class ExcelToMarkdownConverter:
"""エクセルファイルをマークダウンに変換するクラス"""

def __init__(self):
"""初期化"""
self.converter = MarkItDown()

def convert_file(self, input_path: str, output_path: Optional[str] = None) -> str:
"""
エクセルファイルをマークダウンに変換

Args:
input_path (str): 入力エクセルファイルのパス
output_path (Optional[str]): 出力マークダウンファイルのパス(省略時は自動生成)

Returns:
str: 出力ファイルのパス

Raises:
FileNotFoundError: 入力ファイルが存在しない場合
ValueError: ファイル形式がサポートされていない場合
"""
# 入力ファイルの存在確認
if not os.path.exists(input_path):
raise FileNotFoundError(f"入力ファイルが見つかりません: {input_path}")

# ファイル拡張子の確認
input_ext = Path(input_path).suffix.lower()
if input_ext not in ['.xlsx', '.xls', '.xlsm']:
raise ValueError(f"サポートされていないファイル形式です: {input_ext}")

# 出力ファイルパスの生成
if output_path is None:
input_path_obj = Path(input_path)
output_path = input_path_obj.with_suffix('.md')

try:
# ファイル変換の実行
print(f"変換中: {input_path} -> {output_path}")
result = self.converter.convert(input_path)

# マークダウンファイルの保存
with open(output_path, 'w', encoding='utf-8') as f:
f.write(result.text_content)

print(f"変換完了: {output_path}")
return str(output_path)

except Exception as e:
raise RuntimeError(f"変換中にエラーが発生しました: {str(e)}") from e


def main():
"""メイン関数"""
parser = argparse.ArgumentParser(
description="エクセルファイルをマークダウン形式に変換します",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
使用例:
python excel_to_markdown.py data.xlsx
python excel_to_markdown.py data.xlsx output.md
python excel_to_markdown.py /path/to/data.xlsx /path/to/output.md
"""
)

parser.add_argument(
'input_file',
help='変換するエクセルファイルのパス'
)

parser.add_argument(
'output_file',
nargs='?',
help='出力するマークダウンファイルのパス(省略時は自動生成)'
)

parser.add_argument(
'--version',
action='version',
version='Excel to Markdown Converter 1.0.0'
)

args = parser.parse_args()

try:
# コンバーターの初期化
converter = ExcelToMarkdownConverter()

# ファイル変換の実行
output_path = converter.convert_file(args.input_file, args.output_file)

print(f"✅ 変換が正常に完了しました: {output_path}")

except FileNotFoundError as e:
print(f"❌ ファイルエラー: {e}")
sys.exit(1)

except ValueError as e:
print(f"❌ 値エラー: {e}")
sys.exit(1)

except RuntimeError as e:
print(f"❌ 変換エラー: {e}")
sys.exit(1)
except (OSError, IOError) as e:
print(f"❌ ファイル操作エラー: {e}")
sys.exit(1)


if __name__ == "__main__":
main()

ReactとViteでの@によるパス指定について

事象

ViteでReactを読み込んでるindex.htmlにアクセスしたところ以下のエラーが出た。

[plugin:vite:import-analysis] Failed to resolve import "@/pages/HogeTest" from "src/App.tsx". Does the file exist?

index.html

<script type="module" src="/src/index.tsx">

index.tsx

import App from './App.tsx'

App.tss

import MasterManagement from '@/pages/HogeTest';
import '@/styles/globals.css';

原因

Viteはtsconfig.jsonのパス設定を自動的に読み取らないため、@/pages/HogeTestのようなパスエイリアスを解決できないらしい。

対策

vite.config.tsにVite用のパスエイリアス設定を追加。
Viteがパスエイリアスを理解できるようになる。
TypeScriptの設定(tsconfig.json)とViteの設定が一致する。

resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},

Reactの@について

この@は、通常プロジェクトのsrcディレクトリを指すように設定されている。
tsconfig.json

"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@/components/*": ["src/components/*"],
"@/pages/*": ["src/pages/*"],
"@/hooks/*": ["src/hooks/*"],
"@/services/*": ["src/services/*"],
"@/types/*": ["src/types/*"],
"@/utils/*": ["src/utils/*"],
"@/styles/*": ["src/styles/*"]
}

Azure Static Web Apps でデプロイ

追記
こちらの公式がよいかも
クイック スタート: 静的 Web アプリを初めてビルドする | Microsoft Learn


以下ページ参考。
Azure Static Web Apps で静的ページをDeployするまで #HTML - Qiita

今回はReactアプリを配置するので、ビルドのプリセットでReactを選択。
分岐というのは、ここで選択したブランチがpushされたらworkflowが実行されるらしい。
アプリケーションパスは存在してないとgithubアクションでエラーなるので注意。

無料プラン(F1)のAzure App Serviceを作成しようとしたらエラー

事象

無料プラン(F1)のAzure App Serviceを作成しようとしたら以下のエラー
※一部伏字

{"code":"InvalidTemplateDeployment","details":[{"code":"ValidationForResourceFailed","message":"Validation failed for a resource. Check 'Error.Details[0]' for more information.","details":[{"code":"SubscriptionIsOverQuotaForSku","message":"Quota exceeded for : 0 VMs allowed, 1 VMs requested.. Try selecting different region or SKU."}]}],"message":"テンプレート デプロイ 'Microsoft.Web-WebApp-Portal-49ca1dda-9961' は、検証プロシージャによって無効とされました。追跡 ID は '*****' です。詳細については、内部エラーを参照してください。"}

「このサブスクリプションでは対象のSKUで使える VM が 0 台に制限されているのに、1 台必要なリソースを作ろうとした」 という意味。
つまり「この地域やSKUでは VM を消費する App Service プランが使えない」状態。
このエラーは「サブスクリプションクォータ制限」で止められており、リージョン変更かプラン(SKU)変更で解決できる可能性が高い。

対策

元々、リージョンを「Japan EAST」にしていたが、「Japan WEST」に変更したら作成できた。


ChatGPTによると、無料枠での App Service F1 (Free) も、リージョンによってはキャパシティ不足で作れない。
選んだリージョンで 空き容量がない 場合も同じエラーになる。
とかあったけど。。

Cursor/VSCodeのDev Container環境でReactのデバッグ

  1. .vscodeディレクトリ作成してlaunch.jsonファイル作成

{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Chrome",
"request": "launch",
"type": "chrome",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/frontend/src"
}
]
}

  1. フロントエンド起動
  2. ブレークポイント設定
  3. VSCodeでF5

### 参考
qiita.com