01結果と一緒に、Python とライブラリの版を記録する確認済

同じコードでも、Python とライブラリの版が違うと結果が変わりうる。実行のたびに版・OS・仮想環境かどうかを JSON Lines に追記し、後で結果を再現するときの手がかりにする。

考え方と手順
  1. platform.python_version() と importlib.metadata.version() で、Python と使うライブラリの版を取る。
  2. sys.prefix != sys.base_prefix なら、仮想環境の中で動いている。
  3. 記録は out_runtime_log.jsonl に 1 行ずつ追記し、結果のファイルと同じ場所に置く。
  4. 入っていないライブラリは null として残し、例外で止めない。
  5. Azure Functions やノートブックでも同じ関数を呼び、手元の記録と比べる。
Python手元で動く
"""Record the Python runtime and package versions next to your results (JSON Lines)."""
import datetime
import importlib.metadata as md
import json
import platform
import sys

PACKAGES = ["pandas", "openpyxl", "python-docx", "azure-functions", "microsoft-agents-hosting-core"]


def runtime_record(packages):
    versions = {}
    for name in packages:
        try:
            versions[name] = md.version(name)
        except md.PackageNotFoundError:
            versions[name] = None
    return {
        "recorded_at": datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds"),
        "python": platform.python_version(),
        "implementation": platform.python_implementation(),
        "os": platform.platform(),
        "executable": sys.executable,
        "in_venv": sys.prefix != sys.base_prefix,
        "packages": versions,
    }


if __name__ == "__main__":
    rec = runtime_record(PACKAGES)
    with open("out_runtime_log.jsonl", "a", encoding="utf-8") as f:
        f.write(json.dumps(rec, ensure_ascii=False) + "\n")
    print("python", rec["python"], "| venv:", rec["in_venv"])
    for name, version in rec["packages"].items():
        print(f"  {name}: {version or 'not installed'}")
実行結果(2026-09-12)
python 3.12.10 | venv: True
  pandas: 3.0.5
  openpyxl: 3.1.5
  python-docx: 1.2.0
  azure-functions: 1.25.0
  microsoft-agents-hosting-core: 1.5.0
Copilot に書かせる指示の例

実行した Python の版、OS、仮想環境かどうか、指定したパッケージの版を JSON Lines のファイルに 1 行追記する Python の関数を書いて。標準ライブラリだけを使い、入っていないパッケージは null にして。

注意

記録には実行ファイルの場所が入り、ユーザー名を含むことがある。共有する前に確かめる。版が同じでも、OS やデータが違えば結果は変わりうる。

利用条件
標準ライブラリだけで動く(手元は Python 3.12.10)。
必要なもの
pandas 3.0.5, openpyxl 3.1.5, python-docx 1.2.0, azure-functions 1.25.0, microsoft-agents-hosting-core 1.5.0
試験
手元で実行して確認(2026-09-12、Python 3.12.10 (venv) / Windows 11、pandas 3.0.5、openpyxl 3.1.5、python-docx 1.2.0、azure-functions 1.25.0、microsoft-agents-hosting-core 1.5.0)
出典
Python documentation「venv — Creation of virtual environments」
確認日
2026-09-12(第 1 版)
出典の該当箇所
sys.prefix != sys.base_prefix to determine if the current interpreter is

02requirements.txt で固定した版と、入っている版の違いを洗い出す確認済

仮想環境で python -m pip freeze > requirements.txt とし、版を固定した一覧を版管理に入れる。別の環境で動かす前に、一覧の版と実際に入っている版を突き合わせ、違う行を表示する。

考え方と手順
  1. 開発した仮想環境で python -m pip freeze > requirements.txt を実行し、版管理に入れる。
  2. 別の環境では python -m pip install -r requirements.txt で同じ版を入れる。
  3. 動かす前に、このスクリプトで一覧の == の版と importlib.metadata の版を比べる。
  4. 違いがあれば MISMATCH と表示する。STRICT=1 のときは終了コードで止める。
  5. freeze と同じ形の一覧を out_freeze.txt に書き、実行の記録として残す。
Python手元で動く
"""Compare a pinned requirements file with the packages installed in the current environment."""
import importlib.metadata as md
import os
import re
import sys

REQ_FILE = os.environ.get("REQ_FILE", "samples/agents_requirements.txt")
PIN = re.compile(r"^([A-Za-z0-9._-]+)==([^\s;#]+)")


def read_pins(path):
    pins = {}
    with open(path, encoding="utf-8") as f:
        for line in f:
            m = PIN.match(line.strip())
            if m:
                pins[m.group(1)] = m.group(2)
    return pins


