Is there a way to know by which Python version the .pyc file was compiled?

Question:

Is there any way to know by which Python version the .pyc file was compiled?

Asked By: Aamir Rind

||

Answers:

The first two bytes of the .pyc file are the magic number that tells the version of the bytecodes. The word is stored in little-endian format, and the known values are:

Python version Decimal Hexadecimal Comment
Python 1.5 20121 0x994e
Python 1.5.1 20121 0x994e
Python 1.5.2 20121 0x994e
Python 1.6 50428 0x4cc4
Python 2.0 50823 0x87c6
Python 2.0.1 50823 0x87c6
Python 2.1 60202 0x2aeb
Python 2.1.1 60202 0x2aeb
Python 2.1.2 60202 0x2aeb
Python 2.2 60717 0x2ded
Python 2.3a0 62011 0x3bf2
Python 2.3a0 62021 0x45f2
Python 2.3a0 62011 0x3bf2 !
Python 2.4a0 62041 0x59f2
Python 2.4a3 62051 0x63f2
Python 2.4b1 62061 0x6df2
Python 2.5a0 62071 0x77f2
Python 2.5a0 62081 0x81f2 ast-branch
Python 2.5a0 62091 0x8bf2 with
Python 2.5a0 62092 0x8cf2 changed WITH_CLEANUP opcode
Python 2.5b3 62101 0x95f2 fix wrong code: for x, in ...
Python 2.5b3 62111 0x9ff2 fix wrong code: x += yield
Python 2.5c1 62121 0xa9f2 fix wrong lnotab with for loops and storing constants that should have been removed
Python 2.5c2 62131 0xb3f2 fix wrong code: for x, in ... in listcomp/genexp
Python 2.6a0 62151 0xc7f2 peephole optimizations and STORE_MAP opcode
Python 2.6a1 62161 0xd1f2 WITH_CLEANUP optimization
Python 2.7a0 62171 0xdbf2 optimize list comprehensions/change LIST_APPEND
Python 2.7a0 62181 0xe5f2 optimize conditional branches: introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE
Python 2.7a0 62191 0xeff2 introduce SETUP_WITH
Python 2.7a0 62201 0xf9f2 introduce BUILD_SET
Python 2.7a0 62211 0x03f3 introduce MAP_ADD and SET_ADD
Python 3000 3000 0xb80b
3010 0xc20b removed UNARY_CONVERT
3020 0xcc0b added BUILD_SET
3030 0xd60b added keyword-only parameters
3040 0xe00b added signature annotations
3050 0xea0b print becomes a function
3060 0xf40b PEP 3115 metaclass syntax
3061 0xf50b string literals become unicode
3071 0xff0b PEP 3109 raise changes
3081 0x090c PEP 3137 make __file__ and __name__ unicode
3091 0x130c kill str8 interning
3101 0x1d0c merge from 2.6a0, see 62151
3103 0x1f0c __file__ points to source file
Python 3.0a4 3111 0x270c WITH_CLEANUP optimization
Python 3.0a5 3131 0x3b0c lexical exception stacking, including POP_EXCEPT
Python 3.1a0 3141 0x450c optimize list, set and dict comprehensions: change LIST_APPEND and SET_ADD, add MAP_ADD
Python 3.1a0 3151 0x4f0c optimize conditional branches: introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE
Python 3.2a0 3160 0x580c add SETUP_WITH, tag: cpython-32
Python 3.2a1 3170 0x620c add DUP_TOP_TWO, remove DUP_TOPX and ROT_FOUR, tag: cpython-32
Python 3.2a2 3180 0x6c0c add DELETE_DEREF

Sources:

  • Python/import.c – merged by aix from Python 2.7.2 and Python 3.2.2
  • Little endian hex values for comparison first two bytes of Igor Popov’s method added by jimbob
Answered By: NPE

You can get the magic number of your Python as follows:

$ python -V
Python 2.6.2
# python
>>> import imp
>>> imp.get_magic().encode('hex')
'd1f20d0a'

To get the magic number for a pyc file you can do the following:

>>> f = open('test25.pyc')
>>> magic = f.read(4)
>>> magic.encode('hex')
'b3f20d0a'
>>> f = open('test26.pyc')
>>> magic = f.read(4)
>>> magic.encode('hex')
'd1f20d0a'

By comparing the magic numbers you’ll know the python version that generated the pyc file.

Answered By: Igor Popov

Take a look at my script in Python that detects and returns the version of Python by which the file (*.pyc or *.pyo) was compiled.

It detects versions of Python from Python 1.5 up to last Python 3 build.

Answered By: Delimitry

Or, if you have a GNU/Linux system you can use the command “file” in a terminal:

$ file code.pyc
> code.pyc: python 3.5.2 byte-compiled
Answered By: Tom

The official Python github repository no longer appears to keep the list in import.c.

When searching for a more current list than I could find elsewhere, I encountered what appears to be an up-to-date list from Google as of May 2017.

https://github.com/google/pytype/blob/master/pytype/pyc/magic.py

Answered By: Ubuntourist

Adding to @Igor Popov’s answer.

To check the version of the compiled script from a newer version of Python:

# written in python3

filename = "outfit.cpython-39.pyc"

with open(filename,'rb') as f:
    magic = f.read(4)

print(int.from_bytes(magic[:2], 'little'))

You can lookup the output number here:
https://github.com/google/pytype/blob/master/pytype/pyc/magic.py

Answered By: khan
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.