diff --git a/pyproject.toml b/pyproject.toml index 2098865..dd52e8c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ dependencies = [ "mcp[cli]>=1.9", "pydantic>=2.0", "openpyxl>=3.1", + "python-dotenv>=1.0", ] [project.optional-dependencies] diff --git a/scripts/build_db.py b/scripts/build_db.py index e4b0b6e..5a6523c 100644 --- a/scripts/build_db.py +++ b/scripts/build_db.py @@ -4,6 +4,7 @@ # dependencies = [ # "openpyxl>=3.1", # "docling>=2.0", +# "python-dotenv>=1.0", # ] # /// """Build unified SQLite database from organizational data sources. @@ -37,6 +38,13 @@ SCRIPT_DIR = Path(__file__).resolve().parent REPO_ROOT = SCRIPT_DIR.parent DATA_DIR = REPO_ROOT / "data" + +try: + from dotenv import load_dotenv + + load_dotenv(REPO_ROOT / ".env") +except ModuleNotFoundError: + pass VERSION_PATH = REPO_ROOT / "VERSION" GOVERNANCE_DIR = REPO_ROOT / "governance" @@ -54,18 +62,20 @@ JIRA_SCRUM_REF_TAB = os.environ.get("GPS_JIRA_SCRUM_REF_TAB", "Jira and Scrum teams") -EXPECTED_HEADERS = [ - "associate's name", - "manager's name", - "miro team name", - "primary jira component", - "jira team name", - "pm", - "eng lead", - "status", - "engineering speciality", - "last modified date", -] +HEADER_ALIASES: dict[str, list[str]] = { + "associate's name": ["associate's name"], + "manager's name": ["manager's name"], + "miro team name": ["miro team name", "scrum team name"], + "primary jira component": ["primary jira component"], + "jira team name": ["jira team name", "jira filter"], + "pm": ["pm"], + "eng lead": ["eng lead"], + "status": ["status"], + "engineering speciality": ["engineering speciality"], + "last modified date": ["last modified date"], +} + +EXPECTED_HEADERS = list(HEADER_ALIASES.keys()) # --------------------------------------------------------------------------- # Schema @@ -350,9 +360,21 @@ def find_xlsx(directory: Path) -> Path | None: candidates = sorted( (f for f in directory.iterdir() if f.is_file() and f.suffix == ".xlsx"), key=lambda f: f.name, - reverse=True, ) - return candidates[0] if candidates else None + if not candidates: + return None + # Prefer the file whose sheets match the configured TAB_ORG_MAP + expected_tabs = set(TAB_ORG_MAP.keys()) + for c in candidates: + try: + wb = load_workbook(c, read_only=True) + tabs = set(wb.sheetnames) + wb.close() + if expected_tabs & tabs: + return c + except Exception: + continue + return candidates[0] # --------------------------------------------------------------------------- @@ -361,9 +383,10 @@ def find_xlsx(directory: Path) -> Path | None: def _match_header(actual: str) -> str | None: - for expected in EXPECTED_HEADERS: - if actual == expected or actual.startswith(expected): - return expected + for canonical, aliases in HEADER_ALIASES.items(): + for alias in aliases: + if actual == alias or actual.startswith(alias): + return canonical return None diff --git a/uv.lock b/uv.lock index f4d4ca6..c0e3e92 100644 --- a/uv.lock +++ b/uv.lock @@ -578,6 +578,7 @@ dependencies = [ { name = "mcp", extra = ["cli"] }, { name = "openpyxl" }, { name = "pydantic" }, + { name = "python-dotenv" }, ] [package.optional-dependencies] @@ -594,6 +595,7 @@ requires-dist = [ { name = "mcp", extras = ["cli"], specifier = ">=1.9" }, { name = "openpyxl", specifier = ">=3.1" }, { name = "pydantic", specifier = ">=2.0" }, + { name = "python-dotenv", specifier = ">=1.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9" }, ] provides-extras = ["pdf", "dev"] @@ -1285,9 +1287,9 @@ name = "ocrmac" version = "1.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "pillow" }, - { name = "pyobjc-framework-vision" }, + { name = "click", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pillow", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-framework-vision", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5e/07/3e15ab404f75875c5e48c47163300eb90b7409044d8711fc3aaf52503f2e/ocrmac-1.0.1.tar.gz", hash = "sha256:507fe5e4cbd67b2d03f6729a52bbc11f9d0b58241134eb958a5daafd4b9d93d9", size = 1454317, upload-time = "2026-01-08T16:44:26.412Z" } wheels = [ @@ -1763,7 +1765,7 @@ name = "pyobjc-framework-cocoa" version = "12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, + { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/a3/16ca9a15e77c061a9250afbae2eae26f2e1579eb8ca9462ae2d2c71e1169/pyobjc_framework_cocoa-12.1.tar.gz", hash = "sha256:5556c87db95711b985d5efdaaf01c917ddd41d148b1e52a0c66b1a2e2c5c1640", size = 2772191, upload-time = "2025-11-14T10:13:02.069Z" } wheels = [ @@ -1780,8 +1782,8 @@ name = "pyobjc-framework-coreml" version = "12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/30/2d/baa9ea02cbb1c200683cb7273b69b4bee5070e86f2060b77e6a27c2a9d7e/pyobjc_framework_coreml-12.1.tar.gz", hash = "sha256:0d1a4216891a18775c9e0170d908714c18e4f53f9dc79fb0f5263b2aa81609ba", size = 40465, upload-time = "2025-11-14T10:14:02.265Z" } wheels = [ @@ -1798,8 +1800,8 @@ name = "pyobjc-framework-quartz" version = "12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/94/18/cc59f3d4355c9456fc945eae7fe8797003c4da99212dd531ad1b0de8a0c6/pyobjc_framework_quartz-12.1.tar.gz", hash = "sha256:27f782f3513ac88ec9b6c82d9767eef95a5cf4175ce88a1e5a65875fee799608", size = 3159099, upload-time = "2025-11-14T10:21:24.31Z" } wheels = [ @@ -1816,10 +1818,10 @@ name = "pyobjc-framework-vision" version = "12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreml" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-framework-coreml", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c2/5a/08bb3e278f870443d226c141af14205ff41c0274da1e053b72b11dfc9fb2/pyobjc_framework_vision-12.1.tar.gz", hash = "sha256:a30959100e85dcede3a786c544e621ad6eb65ff6abf85721f805822b8c5fe9b0", size = 59538, upload-time = "2025-11-14T10:23:21.979Z" } wheels = [ @@ -2894,8 +2896,8 @@ name = "uvicorn" version = "0.42.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "h11" }, + { name = "click", marker = "sys_platform != 'emscripten'" }, + { name = "h11", marker = "sys_platform != 'emscripten'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/ad/4a96c425be6fb67e0621e62d86c402b4a17ab2be7f7c055d9bd2f638b9e2/uvicorn-0.42.0.tar.gz", hash = "sha256:9b1f190ce15a2dd22e7758651d9b6d12df09a13d51ba5bf4fc33c383a48e1775", size = 85393, upload-time = "2026-03-16T06:19:50.077Z" } wheels = [