From 02fa8ce0d08fba74da19152fe91bcdd3b67c92d2 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 12 May 2025 15:22:14 -0400 Subject: [PATCH] Enhance app.py and lambda_setup.py: improve environment variable handling, explicitly install critical dependencies, and add verification for key imports to ensure proper Lambda functionality --- app.py | 35 +++++++++++++++++++++++++ scripts/lambda_setup.py | 58 ++++++++++++++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/app.py b/app.py index 98f2de4..efaced9 100644 --- a/app.py +++ b/app.py @@ -5,6 +5,41 @@ error by placing an entrypoint at the root level of the Lambda package. """ +import sys +import os +import importlib.util + +# Add Lambda task root directory to Python path +sys.path.insert(0, '/var/task') + +# Try to read environment variables if they exist +if os.path.exists('/var/task/.env'): + with open('/var/task/.env', 'r') as env_file: + for line in env_file: + if '=' in line: + key, value = line.strip().split('=', 1) + os.environ[key] = value + if key == 'PYTHONPATH': + for path in value.split(':'): + if path and path not in sys.path: + sys.path.insert(0, path) + +# Fallback check for critical dependencies +for module in ['pydantic', 'jinja2']: + try: + importlib.import_module(module) + except ImportError: + print(f"Warning: {module} not found in standard paths. Looking in /var/task...") + # Look for the module in /var/task + module_paths = [ + f'/var/task/{module}', + f'/var/task/lib/python3.11/site-packages/{module}' + ] + for path in module_paths: + if os.path.exists(path): + sys.path.insert(0, os.path.dirname(path)) + break + from template_automation.app import lambda_handler # Re-export the lambda_handler function for Lambda runtime to find it diff --git a/scripts/lambda_setup.py b/scripts/lambda_setup.py index 5aa5a4f..a54d601 100644 --- a/scripts/lambda_setup.py +++ b/scripts/lambda_setup.py @@ -12,6 +12,7 @@ # Constants LAMBDA_TASK_ROOT = '/var/task' TMP_DIR = '/tmp' +PYTHON_VERSION = "3.11" # Match the Lambda container's Python version def run_command(cmd, check=True): """Run a shell command and print its output""" @@ -34,14 +35,24 @@ def copy_file(src, dest): def install_dependencies(): """Install Python dependencies""" print("=== Installing dependencies from requirements.txt ===") - run_command(f"pip3 install --no-cache-dir -r {TMP_DIR}/requirements.txt -t {LAMBDA_TASK_ROOT} -v") - # Explicitly install pydantic to ensure it's available - print("=== Explicitly installing pydantic ===") - run_command(f"pip3 install --no-cache-dir pydantic -t {LAMBDA_TASK_ROOT} -v") + # Create a site-packages directory if it doesn't exist + site_packages = f"{LAMBDA_TASK_ROOT}/lib/python{PYTHON_VERSION}/site-packages" + os.makedirs(site_packages, exist_ok=True) + + # Install dependencies directly to the site-packages directory + run_command(f"pip3 install --no-cache-dir -r {TMP_DIR}/requirements.txt -t {LAMBDA_TASK_ROOT}") + + # Explicitly install critical dependencies + print("=== Explicitly installing critical dependencies ===") + run_command(f"pip3 install --no-cache-dir pydantic jinja2 -t {LAMBDA_TASK_ROOT}") + + # Create a .pth file to ensure the Lambda runtime can find the packages + with open(f"{LAMBDA_TASK_ROOT}/lambda_path.pth", "w") as f: + f.write(f"{LAMBDA_TASK_ROOT}\n") print("=== Installing package in development mode ===") - run_command(f"pip3 install --no-cache-dir -e {TMP_DIR} -t {LAMBDA_TASK_ROOT} -v") + run_command(f"pip3 install --no-cache-dir -e {TMP_DIR} -t {LAMBDA_TASK_ROOT}") def verify_dependencies(): """Verify that key dependencies are installed correctly""" @@ -52,13 +63,18 @@ def verify_dependencies(): run_command("python3 -c 'import sys; print(sys.path)'") # Check key dependencies - dependencies = [] + dependencies = ['pydantic', 'jinja2'] # Add critical dependencies here with open(f"{TMP_DIR}/requirements.txt") as f: - dependencies = [line.strip().split("=")[0] for line in f if line.strip() and not line.startswith("#")] + for line in f: + line = line.strip() + if line and not line.startswith("#"): + pkg = line.split("=")[0].split("<")[0].split(">")[0].split("~")[0].strip() + if pkg and pkg not in dependencies: + dependencies.append(pkg) - + # Use the Lambda container's Python to verify imports for dep in dependencies: - cmd = f"python3 -c 'import {dep}; print(f\"{dep} installed successfully\")' || echo '{dep} not installed correctly'" + cmd = f"cd {LAMBDA_TASK_ROOT} && python3 -c 'import {dep}; print(f\"{dep} installed successfully\")' || echo '{dep} not installed correctly'" run_command(cmd, check=False) def setup_lambda_environment(): @@ -81,6 +97,10 @@ def setup_lambda_environment(): print("=== Copying template_automation package ===") copy_directory(f"{TMP_DIR}/template_automation", f"{LAMBDA_TASK_ROOT}/template_automation") + # Create a wrapper script that ensures the Python path is set correctly + with open(f"{LAMBDA_TASK_ROOT}/.env", "w") as f: + f.write(f"PYTHONPATH={LAMBDA_TASK_ROOT}:{LAMBDA_TASK_ROOT}/lib/python{PYTHON_VERSION}/site-packages\n") + # Verify dependencies verify_dependencies() @@ -92,6 +112,26 @@ def setup_lambda_environment(): print("=== Verifying Lambda task root contents ===") run_command(f"ls -la {LAMBDA_TASK_ROOT}") run_command(f"ls -la {LAMBDA_TASK_ROOT}/template_automation") + + # Final check - try to import jinja2 and pydantic from the Lambda environment + print("=== Testing key imports from Lambda environment ===") + test_import = """ +import sys +print("Python Path:", sys.path) +try: + import pydantic + print("pydantic successfully imported:", pydantic.__file__) +except ImportError as e: + print("Error importing pydantic:", str(e)) +try: + import jinja2 + print("jinja2 successfully imported:", jinja2.__file__) +except ImportError as e: + print("Error importing jinja2:", str(e)) +""" + with open(f"{LAMBDA_TASK_ROOT}/test_imports.py", "w") as f: + f.write(test_import) + run_command(f"cd {LAMBDA_TASK_ROOT} && python3 test_imports.py") if __name__ == "__main__": setup_lambda_environment()