Skip to content

Commit

Permalink
Pylint
Browse files Browse the repository at this point in the history
  • Loading branch information
cherriae committed Nov 19, 2024
1 parent 988f4b5 commit b204c42
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 59 deletions.
5 changes: 3 additions & 2 deletions app/app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from bson import ObjectId
from flask import Flask, render_template
from flask_login import LoginManager
from flask_pymongo import PyMongo
Expand All @@ -21,7 +20,9 @@ def create_app():
SECRET_KEY=os.getenv("SECRET_KEY", "team334"),
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SECURE=True,
MONGO_URI=os.getenv("MONGO_URI", "mongodb://localhost:27017/scouting_app"),
MONGO_URI=os.getenv(
"MONGO_URI", "mongodb://localhost:27017/scouting_app"
),
)

mongo.init_app(app)
Expand Down
11 changes: 0 additions & 11 deletions app/auth/__init__.py

This file was deleted.

17 changes: 11 additions & 6 deletions app/auth/auth_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ async def wrapper(*args, **kwargs):
last_error = e
if attempt < retries - 1: # don't sleep on last attempt
logger.warning(
f"Attempt {attempt + 1} failed: {str(e)}. Retrying..."
f"Attempt {attempt + 1} failed: {str(e)}."
)
time.sleep(delay)
else:
logger.error(f"All {retries} attempts failed: {str(e)}")
logger.error(
f"All {retries} attempts failed: {str(e)}")
raise last_error

return wrapper
Expand Down Expand Up @@ -56,7 +57,8 @@ def connect(self):
"""Establish connection to MongoDB with basic error handling"""
try:
if self.client is None:
self.client = MongoClient(self.mongo_uri, serverSelectionTimeoutMS=5000)
self.client = MongoClient(
self.mongo_uri, serverSelectionTimeoutMS=5000)
# Test the connection
self.client.server_info()
self.db = self.client.get_default_database()
Expand All @@ -79,11 +81,14 @@ def ensure_connected(self):
# Test if connection is still alive
self.client.server_info()
except Exception:
logger.warning("Lost connection to MongoDB, attempting to reconnect...")
logger.warning(
"Lost connection to MongoDB, attempting to reconnect...")
self.connect()

@with_mongodb_retry(retries=3, delay=2)
async def create_user(self, email, username, password, team_number, role="user"):
async def create_user(
self, email, username, password, team_number,
role="user"):
"""Create a new user with retry mechanism"""
self.ensure_connected()
try:
Expand Down Expand Up @@ -111,7 +116,7 @@ async def create_user(self, email, username, password, team_number, role="user")
"last_login": None,
}

result = self.db.users.insert_one(user_data)
self.db.users.insert_one(user_data)
logger.info(f"Created new user: {username}")
return True, "User created successfully"

