Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Clinical Trial Participant Screening Tool

A Python command-line tool that screens clinical trial participants against a study protocol's inclusion and exclusion criteria, and generates an eligibility report for each one.

This project was built as a first exercise in applying core programming concepts — classes, modules, and separation of concerns — to a realistic, structured problem: automating patient eligibility screening for a clinical trial.

Table of Contents

Background Information

Study Title

A Phase II, Open-Label Study Evaluating the Safety and Efficacy of an Investigational Immunotherapy in Patients with Advanced Non-Small Cell Lung Cancer (NSCLC)

Study Background

Lung cancer remains one of the leading causes of cancer-related mortality worldwide, with non-small cell lung cancer (NSCLC) representing the majority of diagnosed cases. Despite advances in targeted therapies and immune checkpoint inhibitors, many patients with advanced disease eventually develop resistance or experience disease progression, highlighting the need for new therapeutic approaches.

This Phase II clinical trial aims to evaluate the safety, tolerability, and preliminary efficacy of an investigational immunotherapy agent in adult patients with advanced or metastatic NSCLC who have progressed after standard-of-care treatment. The study will assess whether the investigational therapy can provide meaningful clinical benefit, measured through endpoints such as objective response rate (ORR), progression-free survival (PFS), and safety outcomes.

Patient selection is based on predefined eligibility criteria to ensure that enrolled participants represent the intended study population while maintaining patient safety. These criteria include demographic characteristics, cancer diagnosis and stage, previous treatments, biomarker expression, performance status, and adequate organ function.

The development of automated patient screening tools can support clinical research teams by improving the identification of potentially eligible participants, reducing manual screening workload, and accelerating patient recruitment.

Study Design

  • Phase: II
  • Study ID: NSCLC-001
  • Therapeutic area: Oncology
  • Study type: Interventional clinical trial
  • Condition: Advanced Non-Small Cell Lung Cancer (NSCLC)
  • Population: Adult patients with metastatic disease
  • Intervention: Investigational immunotherapy agent
  • Primary objective: Evaluate preliminary efficacy and safety
  • Estimated Enrollment: 120 participants
  • Study duration: 24 months

Inclusion Criteria

Demographics

  • Age >= 18 years
  • Ability to provide informed consent

Disease Characteristics

  • Histologically confirmed diagnosis of NSCLC
  • Stage IV or unresectable locally advanced disease
  • At least one measurable lesion according to RECIST 1.1

Previous Treatment

  • Disease progression after at least one previous systemic therapy
  • Previous treatment with platinum-based chemotherapy required

Biomarker Requirements

  • PD-L1 expression ≥ 50% (tumor proportion score)

Clinical Status

  • ECOG Performance Status 0–1
  • Life expectancy ≥ 12 weeks

Laboratory Requirements

Adequate bone marrow function:

  • Neutrophils ≥ 1,500/mm³
  • Platelets ≥ 100,000/mm³

Adequate liver function:

  • AST/ALT ≤ 2.5 × ULN
  • Total bilirubin ≤ 1.5 mg/dL

Adequate renal function:

  • Creatinine clearance ≥ 50 mL/min

Exclusion Criteria

  • Active autoimmune disease requiring systemic immunosuppressive therapy
  • Untreated or symptomatic brain metastases
  • Previous treatment with the same investigational agent
  • Active uncontrolled infection
  • History of another malignancy within the previous 3 years
  • Pregnancy or breastfeeding

Project Structure

ct-screening-tool/
├── main.py          # Entry point: collects participant data and managed the flow
├── participant.py    # Participant class - stores data for one participant
├── protocol.py        # Study protocol - inclusion/exclusion criteria as constants
├── eligibility.py      # Decision logic - checks a Participant against protocol.py
├── validators.py       # Reusable input validation functions (text, int, float, choice)
├── reports.py          # Formats and prints individual and summary eligibility reports
└── README.md

Each file has a single, well-defined responsibility:

