Skip to main content

A context manager for temporary Python virtual environments with extensive configuration options.

Project description

temp_venv

A context manager that creates a temporary Python virtual environment, optionally installs specified packages, and activates it for the duration of the with block.

Installation

You can install temp-venv from PyPI using pip:

pip install temp-venv

Temporary Virtual Environment Context Manager (TempVenv)

This repository provides a Python context manager, TempVenv, that simplifies the creation and management of temporary Python virtual environments. It's useful for scenarios where you need to run scripts or commands in an isolated environment with specific dependencies, without manually creating and cleaning up virtual environments.

Features

  • Creates a temporary virtual environment.
  • Optionally installs a list of specified packages (e.g., requests, numpy==1.20.0) into the environment.
  • Provides the path to the Python executable within the temporary environment.
  • Automatically cleans up the virtual environment (deletes the temporary directory) upon exiting the with block by default.
  • Offers options for verbose logging, custom Python executables, pip and venv flags, and installation via requirements files.

API Reference

Class TempVenv

Constructs a TempVenv object.

  • packages: Optional[List[str]] = None: A list of packages to install (e.g., ["requests", "numpy==1.23.5"]). Defaults to None.
  • python_executable: Optional[str] = None: Specifies the full path to a Python executable to be used for creating the virtual environment. If None, the script will attempt to find a suitable Python executable (e.g., sys.executable, python3, python). Defaults to None.
  • cleanup: bool = True: If True, the temporary directory containing the virtual environment is automatically deleted when the context manager exits. If False, the directory is left behind (you may need to clean it up manually). Defaults to True.
  • pip_options: Optional[List[str]] = None: A list of additional options to pass to pip install (e.g., ["--no-cache-dir"]). Defaults to None.
  • venv_options: Optional[List[str]] = None: A list of additional options to pass to the venv creation command (e.g., ["--copies"]). Defaults to None.
  • requirements_file: Optional[str] = None: Path to a requirements.txt file from which to install packages. Defaults to None.
  • verbose: bool = False: If True, enables verbose output, printing commands executed and their results to stdout/stderr. Useful for debugging. Defaults to False.

Prerequisites

  • Python 3.9+
  • uv

Usage

The primary component is the TempVenv class located in temp_venv.py.

from temp_venv import TempVenv
import subprocess
import sys
import os # Needed for Example 3 file operations

# Example 1: Create a temporary venv and install specific packages with verbose output
print("Example 1: Using TempVenv with 'requests', 'numpy==1.23.5', 'multiext', and verbose=True")
try:
    with TempVenv(packages=["requests", "numpy==1.23.5", "multiext"], verbose=True) as venv_python:
        print(f"  Inside TempVenv: Python executable is {venv_python}")

        print("  Running script to check requests version (verbose output from TempVenv should be visible above)...")
        script_requests = "import requests; print(f'  Requests version: {requests.__version__}')"
        subprocess.run([venv_python, "-c", script_requests], check=True, text=True)

        print("  Running script to check numpy version...")
        script_numpy = "import numpy; print(f'  Numpy version: {numpy.__version__}')"
        subprocess.run([venv_python, "-c", script_numpy], check=True, text=True)

        print("  Running script to check multiext version...")
        script_multiext = "import multiext; print(f'  multiext version: {multiext.__version__}')"
        subprocess.run([venv_python, "-c", script_multiext], check=True, text=True)

    print("  TempVenv context exited. Environment has been cleaned up.")

except RuntimeError as e:
    print(f"Error during Example 1: {e}")
except Exception as e:
    print(f"An unexpected error occurred during Example 1: {e}")

print("\n" + "="*50 + "\n")

# Example 2: Create a temporary venv with cleanup=False
print("Example 2: Using TempVenv with no additional packages and cleanup=False")
temp_dir_path_for_example2 = None
try:
    # The TempVenv instance itself is the context manager, here assigned to 'venv_context'
    with TempVenv(cleanup=False, verbose=True) as venv_python: # venv_python is the path to the executable
        print(f"  Inside TempVenv: Python executable is {venv_python}")
        # To get the temp_dir_path, you'd typically access it from the TempVenv object if it stores it,
        # or know it from verbose logs. For this example, we'll just note it should persist.
        # temp_dir_path_for_example2 = venv_context.temp_dir_path_str # If TempVenv instance was captured and exposed it
        # The verbose output from TempVenv will show the temporary directory path.
        print(f"  The temporary directory (shown in verbose logs above) should NOT be cleaned up automatically.")
        subprocess.run([venv_python, "-c", "print('  Hello from the temporary venv that will persist!')"], check=True, text=True)
    print("  TempVenv context exited. Environment should NOT have been cleaned up.")
    print("  Manual cleanup would be needed for the directory mentioned in the verbose logs if this were a real scenario.")
    # In a real script, if you captured the TempVenv instance:
    # if temp_dir_path_for_example2 and os.path.exists(temp_dir_path_for_example2):
    #     print(f"  Manually cleaning up {temp_dir_path_for_example2} now for the sake of example completion.")
    #     shutil.rmtree(temp_dir_path_for_example2)


