Inguinal hernia case presentation with detailed examination of direct and indirect Inguinal hernia and its management

Reading File
Finding Sources
Finding Sources
Searching Images

inguinal hernia anatomy direct indirect comparison diagram

This diagnostic comparison uses laparoscopic (endoscopic) imaging to demonstrate the internal anatomical differences between an indirect and a direct inguinal hernia. Image A displays an indirect inguinal hernia, characterized by a rounded protrusion located lateral to the inferior epigastric vessels. The defect is clearly defined with a localized network of fine vasculature concentrated near the base of the herniated sac. Image B depicts a direct inguinal hernia, presenting as a more diffuse, wide-based bulge through the abdominal wall, located medial to the epigastric vessels in Hesselbach's triangle. The borders of the direct hernia are less distinct than the indirect type, and the overlying peritoneum shows a more prominent, dense, and tortuous vascular network. These images illustrate the surgical perspective during a Transabdominal Preperitoneal (TAPP) repair, emphasizing the importance of anatomical landmarks, specifically the inferior epigastric vessels, in differentiating hernia types based on their exit point relative to the deep inguinal ring.

This diagnostic comparison uses laparoscopic (endoscopic) imaging to demonstrate the internal anatomical differences between an indirect and a direct inguinal hernia. Image A displays an indirect inguinal hernia, characterized by a rounded protrusion located lateral to the inferior epigastric vessels. The defect is clearly defined with a localized network of fine vasculature concentrated near the base of the herniated sac. Image B depicts a direct inguinal hernia, presenting as a more diffuse, wide-based bulge through the abdominal wall, located medial to the epigastric vessels in Hesselbach's triangle. The borders of the direct hernia are less distinct than the indirect type, and the overlying peritoneum shows a more prominent, dense, and tortuous vascular network. These images illustrate the surgical perspective during a Transabdominal Preperitoneal (TAPP) repair, emphasizing the importance of anatomical landmarks, specifically the inferior epigastric vessels, in differentiating hernia types based on their exit point relative to the deep inguinal ring.

This clinical photograph captures an intraoperative view of an inguinal hernia repair, illustrating complex regional anatomy and multiple hernia sacs. The surgical field displays a rare anatomical variation where the inferior epigastric artery (IEA) follows a superficial course along the posterior wall of the inguinal canal. Two distinct direct inguinal hernia sacs are visible: S1, located lateral to the IEA, and S2, located medial to the IEA. Sac S2 appears larger with a wider base compared to the more elongated S1. Additionally, an indirect hernia sac is identified lateral to the direct components. Surgical retractors are in place to expose the posterior wall and cord structures. This image serves as a high-level educational resource for surgical trainees, demonstrating the critical importance of identifying the inferior epigastric vessels to differentiate between direct and indirect hernia components and to recognize vascular anomalies during Lichtenstein or other inguinal hernioplasty procedures.

This clinical photograph captures an intraoperative view of an inguinal hernia repair, illustrating complex regional anatomy and multiple hernia sacs. The surgical field displays a rare anatomical variation where the inferior epigastric artery (IEA) follows a superficial course along the posterior wall of the inguinal canal. Two distinct direct inguinal hernia sacs are visible: S1, located lateral to the IEA, and S2, located medial to the IEA. Sac S2 appears larger with a wider base compared to the more elongated S1. Additionally, an indirect hernia sac is identified lateral to the direct components. Surgical retractors are in place to expose the posterior wall and cord structures. This image serves as a high-level educational resource for surgical trainees, demonstrating the critical importance of identifying the inferior epigastric vessels to differentiate between direct and indirect hernia components and to recognize vascular anomalies during Lichtenstein or other inguinal hernioplasty procedures.

This composite intraoperative clinical photograph illustrates the surgical anatomy of the posterior inguinal region during a laparoscopic hernia repair. Image A displays essential anatomical landmarks and triangles: a green triangle (D) representing the direct hernia area; a yellow triangle (I) for the indirect hernia area; a blue triangle (F) for the femoral hernia area; and the red 'Triangle of Doom' containing the external iliac vessels. Two orange regions (P1 and P2) designate 'Triangles of Pain,' with P2 highlighting a revised superior boundary (2 cm above the iliopubic tract) to account for variations in nerve branches (lateral cutaneous nerve of the thigh and genitofemoral nerve). Image B divides the surgical field into three zones for procedural standardization: Zone 1 (medial/inferior) focusing on Cooper's ligament and epigastric vessels, Zone 2 (central) involving the spermatic cord and vas deferens parietalization, and Zone 3 (lateral) encompassing the pain triangles. The images demonstrate the preperitoneal view necessary for TAPP/TEP procedures, emphasizing safe zones for mesh fixation to avoid neurovascular injury.

This composite intraoperative clinical photograph illustrates the surgical anatomy of the posterior inguinal region during a laparoscopic hernia repair. Image A displays essential anatomical landmarks and triangles: a green triangle (D) representing the direct hernia area; a yellow triangle (I) for the indirect hernia area; a blue triangle (F) for the femoral hernia area; and the red 'Triangle of Doom' containing the external iliac vessels. Two orange regions (P1 and P2) designate 'Triangles of Pain,' with P2 highlighting a revised superior boundary (2 cm above the iliopubic tract) to account for variations in nerve branches (lateral cutaneous nerve of the thigh and genitofemoral nerve). Image B divides the surgical field into three zones for procedural standardization: Zone 1 (medial/inferior) focusing on Cooper's ligament and epigastric vessels, Zone 2 (central) involving the spermatic cord and vas deferens parietalization, and Zone 3 (lateral) encompassing the pain triangles. The images demonstrate the preperitoneal view necessary for TAPP/TEP procedures, emphasizing safe zones for mesh fixation to avoid neurovascular injury.

This endoscopic clinical photograph illustrates the surgical anatomy of the posterior abdominal wall during a laparoscopic inguinal hernia repair (TAPP). The image depicts five critical anatomical zones, superimposed as color-coded triangles, essential for avoiding neurovascular complications. A blue star and line denote the inguinal ligament. The triangles are labeled as follows: Blue 'I' for the Indirect hernia space; Yellow 'D' for the Direct hernia space; Grey 'P' for the 'Triangle of Pain' (bounded by the spermatic vessels and iliopubic tract, containing the femoral branch of the genitofemoral nerve and lateral femoral cutaneous nerve); Black 'D' for the 'Triangle of Doom' (bounded by the vas deferens and spermatic vessels, containing the external iliac vessels); and Green 'F' for the Femoral hernia space. This visualization serves as a surgical guide to the 'myopectineal orifice' anatomy, emphasizing safe zones for mesh fixation and areas to avoid tacking to prevent chronic pain or hemorrhage.

This endoscopic clinical photograph illustrates the surgical anatomy of the posterior abdominal wall during a laparoscopic inguinal hernia repair (TAPP). The image depicts five critical anatomical zones, superimposed as color-coded triangles, essential for avoiding neurovascular complications. A blue star and line denote the inguinal ligament. The triangles are labeled as follows: Blue 'I' for the Indirect hernia space; Yellow 'D' for the Direct hernia space; Grey 'P' for the 'Triangle of Pain' (bounded by the spermatic vessels and iliopubic tract, containing the femoral branch of the genitofemoral nerve and lateral femoral cutaneous nerve); Black 'D' for the 'Triangle of Doom' (bounded by the vas deferens and spermatic vessels, containing the external iliac vessels); and Green 'F' for the Femoral hernia space. This visualization serves as a surgical guide to the 'myopectineal orifice' anatomy, emphasizing safe zones for mesh fixation and areas to avoid tacking to prevent chronic pain or hemorrhage.

