Last active
July 23, 2017 11:11
-
-
Save sharmaeklavya2/fa13d5955a2404942554 to your computer and use it in GitHub Desktop.
Script to make timetable in HTML using a list of sections
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/usr/bin/env python | |
'Generate Time Table' | |
from __future__ import print_function | |
import sys | |
import argparse | |
from collections import defaultdict | |
START_TIME = 8 | |
# Time when classes start | |
DEFAULT_INDENT_STR = ' ' | |
# Default indentation in HTML source | |
DEFAULT_TITLE = 'My timetable' | |
# Default text to show in <title> tag | |
DAY_INDEX = { | |
"M": 0, | |
"T": 1, | |
"W": 2, | |
"Th": 3, | |
"F": 4, | |
"S": 5, | |
} | |
DISP_DAYS = ["Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"] | |
# strings which will be shown in first column of the time table | |
STYLE_CLASS_MAP = { | |
"L": "lec", | |
"T": "tut", | |
"P": "prac", | |
"CH": "ch", | |
} | |
DEFAULT_STYLE = """ | |
.lec | |
{color: black;} | |
.tut | |
{color: blue;} | |
.ch | |
{color: blue;} | |
.prac | |
{color: red;} | |
.clash | |
{background-color: #f2dede;} | |
.day, .timerow | |
{ | |
color: grey; | |
font-size: 75%; | |
} | |
table | |
{ | |
border: 1px solid black; | |
border-collapse: collapse; | |
} | |
td | |
{ | |
border: 1px solid black; | |
padding: 2px 4px; | |
} | |
td.lunch | |
{border: none;} | |
""" | |
class CellPart: | |
subj = '' | |
sec = '' | |
room = '' | |
TEMPLATE = '{subj} {sec}\n{room}' | |
def __init__(self, subj, sec, room): | |
self.subj = subj | |
self.sec = sec | |
self.room = room | |
def get_styleclass(self): | |
return STYLE_CLASS_MAP.get(get_cls_type(self.sec), '') | |
def __str__(self): | |
return "CellPart({}, {}, {})".format(self.subj, self.sec, self.room) | |
def __repr__(self): | |
return str(self) | |
def render(self): | |
return CellPart.TEMPLATE.format(subj=self.subj, sec=self.sec, room=self.room) | |
class Cell: | |
""" | |
A Cell object corresponds to a cell in the timetable. | |
A Cell has multiple CellParts. | |
If the timetable is clash-free, there will be at most 1 CellPart in the Cell, | |
otherwise there can be multiple, each corresponding to a class scheduled at that time. | |
""" | |
parts = [] | |
def __init__(self, parts=None): | |
self.parts = parts or [] | |
def get_styleclass(self): | |
if len(self.parts) > 1: | |
return 'clash' | |
elif len(self.parts) == 0: | |
return None | |
else: | |
return self.parts[0].get_styleclass() | |
def __str__(self): | |
return 'Cell({})'.format(self.parts) | |
def __repr__(self): | |
return str(self) | |
def inner(self): | |
if len(self.parts) > 1: | |
res = '\n'.join(['<span class="{}">{}</span>'.format( | |
part.get_styleclass(), part.render()) for part in self.parts]) | |
else: | |
res = '\n'.join([part.render() for part in self.parts]) | |
return res.replace('\n', '<br />') | |
def outer(self): | |
styleclass = self.get_styleclass() | |
class_attr = '' if styleclass is None else ' class="{}"'.format(self.get_styleclass()) | |
return '\t\t<td{}>{}</td>'.format(class_attr, self.inner()) | |
def get_cls_type(mystr): | |
'Gets the longest prefix of mystr which does not contain any digit or special_char.' | |
for i, ch in enumerate(mystr): | |
if ch.isdigit() or ch in '?-': | |
return mystr[0:i] | |
return mystr | |
def read_sched(fname, min_hours=0): | |
""" | |
Reads a file fname and returns a matrix of Cell objects. | |
min_hours is the minimum number of hours to show in timetable. | |
""" | |
cell_parts = defaultdict(list) | |
myfile = open(fname) | |
for line in myfile: | |
line = line.split('#', 1)[0] # remove comments | |
parts = line.split() | |
if parts: # continue only if line was non-empty after removing comments | |
subj, sec, days_str, hours_str, room = parts[:5] | |
days = [DAY_INDEX[x] for x in days_str.split(',')] | |
hours = [int(x, 16) - 1 for x in hours_str.split(',')] | |
min_hours = max(min_hours, max(hours) + 1) | |
for day in days: | |
for hour in hours: | |
cell_parts[(day, hour)].append(CellPart(subj, sec, room)) | |
tt = [[Cell(cell_parts[(day, hour)]) for hour in range(min_hours)] for day in range(len(DISP_DAYS))] | |
return tt | |
TIMECELL_TEMPLATE = '\t\t<td>{hour} ({beg}-{end})</td>' | |
HTML_TEMPLATE = """<!DOCTYPE html> | |
{comment} | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
<title>{title}</title>{styletag} | |
</head> | |
<body> | |
<table{tableattrs}> | |
<tr class="timerow"> | |
<td></td>{timerow} | |
<td></td> | |
</tr>{tbody} | |
<tr class="timerow"> | |
<td></td>{timerow} | |
<td></td> | |
</tr> | |
</table> | |
</body> | |
</html>""" | |
def tt_as_html(tt, style, indent=DEFAULT_INDENT_STR, title=None, comment=None): | |
""" Takes the 3D list created by read_sched and prints the timetable to stdout""" | |
title = title or DEFAULT_TITLE | |
comment = '<!-- {} -->'.format(comment) if comment else '' | |
if style: | |
styletag = '\n<style>{0}</style>'.format(style) | |
tableattrs = '' | |
else: | |
styletag = '' | |
tableattrs = ' border="1"' | |
min_hours = len(tt[0]) | |
timerow = '\n' + '\n'.join([TIMECELL_TEMPLATE.format( | |
hour=i+1, beg=(i+START_TIME-1)%12+1, end=(i+8)%12+1) for i in range(min_hours)]) | |
trs = [] | |
for i, row in enumerate(tt): | |
daycell = '<td class="day">{day}</td>'.format(day=DISP_DAYS[i]) | |
tds = '\n'.join([cell.outer() for cell in row]) | |
tr = '\n\t<tr>\n\t\t{daycell}\n{tds}\n\t\t{daycell}\n\t</tr>'.format( | |
daycell=daycell, tds=tds) | |
trs.append(tr) | |
res = HTML_TEMPLATE.format(title=title, comment=comment, styletag=styletag, | |
tableattrs=tableattrs, timerow=timerow, tbody=''.join(trs)) | |
return res.replace(' ', indent).replace('\t', indent) | |
def main(): | |
parser = argparse.ArgumentParser(description=__doc__) | |
parser.add_argument('file') | |
parser.add_argument('--title', default=DEFAULT_TITLE, | |
help='text to show in <title> tag') | |
parser.add_argument('--indent', default=DEFAULT_INDENT_STR, | |
help="""indent string to use in HTML source. | |
If this is an integer, use that many spaces. | |
Use '\\t' to specify tabs.""") | |
parser.add_argument('--min-hours', default=0, type=int, | |
help='minimum number of hours to show in timetable') | |
args = parser.parse_args() | |
fpath = args.file | |
try: | |
indent = ' ' * int(args.indent) | |
except ValueError: | |
indent = args.indent.replace('\\t', '\t') | |
style = DEFAULT_STYLE | |
print(tt_as_html(read_sched(fpath, args.min_hours), style, indent, args.title, comment=fpath)) | |
if __name__=="__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#CS F213 Object Oriented Programming | |
OOP L2 T,Th,S 3 6109 Pankaj Vyas | |
OOP P3 Th 8,9 6018 Sunita Singhal | |
#CS F214 Logic in Computer Science | |
Logic L1 T,Th,S 5 5105 SHAN BALASUBRAMANIAM | |
Logic T2 T 2 6160 Vishal Gupta | |
#CS F215 Digital Design | |
DD L2 T,Th,S 4 5101 S MOHAN | |
DD P2 T 7,8,9 2241 Lucky Sharan, Priya Gupta | |
DD T1 M 1 2206 Sneh Lata Murotiya | |
#CS F222 Discrete Structures for Computer Science | |
Disco L1 M,W,F 7 6109 SK HAFIZUL ISLAM | |
Disco T3 W 1 6160 SK HAFIZUL ISLAM | |
#MATH F211 Mathematics III | |
Math3 L6 M,W,F 8 6153 Rakhee | |
Math3 CH6 S 1 6156 Rakhee | |
#GS F232 Introductory Psychology | |
Psycho L1 M,W,F 9 6105 TANU SHUKLA | |
#GS F321 Mass Media and Content Design | |
MMCD L1 M 3 6156 VIRENDRA SINGH NIRBAN | |
MMCD T1 W 2,3 6118 VIRENDRA SINGH NIRBAN |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment