~/court-study-guide/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.flowables import HRFlowable
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Arrow
from reportlab.graphics import renderPDF
from reportlab.platypus import Flowable
import os
OUTPUT_PATH = "/tmp/workspace/court-study-guide/Indian_Court_Hierarchy_Study_Guide.pdf"
# ── Colour palette ────────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#1a3a5c")
C_GOLD = colors.HexColor("#c8960c")
C_BLUE = colors.HexColor("#2a6496")
C_LBLUE = colors.HexColor("#d6eaf8")
C_GREEN = colors.HexColor("#1e7e34")
C_LGREEN = colors.HexColor("#d4edda")
C_ORANGE = colors.HexColor("#c0392b")
C_LORANGE = colors.HexColor("#fde8e8")
C_PURPLE = colors.HexColor("#6c3483")
C_LPURPLE = colors.HexColor("#f3e6f9")
C_GREY = colors.HexColor("#f4f6f9")
C_DGREY = colors.HexColor("#5d6d7e")
C_WHITE = colors.white
C_BLACK = colors.black
C_YELLOW = colors.HexColor("#fff9c4")
C_TEAL = colors.HexColor("#117a8b")
C_LTEAL = colors.HexColor("#d1ecf1")
# ── Styles ────────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def make_style(name, parent="Normal", **kwargs):
s = ParagraphStyle(name, parent=styles[parent], **kwargs)
return s
sTitle = make_style("sTitle", fontSize=28, textColor=C_WHITE, alignment=TA_CENTER,
fontName="Helvetica-Bold", spaceAfter=6)
sSubtitle = make_style("sSubtitle", fontSize=14, textColor=C_GOLD, alignment=TA_CENTER,
fontName="Helvetica", spaceAfter=4)
sChapter = make_style("sChapter", fontSize=16, textColor=C_WHITE, alignment=TA_LEFT,
fontName="Helvetica-Bold", spaceAfter=4, spaceBefore=8,
leftIndent=8)
sSection = make_style("sSection", fontSize=13, textColor=C_NAVY, alignment=TA_LEFT,
fontName="Helvetica-Bold", spaceAfter=4, spaceBefore=10,
borderPad=4)
sBody = make_style("sBody", fontSize=10, textColor=C_BLACK, alignment=TA_JUSTIFY,
fontName="Helvetica", spaceAfter=4, leading=15)
sBullet = make_style("sBullet", fontSize=10, textColor=C_BLACK, alignment=TA_LEFT,
fontName="Helvetica", spaceAfter=3, leftIndent=14, leading=14,
bulletIndent=4)
sNote = make_style("sNote", fontSize=9, textColor=C_TEAL, alignment=TA_LEFT,
fontName="Helvetica-Oblique", spaceAfter=4, leftIndent=8, leading=13)
sTableHdr = make_style("sTableHdr", fontSize=10, textColor=C_WHITE, alignment=TA_CENTER,
fontName="Helvetica-Bold")
sTableCell = make_style("sTableCell", fontSize=9, textColor=C_BLACK, alignment=TA_LEFT,
fontName="Helvetica", leading=13)
sTableCellC = make_style("sTableCellC", fontSize=9, textColor=C_BLACK, alignment=TA_CENTER,
fontName="Helvetica", leading=13)
sLabel = make_style("sLabel", fontSize=9, textColor=C_NAVY, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=12)
sSmall = make_style("sSmall", fontSize=8, textColor=C_DGREY, alignment=TA_CENTER,
fontName="Helvetica-Oblique")
sBoxTitle = make_style("sBoxTitle", fontSize=11, textColor=C_NAVY, alignment=TA_CENTER,
fontName="Helvetica-Bold", spaceAfter=3)
sMemonic = make_style("sMemonic", fontSize=11, textColor=C_PURPLE, alignment=TA_CENTER,
fontName="Helvetica-Bold", spaceAfter=2)
sQAQ = make_style("sQAQ", fontSize=10, textColor=C_NAVY, alignment=TA_LEFT,
fontName="Helvetica-Bold", spaceAfter=2, spaceBefore=4)
sQAA = make_style("sQAA", fontSize=10, textColor=C_BLACK, alignment=TA_LEFT,
fontName="Helvetica", spaceAfter=4, leftIndent=12)
W, H = A4 # 595 x 842 pts
# ── Helper: coloured section header ──────────────────────────────────────────
def sec_header(text, bg=C_NAVY, fg=C_WHITE, size=13):
data = [[Paragraph(f"<b>{text}</b>",
make_style("_sh", fontSize=size, textColor=fg,
fontName="Helvetica-Bold", alignment=TA_LEFT))]]
t = Table(data, colWidths=[W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
]))
return t
def colored_box(content_items, bg=C_GREY, border=C_BLUE, padding=8):
"""Wrap flowables in a coloured box via a 1-cell table."""
from reportlab.platypus import KeepTogether
inner = Table([[item] for item in content_items],
colWidths=[W - 4*cm - 2*padding])
t = Table([[inner]], colWidths=[W - 4*cm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("BOX", (0,0), (-1,-1), 1.2, border),
("TOPPADDING", (0,0), (-1,-1), padding),
("BOTTOMPADDING", (0,0), (-1,-1), padding),
("LEFTPADDING", (0,0), (-1,-1), padding),
("RIGHTPADDING", (0,0), (-1,-1), padding),
]))
return t
# ── Hierarchy diagram using a Table ──────────────────────────────────────────
def court_hierarchy_diagram():
rows = [
# (label, bg, fg, level_indent_cells_left)
("SUPREME COURT", C_NAVY, C_WHITE, 0),
("HIGH COURT", C_BLUE, C_WHITE, 1),
("DISTRICT / SESSION COURT", C_TEAL, C_WHITE, 2),
("MAGISTRATE COURT", C_GREEN, C_WHITE, 3),
("JUVENILE COURT", C_PURPLE, C_WHITE, 4),
]
NCOLS = 6
table_data = []
for label, bg, fg, indent in rows:
span_start = indent
span_end = NCOLS - 1
row = [""] * NCOLS
row[span_start] = Paragraph(
f"<b>{label}</b>",
make_style("_hd", fontSize=10, textColor=fg,
fontName="Helvetica-Bold", alignment=TA_CENTER)
)
table_data.append(row)
col_w = (W - 4*cm) / NCOLS
t = Table(table_data, colWidths=[col_w]*NCOLS, rowHeights=[30]*len(rows))
ts = TableStyle([
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0), (-1,-1), 4),
])
for i, (_, bg, _, indent) in enumerate(rows):
ts.add("BACKGROUND", (indent, i), (NCOLS-1, i), bg)
if indent > 0:
ts.add("BACKGROUND", (0, i), (indent-1, i), C_WHITE)
ts.add("SPAN", (indent, i), (NCOLS-1, i))
t.setStyle(ts)
return t
# ── Main content builder ──────────────────────────────────────────────────────
def build_story():
story = []
# ── COVER ─────────────────────────────────────────────────────────────────
cover_data = [[
Paragraph("INDIAN COURT HIERARCHY", sTitle),
Spacer(1, 6),
Paragraph("& JURISDICTION", sTitle),
Spacer(1, 10),
Paragraph("Comprehensive Study Guide", sSubtitle),
Spacer(1, 6),
Paragraph("Agada Tantra & Vidhi Vaidyak | Chapter 17", sSubtitle),
]]
cover_t = Table(cover_data, colWidths=[W - 4*cm])
cover_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_NAVY),
("TOPPADDING", (0,0), (-1,-1), 30),
("BOTTOMPADDING", (0,0), (-1,-1), 30),
("LEFTPADDING", (0,0), (-1,-1), 20),
("RIGHTPADDING", (0,0), (-1,-1), 20),
]))
story.append(cover_t)
story.append(Spacer(1, 14))
# Quick overview boxes
overview = [
("4", "Criminal\nCourt Types"),
("3", "Magistrate\nCourt Types"),
("2", "Inquest\nTypes in India"),
("2", "Evidence\nForms"),
]
ov_cells = []
for num, label in overview:
cell = Table([
[Paragraph(f"<b>{num}</b>", make_style("_n", fontSize=22, textColor=C_GOLD,
fontName="Helvetica-Bold", alignment=TA_CENTER))],
[Paragraph(label, make_style("_l", fontSize=9, textColor=C_WHITE,
fontName="Helvetica", alignment=TA_CENTER, leading=12))],
], colWidths=[3.5*cm])
cell.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_BLUE),
("BOX", (0,0), (-1,-1), 1, C_GOLD),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
]))
ov_cells.append(cell)
ov_t = Table([ov_cells], colWidths=[3.6*cm]*4)
ov_t.setStyle(TableStyle([("LEFTPADDING",(0,0),(-1,-1),3),("RIGHTPADDING",(0,0),(-1,-1),3)]))
story.append(ov_t)
story.append(Spacer(1, 16))
# ── SECTION 1: Court Hierarchy Diagram ────────────────────────────────────
story.append(sec_header("1. Court Hierarchy at a Glance", C_NAVY))
story.append(Spacer(1, 8))
story.append(Paragraph(
"India's judicial system is hierarchical. At the apex is the <b>Supreme Court</b>, "
"followed by <b>High Courts</b> at state level, <b>District/Session Courts</b> at district "
"level, and <b>Magistrate Courts</b> at the lower level. <b>Lok Adalats</b> operate at "
"village/Panchayat level.",
sBody))
story.append(Spacer(1, 8))
story.append(court_hierarchy_diagram())
story.append(Spacer(1, 6))
story.append(Paragraph("* Arrow indicates appellate direction (lower → higher)", sSmall))
story.append(Spacer(1, 14))
# ── SECTION 2: Supreme Court ──────────────────────────────────────────────
story.append(sec_header("2. Supreme Court", C_NAVY))
story.append(Spacer(1, 6))
sc_data = [
[Paragraph("<b>Feature</b>", sTableHdr), Paragraph("<b>Details</b>", sTableHdr)],
[Paragraph("Location", sTableCell), Paragraph("New Delhi", sTableCell)],
[Paragraph("Established", sTableCell), Paragraph("28 January 1950 (two days after Constitution came into effect)", sTableCell)],
[Paragraph("Composition", sTableCell), Paragraph("Chief Justice of India + 25 other judges", sTableCell)],
[Paragraph("Appointments", sTableCell), Paragraph("Directly by the President of India", sTableCell)],
[Paragraph("Original Jurisdiction", sTableCell), Paragraph("Protection of Fundamental Rights; settling disputes between governments", sTableCell)],
[Paragraph("Appellate Role", sTableCell), Paragraph("Highest court of appeal in India", sTableCell)],
[Paragraph("Law binding on", sTableCell), Paragraph("All courts within India", sTableCell)],
[Paragraph("Guardian of", sTableCell), Paragraph("The Constitution of India", sTableCell)],
]
sc_t = Table(sc_data, colWidths=[5.5*cm, W - 4*cm - 5.5*cm])
sc_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_NAVY),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_GREY]),
("BOX", (0,0), (-1,-1), 0.8, C_NAVY),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(sc_t)
story.append(Spacer(1, 14))
# ── SECTION 3: High Court ─────────────────────────────────────────────────
story.append(sec_header("3. High Court", C_BLUE))
story.append(Spacer(1, 6))
hc_data = [
[Paragraph("<b>Feature</b>", sTableHdr), Paragraph("<b>Details</b>", sTableHdr)],
[Paragraph("Level", sTableCell), Paragraph("State level (present in almost all states and union territories)", sTableCell)],
[Paragraph("Supervising body", sTableCell),Paragraph("Works under superintendence, direction, and control of the Supreme Court", sTableCell)],
[Paragraph("Original Jurisdiction", sTableCell), Paragraph("Cases brought directly to it (civil and criminal)", sTableCell)],
[Paragraph("Appellate Jurisdiction", sTableCell),Paragraph("Appeals against decisions of lower/district courts", sTableCell)],
[Paragraph("Special cases heard", sTableCell), Paragraph("Patents, designs, succession, land acquisition, insolvency, guardianship", sTableCell)],
[Paragraph("Death sentence", sTableCell), Paragraph("Must confirm any death sentence passed by Sessions Court before execution", sTableCell)],
[Paragraph("Powers over Sessions Court", sTableCell), Paragraph("Accept, alter, increase/reduce sentence, change nature, or acquit accused", sTableCell)],
]
hc_t = Table(hc_data, colWidths=[5.5*cm, W - 4*cm - 5.5*cm])
hc_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LBLUE]),
("BOX", (0,0), (-1,-1), 0.8, C_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(hc_t)
story.append(Spacer(1, 14))
# ── SECTION 4: District / Session Court ───────────────────────────────────
story.append(sec_header("4. District / Session Court", C_TEAL))
story.append(Spacer(1, 6))
ds_data = [
[Paragraph("<b>Feature</b>", sTableHdr), Paragraph("<b>Details</b>", sTableHdr)],
[Paragraph("Also known as", sTableCell), Paragraph("District Session Court", sTableCell)],
[Paragraph("Location", sTableCell), Paragraph("District headquarters", sTableCell)],
[Paragraph("Presided by", sTableCell), Paragraph("District and Session Judge (known as District Judge in civil / Session Judge in criminal cases)", sTableCell)],
[Paragraph("Sentencing power", sTableCell),Paragraph("Any sentence authorised by law; death sentences need High Court confirmation", sTableCell)],
[Paragraph("Ass. Session Judge", sTableCell), Paragraph("Any sentence except death or imprisonment > 10 years", sTableCell)],
[Paragraph("District Judge", sTableCell), Paragraph("Power to improve any sentence, including capital punishment", sTableCell)],
[Paragraph("Sub-courts", sTableCell), Paragraph("Civil, Criminal, and Revenue subordinate courts in each district", sTableCell)],
]
ds_t = Table(ds_data, colWidths=[5.5*cm, W - 4*cm - 5.5*cm])
ds_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_TEAL),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LTEAL]),
("BOX", (0,0), (-1,-1), 0.8, C_TEAL),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(ds_t)
story.append(Spacer(1, 14))
# ── SECTION 5: Magistrate Court comparison ────────────────────────────────
story.append(sec_header("5. Magistrate Courts - Comparison", C_GREEN))
story.append(Spacer(1, 6))
mag_data = [
[Paragraph("<b>Type</b>", sTableHdr),
Paragraph("<b>Try Cases</b>", sTableHdr),
Paragraph("<b>Max Imprisonment</b>", sTableHdr),
Paragraph("<b>Max Fine</b>", sTableHdr)],
[Paragraph("Chief Judicial Magistrate", sTableCell),
Paragraph("Any case except death sentence", sTableCell),
Paragraph("7 years", sTableCell),
Paragraph("Unlimited", sTableCell)],
[Paragraph("1st Class Magistrate", sTableCell),
Paragraph("All except murder, rape, miscarriage; can only enquire + send to Sessions Court for those", sTableCell),
Paragraph("3 years (incl. solitary confinement)", sTableCell),
Paragraph("Rs. 10,000", sTableCell)],
[Paragraph("2nd Class Magistrate", sTableCell),
Paragraph("Offences punishable up to 1 year imprisonment", sTableCell),
Paragraph("1 year", sTableCell),
Paragraph("Rs. 5,000", sTableCell)],
]
mag_t = Table(mag_data, colWidths=[4*cm, 7*cm, 3.5*cm, 3*cm])
mag_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_GREEN),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LGREEN]),
("BOX", (0,0), (-1,-1), 0.8, C_GREEN),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(mag_t)
story.append(Spacer(1, 10))
# Juvenile Magistrates note
juv_box_content = [
Paragraph("Juvenile Magistrates", sBoxTitle),
Paragraph(
"Usually ladies preside. Handle <b>juvenile offenders</b> - boys below <b>16 years</b> "
"and girls below <b>18 years</b> accused of a crime. Governed by <b>Children Act 1960</b>. "
"Focus: treatment, training and rehabilitation (not punishment).",
sBody),
]
story.append(colored_box(juv_box_content, bg=C_LPURPLE, border=C_PURPLE))
story.append(Spacer(1, 14))
# ── SECTION 6: Subordinate Courts Structure ───────────────────────────────
story.append(sec_header("6. Subordinate / Lower Courts Structure", C_ORANGE))
story.append(Spacer(1, 8))
sub_data = [
[Paragraph("<b>Civil Courts</b>", sTableHdr),
Paragraph("<b>Criminal Courts</b>", sTableHdr),
Paragraph("<b>Revenue Courts</b>", sTableHdr)],
[Paragraph("District Judge / District & Sessions Judge", sTableCell),
Paragraph("Session Judge / District & Sessions Judge", sTableCell),
Paragraph("Board of Revenue", sTableCell)],
[Paragraph("Sub Judge / Family Courts", sTableCell),
Paragraph("Metropolitan Magistrate", sTableCell),
Paragraph("Commissioner / Collector", sTableCell)],
[Paragraph("Munsif", sTableCell),
Paragraph("Class I Magistrate", sTableCell),
Paragraph("Tehsildar", sTableCell)],
[Paragraph("Small Causes Courts", sTableCell),
Paragraph("Class II / Class III Magistrate", sTableCell),
Paragraph("Naib Tehsildar", sTableCell)],
]
sub_t = Table(sub_data, colWidths=[(W-4*cm)/3]*3)
sub_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,0), C_ORANGE),
("BACKGROUND", (1,0), (1,0), C_ORANGE),
("BACKGROUND", (2,0), (2,0), C_ORANGE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LORANGE]),
("BOX", (0,0), (-1,-1), 0.8, C_ORANGE),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(sub_t)
story.append(Spacer(1, 6))
story.append(Paragraph(
"Revenue Courts: Hear land revenue cases. Board of Revenue is the highest revenue court in the district.",
sNote))
story.append(Spacer(1, 14))
# ── SECTION 7: Sentences Authorised by Law ────────────────────────────────
story.append(sec_header("7. Sentences Authorised by Law", C_NAVY))
story.append(Spacer(1, 6))
sent_data = [
[Paragraph("<b>#</b>", sTableHdr), Paragraph("<b>Sentence Type</b>", sTableHdr), Paragraph("<b>Notes</b>", sTableHdr)],
[Paragraph("1", sTableCellC), Paragraph("Death", sTableCell), Paragraph("Highest; Sessions Court sentence must be confirmed by High Court", sTableCell)],
[Paragraph("2", sTableCellC), Paragraph("Life Imprisonment", sTableCell), Paragraph("Cannot be awarded by 2nd Class Magistrate", sTableCell)],
[Paragraph("3", sTableCellC), Paragraph("Fine", sTableCell), Paragraph("Varies by court level", sTableCell)],
[Paragraph("4", sTableCellC), Paragraph("Forfeiture of Property", sTableCell),Paragraph("May accompany other sentences", sTableCell)],
[Paragraph("5", sTableCellC), Paragraph("Treatment/Rehabilitation", sTableCell),Paragraph("For youthful offenders under Children Act 1960", sTableCell)],
]
sent_t = Table(sent_data, colWidths=[1*cm, 5*cm, W - 4*cm - 6*cm])
sent_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_NAVY),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_GREY]),
("BOX", (0,0), (-1,-1), 0.8, C_NAVY),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(sent_t)
story.append(Spacer(1, 14))
# ── PAGE BREAK ─────────────────────────────────────────────────────────────
story.append(PageBreak())
# ── SECTION 8: Jurisdiction types ─────────────────────────────────────────
story.append(sec_header("8. Types of Jurisdiction", C_PURPLE))
story.append(Spacer(1, 6))
jur_data = [
[Paragraph("<b>Jurisdiction</b>", sTableHdr),
Paragraph("<b>Definition</b>", sTableHdr),
Paragraph("<b>Court</b>", sTableHdr)],
[Paragraph("Original", sTableCell),
Paragraph("Cases brought directly to the court without going through a lower court first", sTableCell),
Paragraph("Supreme Court, High Court", sTableCell)],
[Paragraph("Appellate", sTableCell),
Paragraph("Court hears an appeal against a lower court's decision", sTableCell),
Paragraph("Supreme Court, High Court", sTableCell)],
[Paragraph("Supervisory", sTableCell),
Paragraph("Superintendence, direction, and control over subordinate courts", sTableCell),
Paragraph("Supreme Court (over all), High Court (over state courts)", sTableCell)],
]
jur_t = Table(jur_data, colWidths=[3.5*cm, 8*cm, 6*cm])
jur_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_PURPLE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LPURPLE]),
("BOX", (0,0), (-1,-1), 0.8, C_PURPLE),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(jur_t)
story.append(Spacer(1, 14))
# ── SECTION 9: CrPC Offence Types ─────────────────────────────────────────
story.append(sec_header("9. CrPC Offence Categories", C_TEAL))
story.append(Spacer(1, 6))
off_items = [
("Bailable offences", "Accused has right to get bail as a matter of right"),
("Non-bailable offences", "Bail is not a right; court's discretion"),
("Warrant Cases", "Cases involving offences punishable with death, life, or >2 years imprisonment"),
("Summons Cases", "Cases involving offences punishable with <2 years imprisonment"),
("Cognizable offences", "Police can arrest without warrant; can investigate without Magistrate's order"),
("Non-Cognizable offences", "Police cannot arrest without warrant; require Magistrate's order to investigate"),
]
off_data = [[Paragraph("<b>Category</b>", sTableHdr), Paragraph("<b>Description</b>", sTableHdr)]]
for cat, desc in off_items:
off_data.append([Paragraph(cat, sTableCell), Paragraph(desc, sTableCell)])
off_t = Table(off_data, colWidths=[5*cm, W-4*cm-5*cm])
off_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_TEAL),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LTEAL]),
("BOX", (0,0), (-1,-1), 0.8, C_TEAL),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(off_t)
story.append(Spacer(1, 14))
# ── SECTION 10: Key Definitions ────────────────────────────────────────────
story.append(sec_header("10. Key Definitions", C_NAVY))
story.append(Spacer(1, 6))
defs = [
("Court", "A body presided over by a judge/magistrate acting as a tribunal in civil and criminal cases."),
("Judiciary", "The system of courts that interprets and applies the law collectively."),
("Venue", "The place where a court sits."),
("Courtroom", "The room/building where court proceedings occur."),
("Inquest", "A legal or judicial inquiry to ascertain facts where death is under suspicious circumstances."),
("Panchnama", "The inquiry report prepared by police during a Police Inquest (BNSS 176)."),
("Subpoena", "A written document compelling a witness to attend court on a specified date under penalty (64 BNSS / 62 CrPC)."),
("Conduct Money", "Fee tendered to cover a witness's expense to attend court in civil cases."),
("Oath", "A solemn promise by a witness to tell the truth before giving evidence (Sec. 1(23) BNS)."),
("Perjury", "Knowingly making a false statement after taking oath - an offence (Sec. BNS 227 / Sec. 193 IPC)."),
]
def_data = [[Paragraph("<b>Term</b>", sTableHdr), Paragraph("<b>Definition</b>", sTableHdr)]]
for term, defn in defs:
def_data.append([Paragraph(f"<b>{term}</b>", sTableCell), Paragraph(defn, sTableCell)])
def_t = Table(def_data, colWidths=[4*cm, W-4*cm-4*cm])
def_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_NAVY),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_GREY]),
("BOX", (0,0), (-1,-1), 0.8, C_NAVY),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(def_t)
story.append(Spacer(1, 14))
# ── PAGE BREAK ─────────────────────────────────────────────────────────────
story.append(PageBreak())
# ── SECTION 11: Quick Revision - Q&A ──────────────────────────────────────
story.append(sec_header("11. Quick Revision - Q&A", C_ORANGE))
story.append(Spacer(1, 8))
qa_pairs = [
("Q1. Where is the Supreme Court situated?",
"New Delhi. It came into power on 28 January 1950."),
("Q2. How many judges are in the Supreme Court?",
"Chief Justice of India + 25 other judges = 26 total. Appointed by the President of India."),
("Q3. What is the difference between Original and Appellate Jurisdiction?",
"Original Jurisdiction = cases brought directly to the court. Appellate Jurisdiction = court hears an appeal against a lower court's decision."),
("Q4. What must happen before a death sentence from Sessions Court is executed?",
"The High Court must confirm the death sentence even if the accused does not file an appeal."),
("Q5. Which Magistrate cannot try murder, rape, or miscarriage cases?",
"1st Class Magistrate - can only enquire into such cases and send them to Sessions Court for trial."),
("Q6. What is a Juvenile offender?",
"Boys below 16 years and girls below 18 years accused of a crime. Handled under the Children Act 1960."),
("Q7. What is a Cognizable offence?",
"An offence where police can arrest without a warrant and investigate without a Magistrate's order."),
("Q8. What are the 4 questions answered by a Police Inquest?",
"Q1: Identity of the deceased | Q2: Place of death | Q3: Time of death | Q4: Apparent cause of death"),
("Q9. What is the difference between Bailable and Non-bailable offences?",
"Bailable: accused has a right to get bail. Non-bailable: bail is at the court's discretion, not a right."),
("Q10. What is Perjury?",
"Knowingly making a false statement after taking an oath or solemn affirmation - an offence under Sec. BNS 227 / Sec. 193 IPC."),
("Q11. Who conducts a Magistrate Inquest?",
"District Magistrate, Judicial Magistrate, or any Executive Magistrate empowered by the State Government (Sec. 196 BNSS / Sec. 176 CrPC)."),
("Q12. What is Panchnama?",
"The inquiry report prepared by police at the end of a Police Inquest (under BNSS 176)."),
]
for q, a in qa_pairs:
story.append(Paragraph(q, sQAQ))
story.append(Paragraph(a, sQAA))
story.append(Spacer(1, 14))
# ── SECTION 12: Memory Aids ────────────────────────────────────────────────
story.append(sec_header("12. Memory Aids & Mnemonics", C_PURPLE))
story.append(Spacer(1, 8))
# Mnemonic 1
mn1 = colored_box([
Paragraph("Criminal Courts Hierarchy - <b>\"S H D M\"</b>", sMemonic),
Paragraph(
"<b>S</b>upreme Court | <b>H</b>igh Court | <b>D</b>istrict/Session Court | <b>M</b>agistrate Court",
make_style("_m1", fontSize=10, textColor=C_NAVY, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=14)),
Spacer(1, 4),
Paragraph(
"Remember: <i>\"Some Hierarchies Define Magistrates\"</i>",
make_style("_m1b", fontSize=10, textColor=C_PURPLE, alignment=TA_CENTER,
fontName="Helvetica-Oblique")),
], bg=C_LPURPLE, border=C_PURPLE)
story.append(mn1)
story.append(Spacer(1, 10))
# Mnemonic 2
mn2 = colored_box([
Paragraph("Sentences by Law - <b>\"D L F F T\"</b>", sMemonic),
Paragraph(
"<b>D</b>eath | <b>L</b>ife imprisonment | <b>F</b>ine | <b>F</b>orfeiture | <b>T</b>reatment/Rehabilitation",
make_style("_m2", fontSize=10, textColor=C_NAVY, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=14)),
Spacer(1, 4),
Paragraph(
"Remember: <i>\"Don't Let Felons Forget Treatment\"</i>",
make_style("_m2b", fontSize=10, textColor=C_PURPLE, alignment=TA_CENTER,
fontName="Helvetica-Oblique")),
], bg=C_LPURPLE, border=C_PURPLE)
story.append(mn2)
story.append(Spacer(1, 10))
# Mnemonic 3
mn3 = colored_box([
Paragraph("4 Qs of Police Inquest - <b>\"I P T C\"</b>", sMemonic),
Paragraph(
"<b>I</b>dentity of deceased | <b>P</b>lace of death | <b>T</b>ime of death | <b>C</b>ause of death",
make_style("_m3", fontSize=10, textColor=C_NAVY, alignment=TA_CENTER,
fontName="Helvetica-Bold", leading=14)),
Spacer(1, 4),
Paragraph(
"Remember: <i>\"Investigating Police Track Cases\"</i>",
make_style("_m3b", fontSize=10, textColor=C_PURPLE, alignment=TA_CENTER,
fontName="Helvetica-Oblique")),
], bg=C_LPURPLE, border=C_PURPLE)
story.append(mn3)
story.append(Spacer(1, 14))
# ── SECTION 13: Comparison Tables ─────────────────────────────────────────
story.append(sec_header("13. Important Comparisons", C_BLUE))
story.append(Spacer(1, 8))
# Inquest comparison
story.append(Paragraph("Types of Inquest in India:", sSection))
inq_data = [
[Paragraph("<b>Feature</b>", sTableHdr),
Paragraph("<b>Police Inquest</b>", sTableHdr),
Paragraph("<b>Magistrate Inquest</b>", sTableHdr)],
[Paragraph("Authority", sTableCell), Paragraph("Police officer (not below rank of senior head constable)", sTableCell), Paragraph("District/Judicial/Executive Magistrate", sTableCell)],
[Paragraph("Legal provision", sTableCell), Paragraph("BNSS 194 / Sec 174 CrPC", sTableCell), Paragraph("Sec. 196 BNSS / Sec. 176 CrPC", sTableCell)],
[Paragraph("Frequency", sTableCell), Paragraph("Held routinely for suspicious deaths", sTableCell), Paragraph("Only when specially indicated", sTableCell)],
[Paragraph("Report called", sTableCell), Paragraph("Panchnama", sTableCell), Paragraph("Magistrate's report", sTableCell)],
[Paragraph("Geographic scope", sTableCell), Paragraph("All of India", sTableCell), Paragraph("Practical all over India", sTableCell)],
]
inq_t = Table(inq_data, colWidths=[4*cm, (W-4*cm-4*cm)/2, (W-4*cm-4*cm)/2])
inq_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_BLUE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LBLUE]),
("BOX", (0,0), (-1,-1), 0.8, C_BLUE),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(inq_t)
story.append(Spacer(1, 12))
# Dying declaration vs deposition
story.append(Paragraph("Dying Declaration vs Dying Deposition:", sSection))
dd_data = [
[Paragraph("<b>Feature</b>", sTableHdr),
Paragraph("<b>Dying Declaration</b>", sTableHdr),
Paragraph("<b>Dying Deposition</b>", sTableHdr)],
[Paragraph("Recorded by", sTableCell), Paragraph("Anyone", sTableCell), Paragraph("Magistrate only", sTableCell)],
[Paragraph("Oath required", sTableCell), Paragraph("Not required", sTableCell), Paragraph("Yes - oath is must", sTableCell)],
[Paragraph("Legal value", sTableCell), Paragraph("Less", sTableCell), Paragraph("More (higher legal weight)", sTableCell)],
[Paragraph("Type of evidence", sTableCell), Paragraph("Documentary", sTableCell), Paragraph("Oral evidence needed", sTableCell)],
[Paragraph("Who present", sTableCell), Paragraph("Any respectable witnesses", sTableCell), Paragraph("Accused or his lawyer present", sTableCell)],
[Paragraph("Cross-examination", sTableCell), Paragraph("Not possible", sTableCell), Paragraph("Possible by accused's lawyer", sTableCell)],
]
dd_t = Table(dd_data, colWidths=[4*cm, (W-4*cm-4*cm)/2, (W-4*cm-4*cm)/2])
dd_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_TEAL),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LTEAL]),
("BOX", (0,0), (-1,-1), 0.8, C_TEAL),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(dd_t)
story.append(Spacer(1, 14))
# ── SECTION 14: Examination types ─────────────────────────────────────────
story.append(sec_header("14. Types of Examination in Court", C_GREEN))
story.append(Spacer(1, 6))
exam_data = [
[Paragraph("<b>Type</b>", sTableHdr),
Paragraph("<b>Section</b>", sTableHdr),
Paragraph("<b>By Whom</b>", sTableHdr),
Paragraph("<b>Purpose</b>", sTableHdr)],
[Paragraph("Examination-in-Chief", sTableCell),
Paragraph("Sec. 142 BSA / 137 IPC", sTableCell),
Paragraph("Your own counsel", sTableCell),
Paragraph("Places principal facts on record; establishes your credentials and evidence", sTableCell)],
[Paragraph("Cross-examination", sTableCell),
Paragraph("Sec. 146-149 BSA / 141-146 IEA", sTableCell),
Paragraph("Opposing counsel", sTableCell),
Paragraph("Weaken or discredit evidence; show details are inaccurate/contradictory; leading questions allowed", sTableCell)],
[Paragraph("Re-examination", sTableCell),
Paragraph("Sec. 143 BSA / 138 IEA", sTableCell),
Paragraph("Your own counsel (again)", sTableCell),
Paragraph("Explain discrepancies from cross-exam; no new matter without judge's consent", sTableCell)],
[Paragraph("Court questions", sTableCell),
Paragraph("-", sTableCell),
Paragraph("The Judge", sTableCell),
Paragraph("Clear up ambiguous or doubtful points at any stage of trial", sTableCell)],
]
exam_t = Table(exam_data, colWidths=[3.5*cm, 4*cm, 3.5*cm, W-4*cm-11*cm])
exam_t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_GREEN),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LGREEN]),
("BOX", (0,0), (-1,-1), 0.8, C_GREEN),
("INNERGRID", (0,0), (-1,-1), 0.4, colors.HexColor("#b0bec5")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]))
story.append(exam_t)
story.append(Spacer(1, 14))
# ── FOOTER NOTE ────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=1.5, color=C_NAVY))
story.append(Spacer(1, 6))
story.append(Paragraph(
"Source: Textbook of Agada Tantra and Vidhi Vaidyak, Chapter 17 - Legal Procedures, Courts, and Medical Evidence",
sSmall))
story.append(Paragraph(
"This study guide is intended for academic purposes only.",
sSmall))
return story
# ── Build PDF ─────────────────────────────────────────────────────────────────
def on_first_page(canvas, doc):
pass
def on_later_pages(canvas, doc):
canvas.saveState()
canvas.setFont("Helvetica", 8)
canvas.setFillColor(C_DGREY)
canvas.drawString(2*cm, 1.2*cm, "Indian Court Hierarchy & Jurisdiction - Study Guide")
canvas.drawRightString(W - 2*cm, 1.2*cm, f"Page {doc.page}")
canvas.restoreState()
doc = SimpleDocTemplate(
OUTPUT_PATH,
pagesize=A4,
leftMargin=2*cm,
rightMargin=2*cm,
topMargin=2*cm,
bottomMargin=2*cm,
title="Indian Court Hierarchy & Jurisdiction - Study Guide",
author="Agada Tantra & Vidhi Vaidyak",
subject="Legal Procedures, Courts, Jurisdiction",
)
story = build_story()
doc.build(story, onFirstPage=on_first_page, onLaterPages=on_later_pages)
print(f"PDF saved to: {OUTPUT_PATH}")