Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project Contribution #11

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.analysis.typeCheckingMode": "basic"
}
148 changes: 137 additions & 11 deletions app/data.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,151 @@
# Standard library imports
from datetime import datetime
from os import getenv
import math
import random
import unittest

# Misc imports
from certifi import where
from dotenv import load_dotenv
from MonsterLab import Monster
from pandas import DataFrame
from pymongo import MongoClient
from pymongo.errors import ServerSelectionTimeoutError
import pandas as pd

# Typing
from typing import Dict, Iterable, Iterator


# List and Etc.

ranks = ['Private', 'Sergeant', 'Lieutenant', 'Captain', 'Commander']
rank_probabilities = [round(random.uniform(0.0,0.1),2),
round(random.uniform(0.1,0.15),2),
round(random.uniform(0.2,0.25),2),
round(random.uniform(0.25,0.3),2),
round(random.uniform(0.3,0.35),2)]

clone_types = ['Standard','Recon', 'Heavy', 'Commando', 'ARC Trooper']
clone_type_probabilities = [round(random.uniform(0.0,0.1),2),
round(random.uniform(0.1,0.15),2),
round(random.uniform(0.2,0.25),2),
round(random.uniform(0.25,0.3),2),
round(random.uniform(0.3,0.35),2)]

assigned_weapons = ["DC-15A Blaster Rifle",
"DC-15X Sniper Rifle",
"DC-17m Blaster Rifle",
"DC-15S Blaster Carbine",
"WESTAR-M5 Blaster Rifle"]

assigned_general = ['General Mace Windu', "General Plo Koon", 'General Yoda', 'General Kenobi', 'General Skywalker',]
assigned_general_probabilities = [round(random.uniform(0.0,0.1),2),
round(random.uniform(0.1,0.15),2),
round(random.uniform(0.2,0.25),2),
round(random.uniform(0.25,0.3),2),
round(random.uniform(0.3,0.35),2)]


class Database:
load_dotenv()

def seed(self, amount):
pass
def __init__(self, collection_name: str):
db_url = getenv("DB_URL")
self.client = MongoClient(db_url,
tlsCAFile=where(),
tls=True,
tlsAllowInvalidCertificates=True)["MainDatabase"]
self.collection = self.client[collection_name]

def reset(self):
pass
def seed(self, amount):
data = self.generate_clone_trooper(amount)
self.collection.insert_many(data)

def reset(self) -> int:
return self.collection.delete_many({}).deleted_count

def count(self) -> int:
pass
return self.collection.count_documents({})

def to_dataframe(self) -> pd.DataFrame:
return pd.DataFrame(list(self.collection.find()))

def to_html_table(self) -> str:
df = self.to_dataframe()
return df.to_html()

# Generate a random clone trooper!
@staticmethod
def generate_clone_trooper(n):
data = []
for _ in range(n):

# Select a clone type and its probability
clone_type_index = random.choices(range(len(clone_types)), clone_type_probabilities, k=1)[0]
clone_type = clone_types[clone_type_index]
clone_type_probability = clone_type_probabilities[clone_type_index]

# Select a rank and its probability
rank_index = random.choices(range(len(ranks)), rank_probabilities, k=1)[0]
rank = ranks[rank_index]
rank_probability = rank_probabilities[rank_index]

# Weapon Selected
assigned_weapon = random.choice(assigned_weapons)

# Random health and energy
health = random.randint(3, 9)
energy = random.randint(2, 6)

# Select a general and its probability
general_index = random.choices(range(len(assigned_general)), assigned_general_probabilities, k=1)[0]
general = assigned_general[general_index]
general_probability = assigned_general_probabilities[general_index]

# Calculated the success percentage. But also included a skew towards healthier clones.
success_percentage = round(sum([clone_type_probability, rank_probability, general_probability,math.log10(health)-0.80]), 2)

data.append({
"CT ID": clone_trooper_name,
'Clone Type': clone_type,
'Rank': rank,
'Assigned Weapon': assigned_weapon,
'Health': health,
'Energy': energy,
'Success Percentage': success_percentage,
'Assigned General': general,
'Check In Time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
})
return data


