示例#1
0
 def reportChangedClone(self, child_v, b, h, gnx):
     trace = (False or g.app.debug) and not g.unitTesting
     c = self.c
     fileName = c.cacheListFileName
     old, new = child_v.b, b
     same = (
         old == new or
         new.endswith('\n') and old == new[: -1] or
         old.endswith('\n') and new == old[: -1])
     # if trace and not same:
     if trace and (not same or h == 'writeException'):
         g.trace('same %s old %s new %s %s %s' % (
             same, len(old), len(new), h, fileName))
     # This would make it impossible to clear nodes!
     # if not new: return same
     if same: return
     c.nodeConflictList.append(g.bunch(
         tag='(cached)',
         fileName=fileName,
         gnx=gnx,
         b_old=child_v.b,
         h_old=child_v.h,
         b_new=b,
         h_new=h,
     ))
     # Always issue the warning.
     g.error("cached read node changed:", child_v.h)
     child_v.h, child_v.b = h, b
     child_v.setDirty()
     c.changed = True # Tell getLeoFile to propegate dirty nodes.
示例#2
0
 def reportChangedClone(self, child_v, b, h, gnx):
     trace = (False or g.app.debug) and not g.unitTesting
     c = self.c
     fileName = c.cacheListFileName
     old, new = child_v.b, b
     same = (
         old == new or
         new.endswith('\n') and old == new[: -1] or
         old.endswith('\n') and new == old[: -1])
     # if trace and not same:
     if trace and (not same or h == 'writeException'):
         g.trace('same %s old %s new %s %s %s' % (
             same, len(old), len(new), h, fileName))
     # This would make it impossible to clear nodes!
     # if not new: return same
     if same: return
     c.nodeConflictList.append(g.bunch(
         tag='(cached)',
         fileName=fileName,
         gnx=gnx,
         b_old=child_v.b,
         h_old=child_v.h,
         b_new=b,
         h_new=h,
     ))
     # Always issue the warning.
     g.error("cached read node changed:", child_v.h)
     child_v.h, child_v.b = h, b
     child_v.setDirty()
     c.changed = True # Tell getLeoFile to propegate dirty nodes.
示例#3
0
    def reportIfNodeChanged(self, child_tuple, child_v, fileName, parent_v):
        '''
        Schedule a recovered node if child_v is substantially different from an
        earlier version.

        Issue a (rare) warning if two different files are involved.
        '''
        trace = (False or g.app.debug) and not g.unitTesting
        always_warn = True # True always warn about changed nodes.
        c = self.c
        h, b, gnx, grandChildren = child_tuple
        old_b, new_b = child_v.b, b
        old_h, new_h = child_v.h, h
        # Leo 5.6: test headlines.
        same_head = old_h == new_h
        same_body = (
            old_b == new_b or
            new_b.endswith('\n') and old_b == new_b[: -1] or
            old_b.endswith('\n') and new_b == old_b[: -1]
        )
        if same_head and same_body:
            return
        old_roots = list(getattr(child_v, 'tempRoots', set()))
        same_file = (
            len(old_roots) == 0 or
            len(old_roots) == 1 and old_roots[0] == fileName
        )
        must_warn = not same_file
        if not hasattr(child_v, 'tempRoots'):
            child_v.tempRoots = set()
        child_v.tempRoots.add(fileName)
        if trace:
            # g.trace('same h: %s, same b: %s same fn: %s' % (
                # same_head, same_body, same_file))
            g.trace('fileName', fileName)
            g.trace('tempRoots', old_roots)
        if must_warn:
            # This is the so-called "rare" case:
            # The node differs  in two different external files.
            self.warning('out-of-sync node: %s' % h)
            g.es_print('using node in %s' % fileName)
        if always_warn or must_warn:
            if c.make_node_conflicts_node:
                g.es_print('creating recovered node:', h)
            c.nodeConflictList.append(g.bunch(
                tag='(cached)',
                fileName=fileName,
                gnx=gnx,
                b_old=child_v.b,
                h_old=child_v.h,
                b_new=b,
                h_new=h,
                root_v=parent_v,
            ))
        # Always update the node.
        child_v.h, child_v.b = h, b
        child_v.setDirty()
        c.changed = True # Tell getLeoFile to propegate dirty nodes.
