Ideally, setup.py is for generic minimum-version-known-to-work dependencies of a package. Pip requirements files are for very specific known-good combinations of dependencies of an application. https://caremad.io/blog/setup-vs-requirement/
It's an anti-pattern to not pin versions in libs. setup.py is a contract. Every version listed as a dependency should have been tested, otherwise the package will bitrot. It should be safe to pin major versions, if you can trust upstream packages to follow best practices with version numbers and you aren't using any "undocumented" features of the lib. Ideally, your packages are tested and built into binary packages before they are deployed to production systems. If you are following that best practice, then your risk of a patch breaking your system are minimized.