lifelines needs Python 3.11 or later, and its Makefile skips its own format check
Survival analysis in Python
At a glance
- What is it?
- A pure Python survival analysis library whose README is 229 words long and contains no install command. The packaging metadata pins an open floor at 3.11, takes its dependency list from a text file read line by line, and the Makefile guards its formatting targets on Python versions the package no longer supports. `make test` covers the library directory and nothing else.
- Who is it for?
- Fits a project that measures time to an event and has not lined up its data yet. Censoring, hazard ratios, proportional hazards and splines, all pure Python, all with a paper trail behind them, and a documentation site that stands well clear of the README.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 7 months ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 6, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The README has no install command anywhere in it
The README is 229 words and does not contain a single installation line. What it has is three badges pointing at PyPI, conda-forge and a Zenodo DOI, a paragraph on why survival analysis exists, four bullets of applications outside medicine, one link to the documentation, and a contact section.
Those four bullets are the interesting part. SaaS providers measuring subscriber lifetimes or the time to a first action. Inventory stockout described as a censoring event for true demand. Sociologists measuring the lifetimes of political parties, relationships or marriages. And A/B tests to find out how long each group takes to perform an action. So the pitch is aimed well outside the actuarial and medical community the discipline came from, and the package is described as a pure Python implementation of the best parts of survival analysis.
What is missing is the one line a newcomer needs. The badges say the package exists on PyPI and conda-forge. Nothing on the page says which Python versions it takes.
python_requires is an open floor and the classifiers stop at 3.14
Two version declarations sit in the packaging script and they are shaped differently. The install constraint is a single string, `PYTHON_REQ = ">=3.11"`, so any future interpreter is admitted. The classifier list names four: Python 3.11, 3.12, 3.13 and 3.14, alongside Python :: 3 :: Only and a Development Status of 4 - Beta.
So the floor is enforced and the ceiling is not. Someone on 3.15 would pass the requirement and find no classifier asserting the package was ever tested against their interpreter. The Beta status alongside a 0.30 series version is at least internally consistent.
The description string is narrower than the package. It claims Kaplan Meier, Nelson Aalen and regression specifically, while the prose claims the best parts of survival analysis generally. Package data is declared as `datasets/*` inside the package, which is where bundled example data such as `colon.csv` is expected to live.
install_requires is a text file read line by line
The dependency list is not written into the setup call. It is read out of a file while the build runs:
exec(compile(open("lifelines/version.py").read(), "lifelines/version.py", "exec"))
with open("reqs/base-requirements.txt") as f:
REQUIREMENTS = f.read().splitlines()Three things follow from those lines. The version number is not a literal in the packaging script at all; it is whatever `lifelines/version.py` assigns, obtained by compiling and executing that file. The requirements are every line of a plain text file split on newlines with no filtering, so a comment or a blank line in it becomes an entry in install_requires. And the long description is the README read straight from the repository root, marked as text/markdown.
Data shipping is declared twice over. `package_data` covers `datasets/*` inside the package while `include_package_data=False` switches off the manifest mechanism, and a MANIFEST.in sits in the tree regardless.
Both format targets are gated on Python versions setup.py dropped
The Makefile has six targets and two are guarded by conditions that can no longer be true. Formatting looks like this:
check_format:
ifeq ($(TRAVIS_PYTHON_VERSION), 3.6)
black . --check --line-length 120
else
echo "Only check format on Python3.6"
endifThe check runs only when TRAVIS_PYTHON_VERSION is exactly 3.6, which is below the 3.11 floor declared in the packaging script, so on any supported interpreter the target prints a message and does nothing. The lint and black targets carry the mirror-image guard, skipping when that same variable is 2.7 and otherwise running `black lifelines/ -l 120 --fast` followed by `prospector --output-format grouped`.
The detection is an environment variable rather than a question about whether a CI system is present. The init target branches on `ifeq ($(TRAVIS), true)`, and its first branch pins pandas and numpy to values passed in as PANDAS_VERSION and NUMPY_VERSION.
make test walks one directory and measures coverage on that one
The test target is a single line, and the directory it names is the package itself:
py.test lifelines/ -rfs --cov=lifelines --block=False --cov-report term-missingCoverage is scoped to the same path, so the numbers a run prints describe the library and nothing beside it. That leaves the root `conftest.py` outside the path pytest is pointed at, along with the `perf_tests/`, `experiments/` and `examples/` directories that also sit at the top level. Whether those are reached by a separate invocation is not something the Makefile says.
There is no packaging target in the file at all: no sdist, no wheel, no build, and no docs target, even though the tree carries a `docs/` directory, a `.readthedocs.yaml` and a `mypy.ini`. Alongside those sit a `.coveragerc`, a `.prospector.yaml` and a `.pre-commit-config.yaml`, and the last of those has its own entry point, `pre-commit run --all-files`.
Ten notebooks and nine scripts, two of them on the same churn question
The examples directory holds ten Jupyter notebooks and nine Python scripts, plus a `colon.csv` and its own README. The notebooks cover B-splines, Cox residuals, custom regression models, customer churn, modelling time-lagged conversion rates, piecewise exponential models, the proportional hazard assumption, SaaS churn with piecewise regression, a mixture of exponentials with interval censoring, and United States presidential cabinet survival.
Two of those ten ask the churn question twice, once as Customer Churn and once as SaaS churn and piecewise regression models. That is the use case the application list leads with, so the duplication is not a distraction, but it does mean two notebooks open on the same data question.
The nine scripts sit beside the notebooks rather than inside them, named things like left_censoring_experiments, cure_model, haft_model, mixture_cure_model and royston_parmar_splines. Five of the nine are about one parametric family each, so the directory is really two collections, notebooks meant for reading and scripts meant for running, tied together by nothing beyond an examples README.
The last push is 2026-03-07 and the newest release is two days earlier
Three releases are published across two months: v0.30.1 on 2026-02-04, v0.30.2 on 2026-03-04 and v0.30.3 on 2026-03-05, the last two one day apart at almost the same time of day. The master branch was last pushed on 2026-03-07, two days after the newest tag, and the repository is not archived.
Since that date the front page has not changed. The README is the same 229 words, and the contact section still routes questions three ways: a GitHub Discussions room, a Stack Exchange search for the `lifelines` tag on stats.stackexchange.com, and the issue tracker. Sending library questions to the site where statistics questions are actually asked is a better default than a mailing list that does not exist.
For citing the work there is a Zenodo DOI badge at the top and a CITATION.cff in the tree, and a `paper/` directory beside them. None of the three is mentioned in the prose, and neither is .readthedocs.yaml.
Editorial conclusion
Fits a project that measures time to an event and has not lined up its data yet. Censoring, hazard ratios, proportional hazards and splines, all pure Python, all with a paper trail behind them, and a documentation site that stands well clear of the README. Three things to settle before you commit. The README gives no install command, so budget a minute finding the version floor and the dependency file yourself rather than assuming the badges tell you. The single test target covers the `lifelines/` directory only, so do not read its coverage figure as a statement about the repository. And master was last pushed on 2026-03-07, with v0.30.3 the newest release from two days before that, so pin the version whose documentation you are reading instead of tracking the branch.
Frequently asked questions
how to install lifelines
The README gives no install line, but the packaging metadata does: Python 3.11 or later is required, install_requires is read from reqs/base-requirements.txt, and the badges show the package published on both PyPI and conda-forge. The version number itself comes from lifelines/version.py rather than from a literal in setup.py.
how to install lifelines in jupyter notebook
The package installs the same way it does anywhere, from Python 3.11 up. What makes the notebook case easy is the examples directory, which already ships ten Jupyter notebooks, among them B-splines, Cox residuals, Customer Churn, the proportional hazard assumption and United States presidential cabinet survival, along with a colon.csv dataset.
What does the lifelines package cover?
It is described as a pure Python implementation of the best parts of survival analysis. The setup.py description is narrower, naming Kaplan Meier, Nelson Aalen and regression specifically. The tutorials and API reference live at lifelines.readthedocs.org rather than in the repository README.
Which Python versions does lifelines support?
The packaging script sets python_requires to 3.11 or later and the classifiers name 3.11, 3.12, 3.13 and 3.14, together with Python 3 only and a Beta development status. The requirement is an open floor, so a newer interpreter is admitted without any classifier claiming it was tested.
Where should I ask a question about lifelines?
The page gives three routes: a GitHub Discussions room, a Stack Exchange search for the lifelines tag on stats.stackexchange.com, and the issue tracker. For citing the library there is a Zenodo DOI badge at the top of the README and a CITATION.cff in the repository root.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/camdavidsonpilon-lifelines)