This grayscale clinical photograph of a cadaveric dissection illustrates the surgical anatomy of the inguinal region, specifically highlighting the topographic relationships during an indirect inguinal hernia repair. The dissection reveals the inferior epigastric artery (IEA) running cranially and medially. Lateral and inferior to the IEA, an indirect inguinal hernia is visible, marked with a white star, having protruded through the deep inguinal ring lateral to the epigastric vessels. Key neural structures are identified: the iliohypogastric nerve (IHN) is positioned superomedially to the hernia, while the ilio-inguinal nerve (I-IN) runs inferior and lateral to the IEA, passing toward the superficial inguinal ring. Black arrowheads delineate the reflected edges of the external oblique aponeurosis. The image provides critical educational context regarding the 'triangle of pain' and the importance of identifying these neurovascular structures to avoid iatrogenic injury during herniorrhaphy. The anatomical orientation is provided by a 'cranial/lateral' directional indicator, emphasizing the spatial arrangement of the spermatic cord structures and the transversalis fascia.

This grayscale clinical photograph of a cadaveric dissection illustrates the surgical anatomy of the inguinal region, specifically highlighting the topographic relationships during an indirect inguinal hernia repair. The dissection reveals the inferior epigastric artery (IEA) running cranially and medially. Lateral and inferior to the IEA, an indirect inguinal hernia is visible, marked with a white star, having protruded through the deep inguinal ring lateral to the epigastric vessels. Key neural structures are identified: the iliohypogastric nerve (IHN) is positioned superomedially to the hernia, while the ilio-inguinal nerve (I-IN) runs inferior and lateral to the IEA, passing toward the superficial inguinal ring. Black arrowheads delineate the reflected edges of the external oblique aponeurosis. The image provides critical educational context regarding the 'triangle of pain' and the importance of identifying these neurovascular structures to avoid iatrogenic injury during herniorrhaphy. The anatomical orientation is provided by a 'cranial/lateral' directional indicator, emphasizing the spatial arrangement of the spermatic cord structures and the transversalis fascia.

This composite diagnostic image features three panels (A, B, and C) of an abdomino-pelvic computerized tomography (CT) scan. Panels A and B are axial views, and Panel C is a sagittal view. The imaging demonstrates a right direct inguinal hernia involving the urinary bladder. In axial view A, a yellow arrow points to a lateral protrusion of the contrast-filled urinary bladder wall into the inguinal canal, identified as a bladder horn or cystocele. View B, at a lower axial level, shows the continuation of the herniated tissue near the symphysis pubis. The sagittal view (C) provides a longitudinal perspective, with a yellow arrow highlighting the bladder anteriorly herniating through the abdominal wall defect. The images show key pelvic anatomy including the sacrum, iliac bones, pelvic floor musculature, and the lumbar-sacral spine. This case illustrates a rare content of a direct inguinal hernia, useful for surgical planning and differentiating between direct and indirect hernia types based on their relationship to the inferior epigastric vessels.

This composite diagnostic image features three panels (A, B, and C) of an abdomino-pelvic computerized tomography (CT) scan. Panels A and B are axial views, and Panel C is a sagittal view. The imaging demonstrates a right direct inguinal hernia involving the urinary bladder. In axial view A, a yellow arrow points to a lateral protrusion of the contrast-filled urinary bladder wall into the inguinal canal, identified as a bladder horn or cystocele. View B, at a lower axial level, shows the continuation of the herniated tissue near the symphysis pubis. The sagittal view (C) provides a longitudinal perspective, with a yellow arrow highlighting the bladder anteriorly herniating through the abdominal wall defect. The images show key pelvic anatomy including the sacrum, iliac bones, pelvic floor musculature, and the lumbar-sacral spine. This case illustrates a rare content of a direct inguinal hernia, useful for surgical planning and differentiating between direct and indirect hernia types based on their relationship to the inferior epigastric vessels.

Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
I now have comprehensive material from multiple authoritative surgical textbooks. Let me compile the full case presentation.

Inguinal Hernia: Case Presentation, Examination & Management


ILLUSTRATIVE CASE

Patient: Mr. R.K., 55-year-old male, farmer Presenting complaint: Swelling in the right groin for 8 months, increasing with activity
History of presenting illness:
  • The swelling first appeared in the right groin after heavy lifting in the field
  • It initially appeared in the groin and gradually extended towards the scrotum
  • The swelling reduces spontaneously when the patient lies down (direct component) or requires manual reduction when indirect
  • Associated with dragging discomfort and a sense of heaviness, worsening by evening
  • No history of irreducibility, severe pain, vomiting, or fever
Predisposing factors:
  • Chronic cough (smoker, 20 pack-years)
  • Constipation (strains at stool)
  • History of heavy manual labour
Past history: Appendicectomy 15 years ago (division of the ilioinguinal nerve can weaken the inguinal floor)
Family history: Nil significant
Systemic enquiry: No urinary symptoms, no symptoms of intestinal obstruction

ANATOMY OF THE INGUINAL CANAL

Understanding the canal is the foundation for distinguishing hernia types.
The deep (internal) inguinal ring is a defect in the transversalis fascia, situated midway between the anterior superior iliac spine (ASIS) and the pubic tubercle, approximately 2-3 cm above and lateral to the femoral artery. The inferior epigastric vessels run just medial to the deep ring - this is the KEY landmark separating direct from indirect hernias.
Hesselbach's triangle is bounded by:
  • Medially - lateral border of rectus sheath
  • Superolaterally - inferior epigastric vessels
  • Inferiorly - inguinal ligament
The conjoint tendon (fusion of transversus abdominis and internal oblique) arches over the deep ring and reinforces the posterior wall. The superficial (external) inguinal ring is formed by decussating fibers of the external oblique aponeurosis.

DIRECT vs. INDIRECT INGUINAL HERNIA: DETAILED COMPARISON

FeatureIndirect (Lateral/Oblique)Direct (Medial)
Exit pointLateral to inferior epigastric vessels, through deep inguinal ringMedial to inferior epigastric vessels, through Hesselbach's triangle
AetiologyCongenital (patent processus vaginalis) or acquiredAlways acquired
Age groupAll ages; infants, young malesOlder, elderly males
CoveringCovered by all 3 layers of spermatic cord fascia (internal spermatic fascia, cremasteric fascia, external spermatic fascia) - lies WITHIN the cordAdjacent to spermatic cord, NOT within it; covered only by attenuated transversalis fascia and (if exits external ring) external spermatic fascia
PathOblique - traverses the entire inguinal canalDirect - passes directly/perpendicularly through posterior wall
Descent to scrotumFrequent - can reach the bottom of the scrotumUncommon - rarely descends far
ShapePyriform/elongatedRounded, globular, broad-based
ReducibilityRequires manual reduction in many casesOften reduces spontaneously on lying down
Strangulation riskHigher - narrow deep ring acts as a tight neckLower - broad base, wide neck
BilateralLess commonMore common (bilateral weakness of posterior wall)
Bladder involvementRareBladder may be pulled into sac (sliding hernia)
Ring occlusion testHernia controlled (does NOT reappear)Hernia reappears medially (NOT controlled)
  • Fischer's Mastery of Surgery, 8th Ed., p. 6048
  • Bailey and Love's Short Practice of Surgery, 28th Ed., p. 1087

EXAMINATION

General Inspection (Patient Standing)

  1. Position - Always examine in standing position with genitalia fully exposed
  2. Look for a swelling in the groin region; note:
    • Position: above the inguinal ligament (inguinal hernia) vs. below (femoral hernia)
    • Inguinal hernia lies medial to the pubic tubercle (the swelling occupies the groin and can extend to the scrotum)
    • Femoral hernia lies below and lateral to the pubic tubercle, and ascends over the ligament
    • Shape: elongated (indirect) or globular (direct)
    • Extent: does it reach the bottom of the scrotum? If so, suggests congenital indirect hernia with preformed sac
    • Visible peristalsis in thin patients (very thin covering) suggests small bowel content
    • Skin changes: redness (strangulation), pigmentation/wrinkling (chronic truss use), scars (previous repair)
  3. Impulse on coughing (Inspection): Ask the patient to turn away and cough. Observe for an expansile bulge appearing synchronously with coughing - this is almost diagnostic of hernia.

Palpation

