How to do ring invagination test Step wise manner
ring invagination test intestinal atresia stepwise procedure
ring invagination test bowel patency neonatal surgery technique steps


| Finding | Indirect (Oblique) Hernia | Direct Hernia |
|---|---|---|
| Direction finger travels | Upward, backward, lateral | Directly backward |
| Cough impulse felt on | Tip of finger | Pulp of finger |
| Ring occlusion test | Hernia does NOT appear (ring is occluded) | Hernia appears medial to occluding finger |
More easy steps
Position: Nail faces the spermatic cord. Pulp faces the ring.
| Impulse felt on... | Means... |
|---|---|
| Tip of finger | Indirect hernia |
| Pulp of finger | Direct hernia |
| No impulse, canal empty | Femoral hernia |
| Finger gets squeezed (no impulse) | Normal - no hernia |
"TIP = Indirect" (T for Tip, I for Indirect) The sac travels the long indirect route down the canal and taps the fingertip. Direct hernia punches straight back into the pulp (the flat face of your finger).
Create a quick reference guide on hernia examination
mkdir -p /tmp/workspace/hernia-guide && ls /tmp/workspace/
~/hernia-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 mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import PageBreak
OUTPUT = "/tmp/workspace/hernia-guide/Hernia_Examination_Quick_Reference.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
NAVY = colors.HexColor("#1a3a5c")
TEAL = colors.HexColor("#0e7c7b")
AMBER = colors.HexColor("#e07b00")
LIGHT_BG = colors.HexColor("#f0f4f8")
HIGHLIGHT = colors.HexColor("#fff3cd")
RED_ALERT = colors.HexColor("#c0392b")
GREEN_OK = colors.HexColor("#1e7e34")
WHITE = colors.white
LIGHT_TEAL= colors.HexColor("#e6f5f5")
LIGHT_AMBER=colors.HexColor("#fff8e6")
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
topMargin=15*mm, bottomMargin=15*mm,
leftMargin=15*mm, rightMargin=15*mm,
title="Hernia Examination Quick Reference Guide",
author="Orris Medical"
)
styles = getSampleStyleSheet()
# Custom styles
def S(name, **kw):
return ParagraphStyle(name, **kw)
title_style = S("Title2", fontSize=22, textColor=WHITE, alignment=TA_CENTER,
fontName="Helvetica-Bold", spaceAfter=4)
subtitle_style = S("Sub2", fontSize=11, textColor=colors.HexColor("#cfe8f3"),
alignment=TA_CENTER, fontName="Helvetica", spaceAfter=2)
section_header = S("SH", fontSize=13, textColor=WHITE, fontName="Helvetica-Bold",
alignment=TA_LEFT, spaceAfter=2, spaceBefore=4,
backColor=TEAL, leftIndent=6, rightIndent=6,
borderPad=4)
sub_section = S("SSH", fontSize=11, textColor=NAVY, fontName="Helvetica-Bold",
spaceAfter=3, spaceBefore=5)
body_style = S("Body2", fontSize=9, fontName="Helvetica", leading=14,
spaceAfter=2, textColor=colors.HexColor("#2c2c2c"))
bullet_style = S("Bull", fontSize=9, fontName="Helvetica", leading=13,
leftIndent=12, bulletIndent=4, spaceAfter=1,
textColor=colors.HexColor("#2c2c2c"))
bold_bullet = S("BoldBull", fontSize=9, fontName="Helvetica-Bold", leading=13,
leftIndent=12, bulletIndent=4, spaceAfter=1, textColor=NAVY)
note_style = S("Note", fontSize=8.5, fontName="Helvetica-Oblique",
textColor=colors.HexColor("#555555"), leading=12,
leftIndent=8, spaceAfter=2)
alert_style = S("Alert", fontSize=9, fontName="Helvetica-Bold",
textColor=RED_ALERT, leading=12, spaceAfter=2)
footer_style = S("Footer", fontSize=7.5, textColor=colors.HexColor("#888888"),
alignment=TA_CENTER, fontName="Helvetica-Oblique")
def section_box(title):
"""Returns a coloured section header table."""
t = Table([[Paragraph(title, S("SHi", fontSize=12, textColor=WHITE,
fontName="Helvetica-Bold", spaceAfter=0))]],
colWidths=[180*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), TEAL),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def amber_box(title):
t = Table([[Paragraph(title, S("AH", fontSize=11, textColor=WHITE,
fontName="Helvetica-Bold", spaceAfter=0))]],
colWidths=[180*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), AMBER),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
def navy_box(title):
t = Table([[Paragraph(title, S("NH", fontSize=12, textColor=WHITE,
fontName="Helvetica-Bold", spaceAfter=0))]],
colWidths=[180*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
return t
story = []
# ─────────────────────────────────────────────────────────────────────────────
# TITLE BANNER
# ─────────────────────────────────────────────────────────────────────────────
title_table = Table(
[[Paragraph("HERNIA EXAMINATION", title_style)],
[Paragraph("Quick Reference Guide", subtitle_style)],
[Paragraph("Source: S. Das — A Manual on Clinical Surgery, 13th Edition",
S("src", fontSize=8.5, textColor=colors.HexColor("#a8d4e8"),
alignment=TA_CENTER, fontName="Helvetica-Oblique", spaceAfter=0))]],
colWidths=[180*mm]
)
title_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (0,0), 14),
("BOTTOMPADDING",(0,2),(0,2), 12),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
story.append(title_table)
story.append(Spacer(1, 6*mm))
# ─────────────────────────────────────────────────────────────────────────────
# ROW 1: History + Inspection (side by side)
# ─────────────────────────────────────────────────────────────────────────────
def make_cell_content(items):
"""items: list of (bold_label, text) or (None, text)"""
paras = []
for label, text in items:
if label:
paras.append(Paragraph(f"<b>{label}</b> {text}", body_style))
else:
paras.append(Paragraph(text, body_style))
return paras
# --- HISTORY CELL ---
hist_items = [
("Onset:", "Started on straining/coughing/lifting?"),
("Where first?", "Groin → scrotum = Inguinal; Below groin → up = Femoral"),
("Size at onset:", "Reaches scrotum at onset = Congenital sac"),
("Reduces lying down?", "Direct hernia → auto-reduces; Indirect → needs manual reduction"),
("Systemic:", "Colicky pain + vomiting + distension + constipation → Obstruction"),
("Causes:", "Chronic cough, constipation, BPH (straining factors)"),
]
hist_paras = [Paragraph("<b>• " + l + "</b> " + t, body_style) for l, t in hist_items]
hist_cell = [
Table([[Paragraph("HISTORY", S("CH", fontSize=11, textColor=WHITE,
fontName="Helvetica-Bold"))]],
colWidths=[85*mm],
style=TableStyle([("BACKGROUND",(0,0),(-1,-1),TEAL),
("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6)])),
] + hist_paras
# --- INSPECTION CELL ---
insp_items = [
("Shape:", "Inguinal = pear-shaped (can extend to scrotum); Femoral = spherical (retort-shaped)"),
("Position:", "Inguinal = above & medial to pubic tubercle; Femoral = below & lateral"),
("Skin:", "Normal = uncomplicated; Red = strangulated; Pigmented streaks = truss use"),
("Cough impulse:", "Visible expansion/bulge synchronous with cough = hernia"),
("Peristalsis:", "Visible peristalsis only in recurrent inguinal hernia (thin skin)"),
("Penis position:", "Pushed to opposite side in large inguinoscrotal hernia"),
]
insp_paras = [Paragraph("<b>• " + l + "</b> " + t, body_style) for l, t in insp_items]
insp_cell = [
Table([[Paragraph("INSPECTION", S("CH2", fontSize=11, textColor=WHITE,
fontName="Helvetica-Bold"))]],
colWidths=[85*mm],
style=TableStyle([("BACKGROUND",(0,0),(-1,-1),TEAL),
("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6)])),
] + insp_paras
two_col = Table(
[[hist_cell, insp_cell]],
colWidths=[89*mm, 89*mm],
spaceBefore=0
)
two_col.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 2),
("RIGHTPADDING",(0,0), (-1,-1), 2),
("BACKGROUND", (0,0), (0,0), LIGHT_BG),
("BACKGROUND", (1,0), (1,0), LIGHT_BG),
("BOX", (0,0), (0,0), 0.5, colors.HexColor("#aaaaaa")),
("BOX", (1,0), (1,0), 0.5, colors.HexColor("#aaaaaa")),
]))
story.append(two_col)
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# PALPATION — KEY TESTS
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_box("PALPATION — KEY EXAMINATION TESTS"))
story.append(Spacer(1, 3*mm))
# Test 1: Cough impulse
story.append(Paragraph("1. Impulse on Coughing", sub_section))
story.append(Paragraph(
"Ask patient to cough while placing a flat hand over the swelling. "
"<b>Expansile impulse</b> (swelling expands outward on cough) = diagnostic of hernia. "
"Absence does not exclude hernia if neck is blocked by adhesions.", body_style))
story.append(Spacer(1, 2*mm))
# Test 2: Reducibility
story.append(Paragraph("2. Reducibility (Taxis)", sub_section))
palpation_data = [
["Step", "Action"],
["1", "Patient lies supine. Ask to flex, adduct & internally rotate the affected thigh."],
["2", "Gently hold the fundus of the sac with one hand."],
["3", "Apply even pressure squeezing contents toward and through the superficial ring."],
["4", "Gurgling on reduction = enterocele (intestine). Omentocele: last part resists."],
["5", "If unreducible → Irreducible / Obstructed / Strangulated hernia."],
]
t = Table(palpation_data, colWidths=[12*mm, 166*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), AMBER),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BG]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(t)
story.append(Spacer(1, 3*mm))
# Test 3: Consistency
story.append(Paragraph("3. Consistency of the Hernia", sub_section))
consist_data = [
["Consistency", "Contents", "Type"],
["Doughy / Granular", "Omentum", "Omentocele / Epiplocele"],
["Elastic / Resonant", "Intestine", "Enterocele"],
["Tense + Tender", "Compromised bowel", "Strangulated hernia ⚠"],
]
tc = Table(consist_data, colWidths=[45*mm, 55*mm, 78*mm])
tc.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BG, HIGHLIGHT]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(tc)
story.append(Spacer(1, 3*mm))
# Test 4: Relation to testis
story.append(Paragraph("4. Relation to Testis & Spermatic Cord", sub_section))
story.append(Paragraph(
"In <b>inguinal hernia</b>: hernia lies in <i>front and sides</i> of the cord — testis is incorporated. "
"You cannot get above the swelling. "
"In <b>scrotal swelling</b>: you can get above the swelling and feel normal cord above it.", body_style))
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# RING INVAGINATION TEST
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_box("RING INVAGINATION TEST (After reducing hernia)"))
story.append(Spacer(1, 3*mm))
inv_data = [
["Step", "Action", "Purpose"],
["PRE", "Reduce hernia first. Patient supine. Use little finger (R hand → R side).", "Setup"],
["1", "Start at bottom of scrotum. Invaginate scrotal skin inward and upward.", "Gain reach"],
["2", "Push finger up to touch the pubic tubercle (bony landmark).", "Locate landmark"],
["3", "Rotate finger and push into the superficial inguinal ring.\nNail faces cord. Pulp faces ring.", "Enter ring"],
["4", "Assess ring size. Normal = admits fingertip only.\nIf >1 finger fits = dilated ring.", "Size"],
["5", "Note direction the canal guides your finger:\n• Upward + backward + outward = Indirect track\n• Directly backward = Direct track", "Type of hernia"],
["6", "Rotate finger: pulp faces posteriorly. Ask patient to cough.", "Cough test"],
["7", "Feel where impulse hits:\n• TIP of finger = Indirect (oblique) hernia\n• PULP of finger = Direct hernia\n• Canal empty = Femoral hernia\n• Finger squeezed, no impulse = Normal", "Interpretation"],
]
ti = Table(inv_data, colWidths=[12*mm, 100*mm, 66*mm])
ti.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), AMBER),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (0,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_TEAL, WHITE, LIGHT_TEAL, WHITE, LIGHT_TEAL, WHITE, HIGHLIGHT]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
]))
story.append(ti)
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# RING OCCLUSION TEST
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_box("RING OCCLUSION TEST (Confirmatory)"))
story.append(Spacer(1, 3*mm))
story.append(Paragraph(
"Performed in <b>standing position</b> after reducing hernia. Press thumb firmly over the <b>deep inguinal ring</b> "
"(½ inch above midpoint of inguinal ligament — mid-inguinal point). Ask patient to cough.",
body_style))
story.append(Spacer(1, 2*mm))
occ_data = [
["Result on Coughing", "Interpretation"],
["No bulge appears", "Indirect (oblique) hernia — sac cannot exit through occluded deep ring"],
["Bulge appears MEDIAL to thumb", "Direct hernia — exits through posterior wall, not through deep ring"],
["Bulge appears BELOW inguinal ligament", "Femoral hernia — occluding the ring has no effect"],
]
to2 = Table(occ_data, colWidths=[70*mm, 108*mm])
to2.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [LIGHT_BG, HIGHLIGHT, LIGHT_TEAL]),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(to2)
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# DIFFERENTIATION TABLE
# ─────────────────────────────────────────────────────────────────────────────
story.append(section_box("DIFFERENTIAL DIAGNOSIS: INDIRECT vs DIRECT vs FEMORAL"))
story.append(Spacer(1, 3*mm))
diff_data = [
["Feature", "Indirect (Oblique)", "Direct", "Femoral"],
["Age", "Any age", "> 40 yrs", "> 50 yrs (F > M)"],
["Sex", "M >> F", "M >> F", "F > M (2:1)"],
["Position\n(re: pubic tubercle)", "Above & medial", "Above & medial", "Below & lateral"],
["Shape", "Pear-shaped,\ndown to scrotum", "Spherical, rarely\ninto scrotum", "Retort-shaped\n(bulb turns upward)"],
["Reduces lying down?", "Manual reduction\nneeded (indirect)", "Auto-reduces\nimmediately", "May need manual\nreduction"],
["Invagination test\n(impulse felt on...)", "TIP of finger", "PULP of finger", "Canal EMPTY"],
["Ring occlusion test", "Hernia controlled\n(no bulge)", "Bulge appears\nMEDIAL to thumb", "Not controlled\n(below ring)"],
["Strangulation risk", "Moderate", "Low", "HIGH (rigid canal)"],
["Neck of sac", "Lateral to inferior\nepigastric artery", "Medial to inferior\nepigastric artery", "Below inguinal\nligament"],
]
td = Table(diff_data, colWidths=[42*mm, 46*mm, 46*mm, 44*mm])
td.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("BACKGROUND", (0,1), (0,-1), colors.HexColor("#e8edf2")),
("FONTSIZE", (0,0), (-1,-1), 8.5),
("ALIGN", (0,0), (-1,-1), "CENTER"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#aaaaaa")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BG, WHITE, LIGHT_BG, WHITE, LIGHT_BG, WHITE, LIGHT_BG, WHITE, LIGHT_BG]),
# Highlight strangulation row
("BACKGROUND", (3,8), (3,8), colors.HexColor("#fde8e8")),
("TEXTCOLOR", (3,8), (3,8), RED_ALERT),
("FONTNAME", (3,8), (3,8), "Helvetica-Bold"),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 4),
]))
story.append(td)
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# STRANGULATION / COMPLICATIONS — ALERT BOX
# ─────────────────────────────────────────────────────────────────────────────
story.append(amber_box("⚠ STRANGULATION — DO NOT MISS"))
story.append(Spacer(1, 2*mm))
strang_data = [
["Sign / Symptom", "Detail"],
["Tense, tender, irreducible lump", "Tense = diagnostic of strangulation"],
["Skin overlying = RED / INFLAMED", "Cellulitis over hernia sac"],
["Colicky abdominal pain + vomiting", "Signs of intestinal obstruction"],
["Faecal vomiting", "Late, ominous sign — indicates low obstruction"],
["Absent cough impulse", "Strangulated sac — blocked neck"],
["Femoral hernia strangulates MOST often", "Rigid walls of femoral canal"],
]
ts = Table(strang_data, colWidths=[75*mm, 103*mm])
ts.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), RED_ALERT),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, colors.HexColor("#fff0f0"), WHITE,
colors.HexColor("#fff0f0"), WHITE, colors.HexColor("#fde8e8")]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(ts)
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# PERCUSSION & AUSCULTATION
# ─────────────────────────────────────────────────────────────────────────────
perc_insp = Table(
[[
# Percussion
[
Table([[Paragraph("PERCUSSION", S("PCH", fontSize=11, textColor=WHITE, fontName="Helvetica-Bold"))]],
colWidths=[85*mm],
style=TableStyle([("BACKGROUND",(0,0),(-1,-1),TEAL),("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),("LEFTPADDING",(0,0),(-1,-1),6)])),
Paragraph("• <b>Resonant</b> → Enterocele (intestine)", body_style),
Paragraph("• <b>Dull</b> → Omentocele / Extraperitoneal fat", body_style),
Paragraph("• <b>Upper dull + lower resonant</b> → Mixed contents", body_style),
],
# Auscultation
[
Table([[Paragraph("AUSCULTATION", S("ACH", fontSize=11, textColor=WHITE, fontName="Helvetica-Bold"))]],
colWidths=[85*mm],
style=TableStyle([("BACKGROUND",(0,0),(-1,-1),TEAL),("TOPPADDING",(0,0),(-1,-1),4),
("BOTTOMPADDING",(0,0),(-1,-1),4),("LEFTPADDING",(0,0),(-1,-1),6)])),
Paragraph("• <b>Bowel sounds present</b> → Enterocele (live bowel)", body_style),
Paragraph("• <b>Bowel sounds absent</b> → Strangulated / Omentocele", body_style),
Paragraph("• Always auscultate before reducing obstructed hernia", body_style),
]
]],
colWidths=[89*mm, 89*mm]
)
perc_insp.setStyle(TableStyle([
("VALIGN", (0,0), (-1,-1), "TOP"),
("LEFTPADDING", (0,0), (-1,-1), 2),
("RIGHTPADDING",(0,0),(-1,-1), 2),
("BACKGROUND", (0,0), (0,0), LIGHT_BG),
("BACKGROUND", (1,0), (1,0), LIGHT_BG),
("BOX", (0,0), (0,0), 0.5, colors.HexColor("#aaaaaa")),
("BOX", (1,0), (1,0), 0.5, colors.HexColor("#aaaaaa")),
]))
story.append(perc_insp)
story.append(Spacer(1, 4*mm))
# ─────────────────────────────────────────────────────────────────────────────
# MEMORY AIDS
# ─────────────────────────────────────────────────────────────────────────────
story.append(navy_box("MEMORY AIDS"))
story.append(Spacer(1, 2*mm))
mem_data = [
["Mnemonic / Rule", "What it means"],
["TIP = Indirect", "Cough impulse on fingertip during invagination test = Indirect hernia\n(long oblique path taps the tip)"],
["PULP = Direct", "Cough impulse on pulp of finger = Direct hernia (punches straight back)"],
["EMPTY canal = Femoral", "Invagination test finds empty inguinal canal in femoral hernia"],
["TWO CLASSICAL SIGNS of hernia", "① Expansile impulse on coughing ② Reducibility"],
["Femoral strangulates FIRST", "Rigid femoral canal → earliest strangulation among all hernias"],
["Inguinal > Femoral in WOMEN too", "Even in women, inguinal hernia is commoner than femoral"],
]
tm = Table(mem_data, colWidths=[60*mm, 118*mm])
tm.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), NAVY),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("TEXTCOLOR", (0,1), (0,-1), TEAL),
("FONTSIZE", (0,0), (-1,-1), 9),
("ALIGN", (0,0), (-1,-1), "LEFT"),
("VALIGN", (0,0), (-1,-1), "TOP"),
("GRID", (0,0), (-1,-1), 0.4, colors.HexColor("#cccccc")),
("ROWBACKGROUNDS", (0,1), (-1,-1), [WHITE, LIGHT_BG, WHITE, LIGHT_BG, WHITE, LIGHT_BG]),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
]))
story.append(tm)
story.append(Spacer(1, 5*mm))
# ─────────────────────────────────────────────────────────────────────────────
# FOOTER
# ─────────────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=0.5, color=colors.HexColor("#aaaaaa")))
story.append(Spacer(1, 2*mm))
story.append(Paragraph(
"Orris Medical | Hernia Examination Quick Reference Guide | "
"Based on S. Das — Manual on Clinical Surgery, 13th Ed. | For educational use only",
footer_style))
# ─────────────────────────────────────────────────────────────────────────────
# BUILD
# ─────────────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {OUTPUT}")
cd /tmp/workspace/hernia-guide && python generate_pdf.py
Hernia Examination Quick Reference
PDF Document · PDF
| Section | Contents |
|---|---|
| History | Onset, position, reducibility, obstruction symptoms, precipitating causes |
| Inspection | Shape, skin changes, cough impulse, peristalsis, penis position |
| Palpation - Key Tests | Taxis (reduction), consistency, relation to testis/cord |
| Ring Invagination Test | Full 7-step table with purpose of each step |
| Ring Occlusion Test | Confirmatory test with 3-way result interpretation |
| Differential Diagnosis Table | Indirect vs Direct vs Femoral - 10 features compared side by side |
| Strangulation Alert | Red-flagged warning box with all signs |
| Percussion & Auscultation | Resonant/dull findings, bowel sounds |
| Memory Aids | TIP = Indirect, PULP = Direct, EMPTY = Femoral, and more |