Remove comments from python files.

This commit is contained in:
retoor 2025-06-07 11:43:44 +02:00
parent daf77f0ba2
commit 00b5d2d903
2 changed files with 74 additions and 21 deletions

53
pf.py Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
import argparse
import tokenize
import io
import sys
def remove_comments_from_code(source_code):
tokens = tokenize.generate_tokens(io.StringIO(source_code).readline)
tokens_no_comments = [
token for token in tokens if token.type != tokenize.COMMENT
]
return tokenize.untokenize(tokens_no_comments)
def main():
parser = argparse.ArgumentParser(
description='Remove all comments from a Python file using tokenize.'
)
parser.add_argument(
'input_file',
help='Path to the target Python file.'
)
parser.add_argument(
'output_file',
nargs='?',
help='Path to save the cleaned Python file. If omitted, prints to stdout.'
)
args = parser.parse_args()
try:
with open(args.input_file, 'r', encoding='utf-8') as f:
source_code = f.read()
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error reading file: {e}", file=sys.stderr)
sys.exit(1)
cleaned_code = remove_comments_from_code(source_code)
if args.output_file:
try:
with open(args.output_file, 'w', encoding='utf-8') as f:
f.write(cleaned_code)
except Exception as e:
print(f"Error writing file: {e}", file=sys.stderr)
sys.exit(1)
else:
print(cleaned_code)
if __name__ == '__main__':
main()

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3
"""
vim_terminal_trainer.py *v2*
================================
@ -35,7 +35,7 @@ import time
from pathlib import Path
from typing import Dict, List, Tuple
# ------------------- DATA & CONFIG -----------------------------------------
DEFAULT_QUESTIONS: List[Dict[str, object]] = [
{"task": "Delete (cut) the current line in Vim", "answers": ["dd"]},
@ -462,7 +462,7 @@ TIME_LIMIT_SEC = 15
DATA_DIR = Path.home() / ".vim_terminal_trainer"
SCORE_FILE = DATA_DIR / "score.json"
# ------------------- PERSISTENCE -------------------------------------------
def load_score() -> Dict[str, int]:
@ -485,7 +485,7 @@ def save_score(high: int, played: int) -> None:
json.dump({"high_score": high, "games_played": played}, f)
# ------------------- CURSES UI HELPERS -------------------------------------
def draw_centered(
@ -506,7 +506,7 @@ def render_timer(stdscr: "curses._CursesWindow", remaining: float) -> None:
stdscr.addstr(0, 0, f"⏰[{bar}] {remaining:4.1f}s")
# ------------------- GAMEPLAY ----------------------------------------------
def sanitize_question(q):
"""Return a dict with keys 'task' and 'answers' no matter what comes in."""
if isinstance(q, dict):
@ -524,20 +524,20 @@ def ask_question_curses(
idx: int,
total: int,
) -> bool:
q = sanitize_question(q) # ← new normalise input
q = sanitize_question(q)
stdscr.clear()
h, w = stdscr.getmaxyx()
# Header
header = f"Question {idx}/{total} Type the command:"
draw_centered(stdscr, 2, header, bold=True)
# Task text (wrapped)
wrapped = textwrap.fill(q["task"], width=min(70, w - 4))
for i, line in enumerate(wrapped.splitlines(), start=4):
draw_centered(stdscr, i, line)
# Input prompt area
input_y = 6 + wrapped.count("\n")
stdscr.addstr(input_y, 2, " ")
stdscr.refresh()
@ -558,46 +558,46 @@ def ask_question_curses(
if remaining <= 0:
return False
# Nonblocking read (100ms chunks)
stdscr.timeout(100)
ch = stdscr.getch()
if ch == -1:
continue # no keypress yet
continue
if ch in (curses.KEY_BACKSPACE, 127, 8):
buffer = buffer[:-1]
continue
if ch in (10, 13):
# User pressed Return anyway treat as submission
break
if 0 <= ch <= 255:
buffer += chr(ch)
# Autocheck
norm = " ".join(buffer.split())
if norm in valid:
# Flash feedback
curses.curs_set(0)
stdscr.addstr(input_y + 1, 4, "✅ Correct!", curses.A_BOLD)
stdscr.refresh()
time.sleep(0.4)
return True
# Trim oversized buffer to keep UI tidy
if len(buffer) > longest + 5:
buffer = buffer[-(longest + 5) :]
# Manual submission (Return) or timeout
norm = " ".join(buffer.split())
return norm in valid
# -----------------------------------------------------------------------------
def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) -> None:
score_data = load_score()
curses.curs_set(0)
# Ask number of questions (simple prompt outside curses because of text input)
curses.endwin()
try:
q_default = 10 if len(pool) >= 10 else len(pool)
@ -606,7 +606,7 @@ def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) ->
num_q = q_default
num_q = max(1, min(num_q, len(pool)))
# Back into curses
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
@ -619,7 +619,7 @@ def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) ->
if ask_question_curses(stdscr, q, idx, num_q):
correct += 1
# Final screen
stdscr.clear()
result_text = f"You scored {correct}/{num_q}!"
draw_centered(stdscr, 3, result_text, bold=True)
@ -640,7 +640,7 @@ def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) ->
stdscr.getch()
# ------------------- MAIN ---------------------------------------------------
def main_menu() -> None: