airspeed-velocity / asv

Airspeed Velocity: A simple Python benchmarking tool with web-based reporting
https://asv.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
870 stars 180 forks source link

Support venv on python>=3.3 #523

Open anntzer opened 7 years ago

anntzer commented 7 years ago

I know that the docs state a dependency on

virtualenv, 1.10 or later (this is true even with Python 3.3, where virtualenv is included as venv, since venv is not compatible with other versions of Python).

but would it be possible to just replace

import virtualenv

by

try: import venv as virtualenv
except ImportError: import virtualenv

everywhere, so that virtualenv becomes unneeded on Python>=3.3?

(Basically, I don't know if the two have APIs compatible enough for asv.)

pv commented 7 years ago

Want to try if it works? Patches are welcome in principle. All relevant code is in asv/plugins/virtualenv.py

anntzer commented 7 years ago

Ah, I think that won't work because you want to be able to use the current python to create virtualenvs for other pythons, which venv doesn't support.

pv commented 7 years ago

I think that's probably not so crucial, it would probably also be fine to shell out to a subprocess for the env creation.

pv commented 6 years ago

The workaround to the nested virtualenv/venv case apparently requires finding the "real" Python executable: from https://github.com/berdario/pew/blob/c25f19e9bb0bc94f696407378fc104706b5dd3b5/pew/_venv.py#L68-L104

def find_real_python():
    # We need to run venv on the Python we want to use. sys.executable is not
    # enough because it might come from a venv itself. venv can be easily
    # confused if it is nested inside another venv.
    # https://bugs.python.org/issue30811
    python = ('python.exe' if windows else 'python')

    # If we're in a venv, excellent! The config file has this information.
    pyvenv_cfg = pathlib.Path(sys.prefix, 'pyvenv.cfg')
    if pyvenv_cfg.exists():
        return Cfg(pyvenv_cfg).bindir.joinpath(python)

    # Or we can try looking this up from the build configuration. This is
    # usually good enough, unless we're in a virtualenv (i.e. sys.real_prefix
    # is set), and sysconfig reports the wrong Python (i.e. in the virtualenv).
    import sysconfig
    bindir = sysconfig.get_config_var('BINDIR')
    try:
        real_prefix = sys.real_prefix
    except AttributeError:
        return pathlib.Path(bindir, python)
    if not os.path.realpath(bindir).startswith(real_prefix):
        return pathlib.Path(bindir, python)

    # OK, so we're in a virtualenv, and sysconfig lied. At this point there's
    # no definitive way to tell where the real Python is, so let's make an
    # educated guess. This works if the user isn't using a very exotic build.
    for rel in ['', os.path.relpath(str(bindir), real_prefix), env_bin_dir]:
        try:
            path = pathlib.Path(real_prefix, rel, python).resolve()
        except FileNotFoundError:
            continue
        if path.exists():   # On 3.6+ resolve() doesn't check for existence.
            return path

    # We've tried everything. Sorry.
    raise BrokenEnvironmentError