Generic Python Virtual Environment
, automation | python
I have worked on a deployment solution for Python applications utilizing Python virtual environment and wanted a generic way to manage and generate the virtual environment on a build server.

Locally the setup of the virtual environment is performed by the following command:
New-item -Name .venv -ItemType Directory -Force
pipenv install
The above works as expected locally, but the virtual environment cannot be moved to another server as absolute paths are present in the .venv/Scripts folder. This is an issue if you want to reuse an already build virtual environment and you do not want to rebuild the virtual environment on each deployment.

In order to generate a generic virtual environment I created a small Python script called 'create_generic_pipenv.py' which updates the absolute paths in the .venv/Script folder of the virtual environment.
import glob, os

# the purpose of this script is to convert a pipenv virtual environment paths from absolute to relative paths in scripts/exe files of the environment
# these changes allows the virtual environment to be build in one place and be relocated to other and still be able to run

env = os.getcwd() + "\\"
os.chdir(".venv/Scripts")

for file in glob.glob("*.exe"):
  with open(file, 'rb+') as f:text = f.read()
    text = text.replace( bytes( env, encoding='ansi'), bytes("",
    encoding='ansi') )
    f.seek(0)
    f.write(text)
    f.truncate()

for file in glob.glob("*[!exe]"):
  if os.path.isfile( file ):
    with open(file, 'r+') as f:
      text = f.read()
      text = text.replace( env, "" )
      f.seek(0)
      f.write(text)
      f.truncate()
The script is called on a Windows server and is using a simple check for binary executables. Update accordingly if you want an improved check or if you are working on Linux distribution.

On the build server the following needs to be called to create the generic virtual environment:
New-item -Name .venv -ItemType Directory -Force
pipenv install
python create_generic_pipenv.py
The newly create .venv virtual environment can be saved as an artifact and be deployed on any server.

If pyvenv.cfg exists in the .venv folder the following is also needed:
# replace home path with deployment server python installation path
$builder_python_home_path = ( ( ( Get-Content -path ".venv/pyvenv.cfg" ) | select-string home ) -split " = " )[1]
$deployment_server_python_home_path = "C:\Program Files\Python310"

$updated_cfg = (Get-Content -path ".venv/pyvenv.cfg").replace("$builder_python_home_path", "$deployment_server_python_home_path" )
$updated_cfg | Set-Content -path ".venv/pyvenv.cfg"
The above ensures that the virtual environment is setup correctly with respect to the deployment server. You may need to change the home path with respect to your deployment server Python installation.