问题
I'm running multiple installs of Python on Windows Server 2012. I can probably find a way to work around this, but I'm curious as to what is going on. I'm wary about radically changing the installs in case I break other people's Python scheduled tasks that I may not be aware of.
(All the code boxes below are PowerShell).
PS C:\> C:\Python34\Scripts\pip.exe list
jdcal (1.0)
pip (7.1.2)
setuptools (12.0.5)
virtualenv (13.1.2)
Although this Python 3.4 install doesn't have Django installed, it appears to pick up the version from the Python 33x86 install. Is that normal?
PS C:\> C:\Python34\python.exe -c "import django; print(django.get_version())"
1.6.5
PS C:\> C:\Python33x86\python.exe -c "import django; print(django.get_version())"
1.6.5
I've created a Python virtualenv based on Python 3.4 and installed Django 1.8.4 in it. Doing a "pip list" confirms that it is installed correctly:-
PS C:\> D:\PyVirtualEnvs\example_py34\Scripts\activate.bat
PS C:\> D:\PyVirtualEnvs\example_py34\Scripts\pip.exe list | Select-String "Django "
Django (1.8.4)
However, when I import within that virtualenv, I get Django version 1.6.5:-
PS C:\> D:\PyVirtualEnvs\example_py34\Scripts\python.exe -c "import django; print(django.get_version())"
1.6.5
Is this a bug in virtualenv or am I missing something?
EDIT: Could it be related to this question?
EDIT2: The same thing happens when using pyvenv, as suggested by ham-sandwich.
回答1:
The only thing that looks strange to me is that you are running
D:\PyVirtualEnvs\example_py34\Scripts\activate.bat
in powershell when a there is a activate.ps1. I don't know if there are compatibility issues with this.
回答2:
If you run a cmd.exe
shell script from PowerShell (a batch file), PowerShell spawns an instance of cmd.exe
to run the script (batch file). If the batch file sets environment variables, they exist only in the spawned cmd.exe
instance. Once that instance terminates (i.e., when the script ends), the environment variables do not propagate to the calling process (PowerShell, in this case). This is by design.
If you want to propagate environment variables, you can use the following Invoke-CmdScript
function in PowerShell:
function Invoke-CmdScript {
param(
[String] $scriptName
)
$cmdLine = """$scriptName"" $args & set"
& $Env:SystemRoot\system32\cmd.exe /c $cmdLine |
Select-String '^([^=]*)=(.*)$' | ForEach-Object {
$varName = $_.Matches[0].Groups[1].Value
$varValue = $_.Matches[0].Groups[2].Value
Set-Item Env:$varName $varValue
}
}
Some more information about this in the following article:
Windows IT Pro: Take Charge of Environment Variables in PowerShell
In your case, you would run:
PS C:\> Invoke-CmdScript D:\PyVirtualEnvs\example_py34\Scripts\activate.bat
This will spawn activate.bat
and propagate the environment variable changes.
回答3:
I've discovered the reason for this behaviour. The PYTHONPATH environment variable was set to a Python installation at an unusual location on the machine.
According to the documentation, PYTHONPATH is used as the import location when the module is not found in the current directory.
When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:
- the directory containing the input script (or the current directory).
- PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
- the installation-dependent default.
For some reason PYTHONPATH is not set/unset by the activate/deactivate scripts. It does set PYTHONHOME, but this doesn't seem to affect imports. This feels like a bug in virtualenv and pyvenv (I tried both).
The original activate.bat scripts change a "set" variable, which doesn't affect the $env:PYTHONPATH. Activate.ps1 attempts to save the original PYTHONPATH in a variable, set it to the virtual environment directory, then on deactivate, restore the original PYTHONPATH. Neither of these work anymore, possibly due to a Powershell or Python update.
The solution for us is to modify the activate and deactivate scripts (PoSh or bat) to switch the PYTHONPATH between two hard-coded values.
来源:https://stackoverflow.com/questions/32519580/module-being-imported-from-another-python-install