Step 1 - Identify the pubic tubercle. The hernia lies above and medial to it (contrast with femoral hernia which is below and lateral).
Step 2 - Temperature and tenderness: Should be normal in uncomplicated hernia; warm and tender indicates incarceration or strangulation.
Step 3 - Impulse on coughing (palpation):
  • Place a finger over the superficial inguinal ring
  • Ask the patient to cough - an expansile impulse is felt
  • Absent in strangulated or incarcerated hernia (adhesions block content re-entry)
Step 4 - Zieman's three-finger technique: Applied when there is no obvious swelling or after complete reduction. The patient stands and performs a Valsalva:
  • Index finger over the deep inguinal ring (½ inch above the mid-inguinal point) - detects indirect hernia impulse
  • Middle finger over the superficial inguinal ring - detects direct hernia impulse
  • Ring finger over the saphenous opening (4 cm below and lateral to pubic tubercle) - detects femoral hernia
  • S. Das Manual of Clinical Surgery, 13th Ed.
Step 5 - Invagination test (Finger-in-ring test): The little finger is insinuated into the scrotum upwards through the superficial inguinal ring. The patient is asked to cough.
  • If the impulse is felt on the pulp of the finger → direct hernia (comes directly backward)
  • If the impulse is felt on the tip of the finger → indirect hernia (comes from above, backward and outward)
Step 6 - Reducibility:
  • Attempt to reduce the hernia manually; note the direction of reduction (upward, backward, laterally for indirect; directly backward for direct)
  • In direct hernia, reduction is easy and spontaneous
  • Indirect hernia requires gentle sustained pressure along the canal direction