示例#4
0
    def reportIfNodeChanged(self, child_tuple, child_v, fileName, parent_v):
        '''
        Schedule a recovered node if child_v is substantially different from an
        earlier version.

        Issue a (rare) warning if two different files are involved.
        '''
        trace = (False or g.app.debug) and not g.unitTesting
        always_warn = True # True always warn about changed nodes.
        c = self.c
        h, b, gnx, grandChildren = child_tuple
        old_b, new_b = child_v.b, b
        old_h, new_h = child_v.h, h
        # Leo 5.6: test headlines.
        same_head = old_h == new_h
        same_body = (
            old_b == new_b or
            new_b.endswith('\n') and old_b == new_b[: -1] or
            old_b.endswith('\n') and new_b == old_b[: -1]
        )
        if same_head and same_body:
            return
        old_roots = list(getattr(child_v, 'tempRoots', set()))
        same_file = (
            len(old_roots) == 0 or
            len(old_roots) == 1 and old_roots[0] == fileName
        )
        must_warn = not same_file
        if not hasattr(child_v, 'tempRoots'):
            child_v.tempRoots = set()
        child_v.tempRoots.add(fileName)
        if trace:
            # g.trace('same h: %s, same b: %s same fn: %s' % (
                # same_head, same_body, same_file))
            g.trace('fileName', fileName)
            g.trace('tempRoots', old_roots)
        if must_warn:
            # This is the so-called "rare" case:
            # The node differs  in two different external files.
            self.warning('out-of-sync node: %s' % h)
            g.es_print('using node in %s' % fileName)
        if always_warn or must_warn:
            if c.make_node_conflicts_node:
                g.es_print('creating recovered node:', h)
            c.nodeConflictList.append(g.bunch(
                tag='(cached)',
                fileName=fileName,
                gnx=gnx,
                b_old=child_v.b,
                h_old=child_v.h,
                b_new=b,
                h_new=h,
                root_v=parent_v,
            ))
        # Always update the node.
        child_v.h, child_v.b = h, b
        child_v.setDirty()
        c.changed = True # Tell getLeoFile to propegate dirty nodes.
示例#5
0
 def state_handler(self, event=None):
     '''Handle keys while in the "screencast" input state.'''
     trace = False and not g.unitTesting
     m = self
     c = m.c
     k = c.k
     state = k.getState(m.state_name)
     char = event and event.char or ''
     if trace:
         g.trace('char: %s k.state.kind: %s m.k_state: %s' %
                 (repr(char), repr(k.state.kind),
                  m.k_state and repr(m.k_state.kind) or '<none>'))
     if m.ignore_keys:
         return
     if state == 0:
         # Init the minibuffer as in k.fullCommand.
         if trace: g.trace('======= state 0 =====')
         assert m.p1 and m.p1 == m.p
         k.mb_event = event
         k.mb_prefix = k.getLabel()
         k.mb_prompt = 'Screencast: '
         k.mb_tabList = []
         k.setLabel(k.mb_prompt)
         k.setState(m.state_name, 1, m.state_handler)
         m.next()
     # Only exit on Ctrl-g.
     # Because of menu handling, it's convenient to have escape go to the next slide.
     # That way an "extra" escape while dismissing menus will be handled well.
     elif char == 'Escape':
         # m.quit()
         m.next()
     elif char == 'Right':
         m.next()
     elif char == 'Left':
         m.prev()
     elif m.k_state.kind != m.state_name:
         # We are simulating another state.
         # Pass the character to *that* state,
         # making *sure* to save/restore all state.
         kind, n, handler = k.state.kind, k.state.n, k.state.handler
         m_state_copy = g.bunch(kind=m.k_state.kind,
                                n=m.k_state.n,
                                handler=m.k_state.handler)
         m.single_key(char)
         k.setState(kind, n, handler)
         m.set_state(m_state_copy)
     elif trace:
         g.trace('ignore %s' % (repr(char)))
