Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance dis.dis to autocompile codestrings #50756

Closed
terryjreedy opened this issue Jul 17, 2009 · 15 comments
Closed

Enhance dis.dis to autocompile codestrings #50756

terryjreedy opened this issue Jul 17, 2009 · 15 comments
Assignees
Labels
easy stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@terryjreedy
Copy link
Member

BPO 6507
Nosy @birkenfeld, @rhettinger, @terryjreedy, @mdickinson, @ncoghlan, @benjaminp, @durban
Files
  • issue6507.diff: Patch (py3k branch)
  • issue6507_2_priv.diff
  • issue6507_3.diff
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/ncoghlan'
    closed_at = <Date 2010-07-03.07:43:11.122>
    created_at = <Date 2009-07-17.19:06:14.005>
    labels = ['easy', 'type-feature', 'library']
    title = 'Enhance dis.dis to autocompile codestrings'
    updated_at = <Date 2010-07-09.15:11:16.577>
    user = 'https://github.com/terryjreedy'

    bugs.python.org fields:

    activity = <Date 2010-07-09.15:11:16.577>
    actor = 'eric.araujo'
    assignee = 'ncoghlan'
    closed = True
    closed_date = <Date 2010-07-03.07:43:11.122>
    closer = 'ncoghlan'
    components = ['Library (Lib)']
    creation = <Date 2009-07-17.19:06:14.005>
    creator = 'terry.reedy'
    dependencies = []
    files = ['16871', '17265', '17839']
    hgrepos = []
    issue_num = 6507
    keywords = ['patch', 'easy']
    message_count = 15.0
    messages = ['90637', '90647', '90670', '90675', '90892', '102851', '102859', '103507', '105329', '105336', '106502', '109102', '109119', '109127', '109162']
    nosy_count = 8.0
    nosy_names = ['georg.brandl', 'rhettinger', 'terry.reedy', 'mark.dickinson', 'ncoghlan', 'scott.dial', 'benjamin.peterson', 'daniel.urban']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue6507'
    versions = ['Python 3.2']

    @terryjreedy
    Copy link
    Member Author

    dis.dis(ob) currently accepts "a module, a class, a method, a function,
    or a code object." But for most uses I have seen on python-list, people
    start with a code snippet. They must then wrap that in a function or
    remember (or lookup) a call such as compile(code, '', 'exec') to make a
    code object. I propose that dis do the latter automatically. Dis already
    has to branch on the input class, so I assume adding another branch
    should not be difficult.

    On the Python ideas list, Steven D'Aprano raised the issue of 'exec'
    versus 'single' versus 'eval'. As far as dis is concerned, there seems
    to be no difference between 'exec' and 'single'.

    >>> dis(compile('x = x+1', '', 'single'))
      1           0 LOAD_NAME                0 (x) 
                  3 LOAD_CONST               0 (1) 
                  6 BINARY_ADD           
                  7 STORE_NAME               0 (x) 
                 10 LOAD_CONST               1 (None) 
                 13 RETURN_VALUE         
    
    >>> dis(compile('x = x+1', '', 'exec'))
      1           0 LOAD_NAME                0 (x) 
                  3 LOAD_CONST               0 (1) 
                  6 BINARY_ADD           
                  7 STORE_NAME               0 (x) 
                 10 LOAD_CONST               1 (None) 
                 13 RETURN_VALUE         

    Using 'exec' instead of 'eval' adds two spurious, but easily ignored, lines.

    >>> dis(compile('x+1','', 'eval'))
      1           0 LOAD_NAME                0 (x) 
                  3 LOAD_CONST               0 (1) 
                  6 BINARY_ADD           
                  7 RETURN_VALUE    
         
    >>> dis(compile('x+1', '', 'exec'))
      1           0 LOAD_NAME                0 (x) 
                  3 LOAD_CONST               0 (1) 
                  6 BINARY_ADD           
                  7 POP_TOP              
                  8 LOAD_CONST               1 (None) 
                 11 RETURN_VALUE         

    Between the current doc sentences "For a single code sequence, it prints
    one line per bytecode instruction." and "If no object is provided, it
    disassembles the last traceback." I propose adding the following two
    sentences.

    "Strings are first compiled as statements to code objects with
    compile(string,'','exec'). For expressions, this adds a spurious POP_TOP
    and LOAD_CONST at the end."

    'compile' should be cross-referenced to its listing under built-in
    functions.

    @terryjreedy terryjreedy added stdlib Python modules in the Lib dir type-feature A feature request or enhancement labels Jul 17, 2009
    @ncoghlan
    Copy link
    Contributor

    Copying my suggestion (minus examples) over from the python-ideas thread:

    We could define it as trying the three modes in order (first 'eval',
    then 'single', then 'exec') moving on to the next option if it raises
    syntax error:

    from dis import dis
    def dis_str(source):
      modes = ('eval', 'single', 'exec')
      for mode in modes:
        try:
          c = compile(source, '', mode)
          break
        except SyntaxError:
          if mode is modes[-1]:
            raise
      return dis(c)

    @birkenfeld
    Copy link
    Member

    As I explained on python-ideas, 'single' should not be tried.

    @ncoghlan
    Copy link
    Contributor

    As per Georg's suggestion, a better approach would look like:

    from dis import dis
    def dis_str(source):
      try:
        c = compile(source, '', 'eval')
      except SyntaxError:
        c = compile(source, '', 'exec')
      return dis(c)

    @terryjreedy
    Copy link
    Member Author

    Trying both 'eval' and 'exec' looks fine to me.
    Marking 'easy' because I expect it should be ;-)

    @durban
    Copy link
    Mannequin

    durban mannequin commented Apr 11, 2010

    I've made a patch, which adds a disassemble_str function to the dis module. The dis.dis function calls this function if x is a string. Added the following sentence to the documentation: "Strings are first compiled to code objects with the :func:`compile` built-in function." Added two simle unittests.

    @rhettinger
    Copy link
    Contributor

    +1

    @durban
    Copy link
    Mannequin

    durban mannequin commented Apr 18, 2010

    Any chance, that my patch will be accepted? Is there a problem with it?

    Thanks.

    @benjaminp
    Copy link
    Contributor

    disassemble_str should be private with an underscore.

    @durban
    Copy link
    Mannequin

    durban mannequin commented May 8, 2010

    Done. Attached new patch as issue6507_2_priv.diff.

    @ncoghlan
    Copy link
    Contributor

    Missed the window for 2.7, but should be right for 3.2.

    There's a minor error in the documentation (strings need to be mentioned in the list of acceptable types), but I can fix that on commit.

    @ncoghlan ncoghlan assigned ncoghlan and unassigned benjaminp May 26, 2010
    @scottdial
    Copy link
    Mannequin

    scottdial mannequin commented Jul 2, 2010

    disassemble_str should be private with an underscore.

    disassemble_string should've been private as well, while we are editing this module.

    @durban
    Copy link
    Mannequin

    durban mannequin commented Jul 2, 2010

    disassemble_string should've been private as well, while we are editing this module.

    Attached the updated patch.

    @terryjreedy
    Copy link
    Member Author

    Just today, someone posted the result of dis.dis('somebytes') and did not notice the error because dis blithely disassembles bytes as bytecodes, even in 3.x. (The person actually dissed a 2.x string).

    >>> from dis import dis
    >>> dis(b'cat')
              0 DUP_TOPX        29793

    It is a natural thing to do, so I hope this is put in 3.2.

    Since the undocumented 'disassemble_string' now disassembles bytes, I think it should be renamed '_disassemble_bytes' instead of '_disassemble_string'. This would accord with the general effort to remove 2.x fossils from 3.x.

    Aside from that, it looks ready, from a reading review, to apply and test: doc addition, added tests, new function and else case, and rename.

    @ncoghlan
    Copy link
    Contributor

    ncoghlan commented Jul 3, 2010

    Committed (with some minor modifications) in r82471.

    Inspired by Yanov Aknin's ssc() tool, I've opened a new RFE (bpo-9147) for a similarly enhanced show_code() implementation.

    @ncoghlan ncoghlan closed this as completed Jul 3, 2010
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    easy stdlib Python modules in the Lib dir type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    5 participants