def compare(pins):
    rows = []
    for name, wanted in sorted(pins.items()):
        try:
            have = md.version(name)
        except md.PackageNotFoundError:
            have = None
        rows.append((name, wanted, have, "ok" if have == wanted else "MISMATCH"))
    return rows


def freeze_lines():
    """The same shape as `python -m pip freeze`, without starting another process."""
    return sorted(f"{d.metadata['Name']}=={d.version}" for d in md.distributions())


if __name__ == "__main__":
    rows = compare(read_pins(REQ_FILE))
    for name, wanted, have, state in rows:
        print(f"{name:<16} want {wanted:<8} have {str(have):<8} {state}")
    with open("out_freeze.txt", "w", encoding="utf-8") as f:
        f.write("\n".join(freeze_lines()) + "\n")
    bad = [r for r in rows if r[3] != "ok"]
    print("mismatches:", len(bad))
    sys.exit(1 if bad and os.environ.get("STRICT") == "1" else 0)
実行結果(2026-09-12)
azure-functions  want 1.25.0   have 1.25.0   ok
openpyxl         want 3.1.5    have 3.1.5    ok
pandas           want 3.0.5    have 3.0.5    ok
python-docx      want 1.2.0    have 1.2.0    ok
requests         want 2.0.0    have 2.34.2   MISMATCH
mismatches: 1
Copilot に書かせる指示の例

requirements.txt の == で固定した版と、今の環境に入っている版を比べて違いを表にする Python のスクリプトを書いて。subprocess は使わず importlib.metadata で版を読み、pip freeze と同じ形の一覧もファイルに書いて。

注意

freeze の一覧には、依存で入っただけのパッケージも並ぶ。Azure Functions は requirements.txt の依存を配置時の遠隔ビルドで入れる。Python の版が変わると、同じ版のパッケージが入らないことがある。

利用条件
標準ライブラリだけで動く(手元は Python 3.12.10)。
試験
手元で実行して確認(2026-09-12、Python 3.12.10 (venv) / Windows 11)
出典
Python documentation「12. Virtual Environments and Packages」
Microsoft Learn「Python developer reference for Azure Functions」
確認日
2026-09-12(第 1 版)
出典の該当箇所
The requirements.txt can then be committed to version control
python -m pip freeze > requirements.txt
python -m pip install -r requirements.txt
Python dependencies installed during publish when using remote build.

03Python in Excel の実行環境を =PY セルに表示し、手元の Python と比べる確認済

Python in Excel のコードは Microsoft のクラウドで動き、手元の Python の設定は反映されない。最初のシートに版を表示するセルを置き、手元の pandas で同じ集計を検算するときに、版の違いを確かめる。

考え方と手順
  1. 最初のワークシートに =PY セルを置き、sys.version と pandas・numpy の __version__ を表にして返す。
  2. xl("ledger[#All]", headers=True) で表を読み、行数も並べて、読んだ範囲を確かめる。
  3. 手元の Python では、版を記録するスクリプトで同じ項目を残す。
  4. 版が違えば、関数の既定の動きの違いで結果がずれることがある。検算の結果と一緒に両方の版を残す。
  5. Python in Excel からは外部の Web やファイルを読めない。必要なデータはブックの表に置く。
PythonMicrosoft のクラウドで動く
# =PY cell on the first sheet: show the runtime used for this workbook's Python results
import sys

import numpy as np
import pandas as pd

df = xl("ledger[#All]", headers=True)
pd.DataFrame({
    "item": ["python", "pandas", "numpy", "ledger rows"],
    "value": [sys.version.split()[0], pd.__version__, np.__version__, len(df)],
})
Copilot に書かせる指示の例

Python in Excel の =PY セルで、Python・pandas・numpy の版と、xl("ledger[#All]", headers=True) で読んだ表の行数を 2 列の DataFrame で返すコードを書いて。

注意

Python in Excel のコードはネットワークに出られず、使えるライブラリは Anaconda が提供する範囲に限られる。手元に入れたパッケージや設定は使えない。計算はクラウドの隔離されたコンテナーで行われる。

利用条件
Python in Excel が使えるライセンスと環境が要る(詳細は Excel × Python のページ)。
必要なもの
pandas 3.0.5
試験
xl() を見本データで代用して手元で実行(2026-09-12、Python 3.12.10 (venv) / Windows 11、pandas 3.0.5)
実践編
Excel ── Python による分析で質問に答えさせる
出典
Microsoft Support「Introduction to Python in Excel」
Microsoft Support「Data security and Python in Excel」
確認日
2026-09-12(第 1 版)
出典の該当箇所
Python in Excel calculations run in the Microsoft Cloud with a standard version of the Python language.
any customizations you've made to that Python installation won't be reflected in Python in Excel calculations.
The Python code doesn't have network access.