File Responsibility
participant.py Holds data for one participant. No logic.
protocol.py Holds the trial's eligibility criteria as named constants. No logic.
validators.py Repeatedly prompts the user until a valid value is entered. No knowledge of the trial's specific criteria.
eligibility.py Pure decision logic: takes a Participant, compares it against protocol.py, returns whether they're eligible and why (if not).
reports.py Takes the result from eligibility.py and formats it for display. No decision-making.
main.py Orchestrates everything: calls the input functions, then eligibility.py, then reports.py.

How It Works

main.py
  │
  ├── collects participant data (via validators.py)
  │         ↓
  ├── creates a Participant object (participant.py)
  │         ↓
  ├── passes it to eligibility.is_eligible() (eligibility.py)
  │         │
  │         └── compares Participant's attributes against protocol.py's criteria
  │         ↓
  └── passes the result to reports.py, which prints the final report

Because eligibility.py never touches input() or print(), it can be tested independently of the console — for example, feeding it hand-crafted Participant objects and checking the output, without needing to type anything.

Getting Started

Requirements

  • Python 3.8 or later
  • No external dependencies — the project only uses the Python standard library

Installation

git clone https://github.com/tomasgeraldes/Clinical-Trial-Screening-Tool.git
cd ct_screening_tool

Running the tool

python main.py

On startup, you'll see a menu:

1 - Introduce new participant
2 - Load sample participants
3 - Finish and generate reports

Option 2 loads 5 pre-built sample participants (1 eligible, 4 non-eligible for different reasons) — a quick way to see the tool in action without manually entering data.

Usage Example

Loading the sample participants (option 2) produces output like this:

============================================================
ELIGIBILITY REPORT - John Smith (ID: P001)
============================================================
Age: 65 | Gender: M | Stage: IV
Result: ELEGIBLE
============================================================

============================================================
ELIGIBILITY REPORT - Anna Lee (ID: P002)
============================================================
Age: 16 | Gender: F | Stage: IV
Result: NOT ELEGIBLE

Criteria failed:
 - Age below the minimum required (18 years old).
 - PD-L1 expression insufficient (minimum: 50%).
============================================================

============================================================
ELIGIBILITY REPORT - Hudson Brown (ID: P003)
============================================================
Age: 58 | Gender: M | Stage: ULA
Result: NOT ELEGIBLE

Criteria failed:
 - Active autoimmune disease requiring systemic immunosuppression therapy (exclusion criterion)
============================================================

...followed by a final summary of how many participants were eligible overall.

Design Decisions

  • Separation of data, logic, and presentation. participant.py and protocol.py only hold data; eligibility.py only makes decisions; reports.py only formats output. This means, for example, that the eligibility rules can be unit-tested without any console interaction, and the output format can be changed (e.g., to write to a file) without touching the decision logic.
  • Protocol as configuration, not hardcoded logic. All eligibility thresholds live in protocol.py as plain constants. If the trial's criteria change, only that file needs editing — eligibility.py doesn't need to change.
  • A single renal function cutoff, not gender-specific. Reference ranges for creatinine clearance differ by sex and age in the general population, but clinical trial eligibility typically uses a single safety cutoff, since the value entered is generally already derived from a formula that accounts for age, sex, and weight. This was a deliberate choice, not an oversight.
  • Full failure reporting, not fail-fast. check_inclusion() and check_exclusion() collect all failed criteria rather than stopping at the first one, so the final report shows a participant's complete picture — closer to how a real screening report would be used.

Limitations & Future Improvements

  • Command-line only. All interaction happens via the terminal. A natural next step would be a web-based interface (e.g., with Streamlit) built on top of the same eligibility.py and protocol.py, without changing the decision logic.
  • No persistence. Participant data and reports exist only for the duration of a single run; nothing is saved to disk. Exporting reports to CSV or a text file would be a straightforward addition.
  • No automated tests yet. Since eligibility.py is pure logic with no I/O, it's a good candidate for unit tests (e.g., with pytest) — a planned next step.
  • Single-protocol design. The tool currently supports one hardcoded protocol (protocol.py). Supporting multiple trials would require loading protocol definitions dynamically (e.g., from JSON or YAML files) instead of a single Python module.

About

Python command-line interface tool to screen clinical trial participants against protocol eligibility criteria.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages