Compute attendance rate from LMS student progress CSVs in Python and publish a sharable URL with Functory
This article explains how to compute an accreditation-ready attendance rate from LMS student progress CSVs (enrollments, progress percent, last_activity) and expose the result as a shareable URL using Functory. It's targeted at founders and small teams that need automated, repeatable reporting without running servers or building a dashboard.
Precise function description
Input: student_progress.csv (columns: student_email, course_code, term, enroll_date, progress_pct, last_activity (ISO8601), status). Processing: filter enrolled students (status==active), determine presence as last_activity within term date range or progress_pct >= 5%, and then compute attendance rate per course. Output: CSV attendance_summary.csv and JSON metrics for API consumers.
Concrete input schema
- student_progress.csv example row: alice@example.com,CS201,2024-Spring,2024-01-10T00:00:00Z,12.5,2024-02-12T09:21:00Z,active
- course_dates.json (optional): maps course_code to term start and end dates; used to interpret last_activity windows (e.g., CS201: {start:'2024-01-08', end:'2024-05-12'}).
Output example
attendance_summary.csv (example):
course_code,term,enrolled_count,present_count,attendance_rate_pct
CS201,2024-Spring,95,81,85.26
MATH101,2024-Spring,120,102,85.00
attendance_details.json contains per-student last_activity and a boolean present flag for downstream auditing.
Real-world scenario
Startup example: A product team with 4 instructors needs weekly attendance updates shared with a non-technical COO. Data: student_progress.csv with 5,000 rows (covering 20 courses). Specific problem: accuracy—progress_pct is noisy (system records 0.1% for auto-saves). The function treats a student as present if progress_pct >= 5% OR last_activity inside term range to reduce false negatives.
Example dataset and problem
Dataset: 5,000 rows, columns listed above. Problem solved: automatic weekly generation of attendance_summary.csv, which is then published via Functory as an endpoint the COO can bookmark. The function handles timezone normalization, ignores audit-only auto-saves (filter progress_pct < 1%), and enforces term window checks to avoid counting pre-enrollment activity.
Workflow (end-to-end)
- Export student_progress.csv from LMS weekly or point the function at an S3 URL.
- Call the Functory function via the web UI or HTTP API; upload CSV or pass a URL string to the file parameter.
- Function returns attendance_summary.csv path; Functory exposes a downloadable link that can be shared with the team.
- Optional: chain with a Functory function that emails the CSV to stakeholders on completion.
Algorithm summary
- Load student_progress.csv; parse last_activity as UTC datetime.
- Filter to status==active and progress_pct >= 1% (noise filter).
- Define present if (progress_pct >= 5%) OR (last_activity between term_start and term_end).
- Aggregate present by course_code and term; compute attendance_rate_pct.
Python snippet
import pandas as pd
from pathlib import Path
def main(progress_csv: str, course_dates_json: str | None = None, out_dir: str = '.') -> str:
df = pd.read_csv(progress_csv, parse_dates=['enroll_date','last_activity'])
df['student_email'] = df['student_email'].str.lower().str.strip()
# noise filter
df = df[df['status'].eq('active') & (df['progress_pct'].fillna(0) >= 1.0)]
# optional course dates
if course_dates_json:
import json
cd = json.loads(Path(course_dates_json).read_text())
else:
cd = {}
def is_present(row):
if row.get('progress_pct',0) >= 5.0:
return True
dates = cd.get(row['course_code'], None)
if dates:
return dates['start'] <= row['last_activity'].date().isoformat() <= dates['end']
return not pd.isna(row['last_activity'])
df['present'] = df.apply(is_present, axis=1)
summary = df.groupby(['course_code','term']).agg(enrolled_count=('student_email','nunique'), present_count=('present','sum')).reset_index()
summary['attendance_rate_pct'] = (summary['present_count']/summary['enrolled_count']*100).round(2)
out = Path(out_dir); out.mkdir(exist_ok=True)
summary.to_csv(out/'attendance_summary.csv', index=False)
return str(out/'attendance_summary.csv')
Comparison to other approaches
Teams often solve this with: spreadsheets shared on Google Drive (manual), scheduled SQL queries in a data warehouse (requires infra and data syncing), or ad-hoc scripts in a notebook (hard to expose as a URL). Publishing this single-file function on Functory gives the advantages of a hosted API without managing servers—shareable URL, parameterized inputs, and a consistent runtime environment.
Business or productivity benefit
Concrete benefit: replacing a weekly manual export+email workflow with an automated Functory endpoint saves 2–3 staff-hours per week, or ~104–156 hours per year—a measurable productivity gain for a small team. It also reduces reporting latency from 2 days to immediate.
Industry stat: A 2023 EdTech adoption study found 58% of small training providers increased automation in reporting in the prior year (EdTech Insights, 2023).
How Functory Makes It Easy
Wrap the core logic in main(progress_csv: str, course_dates_json: str | None = None) and choose an exact Python version such as 3.11.11. In requirements.txt pin dependencies: pandas==2.2.3. Functory will surface progress_csv as an upload field or URL input and return a path to attendance_summary.csv which becomes a downloadable link. No CLI: Functory calls main directly. Benefits include autoscaling, built-in logs via print(), CPU/GPU tier choice for heavier analysis, and pay-per-use billing. Chain this function with other Functory functions (for emailing or pushing to Slack) to create a full reporting automation without managing servers.
Conclusion: This pattern turns weekly LMS progress exports into a shareable attendance report with minimal engineering. Next steps: add automated scheduling, integrate course date management, or add an audit CSV for regulators. Deploy on Functory and give your stakeholders a single URL to always fetch the latest metric.
Thanks for reading.