示例#6
0
    def state_handler (self,event=None):
        
        '''Handle keys while in the "screencast" input state.'''

        trace = False and not g.unitTesting
        m = self ; c = m.c ; k = c.k
        state = k.getState(m.state_name)
        char = event and event.char or ''
        if trace:
            g.trace('char: %s k.state.kind: %s m.k_state: %s' % (
                repr(char),repr(k.state.kind),
                m.k_state and repr(m.k_state.kind) or '<none>'))
        if m.ignore_keys:
            return
        if state == 0:
            # Init the minibuffer as in k.fullCommand.
            if trace: g.trace('======= state 0 =====')
            assert m.p1 and m.p1 == m.p
            k.mb_event = event
            k.mb_prefix = k.getLabel()
            k.mb_prompt = 'Screencast: '
            k.mb_tabList = []
            k.setLabel(k.mb_prompt)
            k.setState(m.state_name,1,m.state_handler)
            m.next()
        # Only exit on Ctrl-g.
        # Because of menu handling, it's convenient to have escape go to the next slide.
        # That way an "extra" escape while dismissing menus will be handled well.
        elif char == 'Escape':
            # m.quit()
            m.next()
        elif char == 'Right':
            m.next()
        elif char == 'Left':
            m.prev()
        elif m.k_state.kind != m.state_name:
            # We are simulating another state.
            # Pass the character to *that* state,
            # making *sure* to save/restore all state.
            kind,n,handler = k.state.kind,k.state.n,k.state.handler
            m_state_copy = g.bunch(kind=m.k_state.kind,
                n=m.k_state.n,handler=m.k_state.handler)
            m.single_key(char)
            k.setState(kind,n,handler)
            m.set_state(m_state_copy)
        elif trace:
            g.trace('ignore %s' % (repr(char)))
示例#7
0
    def collectChangedNodes(self, root_v, aList, fileName):
        '''Populates c.nodeConflictList with data about nodes that
           are going to change during recreation of outline from 
           cached list.'''
        c = self.c
        #@+others
        #@+node:vitalije.20180507113809.1: *5* vnodes helper iterator
        gnxDict = c.fileCommands.gnxDict

        def vnodes(_vlist):
            h, b, gnx, c_vlist = _vlist
            v = gnxDict.get(gnx)
            if v:
                yield v, h, b, gnx
            for x in c_vlist:
                for y in vnodes(x):
                    yield y

        #@-others
        for v, h, b, gnx in vnodes(aList):
            if v is root_v and not (v.b or v.children):
                #
                # no children and an empty body of root node most probably means
                # we are reading external file for the first time. In this case
                # there is no point in counting this as nodeConflict
                continue
            same_h = v.h == h
            same_b = (v.b == b or (v.b[-1:] == '\n' and v.b[:-1] == b)
                      or (b[-1:] == '\n' and v.b == b[:-1]))
            if same_h and same_b:
                continue
            c.nodeConflictList.append(
                g.bunch(
                    tag='(cached)',
                    fileName=fileName,
                    gnx=gnx,
                    b_old=v.b,
                    h_old=v.h,
                    b_new=b,
                    h_new=h,
                    root_v=root_v,
                ))
示例#8
0
 def __init__(self, c):
     self.c = c
     self.log_color = 'black'
     self.log_focus = True # True: writing to log sets focus to log.
     self.ignore_keys = False # True: ignore keys in state_handler.
     self.quit_flag = False # True if m.quit has been called.
     self.k_state = g.bunch(kind=None, n=None, handler=None) # Saved k.state.
     self.key_w = None # Saved widget for passed-along key handling.
     self.n1 = 0.02 # default minimal typing delay.
     self.n2 = 0.175 # default maximum typing delay.
     self.p1 = None # The first slide of the show.
     self.p = None # The present slide of the show.
     self.speed = 1.0 # Amount to multiply wait times.
     self.state_name = 'screencast' # The state name to enable m.state_handler.
     self.node_stack = [] # For m.prev and m.undo.
     self.text_flag = False # True: m.next shows body text instead of executing it.
     self.user_dict = {} # For use by scripts.
     self.widgets = [] # List of (popup) widgets created by this class.
     # inject c.screenCastController
     c.screenCastController = self
示例#9
0
 def __init__(self, c):
     self.c = c
     self.log_color = 'black'
     self.log_focus = True  # True: writing to log sets focus to log.
     self.ignore_keys = False  # True: ignore keys in state_handler.
     self.quit_flag = False  # True if m.quit has been called.
     self.k_state = g.bunch(kind=None, n=None,
                            handler=None)  # Saved k.state.
     self.key_w = None  # Saved widget for passed-along key handling.
     self.n1 = 0.02  # default minimal typing delay.
     self.n2 = 0.175  # default maximum typing delay.
     self.p1 = None  # The first slide of the show.
     self.p = None  # The present slide of the show.
     self.speed = 1.0  # Amount to multiply wait times.
     self.state_name = 'screencast'  # The state name to enable m.state_handler.
     self.node_stack = []  # For m.prev and m.undo.
     self.text_flag = False  # True: m.next shows body text instead of executing it.
     self.user_dict = {}  # For use by scripts.
     self.widgets = []  # List of (popup) widgets created by this class.
     # inject c.screenCastController
     c.screenCastController = self
