Here is a utility script - in the attached outline - that will list the 
contents of an object's __dict__ in a fairly readable way including the 
docstrings.  You can use it for listing the methods, functions, and classes 
of c or g, or of any other Python object.  In the outline, the script 
inspects the contents of the ViewRenderedController3 of the viewrendered3 
plugin, but you can use it for c, g, or anything else.

I actually developed it to view c and g to help me with other development 
projects.  It's pretty brute force, and I suppose it could be done better 
using the inspect module, but I was concentrating on formatting the 
docstrings.  You can use the format_docstr() function to format other 
docstrings, including in actual python files that have been read but not 
opened or imported - for example, Leo plugin files.

In the outline, I copy the output to the clipboard.  That's because it 
tends to be fairly long, and it's better to paste it into a node or another 
editor than to try to print it to the log pane or the console.

I won't pretend this is bullet proof or production ready, but it is useful 
as is.

Here is a sample output for a commander (lines may be wrapped here - could 
be more readable in a page with wider lines):

_currentPosition  class 'leo.core.leoNodes.Position'  
_prev_next  class 'leo.plugins.nav_qt.NavController'  
_style_deltas  class 'collections.defaultdict'  
  defaultdict(default_factory=None, /, [...]) --> dict with
  default factory The default factory is called without
  arguments to produce a new value when a key is not present,
  in __getitem__ only. ...

_topPosition    
abbrevCommands  class 'leo.commands.abbrevCommands.AbbrevCommandsClass'  
     A class to handle user-defined abbreviations.   See
  apropos-abbreviations for details.

abbrev_place_end  class 'str'  
abbrev_place_start  class 'str'  
abbrev_subst_end  class 'str'  
abbrev_subst_env  class 'dict'  
abbrev_subst_start  class 'bool'  
active_stylesheet  class 'str'  
atFileCommands  class 'leo.core.leoAtFile.AtFile'  A class implementing the 
atFile subcommander.
at_root_bodies_start_in_doc_mode  class 'bool'  
autoindent_in_nocolor  class 'bool'  
bufferCommands  class 'leo.commands.bufferCommands.BufferCommandsClass'  
     An Emacs instance does not have knowledge of what is
  considered a   buffer in the environment.

changed  class 'bool'  
chapterCommands    
chapterController  class 'leo.core.leoChapters.ChapterController'  A 
per-commander controller that manages chapters and related nodes.
collapse_nodes_after_move  class 'bool'  
collapse_on_lt_arrow  class 'bool'  
command_count  class 'int'  
command_function  class 'function'  
  Execute a *Leo* script, written in python.     Keyword
  args:     args=None        Not None: set
  script_args in the execution environment.     p=None
  Get the script from p.b, unless script is given. ...


-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/leo-editor/c7e212be-13cf-4319-af09-1ffcef006b4en%40googlegroups.com.
<?xml version="1.0" encoding="utf-8"?>
<!-- Created by Leo: http://leoeditor.com/leo_toc.html -->
<leo_file xmlns:leo="http://leoeditor.com/namespaces/leo-python-editor/1.1"; >
<leo_header file_format="2"/>
<vnodes>
<v t="tom.20220315180258.1"><vh>List object Methods and Classes</vh>
<v t="tom.20220315181420.1"><vh>reformat docstring</vh></v>
</v>
</vnodes>
<tnodes>
<t tx="tom.20220315180258.1">@language python
@others

def list_namespace(obj):
    """Return a formatted string representing the contents of an objects's dict.
    
    Includes a formatted and possibly truncated version of the docstring.
    """
    excludes = ("class 'str'", "class 'int'", "class 'bool'", "class 'tuple'",
                "class 'dict'", )
    res = []
    for n, v in sorted(obj.__dict__.items(), key = lambda x: x[0]):
        docstr = ''
        typestr = f'{type(v)}'
        if typestr == "&lt;class 'NoneType'&gt;":
            typestr = ''
        typestr = typestr.replace('&lt;', '').replace('&gt;', '')
        if typestr not in excludes:
            docstr = f'"""{v.__doc__ }"""' if v.__doc__ else  ""
            docstr = format_docstr(docstr).replace('  ', ' ')

        res.append(f'{n}  {typestr}  {docstr}')
    return '\n'.join(res)

from leo.plugins import viewrendered3 as vr3

ns = list_namespace(vr3.ViewRenderedController3)
g.app.gui.replaceClipboardWith(ns)

</t>
<t tx="tom.20220315181420.1">@language python
from textwrap import wrap

def format_docstr(block, too_long = 5):
    """Try to find the docstring of a python file.
    
    Works even if the docstr is contained in a &lt;&lt; named section &gt;&gt;.
    The docstring is shortened if it contains too many lines,
    and is rewrapped.

    Docstring multiline formatting principles:
        1. First line is not blank.
        2. First line has same indentation as the rest of the body.
        3. No more than too_long lines.
        4. If clipped, end docstr with ellipsis ('...').
        5. If last line would contain only an ellipsis, move it
           to the end of the previous line and remove the last (now blank)
           line.
        6. No sentinal lines included. 
    
    RETURNS:
    the modified docstring
    """
    if not block: return ''
    start = -1
    for quote in '"""', "'''":
        start = block.find(quote)
        if start &gt; -1:
            break

    if start == -1:
        return ''

    start = block.find(quote) + 3
    end =  start + block[start:].find(quote)
    doc = block[start:end]

    if doc == 'None':
        doc = ''

    # Formatting for multi-line docstring
    doclines = [line for line in doc.split('\n') if not line.lstrip().startswith('#@')]
    if not doclines[0].strip():
        doclines = doclines[1:]
    toolong = len(doclines) &gt; 5
    if toolong:
        doclines = doclines[:4]
        doclines[0] = doclines[0].lstrip()
        while not doclines[-1].strip():
            doclines.pop(-1)
        doclines[-1] += ' ...'
        doc = '\n'.join(doclines)
    manylines = len(doclines) &gt; 1
    if manylines:
        doc = '\n' + '\n'.join(wrap(doc, width = 65, initial_indent = ' '*4,
                        subsequent_indent = ' '*4)) + '\n'
    else:
        doc = doc.strip()
    return doc
</t>
</tnodes>
</leo_file>

Reply via email to