[Django]-Find out Python version from source code (or Heroku)

4👍

Depending on what you need. Either (a) the version you are running on or (b) the version under the .pyc file was compiled?

a. If you need to know the python version you are running, do the following:

>>> import sys
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=3, releaselevel='final', serial=0)
>>> print sys.version_info.major
2
>>> print sys.version_info.minor
7
>>> print sys.version_info.micro
3
>>> print '%s.%s.%s' % (sys.version_info.major, sys.version_info.minor, sys.version_info.micro)
2.7.3

b. If you want to know the python version under a .pyc file was compiled, do the following:

>>> f = open('somefile.pyc')
>>> magic = f.read(4)
>>> magic
'\x03\xf3\r\n'
>>> magic.encode('hex')
'03f30d0a'
>>> import struct
>>> struct.unpack("<HH", magic)
(62211, 2573)
>>> struct.unpack("<HH", magic)[0]
62211

The known values are listed in the python source file Python/import.c. Here the known values from Python 2.7.10rc1:

   Python 1.5:   20121
   Python 1.5.1: 20121
   Python 1.5.2: 20121
   Python 1.6:   50428
   Python 2.0:   50823
   Python 2.0.1: 50823
   Python 2.1:   60202
   Python 2.1.1: 60202
   Python 2.1.2: 60202
   Python 2.2:   60717
   Python 2.3a0: 62011
   Python 2.3a0: 62021
   Python 2.3a0: 62011 (!)
   Python 2.4a0: 62041
   Python 2.4a3: 62051
   Python 2.4b1: 62061
   Python 2.5a0: 62071
   Python 2.5a0: 62081 (ast-branch)
   Python 2.5a0: 62091 (with)
   Python 2.5a0: 62092 (changed WITH_CLEANUP opcode)
   Python 2.5b3: 62101 (fix wrong code: for x, in ...)
   Python 2.5b3: 62111 (fix wrong code: x += yield)
   Python 2.5c1: 62121 (fix wrong lnotab with for loops and
                        storing constants that should have been removed)
   Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp)
   Python 2.6a0: 62151 (peephole optimizations and STORE_MAP opcode)
   Python 2.6a1: 62161 (WITH_CLEANUP optimization)
   Python 2.7a0: 62171 (optimize list comprehensions/change LIST_APPEND)
   Python 2.7a0: 62181 (optimize conditional branches:
            introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE)
   Python 2.7a0  62191 (introduce SETUP_WITH)
   Python 2.7a0  62201 (introduce BUILD_SET)
   Python 2.7a0  62211 (introduce MAP_ADD and SET_ADD)

To solve your problem, you could recursively walk your directory and extract the values from every .pyc file and populate a dictionary with a list of files for every value/version. See following example:

import os, struct

your_path = '/your/path' # <- enter your path here
values = {}

for root, dirs, files in os.walk(your_path):
    for file in files:
        if file.endswith('.pyc'):
            full_path = os.path.join(root, file)
            value = struct.unpack("<HH", open(full_path).read(4))[0] # <- evtl. enclose this in a try block
            if not values.has_key(value):
                values[value] = []
            values[value].append(full_path)
            print '%s %s' % (value, full_path)

for value, files in values.items():
    print 'Following files have value %s' % (value)
    for file in files:
        print '    %s' % (file)

If you are under Linux, you could solve your problem with the following one line commando (thanks to Neftas suggestion!):

dir=/your/path; find ${dir} -name "*.pyc" | while read file; do head -c 2 ${file} | od -d | head -n 1 | awk -v z=${file} -F ' ' '{print $2 "\t" z}'; done

This outputs a list with value and filename like the following:

62211   /usr/lib/pymodules/python2.7/reportbug/ui/urwid_ui.pyc
62211   /usr/lib/pymodules/python2.7/reportbug/debbugs.pyc
62211   /usr/lib/pymodules/python2.7/reportbug/checkbuildd.pyc
...
62161   /usr/lib/pymodules/python2.6/debianbts.pyc
62161   /usr/lib/pymodules/python2.6/fpconst.pyc
62161   /usr/lib/pymodules/python2.6/SOAPpy/Server.pyc
...

4👍

Seems like the least complex answer (for Heroku) is missing:

Log into Heroku bash session, something like this in your authenticated terminal:

heroku run bash --app YOURAPPNAME

then type:

python --version

done

👤Marc

1👍

You want to know what runtime is used to run your code on Heroku. At the time of writing this, new applications default to the Python 2.7.9 runtime. This may have been modified in the ‘runtime.txt’ file so to find out if it has been set:

$ cat runtime.txt
python-3.4.2

0👍

If you didn’t have access to source code, from headers I can see that server is using Gunicorn 0.17.2, which is compatible with Python 2.x >= 2.6, which rules out i.e. Python 3.

Leave a comment