119 lines
3.1 KiB
Python
119 lines
3.1 KiB
Python
"""Small input-prompting and formatting helpers shared by the menu screens."""
|
|
|
|
import datetime
|
|
import re
|
|
|
|
GUID_RE = re.compile(r"^\d{12}$")
|
|
PHONE_RE = re.compile(r"^\d{10}$")
|
|
|
|
|
|
def pause():
|
|
input("\nPress Enter to continue...")
|
|
|
|
|
|
def clear_hint():
|
|
print("\n" + "-" * 60 + "\n")
|
|
|
|
|
|
def prompt_str(label, max_len=None, required=True, allow_blank_skip=False):
|
|
"""Prompt for a string. allow_blank_skip=True returns None on empty input (for 'leave unchanged')."""
|
|
while True:
|
|
suffix = f" (max {max_len} chars)" if max_len else ""
|
|
val = input(f"{label}{suffix}: ").strip()
|
|
if not val:
|
|
if allow_blank_skip:
|
|
return None
|
|
if required:
|
|
print(" This field is required.")
|
|
continue
|
|
return ""
|
|
if max_len and len(val) > max_len:
|
|
print(f" Too long — max {max_len} characters.")
|
|
continue
|
|
return val
|
|
|
|
|
|
def prompt_int(label, max_digits=None, allow_blank_skip=False):
|
|
while True:
|
|
val = input(f"{label}: ").strip()
|
|
if not val:
|
|
if allow_blank_skip:
|
|
return None
|
|
print(" This field is required.")
|
|
continue
|
|
if not val.isdigit():
|
|
print(" Please enter a whole number.")
|
|
continue
|
|
if max_digits and len(val) > max_digits:
|
|
print(f" Too many digits — max {max_digits}.")
|
|
continue
|
|
return int(val)
|
|
|
|
|
|
def prompt_guid(label="Guardian ID / GUID (12-digit Aadhaar number)", allow_blank_skip=False):
|
|
while True:
|
|
val = input(f"{label}: ").strip()
|
|
if not val:
|
|
if allow_blank_skip:
|
|
return None
|
|
print(" This field is required.")
|
|
continue
|
|
if not GUID_RE.match(val):
|
|
print(" GUID must be exactly 12 digits.")
|
|
continue
|
|
return val
|
|
|
|
|
|
def prompt_phone(label="Guardian phone (10 digits, optional)", allow_blank_skip=True):
|
|
while True:
|
|
val = input(f"{label}: ").strip()
|
|
if not val:
|
|
return None # NULL is allowed for GPhone
|
|
if not PHONE_RE.match(val):
|
|
print(" Phone must be exactly 10 digits (or leave blank).")
|
|
continue
|
|
return val
|
|
|
|
|
|
def prompt_date(label, allow_blank_skip=False):
|
|
while True:
|
|
val = input(f"{label} (YYYY-MM-DD): ").strip()
|
|
if not val:
|
|
if allow_blank_skip:
|
|
return None
|
|
print(" This field is required.")
|
|
continue
|
|
try:
|
|
return datetime.datetime.strptime(val, "%Y-%m-%d").date()
|
|
except ValueError:
|
|
print(" Invalid date — use format YYYY-MM-DD, e.g. 2015-08-21.")
|
|
|
|
|
|
def prompt_attendance_status(label="Status (P=present, A=absent)"):
|
|
while True:
|
|
val = input(f"{label}: ").strip().upper()
|
|
if val in ("P", "A"):
|
|
return val
|
|
print(" Please enter 'P' or 'A'.")
|
|
|
|
|
|
def print_table(rows, columns=None):
|
|
"""Pretty-print a list of dict rows as a simple aligned table."""
|
|
if not rows:
|
|
print(" (no records found)")
|
|
return
|
|
|
|
if columns is None:
|
|
columns = list(rows[0].keys())
|
|
|
|
widths = {}
|
|
for col in columns:
|
|
widths[col] = max(len(str(col)), *(len(str(r.get(col, ""))) for r in rows))
|
|
|
|
header = " " + " | ".join(str(col).ljust(widths[col]) for col in columns)
|
|
print(header)
|
|
print(" " + "-+-".join("-" * widths[col] for col in columns))
|
|
for r in rows:
|
|
print(" " + " | ".join(str(r.get(col, "")).ljust(widths[col]) for col in columns))
|
|
print(f"\n ({len(rows)} record{'s' if len(rows) != 1 else ''})")
|