Step 7 - Ring Occlusion Test (confirmatory): This is performed after complete reduction, with the patient standing.
  • Press the thumb firmly over the deep inguinal ring (½ inch above the mid-inguinal point)
  • Ask the patient to cough or strain
  • Indirect hernia: Hernia is CONTROLLED - does not reappear (because the neck at the deep ring is occluded)
  • Direct hernia: Hernia REAPPEARS medially (escapes through Hesselbach's triangle, not through the deep ring)
Ring occlusion test showing direct hernia reappearing medially when deep ring is compressed
Ring occlusion test: Indirect hernia is controlled; direct hernia reappears medially - S. Das Manual of Clinical Surgery
Step 8 - Examine the opposite groin (bilateral hernias common with direct type).
Step 9 - Examine the testis - to rule out descent anomalies and to confirm that the testis is separate from the hernia (helps exclude hydrocele and other scrotal swellings).

Percussion & Auscultation

  • Percussion: Resonant (bowel content) or dull (omentum/solid organ)
  • Auscultation: Bowel sounds over the swelling if intestine is content

Relevant Systemic Examination

  • Abdomen: For organomegaly, ascites, masses, scars
  • Respiratory: Chronic cough (COPD, bronchiectasis) as a predisposing cause
  • Prostate/bladder: Urinary symptoms (BPH) as a predisposing cause
  • Rectal exam: To exclude rectal mass causing straining

LAPAROSCOPIC ANATOMY

Laparoscopic view showing triangles: D=Direct hernia space, I=Indirect hernia space, F=Femoral space, Triangle of Pain, Triangle of Doom with epigastric vessels as landmark
Laparoscopic comparison: Image A (indirect hernia) - rounded protrusion LATERAL to inferior epigastric vessels; Image B (direct hernia) - diffuse wide-based bulge MEDIAL to epigastric vessels in Hesselbach's triangle

SPECIAL TYPES

TypeDescription
Pantaloon herniaBoth direct and indirect components present simultaneously, straddling the inferior epigastric vessels like two trouser legs
Sliding herniaRetroperitoneal organ (cecum right; sigmoid left; bladder in direct) forms part of the hernia sac wall
Richter's herniaOnly the antimesenteric border of the bowel is trapped - intestinal obstruction may be absent while strangulation occurs
Littre's herniaMeckel's diverticulum in the sac
Maydl's hernia"W" hernia - two loops of bowel in sac with the connecting loop remaining intraperitoneal; high strangulation risk

COMPLICATIONS

  1. Irreducibility (Incarceration) - contents cannot be reduced back; bowel obstruction follows
  2. Obstruction - colicky pain, vomiting, distension, absolute constipation
  3. Strangulation - blood supply cut off; tender, tense, irreducible swelling; loss of cough impulse; requires emergency surgery
  4. Inflammation - secondary to strangulation or foreign body
  5. Hydrocele - secondary to peritoneal irritation

INVESTIGATIONS

  • In most cases, no investigations are required - the diagnosis is clinical
  • Ultrasonography - useful in occult hernias; Valsalva maneuver during US increases sensitivity
  • CT/MRI - excellent anatomical detail but may miss hernia (patients are supine and hernia reduces)
  • Herniography - injection of contrast into peritoneum; now largely obsolete
  • Routine pre-operative workup - CBC, renal function, ECG in elderly

MANAGEMENT

Conservative (Non-operative)

  • Watchful waiting is acceptable for asymptomatic or minimally symptomatic direct hernias in elderly patients who decline surgery
  • Patients must be warned to seek immediate advice if the hernia enlarges, becomes symptomatic, or irreducible
  • Trusses are NOT recommended - they do not treat the underlying defect and cause skin damage and adhesions
  • Bailey and Love, 28th Ed., p. 1088

Operative - Indications

Surgery is indicated for:
  • All symptomatic hernias
  • All indirect hernias (risk of strangulation)
  • Any irreducible/incarcerated hernia (urgent/emergency)
  • Strangulation (emergency)

Surgical Approaches

1. Herniotomy (Children)

  • Excision and ligation of the hernial sac at its neck
  • No floor repair needed in children with a patent processus vaginalis
  • Herniotomy alone has a high recurrence rate in adults

2. Open Suture Repairs (Adults)

Bassini Repair (1890)
  • Opening of the anterior wall (external oblique aponeurosis)
  • Spermatic cord dissected free
  • Sac of indirect hernia is separated from cord, opened, contents reduced, and sac ligated and excised at neck
  • For direct hernia: sac is inverted and transversalis fascia plicated
  • Sutures placed between conjoint tendon (above) and inguinal ligament (below) from pubic tubercle to deep ring - strengthening the posterior wall
Shouldice Repair
  • Transversalis fascia opened centrally from deep ring to pubic tubercle, then double-breasted (two-layered closure)
  • External oblique closed similarly (four-layer repair)
  • Best results: lifetime failure rates <2% at expert centres
  • Technically demanding; results approach Bassini in less experienced hands
Desarda Repair
  • Uses a strip of external oblique aponeurosis to reinforce the posterior wall (no mesh, no prosthetic)
Maloney Darn
  • Continuous non-absorbable nylon/polypropylene darned between conjoint tendon and inguinal ligament
  • Widely used as a simple Bassini-type modification

3. Open Mesh Repairs (Tension-free - Current Gold Standard for Open Surgery)

Lichtenstein Tension-free Hernioplasty
  • A flat polypropylene mesh is sutured over the posterior wall of the inguinal canal and around the spermatic cord
  • Tension-free repair - dramatically reduces recurrence
  • Recurrence rates <1-2% in most series
  • Can be performed under local anaesthesia as a day-case

4. Laparoscopic Mesh Repair

TEP (Totally Extraperitoneal)
  • Dissection and mesh placement entirely in the preperitoneal space
  • Peritoneal cavity NOT entered
  • Technically demanding but avoids peritoneal violation
TAPP (Transabdominal Preperitoneal)
  • Peritoneal cavity entered; posterior abdominal wall inspected
  • Peritoneum incised, preperitoneal space dissected, mesh placed, peritoneum closed over mesh
  • Allows simultaneous inspection for bilateral hernias
Advantages of laparoscopic over open:
  • Reduced immediate and long-term pain (up to 5 years)
  • Faster return to full activity
  • Fewer wound complications (infection, bleeding, seroma)
  • Particularly beneficial for bilateral hernias and recurrence after previous open repair
  • Bailey and Love, 28th Ed., p. 1090
Robot-assisted repair: Increasingly used; enhanced surgical view and ergonomics for the surgeon, but additional patient benefit over standard laparoscopy is not yet established, and cost is difficult to justify for simple repairs.

5. European Hernia Society (EHS) Classification

Guides surgical approach:
  • P (Primary) or R (Recurrent)
  • L (Lateral/indirect), M (Medial/direct), F (Femoral)
  • Defect size in fingerbreadths: 1 (<1.5 cm), 2 (1.5-4.5 cm), 3 (>4.5 cm)
  • Example: A primary indirect hernia with 3-cm defect = PL2

Emergency Surgery

  • ~5% of inguinal hernias present as an irreducible, painful lump progressing to strangulation
  • Emergency repair follows same principles as elective surgery
  • ~20% require bowel resection (may need conversion to midline laparotomy)
  • Mesh use in emergency is acceptable if covered by antibiotics, unless there is gross contamination

SUMMARY TABLE: DIRECT vs. INDIRECT AT A GLANCE

IndirectDirect
Relation to epigastric vesselsLateralMedial
ThroughDeep inguinal ring → inguinal canalHesselbach's triangle directly
Congenital originYes (patent PV)No
Common ageYoungElderly
Scrotal descentCommonRare
StrangulationMore commonLess common
Ring occlusion testControlledNot controlled (reappears medially)
Finger-in-ring tip impulseOn tip (oblique)On pulp (direct)
Zieman's testIndex finger impulseMiddle finger impulse

Sources:
  • Bailey and Love's Short Practice of Surgery, 28th Ed., pp. 1085-1092
  • S. Das: A Manual on Clinical Surgery, 13th Ed., pp. 599-612
  • Fischer's Mastery of Surgery, 8th Ed., pp. 6047-6052
  • Schwartz's Principles of Surgery, 11th Ed., pp. 1771-1780
  • Roberts and Hedges' Clinical Procedures in Emergency Medicine, Ch. 44

Create a surgical examination checklist PDF for bedside inguinal hernia assessment

Reading File
Running Command

ls -la /tmp/workspace/ 2>/dev/null || echo "workspace empty or missing"

Running Command

mkdir -p /tmp/workspace/inguinal-hernia-checklist

Writing File

~/inguinal-hernia-checklist/generate_checklist.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.pdfgen import canvas
from reportlab.platypus import BaseDocTemplate, PageTemplate, Frame
import datetime

OUTPUT = "/tmp/workspace/inguinal-hernia-checklist/Inguinal_Hernia_Surgical_Examination_Checklist.pdf"

# ─── Color Palette ────────────────────────────────────────────────────────────
DARK_BLUE   = colors.HexColor("#1B3A6B")
MID_BLUE    = colors.HexColor("#2A5BAD")
LIGHT_BLUE  = colors.HexColor("#D6E4F7")
ACCENT      = colors.HexColor("#E84545")   # red for warnings/strangulation
GREEN       = colors.HexColor("#2D7D46")
PALE_GREEN  = colors.HexColor("#DFF2E3")
PALE_YELLOW = colors.HexColor("#FFF8DC")
PALE_RED    = colors.HexColor("#FDECEA")
GREY_LIGHT  = colors.HexColor("#F5F5F5")
GREY_MED    = colors.HexColor("#CCCCCC")
BLACK       = colors.black
WHITE       = colors.white

W, H = A4   # 595.27 x 841.89 pt

# ─── Page numbering canvas ─────────────────────────────────────────────────────
class NumberedCanvas(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self.draw_page_number(num_pages)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def draw_page_number(self, page_count):
        page_num = self._saved_page_states.index(
            {k: v for k, v in self.__dict__.items() if k in self._saved_page_states[0]}
        ) + 1 if hasattr(self, '_page_count_hack') else None
        # simple footer
        self.saveState()
        self.setFont("Helvetica", 7)
        self.setFillColor(colors.HexColor("#888888"))
        self.drawCentredString(W / 2, 18, f"Inguinal Hernia Bedside Examination Checklist  |  Page {page_count}")
        self.restoreState()


def header_footer(canvas_obj, doc):
    canvas_obj.saveState()
    # Top banner
    canvas_obj.setFillColor(DARK_BLUE)
    canvas_obj.rect(0, H - 28*mm, W, 28*mm, fill=1, stroke=0)
    canvas_obj.setFillColor(WHITE)
    canvas_obj.setFont("Helvetica-Bold", 13)
    canvas_obj.drawCentredString(W/2, H - 14*mm, "INGUINAL HERNIA — BEDSIDE SURGICAL EXAMINATION CHECKLIST")
    canvas_obj.setFont("Helvetica", 8)
    canvas_obj.drawCentredString(W/2, H - 21*mm, "For use by medical students, surgical trainees, and examiners at the bedside")

    # Bottom bar
    canvas_obj.setFillColor(DARK_BLUE)
    canvas_obj.rect(0, 0, W, 12*mm, fill=1, stroke=0)
    canvas_obj.setFillColor(WHITE)
    canvas_obj.setFont("Helvetica", 7)
    today = datetime.date.today().strftime("%B %Y")
    canvas_obj.drawString(15*mm, 4*mm, f"Sources: Bailey & Love 28e | S. Das Manual of Clinical Surgery 13e | Fischer's Mastery of Surgery 8e")
    canvas_obj.drawRightString(W - 15*mm, 4*mm, today)
    canvas_obj.restoreState()


def build_pdf():
    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=A4,
        leftMargin=14*mm,
        rightMargin=14*mm,
        topMargin=34*mm,
        bottomMargin=18*mm,
        title="Inguinal Hernia Bedside Examination Checklist",
        author="Orris Medical",
    )

    styles = getSampleStyleSheet()

    # ── Custom Styles ────────────────────────────────────────────────────────
    def S(name, **kw):
        return ParagraphStyle(name, **kw)

    body      = S("body",      fontName="Helvetica",       fontSize=8,  leading=11, spaceAfter=2)
    bold_body = S("bold_body", fontName="Helvetica-Bold",  fontSize=8,  leading=11)
    small     = S("small",     fontName="Helvetica",       fontSize=7,  leading=9,  textColor=colors.HexColor("#444444"))
    h1        = S("h1",        fontName="Helvetica-Bold",  fontSize=10, leading=14, textColor=WHITE)
    h2        = S("h2",        fontName="Helvetica-Bold",  fontSize=9,  leading=12, textColor=DARK_BLUE)
    h3        = S("h3",        fontName="Helvetica-Bold",  fontSize=8,  leading=11, textColor=MID_BLUE)
    note_st   = S("note",      fontName="Helvetica-Oblique", fontSize=7, leading=9, textColor=colors.HexColor("#555555"))
    warn_st   = S("warn",      fontName="Helvetica-Bold",  fontSize=8,  leading=10, textColor=ACCENT)
    center_s  = S("center",    fontName="Helvetica",       fontSize=8,  leading=11, alignment=TA_CENTER)
    center_b  = S("centerb",   fontName="Helvetica-Bold",  fontSize=8,  leading=11, alignment=TA_CENTER, textColor=WHITE)
    cell_hdr  = S("cellhdr",   fontName="Helvetica-Bold",  fontSize=7.5, leading=10, textColor=WHITE, alignment=TA_CENTER)
    cell_body = S("cellbody",  fontName="Helvetica",       fontSize=7.5, leading=10)
    cell_b2   = S("cellb2",    fontName="Helvetica-Bold",  fontSize=7.5, leading=10)

    story = []

    # ═══════════════════════════════════════════════════════════════════════════
    # SECTION HELPER
    # ═══════════════════════════════════════════════════════════════════════════
    def section_header(title, color=DARK_BLUE):
        data = [[Paragraph(title, h1)]]
        t = Table(data, colWidths=[W - 28*mm])
        t.setStyle(TableStyle([
            ("BACKGROUND", (0,0), (-1,-1), color),
            ("TOPPADDING",    (0,0), (-1,-1), 4),
            ("BOTTOMPADDING", (0,0), (-1,-1), 4),
            ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ]))
        story.append(t)
        story.append(Spacer(1, 2*mm))

    def subsection(title):
        story.append(Spacer(1, 1.5*mm))
        story.append(Paragraph(title, h2))
        story.append(HRFlowable(width="100%", thickness=0.5, color=MID_BLUE, spaceAfter=1*mm))

    def checkbox_row(label, note="", indent=0):
        """Returns a list of 2-column row data: [checkbox cell, label+note cell]."""
        box = "☐"
        lbl = Paragraph(f"<b>{label}</b>", bold_body) if not note else \
              Paragraph(f"<b>{label}</b>  <font size='7' color='#666666'><i>{note}</i></font>", body)
        return [Paragraph(box, center_s), lbl]

    def cb_table(rows, bg=None):
        """Build a compact checkbox table from rows of [box, label]."""
        ts = [
            ("VALIGN",        (0,0), (-1,-1), "TOP"),
            ("LEFTPADDING",   (0,0), (-1,-1), 2),
            ("RIGHTPADDING",  (0,0), (-1,-1), 2),
            ("TOPPADDING",    (0,0), (-1,-1), 2.5),
            ("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
            ("GRID",          (0,0), (-1,-1), 0.3, GREY_MED),
        ]
        if bg:
            ts.append(("BACKGROUND", (0,0), (-1,-1), bg))
        t = Table(rows, colWidths=[8*mm, W - 28*mm - 8*mm])
        t.setStyle(TableStyle(ts))
        return t

    def two_col_cb(left_rows, right_rows, left_title="", right_title=""):
        """Side-by-side two-column checkbox block."""
        cw = (W - 28*mm) / 2 - 2*mm

        def mini(rows, title, title_color=MID_BLUE):
            inner = []
            if title:
                inner.append(Table([[Paragraph(title, h3)]], colWidths=[cw],
                    style=TableStyle([
                        ("BACKGROUND", (0,0), (-1,-1), LIGHT_BLUE),
                        ("TOPPADDING",    (0,0), (-1,-1), 3),
                        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
                        ("LEFTPADDING",   (0,0), (-1,-1), 5),
                    ])))
            cb = Table(rows, colWidths=[7*mm, cw - 7*mm],
                style=TableStyle([
                    ("VALIGN",        (0,0), (-1,-1), "TOP"),
                    ("LEFTPADDING",   (0,0), (-1,-1), 2),
                    ("RIGHTPADDING",  (0,0), (-1,-1), 2),
                    ("TOPPADDING",    (0,0), (-1,-1), 2.5),
                    ("BOTTOMPADDING", (0,0), (-1,-1), 2.5),
                    ("GRID",          (0,0), (-1,-1), 0.3, GREY_MED),
                ]))
            inner.append(cb)
            return inner

        left  = mini(left_rows,  left_title)
        right = mini(right_rows, right_title)

        outer_data = [[left, right]]
        outer = Table(outer_data, colWidths=[cw + 2*mm, cw + 2*mm])
        outer.setStyle(TableStyle([
            ("VALIGN",        (0,0), (-1,-1), "TOP"),
            ("LEFTPADDING",   (0,0), (-1,-1), 0),
            ("RIGHTPADDING",  (0,0), (-1,-1), 0),
            ("TOPPADDING",    (0,0), (-1,-1), 0),
            ("BOTTOMPADDING", (0,0), (-1,-1), 0),
        ]))
        return outer

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 1: PATIENT DETAILS ──────────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 1 — PATIENT IDENTIFICATION & PRE-EXAMINATION SETUP")

    pt_data = [
        [Paragraph("<b>Patient Name:</b>", body), Paragraph("_______________________________", body),
         Paragraph("<b>Age / Sex:</b>", body),    Paragraph("_______ / _______", body)],
        [Paragraph("<b>Date:</b>", body),          Paragraph("_______________________________", body),
         Paragraph("<b>Ward / Bed:</b>", body),    Paragraph("_______________________________", body)],
        [Paragraph("<b>Examiner:</b>", body),      Paragraph("_______________________________", body),
         Paragraph("<b>Side:</b>", body),          Paragraph("☐ Right   ☐ Left   ☐ Bilateral", body)],
    ]
    pt = Table(pt_data, colWidths=[28*mm, 57*mm, 28*mm, 57*mm])
    pt.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), GREY_LIGHT),
        ("GRID", (0,0), (-1,-1), 0.4, GREY_MED),
        ("TOPPADDING",    (0,0), (-1,-1), 4),
        ("BOTTOMPADDING", (0,0), (-1,-1), 4),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ]))
    story.append(pt)
    story.append(Spacer(1, 3*mm))

    # Pre-exam setup
    subsection("Pre-Examination Setup")
    setup = [
        checkbox_row("Explain procedure and obtain verbal consent"),
        checkbox_row("Adequate privacy; patient standing (primary) and lying supine (secondary)"),
        checkbox_row("Expose groin, lower abdomen and scrotum/labia fully"),
        checkbox_row("Examiner seated in front of standing patient"),
        checkbox_row("Ask patient to point to site of swelling/discomfort"),
    ]
    story.append(cb_table(setup, bg=GREY_LIGHT))
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 2: HISTORY CHECKLIST ────────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 2 — FOCUSED HISTORY", color=MID_BLUE)

    hist = [
        checkbox_row("Onset: sudden (with strain/lift) or gradual?"),
        checkbox_row("First site: groin → scrotum (inguinal) OR below groin crease ascending (femoral)?"),
        checkbox_row("Size at onset — small and gradually enlarging (acquired) OR immediately large (congenital)?"),
        checkbox_row("Reducibility: disappears on lying down automatically (direct) OR requires manual reduction (indirect)?"),
        checkbox_row("Aggravating factors: coughing, straining, heavy lifting, prolonged standing"),
        checkbox_row("Pain/discomfort: dragging, aching; severe pain suggests incarceration/strangulation"),
        checkbox_row("Features of bowel obstruction: colicky pain, vomiting, distension, absolute constipation"),
        checkbox_row("Predisposing causes: chronic cough, constipation, BPH (straining), ascites, heavy labour"),
        checkbox_row("Past surgical history: appendicectomy (nerve damage → weak inguinal floor), previous hernia repair"),
        checkbox_row("Truss use: duration; note pigmentation/skin damage from long-term use"),
    ]
    story.append(cb_table(hist))
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 3: INSPECTION ───────────────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 3 — INSPECTION  (Patient Standing)")

    insp = [
        checkbox_row("Swelling visible at rest in groin?", "Note: above inguinal ligament = inguinal; below = femoral"),
        checkbox_row("Position relative to pubic tubercle:",
                     "Inguinal = above & medial to PT; Femoral = below & lateral to PT"),
        checkbox_row("Shape: elongated/pyriform (indirect) vs. globular/rounded (direct)"),
        checkbox_row("Extent: does swelling reach bottom of scrotum? (congenital indirect hernia)"),
        checkbox_row("Visible peristalsis over swelling?", "Suggests small bowel content; never seen in femoral hernia"),
        checkbox_row("Skin: normal (uncomplicated) | reddened (strangulation) | pigmented+wrinkled (truss use)"),
        checkbox_row("Scars: site and quality of any previous surgical scar", "Puckered scar = previous infection → common recurrence cause"),
        checkbox_row("Scrotal skin movement (dartos contraction) — distinguish from peristalsis"),
        checkbox_row("Ask patient to cough — observe for expansile bulge synchronous with cough"),
    ]
    story.append(cb_table(insp, bg=GREY_LIGHT))
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 4: PALPATION ────────────────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 4 — PALPATION")

    subsection("4A — Basic Palpation (Both positions)")
    basic = [
        checkbox_row("Identify pubic tubercle — confirm swelling is above (inguinal) vs. below (femoral)"),
        checkbox_row("Temperature: warm (strangulation/inflammation) vs. normal"),
        checkbox_row("Tenderness: mild (uncomplicated) vs. severe (complication)"),
        checkbox_row("Consistency: soft/reducible (uncomplicated) | firm/hard (omentum/incarcerated bowel)"),
        checkbox_row("Spermatic cord: palpate; thicker cord on affected side suggests hernia sac within cord (indirect)"),
        checkbox_row("Can you get above the swelling?", "YES = scrotal swelling | CANNOT = hernia/hydrocele communicating"),
        checkbox_row("Testis: palpate separately; confirm testis present and separate from swelling"),
        checkbox_row("Percussion: resonant (bowel) vs. dull (omentum/fluid)"),
        checkbox_row("Auscultation: bowel sounds over swelling?"),
    ]
    story.append(cb_table(basic))
    story.append(Spacer(1, 3*mm))

    subsection("4B — Impulse on Coughing (Standing)")
    imp = [
        checkbox_row("Place finger over superficial inguinal ring; ask patient to cough"),
        checkbox_row("Expansile cough impulse PRESENT → consistent with hernia"),
        checkbox_row("Impulse ABSENT → suggests strangulation, incarceration, or neck blocked by adhesions"),
        checkbox_row("Note: ask patient to turn face away before coughing"),
    ]
    story.append(cb_table(imp, bg=PALE_GREEN))
    story.append(Spacer(1, 3*mm))

    subsection("4C — Reducibility Test (Standing → Lying)")
    red = [
        checkbox_row("Attempt reduction with patient standing; note direction (upward+backward+lateral for indirect)"),
        checkbox_row("Reduction spontaneous on lying down → suggests DIRECT hernia"),
        checkbox_row("Requires gentle sustained manual pressure → suggests INDIRECT hernia"),
        checkbox_row("Note gurgling sound on reduction (bowel) or absence of sound (omentum)"),
        checkbox_row("NOT REDUCIBLE → document: likely incarcerated; do NOT force reduction"),
    ]
    story.append(cb_table(red))
    story.append(Spacer(1, 3*mm))

    subsection("4D — Zieman's Three-Finger Test (after complete reduction)")
    story.append(Paragraph(
        "<i>Note: Only applicable when no obvious swelling OR after hernia fully reduced. "
        "Patient stands. Place fingers simultaneously:</i>", note_st))
    story.append(Spacer(1, 1*mm))

    ziem_data = [
        [Paragraph("<b>Finger</b>", cell_hdr), Paragraph("<b>Position</b>", cell_hdr),
         Paragraph("<b>Hernia Detected</b>", cell_hdr), Paragraph("<b>Result</b>", cell_hdr)],
        [Paragraph("Index finger", cell_body),
         Paragraph("Deep inguinal ring\n(½ inch above mid-inguinal point = midpoint between ASIS and symphysis pubis)", cell_body),
         Paragraph("Indirect inguinal hernia", cell_body),
         Paragraph("☐ Impulse felt\n☐ No impulse", cell_body)],
        [Paragraph("Middle finger", cell_body),
         Paragraph("Superficial inguinal ring", cell_body),
         Paragraph("Direct inguinal hernia", cell_body),
         Paragraph("☐ Impulse felt\n☐ No impulse", cell_body)],
        [Paragraph("Ring finger", cell_body),
         Paragraph("Saphenous opening\n(4 cm below & lateral to pubic tubercle)", cell_body),
         Paragraph("Femoral hernia", cell_body),
         Paragraph("☐ Impulse felt\n☐ No impulse", cell_body)],
    ]
    ziem_t = Table(ziem_data, colWidths=[22*mm, 58*mm, 50*mm, 30*mm - 2*mm])
    ziem_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),   DARK_BLUE),
        ("BACKGROUND",    (0,1), (-1,1),   LIGHT_BLUE),
        ("BACKGROUND",    (0,2), (-1,2),   GREY_LIGHT),
        ("BACKGROUND",    (0,3), (-1,3),   LIGHT_BLUE),
        ("GRID",          (0,0), (-1,-1),  0.5, GREY_MED),
        ("VALIGN",        (0,0), (-1,-1),  "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1),  3),
        ("BOTTOMPADDING", (0,0), (-1,-1),  3),
        ("LEFTPADDING",   (0,0), (-1,-1),  4),
        ("FONTNAME",      (0,0), (-1,0),   "Helvetica-Bold"),
    ]))
    story.append(ziem_t)
    story.append(Spacer(1, 3*mm))

    subsection("4E — Invagination Test (Finger-in-Ring Test)")
    inv_note = Paragraph(
        "<i>Insinuate the little finger into the scrotum upwards through the superficial inguinal ring. "
        "Ask patient to cough.</i>", note_st)
    story.append(inv_note)
    story.append(Spacer(1, 1*mm))

    inv_data = [
        [Paragraph("<b>Finding</b>", cell_hdr), Paragraph("<b>Interpretation</b>", cell_hdr),
         Paragraph("<b>Result</b>", cell_hdr)],
        [Paragraph("Impulse felt on PULP of finger", cell_body),
         Paragraph("DIRECT hernia — comes directly backwards", cell_b2),
         Paragraph("☐", center_s)],
        [Paragraph("Impulse felt on TIP of finger", cell_body),
         Paragraph("INDIRECT hernia — comes from above, backwards and outwards (oblique)", cell_b2),
         Paragraph("☐", center_s)],
        [Paragraph("Finger enters ring and goes DIRECTLY BACKWARDS", cell_body),
         Paragraph("DIRECT hernia", cell_b2),
         Paragraph("☐", center_s)],
        [Paragraph("Finger enters ring going UPWARDS, BACKWARDS and OUTWARDS", cell_body),
         Paragraph("INDIRECT hernia", cell_b2),
         Paragraph("☐", center_s)],
    ]
    inv_t = Table(inv_data, colWidths=[70*mm, 72*mm, 18*mm])
    inv_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  DARK_BLUE),
        ("BACKGROUND",    (0,1), (-1,1),  PALE_YELLOW),
        ("BACKGROUND",    (0,2), (-1,2),  PALE_GREEN),
        ("BACKGROUND",    (0,3), (-1,3),  PALE_YELLOW),
        ("BACKGROUND",    (0,4), (-1,4),  PALE_GREEN),
        ("GRID",          (0,0), (-1,-1), 0.5, GREY_MED),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("ALIGN",         (2,0), (2,-1),  "CENTER"),
    ]))
    story.append(inv_t)
    story.append(Spacer(1, 3*mm))

    subsection("4F — Ring Occlusion Test (Confirmatory — after full reduction, standing)")
    story.append(Paragraph(
        "<i>Press thumb firmly over the deep inguinal ring (½ inch above the mid-point between ASIS and symphysis pubis). "
        "Ask patient to cough or strain.</i>", note_st))
    story.append(Spacer(1, 1*mm))

    roc_data = [
        [Paragraph("<b>Finding on Coughing</b>", cell_hdr), Paragraph("<b>Interpretation</b>", cell_hdr),
         Paragraph("<b>Result</b>", cell_hdr)],
        [Paragraph("Hernia DOES NOT REAPPEAR (controlled)", cell_body),
         Paragraph("INDIRECT hernia — deep ring occluded, hernia cannot exit", cell_b2),
         Paragraph("☐", center_s)],
        [Paragraph("Hernia REAPPEARS medially to occluding thumb", cell_body),
         Paragraph("DIRECT hernia — exits through Hesselbach's triangle, not deep ring", cell_b2),
         Paragraph("☐", center_s)],
    ]
    roc_t = Table(roc_data, colWidths=[70*mm, 82*mm, 8*mm])
    roc_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  DARK_BLUE),
        ("BACKGROUND",    (0,1), (-1,1),  PALE_GREEN),
        ("BACKGROUND",    (0,2), (-1,2),  PALE_RED),
        ("GRID",          (0,0), (-1,-1), 0.5, GREY_MED),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("ALIGN",         (2,0), (2,-1),  "CENTER"),
    ]))
    story.append(roc_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 5: COMPARISON TABLE ─────────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 5 — DIRECT vs. INDIRECT INGUINAL HERNIA: KEY DIFFERENTIATORS", color=GREEN)

    comp_data = [
        [Paragraph("<b>Feature</b>", cell_hdr),
         Paragraph("<b>INDIRECT (Lateral/Oblique)</b>", cell_hdr),
         Paragraph("<b>DIRECT (Medial)</b>", cell_hdr)],
        ["Relation to inf. epigastric vessels",    "LATERAL — exits through deep inguinal ring",        "MEDIAL — exits through Hesselbach's triangle"],
        ["Origin",                                  "Congenital (patent processus vaginalis) or acquired", "Always ACQUIRED"],
        ["Typical age",                             "All ages; infants to young adults",                  "Middle-aged to elderly males"],
        ["Hernia sac & spermatic cord",             "Within cord (covered by all 3 fascial layers)",      "Adjacent to cord, NOT within it"],
        ["Path",                                    "Oblique — traverses full inguinal canal",            "Direct — perpendicular through posterior wall"],
        ["Shape",                                   "Pyriform/elongated",                                 "Globular, rounded, broad-based"],
        ["Scrotal descent",                         "Common — may reach bottom of scrotum",               "Uncommon"],
        ["Spontaneous reduction",                   "Requires manual reduction (mostly)",                 "Often disappears on lying down"],
        ["Strangulation risk",                      "HIGHER — narrow neck at deep ring",                  "LOWER — broad base, wide neck"],
        ["Zieman's test",                           "Index finger impulse",                               "Middle finger impulse"],
        ["Invagination test",                       "Impulse on TIP of finger",                           "Impulse on PULP of finger"],
        ["Ring occlusion test",                     "CONTROLLED (hernia does not reappear)",              "NOT controlled (reappears medially)"],
        ["Bilateral occurrence",                    "Less common",                                        "More common (bilateral wall weakness)"],
        ["Bladder involvement",                     "Rare",                                               "May occur (sliding direct hernia)"],
    ]

    comp_rows = []
    for i, row in enumerate(comp_data):
        if i == 0:
            comp_rows.append([Paragraph(str(c), cell_hdr) for c in row])
        else:
            comp_rows.append([
                Paragraph(str(row[0]), cell_b2 if i % 2 == 1 else cell_body),
                Paragraph(str(row[1]), cell_body),
                Paragraph(str(row[2]), cell_body),
            ])

    comp_t = Table(comp_rows, colWidths=[42*mm, 70*mm, 50*mm])
    ts = TableStyle([
        ("BACKGROUND",    (0,0),  (-1,0),   GREEN),
        ("GRID",          (0,0),  (-1,-1),  0.4, GREY_MED),
        ("VALIGN",        (0,0),  (-1,-1),  "TOP"),
        ("TOPPADDING",    (0,0),  (-1,-1),  3),
        ("BOTTOMPADDING", (0,0),  (-1,-1),  3),
        ("LEFTPADDING",   (0,0),  (-1,-1),  4),
    ])
    for i in range(1, len(comp_rows)):
        bg = GREY_LIGHT if i % 2 == 0 else WHITE
        ts.add("BACKGROUND", (0,i), (-1,i), bg)
    comp_t.setStyle(ts)
    story.append(comp_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 6: COMPLICATIONS CHECKLIST ──────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 6 — ASSESSMENT FOR COMPLICATIONS", color=ACCENT)

    story.append(Paragraph(
        "<b>⚠ RED FLAGS — Assess at every examination. Mark if present.</b>", warn_st))
    story.append(Spacer(1, 1*mm))

    comp_check = [
        checkbox_row("Irreducibility (Incarceration)",
                     "Firm, non-reducible swelling; may have absent cough impulse → URGENT surgical referral"),
        checkbox_row("Intestinal Obstruction",
                     "Colicky abdominal pain + vomiting + distension + absolute constipation"),
        checkbox_row("Strangulation",
                     "Tender, tense, irreducible swelling; ABSENT cough impulse; skin changes → EMERGENCY surgery"),
        checkbox_row("Inflammation",
                     "Warm, red, tender swelling without signs of strangulation"),
        checkbox_row("Faecal vomiting",
                     "Ominous — indicates low small bowel or large bowel obstruction"),
        checkbox_row("Secondary hydrocele",
                     "Fluid around testis due to peritoneal irritation from hernia"),
    ]
    complication_table = cb_table(comp_check, bg=PALE_RED)
    story.append(complication_table)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 7: SPECIAL TYPES ────────────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 7 — SPECIAL HERNIA TYPES TO RECOGNISE", color=MID_BLUE)

    sp_data = [
        [Paragraph("<b>Type</b>", cell_hdr), Paragraph("<b>Key Feature</b>", cell_hdr),
         Paragraph("<b>Clinical Clue</b>", cell_hdr)],
        ["Pantaloon (Saddle-bag)", "Both direct + indirect components straddle epigastric vessels",
         "Difficult to reduce; found at operation"],
        ["Sliding hernia", "Retroperitoneal organ (cecum R / sigmoid L / bladder in direct) forms part of sac wall",
         "Caution during sac dissection — risk of bowel/bladder injury"],
        ["Richter's hernia", "Only antimesenteric border of bowel trapped",
         "Obstruction may be absent even though strangulation is occurring"],
        ["Littre's hernia", "Meckel's diverticulum in the sac",
         "Presents like standard hernia; diagnosed intraoperatively"],
        ["Maydl's hernia ('W' hernia)", "Two bowel loops in sac; connecting loop intraperitoneal",
         "High strangulation risk of intraperitoneal loop"],
        ["Congenital (infantile)", "Hernia reaches base of scrotum at first presentation",
         "Preformed sac; may appear at any age"],
    ]
    sp_rows = []
    for i, row in enumerate(sp_data):
        if i == 0:
            sp_rows.append([Paragraph(c, cell_hdr) for c in row])
        else:
            sp_rows.append([Paragraph(c, cell_b2 if i == 0 else cell_body) for c in row])

    sp_t = Table(sp_rows, colWidths=[38*mm, 67*mm, 57*mm])
    sp_ts = TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  MID_BLUE),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_MED),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ])
    for i in range(1, len(sp_rows)):
        sp_ts.add("BACKGROUND", (0,i), (-1,i), GREY_LIGHT if i % 2 == 0 else WHITE)
    sp_t.setStyle(sp_ts)
    story.append(sp_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 8: MANAGEMENT SUMMARY ───────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 8 — MANAGEMENT PATHWAY CHECKLIST")

    subsection("8A — Conservative Management (Watchful Waiting)")
    cons = [
        checkbox_row("Appropriate for: asymptomatic/minimally symptomatic DIRECT hernia in elderly patients who decline surgery"),
        checkbox_row("Educate patient: seek urgent review if hernia enlarges, becomes symptomatic, or is irreducible"),
        checkbox_row("TRUSSES ARE NOT RECOMMENDED — do not prescribe"),
        checkbox_row("Treat predisposing causes: cough (COPD), constipation, BPH"),
    ]
    story.append(cb_table(cons, bg=PALE_YELLOW))
    story.append(Spacer(1, 3*mm))

    subsection("8B — Surgical Indications")
    surg_ind = [
        checkbox_row("All symptomatic hernias"),
        checkbox_row("All INDIRECT hernias (higher strangulation risk)"),
        checkbox_row("Irreducible/incarcerated hernia — URGENT"),
        checkbox_row("Strangulated hernia — EMERGENCY"),
    ]
    story.append(cb_table(surg_ind))
    story.append(Spacer(1, 3*mm))

    subsection("8C — Surgical Options")

    surg_data = [
        [Paragraph("<b>Procedure</b>", cell_hdr), Paragraph("<b>Indication</b>", cell_hdr),
         Paragraph("<b>Key Points</b>", cell_hdr), Paragraph("<b>Plan</b>", cell_hdr)],
        ["Herniotomy",
         "Children with indirect hernia (patent PV)",
         "Excision + ligation of sac at neck; NO floor repair needed in children",
         "☐"],
        ["Bassini Repair",
         "Adults; open suture repair",
         "Conjoint tendon sutured to inguinal ligament (pubic tubercle → deep ring); floor reconstruction",
         "☐"],
        ["Shouldice Repair",
         "Adults; best open suture repair",
         "Four-layer repair; double-breasting of transversalis fascia; <2% lifetime failure at expert centres",
         "☐"],
        ["Lichtenstein Tension-free (Mesh)",
         "Adults — current gold standard open repair",
         "Flat polypropylene mesh; tension-free; recurrence <1-2%; can be done under LA as day-case",
         "☐"],
        ["Desarda Repair",
         "Adults; no-mesh open repair",
         "Strip of external oblique aponeurosis used to reinforce posterior wall",
         "☐"],
        ["TEP (Laparoscopic)",
         "Bilateral; recurrence; active patients",
         "Totally extraperitoneal; no peritoneal entry; longer learning curve",
         "☐"],
        ["TAPP (Laparoscopic)",
         "Bilateral; recurrence; diagnostic uncertainty",
         "Transabdominal; peritoneum entered; allows bilateral inspection",
         "☐"],
        ["Robot-assisted",
         "Institutional/surgeon preference",
         "Enhanced view; no proven additional patient benefit over standard laparoscopy; high cost",
         "☐"],
    ]
    surg_rows = []
    for i, row in enumerate(surg_data):
        if i == 0:
            surg_rows.append([Paragraph(c, cell_hdr) for c in row])
        else:
            surg_rows.append([Paragraph(c, cell_body) for c in row])

    surg_t = Table(surg_rows, colWidths=[32*mm, 38*mm, 80*mm, 10*mm])
    surg_ts = TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  DARK_BLUE),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_MED),
        ("VALIGN",        (0,0), (-1,-1), "TOP"),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("ALIGN",         (3,0), (3,-1),  "CENTER"),
    ])
    for i in range(1, len(surg_rows)):
        surg_ts.add("BACKGROUND", (0,i), (-1,i), GREY_LIGHT if i % 2 == 0 else WHITE)
    surg_t.setStyle(surg_ts)
    story.append(surg_t)
    story.append(Spacer(1, 3*mm))

    # Laparoscopic advantages
    lap_box_data = [[
        Paragraph(
            "<b>Laparoscopic advantages over open:</b>  Less immediate and long-term pain (up to 5 years) · "
            "Faster return to activity · Fewer wound complications · "
            "Preferred for BILATERAL hernias and RECURRENCE after previous open repair",
            body)
    ]]
    lap_box = Table(lap_box_data, colWidths=[W - 28*mm])
    lap_box.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), LIGHT_BLUE),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("BOX",           (0,0), (-1,-1), 0.8, MID_BLUE),
    ]))
    story.append(lap_box)
    story.append(Spacer(1, 3*mm))

    subsection("8D — EHS Classification (record pre-operatively)")
    ehs_data = [
        [Paragraph("<b>Axis</b>", cell_hdr), Paragraph("<b>Code</b>", cell_hdr),
         Paragraph("<b>Value for this patient</b>", cell_hdr)],
        ["Primary (P) or Recurrent (R)", "P / R", "☐ P   ☐ R"],
        ["Lateral (L) / Medial (M) / Femoral (F)", "L / M / F", "☐ L   ☐ M   ☐ F"],
        ["Defect size (fingerbreadths; 1 fb ≈ 1.5 cm)", "1 (<1.5cm) / 2 (1.5-4.5cm) / 3 (>4.5cm)", "☐ 1   ☐ 2   ☐ 3"],
        ["Example: primary indirect, 3 cm defect =", "PL2", "Classification: ___________"],
    ]
    ehs_rows = []
    for i, row in enumerate(ehs_data):
        if i == 0:
            ehs_rows.append([Paragraph(c, cell_hdr) for c in row])
        else:
            ehs_rows.append([Paragraph(str(c), cell_body) for c in row])

    ehs_t = Table(ehs_rows, colWidths=[55*mm, 70*mm, 37*mm])
    ehs_ts = TableStyle([
        ("BACKGROUND",    (0,0), (-1,0),  GREEN),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_MED),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0), (-1,-1), 3),
        ("BOTTOMPADDING", (0,0), (-1,-1), 3),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
    ])
    for i in range(1, len(ehs_rows)):
        ehs_ts.add("BACKGROUND", (0,i), (-1,i), GREY_LIGHT if i % 2 == 0 else WHITE)
    ehs_t.setStyle(ehs_ts)
    story.append(ehs_t)
    story.append(Spacer(1, 4*mm))

    # ═══════════════════════════════════════════════════════════════════════════
    # ── SECTION 9: EXAMINER'S SUMMARY ───────────────────────────────────────
    # ═══════════════════════════════════════════════════════════════════════════
    section_header("SECTION 9 — EXAMINER'S SUMMARY & PROVISIONAL DIAGNOSIS", color=colors.HexColor("#4A4A4A"))

    summary_data = [
        [Paragraph("<b>Type of hernia:</b>", body),
         Paragraph("☐ Indirect (Lateral)   ☐ Direct (Medial)   ☐ Pantaloon   ☐ Femoral   ☐ Uncertain", body)],
        [Paragraph("<b>Side:</b>", body),
         Paragraph("☐ Right   ☐ Left   ☐ Bilateral", body)],
        [Paragraph("<b>Status:</b>", body),
         Paragraph("☐ Reducible   ☐ Irreducible   ☐ Incarcerated   ☐ Strangulated", body)],
        [Paragraph("<b>Complications:</b>", body),
         Paragraph("☐ None   ☐ Obstruction   ☐ Strangulation   ☐ Inflammation   ☐ Hydrocele", body)],
        [Paragraph("<b>EHS Classification:</b>", body),
         Paragraph("_____________", body)],
        [Paragraph("<b>Management plan:</b>", body),
         Paragraph("☐ Watchful waiting   ☐ Elective surgery   ☐ Urgent surgery   ☐ Emergency surgery", body)],
        [Paragraph("<b>Proposed operation:</b>", body),
         Paragraph("______________________________________________________________________________", body)],
        [Paragraph("<b>Anaesthesia:</b>", body),
         Paragraph("☐ Local   ☐ Regional   ☐ General", body)],
        [Paragraph("<b>Examiner signature:</b>", body),
         Paragraph("________________________________   Date: _________________", body)],
    ]
    sum_t = Table(summary_data, colWidths=[38*mm, W - 28*mm - 38*mm])
    sum_t.setStyle(TableStyle([
        ("BACKGROUND",    (0,0), (-1,-1), GREY_LIGHT),
        ("GRID",          (0,0), (-1,-1), 0.4, GREY_MED),
        ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
    ]))
    story.append(sum_t)
    story.append(Spacer(1, 3*mm))

    # Notes box
    notes_data = [[Paragraph("<b>Clinical Notes / Additional Findings:</b>", body)],
                  [Paragraph("\n\n\n\n\n\n", body)]]
    notes_t = Table(notes_data, colWidths=[W - 28*mm])
    notes_t.setStyle(TableStyle([
        ("BOX",           (0,0), (-1,-1), 0.8, DARK_BLUE),
        ("BACKGROUND",    (0,0), (-1,0),  LIGHT_BLUE),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("LINEBELOW",     (0,0), (-1,0),  0.5, MID_BLUE),
    ]))
    story.append(notes_t)

    # ─── Build ───────────────────────────────────────────────────────────────
    doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer)
    print(f"PDF created: {OUTPUT}")


if __name__ == "__main__":
    build_pdf()
Running Command

cd /tmp/workspace/inguinal-hernia-checklist && python generate_checklist.py 2>&1

Editing File

~/inguinal-hernia-checklist/generate_checklist.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/inguinal-hernia-checklist/generate_checklist.py'
Running Command

cd /tmp/workspace/inguinal-hernia-checklist && python generate_checklist.py 2>&1

Editing File

~/inguinal-hernia-checklist/generate_checklist.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/inguinal-hernia-checklist/generate_checklist.py'
Editing File

~/inguinal-hernia-checklist/generate_checklist.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/inguinal-hernia-checklist/generate_checklist.py'
Editing File

~/inguinal-hernia-checklist/generate_checklist.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/inguinal-hernia-checklist/generate_checklist.py'
Editing File

~/inguinal-hernia-checklist/generate_checklist.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/inguinal-hernia-checklist/generate_checklist.py'
This is a shared conversation. Sign in to Orris to start your own chat.