便利な小ネタ集（Python編）

# はじめに
ソフト作るときに地味にストレスなのが

- この程度の機能の実装に時間をかけたくない
- メモっていたけどどこに置いたか忘れた（探すのめんど）

です。

これらを解消したいので何度も使いそうなプログラム部品を記録しておきます。
Python編です。

# 部品たち
それでは早速便利な部品たちを載せていきます。
## モジュールログをファイルに出力
```python
### ログ #################
import os
import logging
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# loggerのフォーマット、出力先ファイルを定義
log_dir = fr"./log/"
os.makedirs(log_dir, exist_ok=True)
formatter = logging.Formatter('%(asctime)s - %(levelname)s:%(name)s - %(message)s')
rh = logging.handlers.RotatingFileHandler(
    f'{log_dir}{__name__}.log',
    maxBytes=1024*1024*10,
    backupCount=100,
    )
rh.setFormatter(formatter)
# loggerのフォーマット、出力先ファイルを設定
logger.addHandler(rh)
##########################
```

## マルチプロセス（並列処理）でも使えるモジュールログ
別のプロセスから同じモジュールを使った場合も、同じファイルにログ出力が出来るので便利。

```init_logger()```の引数は
- ```parent_name```には大元のLoggerの名前を、
- ```process_info```には派生したプロセスの名前（自由につけて良い）

を渡す。

```python
### ログ #################
import logging
module_logger = None
module_process_info = ""

# ロガー初期化
def init_logger(parent_name: str, process_info:str):
    global module_logger
    global module_process_info

    module_logger = logging.getLogger(f'{parent_name}.{__name__}')
    module_process_info = process_info
    log_info(f"Created module_logger({__name__})")

# デバッグログ
def log_debug(message: str):
    global module_logger
    global module_process_info

    if module_logger is not None:
        module_logger.debug(f"<{module_process_info}>{message}")
    print(f"[{module_process_info}:DEBUG]{message}")

# ログ
def log_info(message: str):
    global module_logger
    global module_process_info

    if module_logger is not None:
        module_logger.info(f"<{module_process_info}>{message}")
    print(f"[{module_process_info}:INFO]{message}")

# エラーログ
def log_error(message: str):
    global module_logger
    global module_process_info

    if module_logger is not None:
        module_logger.error(f"<{module_process_info}>{message}")
    print(f"[{module_process_info}:ERROR]{message}")
##########################
```

## jsonデータの読み書き(バリデーションチェック付き）
バリデーションチェックのためのjsonスキーマを定義して、チェックする。
```"required"```が肝。必須項目を指定する。
```python
import json
import jsonschema

# JSONスキーマの定義(中身は適宜変えてくださいね)
schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "number"},
        "email": {"type": "string", "format": "email"},
        "address": {
            "type": "object",
            "properties": {
            "city": {"type": "string"},
            "state": {"type": "string"},
            "zip": {"type": "string"}
            },
            "required": ["city", "state"]
        },
        "items": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "MinX": {"type": "number"},
                    "MaxX": {"type": "number"},
                    "MinY": {"type": "number"},
                    "MaxY": {"type": "number"},
                    "MinZ": {"type": "number"},
                    "MaxZ": {"type": "number"}
                }
            }
        }
    },
    "required": ["name", "age", "address", "items"]
}

#　JSONファイル読み込み
def load_settings(json_path:str):
    try:
        with open(json_path, "r", encoding='utf-8_sig') as file:
            data = json.load(file)
            for key in data.keys():
                print(f"{key} : {data[key]}")
            
            try:
                # JSONデータのバリデーションチェック
                jsonschema.validate(data, schema)
                print("Valid JSON")
                return data
            except jsonschema.ValidationError as e:
                print(f"Invalid JSON:{e}")
                return None
    except Exception as ex:
        print(f"Failed to load_settings(): {ex}")
        return None
```

# 最後に
まだまだ少ないけど、どんどん追加していきます。

どこかで誰かの役に立ってくれればいいな。
（主に将来の自分）

zennでも活動してますので、応援よろしくお願いします。

https://zenn.dev/hiyokotti