Jump to content

FDA Oncology Approvals 2025: Difference between revisions

From Neoplasm
No edit summary
No edit summary
Line 1: Line 1:
import re
{| class="wikitable sortable" style="width:100%;"
import sys
! #
from datetime import datetime
! Approval date
import requests
! Medication (Brand)
from bs4 import BeautifulSoup
! Company
from urllib.parse import urljoin
! Indication
! Regulatory type


FDA_INDEX = "https://www.fda.gov/drugs/resources-information-approved-drugs/oncology-cancerhematologic-malignancies-approval-notifications"
|-
 
| 1 | 12/17/2025 | Amivantamab + hyaluronidase-lpuj (Rybrevant Faspro) | Janssen Biotech, Inc. | Subcutaneous injection across all approved amivantamab indications | Traditional
UA = "Mozilla/5.0 (compatible; NeoplasmBot/1.0; +https://neoplasm.org/)"
|-
 
| 2 | 12/17/2025 | Rucaparib (Rubraca) | pharmaand GmbH | BRCA-mutated mCRPC after androgen receptor therapy | Traditional
def clean_ws(s: str) -> str:
|-
    return re.sub(r"\s+", " ", s).strip()
| 3 | 12/15/2025 | Fam-trastuzumab deruxtecan-nxki + pertuzumab (Enhertu + Perjeta) | Daiichi Sankyo | 1L unresectable/metastatic HER2+ breast cancer | Traditional
 
|-
def infer_regulatory_type(title: str) -> str:
| 4 | 12/12/2025 | Niraparib + abiraterone acetate + prednisone (Akeega) | Janssen Biotech | BRCA2-mutated mCSPC | Traditional
    t = title.lower()
|-
    if "accelerated approval" in t:
| 5 | 12/04/2025 | Lisocabtagene maraleucel (Breyanzi) | Juno / BMS | R/R marginal zone lymphoma ≥2 lines | Traditional
        return "Accelerated approval"
|-
    if "regular approval" in t or "traditional approval" in t or "grants traditional approval" in t:
| 6 | 12/03/2025 | Pirtobrutinib (Jaypirca) | Eli Lilly | R/R CLL/SLL after BTK inhibitor | Traditional
        return "Traditional approval"
|-
    # Many FDA titles are "FDA approves ..."
| 7 | 11/25/2025 | Durvalumab (Imfinzi) | AstraZeneca | Resectable gastric/GEJ adenocarcinoma | Traditional
    return "Traditional approval"
|-
 
| 8 | 11/21/2025 | Pembrolizumab + enfortumab vedotin (Keytruda + Padcev) | Merck / Astellas | Cisplatin-ineligible MIBC | Traditional
def extract_company_and_brand(desc: str):
|-
    # Typical: "... approved DRUG (Brand, Company) for ..."
| 9 | 11/19/2025 | Tarlatamab-dlle (Imdelltra) | Amgen | ES-SCLC after platinum | Traditional
    # We'll try to grab the first parenthetical after the drug name.
|-
    m = re.search(r"\(([^)]*?),\s*([^)]+?)\)", desc)
| 10 | 11/19/2025 | Sevabertinib (Hyrnuo) | Bayer | HER2-mutated NSCLC | Accelerated
    if m:
|-
        brand = clean_ws(m.group(1))
| 11 | 11/19/2025 | Daratumumab + hyaluronidase-fihj (Darzalex Faspro) | Janssen | Newly diagnosed AL amyloidosis | Traditional
        company = clean_ws(m.group(2))
|-
        return brand, company
| 12 | 11/19/2025 | Selumetinib (KOSELUGO) | AstraZeneca | Adult NF1 plexiform neurofibromas | Traditional
    return "", ""
|-
 
| 13 | 11/18/2025 | Epcoritamab-bysp (Epkinly) | Genmab | Relapsed/refractory follicular lymphoma | Traditional
def extract_drug_from_desc(desc: str):
|-
    # Try: "approved X (Brand, Company..." => capture X
| 14 | 11/13/2025 | Pertuzumab-dpzb (Poherdy) | Henlius | Interchangeable biosimilar to Perjeta | Traditional
    m = re.search(r"(approved|granted .*? approval to)\s+(.+?)\s*\(", desc, flags=re.IGNORECASE)
|-
    if m:
| 15 | 11/13/2025 | Ziftomenib (Komzifti) | Kura Oncology | R/R NPM1-mutated AML | Traditional
        return clean_ws(m.group(2))
|-
    # fallback: take first sentence fragment after "approved"
| 16 | 11/06/2025 | Daratumumab + hyaluronidase-fihj | Janssen | High-risk smoldering multiple myeloma | Traditional
    m2 = re.search(r"approved\s+(.+?)[\.,]", desc, flags=re.IGNORECASE)
|-
    if m2:
| 17 | 10/24/2025 | Revumenib (Revuforj) | Syndax | R/R NPM1-mutated AML | Traditional
        return clean_ws(m2.group(1))
|-
    return ""
| 18 | 10/23/2025 | Belantamab mafodotin-blmf (Blenrep) | GSK | R/R multiple myeloma ≥2 lines | Traditional
 
|-
def extract_indication(desc: str):
| 19 | 10/08/2025 | Cemiplimab-rwlc (Libtayo) | Regeneron | Adjuvant CSCC | Traditional
    # Remove leading "On DATE, FDA approved ..." and keep the "for ..." clause, if possible
|-
    # We’ll keep the whole description but trim the leading "On ..."
| 20 | 10/02/2025 | Lurbinectedin + atezolizumab | Jazz / Genentech | ES-SCLC maintenance | Traditional
    desc = clean_ws(desc)
|-
    desc = re.sub(r"^On\s+[A-Za-z]+\s+\d{1,2},\s+2025,\s+the\s+Food\s+and\s+Drug\s+Administration\s+",
| 21 | 09/25/2025 | Imlunestrant (Inluriyo) | Eli Lilly | ESR1-mutated ER+ MBC | Traditional
                  "", desc, flags=re.IGNORECASE)
|-
    desc = re.sub(r"^FDA\s+", "FDA ", desc, flags=re.IGNORECASE)
| 22 | 09/19/2025 | Pembrolizumab SC (Keytruda Qlex) | Merck | Solid tumors (SC formulation) | Traditional
    # Keep it readable
|-
    return desc
| 23 | 09/10/2025 | Selumetinib (KOSELUGO) | AstraZeneca | Pediatric NF1 PN | Traditional
 
|-
TRIAL_PATTERNS = [
| 24 | 09/09/2025 | Gemcitabine intravesical system (Inlexzo) | Janssen | BCG-unresponsive NMIBC | Traditional
    r"\b[A-Z][A-Z0-9]+(?:[-–][A-Z0-9]+)+\b",    # e.g., TROPION-Lung01, CodeBreaK-300, KOMET-001
|-
    r"\b[A-Z][a-zA-Z]+(?:[-–][A-Za-z0-9]+)+\b",  # e.g., PALOMA-3
| 25 | 08/08/2025 | Zongertinib (Hernexeos) | Boehringer Ingelheim | HER2-mutated NSCLC | Accelerated
]
|-
 
| 26 | 08/06/2025 | Dordaviprone (Modeyso) | Jazz | Diffuse midline glioma | Accelerated
def extract_trials_from_page(text: str):
|-
    trials = set()
| 27 | 07/02/2025 | Sunvozertinib (Zegfrovy) | Dizal | EGFR exon 20 NSCLC | Accelerated
    for pat in TRIAL_PATTERNS:
|-
        for m in re.finditer(pat, text):
| 28 | 07/02/2025 | Linvoseltamab-gcpt (Lynozyfic) | Regeneron | R/R multiple myeloma | Accelerated
            token = m.group(0).replace("–", "-")
|-
            # filter obvious non-trial noise
| 29 | 06/23/2025 | Datopotamab deruxtecan-dlnk (Datroway) | Daiichi Sankyo | EGFR-mutated NSCLC | Accelerated
            if len(token) < 6:
|-
                continue
| 30 | 06/18/2025 | Tafasitamab-cxix (Monjuvi) | Incyte | R/R follicular lymphoma | Traditional
            if token.lower() in {"non-small", "small-cell"}:
|-
                continue
| 31 | 06/12/2025 | Pembrolizumab (Keytruda) | Merck | Resectable HNSCC | Traditional
            trials.add(token)
|-
    # Remove very common false-positives
| 32 | 06/12/2025 | Mitomycin intravesical solution (Zusduri) | UroGen | LG-IR NMIBC | Traditional
    blacklist = {"FDA", "IHC", "ISH", "CDx", "NF1", "HNSCC", "NSCLC", "ES-SCLC", "mCRPC", "mCSPC"}
|-
    trials = [t for t in trials if t not in blacklist]
| 33 | 06/11/2025 | Taletrectinib (Ibtrozi) | Nuvation Bio | ROS1+ NSCLC | Traditional
    # sort with a stable, human-friendly order
|-
    return sorted(trials, key=lambda x: (x.lower(), x))
| 34 | 06/03/2025 | Darolutamide (Nubeqa) | Bayer | mCSPC | Traditional
 
|-
def fetch(url: str):
| 35 | 05/15/2025 | Retifanlimab-dlwr (Zynyz) | Incyte | Anal squamous cell carcinoma | Traditional
    r = requests.get(url, headers={"User-Agent": UA}, timeout=30)
|-
    r.raise_for_status()
| 36 | 05/14/2025 | Telisotuzumab vedotin-tllv (Emrelis) | AbbVie | c-MET high NSCLC | Accelerated
    return r.text
|-
 
| 37 | 05/14/2025 | Belzutifan (Welireg) | Merck | PPGL | Traditional
def parse_index_2025(index_html: str):
|-
    soup = BeautifulSoup(index_html, "html.parser")
| 38 | 05/08/2025 | Avutometinib + defactinib | Verastem | KRAS-mutated LGSOC | Accelerated
 
|-
    # The FDA page is basically a list/table of entries; simplest is: find all links inside the “Webpage Description Date” list
| 39 | 04/23/2025 | Penpulimab-kcqx | Akeso | Nasopharyngeal carcinoma | Traditional
    # We’ll collect rows that have a visible date ending in /2025.
|-
    entries = []
| 40 | 04/11/2025 | Nivolumab + ipilimumab | BMS | HCC | Traditional
    text = soup.get_text("\n", strip=True)
|-
 
| 41 | 04/08/2025 | Nivolumab + ipilimumab | BMS | MSI-H/dMMR CRC | Traditional
    # Better: find all <a> that look like approval items, then look for the date nearby.
|-
    for a in soup.select("a"):
| 42 | 03/28/2025 | Durvalumab | AstraZeneca | MIBC | Traditional
        title = clean_ws(a.get_text(" ", strip=True))
|-
        href = a.get("href") or ""
| 43 | 03/28/2025 | Lutetium Lu-177 vipivotide tetraxetan (Pluvicto) | Novartis | PSMA+ mCRPC | Traditional
        if not title.lower().startswith("fda "):
|-
            continue
| 44 | 03/26/2025 | Cabozantinib (Cabometyx) | Exelixis | pNET / epNET | Traditional
        if "/drugs/resources-information-approved-drugs/" not in href:
|-
            continue
| 45 | 03/19/2025 | Pembrolizumab + trastuzumab | Merck | HER2+ gastric cancer | Traditional
        url = urljoin(FDA_INDEX, href)
|-
 
| 46 | 02/14/2025 | Vimseltinib (Romvimza) | Deciphera | TGCT | Traditional
        # Find date near the link (FDA index typically has the date at end of same line)
|-
        parent_text = clean_ws(a.parent.get_text(" ", strip=True))
| 47 | 02/12/2025 | Brentuximab vedotin + lenalidomide + rituximab | Seagen | R/R LBCL | Traditional
        mdate = re.search(r"(\d{1,2}/\d{1,2}/2025)\b", parent_text)
|-
        if not mdate:
| 48 | 02/11/2025 | Mirdametinib (Gomekli) | SpringWorks | NF1 plexiform neurofibromas | Traditional
            continue
|-
        date_str = mdate.group(1)
| 49 | 02/06/2025 | Treosulfan + fludarabine | medac | AML/MDS HSCT conditioning | Traditional
 
|-
        # Description is usually right after link text in the same parent line
| 50 | 01/27/2025 | Fam-trastuzumab deruxtecan-nxki (Enhertu) | Daiichi Sankyo | HR+ HER2-low breast cancer | Traditional
        # We’ll take parent_text with title removed
|-
        desc = parent_text.replace(title, "").strip()
| 51 | 01/17/2025 | Datopotamab deruxtecan-dlnk (Datroway) | Daiichi Sankyo | HR+ HER2- breast cancer | Traditional
        desc = desc.replace(date_str, "").strip(" -\u00a0")
|-
 
| 52 | 01/16/2025 | Sotorasib + panitumumab | Amgen | KRAS G12C mCRC | Traditional
        entries.append({
|-
            "date": datetime.strptime(date_str, "%m/%d/%Y"),
| 53 | 01/16/2025 | Acalabrutinib + bendamustine + rituximab | AstraZeneca | Untreated mantle cell lymphoma | Traditional
            "date_str": date_str,
|}
            "title": title,
            "url": url,
            "desc": desc
        })
 
    # Deduplicate by URL
    seen = set()
    uniq = []
    for e in entries:
        if e["url"] in seen:
            continue
        seen.add(e["url"])
        uniq.append(e)
 
    # Sort newest first by date (matches FDA page ordering); you can reverse if you want
    uniq.sort(key=lambda x: x["date"], reverse=True)
    return uniq
 