## TESTING CENTER ###

class TestMongoDBConnection(unittest.TestCase):

def setUp(self):
db_url = getenv("DB_URL")
# Set serverSelectionTimeoutMS to 5000 milliseconds (5 second)
self.client = MongoClient(db_url,
tlsCAFile=where(),
tls=True,
tlsAllowInvalidCertificates=True,
serverSelectionTimeoutMS=5000)
self.db_class = Database("test_collection")


def test_connection(self):
try:
self.client.admin.command('ismaster')
except ServerSelectionTimeoutError:
self.fail("MongoDB connection failed.")

def test_generate_clone_trooper(self):
n = 5
result = self.db_class.generate_clone_trooper(n)
self.assertEqual(len(result), n)


def dataframe(self) -> DataFrame:
pass

def html_table(self) -> str:
pass
if __name__ == '__main__':
unittest.main()
163 changes: 163 additions & 0 deletions app/data2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Standard library imports
import math
import random
import unittest
from datetime import datetime
from os import getenv
from typing import List, Tuple

# Third-party imports
from dotenv import load_dotenv
import pandas as pd
import psycopg2

# Constants
RANKS = ['Private', 'Lieutenant', 'Captain', 'Commander']
RANK_PROBABILITIES = [round(random.uniform(0.0, 0.2), 2),
round(random.uniform(0.2, 0.25), 2),
round(random.uniform(0.25, 0.3), 2),
round(random.uniform(0.3, 0.37), 2)]

CLONE_TYPES = ['Standard', 'Heavy', 'Commando', 'ARC Trooper']
CLONE_TYPE_PROBABILITIES = [round(random.uniform(0.0, 0.2), 2),
round(random.uniform(0.2, 0.25), 2),
round(random.uniform(0.25, 0.3), 2),
round(random.uniform(0.3, 0.37), 2)]

ASSIGNED_WEAPONS = ["DC-15A Blaster Rifle", "DC-15X Sniper Rifle", "DC-17m Blaster Rifle",
"DC-15S Blaster Carbine", "WESTAR-M5 Blaster Rifle"]

ASSIGNED_GENERALS = ['General Mace Windu', 'General Yoda', 'General Kenobi', 'General Skywalker']
ASSIGNED_GENERAL_PROBABILITIES = [round(random.uniform(0.0, 0.2), 2),
round(random.uniform(0.2, 0.25), 2),
round(random.uniform(0.25, 0.3), 2),
round(random.uniform(0.3, 0.37), 2)]


class Database:
"""Database class for managing and manipulating clone trooper records."""
load_dotenv()

def __init__(self):
self.conn = psycopg2.connect(
dbname=getenv("DB_NAME"),
user=getenv("DB_USER"),
password=getenv("DB_PASSWORD"),
host=getenv("DB_HOST")
)
self.cur = self.conn.cursor()

def create_table(self):
"""Create table in the database if it doesn't already exist."""
self.cur.execute("""
CREATE TABLE IF NOT EXISTS clone_troopers (
ct_id SERIAL PRIMARY KEY,
clone_type VARCHAR(50),
rank VARCHAR(50),
assigned_weapon VARCHAR(50),
health INTEGER,
energy INTEGER,
success_percentage NUMERIC,
assigned_general VARCHAR(50),
check_in_time TIMESTAMP
)
""")
self.conn.commit()

def seed(self, amount: int):
"""Insert generated data into the database."""
data = self.generate_clone_trooper(amount)
for row in data:
self.cur.execute("""
INSERT INTO clone_troopers (clone_type, rank, assigned_weapon, health, energy, success_percentage, assigned_general, check_in_time)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
""", row)
self.conn.commit()

def reset(self) -> int:
"""Delete all records from the table and return the number of deleted rows."""
self.cur.execute("DELETE FROM clone_troopers")
self.conn.commit()
return self.cur.rowcount

