explain me all types of pyeloplasty done for puj obstruction
pyeloplasty "ureteropelvic junction" obstruction techniques
| Category | Techniques |
|---|---|
| Dismembered (excisional) | Anderson-Hynes pyeloplasty |
| Non-dismembered (flap) | Foley Y-V plasty, Fenger (Heineke-Mikulicz) pyeloplasty, Spiral flap, Vertical flap, Tubularized flap |
| Non-dismembered (other) | Davis Intubated Ureterotomy, Hellstrom Vascular Hitch |
| By surgical approach | Open (flank/lumbotomy), Laparoscopic, Robotic-assisted, LESS (single-site) |
| Endoscopic (non-reconstructive) | Endopyelotomy (antegrade/retrograde), Balloon dilation |

| Technique | Best For | Key Feature | Success Rate |
|---|---|---|---|
| Anderson-Hynes | All scenarios (gold standard) | Dismembered; full excision; vessel transposition possible | ~95% |
| Foley Y-V | High ureteral insertion | Non-dismembered V flap; no vessel transposition | ~86% |
| Fenger (H-M) | Short intrinsic stenosis | Longitudinal incision closed transversely | Limited use |
| Spiral flap | Long proximal ureteral stricture, dependent UPJ | Long spiraling pelvic flap bridges defect | Good, limited data |
| Vertical flap | Long stricture, box-shaped extrarenal pelvis | Straight flap, horizontal base | Similar to spiral |
| Tubularized flap | Large ureteral gap (3+ cm) | Pelvic tissue tubularized to form new ureter | Case reports |
| Davis intubated ureterotomy | Long/multiple strictures (rare) | Incise + stent; heals by re-epithelialization | Poor; abandoned |
| Hellstrom vascular hitch | Crossing vessel, NO intrinsic stenosis | Vessel repositioned cranially | Comparable to dismembered (select cases) |
| Laparoscopic (transperitoneal/retroperitoneal) | Standard minimally invasive | Any of above techniques; ~same success as open | >95% |
| Robotic-assisted | Children, complex cases | Easier intracorporeal suturing | >95% |
| LESS/R-LESS | Cosmetically conscious patients | Single umbilical incision | ~93% |
| Endopyelotomy | Short stricture, no crossing vessel | Incisional only; no reconstruction | ~65-75% |
Make a PDF quick-reference guide for pyeloplasty techniques and approaches
ls -la /home/daytona/workspace/
mkdir -p /home/daytona/workspace/pyeloplasty-guide && python3 -c "from reportlab.lib.pagesizes import A4; print('reportlab OK')" && python3 -c "from reportlab.platypus import SimpleDocTemplate; print('platypus OK')"
~/pyeloplasty-guide/build_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, PageBreak
)
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Polygon, Circle
from reportlab.graphics import renderPDF
from reportlab.platypus.flowables import Flowable
import os
OUTPUT = "/home/daytona/workspace/pyeloplasty-guide/Pyeloplasty_Quick_Reference.pdf"
# ─── Colour palette ───────────────────────────────────────────────────────────
DARK_BLUE = colors.HexColor("#1A3557") # headings / header bg
MID_BLUE = colors.HexColor("#2E6DA4") # sub-heading accent
LIGHT_BLUE = colors.HexColor("#D6E8F7") # table header bg
ACCENT_GOLD = colors.HexColor("#C9902A") # gold standard badge
LIGHT_GOLD = colors.HexColor("#FFF5E0") # gold standard row bg
LIGHT_GREY = colors.HexColor("#F4F6F9") # alternating row
WHITE = colors.white
RED_SOFT = colors.HexColor("#B83232") # contraindication text
GREEN_SOFT = colors.HexColor("#2A7A3B") # success rates
BORDER_GREY = colors.HexColor("#C0C8D4")
# ─── Styles ───────────────────────────────────────────────────────────────────
def make_styles():
s = {}
s["cover_title"] = ParagraphStyle(
"cover_title",
fontName="Helvetica-Bold",
fontSize=22,
textColor=WHITE,
leading=28,
alignment=TA_CENTER,
)
s["cover_subtitle"] = ParagraphStyle(
"cover_subtitle",
fontName="Helvetica",
fontSize=12,
textColor=colors.HexColor("#B8D4EE"),
leading=16,
alignment=TA_CENTER,
)
s["section_heading"] = ParagraphStyle(
"section_heading",
fontName="Helvetica-Bold",
fontSize=13,
textColor=WHITE,
leading=18,
spaceBefore=0,
spaceAfter=4,
leftIndent=0,
borderPad=6,
backColor=DARK_BLUE,
)
s["sub_heading"] = ParagraphStyle(
"sub_heading",
fontName="Helvetica-Bold",
fontSize=10.5,
textColor=DARK_BLUE,
leading=14,
spaceBefore=6,
spaceAfter=2,
)
s["body"] = ParagraphStyle(
"body",
fontName="Helvetica",
fontSize=9,
textColor=colors.HexColor("#222222"),
leading=13,
spaceAfter=3,
alignment=TA_JUSTIFY,
)
s["body_small"] = ParagraphStyle(
"body_small",
fontName="Helvetica",
fontSize=8,
textColor=colors.HexColor("#333333"),
leading=11,
spaceAfter=2,
alignment=TA_LEFT,
)
s["bullet"] = ParagraphStyle(
"bullet",
fontName="Helvetica",
fontSize=8.5,
textColor=colors.HexColor("#222222"),
leading=12,
leftIndent=12,
bulletIndent=0,
spaceAfter=2,
)
s["cell_head"] = ParagraphStyle(
"cell_head",
fontName="Helvetica-Bold",
fontSize=8.5,
textColor=WHITE,
leading=12,
alignment=TA_CENTER,
)
s["cell_body"] = ParagraphStyle(
"cell_body",
fontName="Helvetica",
fontSize=8,
textColor=colors.HexColor("#111111"),
leading=11,
alignment=TA_LEFT,
)
s["cell_body_center"] = ParagraphStyle(
"cell_body_center",
fontName="Helvetica",
fontSize=8,
textColor=colors.HexColor("#111111"),
leading=11,
alignment=TA_CENTER,
)
s["cell_success"] = ParagraphStyle(
"cell_success",
fontName="Helvetica-Bold",
fontSize=8,
textColor=GREEN_SOFT,
leading=11,
alignment=TA_CENTER,
)
s["cell_contra"] = ParagraphStyle(
"cell_contra",
fontName="Helvetica",
fontSize=7.5,
textColor=RED_SOFT,
leading=10.5,
alignment=TA_LEFT,
)
s["gold_badge"] = ParagraphStyle(
"gold_badge",
fontName="Helvetica-Bold",
fontSize=8.5,
textColor=ACCENT_GOLD,
leading=11,
alignment=TA_CENTER,
)
s["footer"] = ParagraphStyle(
"footer",
fontName="Helvetica",
fontSize=7,
textColor=colors.HexColor("#888888"),
leading=10,
alignment=TA_CENTER,
)
s["caption"] = ParagraphStyle(
"caption",
fontName="Helvetica-Oblique",
fontSize=7.5,
textColor=colors.HexColor("#555555"),
leading=10,
alignment=TA_CENTER,
spaceAfter=4,
)
return s
# ─── Helper: coloured section banner ─────────────────────────────────────────
class SectionBanner(Flowable):
def __init__(self, text, width, bg=DARK_BLUE, fg=WHITE, font_size=12, height=22):
super().__init__()
self.text = text
self._width = width
self.bg = bg
self.fg = fg
self.font_size = font_size
self._height = height
def wrap(self, availW, availH):
return self._width, self._height
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 0, self._width, self._height, 4, fill=1, stroke=0)
c.setFillColor(self.fg)
c.setFont("Helvetica-Bold", self.font_size)
c.drawString(8, 6, self.text)
# ─── Helper: horizontal rule ──────────────────────────────────────────────────
def hrule(width, color=BORDER_GREY, thickness=0.5):
return HRFlowable(width=width, thickness=thickness, color=color, spaceAfter=4, spaceBefore=4)
# ─── Cover page flowable ──────────────────────────────────────────────────────
class CoverPage(Flowable):
def __init__(self, width, height):
super().__init__()
self._width = width
self._height = height
def wrap(self, availW, availH):
return self._width, self._height
def draw(self):
c = self.canv
w, h = self._width, self._height
# Dark blue gradient background (solid for simplicity)
c.setFillColor(DARK_BLUE)
c.rect(0, 0, w, h, fill=1, stroke=0)
# Decorative horizontal bands
c.setFillColor(MID_BLUE)
c.rect(0, h * 0.38, w, h * 0.25, fill=1, stroke=0)
c.setFillColor(DARK_BLUE)
c.rect(0, h * 0.40, w, h * 0.21, fill=1, stroke=0)
# Top accent stripe
c.setFillColor(ACCENT_GOLD)
c.rect(0, h - 8, w, 8, fill=1, stroke=0)
# Bottom accent stripe
c.setFillColor(MID_BLUE)
c.rect(0, 0, w, 6, fill=1, stroke=0)
# Title text
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 26)
c.drawCentredString(w / 2, h * 0.70, "PYELOPLASTY")
c.setFont("Helvetica-Bold", 20)
c.drawCentredString(w / 2, h * 0.62, "Quick Reference Guide")
# Subtitle
c.setFillColor(colors.HexColor("#B8D4EE"))
c.setFont("Helvetica", 12)
c.drawCentredString(w / 2, h * 0.54, "Techniques & Surgical Approaches for PUJ Obstruction")
# Horizontal gold rule under subtitle
c.setStrokeColor(ACCENT_GOLD)
c.setLineWidth(1.5)
c.line(w * 0.2, h * 0.50, w * 0.8, h * 0.50)
# Info box
c.setFillColor(colors.HexColor("#0D2236"))
c.roundRect(w * 0.12, h * 0.12, w * 0.76, h * 0.29, 6, fill=1, stroke=0)
c.setStrokeColor(MID_BLUE)
c.setLineWidth(1)
c.roundRect(w * 0.12, h * 0.12, w * 0.76, h * 0.29, 6, fill=0, stroke=1)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 10)
c.drawCentredString(w / 2, h * 0.37, "CONTENTS")
items = [
"I. Anderson-Hynes Dismembered Pyeloplasty (Gold Standard)",
"II. Non-Dismembered Flap Techniques",
"III. Other UPJ Reconstruction Methods",
"IV. Surgical Approaches (Open / Laparoscopic / Robotic)",
"V. Comparison Summary Table",
"VI. Stenting & Key Clinical Points",
]
c.setFont("Helvetica", 8.5)
c.setFillColor(colors.HexColor("#C8DDEF"))
y = h * 0.33
for item in items:
c.drawCentredString(w / 2, y, item)
y -= 13
# Source attribution
c.setFillColor(colors.HexColor("#7AAAC8"))
c.setFont("Helvetica-Oblique", 7.5)
c.drawCentredString(w / 2, h * 0.07,
"Sources: Campbell-Walsh-Wein Urology | Hinman's Atlas of Urologic Surgery | Smith & Tanagho's General Urology")
# ─── Build document ───────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=18 * mm,
rightMargin=18 * mm,
topMargin=16 * mm,
bottomMargin=16 * mm,
title="Pyeloplasty Quick Reference Guide",
author="Orris Medical Reference",
subject="PUJ Obstruction Surgical Techniques",
)
W = A4[0] - 36 * mm # usable width
s = make_styles()
story = []
# ── Cover page ────────────────────────────────────────────────────────────
story.append(CoverPage(W, 240 * mm))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION I – OVERVIEW & ANDERSON-HYNES
# ══════════════════════════════════════════════════════════════════════════
story.append(SectionBanner("SECTION I Anderson-Hynes Dismembered Pyeloplasty", W, DARK_BLUE, WHITE, 11, 24))
story.append(Spacer(1, 5))
story.append(Paragraph(
"The Anderson-Hynes dismembered pyeloplasty is the <b>gold standard</b> for repair of PUJ obstruction, "
"applicable to virtually all clinical scenarios. The UPJ is completely excised, the aperistaltic segment "
"removed, and a wide, dependent, tension-free anastomosis constructed. Success rate ~95%.",
s["body"]
))
story.append(Spacer(1, 4))
# Two-column layout: Indications | Contraindications
ind_data = [
[Paragraph("<b>INDICATIONS</b>", s["cell_head"]),
Paragraph("<b>ADVANTAGES</b>", s["cell_head"])],
[
Paragraph(
"• All anatomical configurations\n"
"• High or dependent ureteral insertion\n"
"• Crossing/aberrant lower pole vessels\n"
"• Redundant renal pelvis (reduction pyeloplasty)\n"
"• Tortuous proximal ureter\n"
"• Redo pyeloplasty\n"
"• Most common first-line technique",
s["cell_body"]
),
Paragraph(
"• Complete excision of dysplastic segment\n"
"• UPJ transposition anterior to vessels possible\n"
"• Pelvis reduction simultaneous\n"
"• Universal applicability\n"
"• Largest long-term outcome data\n"
"• Suitable for open, laparoscopic, robotic\n"
"• 95% success rate",
s["cell_body"]
),
],
]
ind_table = Table(ind_data, colWidths=[W * 0.49, W * 0.49], hAlign="LEFT")
ind_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), MID_BLUE),
("BACKGROUND", (0, 1), (-1, 1), LIGHT_BLUE),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("ROUNDEDCORNERS", [4]),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 7),
("RIGHTPADDING", (0, 0), (-1, -1), 7),
]))
story.append(ind_table)
story.append(Spacer(1, 7))
story.append(Paragraph("Surgical Steps", s["sub_heading"]))
steps = [
("1", "Open Gerota's fascia; dissect UPJ and free lower renal pole. Inspect for crossing vessels."),
("2", "Place stay sutures on medial & lateral pelvis + lateral ureter below obstruction (orientation guide)."),
("3", "Dismember (excise) the UPJ. Aspirate tense pelvis with 21G needle before dismembering. Reduce redundant pelvis if needed."),
("4", "Spatulate the ureter along its LATERAL border, well beyond the dysplastic segment into healthy tissue."),
("5", "Bring apex of spatulated ureter to INFERIOR border of pelvis; medial ureter to SUPERIOR edge."),
("6", "Anastomose with 5-0 or 6-0 absorbable monofilament (round needle), interrupted or running, full-thickness, watertight."),
("7", "Place ureteral stent (internal double-J or externalized nephro-ureteric). Insert drain. Close Gerota's fascia."),
]
steps_data = [[
Paragraph(f"<b>{n}</b>", s["cell_body_center"]),
Paragraph(txt, s["cell_body"])
] for n, txt in steps]
steps_table = Table(steps_data, colWidths=[10 * mm, W - 10 * mm], hAlign="LEFT")
steps_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (0, -1), DARK_BLUE),
("TEXTCOLOR", (0, 0), (0, -1), WHITE),
("BACKGROUND", (1, 0), (1, -1), WHITE),
("ROWBACKGROUNDS", (1, 0), (1, -1), [WHITE, LIGHT_GREY]),
("GRID", (0, 0), (-1, -1), 0.3, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(steps_table)
story.append(Spacer(1, 6))
# Crossing vessel note
cv_data = [[
Paragraph(
"<b>CROSSING LOWER POLE VESSEL:</b> After dismembering, swing the ureter ANTERIOR to the vessel "
"before completing the anastomosis. The new UPJ lies ventral to the vessel. This is the key advantage "
"of dismembered over flap techniques.",
s["cell_body"]
)
]]
cv_table = Table(cv_data, colWidths=[W])
cv_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), LIGHT_GOLD),
("BOX", (0, 0), (-1, -1), 1, ACCENT_GOLD),
("TOPPADDING", (0, 0), (-1, -1), 7),
("BOTTOMPADDING", (0, 0), (-1, -1), 7),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
]))
story.append(cv_table)
story.append(Spacer(1, 10))
# ══════════════════════════════════════════════════════════════════════════
# SECTION II – NON-DISMEMBERED FLAP TECHNIQUES
# ══════════════════════════════════════════════════════════════════════════
story.append(SectionBanner("SECTION II Non-Dismembered Flap Pyeloplasties", W, MID_BLUE, WHITE, 11, 24))
story.append(Spacer(1, 5))
story.append(Paragraph(
"Flap techniques preserve UPJ continuity and widen the obstruction using pelvic tissue. "
"They are <b>universally contraindicated when crossing vessel transposition is needed</b>. "
"Largely replaced by Anderson-Hynes but useful in specific anatomical scenarios.",
s["body"]
))
story.append(Spacer(1, 5))
# --- Foley Y-V ---
story.append(SectionBanner(" 1. Foley Y-V Plasty", W, colors.HexColor("#3A6B9A"), WHITE, 10, 20))
story.append(Spacer(1, 4))
foley_data = [
[Paragraph("<b>Indication</b>", s["cell_head"]),
Paragraph("<b>Technique</b>", s["cell_head"]),
Paragraph("<b>Limitations</b>", s["cell_head"])],
[
Paragraph(
"High ureteral insertion (ureter inserts into apex/superior wall of pelvis rather than dependently). "
"No crossing vessels.",
s["cell_body"]
),
Paragraph(
"V-shaped flap outlined on dependent/medial pelvis, apex at UPJ. "
"Incision (stem of Y) down lateral ureter past stenosis into normal caliber. "
"Pelvic flap apex advanced to inferior ureterotomy. Closed in Y configuration.",
s["cell_body"]
),
Paragraph(
"• Cannot transpose crossing vessels\n"
"• Cannot reduce redundant pelvis\n"
"• Success ~86% vs 95% (Anderson-Hynes)\n"
"• Not for long ureteral strictures",
s["cell_contra"]
),
],
]
foley_table = Table(foley_data, colWidths=[W * 0.22, W * 0.44, W * 0.31], hAlign="LEFT")
foley_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#3A6B9A")),
("BACKGROUND", (0, 1), (-1, 1), LIGHT_BLUE),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(foley_table)
story.append(Spacer(1, 6))
# --- Fenger ---
story.append(SectionBanner(" 2. Fenger Pyeloplasty (Heineke-Mikulicz Principle)", W, colors.HexColor("#3A6B9A"), WHITE, 10, 20))
story.append(Spacer(1, 4))
fenger_data = [
[Paragraph("<b>Indication</b>", s["cell_head"]),
Paragraph("<b>Technique</b>", s["cell_head"]),
Paragraph("<b>Notes</b>", s["cell_head"])],
[
Paragraph("Short, localised intrinsic UPJ narrowing. No high insertion. No vessel transposition needed.", s["cell_body"]),
Paragraph(
"Longitudinal incision across the narrowed UPJ spanning the stenosis. "
"Closed TRANSVERSELY with interrupted absorbable sutures — widens the lumen without excision. "
"(Same principle as Heineke-Mikulicz pyloroplasty.)",
s["cell_body"]
),
Paragraph(
"• Only for very short stenoses\n"
"• Largely replaced by A-H\n"
"• Simple technique\n"
"• Can be done laparoscopically",
s["cell_body"]
),
],
]
fenger_table = Table(fenger_data, colWidths=[W * 0.22, W * 0.44, W * 0.31], hAlign="LEFT")
fenger_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#3A6B9A")),
("BACKGROUND", (0, 1), (-1, 1), LIGHT_BLUE),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(fenger_table)
story.append(Spacer(1, 6))
# --- Spiral + Vertical flaps ---
story.append(SectionBanner(" 3. Spiral Flap & Vertical Flap Pyeloplasty", W, colors.HexColor("#3A6B9A"), WHITE, 10, 20))
story.append(Spacer(1, 4))
flap_data = [
[Paragraph("<b>Type</b>", s["cell_head"]),
Paragraph("<b>Indication</b>", s["cell_head"]),
Paragraph("<b>Technique Key Points</b>", s["cell_head"]),
Paragraph("<b>Rule</b>", s["cell_head"])],
[
Paragraph("<b>Spiral Flap</b>\n(Culp-DeWeerd)", s["cell_body"]),
Paragraph("Long proximal ureteral obstruction; UPJ already in dependent position", s["cell_body"]),
Paragraph(
"Oblique base on dependent pelvis. Flap spirals post-to-ant (or vice versa). "
"Medial incision through entire stricture. Apex rotated to inferior ureterotomy.",
s["cell_body"]
),
Paragraph("Flap L:W ratio\nmax 3:1\n(vascular integrity)", s["cell_body"]),
],
[
Paragraph("<b>Vertical Flap</b>\n(Scardino-Prince)", s["cell_body"]),
Paragraph("Long stricture; UPJ at medial margin of large box-shaped extrarenal pelvis", s["cell_body"]),
Paragraph(
"Horizontal base between UPJ and renal parenchyma. Two straight converging incisions to apex "
"(ant or post pelvic wall). Apex rotated to inferior ureterotomy.",
s["cell_body"]
),
Paragraph("Flap L:W ratio\nmax 3:1", s["cell_body"]),
],
[
Paragraph("<b>Tubularized Flap</b>", s["cell_body"]),
Paragraph("Large ureteral gap (3+ cm) after excision of long stricture; tension-free anastomosis impossible", s["cell_body"]),
Paragraph(
"Wide-based pelvic flap rolled/tubularized over stent to bridge the ureteral defect. "
"Can be performed laparoscopically (Kaouk 2002).",
s["cell_body"]
),
Paragraph("Rarely needed;\nlimited data", s["cell_body"]),
],
]
flap_table = Table(flap_data, colWidths=[W * 0.16, W * 0.25, W * 0.43, W * 0.14], hAlign="LEFT")
flap_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#3A6B9A")),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, LIGHT_GREY, LIGHT_BLUE]),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 5),
("RIGHTPADDING", (0, 0), (-1, -1), 5),
]))
story.append(flap_table)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION III – OTHER UPJ RECONSTRUCTION
# ══════════════════════════════════════════════════════════════════════════
story.append(SectionBanner("SECTION III Other UPJ Reconstruction Methods", W, DARK_BLUE, WHITE, 11, 24))
story.append(Spacer(1, 5))
other_data = [
[Paragraph("<b>Technique</b>", s["cell_head"]),
Paragraph("<b>Indication</b>", s["cell_head"]),
Paragraph("<b>Principle</b>", s["cell_head"]),
Paragraph("<b>Notes / Status</b>", s["cell_head"])],
[
Paragraph("<b>Davis Intubated\nUreterotomy</b>", s["cell_body"]),
Paragraph("Long or multiple ureteral strictures at/near UPJ", s["cell_body"]),
Paragraph(
"Longitudinal incision through entire stricture. Stent (intubating catheter) left for 4-6 weeks. "
"Heals by secondary urothelial re-epithelialization over stent.",
s["cell_body"]
),
Paragraph("Rarely used today. High recurrence. Unpredictable healing. Largely abandoned.", s["cell_contra"]),
],
[
Paragraph("<b>Hellstrom\nVascular Hitch</b>", s["cell_body"]),
Paragraph("Crossing lower pole vessel as SOLE cause; NO intrinsic UPJ stenosis", s["cell_body"]),
Paragraph(
"Crossing vessel mobilized off UPJ and sutured ('hitched') cranially onto renal pelvic tissue, "
"eliminating extrinsic compression. No ureteral reconstruction.",
s["cell_body"]
),
Paragraph(
"Select patients only (Gundeti criteria: moderate hydronephrosis, normal ureter/UPJ with peristalsis). "
"Long-term data limited. Comparable to A-H in select cases (Madec 2016).",
s["cell_body"]
),
],
[
Paragraph("<b>Bypass\nPyeloplasty</b>", s["cell_body"]),
Paragraph("UPJ with near-dependent position; side-to-side anastomosis preferred", s["cell_body"]),
Paragraph(
"Side-to-side anastomosis of ureter and renal pelvis WITHOUT transecting the stenotic UPJ. "
"New UPJ configured within 1 cm of lower pole parenchyma. Ureter kept anchored.",
s["cell_body"]
),
Paragraph("Feasible alternative; no systematic review available.", s["cell_body"]),
],
[
Paragraph("<b>Ureterocalicostomy</b>", s["cell_body"]),
Paragraph("Failed pyeloplasty; severely scarred UPJ; small intrarenal pelvis inaccessible", s["cell_body"]),
Paragraph(
"Ureter anastomosed directly to the most dependent lower pole calyx after amputation of the "
"lower pole parenchyma. Bypasses the scarred UPJ entirely.",
s["cell_body"]
),
Paragraph("Salvage procedure. Robotic-assisted variant described (RALUC - systematic review 2025).", s["cell_body"]),
],
]
other_table = Table(other_data, colWidths=[W * 0.17, W * 0.22, W * 0.36, W * 0.23], hAlign="LEFT")
other_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), DARK_BLUE),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, LIGHT_GREY, WHITE, LIGHT_GREY]),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(other_table)
story.append(Spacer(1, 10))
# ══════════════════════════════════════════════════════════════════════════
# SECTION IV – SURGICAL APPROACHES
# ══════════════════════════════════════════════════════════════════════════
story.append(SectionBanner("SECTION IV Surgical Approaches", W, DARK_BLUE, WHITE, 11, 24))
story.append(Spacer(1, 5))
# --- Open ---
story.append(Paragraph("A. Open Pyeloplasty", s["sub_heading"]))
open_data = [
[Paragraph("<b>Approach</b>", s["cell_head"]),
Paragraph("<b>Patient Position</b>", s["cell_head"]),
Paragraph("<b>Best For</b>", s["cell_head"]),
Paragraph("<b>Notes</b>", s["cell_head"])],
[
Paragraph("Flank (subcostal / transcostal)", s["cell_body"]),
Paragraph("Lateral decubitus", s["cell_body"]),
Paragraph("Standard approach; most adults & children", s["cell_body"]),
Paragraph("Most commonly used open route", s["cell_body"]),
],
[
Paragraph("Posterior Lumbotomy (Dorsal)", s["cell_body"]),
Paragraph("Prone", s["cell_body"]),
Paragraph("Infants & toddlers ONLY", s["cell_body"]),
Paragraph("Increasing dorsal musculature with age makes this impractical in older patients", s["cell_body"]),
],
[
Paragraph("Anterior (subcostal / transabdominal)", s["cell_body"]),
Paragraph("Supine / lateral", s["cell_body"]),
Paragraph("Horseshoe/malrotated kidneys; bilateral cases", s["cell_body"]),
Paragraph("Direct access when UPJ is anterior", s["cell_body"]),
],
[
Paragraph("Transmesocolic (through mesocolon)", s["cell_body"]),
Paragraph("Supine", s["cell_body"]),
Paragraph("Pediatric/thin patients; horseshoe/malrotated kidneys; left side", s["cell_body"]),
Paragraph(
"Incision through mesocolon without colon mobilization. Quick UPJ access. "
"Ideal when pelvis anatomy is distorted.",
s["cell_body"]
),
],
]
open_table = Table(open_data, colWidths=[W * 0.24, W * 0.17, W * 0.30, W * 0.27], hAlign="LEFT")
open_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), MID_BLUE),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, LIGHT_GREY, WHITE, LIGHT_GREY]),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(open_table)
story.append(Spacer(1, 7))
# --- Laparoscopic ---
story.append(Paragraph("B. Laparoscopic Pyeloplasty (First described 1993 - Kavoussi & Peters)", s["sub_heading"]))
lap_data = [
[Paragraph("<b>Route</b>", s["cell_head"]),
Paragraph("<b>Description</b>", s["cell_head"]),
Paragraph("<b>Advantages</b>", s["cell_head"]),
Paragraph("<b>Considerations</b>", s["cell_head"])],
[
Paragraph("<b>Transperitoneal</b>\n(most common)", s["cell_body"]),
Paragraph("Enter peritoneal cavity; reflect colon; standard port placement", s["cell_body"]),
Paragraph("Largest working space; familiar anatomy; good visualization", s["cell_body"]),
Paragraph("Standard route for adults; most literature data", s["cell_body"]),
],
[
Paragraph("<b>Retroperitoneal</b>\n(retroperitoneoscopic)", s["cell_body"]),
Paragraph("Balloon/manual dilation of retroperitoneal space; direct UPJ access", s["cell_body"]),
Paragraph("Avoids peritoneal cavity; shorter path to UPJ; faster bowel recovery; preferred in redo cases", s["cell_body"]),
Paragraph("More technically challenging; less working space; higher conversion rate in some series", s["cell_body"]),
],
[
Paragraph("<b>Hand-Assisted</b>", s["cell_body"]),
Paragraph("Hand port added to standard laparoscopic ports", s["cell_body"]),
Paragraph("Bridge for surgeons building laparoscopic skills; tactile feedback", s["cell_body"]),
Paragraph("Less commonly used now", s["cell_body"]),
],
]
lap_table = Table(lap_data, colWidths=[W * 0.18, W * 0.27, W * 0.29, W * 0.24], hAlign="LEFT")
lap_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), MID_BLUE),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, LIGHT_GREY, WHITE]),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(lap_table)
lap_note_data = [[Paragraph(
"<b>Key fact:</b> Laparoscopic pyeloplasty achieves success rates >95% in experienced hands, "
"comparable to open surgery with less morbidity. "
"All pyeloplasty techniques (A-H, Y-V, H-M, Davis, Hellstrom, tubularized flap) have been described laparoscopically. "
"(Autorino et al. meta-analysis 2014)",
s["cell_body"]
)]]
lap_note_table = Table(lap_note_data, colWidths=[W])
lap_note_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), LIGHT_BLUE),
("BOX", (0, 0), (-1, -1), 0.8, MID_BLUE),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
]))
story.append(Spacer(1, 4))
story.append(lap_note_table)
story.append(Spacer(1, 7))
# --- Robotic ---
story.append(Paragraph("C. Robotic-Assisted Pyeloplasty (Since ~2004)", s["sub_heading"]))
rob_data = [
[Paragraph("<b>Platform</b>", s["cell_head"]),
Paragraph("<b>Key Points</b>", s["cell_head"]),
Paragraph("<b>Evidence (2025)</b>", s["cell_head"])],
[
Paragraph("Standard Multiport Robotic\n(transperitoneal, most common)", s["cell_body"]),
Paragraph(
"Wristed articulating instruments ease intracorporeal suturing. "
"Shorter learning curve vs. pure laparoscopy. Especially advantageous in children and complex anatomies.",
s["cell_body"]
),
Paragraph("Equivalent or superior outcomes to laparoscopic pyeloplasty (Kuiqing et al. PMID 40753141, J Robot Surg 2025)", s["cell_body"]),
],
[
Paragraph("Retroperitoneal Robotic", s["cell_body"]),
Paragraph("Same advantages as retroperitoneal laparoscopic + robotic dexterity. Emerging approach.", s["cell_body"]),
Paragraph("Limited comparative data vs transperitoneal robotic", s["cell_body"]),
],
[
Paragraph("Single-Port Robotic (SP)", s["cell_body"]),
Paragraph("Single trocar entry. Improved cosmesis. All instruments through one port.", s["cell_body"]),
Paragraph("Meta-analysis (Yang et al. PMID 40016552, 2025): comparable efficacy to multiport with better cosmesis", s["cell_body"]),
],
[
Paragraph("LESS / R-LESS\n(Laparoendoscopic Single-Site)", s["cell_body"]),
Paragraph(
"Umbilical multichannel port (GelPoint). 2 robotic + 2 standard trocars 3 cm apart (diamond config). "
"Near-invisible cosmetic result.",
s["cell_body"]
),
Paragraph("~93% success (Harrow et al. 2013). Technically demanding (instrument clashing).", s["cell_body"]),
],
]
rob_table = Table(rob_data, colWidths=[W * 0.22, W * 0.44, W * 0.32], hAlign="LEFT")
rob_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), DARK_BLUE),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, LIGHT_GREY, WHITE, LIGHT_GREY]),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(rob_table)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION V – COMPARISON TABLE
# ══════════════════════════════════════════════════════════════════════════
story.append(SectionBanner("SECTION V Comparison Summary Table", W, DARK_BLUE, WHITE, 11, 24))
story.append(Spacer(1, 5))
comp_headers = ["Technique", "Best Indication", "Crossing Vessel?", "Success", "Key Limitation"]
comp_rows = [
["Anderson-Hynes\n(Dismembered) ★", "All scenarios; gold standard", "YES - transpose", "~95%",
"Not for tiny intrarenal pelvis or very long stricture"],
["Foley Y-V Plasty", "High ureteral insertion", "NO", "~86%",
"Cannot transpose vessels; no pelvis reduction"],
["Fenger (H-M)", "Short intrinsic stenosis", "NO", "Limited data",
"Only for very short strictures"],
["Spiral Flap\n(Culp-DeWeerd)", "Long proximal stricture, dependent UPJ", "NO", "Good",
"L:W ratio max 3:1; cannot transpose vessels"],
["Vertical Flap\n(Scardino-Prince)", "Long stricture, box-shaped pelvis", "NO", "Good",
"Same constraints as spiral flap"],
["Tubularized Flap", "Large ureteral gap (>3 cm)", "NO", "Case reports",
"Rarely needed; limited outcome data"],
["Davis Intubated\nUreterotomy", "Long/multiple strictures", "NO", "Poor",
"High recurrence; largely abandoned"],
["Hellstrom Vascular\nHitch", "Crossing vessel ONLY, no intrinsic stenosis", "N/A - addressed", "Comparable (selected)",
"Strict patient selection; limited long-term data"],
["Laparoscopic\n(trans/retroperitoneal)", "Standard minimally invasive approach", "YES (with A-H)", ">95%",
"Requires advanced laparoscopic suturing skills"],
["Robotic-Assisted\n(multiport / SP)", "Children; complex anatomy; suturing difficult", "YES (with A-H)", ">95%",
"Higher cost; availability"],
["LESS / R-LESS", "Cosmetically conscious patients", "YES (with A-H)", "~93%",
"Instrument clashing; steep learning curve"],
["Endopyelotomy\n(antegrade/retrograde)", "Short stricture, no crossing vessel, limited function", "CONTRAINDICATED", "65-75%",
"Inferior to all pyeloplasty types; high recurrence"],
]
comp_data = [[Paragraph(f"<b>{h}</b>", s["cell_head"]) for h in comp_headers]]
for i, row in enumerate(comp_rows):
bg = LIGHT_GOLD if i == 0 else (LIGHT_GREY if i % 2 == 0 else WHITE)
# success column coloring
cells = []
for j, cell_text in enumerate(row):
if j == 3: # success column
if "95%" in cell_text or ">95" in cell_text:
cells.append(Paragraph(f"<b>{cell_text}</b>", s["cell_success"]))
elif "65" in cell_text or "75" in cell_text:
cells.append(Paragraph(cell_text, s["cell_contra"]))
elif "86%" in cell_text:
cells.append(Paragraph(cell_text, s["cell_body_center"]))
else:
cells.append(Paragraph(cell_text, s["cell_body_center"]))
elif j == 2 and "CONTRA" in cell_text:
cells.append(Paragraph(cell_text, s["cell_contra"]))
else:
cells.append(Paragraph(cell_text, s["cell_body"]))
comp_data.append(cells)
# Mark gold standard row
comp_data[1][0] = Paragraph("<b>Anderson-Hynes\n(Dismembered) ★</b>", s["gold_badge"])
col_widths = [W * 0.20, W * 0.26, W * 0.14, W * 0.10, W * 0.28]
comp_table = Table(comp_data, colWidths=col_widths, hAlign="LEFT", repeatRows=1)
row_styles = [
("BACKGROUND", (0, 0), (-1, 0), DARK_BLUE),
("BACKGROUND", (0, 1), (-1, 1), LIGHT_GOLD),
("BOX", (0, 1), (-1, 1), 1, ACCENT_GOLD),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 4),
("BOTTOMPADDING", (0, 0), (-1, -1), 4),
("LEFTPADDING", (0, 0), (-1, -1), 5),
("RIGHTPADDING", (0, 0), (-1, -1), 5),
]
for i in range(2, len(comp_data)):
if i % 2 == 0:
row_styles.append(("BACKGROUND", (0, i), (-1, i), LIGHT_GREY))
else:
row_styles.append(("BACKGROUND", (0, i), (-1, i), WHITE))
comp_table.setStyle(TableStyle(row_styles))
story.append(comp_table)
story.append(Spacer(1, 6))
story.append(Paragraph(
"★ Anderson-Hynes dismembered pyeloplasty is the gold standard — the reference for all comparisons. "
"Endopyelotomy is inferior to all pyeloplasty forms and should NOT be used when a crossing vessel is present (haemorrhage risk).",
s["caption"]
))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════
# SECTION VI – STENTING + KEY CLINICAL POINTS
# ══════════════════════════════════════════════════════════════════════════
story.append(SectionBanner("SECTION VI Stenting & Key Clinical Points", W, DARK_BLUE, WHITE, 11, 24))
story.append(Spacer(1, 6))
# Stenting
story.append(Paragraph("Ureteral Stenting After Pyeloplasty", s["sub_heading"]))
stent_data = [
[Paragraph("<b>Stent Type</b>", s["cell_head"]),
Paragraph("<b>Features</b>", s["cell_head"]),
Paragraph("<b>Removal</b>", s["cell_head"])],
[
Paragraph("Internal Double-J (Pigtail)", s["cell_body"]),
Paragraph(
"Both ends in bladder & renal pelvis. Invisible externally. "
"Avoids second anesthesia in adults. May be difficult to pass UVJ in small infants.",
s["cell_body"]
),
Paragraph("Outpatient cystoscopy at 4-6 weeks", s["cell_body"]),
],
[
Paragraph("Externalized Nephro-Ureteric Stent", s["cell_body"]),
Paragraph(
"Exits via nephrostomy (external). Preferred in infants (Nasser et al. RCT: reduces complications & hospital stay). "
"Avoids need for cystoscopy under GA.",
s["cell_body"]
),
Paragraph("Bedside removal at 4-6 weeks", s["cell_body"]),
],
[
Paragraph("Stentless Anastomosis", s["cell_body"]),
Paragraph(
"Advocated by some surgeons; requires meticulous tissue handling to prevent edema/leak. "
"Historically, Anderson & Hynes themselves opposed routine stenting.",
s["cell_body"]
),
Paragraph("N/A - no stent placed", s["cell_body"]),
],
]
stent_table = Table(stent_data, colWidths=[W * 0.22, W * 0.52, W * 0.24], hAlign="LEFT")
stent_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), MID_BLUE),
("ROWBACKGROUNDS", (0, 1), (-1, -1), [WHITE, LIGHT_GREY, WHITE]),
("GRID", (0, 0), (-1, -1), 0.4, BORDER_GREY),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 6),
("RIGHTPADDING", (0, 0), (-1, -1), 6),
]))
story.append(stent_table)
story.append(Spacer(1, 8))
# Key clinical points
story.append(Paragraph("Key Clinical Points", s["sub_heading"]))
key_points = [
("TECHNIQUE SELECTION", [
"Anderson-Hynes is the go-to for >95% of cases. Only switch to a flap technique when anatomy specifically demands it.",
"Foley Y-V: only for confirmed high ureteral insertion with no crossing vessel.",
"Spiral/vertical flap: only when a long proximal ureteral gap prevents tension-free A-H anastomosis.",
"Hellstrom hitch: only when intraoperative peristalsis confirms NO intrinsic stenosis.",
]),
("CROSSING VESSEL MANAGEMENT", [
"Always inspect for lower pole crossing vessels before dismembering.",
"With A-H: swing ureter anterior to vessel - confirmed by visualizing vessel lying posterior to anastomosis.",
"With Hellstrom hitch: embed vessel into pelvic tissue with non-absorbable sutures cranially.",
"Hypertension from embedding vessels has NOT been observed in follow-up.",
]),
("OPERATIVE TIPS", [
"Aspirate a tensely dilated pelvis with a 21G needle before dismembering (avoid excessive pelvic reduction).",
"Preserve periureteral tissue when mobilizing ureter (blood supply runs within it).",
"Use bipolar diathermy near pelvis/ureter - avoid monopolar cautery.",
"The anastomotic 'crotch' (V tip) must be assembled precisely and tension-free.",
"Irrigate pelvis with saline before completing anastomosis (remove blood clots).",
"Reduce pelvis only if it is genuinely redundant - unnecessary reduction risks ischemia.",
]),
("POSTOPERATIVE FOLLOW-UP", [
"Foley catheter removed POD 1; drain removed when output <60 mL/8hr.",
"Typical discharge POD 1-2 after minimally invasive pyeloplasty.",
"Ureteral stent removed at 4-6 weeks (outpatient).",
"MAG3 diuretic renal scan at 3 months, 6 months, then annually x 2 years.",
"Whitaker pressure-flow test: used to differentiate residual obstruction vs. dilatation after pyeloplasty.",
]),
("COMPLICATIONS", [
"Urinary leak / urinoma (most common): usually managed conservatively with prolonged stenting.",
"Anastomotic stricture / failure: ~5%; redo pyeloplasty, endopyelotomy, or ureterocalicostomy.",
"Laparoscopic-specific: colonic injury, ileus, urinary ascites, thrombophlebitis (~12-15% overall complication rate).",
"Endopyelotomy-specific: haemorrhage if crossing vessel present (major risk - avoid if vessel present).",
]),
]
for section_title, points in key_points:
row_data = [
[
Paragraph(f"<b>{section_title}</b>", s["cell_head"]),
]
]
pts_para = "".join([f"<bullet bulletChar='•'>{pt}</bullet>" for pt in points])
pts_para_obj = Paragraph(pts_para, s["bullet"])
row_data.append([pts_para_obj])
kp_table = Table(row_data, colWidths=[W])
kp_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), DARK_BLUE),
("BACKGROUND", (0, 1), (-1, 1), LIGHT_GREY),
("BOX", (0, 0), (-1, -1), 0.5, BORDER_GREY),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
]))
story.append(kp_table)
story.append(Spacer(1, 4))
story.append(Spacer(1, 8))
# Hellstrom patient selection box
hs_data = [[Paragraph(
"<b>Hellstrom Vascular Hitch - Gundeti Selection Criteria (ALL must be met):</b> "
"Moderate hydronephrosis | No calyceal dilation | Preserved renal cortex | "
"Poor drainage with preserved split function | Lower pole crossing vessel on imaging | "
"Intraoperatively: normal-caliber ureter AND active peristalsis at UPJ",
s["cell_body"]
)]]
hs_table = Table(hs_data, colWidths=[W])
hs_table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), LIGHT_GOLD),
("BOX", (0, 0), (-1, -1), 1, ACCENT_GOLD),
("TOPPADDING", (0, 0), (-1, -1), 7),
("BOTTOMPADDING", (0, 0), (-1, -1), 7),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
]))
story.append(hs_table)
story.append(Spacer(1, 10))
# Sources
story.append(hrule(W))
story.append(Paragraph(
"<b>Sources:</b> Campbell-Walsh-Wein Urology 3-Volume Set (Dismembered Pyeloplasty pp. 2605-2612; "
"Laparoscopic/Robotic pp. 2100-2151) | Hinman's Atlas of Urologic Surgery (pp. 164, 207) | "
"Smith & Tanagho's General Urology 19th Ed. (p. 176) | "
"Kuiqing et al. J Robot Surg 2025 [PMID 40753141] | Yang et al. J Robot Surg 2025 [PMID 40016552] | "
"Spinos et al. World J Urol 2025 [PMID 41405725 - RALUC]",
s["footer"]
))
doc.build(story)
print(f"PDF saved to {OUTPUT}")
build()
cd /home/daytona/workspace/pyeloplasty-guide && python3 build_pdf.py 2>&1
~/pyeloplasty-guide/build_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/pyeloplasty-guide/build_pdf.py'
cd /home/daytona/workspace/pyeloplasty-guide && python3 build_pdf.py 2>&1
ls -lh /home/daytona/workspace/pyeloplasty-guide/Pyeloplasty_Quick_Reference.pdf && python3 -c "from pypdf import PdfReader; r = PdfReader('/home/daytona/workspace/pyeloplasty-guide/Pyeloplasty_Quick_Reference.pdf'); print(f'Pages: {len(r.pages)}')"
Pyeloplasty Quick Reference
PDF Document · PDF
| Page | Section |
|---|---|
| 1 | Cover page with contents list |
| 2 | Section I - Anderson-Hynes Dismembered Pyeloplasty (gold standard, step-by-step, crossing vessel note) |
| 3 | Section II - All Non-Dismembered Flap Techniques (Foley Y-V, Fenger, Spiral, Vertical, Tubularized) |
| 4 | Section III - Other UPJ Methods (Davis, Hellstrom Hitch, Bypass, Ureterocalicostomy) |
| 4-5 | Section IV - All Surgical Approaches (Open incisions, Laparoscopic trans/retroperitoneal, Robotic multiport/SP/LESS) |
| 6 | Section V - Full Comparison Summary Table (12 techniques, color-coded success rates, contraindications) |
| 7-8 | Section VI - Stenting options + Key Clinical Points (technique selection, crossing vessel management, operative tips, follow-up, complications) + Hellstrom Gundeti selection criteria box |