def to_wikitable(entries):
    out = []
    out.append('{| class="wikitable sortable" style="width:100%; text-align:left;"')
    out.append("! #")
    out.append("! Approval date")
    out.append("! Medication (Brand)")
    out.append("! Company")
    out.append("! Indication (FDA summary)")
    out.append("! Regulatory type")
    out.append("! Trial(s) cited on FDA page")
 
    for i, e in enumerate(entries, start=1):
        # Fetch the FDA notification page and extract trial names
        try:
            page_html = fetch(e["url"])
        except Exception:
            page_html = ""
 
        page_text = BeautifulSoup(page_html, "html.parser").get_text("\n", strip=True) if page_html else ""
        trials = extract_trials_from_page(page_text)
 
        reg_type = infer_regulatory_type(e["title"])
 
        # From index description, try to extract drug/company/brand
        brand, company = extract_company_and_brand(e["desc"])
        drug = extract_drug_from_desc(e["desc"])
 
        # Medication display
        med_display = drug if drug else e["title"].replace("FDA approves ", "").replace("FDA grants ", "").replace("FDA approves", "").strip()
        if brand:
            med_display = f"{med_display} ({brand})"
 
        # Indication text
        indication = extract_indication(e["desc"]) if e["desc"] else e["title"]
 
        # Trials: link each trial name to the FDA page (same URL)
        if trials:
            trial_cell = ", ".join([f"[{e['url']} {t}]" for t in trials])
        else:
            trial_cell = f"[{e['url']} (see FDA page)]"
 
        out.append("|-")
        out.append(f"| {i}")
        out.append(f"| {e['date_str']}")
        out.append(f"| [{e['url']} {med_display}]")
        out.append(f"| {company if company else ''}")
        out.append(f"| {indication}")
        out.append(f"| {reg_type}")
        out.append(f"| {trial_cell}")
 
    out.append("|}")
    return "\n".join(out)
 