04Core Tools で関数を手元で動かし、設定は local.settings.json から読む確認済

Azure Functions の Python の関数は、仮想環境の中で Core Tools の func start により手元で起動できる。アプリ設定は local.settings.json の Values に置き、コードは os.getenv で読む。ホストを起動する前に、関数を直接呼んで確かめることもできる。

考え方と手順
  1. 仮想環境を作って有効にし、func init MyProjFolder --worker-runtime python --model V2 で雛形を作る。
  2. 設定値は local.settings.json の Values に置き、コードでは os.getenv("LEDGER_PATH", 既定値) で読む。
  3. このスクリプトを python で実行すると、Values を環境変数に写して関数を直接呼ぶ。
  4. 次に func start で起動し、表示された http://localhost:7071/api/... の URL に要求を送る。
  5. 手元では HTTP の認証が強制されない。キーの確認は Azure に置いてから行う。
Python手元で動く
"""function_app.py: settings come from app settings in Azure and from local.settings.json on your machine."""
import csv
import json
import os

import azure.functions as func

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)


@app.route(route="open_requests", methods=["GET"])
def open_requests(req: func.HttpRequest) -> func.HttpResponse:
    open_states = set(os.getenv("OPEN_STATES", "受付,確認中").split(","))
    with open(os.getenv("LEDGER_PATH", "ledger.csv"), encoding="utf-8-sig", newline="") as f:
        rows = [r for r in csv.DictReader(f) if r["状態"] in open_states]
    dept = req.params.get("dept")
    if dept:
        rows = [r for r in rows if r["依頼部署"] == dept]
    body = {"count": len(rows), "ids": [r["依頼ID"] for r in rows]}
    return func.HttpResponse(json.dumps(body, ensure_ascii=False), mimetype="application/json")


def load_local_settings(path):
    """Copy the Values section into os.environ; values already set in the environment win."""
    with open(path, encoding="utf-8") as f:
        values = json.load(f).get("Values", {})
    for name, value in values.items():
        os.environ.setdefault(name, str(value))
    return sorted(values)


if __name__ == "__main__":
    # Quick check without Core Tools (azure-functions >= 1.21.0). Use `func start` for the real host.
    print("settings:", load_local_settings(os.getenv("LOCAL_SETTINGS", "samples/agents_local.settings.json")))
    req = func.HttpRequest(method="GET", url="/api/open_requests", body=b"", params={"dept": "広報部"})
    resp = open_requests.build().get_user_function()(req)
    print(resp.status_code, resp.get_body().decode("utf-8"))
実行結果(2026-09-12)
settings: ['AzureWebJobsStorage', 'FUNCTIONS_WORKER_RUNTIME', 'LEDGER_PATH', 'OPEN_STATES']
200 {"count": 14, "ids": ["R-2026-002", "R-2026-003", "R-2026-007", "R-2026-008", "R-2026-010", "R-2026-011", "R-2026-019", "R-2026-022", "R-2026-023", "R-2026-025", "R-2026-026", "R-2026-028", "R-2026-029", "R-2026-038"]}
Copilot に書かせる指示の例

Azure Functions の Python v2 の関数で、設定を os.getenv で読むように直して。あわせて、local.settings.json の Values を環境変数に写してから関数を直接呼ぶ、手元確認用の __main__ も付けて。

注意

local.settings.json には接続文字列などの秘密が入りうるので、リモートのリポジトリに入れない。Values は配置のときに自動では Azure に送られない。関数の直接の呼び出しは、バインドやホストの設定を通らない。最後は func start で確かめる。

利用条件
Azure Functions Core Tools と azure-functions(直接の呼び出しは 1.21.0 以降)。手元では azure-functions 1.25.0 で確認。
必要なもの
azure-functions 1.25.0
試験
手元で実行して確認(2026-09-12、Python 3.12.10 (venv) / Windows 11、azure-functions 1.25.0)
出典
Microsoft Learn「Develop Azure Functions Locally by using Core Tools」
Microsoft Learn「Python developer reference for Azure Functions」
確認日
2026-09-12(第 1 版)
出典の該当箇所
For Python, you must run Core Tools commands in a virtual environment.
func init MyProjFolder --worker-runtime python --model V2
Access the variables directly in your code by using os.environ or os.getenv.
Because the local.settings.json may contain secrets, such as connection strings, you should never store it in a remote repository.
By default, local settings aren't migrated automatically when the project is published to Azure.
By default, authorization isn't enforced locally for HTTP endpoints.