Expand Down
8 changes: 5 additions & 3 deletions app/auth/routes.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from flask import (
Blueprint,
current_app,
render_template,
redirect,
url_for,
Expand Down Expand Up @@ -59,7 +58,8 @@ async def login():
return render_template("auth/login.html", form_data=form_data)

try:
success, user = await user_manager.authenticate_user(login, password)
success, user = await user_manager.authenticate_user(
login, password)
if success and user:
login_user(user, remember=remember)
next_page = request.args.get("next")
Expand Down Expand Up @@ -89,7 +89,9 @@ async def register():
confirm_password = request.form.get("confirm_password", "").strip()
team_number = request.form.get("teamNumber", 0)

form_data = {"email": email, "username": username, "team_number": team_number}
form_data = {
"email": email, "username": username, "team_number": team_number
}

if not all([email, username, password, confirm_password]):
flash("All fields are required", "error")
Expand Down
7 changes: 5 additions & 2 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def get_id(self):
try:
return str(self._id)
except AttributeError as e:
raise NotImplementedError("No `_id` attribute - override `get_id`") from e
raise NotImplementedError(
"No `_id` attribute - override `get_id`") from e

def is_authenticated(self):
return True
Expand Down Expand Up @@ -92,7 +93,9 @@ def create_from_db(data):
data["_id"] = ObjectId(data["_id"])

# Ensure scouter_id is ObjectId
if "scouter_id" in data and not isinstance(data["scouter_id"], ObjectId):
if "scouter_id" in data and not isinstance(
data["scouter_id"], ObjectId
):
data["scouter_id"] = ObjectId(data["scouter_id"])

return TeamData(data)
Expand Down
29 changes: 22 additions & 7 deletions app/scout/TBA.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import aiohttp
import asyncio
import os
from typing import Optional, List, Dict
from dataclasses import dataclass
from dotenv import load_dotenv

from flask import jsonify
load_dotenv()

"""
Credits to PAWNAGERobitics for the original code:
https://github.com/PWNAGERobotics/ScoutingPASS/blob/main/resources/js/TBAInterface.js
"""


@dataclass
Expand All @@ -12,7 +19,7 @@ class TBAInterface:

def __init__(
self,
auth_key: str = "uTHeEfPigDp9huQCpLNkWK7FBQIb01Qrzvt4MAjh9z2WQDkrsvNE77ch6bOPvPb6",
auth_key: str = os.getenv("TBA_AUTH_KEY"),
):
self.auth_key = auth_key
self.base_url = "https://www.thebluealliance.com/api/v3"
Expand All @@ -31,12 +38,15 @@ async def __aexit__(self, exc_type, exc_val, exc_tb):
if self.session:
await self.session.close()

async def get_teams_at_event(self, event_code: str) -> Optional[List[Dict]]:
async def get_teams_at_event(
self, event_code: str
) -> Optional[List[Dict]]:
"""
Get list of teams in event
Args:
event_code (str): The event code (i.e. 2020caln) to pull the team list
event_code (str): The event code (i.e. 2020caln) to pull
the team list
Returns:
Optional[List[Dict]]: List of team data or None if request fails
Expand All @@ -63,7 +73,8 @@ async def get_schedule(self, event_code: str) -> Optional[List[Dict]]:
Get schedule for event
Args:
event_code (str): The event code (i.e. 2020caln) to pull the schedule
event_code (str): The event code (i.e. 2020caln)
to pull the schedule
Returns:
Optional[List[Dict]]: List of match data or None if request fails
Expand Down Expand Up @@ -95,10 +106,14 @@ async def get_event_data(
event_code (str): The event code (i.e. 2020caln)
Returns:
tuple[Optional[List[Dict]], Optional[List[Dict]]]: Tuple of (teams, schedule) data
tuple[
Optional[List[Dict]],
Optional[List[Dict]]
]: Tuple of (teams, schedule) data
"""
async with self:
teams_task = asyncio.create_task(self.get_teams_at_event(event_code))
teams_task = asyncio.create_task(
self.get_teams_at_event(event_code))
schedule_task = asyncio.create_task(self.get_schedule(event_code))

teams, schedule = await asyncio.gather(teams_task, schedule_task)
Expand Down
7 changes: 0 additions & 7 deletions app/scout/__init__.py

This file was deleted.

46 changes: 32 additions & 14 deletions app/scout/routes.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import asyncio
from functools import wraps
import aiohttp
from flask import Blueprint, flash, render_template, request, redirect, url_for, jsonify
from flask import (
Blueprint, flash, render_template, request, redirect, url_for, jsonify
)
from flask_login import login_required, current_user
from datetime import datetime, timezone
from scout.scouting_utils import ScoutingManager
from .TBA import TBAInterface

Expand Down Expand Up @@ -67,7 +68,8 @@ def edit_scouting_data(id):

if not team_data:
flash(
"Team data not found or you do not have permission to edit it", "error"
"Team data not found or you do not have permission to edit it",
"error"
)
return redirect(url_for("scouting.list_scouting_data"))

Expand Down Expand Up @@ -131,7 +133,8 @@ async def compare_teams():
async with aiohttp.ClientSession(headers=tba.headers) as session:
async with session.get(url) as response:
if response.status != 200:
return jsonify({"error": f"Team {team_num} not found"}), 404
return jsonify(
{"error": f"Team {team_num} not found"}), 404
team = await response.json()

# Fetch all scouting data for this team from MongoDB
Expand All @@ -148,25 +151,39 @@ async def compare_teams():
{"$unwind": "$scouter"},
]

team_scouting_data = list(scouting_manager.db.team_data.aggregate(pipeline))
team_scouting_data = list(
scouting_manager.db.team_data.aggregate(pipeline))

