project-init
This commit is contained in:
commit
65691a0aee
7 files changed
+897
No files matched your search
+118
@@ -0,0 +1,118 @@
|
||||
"""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 ''})")
|
||||
Reference in new issue
Block a user