From 76f850f4ec1597cc051ebadfe47c42a1b7065c3e Mon Sep 17 00:00:00 2001 From: gavvahar Date: Mon, 16 Jun 2025 23:27:54 -0400 Subject: [PATCH 1/6] updating import since clock has been removed since python 3.8 --- src/clonenames/clonenames.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clonenames/clonenames.py b/src/clonenames/clonenames.py index 76b2915..d9acea1 100644 --- a/src/clonenames/clonenames.py +++ b/src/clonenames/clonenames.py @@ -51,8 +51,8 @@ def check_size(self, size: int) -> None: self.length = int(self.size ** 0.5) def load_words(self) -> None: - from time import clock - random.seed(clock()) + from time import perf_counter + random.seed(perf_counter()) self.COLORS = [u'red', u'blue', u'green', u'yellow'] random.shuffle(self.COLORS) From 0b88da4c761221fd7d42e3bb1e3250635ba5c159 Mon Sep 17 00:00:00 2001 From: gavvahar Date: Wed, 18 Jun 2025 15:32:21 -0400 Subject: [PATCH 2/6] add .lh to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f8c1b9b..41aeb85 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ dmypy.json # Pyre type checker .pyre/ +.lh From 91e4acc364bf444ce1a4a45d1006776b8d3461c8 Mon Sep 17 00:00:00 2001 From: gavvahar Date: Wed, 18 Jun 2025 15:32:32 -0400 Subject: [PATCH 3/6] add Dockerfile, docker-compose.yml, and .dockerignore; refactor web.py for consistency --- .dockerignore | 10 ++++ Dockerfile | 21 +++++++ docker-compose.yml | 10 ++++ src/clonenames/web.py | 135 ++++++++++++++++++++++-------------------- 4 files changed, 112 insertions(+), 64 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a90a99f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +env/ +venv/ +.git +.gitignore +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..41cc008 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.12-slim + + +# Upgrade pip and system packages to reduce vulnerabilities +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y --no-install-recommends gcc build-essential && \ + python3 -m pip install --upgrade pip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +COPY requirements.txt ./ +RUN python3 -m pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 5000 + +CMD ["python3", "web.py"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..eff589f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: "3.12" + +services: + clonenames: + build: . + ports: + - "5000:5000" + environment: + - PYTHONUNBUFFERED=1 + restart: unless-stopped diff --git a/src/clonenames/web.py b/src/clonenames/web.py index adaf3b9..4126062 100644 --- a/src/clonenames/web.py +++ b/src/clonenames/web.py @@ -25,77 +25,80 @@ games = dict() -@app.route(u'/') +@app.route("/") def home_page(): - return render_template(u'index.html') + return render_template("index.html") -@app.route(u'/start', methods = [u'GET', u'POST']) +@app.route("/start", methods=["GET", "POST"]) def start_page(): - if request.method == u'POST': - game = clonenames.Board(request.form.get(u'words')) + if request.method == "POST": + game = clonenames.Board(request.form.get("words")) success = game.load_settings( - teams = int(request.form.get(u'number')), - size = int(request.form.get(u'size'))) + teams=int(request.form.get("number")), size=int(request.form.get("size")) + ) if success: room = generate_room_code() games[room] = game - return redirect(url_for(u'game_page', room = room)) + return redirect(url_for("game_page", room=room)) else: return render_template( - u'start.html', - words = clonenames.wordlists, - alert = u'The word list selected must be played on a smaller game board... Sorry!') + "start.html", + words=clonenames.wordlists, + alert="The word list selected must be played on a smaller game board... Sorry!", + ) - elif request.method == u'GET': - return render_template(u'start.html', words = wordlists) + elif request.method == "GET": + return render_template("start.html", words=wordlists) -@app.route(u'/game', methods = [u'GET', u'POST']) +@app.route("/game", methods=["GET", "POST"]) def game_page(): - if request.args.get(u'room'): - room = request.args.get(u'room') + if request.args.get("room"): + room = request.args.get("room") return render_template( - u'game.html', - show_input = False, - room = room, - host = True, - words = games[room].table(), - start = games[room].order[0], - remnants = games[room].remnants) + "game.html", + show_input=False, + room=room, + host=True, + words=games[room].table(), + start=games[room].order[0], + remnants=games[room].remnants, + ) else: try: - if request.method == u'GET': - return render_template( - u'game.html', - show_input = True) + if request.method == "GET": + return render_template("game.html", show_input=True) - elif request.method == u'POST': - room = request.form.get(u'room', False).upper() + elif request.method == "POST": + room = request.form.get("room", False).upper() if check_room_code(room): return render_template( - u'game.html', - show_input = False, - room = room, - host = request.form.get(u'host', False) == u'on', - words = games[room].table(), - start = games[room].order[0], - remnants = games[room].remnants) + "game.html", + show_input=False, + room=room, + host=request.form.get("host", False) == "on", + words=games[room].table(), + start=games[room].order[0], + remnants=games[room].remnants, + ) else: return render_template( - u'game.html', - show_input = True, - alert = u'The room code you entered does not exist. Please try again!') + "game.html", + show_input=True, + alert="The room code you entered does not exist. Please try again!", + ) except AttributeError: - return redirect(url_for(u'home_page')) + return redirect(url_for("home_page")) + # @app.route(u'/statistics') # def stats_page(): @@ -103,38 +106,42 @@ def game_page(): # rooms = [games[game].statistics() for game in games]) -@socketio.on(u'join') +@socketio.on("join") def join(data): - join_room(data[u'room']) + join_room(data["room"]) -@socketio.on(u'clicked') +@socketio.on("clicked") def handle_host_click(json): - response = games[json[u'room']].get(json[u'id']) - socketio.emit(u'revealed', { - u'text': u'Host clicked on {word}'.format( - word = response[u'word']), - u'id': u'#{id}'.format(id = json[u'id']), - u'remnant': response[u'remnant'], - u'class': u'btn-{team}'.format( - team = response[u'team'])}, room = json['room']) - - -@socketio.on(u'ended_turn') + response = games[json["room"]].get(json["id"]) + socketio.emit( + "revealed", + { + "text": "Host clicked on {word}".format(word=response["word"]), + "id": "#{id}".format(id=json["id"]), + "remnant": response["remnant"], + "class": "btn-{team}".format(team=response["team"]), + }, + room=json["room"], + ) + + +@socketio.on("ended_turn") def handle_end_turn(json): - team = games[json[u'room']].advance_turn() + team = games[json["room"]].advance_turn() - alert = u'alert {team}-start alert-start'.format(team = team) - button = u'btn btn-{team} float-right'.format(team = team) + alert = "alert {team}-start alert-start".format(team=team) + button = "btn btn-{team} float-right".format(team=team) - socketio.emit(u'change_turn', { - u'alert': alert, - u'text': team, - u'button': button}, room = json[u'room']) + socketio.emit( + "change_turn", + {"alert": alert, "text": team, "button": button}, + room=json["room"], + ) def generate_room_code(): - letters = u''.join(random.sample(list(u'ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 5)) + letters = "".join(random.sample(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 5)) while letters in games.keys(): return generate_room_code() @@ -145,5 +152,5 @@ def check_room_code(code): return code in games.keys() -def run(): - socketio.run(app, debug=True, host=u'0.0.0.0', port=12345) +if __name__ == '__main__': + socketio.run(app, debug=True, host=u'0.0.0.0') From e8d43ee2d5c6ab42997d6f1d22c323ddc1a3768a Mon Sep 17 00:00:00 2001 From: Brendan Cazier <520246+cazier@users.noreply.github.com> Date: Fri, 4 Jul 2025 09:45:54 -0400 Subject: [PATCH 4/6] Merge conflicts --- .gitignore | 1 - docker-compose.yml | 10 ---------- src/clonenames/web.py | 4 ++-- 3 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 docker-compose.yml diff --git a/.gitignore b/.gitignore index 41aeb85..f8c1b9b 100644 --- a/.gitignore +++ b/.gitignore @@ -117,4 +117,3 @@ dmypy.json # Pyre type checker .pyre/ -.lh diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index eff589f..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: "3.12" - -services: - clonenames: - build: . - ports: - - "5000:5000" - environment: - - PYTHONUNBUFFERED=1 - restart: unless-stopped diff --git a/src/clonenames/web.py b/src/clonenames/web.py index 4126062..50cca4b 100644 --- a/src/clonenames/web.py +++ b/src/clonenames/web.py @@ -152,5 +152,5 @@ def check_room_code(code): return code in games.keys() -if __name__ == '__main__': - socketio.run(app, debug=True, host=u'0.0.0.0') +if __name__ == "__main__": + socketio.run(app, debug=False, host="0.0.0.0") From 8c4a38c8e91be4324f3d45b67c59f01999ed4315 Mon Sep 17 00:00:00 2001 From: Brendan Cazier <520246+cazier@users.noreply.github.com> Date: Fri, 4 Jul 2025 10:00:47 -0400 Subject: [PATCH 5/6] Moving dockerfile to uv --- Dockerfile | 21 ++++++++++----------- src/clonenames/web.py | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 41cc008..4e54703 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,20 @@ FROM python:3.12-slim - +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/ # Upgrade pip and system packages to reduce vulnerabilities -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install -y --no-install-recommends gcc build-essential && \ - python3 -m pip install --upgrade pip && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* +# RUN apt-get update && \ +# apt-get upgrade -y && \ +# apt-get install -y --no-install-recommends gcc build-essential && \ +# python3 -m pip install --upgrade pip && \ +# apt-get clean && \ +# rm -rf /var/lib/apt/lists/* WORKDIR /app -COPY requirements.txt ./ -RUN python3 -m pip install --no-cache-dir -r requirements.txt - COPY . . +RUN uv sync --locked --no-dev + EXPOSE 5000 -CMD ["python3", "web.py"] +CMD ["uv", "run", "clonenames"] diff --git a/src/clonenames/web.py b/src/clonenames/web.py index 50cca4b..146547b 100644 --- a/src/clonenames/web.py +++ b/src/clonenames/web.py @@ -152,5 +152,5 @@ def check_room_code(code): return code in games.keys() -if __name__ == "__main__": +def run(): socketio.run(app, debug=False, host="0.0.0.0") From db28bc83d05ede5028a5d17efccf8c979c1733db Mon Sep 17 00:00:00 2001 From: Brendan Cazier <520246+cazier@users.noreply.github.com> Date: Fri, 4 Jul 2025 10:02:36 -0400 Subject: [PATCH 6/6] Some cleanup --- Dockerfile | 8 -------- pyproject.toml | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e54703..009c734 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,6 @@ FROM python:3.12-slim COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/ -# Upgrade pip and system packages to reduce vulnerabilities -# RUN apt-get update && \ -# apt-get upgrade -y && \ -# apt-get install -y --no-install-recommends gcc build-essential && \ -# python3 -m pip install --upgrade pip && \ -# apt-get clean && \ -# rm -rf /var/lib/apt/lists/* - WORKDIR /app COPY . . diff --git a/pyproject.toml b/pyproject.toml index 073e3e8..17276ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,9 +25,9 @@ dev = [ "ruff>=0.12.0", ] -# BUILDING -[tool.setuptools] -packages = ["clonenames"] +# # BUILDING +# [tool.setuptools] +# packages = ["clonenames"] # FORMATTING [tool.ruff]