This article is the 19th day article of ZOZO Technologies # 3 Advent Calendar 2020. Yesterday's article was PAC4J: Security library for Play framework and Scala by @BrunoB.
TL;DR
--Confirmed the behavior that Python version is switched when .python-version
exists in the same hierarchy as the file path passed in the Python command line argument.
--Resolved by deleting .python-version
in the same hierarchy as the file path or setting the environment variable PYENV_VERSION
The first time I felt strange about the behavior was when ModuleNotFoundError
was output when executing the python hoge.py -a ./fuga/piyo.txt
command.
I had confirmed that the library was installed with the pip list
command, so I didn't understand why the above command output an error.
A closer look reveals that the version of Python specified by the pyenv local
command is not running, the system default Python is running, and the system default Python does not have the above library installed, so ModuleNotFoundError
Was occurring.
Apparently, the .python-version
in the same hierarchy as the ./fuga/piyo.txt
passed as a command line argument was read, and the version of Python to be executed was switched.
Reproduce the behavior of the problem with the following environment, code, and commands.
Use an instance of AWS EC2.
The contents of the code print_version.py
to be executed this time are as follows. It prints the executed Python version with print (sys.version)
regardless of the contents of the argument arg1
.
The argument arg1
is not used in the main
function, but its existence is the key to this time.
print_version.py
import argparse
import sys
def main(arg1):
print(sys.version)
return()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--arg1")
args = parser.parse_args()
main(args.arg1)
And the directory structure is as follows.
There are two directories in the same hierarchy as print_version.py
, and their contents are the same except for the presence or absence of .python-version
.
By the way, .python-version
is a hidden file created in the directory where the pyenv local
command is executed, so as will be described later, use the pyenv local 3.7.6
command in the pyenv-test
directory and with You are running the
pyenv local system command in the -pv
directory.
pyenv-test
├── .python-version
├── print_version.py
├── with-pv
│ ├── .python-version
│ └── a.txt
└── without-pv
└── a.txt
pyenv-test/.python-version
3.7.6
pyenv-test/with-pv/.python-version
system
a.txt
abcd
First, execute the following command and post the output result.
[ec2-user@******** pyenv-test]$ cd with-pv/
[ec2-user@******** with-pv]$ pyenv local system
[ec2-user@******** with-pv]$ python -V
Python 2.7.18
[ec2-user@******** with-pv]$ cd ../
[ec2-user@******** pyenv-test]$ pyenv local 3.7.6
[ec2-user@******** pyenv-test]$ python -V
Python 3.7.6
Continue to execute the following command and post the output result.
Again, print_version.py
is just code that prints the version of Python that was executed.
[ec2-user@******** pyenv-test]$ python print_version.py -a ./without-pv/a.txt
3.7.6 (default, Dec 8 2020, 06:20:44)
[GCC 7.3.1 20180712 (Red Hat 7.3.1-9)]
[ec2-user@******** pyenv-test]$ python print_version.py -a ./with-pv/a.txt
2.7.18 (default, Aug 27 2020, 21:22:52)
[GCC 7.3.1 20180712 (Red Hat 7.3.1-9)]
You should have passed a file with the same contents as an argument to print_version.py
, but ** the versions of Python executed are different. ** **
Those who passed ./with-pv/a.txt
as command line arguments ran Python 2.7.18, which should not have been specified in pyenv.
The difference between the two commands is that the version of Python described in .python-version
has priority and is executed depending on whether .python-version
exists in the same hierarchy as the file path passed as a command line argument. It is believed that it has been done.
By the way, I tried the same thing with Click because it may be due to the behavior of argparse, but the result was the same.
There are the following two methods.
PYENV_VERSION
When pyenv decides which version of Python to run, the environment variable PYENV_VERSION
has the highest priority (reference: pyenv's home repository).
You can set the environment variable by executing the export PYENV_VERSION = 3.7.6
command or by executing the pyenv shell 3.7.6
command, and the following is executed.
python
[ec2-user@******** pyenv-test]$ pyenv shell 3.7.6
[ec2-user@******** pyenv-test]$ python print_version.py -a ./without-pv/a.txt
3.7.6 (default, Dec 8 2020, 06:20:44)
[GCC 7.3.1 20180712 (Red Hat 7.3.1-9)]
[ec2-user@******** pyenv-test]$ python print_version.py -a ./with-pv/a.txt
3.7.6 (default, Dec 8 2020, 06:20:44)
[GCC 7.3.1 20180712 (Red Hat 7.3.1-9)]
.python-version
As confirmed in the Command section, if the argument does not have .python-version
in the same hierarchy as the file, it will be executed with the Python version specified by the pyenv local
command.
According to pyenv's home repository, .python-version
, which exists in the same hierarchy as the file specified by the command line argument, is expected to have no effect on the Python version being executed.
However, it did not behave as expected, so it seems necessary to understand the specifications in more detail.
This article summarizes what I was addicted to when using pyenv.
At the time of ModuleNotFoundError
, I was completely unaware that the Python version was switched, and for a long time I suspected that the pyenv installation failed, and it took a long time to resolve.
Furthermore, although this article omits the case where there are two or more command line arguments, the code I was writing at that time had four command line arguments. This is also one of the personnel who took a long time to resolve, but I managed to identify the cause.
Tomorrow will be an article by @ Horie1024. look forward to tomorrow too!
Recommended Posts