EMS & clinical drug dosing calculator library with CLI
Project description
๐ drugdose
EMS & Clinical Drug Dosing Calculator โ weight-based doses, IV drip rates, contraindication checking, and drug interaction screening, all in one Python library.
โ ๏ธ Medical Disclaimer
drugdoseis a clinical decision-support tool intended for use by licensed healthcare professionals. It does not replace professional clinical judgment, institutional protocols, or current drug references (e.g. Lexicomp, Micromedex). Always verify doses independently before administration. The authors assume no liability for patient outcomes.
Features
- Weight-based dose calculation โ
mg/kg,mcg/kg, flat doses, across all common administration routes - Pediatric dose caps โ separate adult and pediatric maximum single-dose limits
- IV drip rate calculator โ any rate unit (
mcg/kg/min,mg/hr,g/hr, etc.) โ mL/hr pump rate and bag duration - Allergy checker โ direct, brand-name, cross-reactivity, and drug-class allergy matching
- Contraindication flags โ conditions, age/weight restrictions, pregnancy categories D & X, renal/hepatic caution
- Drugโdrug interaction screener โ 39 curated rules with severity (major/moderate/minor), clinical description, and management guidance
- 49-drug bundled database โ EMS, cardiac, anesthesia, ICU, antibiotics, toxicology, obstetrics, and more
- Rich CLI โ interactive terminal interface with colour-coded safety output
- Pure Python, zero heavy dependencies โ only
richandclick
Installation
pip install drugdose
Requires Python 3.10+.
Quick Start
Python API
from drugdose import Patient, calculate_dose, calculate_drip
# โโ Build a patient โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
patient = Patient(
weight_kg=70,
age_years=35,
allergies=["codeine"],
current_medications=["midazolam"],
conditions=["hypertension"],
renal_impairment=False,
)
# โโ Calculate a single dose โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
result = calculate_dose("fentanyl", patient, route="IV")
print(result.summary())
# โ Fentanyl Citrate IV: 200.00 mcg โ 4.00 mL
print(f"Dose: {result.dose_display:.1f} mcg")
print(f"Volume: {result.volume_ml:.2f} mL")
print(f"Freq: {result.frequency}")
# Safety flags
if result.contraindications:
for ci in result.contraindications:
print(f"[{'ABSOLUTE' if ci.absolute else 'relative'}] {ci.detail}")
if result.interactions:
for ix in result.interactions:
print(f"[{ix.severity.upper()}] {ix.drug_a} โบ {ix.drug_b}: {ix.description}")
IV Drip Rate
from drugdose import Patient, calculate_drip, standard_mixture
patient = Patient(weight_kg=80)
# Calculate pump rate
drip = calculate_drip(
"dopamine",
patient,
ordered_dose=5.0,
dose_unit="mcg/kg/min",
bag_volume_ml=250.0,
)
print(drip.summary())
# โ Dopamine drip @ 5 mcg/kg/min: 15.00 mL/hr (bag lasts 16.7 hr)
print(f"Rate: {drip.rate_ml_per_hr:.2f} mL/hr")
print(f"Delivers: {drip.dose_mg_per_min * 60:.2f} mg/hr")
print(f"Duration: {drip.duration_hr:.1f} hr")
# Build a custom mixture concentration
conc = standard_mixture("norepinephrine", total_drug_mg=4.0, bag_volume_ml=250.0)
print(f"Bag conc: {conc:.4f} mg/mL") # โ 0.0160 mg/mL
Dose Range (min โ max)
from drugdose import Patient, calculate_range
patient = Patient(weight_kg=25, age_years=7)
min_r, max_r = calculate_range("ketamine", patient, route="IV")
print(f"Min dose: {min_r.dose_display:.1f} mg ({min_r.volume_ml:.2f} mL)")
print(f"Max dose: {max_r.dose_display:.1f} mg ({max_r.volume_ml:.2f} mL)")
Safety Check Only
from drugdose import get_drug, Patient, full_safety_check
drug = get_drug("amiodarone")
patient = Patient(
weight_kg=70,
age_years=68,
allergies=["iodine"],
current_medications=["digoxin", "metoprolol"],
)
ci_flags, ix_flags = full_safety_check(drug, patient)
for ci in ci_flags:
severity = "ABSOLUTE" if ci.absolute else "relative"
print(f"[{severity}] [{ci.category}] {ci.detail}")
for ix in ix_flags:
print(f"[{ix.severity.upper()}] {ix.drug_a} + {ix.drug_b}")
print(f" {ix.description}")
print(f" Management: {ix.management}")
Drug Search & Lookup
from drugdose import get_drug, search_drugs, get_all_drugs
# Lookup by name or brand name
drug = get_drug("Narcan") # returns naloxone Drug object
drug = get_drug("epi") # partial match โ epinephrine
# Search with query and/or tag
cardiac_drugs = search_drugs("", tag="cardiac")
opioid_results = search_drugs("opioid")
# Full database
all_drugs = get_all_drugs() # dict[str, Drug]
print(f"{len(all_drugs)} drugs in database")
CLI Reference
Install via pip then run drugdose:
Usage: drugdose [OPTIONS] COMMAND [ARGS]...
๐ drugdose โ Clinical Dosing
Commands:
calculate Calculate a weight-based drug dose
check Run a full safety check for a drug and patient
drip Calculate IV drip / infusion pump rate
info Show detailed information about a drug
list List all drugs in the database
search Search the drug database by name, indication, or tag
version Show version and library info
Every command accepts --help / -h for full option details.
Examples
# Interactive dose calculator (prompts for patient info)
drugdose calculate epinephrine --route IV --weight 70
# Specify everything inline
drugdose calculate fentanyl -r IM -w 25 --age 8 --allergies penicillin
# Show the full min-to-max dose range
drugdose calculate ketamine --range -w 70 --age 30
# IV drip rate
drugdose drip dopamine -w 70 -d 5 -u mcg/kg/min
# Calculate a custom mixture concentration
drugdose drip epinephrine --mix --total-mg 4 -b 250
# Full drug info panel
drugdose info ketamine
drugdose info "Narcan"
# Safety check with patient context
drugdose check amiodarone --meds "digoxin,metoprolol" --age 72 -w 80
drugdose check morphine --allergies codeine --conditions "respiratory depression"
# Search and list
drugdose search opioid
drugdose search --tag cardiac
drugdose list --tag emergency
drugdose list --class benzodiazepine
Drug Database
49 drugs bundled across clinical categories:
| Category | Drugs |
|---|---|
| Emergency / EMS | Epinephrine, Adenosine, Atropine, Naloxone, Dextrose, Tranexamic Acid, Glucagon, Activated Charcoal |
| Cardiac | Amiodarone, Lidocaine, Adenosine, Metoprolol, Diltiazem, Digoxin, Nitroglycerin, Magnesium Sulfate |
| Vasopressors / Inotropes | Norepinephrine, Dopamine, Dobutamine, Vasopressin, Phenylephrine, Epinephrine (drip) |
| Anesthesia / Sedation | Ketamine, Propofol, Etomidate, Midazolam, Lorazepam, Diazepam |
| Neuromuscular Blockers | Succinylcholine, Rocuronium |
| Opioid Analgesics | Morphine, Fentanyl |
| Non-Opioid Analgesics | Ketorolac, Acetaminophen |
| Respiratory | Albuterol, Ipratropium, Methylprednisolone, Dexamethasone |
| Antibiotics | Vancomycin, Ceftriaxone, Piperacillin-Tazobactam |
| Anticoagulants / Thrombolytics | Heparin, Alteplase (tPA) |
| Metabolic / Electrolytes | Insulin Regular, Sodium Bicarbonate, Calcium Gluconate, Furosemide |
| Other | Ondansetron, Diphenhydramine, Haloperidol, Labetalol |
All drugs include: multiple routes, dose ranges (mg/kg or mcg/kg), standard concentrations, adult and pediatric dose caps, frequency, onset/duration, contraindications, cross-reactivity lists, and clinical notes.
Adding Custom Drugs
Extend the bundled database by editing src/drugdose/data/drugs.json, or load your own at runtime:
import json
from drugdose.models.drug import Drug
from drugdose import calculate_dose, Patient
# Load a custom drug dict
with open("my_formulary.json") as f:
entries = json.load(f)
custom_drug = Drug.from_dict(entries[0])
# Pass it directly to the checker or calculator internals
from drugdose.calculator import calculate_dose as _calc
from drugdose.db import get_all_drugs
# Or monkey-patch the cache for the session:
db = get_all_drugs()
db["my_drug"] = custom_drug
A plugin/formulary override system is planned for v0.2.0.
API Reference
Patient(weight_kg, age_years, sex, allergies, current_medications, conditions, is_pregnant, renal_impairment, hepatic_impairment, height_cm)
| Property | Type | Description |
|---|---|---|
is_pediatric |
bool |
Age < 18 years |
is_neonate |
bool |
Age < 28 days |
is_infant |
bool |
Age 28 days โ 1 year |
ibw_kg |
float | None |
Ideal body weight (Devine formula) |
bmi |
float | None |
Body mass index |
age_months |
float | None |
Age expressed in months |
calculate_dose(drug_name, patient, route, concentration_mg_ml, dose_fraction) โ DoseResult
| Parameter | Default | Description |
|---|---|---|
drug_name |
required | Generic name, brand name, or partial name |
patient |
required | Patient object |
route |
"IV" |
Route string: IV, IM, IN, SQ, ETT, PR, SL, INH, IV_DRIP |
concentration_mg_ml |
None |
Override stock concentration. Uses database default when None. |
dose_fraction |
1.0 |
0.0 = minimum dose, 1.0 = maximum dose |
calculate_range(drug_name, patient, route, concentration_mg_ml) โ (DoseResult, DoseResult)
Returns (min_result, max_result).
calculate_drip(drug_name, patient, ordered_dose, dose_unit, concentration_mg_ml, bag_volume_ml) โ DripResult
Supported dose_unit values: mcg/kg/min, mcg/kg/hr, mg/kg/min, mg/kg/hr, mcg/min, mcg/hr, mg/min, mg/hr, g/hr, units/min, units/hr.
standard_mixture(drug_name, total_drug_mg, bag_volume_ml) โ float
Returns concentration in mg/mL.
full_safety_check(drug, patient, route) โ (list[ContraindicationFlag], list[InteractionFlag])
search_drugs(query, tag) โ list[Drug]
get_drug(name) โ Drug | None
Matches by generic name, display name, brand names, and partial substring.
Exceptions
| Exception | Raised when |
|---|---|
DrugNotFoundError |
Drug name not in database |
InvalidRouteError |
Route not available for the drug |
InvalidPatientError |
Weight/age outside physiologic range |
ContraindicatedError |
Absolute contraindication triggered (if you raise it yourself) |
WeightError |
Weight is zero or negative |
ConcentrationError |
No concentration provided and none in database |
All inherit from DrugDoseError.
Development
# Clone and install in editable mode
git clone https://github.com/londonchowdhury/drugdose.git
cd drugdose
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run tests with coverage
pytest tests/ --cov=drugdose --cov-report=term-missing
Project Structure
drugdose/
โโโ pyproject.toml # Package config & dependencies
โโโ README.md
โโโ CHANGELOG.md
โโโ .gitignore
โโโ src/
โ โโโ drugdose/
โ โโโ __init__.py # Public API re-exports
โ โโโ calculator.py # calculate_dose(), calculate_range()
โ โโโ drip.py # calculate_drip(), standard_mixture()
โ โโโ checker.py # Contraindication & interaction engine
โ โโโ db.py # Drug database loader & search
โ โโโ exceptions.py # Custom exception hierarchy
โ โโโ cli.py # Rich + Click CLI
โ โโโ models/
โ โ โโโ drug.py # Drug, RouteConfig dataclasses
โ โ โโโ patient.py # Patient dataclass
โ โ โโโ result.py # DoseResult, DripResult, flags
โ โโโ data/
โ โโโ drugs.json # 49-drug database
โ โโโ interactions.json # 39 interaction rules
โโโ tests/
โโโ test_calculator.py # 24 unit tests
Publishing to PyPI
pip install build twine
python -m build
twine check dist/*
twine upload dist/*
Roadmap
- Renal dose-adjustment engine (Cockcroft-Gault, CKD-EPI)
- ACLS/PALS automated protocol sequences
- Broselow tape weight-estimation by age/length
- Pharmacokinetic simulation (Cp vs. time)
- PDF/JSON export for dose calculations
- REST API via
drugdose serve - Plugin / custom formulary system
- Expanded database: oncology, psychiatry, neonatal specific
- Web UI
Contributing
Contributions are welcome โ especially:
- New drugs or routes โ open a PR editing
drugs.json - Interaction rules โ open a PR editing
interactions.json - Bug reports โ open an issue with patient parameters and expected vs. actual output
- Protocol corrections โ cite your source (AHA guidelines, package insert, etc.)
Please include a citation for any dose ranges added or modified.
License
MIT ยฉ 2026 London Chowdhury. See LICENSE for full text.
Acknowledgements
Dose ranges sourced from and cross-referenced against:
- American Heart Association (AHA) ACLS/PALS Guidelines 2020
- Pediatric Advanced Life Support (PALS) Provider Manual
- Micromedex / Lexicomp drug references
- Surviving Sepsis Campaign Guidelines 2021
- Individual FDA-approved package inserts
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file drugdose-0.1.0.tar.gz.
File metadata
- Download URL: drugdose-0.1.0.tar.gz
- Upload date:
- Size: 53.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd8737e1a9b46a4f2174889f13004f97c736d23f643b2f587e195fb9a35bc12b
|
|
| MD5 |
59d844ac7ba0fd6c53453516d1aaf77d
|
|
| BLAKE2b-256 |
313ceda691660d29b92c319c3828b6cc46d9e08c1fdf1f41788106015c9b9993
|
File details
Details for the file drugdose-0.1.0-py3-none-any.whl.
File metadata
- Download URL: drugdose-0.1.0-py3-none-any.whl
- Upload date:
- Size: 50.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a13793aea5d806f9fe3a4f3e884cb341ab207b8ac51ca22d53308ee0d0e11060
|
|
| MD5 |
26296e2c90a566c153253d689747b0f5
|
|
| BLAKE2b-256 |
ff215b5df3468031fbd7773bcfc6d6e16bf00101a88102913924493a77629606
|