入力フォルダーが変わるたびにコードを書き換えるなら、設定をファイルへ分ける方法があります。ただし、値を外へ出すだけでは、空欄や別のパスを読み込む失敗までは防げません。
読み込んだ設定を検査してから、業務データの処理を始めます。この例では、入力先、出力先、文字コードをJSONで指定し、コードのある場所を基準に解決します。
JSONへ出す値を決める
次をconfig.jsonとしてUTF-8で保存します。フォルダーとファイル名は架空の構成です。
{
"input": "data/sales.csv",
"output": "results/summary.csv",
"encoding": "utf-8-sig"
}
JSONの文字列は二重引用符で囲みます。末尾の余分なカンマやコメントは、この形式では使えません。Windowsのパスを書く場合は、バックスラッシュのエスケープに気を付けるか、この例のように区切りをスラッシュで書けます。
パスワードやAPIキーを、配布する設定例へ入れる必要はありません。誰が変更する値なのか、共有してよい内容かを分けます。
スクリプトの場所を基準に読む
次をcheck_config.pyとしてconfig.jsonと同じフォルダーへ置きます。dataフォルダーには確認用のsales.csvを用意します。内容はこのコードでは読みません。
import json
from pathlib import Path
base = Path(__file__).resolve().parent
with (base / "config.json").open(encoding="utf-8") as f:
config = json.load(f)
required = {"input", "output", "encoding"}
if not isinstance(config, dict) or set(config) != required:
raise ValueError("設定項目はinput、output、encodingの三つです")
if any(not isinstance(config[key], str) or not config[key].strip() for key in required):
raise ValueError("設定値は空でない文字列にしてください")
if config["encoding"] not in {"utf-8", "utf-8-sig", "cp932"}:
raise ValueError("この例で対応しない文字コードです")
input_path = (base / config["input"]).resolve()
output_path = (base / config["output"]).resolve()
if input_path == output_path:
raise ValueError("入力と出力が同じ場所です")
if not input_path.is_file():
raise FileNotFoundError(input_path)
print("入力:", input_path)
print("出力:", output_path)
print("文字コード:", config["encoding"])
このコードが確認するのは設定の形式と、入力ファイルの存在までです。入力の内容、読み取り権限、出力先への書き込み、CSVの集計は検証していません。後の処理でも、実際に開く段階の例外を扱います。
実行場所と設定の場所を混同しない
相対パスをそのままopenへ渡すと、通常は現在の作業フォルダーが基準になります。ターミナルと定期実行でその場所が違えば、同じ文字列でも別のファイルを指す場合があります。
この例はスクリプトのフォルダーを基準にする設計です。別の場所の設定を引数で渡したいツールなら、設定ファイルの場所を基準にするか、作業フォルダーを基準にするかを決めてREADMEへ書きます。どれが正しいかは、配布するツールの仕様によります。
設定を増やすときの確認
初期値を使える項目と、未指定なら止める項目を分けます。出力先や送信先のように間違えると影響が大きい値を、分からないまま推測して埋めないようにします。
項目名を変えると、古い設定が読めなくなる場合があります。配布時には設定例と説明をそろえ、必要なら設定形式のバージョンを持たせます。正常な設定だけでなく、項目不足、空欄、型の違い、入力と出力が同じ場合を試すと、変更時の確認に使えます。
関連する作業
JSONの基本操作と、ツールを配布する前の確認も合わせて読むと設定の役割が整理できます。
