============================================================
 MODULES, PACKAGES & VIRTUAL ENVIRONMENTS - Demo Run
============================================================

--- Building utils.py module ---
  Created: module_demo/utils.py
  import utils; utils.reverse_string('hello') = olleh
  from utils import is_positive; is_positive(-3) = False

--- if __name__ == '__main__': guard confirmation ---
  utils module imported normally -- did NOT run its self-test block (confirmed: no
  'Running utils.py directly' message appeared above).
  Running utils.py directly via subprocess DOES trigger it:
    Running utils.py directly -- self-test mode
    Self-tests passed.

--- Building a proper package ---
  Created package: module_demo/mypackage
  Contents: ['validation_utils.py', '__init__.py', 'string_utils.py']

  import mypackage; mypackage.shout('hi') = HI!
  mypackage.is_valid_age(200) = False
  (Both re-exported at the package level via __init__.py)

============================================================
 Assignment: separating library code from CLI code (conceptual demonstration)
============================================================
  gradebook_lib.py would hold compute_averages(), etc. (pure functions, no I/O)
  gradebook_cli.py would import gradebook_lib and handle menus/print()/input()
  This separation means gradebook_lib could be reused by a totally different
  interface (a web app, a test suite) without dragging along any CLI code.

--- requirements.txt concept ---
  `pip freeze > requirements.txt` captures exact installed versions.
  Another developer runs `pip install -r requirements.txt` in their OWN venv
  to recreate an identical dependency set -- without touching their system Python.