05Functions のプランごとの時間の上限と Python の版を、配置の前に点検する確認済

Azure Functions は、プランによって関数の実行時間の上限が違い、HTTP の応答は 230 秒で打ち切られる。Python の版もプランで制約がある。host.json の functionTimeout と予定する版を、文書の表から写した値で点検する。

考え方と手順
  1. host.json の functionTimeout は [d.]hh:mm:ss の形で書く。-1 は上限なしを表す。
  2. Consumption プランは既定 5 分・最大 10 分、Flex Consumption・Premium・Dedicated は既定 30 分で上限なし(表の注記あり)。
  3. HTTP で起動する関数は、設定にかかわらず 230 秒以内に応答を返す。長い処理は受付だけを返す。
  4. Python の関数アプリは Linux だけで動く。一般提供の版は 3.10 から 3.14 までである。
  5. Linux の Consumption プランは Python 3.12 が最後で、Consumption プランでは Python の版を変更できない。
  6. 表の値は変わるので、スクリプトの定数に確認した日を書き、配置の前に文書を見直す。
Python手元で動く
"""Check host.json functionTimeout and the target Python version against hosting plan limits."""
import json
import os
import re

# Copied from "Azure Functions Scale and Hosting" and "Supported Languages in Azure Functions" on 2026-09-12.
PLAN_MAX_MINUTES = {"consumption": 10, "flex": None, "premium": None, "dedicated": None}  # None = unbounded
HTTP_RESPONSE_LIMIT_SECONDS = 230
PYTHON_GA = ["3.10", "3.11", "3.12", "3.13", "3.14"]
LINUX_CONSUMPTION_LAST = "3.12"
TIMESPAN = re.compile(r"^(?:(\d+)\.)?(\d{1,2}):(\d{2}):(\d{2})$")


def to_minutes(value):
    text = str(value).strip()
    if text == "-1":
        return None
    m = TIMESPAN.match(text)
    if not m:
        raise ValueError(f"not a [d.]hh:mm:ss timespan: {value!r}")
    d, h, mi, s = (int(x or 0) for x in m.groups())
    if h > 23 or mi > 59 or s > 59:
        raise ValueError(f"out of range: {value!r}")
    return d * 1440 + h * 60 + mi + s / 60


def version_key(v):
    return tuple(int(p) for p in v.split("."))


def check(host, plan, python_version, http_seconds):
    notes = []
    minutes = to_minutes(host.get("functionTimeout", "-1"))
    limit = PLAN_MAX_MINUTES[plan]
    if limit is not None and (minutes is None or minutes > limit):
        notes.append(f"functionTimeout {host.get('functionTimeout')} exceeds the {plan} maximum of {limit} min")
    if http_seconds > HTTP_RESPONSE_LIMIT_SECONDS:
        notes.append(f"HTTP work of {http_seconds}s exceeds {HTTP_RESPONSE_LIMIT_SECONDS}s: reply first, finish later")
    if python_version not in PYTHON_GA:
        notes.append(f"Python {python_version} is not in the supported list")
    elif plan == "consumption" and version_key(python_version) > version_key(LINUX_CONSUMPTION_LAST):
        notes.append(f"Linux Consumption stops at Python {LINUX_CONSUMPTION_LAST}")
    return notes


if __name__ == "__main__":
    with open(os.environ.get("HOST_JSON", "samples/agents_host.json"), encoding="utf-8") as f:
        host = json.load(f)
    print("functionTimeout:", host.get("functionTimeout"), "=", to_minutes(host.get("functionTimeout", "-1")), "min")
    for plan, py, seconds in [("consumption", "3.13", 300), ("flex", "3.13", 120)]:
        found = check(host, plan, py, seconds)
        print(f"[{plan} / Python {py} / HTTP {seconds}s]", "ok" if not found else "")
        for note in found:
            print("  -", note)
実行結果(2026-09-12)
functionTimeout: 00:12:00 = 12.0 min
[consumption / Python 3.13 / HTTP 300s] 
  - functionTimeout 00:12:00 exceeds the consumption maximum of 10 min
  - HTTP work of 300s exceeds 230s: reply first, finish later
  - Linux Consumption stops at Python 3.12
[flex / Python 3.13 / HTTP 120s] ok
Copilot に書かせる指示の例

Azure Functions の host.json の functionTimeout([d.]hh:mm:ss)を分に直し、プランごとの上限、HTTP の 230 秒、予定する Python の版を点検する Python のスクリプトを書いて。上限の値は定数にまとめ、確認した日をコメントに書いて。

