Skip to content

feat: overall progress, completion celebration, first-launch welcome (#14, #15, #16)#31

Merged
abhiksark merged 2 commits into
mainfrom
feature/tui-progress-and-welcome
Jun 21, 2026
Merged

feat: overall progress, completion celebration, first-launch welcome (#14, #15, #16)#31
abhiksark merged 2 commits into
mainfrom
feature/tui-progress-and-welcome

Conversation

@abhiksark

@abhiksark abhiksark commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Closes #14
Closes #15
Closes #16

Re-implements the three still-novel 0.3.0 TUI features on top of v0.4.0, after the pylingspythonlings rename made the original PRs (#20/#21) unmergeable. #13 was dropped — main's zero-config first-run already covers it. Built test-first (TDD); the code-review findings from the original PRs are incorporated.

#15 — overall progress

The progress bar now shows overall curriculum progress alongside the current topic. New pure format_progress(); new core.state.completed_count() counts only curriculum members, so stale state (renamed/removed exercises) can't push the display past 100% — fixes the >100% finding from the original review.

#16 — completion celebration

Finishing the final pending exercise overall shows a celebration (count, shareable line, ⭐ nudge) instead of the topic-complete message. Gated on next_pending(manifest.exercises, completed) is None → fires exactly once at true 100%; non-blocking.

#14 — first-launch welcome

On a genuine first launch (and only when launching into an exercise) a dismissible overlay explains the loop + key shortcuts. Reuses the persisted seen_intro flag (shows once); Enter/Esc to dismiss. Not shown for pythonlings topics (the picker already has its first-run banner).

Tests

9 new tests (format_progress, completed_count incl. stale-entry case, celebration_message, welcome content, 3 welcome pilot tests). Full suite 136 → 145 passed, verified on Python 3.9 and 3.13.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a welcome screen displayed on first launch to guide new users
    • Enhanced progress display to show both current topic progress and overall curriculum completion
    • Added celebratory message upon completing the entire curriculum
  • Tests

    • Added comprehensive test coverage for welcome screen, progress tracking, and completion behavior

Closes #15, closes #16. Re-implemented on v0.4.0 after the pylings->pythonlings
rename (the original PRs #20/#21 were built on the old layout).

- #15: the progress bar now shows overall curriculum progress alongside the
  current topic. New pure format_progress() in widgets/progress.py; new
  core.state.completed_count() counts only curriculum members so stale state
  (renamed/removed exercises) can't push the display past 100% — addresses a
  code-review finding on the original PR.
- #16: finishing the final pending exercise overall shows a celebration
  (count, shareable line, star nudge) instead of the topic-complete message;
  gated on next_pending(manifest.exercises, completed) is None, so it fires
  exactly once at true 100% and stays non-blocking.
- Unit tests for format_progress, completed_count (incl. stale-entry case),
  and celebration_message.
Closes #14. Re-implemented on v0.4.0.

On a genuine first launch (no prior progress) and only when launching into an
exercise, pythonlings shows a dismissible welcome overlay explaining the loop
(edit -> save -> check reruns -> remove '# I AM NOT DONE' to advance) plus the
key shortcuts. Reuses the persisted state.seen_intro flag so it shows once;
dismiss with Enter/Esc; non-blocking. Not shown for 'pythonlings topics', which
already has the picker's first-run banner.

The shared pilot helper now seeds seen_intro so returning-user tests are
unaffected; the first-run banner test keeps genuine first-run state. Centered
modal styling mirrors the docs window.
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds three first-run and retention features: a WelcomeScreen modal displayed on first launch (persisting a seen_intro flag), a dual-line progress bar showing both per-topic and overall curriculum progress via a new format_progress helper and completed_count state function, and a full-curriculum celebration_message shown in TrackScreen when all exercises are complete.

Changes

Welcome Screen, Overall Progress Bar, and Celebration Message

Layer / File(s) Summary
completed_count helper and dual-track progress bar
pythonlings/core/state.py, pythonlings/widgets/progress.py, tests/unit/test_progress.py
completed_count is added to count only curriculum-present exercise names from a completed set. format_progress is introduced to render a two-line topic-and-overall progress string, and ProgressBar.update_progress is extended to accept and display both counts. Unit tests cover output format, zero totals, and stale-entry filtering.
WelcomeScreen modal and stylesheet
pythonlings/screens/welcome.py, pythonlings/pythonlings.tcss, tests/unit/test_welcome.py
welcome_text() returns the onboarding copy; WelcomeScreen composes it as a ModalScreen[None] with title/body/footer widgets. action_start() sets seen_intro=True, persists state, and dismisses. Stylesheet adds centered layout and widget styling. Unit test validates welcome_text content.
TrackScreen overall progress and celebration
pythonlings/screens/track.py, tests/unit/test_celebration.py
Imports completed_count; adds celebration_message() for full-curriculum completion text. _render_state computes overall completion and passes it to ProgressBar.update_progress. End-of-topic branching shows celebration_message when no pending exercises remain globally, otherwise shows a topic-complete hint. Unit test verifies emoji and count in celebration output.
App wiring and TUI pilot tests
pythonlings/app.py, tests/tui/test_app_pilot.py, tests/tui/test_welcome_pilot.py
on_mount gains a first_launch flag from seen_intro and conditionally pushes WelcomeScreen after TrackScreen on first launch. Existing _work_copy seeds seen_intro=True; one test uses raw copytree to preserve genuine first-run state. New test_welcome_pilot.py covers: first launch shows WelcomeScreen, seen_intro=True suppresses it, and pressing Enter persists seen_intro in saved state.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant App
  participant WelcomeScreen
  participant TrackScreen
  participant ProgressBar
  participant StateModule

  User->>App: Launch (first run)
  App->>TrackScreen: push_screen(topic, exercise)
  App->>WelcomeScreen: push_screen (first_launch=True)
  WelcomeScreen-->>User: Show onboarding modal
  User->>WelcomeScreen: Press Enter
  WelcomeScreen->>StateModule: seen_intro=True then save_state
  WelcomeScreen->>App: dismiss()

  User->>TrackScreen: Complete an exercise
  TrackScreen->>StateModule: completed_count(all_exercises, state.completed)
  StateModule-->>TrackScreen: overall_completed int
  TrackScreen->>ProgressBar: update_progress(topic_done, topic_total, overall_done, overall_total)
  ProgressBar-->>User: Two-line topic and overall progress bar

  alt All exercises complete
    TrackScreen-->>User: celebration_message(total)
  else Topic complete only
    TrackScreen-->>User: Topic complete with F4 hint
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #14 (Add a first-launch welcome/onboarding screen): Directly implemented — WelcomeScreen modal shown on first launch, seen_intro flag persisted to state, dismissible via Enter/Escape, and integrated into app.on_mount.
  • #15 (Show overall curriculum progress in the TUI): Directly implemented — ProgressBar.update_progress extended to show both per-topic and overall curriculum progress using the new completed_count helper and format_progress renderer.
  • #16 (Add an all-exercises-complete celebration screen): Directly implemented — celebration_message(total) added to TrackScreen, shown when next_pending returns no remaining exercises across the whole manifest.

Poem

🐇 Hop, hop, hooray — a welcome at the door,
The bar shows two tracks now, not just one before.
Edit, save, and watch the checks rerun with glee,
Remove I AM NOT DONE and set your progress free!
When all 292 are done, the emoji 🎉 appears —
A rabbit claps its paws and celebrates for years.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the three main features implemented: overall progress, completion celebration, and first-launch welcome, with explicit issue references.
Description check ✅ Passed The description covers all required template sections (Summary, Tests, Checklist) and provides detailed explanations of the three features and their implementations.
Linked Issues check ✅ Passed All three linked issues (#14, #15, #16) are fully addressed: first-launch welcome with dismissible overlay [#14], overall curriculum progress tracking [#15], and completion celebration on 100% [#16].
Out of Scope Changes check ✅ Passed All changes directly support the three linked issues; test infrastructure updates are necessary for validating the new features and pose no scope concerns.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/tui-progress-and-welcome

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pythonlings/screens/track.py`:
- Around line 195-203: The else branch in track.py calls show_final() which
displays a global completion header, creating misleading messaging when only the
current topic is complete. Create a new method show_topic_complete() in the
OutputPanel class in pythonlings/widgets/output_panel.py that matches the
behavior of show_final() but sets the header to "Topic complete" instead of the
global completion header. Then replace the show_final() call in the else branch
with a call to this new show_topic_complete() method, passing the topic
completion message.

In `@pythonlings/screens/welcome.py`:
- Around line 18-19: The onboarding message on line 18 contains contradictory
instructions that say to save but then state checks rerun "as you type", which
conflicts with the save-driven loop workflow. Update the welcome screen message
text to clarify that checks rerun when you save (remove the "as you type"
phrase) so the instructions are consistent with the actual save-driven behavior
and align with the PR objectives. The message is part of a string literal in the
welcome.py file that instructs users on the workflow.
- Around line 29-32: The BINDINGS class attribute is defined as a list, which is
a mutable shared class attribute that triggers the RUF012 linting rule and can
cause unintended mutations. Convert the BINDINGS list to a tuple by replacing
the square brackets with parentheses around the Binding declarations, keeping
all the Binding elements unchanged.

In `@tests/tui/test_welcome_pilot.py`:
- Around line 1-3: The test_welcome_pilot.py module is missing the required
future-annotations import at the top. Add `from __future__ import annotations`
as the very first line in the file, before the existing imports of shutil and
pathlib.Path, to comply with the coding guidelines that require this import in
all Python modules.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 75663634-681f-4b8f-834b-713b6d23e2d9

📥 Commits

Reviewing files that changed from the base of the PR and between 23fff91 and 99b581d.

📒 Files selected for processing (11)
  • pythonlings/app.py
  • pythonlings/core/state.py
  • pythonlings/pythonlings.tcss
  • pythonlings/screens/track.py
  • pythonlings/screens/welcome.py
  • pythonlings/widgets/progress.py
  • tests/tui/test_app_pilot.py
  • tests/tui/test_welcome_pilot.py
  • tests/unit/test_celebration.py
  • tests/unit/test_progress.py
  • tests/unit/test_welcome.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
tests/unit/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Keep unit tests in tests/unit/ directory

Files:

  • tests/unit/test_celebration.py
  • tests/unit/test_welcome.py
  • tests/unit/test_progress.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use Python 3.11+ idioms in all Python code
Use 4-space indentation in all Python code
Prefer small, typed functions where practical in Python code

**/*.py: Guard newer-stdlib usage with requires-python = ">=3.9" and use fallbacks (e.g. tomllib falls back to tomli) in modules like core/manifest.py
Include from __future__ import annotations at the top of Python modules

Files:

  • tests/unit/test_celebration.py
  • tests/unit/test_welcome.py
  • tests/unit/test_progress.py
  • pythonlings/screens/welcome.py
  • tests/tui/test_app_pilot.py
  • pythonlings/core/state.py
  • pythonlings/app.py
  • tests/tui/test_welcome_pilot.py
  • pythonlings/widgets/progress.py
  • pythonlings/screens/track.py
tests/**/*test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

Name test files as test_<behavior>.py

Files:

  • tests/unit/test_celebration.py
  • tests/unit/test_welcome.py
  • tests/unit/test_progress.py
  • tests/tui/test_app_pilot.py
  • tests/tui/test_welcome_pilot.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.py: Name test functions as test_<expected_behavior>
Use pytest for all tests with pytest-asyncio in auto mode for async tests

Files:

  • tests/unit/test_celebration.py
  • tests/unit/test_welcome.py
  • tests/unit/test_progress.py
  • tests/tui/test_app_pilot.py
  • tests/tui/test_welcome_pilot.py
**/test_*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Name tests as test_<behavior>.py or test_<expected_behavior> (e.g., test_runner.py, test_state.py)

Files:

  • tests/unit/test_celebration.py
  • tests/unit/test_welcome.py
  • tests/unit/test_progress.py
  • tests/tui/test_app_pilot.py
  • tests/tui/test_welcome_pilot.py
pythonlings/pythonlings.tcss

📄 CodeRabbit inference engine (AGENTS.md)

TUI styles must be defined in pythonlings/pythonlings.tcss

Files:

  • pythonlings/pythonlings.tcss
pythonlings/{screens,widgets}/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Textual screens and widgets must live in pythonlings/screens/ and pythonlings/widgets/ directories

Files:

  • pythonlings/screens/welcome.py
  • pythonlings/widgets/progress.py
  • pythonlings/screens/track.py
pythonlings/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Keep UI behavior in screens/ or widgets/ directories; keep filesystem, manifest, reset, and runner behavior in core/

Files:

  • pythonlings/screens/welcome.py
  • pythonlings/core/state.py
  • pythonlings/app.py
  • pythonlings/widgets/progress.py
  • pythonlings/screens/track.py
tests/tui/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Keep TUI tests in tests/tui/ directory

Files:

  • tests/tui/test_app_pilot.py
  • tests/tui/test_welcome_pilot.py
pythonlings/core/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Core exercise loading, workspace setup, state, reset, solutions, and runner logic must live in pythonlings/core/ directory

Keep UI behavior in screens/ and widgets/ modules; keep behavior logic in core/ modules—do not import UI in core

Files:

  • pythonlings/core/state.py
🪛 Ruff (0.15.17)
pythonlings/screens/welcome.py

[warning] 29-32: Mutable default value for class attribute

(RUF012)

🔇 Additional comments (5)
pythonlings/screens/track.py (1)

13-13: LGTM!

Also applies to: 22-30, 96-102

tests/unit/test_celebration.py (1)

1-10: LGTM!

pythonlings/app.py (1)

31-40: LGTM!

tests/tui/test_app_pilot.py (1)

23-25: LGTM!

Also applies to: 75-78

tests/tui/test_welcome_pilot.py (1)

4-63: LGTM!

Comment on lines +195 to +203
all_exercises = self.app.manifest.exercises
if next_pending(all_exercises, self.app.state.completed) is None:
self.query_one(OutputPanel).show_final(
celebration_message(len(all_exercises))
)
else:
self.query_one(OutputPanel).show_final(
f"Topic '{self.topic}' complete — press F4 for topics."
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Topic-only completion still renders a global “All exercises complete” header.

In the else branch (not fully complete curriculum), show_final(...) is still used. That method hardcodes the global completion header in pythonlings/widgets/output_panel.py, so users can see a misleading completion state when only the current topic is done.

Suggested direction
-                self.query_one(OutputPanel).show_final(
+                self.query_one(OutputPanel).show_topic_complete(
                     f"Topic '{self.topic}' complete — press F4 for topics."
                 )
# pythonlings/widgets/output_panel.py (new helper)
def show_topic_complete(self, message: str) -> None:
    self.remove_class("failed", "pending")
    self.add_class("passed")
    self.query_one("`#hint`", Static).remove_class("visible")
    self.query_one("`#output-header`", Static).update("[bold green]Topic complete[/bold green]")
    self.query_one("`#goal`", Static).update("")
    self.query_one("`#docs`", Static).update("")
    self.query_one("`#status`", Static).update(message)
    self.query_one("`#next-step`", Static).update("")
    self.query_one("`#details`", Static).update("")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pythonlings/screens/track.py` around lines 195 - 203, The else branch in
track.py calls show_final() which displays a global completion header, creating
misleading messaging when only the current topic is complete. Create a new
method show_topic_complete() in the OutputPanel class in
pythonlings/widgets/output_panel.py that matches the behavior of show_final()
but sets the header to "Topic complete" instead of the global completion header.
Then replace the show_final() call in the else branch with a call to this new
show_topic_complete() method, passing the topic completion message.

Comment on lines +18 to +19
" 2. Save -- the check reruns automatically as you type.\n"
" 3. Remove the `# I AM NOT DONE` marker to advance to the next one.\n\n"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify the onboarding loop sentence to remove contradictory behavior.

Line 18 says users should save, then says checks rerun “as you type,” which conflicts with the save-driven loop described in the PR objectives.

Proposed copy tweak
-        "  2. Save -- the check reruns automatically as you type.\n"
+        "  2. Save -- checks rerun automatically.\n"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
" 2. Save -- the check reruns automatically as you type.\n"
" 3. Remove the `# I AM NOT DONE` marker to advance to the next one.\n\n"
" 2. Save -- checks rerun automatically.\n"
" 3. Remove the `# I AM NOT DONE` marker to advance to the next one.\n\n"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pythonlings/screens/welcome.py` around lines 18 - 19, The onboarding message
on line 18 contains contradictory instructions that say to save but then state
checks rerun "as you type", which conflicts with the save-driven loop workflow.
Update the welcome screen message text to clarify that checks rerun when you
save (remove the "as you type" phrase) so the instructions are consistent with
the actual save-driven behavior and align with the PR objectives. The message is
part of a string literal in the welcome.py file that instructs users on the
workflow.

Comment on lines +29 to +32
BINDINGS = [
Binding("enter", "start", "Start", priority=True),
Binding("escape", "start", "Start"),
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n pythonlings/screens/welcome.py | sed -n '25,35p'

Repository: abhiksark/pythonlings

Length of output: 444


🌐 Web query:

Ruff RUF012 rule mutable class attribute list comprehension

💡 Result:

The Ruff rule RUF012, titled "mutable-class-default," identifies mutable default values assigned to class attributes [1]. Such attributes are shared across all instances of the class, which can lead to unintended side effects where changes in one instance unexpectedly impact others [1]. While the rule is commonly triggered by simple assignments like my_list: list[int] = [], it also applies to list comprehensions or any other expressions that result in a mutable data structure [1][2]. To resolve RUF012 violations, consider the following approaches: 1. Initialize in init: Move the assignment into the class constructor (init) so that each instance gets its own unique, mutable object [1][3]. 2. Use typing.ClassVar: If the attribute is intentionally meant to be shared across all instances, annotate it with typing.ClassVar to explicitly signal this intent [1]. 3. Use immutable types: Replace the mutable structure with an immutable alternative, such as a tuple instead of a list [1]. 4. Use Optional: Assign None as the default value and handle initialization within the class logic [1][3]. Note that RUF012 generally excludes certain frameworks—such as Pydantic or msgspec—that have built-in copy semantics for their model fields, as these frameworks automatically handle the instantiation of unique values [2][4]. Diagnostic messages for this rule typically suggest these fixes to help you choose the most appropriate pattern for your code [5][6].

Citations:


🏁 Script executed:

rg "BINDINGS\s*=" pythonlings/ -A 2

Repository: abhiksark/pythonlings

Length of output: 912


🌐 Web query:

Textual framework BINDINGS class attribute mutable RUF012

💡 Result:

In the Ruff linter, RUF012 is a rule that identifies mutable default values in class attributes [1][2]. What it does: It flags class attributes that are assigned mutable data structures (such as lists, sets, or dictionaries) directly in the class body [1][2]. Because these objects are created when the class is defined, they are shared across all instances of that class, which often leads to unintended side effects when one instance modifies the shared state [1][2]. Why it is flagged: Mutable default values in class bodies are generally considered an anti-pattern because they create implicit shared state between instances [1]. Common fixes: - Initialize the attribute in the class's init method, which ensures each instance gets its own unique copy of the mutable structure [1][3]. - Annotate the attribute with typing.ClassVar if you explicitly intend for the variable to be shared across all instances [1]. - Use an immutable type, such as a tuple instead of a list, or types.MappingProxyType for dictionaries [1][3]. - Use None as the default value and initialize the object within init [1][3]. Note: The diagnostic message and documentation for RUF012 were improved to clarify these options, as previous versions primarily suggested ClassVar even when initialization in init was the preferred architectural fix [4][5][6]. The rule generally excludes specific frameworks or patterns where default values are intentionally copied on instance creation (e.g., certain uses of Pydantic or msgspec) [7].

Citations:


Use a tuple instead of a list for the BINDINGS class attribute to avoid Ruff RUF012 and prevent accidental mutation.

The list-based BINDINGS is a mutable class attribute shared across all instances, which triggers the RUF012 rule and can lead to unintended side effects.

Suggested change
-    BINDINGS = [
+    BINDINGS = (
         Binding("enter", "start", "Start", priority=True),
         Binding("escape", "start", "Start"),
-    ]
+    )
🧰 Tools
🪛 Ruff (0.15.17)

[warning] 29-32: Mutable default value for class attribute

(RUF012)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pythonlings/screens/welcome.py` around lines 29 - 32, The BINDINGS class
attribute is defined as a list, which is a mutable shared class attribute that
triggers the RUF012 linting rule and can cause unintended mutations. Convert the
BINDINGS list to a tuple by replacing the square brackets with parentheses
around the Binding declarations, keeping all the Binding elements unchanged.

Source: Linters/SAST tools

Comment on lines +1 to +3
import shutil
from pathlib import Path

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add from __future__ import annotations at the module top.

This new Python module is missing the required future-annotations import.

Proposed fix
+from __future__ import annotations
+
 import shutil
 from pathlib import Path

As per coding guidelines, **/*.py: Include from __future__ import annotations at the top of Python modules.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import shutil
from pathlib import Path
from __future__ import annotations
import shutil
from pathlib import Path
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/tui/test_welcome_pilot.py` around lines 1 - 3, The
test_welcome_pilot.py module is missing the required future-annotations import
at the top. Add `from __future__ import annotations` as the very first line in
the file, before the existing imports of shutil and pathlib.Path, to comply with
the coding guidelines that require this import in all Python modules.

Source: Coding guidelines

@abhiksark abhiksark merged commit 29e29bb into main Jun 21, 2026
4 checks passed
@abhiksark abhiksark deleted the feature/tui-progress-and-welcome branch June 21, 2026 14:09
abhiksark added a commit that referenced this pull request Jun 21, 2026
…elcome-copy

fix: topic-complete header + welcome copy (CodeRabbit follow-up to #31)
@abhiksark abhiksark mentioned this pull request Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an all-exercises-complete celebration screen Show overall curriculum progress in the TUI Add a first-launch welcome/onboarding screen

1 participant