The server might have the wrong Python version available (2.x vs 3.x, multiple evolutions of 3.x with big features added in each point release). Et cetera, et cetera.
Or you could just do it with bash or a static Go binary and be done with it. Portable, works pretty much everywhere.
That's the point of using virtual environments, so that you can run the Python version and libraries that you need. Also, as of 3.3, Python ships with venv which means you don't need to separately install virtualenv anymore. It's all very portable.
It really isn't as portable as one might wish.
Not all operating systems carry Python >3.3 by default, that would mean installing backports or unofficial repositories on production machines.
Or you can use a static binary that just works.
Imagine a situation where you'd need to perform an operation on a hundred servers, would you either transfer one static exacutable or build an virtualenv in every machine and download correct versions all of the related libraries?
I had heard that the Python packaging and deployment story had got a lot better in recent years, but this sounds like it still falls far short of table stakes.
We're finally getting around to migrating away, and we've settled on Twitter's github.com/pantsbuild/pants which is like Google's Bazel except that it's jankier in every way _except_ that Pants supports Python while Bazel doesn't (Bazel advertises Python support, but it doesn't work as the many Python 3 issues in their issue tracker can attest). The nicest thing about Pants is that it builds pex files (github.com/pantsbuild/pex) which are executable zip files that ship all of your dependencies except the Python interpreter and shared objects.
I'm still not very satisfied with this solution, and it's still far, far worse than Go's dependency management and packaging model, but it's a dramatic improvement over Pipenv, virtualenv, etc (gives us both reproducibility and performance).
The point is that the static binary created by go is a single file that you copy into place and run. It is a lot simpler.
See this repo: https://github.com/unixtreme/D3Edit. It has Linux/Mac/Windows virtualenvs and it works without any additional setup
Basically build a virtualenv and then pack that into a .deb, install the .deb on the target machine and you have a self-contained package that requires no external resources to install.
That said, using golang is WAAAAY simpler. The virtualenv/deb solution, while it works, is very sketch.
People are now irrationally scared of using dynamic libraries, OS packages and even directories, like virtualenvs.
Instead, a simple solution is replaced with containers, or by rewriting tons of code in the new hyped language.
Are we trying to create job security through unnecessary complexity?
As a python/go dev, I can assure you that go is not much more complex. And as a server admin, it's much easier to deploy.
It does have drawbacks when compared to python, but it can often be the optimal solution.