Yes, but not with the usual open-source tools yet. On a real Python 3.15.0 .pyc (magic number 3666), pycdc says Bad MAGIC! and uncompyle6/decompyle3 say Unknown magic number 3666. Python's own marshal + dis still read every string and the full logic, but only when you run them on 3.15: on 3.14, dis crashed. Our free .pyc Decompiler already rebuilds 3.15 source: my test file came back complete, and on six real standard-library modules every function came back, with about 7 in 10 code objects verified exact.
Python 3.15.0 is out, and with every new release comes the same question: can its .pyc files be turned back into source yet? On 24 October 2026 I compiled a test file and took real standard-library modules from the official 3.15.0 build on python.org, then ran every common method against them. Here's exactly what happened.
The test files
API_KEY = "sk-demo-7c1f2a"def check(user, key):if key == "PRO-2026":return f"welcome {user}"return "access denied"print(check("mithun", "PRO-2026"))
I compiled it with 3.15.0's py_compile. The file starts with 52 0e 0d 0a, magic number 3666, which identifies Python 3.15 (3.14 is 3627; the full table is in fix "bad magic number"). For real-world code I also used six modules from 3.15's own standard library (fnmatch, base64, textwrap, json.decoder, functools and difflib), which the official Windows download ships as 3.15 .pyc files.
The open-source decompilers: not yet
$ pycdc s315.pycBad MAGIC!Could not load file s315.pyc$ uncompyle6 s315.pyc# Unknown magic number 3666 in s315.pyc$ decompyle3 s315.pycUnknown magic number 3666 in s315.pyc
No surprise: pycdc's newest commit is from April 2026, and uncompyle6 and decompyle3 stopped at Python 3.8 and 3.9 years ago. The .pyc isn't damaged or protected; these tools simply don't know version 3666. Support for a new CPython release always arrives late, because every new opcode has to be mapped by hand. For how pycdc behaves on the versions it does support, see the tested pycdc guide.
The standard library still reads it, on 3.15
A .pyc is a 16-byte header plus a marshal-serialized code object, so Python's own marshal and dis modules can read it with no decompiler at all:
import marshal, diswith open("s315.pyc", "rb") as f:f.read(16) # 16-byte headercode = marshal.load(f)def strings(c):for k in c.co_consts:if isinstance(k, str):yield kelif hasattr(k, "co_consts"):yield from strings(k)print(list(strings(code)))check = next(k for k in code.co_consts if hasattr(k, "co_code"))for ins in dis.get_instructions(check):if ins.opname in ("LOAD_CONST", "COMPARE_OP", "RETURN_VALUE", "POP_JUMP_IF_FALSE"):print(f"{ins.opname:18} {ins.argrepr}")
['sk-demo-7c1f2a', 'PRO-2026', 'welcome ', 'access denied', 'mithun', 'PRO-2026']LOAD_CONST 'PRO-2026'COMPARE_OP bool(==)POP_JUMP_IF_FALSE to L1LOAD_CONST 'welcome 'RETURN_VALUELOAD_CONST 'access denied'RETURN_VALUE
Every string, the license check and both branches, with no decompiler installed.
Use the matching Python version. I ran the same script on Python 3.14: marshal.load still read the 3.15 file and the strings printed, but dis then crashed with IndexError: list index out of range (inside get_argval_argrepr), because 3.15 renumbered some opcodes. Read a 3.15 .pyc with Python 3.15.
Our decompiler on 3.15
Our free .pyc Decompiler detects 3.15 from the magic number and runs its deeper reconstruction pass, which rebuilds each function and checks it by recompiling it and comparing the bytecode. The test file came back complete, both branches included, with every function verified:
# Decompiled with https://pyobfuscate.devAPI_KEY = 'sk-demo-7c1f2a'def check(user, key):if key == 'PRO-2026':return f'welcome {user}'else:return 'access denied'print(check('mithun', 'PRO-2026'))
Real modules are harder. Here's what came back for the six standard-library files (a code object is a function, class body, lambda or comprehension):
| 3.15 module | .pyc size | Code objects verified exact | Time |
|---|---|---|---|
| fnmatch | 6.6 KB | 8 of 11 (73%) | 42 s |
| base64 | 15 KB | 20 of 27 (74%) | 74 s |
| textwrap | 12 KB | 12 of 18 (67%) | 89 s |
| json.decoder | 11 KB | 8 of 13 (62%) | 66 s |
| functools | 42 KB | 78 of 92 (85%) | 3.2 min |
| difflib | 45 KB | 42 of 58 (72%) | 3.4 min |
Every module came back with all its function definitions; the unverified parts are best-effort reconstructions, and the page marks the result as partial when that happens. For comparison I compiled the same source files with 3.14 and 3.15: fnmatch, textwrap and json.decoder verified 90%, 94% and 100% on 3.14, against 73%, 67% and 69% on 3.15. So 3.15 works today, but support is newer: expect a few more partial functions for now.
What this means if you ship 3.15 code
"No decompiler supports my version yet" isn't protection: the strings and logic came straight out with two standard-library calls, and a full decompiler already rebuilds most of it. The usual advice holds:
- Obfuscate the source before you compile or ship it. I ran 10 test programs through our Python Obfuscator (both modes, 3 seeds each) and executed all 90 outputs on Python 3.15.0: every one printed exactly the same output as the original. Code that uses syntax new in 3.15, such as
lazy import(PEP 810), is supported too (tested 24 October 2026); in the protected output those imports load at startup instead of lazily, and the program behaves the same. - Keep real secrets off the client. A hard-coded key sits in
co_constsin plain text on every version; load it from the environment or a backend (protecting API keys in Python). - For the strongest bar, compile to a native module (Cython or Nuitka), so there is no code object to
marshal.loadat all. See PyArmor vs Nuitka vs Cython for what each one hides.
Decompile a 3.15 .pyc — free
Our free .pyc Decompiler rebuilds source for Python 2.x through 3.15, with the version detected for you.
Open the .pyc DecompilerFree tools mentioned here
Related guides
Frequently asked questions
Can pycdc decompile Python 3.15?
Not yet. In October 2026, pycdc's current master (commit b428976 from April 2026) rejected a Python 3.15.0 .pyc with 'Bad MAGIC!' because it doesn't know the 3.15 magic number (3666) or its opcodes. uncompyle6 and decompyle3 report 'Unknown magic number 3666'.
What is the Python 3.15 .pyc magic number?
3666. The first four bytes of a Python 3.15 .pyc are 52 0e 0d 0a (3.14 is 3627, bytes 2b 0e 0d 0a). Read the first two bytes as a little-endian integer to identify the version.
How do I decompile a Python 3.15 .pyc file?
Use a decompiler that supports 3.15, such as our free online .pyc Decompiler: in testing it recovered every function of six real 3.15 standard-library modules, with about 7 in 10 code objects verified exact. Without a decompiler, run marshal + dis on Python 3.15 to read the strings and bytecode.
Why does dis crash on a Python 3.15 .pyc?
Because you're running dis from a different Python version. On Python 3.14, marshal.load read a 3.15 .pyc, but dis crashed with 'IndexError: list index out of range' since 3.15 renumbered some opcodes. Run the disassembly with Python 3.15.
Does obfuscated Python code run on Python 3.15?
Ours does: 90 obfuscated test programs (10 programs, both modes, 3 seeds) all produced identical output on Python 3.15.0. Source that uses new 3.15-only syntax such as lazy import (PEP 810) is supported as well; those imports simply load at startup in the protected output.