How to find out the magic number for the .pyc header in Python 3












10














Python bytecode (.pyc) files have a header that starts with a magic number that changes between Python versions. How can I (programmatically) find out that number for the current Python version in order to generate a valid header? I'm currently hard-coding the one for Python 3.7.1, but that means I now depend on a specific Python version.



This answer does exactly what I want using py_compile.MAGIC, but that does not seem to exist anymore in Python 3. How can I do the equivalent in Python 3?



Here's an example of what I'm trying to do:



import dis
import marshal

PYC_HEADER = b'x42x0dx0dx0ax00x00x00x00x00x00x00x00x00x00x00x00'

def f():
print('Hello World')

with open('test.pyc', 'wb') as pyc:
pyc.write(PYC_HEADER)
marshal.dump(dis.Bytecode(f).codeobj, pyc)


This should create a file test.pyc, which can then be run, using the same Python interpreter as the script, and should print "Hello World!". And it does, but only when using Python 3.7. I'm looking for a way that generates the header for whichever version of Python 3 is used to run the script, rather than hard-coding 3.7.



For context:



I'm compiling a simple programming language to different bytecode formats (LLVM, Java bytecode, Web Assembly and now Python bytecode) as part of a planned tutorial series on compiler construction.



I can generate the Python bytecode using the byteasm library, which gives me a function as a result. But in order to write the contents to a .pyc file, I need a valid header. By hard-coding the header, the code will only work if the people following the tutorial are running the same version of Python 3 as I am (3.7) or they'd have to manually find out the magic number for their version.