def main():
    index_html = fetch(FDA_INDEX)
    entries = parse_index_2025(index_html)
 
    # FDA said “54 approvals in 2025” — if this isn’t 54, you’ll immediately know and can debug.
    print(f"Found {len(entries)} FDA oncology/hematology approval notifications for 2025.", file=sys.stderr)
 
    wikicode = to_wikitable(entries)
    print(wikicode)
 
if __name__ == "__main__":
    main()

Revision as of 21:50, 31 December 2025

# Approval date Medication (Brand) Company Indication Regulatory type
12/17/2025 | Amivantamab + hyaluronidase-lpuj (Rybrevant Faspro) | Janssen Biotech, Inc. | Subcutaneous injection across all approved amivantamab indications | Traditional
12/17/2025 | Rucaparib (Rubraca) | pharmaand GmbH | BRCA-mutated mCRPC after androgen receptor therapy | Traditional
12/15/2025 | Fam-trastuzumab deruxtecan-nxki + pertuzumab (Enhertu + Perjeta) | Daiichi Sankyo | 1L unresectable/metastatic HER2+ breast cancer | Traditional
12/12/2025 | Niraparib + abiraterone acetate + prednisone (Akeega) | Janssen Biotech | BRCA2-mutated mCSPC | Traditional
12/04/2025 | Lisocabtagene maraleucel (Breyanzi) | Juno / BMS | R/R marginal zone lymphoma ≥2 lines | Traditional
12/03/2025 | Pirtobrutinib (Jaypirca) | Eli Lilly | R/R CLL/SLL after BTK inhibitor | Traditional
11/25/2025 | Durvalumab (Imfinzi) | AstraZeneca | Resectable gastric/GEJ adenocarcinoma | Traditional
11/21/2025 | Pembrolizumab + enfortumab vedotin (Keytruda + Padcev) | Merck / Astellas | Cisplatin-ineligible MIBC | Traditional
11/19/2025 | Tarlatamab-dlle (Imdelltra) | Amgen | ES-SCLC after platinum | Traditional
11/19/2025 | Sevabertinib (Hyrnuo) | Bayer | HER2-mutated NSCLC | Accelerated
11/19/2025 | Daratumumab + hyaluronidase-fihj (Darzalex Faspro) | Janssen | Newly diagnosed AL amyloidosis | Traditional
11/19/2025 | Selumetinib (KOSELUGO) | AstraZeneca | Adult NF1 plexiform neurofibromas | Traditional
11/18/2025 | Epcoritamab-bysp (Epkinly) | Genmab | Relapsed/refractory follicular lymphoma | Traditional
11/13/2025 | Pertuzumab-dpzb (Poherdy) | Henlius | Interchangeable biosimilar to Perjeta | Traditional
11/13/2025 | Ziftomenib (Komzifti) | Kura Oncology | R/R NPM1-mutated AML | Traditional
11/06/2025 | Daratumumab + hyaluronidase-fihj | Janssen | High-risk smoldering multiple myeloma | Traditional
10/24/2025 | Revumenib (Revuforj) | Syndax | R/R NPM1-mutated AML | Traditional
10/23/2025 | Belantamab mafodotin-blmf (Blenrep) | GSK | R/R multiple myeloma ≥2 lines | Traditional
10/08/2025 | Cemiplimab-rwlc (Libtayo) | Regeneron | Adjuvant CSCC | Traditional
10/02/2025 | Lurbinectedin + atezolizumab | Jazz / Genentech | ES-SCLC maintenance | Traditional
09/25/2025 | Imlunestrant (Inluriyo) | Eli Lilly | ESR1-mutated ER+ MBC | Traditional
09/19/2025 | Pembrolizumab SC (Keytruda Qlex) | Merck | Solid tumors (SC formulation) | Traditional
09/10/2025 | Selumetinib (KOSELUGO) | AstraZeneca | Pediatric NF1 PN | Traditional
09/09/2025 | Gemcitabine intravesical system (Inlexzo) | Janssen | BCG-unresponsive NMIBC | Traditional
08/08/2025 | Zongertinib (Hernexeos) | Boehringer Ingelheim | HER2-mutated NSCLC | Accelerated
08/06/2025 | Dordaviprone (Modeyso) | Jazz | Diffuse midline glioma | Accelerated
07/02/2025 | Sunvozertinib (Zegfrovy) | Dizal | EGFR exon 20 NSCLC | Accelerated
07/02/2025 | Linvoseltamab-gcpt (Lynozyfic) | Regeneron | R/R multiple myeloma | Accelerated
06/23/2025 | Datopotamab deruxtecan-dlnk (Datroway) | Daiichi Sankyo | EGFR-mutated NSCLC | Accelerated
06/18/2025 | Tafasitamab-cxix (Monjuvi) | Incyte | R/R follicular lymphoma | Traditional
06/12/2025 | Pembrolizumab (Keytruda) | Merck | Resectable HNSCC | Traditional
06/12/2025 | Mitomycin intravesical solution (Zusduri) | UroGen | LG-IR NMIBC | Traditional
06/11/2025 | Taletrectinib (Ibtrozi) | Nuvation Bio | ROS1+ NSCLC | Traditional
06/03/2025 | Darolutamide (Nubeqa) | Bayer | mCSPC | Traditional
05/15/2025 | Retifanlimab-dlwr (Zynyz) | Incyte | Anal squamous cell carcinoma | Traditional
05/14/2025 | Telisotuzumab vedotin-tllv (Emrelis) | AbbVie | c-MET high NSCLC | Accelerated
05/14/2025 | Belzutifan (Welireg) | Merck | PPGL | Traditional
05/08/2025 | Avutometinib + defactinib | Verastem | KRAS-mutated LGSOC | Accelerated
04/23/2025 | Penpulimab-kcqx | Akeso | Nasopharyngeal carcinoma | Traditional
04/11/2025 | Nivolumab + ipilimumab | BMS | HCC | Traditional
04/08/2025 | Nivolumab + ipilimumab | BMS | MSI-H/dMMR CRC | Traditional
03/28/2025 | Durvalumab | AstraZeneca | MIBC | Traditional
03/28/2025 | Lutetium Lu-177 vipivotide tetraxetan (Pluvicto) | Novartis | PSMA+ mCRPC | Traditional
03/26/2025 | Cabozantinib (Cabometyx) | Exelixis | pNET / epNET | Traditional
03/19/2025 | Pembrolizumab + trastuzumab | Merck | HER2+ gastric cancer | Traditional
02/14/2025 | Vimseltinib (Romvimza) | Deciphera | TGCT | Traditional
02/12/2025 | Brentuximab vedotin + lenalidomide + rituximab | Seagen | R/R LBCL | Traditional
02/11/2025 | Mirdametinib (Gomekli) | SpringWorks | NF1 plexiform neurofibromas | Traditional
02/06/2025 | Treosulfan + fludarabine | medac | AML/MDS HSCT conditioning | Traditional
01/27/2025 | Fam-trastuzumab deruxtecan-nxki (Enhertu) | Daiichi Sankyo | HR+ HER2-low breast cancer | Traditional
01/17/2025 | Datopotamab deruxtecan-dlnk (Datroway) | Daiichi Sankyo | HR+ HER2- breast cancer | Traditional
01/16/2025 | Sotorasib + panitumumab | Amgen | KRAS G12C mCRC | Traditional
01/16/2025 | Acalabrutinib + bendamustine + rituximab | AstraZeneca | Untreated mantle cell lymphoma | Traditional