!! This notebook is meant to be run by the instructor, not students !!¶
This notebook walks an instructor through placing API keys (OpenAI, Anthropic, etc.) into a .env file stored in a shared-readwrite folder so that all student notebooks can load them without ever seeing the raw key values.
Why a shared .env file?¶
Security: The key is never hard-coded in a notebook and never committed to GitHub.
Convenience: One update to the shared
.envfile rotates the key for every dependent notebook.Transparency: Students learn the best-practice pattern of loading secrets from environment variables.
What this notebook does¶
Confirms the path to the shared-readwrite folder.
Creates the folder if it does not yet exist.
Writes (or updates) a
.envfile in that folder with the API keys you supply.Verifies that the keys can be loaded back with
python-dotenv.
Step 1 — Locate (or create) the shared-readwrite folder¶
Pick the approach that matches your environment and uncomment the relevant block.
Approach 1 — JupyterHub with a shared filesystem (e.g., Berkeley DataHub / Cloudbank Demo / Cal-ICOR)¶
We are using the bash ls command just to check what folders are available
# Cal-ICOR / generic JupyterHub shared folder
# Uncomment the line that matches your hub's layout:
!ls /home/jovyan/shared-readwrite # Cloudbank Classroom workshop hub
# !ls /home/jovyan/_shared/econ148-readwrite # Berkeley DataHub SP25Approach 2 — Local machine or a relative path inside this repo¶
# Relative path (sibling folder next to the repo root notebooks)
# !ls ../shared
# Absolute path on a laptop:
# !ls /Users/yourname/Documents/GitHub/SmallLM-FA25/shared-rwSet shared_folder_path to the correct path for your environment to “Write” to¶
JupyterHub shared folder in the current setup has "shared’ for read-only and “shared-readwrite” for read-write, so we point to the read-write one. For local use, you can create a “shared-rw” folder in the repo or point to any other directory where you want to store the .env file.
import os
# ✏️ Edit this to match your setup:
shared_folder_path = "/home/jovyan/shared-readwrite"
# Expand to an absolute path so every subsequent cell works regardless of cwd
shared_folder_path = os.path.abspath(shared_folder_path)
print(f"Shared ReadWrite folder path: {shared_folder_path}")Step 2 — Create the shared folder if it does not exist¶
Step 3 — Enter your API keys¶
Fill in the API key variables below.
Leave a key as an empty string "" if you do not have it — it will be skipped.
⚠️ Never commit this notebook after filling in real keys.
The keys are written to the shared.envfile and this notebook should be cleared before saving.
# ✏️ Paste your API keys here (leave blank to skip):
openai_api_key = "" # e.g. sk-...
anthropic_api_key = "" # e.g. sk-ant-...
nrp_api_key = "" # e.g. sk-nrp-Step 4 — Write the .env file to the shared folder¶
If a .env file already exists, this cell merges the new values in: existing keys not listed above are preserved, and the keys you supplied above are added or updated.
env_file_path = os.path.join(shared_folder_path, ".env")
if os.path.isfile(env_file_path):
print(f"Found existing .env at {env_file_path}")
else:
with open(env_file_path, "w") as f:
f.write("")
print(f"No .env found — created {env_file_path}")
env_file_path = os.path.join(shared_folder_path, ".env")
# --- Ensure file exists ---
if os.path.isfile(env_file_path):
with open(env_file_path, "r") as f:
existing_lines = f.readlines()
else:
existing_lines = []
print(f"No .env found — creating {env_file_path}")
# --- Build dict of keys to write ---
new_keys = {}
if openai_api_key and openai_api_key.strip():
new_keys["OPENAI_API_KEY"] = openai_api_key.strip()
if anthropic_api_key and anthropic_api_key.strip():
new_keys["ANTHROPIC_API_KEY"] = anthropic_api_key.strip()
if nrp_api_key and nrp_api_key.strip():
new_keys["NRP_API_KEY"] = nrp_api_key.strip()
# --- Merge existing keys with new ones ---
updated_keys = set()
merged_lines = []
for line in existing_lines:
stripped = line.strip()
# keep comments or malformed lines unchanged
if stripped.startswith("#") or "=" not in stripped:
merged_lines.append(line)
continue
key = stripped.split("=", 1)[0].strip()
if key in new_keys:
merged_lines.append(f'{key}="{new_keys[key]}"\n')
updated_keys.add(key)
else:
merged_lines.append(line)
# --- Append keys not already present ---
for key, value in new_keys.items():
if key not in updated_keys:
merged_lines.append(f'{key}="{value}"\n')
# --- Write file ---
with open(env_file_path, "w") as f:
f.writelines(merged_lines)
print(f"\n✅ .env written to: {env_file_path}")
if new_keys:
print("Keys written:", ", ".join(new_keys.keys()))
else:
print("No keys supplied — file unchanged")Step 5 — Verify the keys load correctly¶
# check the filepath
env_file_path = "/home/jovyan/shared/.env"
try:
from dotenv import load_dotenv
except ImportError:
%pip install python-dotenv
from dotenv import load_dotenvfrom dotenv import load_dotenv
import os
load_dotenv(env_file_path, override=True)
loaded_openai = os.getenv("OPENAI_API_KEY")
loaded_anthropic = os.getenv("ANTHROPIC_API_KEY")
loaded_nrp = os.getenv("NRP_API_KEY")
print("OpenAI API key loaded: ", "✅" if loaded_openai else "❌ not found")
print("Anthropic API key loaded: ", "✅" if loaded_anthropic else "❌ not found")
print("NRP API key loaded: ", "✅" if loaded_nrp else "❌ not found")Notes for Instructors¶
The
.envfile at<shared_folder>/.envis intentionally not tracked in this repository.
Make sure it is listed in.gitignoreor kept outside the repo entirely.Student notebooks load the key with:
from dotenv import load_dotenv import os load_dotenv('../shared/.env') key = os.getenv('openai_API_KEY')Students should never print the raw key value or share the
.envfile.To rotate a key, just re-run this notebook with the new key — all student notebooks will pick it up automatically.
On JupyterHub, ensure the shared folder has read permissions for all students and write permission only for instructors.
Related notebooks¶
| Notebook | Description |
|---|---|
HuggingFace_Hub_Download_gguf.ipynb | Download GGUF models into a shared folder |
OpenAI_API.ipynb | Use the OpenAI API (loads key from .env) |
Anthropic_API.ipynb | Use the Anthropic API (loads key from .env) |
#!cat /home/jovyan/shared/.env