# Calculate statistics
auto_points = [entry["auto_points"] for entry in team_scouting_data]
teleop_points = [entry["teleop_points"] for entry in team_scouting_data]
endgame_points = [entry["endgame_points"] for entry in team_scouting_data]
total_points = [entry["total_points"] for entry in team_scouting_data]
auto_points = [
entry["auto_points"] for entry in team_scouting_data
]
teleop_points = [
entry["teleop_points"] for entry in team_scouting_data
]
endgame_points = [
entry["endgame_points"] for entry in team_scouting_data
]
total_points = [
entry["total_points"] for entry in team_scouting_data
]

stats = {
"matches_played": len(team_scouting_data),
"avg_auto": (sum(auto_points) / len(auto_points) if auto_points else 0),
"avg_auto": (
sum(auto_points) / len(auto_points) if auto_points else 0
),
"avg_teleop": (
sum(teleop_points) / len(teleop_points) if teleop_points else 0
sum(teleop_points) / len(teleop_points)
if teleop_points else 0
),
"avg_endgame": (
sum(endgame_points) / len(endgame_points) if endgame_points else 0
sum(endgame_points) / len(endgame_points)
if endgame_points else 0
),
"avg_total": (
sum(total_points) / len(total_points) if total_points else 0
sum(total_points) / len(total_points)
if total_points else 0
),
"max_total": max(total_points, default=0),
"min_total": min(total_points, default=0),
Expand Down Expand Up @@ -243,7 +260,8 @@ async def search_teams():
{"$unwind": "$scouter"},
]

team_scouting_data = list(scouting_manager.db.team_data.aggregate(pipeline))
team_scouting_data = list(
scouting_manager.db.team_data.aggregate(pipeline))

scouting_entries = [
{
Expand Down
22 changes: 15 additions & 7 deletions app/scout/scouting_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ def wrapper(*args, **kwargs):
last_error = e
if attempt < retries - 1:
logger.warning(
f"Attempt {attempt + 1} failed: {str(e)}. Retrying..."
f"Attempt {attempt + 1} failed: {str(e)}."
)
time.sleep(delay)
else:
logger.error(f"All {retries} attempts failed: {str(e)}")
logger.error(
f"All {retries} attempts failed: {str(e)}")
raise last_error

return wrapper
Expand All @@ -45,7 +46,8 @@ def connect(self):
"""Establish connection to MongoDB with basic error handling"""
try:
if self.client is None:
self.client = MongoClient(self.mongo_uri, serverSelectionTimeoutMS=5000)
self.client = MongoClient(self.mongo_uri,
serverSelectionTimeoutMS=5000)
# Test the connection
self.client.server_info()
self.db = self.client.get_default_database()
Expand All @@ -71,7 +73,8 @@ def ensure_connected(self):
# Test if connection is still alive
self.client.server_info()
except Exception:
logger.warning("Lost connection to MongoDB, attempting to reconnect...")
logger.warning(
"Lost connection to MongoDB, attempting to reconnect.")
self.connect()

@with_mongodb_retry(retries=3, delay=2)
Expand All @@ -96,7 +99,7 @@ def add_scouting_data(self, data, scouter_id):
"created_at": datetime.now(timezone.utc),
}

result = self.db.team_data.insert_one(team_data)
self.db.team_data.insert_one(team_data)
logger.info(
f"Added new scouting data for team {
data['team_number']}"
Expand All @@ -120,7 +123,11 @@ def get_all_scouting_data(self):
"as": "scouter",
}
},
{"$unwind": {"path": "$scouter", "preserveNullAndEmptyArrays": True}},
{"$unwind":
{"path": "$scouter",
"preserveNullAndEmptyArrays": True
}
},
]

team_data = list(self.db.team_data.aggregate(pipeline))
Expand All @@ -144,7 +151,8 @@ def get_team_data(self, team_id, scouter_id=None):

# Add an is_owner field to the response
data["is_owner"] = (
str(data["scouter_id"]) == str(scouter_id) if scouter_id else False
str(data["scouter_id"]) == str(scouter_id)
if scouter_id else False
)
return TeamData.create_from_db(data)
except Exception as e:
Expand Down

0 comments on commit b204c42

Please sign in to comment.