Skip to content

Instantly share code, notes, and snippets.

@pvieito
Created June 29, 2016 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pvieito/e7571cf42b28d4541966d7221ea8139e to your computer and use it in GitHub Desktop.
Save pvieito/e7571cf42b28d4541966d7221ea8139e to your computer and use it in GitHub Desktop.
Compute marks from diferent subjects in YMARK format
#!/usr/bin/env python3
'''ymark.py - Pedro José Pereira Vieito © 2016
Compute marks from diferent subjects in YMARK format.
Usage:
ymark.py [-adeghow] [<search>...]
Options:
-a, --all Show all subjects, not only active
-d, --details Show subject details
-e, --edit Edit mark files
-g, --guide Open subject guide
-o, --open Open subject folder
-w, --web Open subject web
-h, --help Show this help
'''
import yaml
import subprocess
import numbers
import os.path
from docopt import docopt
from pathlib import Path
from colorama import Fore, Back, Style
__author__ = "Pedro José Pereira Vieito"
__email__ = "pvieito@gmail.com"
args = docopt(__doc__)
status_array = [{"name": "Passed", "color": Fore.GREEN},
{"name": "Active", "color": Fore.CYAN},
{"name": "Future", "color": Fore.MAGENTA},
{"name": "Failed", "color": Fore.RED},
{"name": "Unknown", "color": Fore.YELLOW}]
courses = {}
def get_status(property, status):
if status < len(status_array):
return status_array[status][property]
else:
return status_array[5][property]
def compute_subject(subject, *, force=False):
# Args Options
if not force and not args['--all'] and "status" in subject and \
not subject["status"] == 1:
return
if args['--edit']:
subprocess.call("open '" + subject["file"] + "'", shell=True)
if args['--open']:
subject_dir = Path(subject["file"]).parent.parent
subprocess.call("open '" + str(subject_dir) + "'", shell=True)
if args['--guide']:
guides = Path(subject["file"]).parent.glob("*.pdf")
for guide in guides:
subprocess.call("open '" + str(guide) + "'", shell=True)
if args['--web']:
if "web" in subject and subject["web"]:
subprocess.call("open '" + str(subject["web"]) + "'", shell=True)
post_mark = None
course_progress = None
# Mark computation
if "assessment" in subject and subject["assessment"] and \
"status" in subject and not subject["status"] == 2:
final_mark = 0
course_progress = 0
for item in subject["assessment"]:
if "mark" in item and isinstance(item["mark"], numbers.Number):
item_mark = item["mark"]
if "weight" in item:
item_mark *= item["weight"]
course_progress += item["weight"] * 100
else:
course_progress = 100
if "fullscale" in item:
item_mark = item_mark / item["fullscale"] * 10
final_mark += item_mark
course_progress = round(course_progress)
if course_progress < 100:
post_mark = " (" + str(course_progress) + "%)"
else:
final_mark = None
# Course computation
if args['--all'] and "status" in subject and \
subject["status"] == 0 and "credits" in subject and final_mark:
credits = subject["credits"]
ponderated_mark = final_mark * credits
if subject["course"] in courses:
courses[subject["course"]]["credits"] += subject["credits"]
courses[subject["course"]]["ponderated_mark"] += ponderated_mark
else:
courses[subject["course"]] = {"credits": subject["credits"],
"ponderated_mark": ponderated_mark}
status_color = get_status("color", subject["status"])
if "codename" in subject:
text = status_color + subject["codename"] + Fore.RESET
else:
text = status_color + "………" + Fore.RESET
optional = None
if "name" in subject:
optional = str(subject["name"])
# Subject
print_mark(text, final_mark, optional, post_mark, extra_width=5)
# Print details
if args["--details"]:
if "course" in subject:
print(" Course:", subject["course"])
if "institution" in subject:
print(" Institution:", subject["institution"])
if "year" in subject:
print(" Year:", subject["year"])
if "term" in subject:
print(" Term:", subject["term"])
if "type" in subject:
print(" Type:", subject["type"])
if "status" in subject:
print(" Status:" + status_color,
get_status("name", subject["status"]), Fore.RESET)
if "credits" in subject:
print(" Credits:", subject["credits"], "ECTS")
if "code" in subject:
print(" Code:", subject["code"])
if "web" in subject:
print(" Web:", subject["web"])
if isinstance(course_progress, numbers.Number):
print(" Progress:", str(course_progress) + "%")
if "assessment" in subject and subject["assessment"]:
if len(subject["assessment"]) == 1 and \
not "weight" in subject["assessment"][0]:
print(" Assesment: Final Mark")
else:
print(" Assesment:", len(subject["assessment"]), "items")
i = 1
for item in subject["assessment"]:
if "mark" in item:
if "description" in item:
description = str(item["description"])
else:
description = "Mark #" + str(i)
if "fullscale" in item:
mark = item["mark"] / item["fullscale"] * 10
else:
mark = item["mark"]
if "weight" in item:
weight = str(round(item["weight"] * 100, 2)) + "%"
else:
weight = "100.0%"
print_mark(" - " + description, mark,
optional=weight, text_color=True)
i += 1
print()
def print_course(course):
credits = courses[course]["credits"]
ponderated_mark = courses[course]["ponderated_mark"] / credits
optional = str(credits) + " ECTS"
print_mark(course, ponderated_mark, optional, extra_width=-5)
def print_mark(text, mark=None, optional=None, post_note=None, *,
extra_width=0, text_color=False):
text = (text[:50] + '…') if len(text) > 50 else text
if isinstance(mark, numbers.Number):
if round(mark, 1) < 5:
color = Fore.RED
else:
color = Fore.GREEN
else:
color = Fore.WHITE
if text_color:
text_color = color
text_color_optional = color
else:
text_color = Style.BRIGHT
text_color_optional = ""
if optional:
optional = (optional[:50] + '…') if len(optional) > 50 else optional
text += Style.RESET_ALL + text_color_optional + " (" + optional + ")"
else:
text += Style.RESET_ALL
text += " "
print(text_color + text.ljust(75 + extra_width, "…"),
Style.RESET_ALL, end="")
if isinstance(mark, numbers.Number):
print(text_color + color, "{0:0.1f}".format(mark), end="")
else:
print(text_color + color, "………", end="")
print(Style.RESET_ALL, end="")
if post_note:
print(post_note, end="")
print()
if __name__ == '__main__':
results = subprocess.check_output("mdfind 'kMDItemFSName=*.ymark' \
-onlyin ~/Dropbox/Universitat",
shell=True)
results = results.decode().splitlines()
results.sort()
marks = []
subjects = {}
for marks_file in results:
try:
marks_dict = yaml.safe_load(open(marks_file))
marks_dict.update({"file": marks_file})
marks.append(marks_dict)
except AttributeError:
pass
for subject in marks:
index = ""
if "status" in subject:
index += str(subject["status"]) + "_" + \
get_status("name", subject["status"]) + "_"
if "course" in subject:
index += subject["course"] + "_"
if "year" in str(subject):
index += str(subject["year"]) + "_"
if "term" in subject:
index += str(subject["term"]) + "_"
if "type" in subject:
index += str(subject["type"]) + "_"
if "codename" in subject:
index += str(subject["codename"]) + "_"
if "name" in subject:
index += str(subject["name"]) + "_"
if "code" in subject:
index += str(subject["code"]) + "_"
if "institution" in subject:
index += str(subject["institution"]) + "_"
subjects[index] = subject
for subject in sorted(subjects):
if args['<search>'] and not args['--all']:
input = list(map(str.upper, args['<search>']))
match = False
for search_term in input:
if search_term in subject.upper():
match = True
if match:
compute_subject(subjects[subject], force=True)
else:
compute_subject(subjects[subject])
if args['--all']:
if courses:
print()
for course in sorted(courses):
print_course(course)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment