From 5f2026dfaa4fc55b22884a16d2601e2f24204898 Mon Sep 17 00:00:00 2001 From: razorblade23 <81590614+razorblade23@users.noreply.github.com> Date: Mon, 12 Oct 2026 13:35:48 +0200 Subject: [PATCH] Revert "added exercises for 06_Scope_and_Namespaces" --- exercises/foundations/06_scopes/README.md | 96 -------------- exercises/foundations/06_scopes/scopes.py | 121 ----------------- .../06_scopes/solution/scopes_solution.py | 123 ------------------ .../solution/test_scopes_solution.py | 99 -------------- .../foundations/06_scopes/test_scopes.py | 107 --------------- 5 files changed, 546 deletions(-) delete mode 100644 exercises/foundations/06_scopes/README.md delete mode 100644 exercises/foundations/06_scopes/scopes.py delete mode 100644 exercises/foundations/06_scopes/solution/scopes_solution.py delete mode 100644 exercises/foundations/06_scopes/solution/test_scopes_solution.py delete mode 100644 exercises/foundations/06_scopes/test_scopes.py diff --git a/exercises/foundations/06_scopes/README.md b/exercises/foundations/06_scopes/README.md deleted file mode 100644 index 0af7208..0000000 --- a/exercises/foundations/06_scopes/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# Exercise 06 - Scope Station: Reactor Rescue (Scope and Namespaces) - -## Description -Orbital Station Alpha is failing! Engineers rushed the code and left variables in the wrong places: some are trapped inside functions, some are missing the right keyword, and some are hiding Python's own tools. - -This is a **debugging game**. `scopes.py` is already written, but it is *almost* working. Your job in each level is to figure out **where each variable must live** (and which keyword, if any, it needs) so the system runs. - -Remember the question from the lesson: *"Where does this name live, and who needs to see it?"* - -> Do not rename the functions. The tests call them by name. You decide where the variables go. - ---- - -## Levels - -### Level 1 - Power Grid (Local vs. Global) -`show_banner()` crashes with a `NameError`. The station name is created inside `boot_system()`, but two functions need it. -* **Your job**: make both `boot_system()` and `show_banner()` work. -* **Expected**: `show_banner()` returns `"=== Orbital Station Alpha ==="`. - -> **Next step:** Run `python check.py 06`. Once Level 1 passes, remove the `@pytest.mark.skip` line above `test_level2` in `test_scopes.py`. - -### Level 2 - Life Support (Enclosing Scope) -`build_oxygen_monitor()` returns an inner function `read_level()`, but it can't find the oxygen value. -* **Your job**: put `oxygen` where `read_level()` can find it by looking outward, and don't use a global. -* **Expected**: the monitor returns `"Oxygen at 100%"`. - -> **Next step:** Unlock `test_level3`. - -### Level 3 - Comms Array (Built-in Scope) -`summarize_signals()` fails with `TypeError: ... object is not callable`. Something is hiding Python's built-in tools. -* **Your job**: find what is shadowing the built-ins and fix it. -* **Expected**: `"3 signals, strength 49"`. - -> **Next step:** Unlock `test_level4`. - -### Level 4 - Reactor Core (`UnboundLocalError`) -`add_bonus_power()` crashes with `UnboundLocalError`. -* **Your job**: fix it by sending the value **in** with a parameter and sending the result **out** with `return`. The global `power` must stay `50`, and `global` is not allowed in this level. -* **Expected**: `add_bonus_power(50)` returns `60`. - -> **Next step:** Unlock `test_level5`. - -### Level 5 - Cargo Bay (Mutable Objects) -`load_crate()` adds items to a list that vanishes when the function ends, and `get_manifest()` can't find it. -* **Your job**: make both functions share the same list. You don't need `global`, because you only change the list's contents. -* **Expected**: loading `"Titanium"` then `"Ice"` gives a manifest ending in `["Titanium", "Ice"]`. - -> **Next step:** Unlock `test_level6`. - -### Level 6 - Alarm System (`global`) -`trigger_alarm()` should count alarms in the global `alarm_count`, but crashes. -* **Your job**: let the function rebind the global variable. -* **Expected**: three calls return `1`, `2`, `3` (from a fresh start) and `alarm_count` ends up updated. - -> **Next step:** Unlock `test_level7`. - -### Level 7 - Drone Memory (`nonlocal`) -Each drone made by `make_drone_counter()` should remember how many scans it did, but `scan()` crashes. -* **Your job**: let the inner function update the enclosing variable. -* **Expected**: one drone counts `1, 2, 3`, and a second drone starts again at `1`. - -> **Next step:** Unlock `test_level8`. - -### Level 8 - Diagnostics (`globals()` and `locals()`) -Complete the three helper functions in the `LEVEL 8` section: -* `list_local_names(a, b)`: return a **sorted list** of the names in the function's local namespace. -* `is_global(name)`: return `True` if `name` exists in the global namespace. -* `probe_hidden()`: try to read `secret_code` (it only exists inside `_make_secret()`). Return `True` if Python raises `NameError`. - -> **Next step:** Unlock `test_level9`. - -### Level 9 - BOSS: Reactor Boot Sequence -`run_station()` has **three** different scope bugs at once. Use everything you have learned. -* **Expected**: `"Checks: 3 | Passed: 2 | Peak: 91"`. - -> **Next step:** If Level 9 passes, congratulations! You saved the station. - ---- - -## How to Run the Tests -Run the following command from the repository root: -```bash -python check.py 06 -``` - -Or run directly with pytest: -```bash -pytest exercises/foundations/06_scopes/test_scopes.py -v -``` - ---- - -## Resources & Notes -Review the concepts covered in this exercise in: -* [The Python Ledger Curriculum: Scope and Namespaces](https://thepythonledger.github.io/Docusaurus-engine/lessons/code-organization/scope-and-namespaces) diff --git a/exercises/foundations/06_scopes/scopes.py b/exercises/foundations/06_scopes/scopes.py deleted file mode 100644 index 29bb38b..0000000 --- a/exercises/foundations/06_scopes/scopes.py +++ /dev/null @@ -1,121 +0,0 @@ -# ORBITAL STATION ALPHA - Reactor Rescue -# Every system below is almost working. Find WHERE each variable should live. -# Do not rename the functions - the tests call them by name. - - -# LEVEL 1 - Power Grid -def boot_system(): - STATION_NAME = "Orbital Station Alpha" - return f"Booting {STATION_NAME}..." - - -def show_banner(): - return f"=== {STATION_NAME} ===" - - -# LEVEL 2 - Life Support -def calibrate_sensors(): - oxygen = 100 - return "Sensors calibrated" - - -def build_oxygen_monitor(): - def read_level(): - return f"Oxygen at {oxygen}%" - - return read_level - - -# LEVEL 3 - Comms Array -list = [12, 7, 30] # incoming signal strengths -sum = 0 # total strength - - -def summarize_signals(): - return f"{len(list)} signals, strength {sum(list)}" - - -# LEVEL 4 - Reactor Core -power = 50 - - -def add_bonus_power(): - print("Current power:", power) - power = power + 10 - return power - - -# LEVEL 5 - Cargo Bay -def load_crate(item): - cargo = [] - cargo.append(item) - - -def get_manifest(): - return cargo - - -# LEVEL 6 - Alarm System -alarm_count = 0 - - -def trigger_alarm(): - alarm_count = alarm_count + 1 - return alarm_count - - -# LEVEL 7 - Drone Memory -def make_drone_counter(): - scans = 0 - - def scan(): - scans = scans + 1 - return scans - - return scan - - -# LEVEL 8 - Diagnostics -def _make_secret(): - secret_code = 42 - return "secret stored" - - -def list_local_names(a, b): - c = a + b - # Return a sorted list of the names in THIS function's local namespace. - pass - - -def is_global(name): - # Return True if `name` exists in the global namespace. - pass - - -def probe_hidden(): - _make_secret() - # Try to read `secret_code` here. Return True if Python raises NameError - # (it is hidden inside _make_secret), otherwise return False. - pass - - -# LEVEL 9 - BOSS: Reactor Boot Sequence -def configure_reactor(): - REACTOR_TARGET = 80 - return "Reactor configured" - - -readings = [72, 91, 85] -max = 0 # highest reading seen so far - - -def run_station(): - checks = 0 - - def run_check(reading): - checks = checks + 1 - return reading >= REACTOR_TARGET - - results = [run_check(r) for r in readings] - highest = max(readings) - return f"Checks: {checks} | Passed: {results.count(True)} | Peak: {highest}" diff --git a/exercises/foundations/06_scopes/solution/scopes_solution.py b/exercises/foundations/06_scopes/solution/scopes_solution.py deleted file mode 100644 index 9e0c221..0000000 --- a/exercises/foundations/06_scopes/solution/scopes_solution.py +++ /dev/null @@ -1,123 +0,0 @@ -# ORBITAL STATION ALPHA - Reactor Rescue (reference solution) - -# LEVEL 1 - Power Grid: shared by two functions -> module level -STATION_NAME = "Orbital Station Alpha" - - -def boot_system(): - return f"Booting {STATION_NAME}..." - - -def show_banner(): - return f"=== {STATION_NAME} ===" - - -# LEVEL 2 - Life Support: lives in the enclosing function -def calibrate_sensors(): - return "Sensors calibrated" - - -def build_oxygen_monitor(): - oxygen = 100 - - def read_level(): - return f"Oxygen at {oxygen}%" - - return read_level - - -# LEVEL 3 - Comms Array: don't shadow built-ins -signals = [12, 7, 30] - - -def summarize_signals(): - return f"{len(signals)} signals, strength {sum(signals)}" - - -# LEVEL 4 - Reactor Core: parameter + return instead of global -power = 50 - - -def add_bonus_power(current_power): - print("Current power:", current_power) - return current_power + 10 - - -# LEVEL 5 - Cargo Bay: shared mutable list, no `global` needed -cargo = [] - - -def load_crate(item): - cargo.append(item) - - -def get_manifest(): - return cargo - - -# LEVEL 6 - Alarm System: rebinding a global needs `global` -alarm_count = 0 - - -def trigger_alarm(): - global alarm_count - alarm_count = alarm_count + 1 - return alarm_count - - -# LEVEL 7 - Drone Memory: rebinding an enclosing variable needs `nonlocal` -def make_drone_counter(): - scans = 0 - - def scan(): - nonlocal scans - scans = scans + 1 - return scans - - return scan - - -# LEVEL 8 - Diagnostics -def _make_secret(): - secret_code = 42 - return "secret stored" - - -def list_local_names(a, b): - c = a + b - return sorted(locals().keys()) - - -def is_global(name): - return name in globals() - - -def probe_hidden(): - _make_secret() - try: - secret_code - except NameError: - return True - return False - - -# LEVEL 9 - BOSS: Reactor Boot Sequence -REACTOR_TARGET = 80 -readings = [72, 91, 85] - - -def configure_reactor(): - return "Reactor configured" - - -def run_station(): - checks = 0 - - def run_check(reading): - nonlocal checks - checks = checks + 1 - return reading >= REACTOR_TARGET - - results = [run_check(r) for r in readings] - highest = max(readings) - return f"Checks: {checks} | Passed: {results.count(True)} | Peak: {highest}" diff --git a/exercises/foundations/06_scopes/solution/test_scopes_solution.py b/exercises/foundations/06_scopes/solution/test_scopes_solution.py deleted file mode 100644 index 196bbf0..0000000 --- a/exercises/foundations/06_scopes/solution/test_scopes_solution.py +++ /dev/null @@ -1,99 +0,0 @@ -import ast -import inspect -import textwrap - -import pytest - -import scopes_solution as m - - -def _run(func, *args, hint=""): - - try: - return func(*args) - except (NameError, TypeError) as err: - pytest.fail( - f"{func.__name__}() crashed with {type(err).__name__}: {err}\n" - f"Hint: {hint}", - pytrace=False, - ) - - -def _has_statement(func, node_type): - tree = ast.parse(textwrap.dedent(inspect.getsource(func))) - return any(isinstance(node, node_type) for node in ast.walk(tree)) - - -def test_level1(): - assert "STATION_NAME" in vars(m), ( - "STATION_NAME should be defined at module level so every function can see it." - ) - assert _run(m.boot_system, hint="Who needs the station name?") == ( - "Booting Orbital Station Alpha..." - ) - assert _run(m.show_banner, hint="Where does STATION_NAME have to live?") == ( - "=== Orbital Station Alpha ===" - ) - - -def test_level2(): - monitor = _run(m.build_oxygen_monitor, hint="Which function does read_level() sit in?") - assert _run(monitor, hint="read_level() looks outward: Local, then...?") == ( - "Oxygen at 100%" - ) - assert "oxygen" not in vars(m), "Don't solve this with a module-level variable." - - -def test_level3(): - assert "list" not in vars(m), "You have shadowed the built-in `list`." - assert "sum" not in vars(m), "You have shadowed the built-in `sum`." - assert _run(m.summarize_signals, hint="Built-in names must stay available.") == ( - "3 signals, strength 49" - ) - - -def test_level4(): - assert _run(m.add_bonus_power, 50, hint="Pass the value in instead.") == 60 - assert m.power == 50, "The global `power` must not be changed." - assert not _has_statement(m.add_bonus_power, ast.Global), ( - "Fix this one with a parameter and `return`, not `global`." - ) - - -def test_level5(): - before = len(_run(m.get_manifest, hint="Where must the cargo list live?")) - _run(m.load_crate, "Titanium", hint="Both functions share one list.") - _run(m.load_crate, "Ice", hint="Both functions share one list.") - assert m.get_manifest()[before:] == ["Titanium", "Ice"] - assert not _has_statement(m.load_crate, ast.Global), ( - "Mutating a list in place doesn't need `global`." - ) - - -def test_level6(): - start = m.alarm_count - for expected in (start + 1, start + 2, start + 3): - assert _run(m.trigger_alarm, hint="Rebinding a global needs a keyword.") == expected - assert m.alarm_count == start + 3, "The global alarm_count should be updated." - - -def test_level7(): - drone_a = m.make_drone_counter() - drone_b = m.make_drone_counter() - assert [_run(drone_a, hint="Rebinding an enclosing variable needs a keyword.") - for _ in range(3)] == [1, 2, 3] - assert drone_b() == 1, "Each drone should keep its own count." - - -def test_level8(): - assert m.list_local_names(1, 2) == ["a", "b", "c"] - assert m.is_global("show_banner") is True - assert m.is_global("no_such_name_xyz") is False - assert m.probe_hidden() is True - - -def test_level9(): - assert "max" not in vars(m), "You have shadowed the built-in `max`." - assert _run(m.run_station, hint="Three scope bugs are hiding here.") == ( - "Checks: 3 | Passed: 2 | Peak: 91" - ) diff --git a/exercises/foundations/06_scopes/test_scopes.py b/exercises/foundations/06_scopes/test_scopes.py deleted file mode 100644 index 553b3ea..0000000 --- a/exercises/foundations/06_scopes/test_scopes.py +++ /dev/null @@ -1,107 +0,0 @@ -import ast -import inspect -import textwrap - -import pytest - -import scopes as m - - -def _run(func, *args, hint=""): - - try: - return func(*args) - except (NameError, TypeError) as err: - pytest.fail( - f"{func.__name__}() crashed with {type(err).__name__}: {err}\n" - f"Hint: {hint}", - pytrace=False, - ) - - -def _has_statement(func, node_type): - tree = ast.parse(textwrap.dedent(inspect.getsource(func))) - return any(isinstance(node, node_type) for node in ast.walk(tree)) - - -def test_level1(): - assert "STATION_NAME" in vars(m), ( - "STATION_NAME should be defined at module level so every function can see it." - ) - assert _run(m.boot_system, hint="Who needs the station name?") == ( - "Booting Orbital Station Alpha..." - ) - assert _run(m.show_banner, hint="Where does STATION_NAME have to live?") == ( - "=== Orbital Station Alpha ===" - ) - - -@pytest.mark.skip(reason="Finish level 1 first") -def test_level2(): - monitor = _run(m.build_oxygen_monitor, hint="Which function does read_level() sit in?") - assert _run(monitor, hint="read_level() looks outward: Local, then...?") == ( - "Oxygen at 100%" - ) - assert "oxygen" not in vars(m), "Don't solve this with a module-level variable." - - -@pytest.mark.skip(reason="Finish level 2 first") -def test_level3(): - assert "list" not in vars(m), "You have shadowed the built-in `list`." - assert "sum" not in vars(m), "You have shadowed the built-in `sum`." - assert _run(m.summarize_signals, hint="Built-in names must stay available.") == ( - "3 signals, strength 49" - ) - - -@pytest.mark.skip(reason="Finish level 3 first") -def test_level4(): - assert _run(m.add_bonus_power, 50, hint="Pass the value in instead.") == 60 - assert m.power == 50, "The global `power` must not be changed." - assert not _has_statement(m.add_bonus_power, ast.Global), ( - "Fix this one with a parameter and `return`, not `global`." - ) - - -@pytest.mark.skip(reason="Finish level 4 first") -def test_level5(): - before = len(_run(m.get_manifest, hint="Where must the cargo list live?")) - _run(m.load_crate, "Titanium", hint="Both functions share one list.") - _run(m.load_crate, "Ice", hint="Both functions share one list.") - assert m.get_manifest()[before:] == ["Titanium", "Ice"] - assert not _has_statement(m.load_crate, ast.Global), ( - "Mutating a list in place doesn't need `global`." - ) - - -@pytest.mark.skip(reason="Finish level 5 first") -def test_level6(): - start = m.alarm_count - for expected in (start + 1, start + 2, start + 3): - assert _run(m.trigger_alarm, hint="Rebinding a global needs a keyword.") == expected - assert m.alarm_count == start + 3, "The global alarm_count should be updated." - - -@pytest.mark.skip(reason="Finish level 6 first") -def test_level7(): - drone_a = m.make_drone_counter() - drone_b = m.make_drone_counter() - assert [_run(drone_a, hint="Rebinding an enclosing variable needs a keyword.") - for _ in range(3)] == [1, 2, 3] - assert drone_b() == 1, "Each drone should keep its own count." - - -@pytest.mark.skip(reason="Finish level 7 first") -def test_level8(): - assert m.list_local_names(1, 2) == ["a", "b", "c"] - assert m.is_global("show_banner") is True - assert m.is_global("no_such_name_xyz") is False - assert m.probe_hidden() is True - - -@pytest.mark.skip(reason="Finish level 8 first") -def test_level9(): - assert "max" not in vars(m), "You have shadowed the built-in `max`." - assert _run(m.run_station, hint="Three scope bugs are hiding here.") == ( - "Checks: 3 | Passed: 2 | Peak: 91" - )