tl;dr: setup.py specifies dependency version ranges, requirements.txt is a snapshot/lock file for repeatable builds.
That doesn’t really tell me why though…
A friend dug this up when faced with very silly duplication, and was wondering how it happened.
And discovered that it isn’t silly duplication :)
There’s a difference between the very precise dependency information for a particular deployment of a python app encoded in requirements.txt and the more broad “we support version x through y of dependency b” version information in setup.py.