注意

表では Python 3.10 のサポート終了の予定が 2026 年 10 月である。Linux の Consumption プランは 2028 年 9 月 30 日に廃止予定で、Flex Consumption への移行が勧められている。スクリプトの値はこのページを書いた日に写したもので、変わりうる。

利用条件
2026-09-12 に Microsoft Learn の表で確認。
試験
手元で実行して確認(2026-09-12、Python 3.12.10 (venv) / Windows 11)
出典
Microsoft Learn「Azure Functions Scale and Hosting」
Microsoft Learn「Supported Languages in Azure Functions」
Microsoft Learn「host.json reference for Azure Functions 2.x」
Microsoft Learn「Update Language Versions in Azure Functions」
確認日
2026-09-12(第 1 版)
出典の該当箇所
Regardless of the function app timeout setting, 230 seconds is the maximum amount of time that an HTTP triggered function can take to respond to a request.
Python 3.12 is the last Python version supported for Linux Consumption plan apps.
You can't change the Python version when your function app runs in a Consumption plan.
The format of the timespan string needs to follow the syntax [d.]hh:mm:ss
A value of -1 indicates unbounded execution, but keeping a fixed upper bound is recommended.
Linux is the only supported operating system for the Python runtime stack.

06Fabric のノートブックは、最初のセルでライブラリの版を確かめる確認済

Fabric のノートブックで %pip install により入れたライブラリは、そのセッションの中だけで有効になる。定期実行やパイプラインで同じ版を使うには、環境の Full モードで固定する。最初のセルで版を確かめ、違えば止める。

考え方と手順
  1. 共同作業や定期実行で使うライブラリは、環境(Environment)に登録し、Full モードで発行する。
  2. %pip install は試行錯誤のときだけに使う。セッションが終われば残らない。
  3. 最初のセルで importlib.metadata から版を読み、期待する版と違えば RuntimeError で止める。
  4. 結果の JSON をセルの出力に残し、どの版で動いたかを後で確かめられるようにする。
  5. 定期実行は予定を作成または最後に更新した人、パイプラインは最後に編集した人の権限で動く。読むデータの権限をその人で確かめる。
PythonMicrosoft のクラウドで動く
# First cell of a Fabric notebook: stop early if the session's libraries differ from the pinned set
import importlib.metadata as md
import json
import sys

EXPECTED = {"pandas": "3.0.5", "openpyxl": "3.1.5"}  # keep in sync with the environment (Full mode)


def library_report(expected):
    report = {"python": sys.version.split()[0], "libraries": {}, "mismatch": []}
    for name, wanted in expected.items():
        try:
            have = md.version(name)
        except md.PackageNotFoundError:
            have = None
        report["libraries"][name] = have
        if have != wanted:
            report["mismatch"].append(f"{name}: want {wanted}, have {have}")
    return report


report = library_report(EXPECTED)
print(json.dumps(report, ensure_ascii=False))
if report["mismatch"]:
    raise RuntimeError("library mismatch: " + "; ".join(report["mismatch"]))
実行結果(2026-09-12)
{"python": "3.12.10", "libraries": {"pandas": "3.0.5", "openpyxl": "3.1.5"}, "mismatch": []}
Copilot に書かせる指示の例

Fabric のノートブックの最初のセルに置く Python のコードを書いて。期待するライブラリの版を辞書で持ち、importlib.metadata で読んだ版と比べて JSON で表示し、違えば RuntimeError で止めて。

注意

ノートブックを実行する ID は、手動・パイプライン・スケジュールで異なる。他人が編集したノートブックは、変更履歴で中身を確かめてから実行する。期待する版の辞書は環境の設定と一緒に更新する。

利用条件
Microsoft Fabric のワークスペースとノートブック。Full モードと Quick モードの詳細は Fabric の環境の文書にある。
必要なもの
pandas 3.0.5, openpyxl 3.1.5
試験
xl() を見本データで代用して手元で実行(2026-09-12、Python 3.12.10 (venv) / Windows 11、pandas 3.0.5、openpyxl 3.1.5)
出典
Microsoft Learn「How to use notebooks - Microsoft Fabric」
確認日
2026-09-12(第 1 版)
出典の該当箇所
libraries installed through inline commands (such as %pip install or install.packages()) are scoped to the current notebook session.
Full mode for reproducibility: Use Full mode when you need consistent library versions across collaborators, scheduled runs, or pipeline jobs.
Scheduler: Execution is triggered from a scheduled run. The notebook runs under the identity of the user who created or last updated the schedule.
The notebook runs under the identity of the pipeline's last modified user