示例#10
0
class ConfigShim(config_base):
    def __init__(self):
        config_base.__init__(self)
        g.pr('\n===== ConfigShim: new_config: %s\n' % new_config)
        self.setObjectName('ConfigShim')

    if new_config:
        #@+<< define bunch settings >>
        #@+node:ekr.20190331082353.1: *3* << define bunch settings >>
        # '(\w+)': With: \1 =

        advanced = g.Bunch(
            autoCompDelay=200,
            fileExtensionsToLoadFromDir='py,pyw,pyx,txt,bat',
            find_autoHide_timeout=10,
            homeAndEndWorkOnDisplayedLine=0,
            shellMaxLines=10000,
            titleText='{fileName} ({fullPath}) - Interactive Editor for Python',
        )

        settings = g.Bunch(
            allowFloatingShell=0,
            autoCallTip=1,
            autoClose_Brackets=1,
            autoClose_Quotes=1,
            autoComplete=1,
            autoComplete_acceptKeys='Tab',
            autoComplete_caseSensitive=0,
            autoComplete_fillups='\n',
            autoComplete_keywords=1,
            autoIndent=1,
            changeDirOnFileExec=0,
            defaultIndentUsingSpaces=1,
            defaultIndentWidth=4,
            defaultLineEndings='CRLF',
            defaultStyle='python',
            justificationWidth=70,
            language='English (US)',
            removeTrailingWhitespaceWhenSaving=0,
        )

        shellConfigs2 = [
            g.Bunch(
                argv='',
                environ='',
                exe='c:\\anaconda3\\python.exe',
                gui='auto',
                ipython='yes',
                name='Python',
                projectPath='',
                pythonPath='',
                scriptFile='',
                startDir='',
                startupScript='',
            )
        ]

        shortcuts2 = g.bunch(
            #@+<< define bunch shortcuts2 >>
            #@+node:ekr.20190331082549.1: *4* << define bunch shortcuts2 >>
            edit__comment='Ctrl+R,',
            edit__copy='Ctrl+C,Ctrl+Insert',
            edit__cut='Ctrl+X,Shift+Delete',
            edit__dedent='Shift+Tab,',
            edit__delete_line='Ctrl+D,',
            edit__duplicate_line='Ctrl+Shift+D,',
            edit__find_next='Ctrl+G,F3',
            edit__find_or_replace='Ctrl+F,',
            edit__find_previous='Ctrl+Shift+G,Shift+F3',
            edit__find_selection='Ctrl+F3,',
            edit__find_selection_backward='Ctrl+Shift+F3,',
            edit__indent='Tab,',
            edit__justify_commentdocstring='Ctrl+J,',
            edit__paste='Ctrl+V,Shift+Insert',
            edit__paste_and_select='Ctrl+Shift+V',
            edit__redo='Ctrl+Y,',
            edit__select_all='Ctrl+A,',
            edit__toggle_breakpoint='Ctrl+B,',
            edit__uncomment='Ctrl+T,',
            edit__undo='Ctrl+Z,',
            file__close='Ctrl+W,',
            file__new='Ctrl+N,',
            file__open='Ctrl+O,',
            file__save='Ctrl+S,',
            run__execute_cell='Ctrl+Return,Ctrl+Enter',
            run__execute_cell_and_advance='Ctrl+Shift+Return,Ctrl+Shift+Enter',
            run__execute_file='Ctrl+E,F5',
            run__execute_main_file='Ctrl+M,F6',
            run__execute_selection='Alt+Return,F9',
            run__execute_selection_and_advance='Shift+F9,Shift+Alt+Return',
            run__run_file_as_script='Ctrl+Shift+E,Ctrl+F5',
            run__run_main_file_as_script='Ctrl+Shift+M,Ctrl+F6',
            shell__clear_screen='Ctrl+L,',
            shell__close='Alt+K,',
            shell__create_shell_1_='Ctrl+1,',
            shell__create_shell_2_='Ctrl+2,',
            shell__create_shell_3_='Ctrl+3,',
            shell__create_shell_4_='Ctrl+4,',
            shell__create_shell_5_='Ctrl+5,',
            shell__create_shell_6_='Ctrl+6,',
            shell__create_shell_7_='Ctrl+7,',
            shell__create_shell_8_='Ctrl+8,',
            shell__interrupt='Ctrl+I,Meta+C',
            shell__postmortem_debug_from_last_traceback='Ctrl+P,',
            shell__restart='Ctrl+K,',
            shell__terminate='Ctrl+Shift+K,',
            view__select_editor='Ctrl+9,F2',
            view__select_previous_file='Ctrl+Tab,',
            view__select_shell='Ctrl+0,F1',
            view__zooming__zoom_in='Ctrl+=,Ctrl++',
            view__zooming__zoom_out='Ctrl+-,',
            view__zooming__zoom_reset='Ctrl+\\,'
            #@-<< define bunch shortcuts2 >>
        )

        state = g.Bunch(
            editorState2=[
                #@+<< define editorState2 >>
                #@+node:ekr.20190331082353.2: *4* << define editorState2 >>
                [
                    'C:\\apps\\pyzo\\source\\pyzo\\codeeditor\\highlighter.py',
                    3279, 96
                ],
                [
                    'C:\\apps\\pyzo\\source\\pyzo\\core\\editorTabs.py', 22913,
                    693
                ],
                [
                    'C:\\apps\\pyzo\\source\\pyzo\\codeeditor\\highlighter.py',
                    'hist'
                ],
                ['C:\\apps\\pyzo\\source\\pyzo\\core\\editorTabs.py', 'hist']
                #@-<< define editorState2 >>
            ],
            find_autoHide=1,
            find_matchCase=0,
            find_regExp=0,
            find_show=0,
            find_wholeWord=1,
            loadedTools=[
                'pyzofilebrowser', 'pyzologger', 'pyzosourcestructure'
            ],
            newUser=1,
            windowGeometry=
            'AdnQywACAAAAAAGjAAAA2AAABv0AAANWAAABqwAAAPcAAAb1AAADTgAAAAAAAAAAB4A=\n',
            windowState=
            ('AAAA/wAAAAD9AAAAAgAAAAAAAACeAAACRPwCAAAAAfwAAAAUAAACRAAAAYgA/////AIAAAAC+wAA\n'
             'AB4AcAB5AHoAbwBmAGkAbABlAGIAcgBvAHcAcwBlAHIBAAAAFAAAAWEAAAEIAP////sAAAAmAHAA\n'
             'eQB6AG8AcwBvAHUAcgBjAGUAcwB0AHIAdQBjAHQAdQByAGUBAAABewAAAN0AAAB6AP///wAAAAEA\n'
             'AAGEAAACRPwCAAAABvsAAAAMAHMAaABlAGwAbABzAQAAABQAAAD/AAAAcwD////7AAAAFABwAHkA\n'
             'egBvAGwAbwBnAGcAZQByAQAAARkAAAE/AAAAWQD////7AAAAGgBwAHkAegBvAHcAbwByAGsAcwBw\n'
             'AGEAYwBlAAAAAT4AAAEaAAAAAAAAAAD7AAAAJgBwAHkAegBvAGkAbgB0AGUAcgBhAGMAdABpAHYA\n'
             'ZQBoAGUAbABwAAAAAnkAAAB6AAAAAAAAAAD7AAAAIgBwAHkAegBvAGgAaQBzAHQAbwByAHkAdgBp\n'
             'AGUAdwBlAHIAAAACGgAAAVsAAAAAAAAAAPsAAAAcAHAAeQB6AG8AdwBlAGIAYgByAG8AdwBzAGUA\n'
             'cgAAAAKwAAAAxQAAAAAAAAAAAAADHQAAAkQAAAAEAAAABAAAAAgAAAAI/AAAAAA=\n'
             ))

        tools = g.Bunch(pyzofilebrowser=g.Bunch(),
                        pyzofilebrowser2=g.Bunch(
                            expandedDirs=['c:\\apps\\pyzo\\source\\pyzo'],
                            nameFilter='!*.pyc',
                            path='c:\\apps\\pyzo\\source\\pyzo',
                            searchMatchCase=0,
                            searchRegExp=0,
                            searchSubDirs=1,
                            starredDirs=[
                                g.Bunch(
                                    addToPythonpath=0,
                                    name='Pyzo sources',
                                    path='c:\\apps\\pyzo\\source',
                                )
                            ]),
                        pyzohistoryviewer=g.Bunch(),
                        pyzointeractivehelp=g.Bunch(fontSize=14,
                                                    noNewlines=1,
                                                    smartNewlines=1),
                        pyzologger=g.Bunch(),
                        pyzosourcestructure=g.Bunch(
                            level=1,
                            showTypes=['class', 'def', 'cell', 'todo'],
                        ),
                        pyzowebbrowser=g.Bunch(
                            bookMarks=[
                                'docs.python.org',
                                'scipy.org',
                                'doc.qt.nokia.com/4.5/',
                                'pyzo.org',
                            ],
                            zoomFactor=1.0,
                        ),
                        pyzoworkspace=g.Bunch(
                            hideTypes=[],
                            typeTranslation=g.Bunch(
                                builtin_function_or_method='function',
                                method='function')))

        view = g.Bunch(autoComplete_popupSize=[300, 100],
                       codeFolding=0,
                       doBraceMatch=1,
                       edgeColumn=80,
                       fontname='DejaVu Sans Mono',
                       highlightCurrentLine=1,
                       highlightMatchingBracket=1,
                       qtstyle='fusion',
                       showIndentationGuides=1,
                       showLineEndings=0,
                       showStatusbar=0,
                       showWhitespace=0,
                       showWrapSymbols=0,
                       tabWidth=4,
                       wrap=1,
                       zoom=2)

        #@-<< define bunch settings >>
        #@+<< new config methods >>
        #@+node:ekr.20190331052308.1: *3* << new config methods >>
        #@+others
        #@+node:ekr.20190331052308.2: *4* ConfigShim.__repr__
        def __repr__(self):

            return 'ConfigShim'
            # return g.obj2string(self)
            # Can't do this: it calls repr!

        #@+node:ekr.20190331052308.3: *4* ConfigShim.__getattribute__
        def __getattribute__(self, key):
            '''The usual shinanigans...'''
            ### return object.__getattribute__(self, key)
            try:
                val = object.__getattribute__(self, key)
            except AttributeError:
                if key in self:
                    val = self[key]
                else:
                    raise
            if key not in config_shim_seen:
                config_shim_seen[key] = True
                g.pr('\n===== ConfigShim.__getattribute__', key, val)
            return val

        #@+node:ekr.20190331052308.4: *4* ConfigShim.__setattr__ (not used)
        # def __setattr__(self, key, val):
        # if key in Dict.__reserved_names__:
        # # Either let OrderedDict do its work, or disallow
        # if key not in Dict.__pure_names__:
        # return _dict.__setattr__(self, key, val)
        # else:
        # raise AttributeError('Reserved name, this key can only ' +
        # 'be set via ``d[%r] = X``' % key)
        # else:
        # # if isinstance(val, dict): val = Dict(val) -> no, makes a copy!
        # self[key] = val
        #@-others
        #@-<< new config methods >>
    else:
        #@+<< old config methods >>
        #@+node:ekr.20190331052251.1: *3* << old config methods >>
        #@+others
        #@+node:ekr.20190317082751.2: *4* ConfigShim.__repr__
        def __repr__(self):

            from pyzo.util.zon import isidentifier
            # Changed import.
            identifier_items = []
            nonidentifier_items = []
            for key, val in self.items():
                if isidentifier(key):
                    identifier_items.append('%s=%r' % (key, val))
                else:
                    nonidentifier_items.append('(%r, %r)' % (key, val))
            if nonidentifier_items:
                return 'Dict([%s], %s)' % (', '.join(nonidentifier_items),
                                           ', '.join(identifier_items))
            else:
                return 'Dict(%s)' % (', '.join(identifier_items))

        #@+node:ekr.20190317082751.3: *4* ConfigShim.__getattribute__
        def __getattribute__(self, key):
            try:
                ### return object.__getattribute__(self, key)
                val = object.__getattribute__(self, key)
                if False and key not in ('advanced', 'shortcuts2', 'settings'):
                    # g.pr('===== LeoPyzoConfig 1: %r: %r' % (key, val))
                    g.pr('===== LeoPyzoConfig 1: %r' % key)
                return val
            except AttributeError:
                if key in self:
                    if False and key not in ('advanced', 'shortcuts2',
                                             'settings'):
                        # g.pr('===== LeoPyzoConfig 1: %r: %r' % (key, g.truncate(self[key], 50)))
                        g.pr('===== LeoPyzoConfig 2: %r' % key)
                    return self[key]
                else:
                    raise

        #@+node:ekr.20190317082751.4: *4* ConfigShim.__setattr__
        def __setattr__(self, key, val):
            if key in Dict.__reserved_names__:
                # Either let OrderedDict do its work, or disallow
                if key not in Dict.__pure_names__:
                    return _dict.__setattr__(self, key, val)
                else:
                    raise AttributeError('Reserved name, this key can only ' +
                                         'be set via ``d[%r] = X``' % key)
            else:
                # if isinstance(val, dict): val = Dict(val) -> no, makes a copy!
                self[key] = val