except RuntimeError as e:
    print(f"Error during Example 2: {e}")
    # Add shutil import if manual cleanup is actually implemented in example
    # import shutil
except Exception as e:
    print(f"An unexpected error occurred during Example 2: {e}")

print("\n" + "="*50 + "\n")

# Example 3: Using the venv's Python to run an external script
print("Example 3: Running an external script with TempVenv")
# Create a dummy external script
external_script_content = """
import sys
import six # This will be installed by TempVenv

print(f"Hello from external_script.py running with {sys.executable}")
print(f"Six version: {six.__version__}")
"""
external_script_name = "my_script_requiring_packages.py"
with open(external_script_name, "w") as f:
    f.write(external_script_content)

try:
    with TempVenv(packages=["six==1.15.0"]) as venv_python_executable:
        print(f"  Inside TempVenv: Python executable is {venv_python_executable}")
        print(f"  Running '{external_script_name}' which requires 'six==1.15.0'")
        subprocess.run([venv_python_executable, external_script_name], check=True, text=True)
    print(f"  TempVenv context exited. '{external_script_name}' and venv are cleaned up (script is not part of venv).")

except RuntimeError as e:
    print(f"Error during Example 3: {e}")
except Exception as e: # Catch broader exceptions for script file operations
    print(f"An unexpected error occurred during Example 3: {e}")
finally:
    # Clean up the dummy script
    if os.path.exists(external_script_name):
        os.remove(external_script_name)
        print(f"  Cleaned up '{external_script_name}'.")

print("\n" + "="*50 + "\n")

# Example 4: Using a requirements file, pip_options and venv_options
print("Example 4: Using TempVenv with a requirements.txt, pip_options, and verbose output")
requirements_content = """
pyjokes # For a bit of fun
requests==2.25.0
# A comment to ensure parsing works
tinydb>=3.0,<5.0
"""
requirements_filename = "temp_requirements_example.txt"
with open(requirements_filename, "w") as f:
    f.write(requirements_content)

try:
    with TempVenv(
        requirements_file=requirements_filename,
        packages=["six"], # Also add 'six' from packages list
        pip_options=["--no-cache-dir"],
        venv_options=["--copies"], # Use --copies instead of --system-site-packages for easier testing
        verbose=True,
        cleanup=True
    ) as venv_python:
        print(f"  Inside TempVenv: Python executable is {venv_python}")
        script_to_run = """
import pyjokes, requests, six, tinydb
print(f'    pyjokes version: {pyjokes.__version__}')
print(f'    requests version: {requests.__version__}')
print(f'    six version: {six.__version__}')
print(f'    tinydb version: {tinydb.__version__}')
"""
        subprocess.run([venv_python, "-c", script_to_run], check=True, text=True)
    print(f"  TempVenv context exited. '{requirements_filename}' was used and venv cleaned up.")
except RuntimeError as e:
    print(f"Error during Example 4: {e}")
finally:
    if os.path.exists(requirements_filename):
        os.remove(requirements_filename)
        print(f"  Cleaned up '{requirements_filename}'.")

print("\nScript finished.")

Running Tests

Unit tests are located in test_temp_venv.py. You can run them using:

python -m unittest test_temp_venv.py

Alternatively, use python -m unittest discover -s . -p "test_temp_venv.py" for discovery, which is what the GitHub Actions workflow uses.

This will execute a series of tests to ensure the TempVenv class functions correctly, including environment creation, package installation (specific versions, multiple packages), isolation, cleanup, and handling of various options like requirements_file, verbose, pip_options, etc.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

temp_venv-0.2.1.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

temp_venv-0.2.1-py3-none-any.whl (20.5 kB view details)

Uploaded Python 3

File details

Details for the file temp_venv-0.2.1.tar.gz.

File metadata

  • Download URL: temp_venv-0.2.1.tar.gz
  • Upload date:
  • Size: 24.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for temp_venv-0.2.1.tar.gz
Algorithm Hash digest
SHA256 c227daec3e79117b15069765bb6d44f2c82181f8949d355cc73b08bf1e71d0d9
MD5 d1013d439cbebcabfd81bdd9377c353e
BLAKE2b-256 1f0f375d00d2c1785952fe6b7b33d7ca7c542ac4670fa09e731df613251e8123

See more details on using hashes here.

File details

Details for the file temp_venv-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: temp_venv-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 20.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for temp_venv-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d18700cdbda6b4fd11fb24f85ad1d2438c5399bf48101f106357b51387460536
MD5 460f2eb502797f0c48640c3e60244bfa
BLAKE2b-256 28b3dd3bd413a117745107e0998d3eaff8a97892070ebd609c8059ada693fd79

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page