def count(self) -> int:
"""Count the number of records in the table."""
self.cur.execute("SELECT COUNT(*) FROM clone_troopers")
return self.cur.fetchone()[0]

def dataframe(self) -> pd.DataFrame:
"""Retrieve table data as a pandas DataFrame."""
self.cur.execute("SELECT * FROM clone_troopers")
rows = self.cur.fetchall()
columns = [desc[0] for desc in self.cur.description]
return pd.DataFrame(rows, columns=columns)

def html_table(self) -> str:
"""Generate HTML table from DataFrame data."""
df = self.dataframe()
return df.to_html()

@staticmethod
def generate_clone_trooper(n: int) -> List[Tuple]:
"""Generate data for 'n' clone troopers."""
data = []
for _ in range(n):
clone_type_index = random.choices(range(len(CLONE_TYPES)), CLONE_TYPE_PROBABILITIES, k=1)[0]
clone_type = CLONE_TYPES[clone_type_index]
rank_index = random.choices(range(len(RANKS)), RANK_PROBABILITIES, k=1)[0]
rank = RANKS[rank_index]
assigned_weapon = random.choice(ASSIGNED_WEAPONS)
health = random.randint(3, 9)
energy = random.randint(2, 6)
general_index = random.choices(range(len(ASSIGNED_GENERALS)), ASSIGNED_GENERAL_PROBABILITIES, k=1)[0]
general = ASSIGNED_GENERALS[general_index]
success_percentage = round(random.uniform(0.1, 0.3), 2) # Example percentage calculation.
check_in_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
data.append((clone_type, rank, assigned_weapon, health, energy, success_percentage, general, check_in_time))
return data

class TestDatabase(unittest.TestCase):
"""Unit tests for the Database class."""

def setUp(self):
self.db = Database()

def test_connection(self):
self.assertIsNotNone(self.db.conn)

def test_seed(self):
self.db.reset()
self.db.seed(10)
self.assertEqual(self.db.count(), 10)

def test_reset(self):
self.db.reset()
self.db.seed(10)
self.db.reset()
self.assertEqual(self.db.count(), 0)

def test_count(self):
self.db.reset()
self.db.seed(5)
self.assertEqual(self.db.count(), 5)

def test_dataframe(self):
self.db.reset()
self.db.seed(5)
df = self.db.dataframe()
self.assertIsInstance(df, pd.DataFrame)
self.assertEqual(len(df), 5)

def test_html_table(self):
self.db.reset()
self.db.seed(5)
html = self.db.html_table()
self.assertIsInstance(html, str)
self.assertTrue('<table' in html)

self.db.reset()
html = self.db.html_table()
self.assertTrue('<tbody>\n </tbody>' in html) # Check if the table body is empty

if __name__ == '__main__':
unittest.main()
44 changes: 41 additions & 3 deletions app/graph.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
from altair import Chart
# Standard library imports
import math
import random
import unittest
from datetime import datetime

# Third-party imports
import pandas as pd
import plotly.express as px
import plotly.io as pio

def chart(df, x, y, target) -> Chart:
pass
# Local application imports
from app.data2 import Database

# Create database instance and dataframe
db = Database()
df = db.dataframe()

def chart(df, x, y, target):
"""Generate a box plot for the given dataframe and axes."""
fig = px.box(df, x=x, y=y, title=target)
fig.update_layout(template='plotly_dark', autosize=True)
return fig

class TestChart(unittest.TestCase):
"""Unit tests for the chart function."""

def test_chart(self):
"""Test the chart function with a predefined DataFrame."""
# Creates a random DataFrame
df = pd.DataFrame({
'clone_type': ['A', 'B', 'C'],
'rank': [1, 2, 3],
'health': [100, 200, 300],
'assigned_general': ['X', 'Y', 'Z'],
'success_percentage': [0.5, 0.6, 0.7]
})

fig = chart(df, 'rank', 'health', 'Test')
self.assertEqual(type(fig).__name__, 'Figure')

if __name__ == '__main__':
unittest.main()
Loading