share|improve this question



























    10














    Python bytecode (.pyc) files have a header that starts with a magic number that changes between Python versions. How can I (programmatically) find out that number for the current Python version in order to generate a valid header? I'm currently hard-coding the one for Python 3.7.1, but that means I now depend on a specific Python version.



    This answer does exactly what I want using py_compile.MAGIC, but that does not seem to exist anymore in Python 3. How can I do the equivalent in Python 3?



    Here's an example of what I'm trying to do:



    import dis
    import marshal

    PYC_HEADER = b'x42x0dx0dx0ax00x00x00x00x00x00x00x00x00x00x00x00'

    def f():
    print('Hello World')

    with open('test.pyc', 'wb') as pyc:
    pyc.write(PYC_HEADER)
    marshal.dump(dis.Bytecode(f).codeobj, pyc)


    This should create a file test.pyc, which can then be run, using the same Python interpreter as the script, and should print "Hello World!". And it does, but only when using Python 3.7. I'm looking for a way that generates the header for whichever version of Python 3 is used to run the script, rather than hard-coding 3.7.



    For context:



    I'm compiling a simple programming language to different bytecode formats (LLVM, Java bytecode, Web Assembly and now Python bytecode) as part of a planned tutorial series on compiler construction.



    I can generate the Python bytecode using the byteasm library, which gives me a function as a result. But in order to write the contents to a .pyc file, I need a valid header. By hard-coding the header, the code will only work if the people following the tutorial are running the same version of Python 3 as I am (3.7) or they'd have to manually find out the magic number for their version.










    share|improve this question

























      10












      10








      10


      1





      Python bytecode (.pyc) files have a header that starts with a magic number that changes between Python versions. How can I (programmatically) find out that number for the current Python version in order to generate a valid header? I'm currently hard-coding the one for Python 3.7.1, but that means I now depend on a specific Python version.



      This answer does exactly what I want using py_compile.MAGIC, but that does not seem to exist anymore in Python 3. How can I do the equivalent in Python 3?



      Here's an example of what I'm trying to do:



      import dis
      import marshal

      PYC_HEADER = b'x42x0dx0dx0ax00x00x00x00x00x00x00x00x00x00x00x00'

      def f():
      print('Hello World')

      with open('test.pyc', 'wb') as pyc:
      pyc.write(PYC_HEADER)
      marshal.dump(dis.Bytecode(f).codeobj, pyc)


      This should create a file test.pyc, which can then be run, using the same Python interpreter as the script, and should print "Hello World!". And it does, but only when using Python 3.7. I'm looking for a way that generates the header for whichever version of Python 3 is used to run the script, rather than hard-coding 3.7.



      For context:



      I'm compiling a simple programming language to different bytecode formats (LLVM, Java bytecode, Web Assembly and now Python bytecode) as part of a planned tutorial series on compiler construction.



      I can generate the Python bytecode using the byteasm library, which gives me a function as a result. But in order to write the contents to a .pyc file, I need a valid header. By hard-coding the header, the code will only work if the people following the tutorial are running the same version of Python 3 as I am (3.7) or they'd have to manually find out the magic number for their version.










      share|improve this question













      Python bytecode (.pyc) files have a header that starts with a magic number that changes between Python versions. How can I (programmatically) find out that number for the current Python version in order to generate a valid header? I'm currently hard-coding the one for Python 3.7.1, but that means I now depend on a specific Python version.



      This answer does exactly what I want using py_compile.MAGIC, but that does not seem to exist anymore in Python 3. How can I do the equivalent in Python 3?



      Here's an example of what I'm trying to do:



      import dis
      import marshal

      PYC_HEADER = b'x42x0dx0dx0ax00x00x00x00x00x00x00x00x00x00x00x00'

      def f():
      print('Hello World')

      with open('test.pyc', 'wb') as pyc:
      pyc.write(PYC_HEADER)
      marshal.dump(dis.Bytecode(f).codeobj, pyc)


      This should create a file test.pyc, which can then be run, using the same Python interpreter as the script, and should print "Hello World!". And it does, but only when using Python 3.7. I'm looking for a way that generates the header for whichever version of Python 3 is used to run the script, rather than hard-coding 3.7.



      For context:



      I'm compiling a simple programming language to different bytecode formats (LLVM, Java bytecode, Web Assembly and now Python bytecode) as part of a planned tutorial series on compiler construction.



      I can generate the Python bytecode using the byteasm library, which gives me a function as a result. But in order to write the contents to a .pyc file, I need a valid header. By hard-coding the header, the code will only work if the people following the tutorial are running the same version of Python 3 as I am (3.7) or they'd have to manually find out the magic number for their version.







      python python-3.x pyc






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Dec 18 at 12:53









      sepp2k

      293k38593609




      293k38593609
























          2 Answers
          2






          active

          oldest

          votes


















          8














          As of Python 3.4 there is the importlib.util.MAGIC_NUMBER in the module importlib:



          >>> import importlib
          >>> importlib.util.MAGIC_NUMBER.hex()
          '420d0d0a'


          Another solution for Python < 3.4 or Python2 is the get_magic method of the imp module.



          >>> import imp
          >>> imp.get_magic().hex()
          '420d0d0a'


          Note, that while this still works in Python 3.7, it is deprecated since Python 3.4






          share|improve this answer























          • Thank you, that's exactly what I needed (minus the .hex() since it should go into the file as bytes, not a hexstring).
            – sepp2k
            Dec 18 at 13:13



















          7














          It moved!1



          >>> import importlib.util
          >>> importlib.util.MAGIC_NUMBER
          b'3rrn'


          New in version 3.4.



          Probably simplest to wrap this in a try/except to fall back to py_compile.






          share|improve this answer



















          • 2




            I think you mean "try/except" instead of "try/catch" ;)
            – LMD
            Dec 18 at 18:09






          • 1




            Hah, too much javascript
            – Josh Lee
            Dec 18 at 18:27











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53833455%2fhow-to-find-out-the-magic-number-for-the-pyc-header-in-python-3%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          8














          As of Python 3.4 there is the importlib.util.MAGIC_NUMBER in the module importlib:



          >>> import importlib
          >>> importlib.util.MAGIC_NUMBER.hex()
          '420d0d0a'


          Another solution for Python < 3.4 or Python2 is the get_magic method of the imp module.



          >>> import imp
          >>> imp.get_magic().hex()
          '420d0d0a'


          Note, that while this still works in Python 3.7, it is deprecated since Python 3.4






          share|improve this answer























          • Thank you, that's exactly what I needed (minus the .hex() since it should go into the file as bytes, not a hexstring).
            – sepp2k
            Dec 18 at 13:13
















          8














          As of Python 3.4 there is the importlib.util.MAGIC_NUMBER in the module importlib:



          >>> import importlib
          >>> importlib.util.MAGIC_NUMBER.hex()
          '420d0d0a'


          Another solution for Python < 3.4 or Python2 is the get_magic method of the imp module.



          >>> import imp
          >>> imp.get_magic().hex()
          '420d0d0a'


          Note, that while this still works in Python 3.7, it is deprecated since Python 3.4






          share|improve this answer























          • Thank you, that's exactly what I needed (minus the .hex() since it should go into the file as bytes, not a hexstring).
            – sepp2k
            Dec 18 at 13:13














          8












          8








          8






          As of Python 3.4 there is the importlib.util.MAGIC_NUMBER in the module importlib:



          >>> import importlib
          >>> importlib.util.MAGIC_NUMBER.hex()
          '420d0d0a'


          Another solution for Python < 3.4 or Python2 is the get_magic method of the imp module.



          >>> import imp
          >>> imp.get_magic().hex()
          '420d0d0a'


          Note, that while this still works in Python 3.7, it is deprecated since Python 3.4






          share|improve this answer














          As of Python 3.4 there is the importlib.util.MAGIC_NUMBER in the module importlib:



          >>> import importlib
          >>> importlib.util.MAGIC_NUMBER.hex()
          '420d0d0a'


          Another solution for Python < 3.4 or Python2 is the get_magic method of the imp module.



          >>> import imp
          >>> imp.get_magic().hex()
          '420d0d0a'


          Note, that while this still works in Python 3.7, it is deprecated since Python 3.4







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 18 at 13:12









          Dan D.

          51.8k107999




          51.8k107999










          answered Dec 18 at 13:04









          kalehmann

          2,031317




          2,031317












          • Thank you, that's exactly what I needed (minus the .hex() since it should go into the file as bytes, not a hexstring).
            – sepp2k
            Dec 18 at 13:13


















          • Thank you, that's exactly what I needed (minus the .hex() since it should go into the file as bytes, not a hexstring).
            – sepp2k
            Dec 18 at 13:13
















          Thank you, that's exactly what I needed (minus the .hex() since it should go into the file as bytes, not a hexstring).
          – sepp2k
          Dec 18 at 13:13




          Thank you, that's exactly what I needed (minus the .hex() since it should go into the file as bytes, not a hexstring).
          – sepp2k
          Dec 18 at 13:13













          7














          It moved!1



          >>> import importlib.util
          >>> importlib.util.MAGIC_NUMBER
          b'3rrn'


          New in version 3.4.



          Probably simplest to wrap this in a try/except to fall back to py_compile.






          share|improve this answer



















          • 2




            I think you mean "try/except" instead of "try/catch" ;)
            – LMD
            Dec 18 at 18:09






          • 1




            Hah, too much javascript
            – Josh Lee
            Dec 18 at 18:27
















          7














          It moved!1



          >>> import importlib.util
          >>> importlib.util.MAGIC_NUMBER
          b'3rrn'


          New in version 3.4.



          Probably simplest to wrap this in a try/except to fall back to py_compile.






          share|improve this answer



















          • 2




            I think you mean "try/except" instead of "try/catch" ;)
            – LMD
            Dec 18 at 18:09






          • 1




            Hah, too much javascript
            – Josh Lee
            Dec 18 at 18:27














          7












          7








          7






          It moved!1



          >>> import importlib.util
          >>> importlib.util.MAGIC_NUMBER
          b'3rrn'


          New in version 3.4.



          Probably simplest to wrap this in a try/except to fall back to py_compile.






          share|improve this answer














          It moved!1



          >>> import importlib.util
          >>> importlib.util.MAGIC_NUMBER
          b'3rrn'


          New in version 3.4.



          Probably simplest to wrap this in a try/except to fall back to py_compile.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 18 at 18:27

























          answered Dec 18 at 13:05









          Josh Lee

          117k23210241




          117k23210241








          • 2




            I think you mean "try/except" instead of "try/catch" ;)
            – LMD
            Dec 18 at 18:09






          • 1




            Hah, too much javascript
            – Josh Lee
            Dec 18 at 18:27














          • 2




            I think you mean "try/except" instead of "try/catch" ;)
            – LMD
            Dec 18 at 18:09






          • 1




            Hah, too much javascript
            – Josh Lee
            Dec 18 at 18:27








          2




          2




          I think you mean "try/except" instead of "try/catch" ;)
          – LMD
          Dec 18 at 18:09




          I think you mean "try/except" instead of "try/catch" ;)
          – LMD
          Dec 18 at 18:09




          1




          1




          Hah, too much javascript
          – Josh Lee
          Dec 18 at 18:27




          Hah, too much javascript
          – Josh Lee
          Dec 18 at 18:27


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53833455%2fhow-to-find-out-the-magic-number-for-the-pyc-header-in-python-3%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Morgemoulin

          Scott Moir

          Souastre