Source code for ccpn.ui.gui.modules.macroEditorUtil.CompletionProviders

"""
Module Documentation here
"""
#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (https://www.ccpn.ac.uk) 2014 - 2022"
__credits__ = ("Ed Brooksbank, Joanna Fox, Victoria A Higman, Luca Mureddu, Eliza Płoskoń",
               "Timothy J Ragan, Brian O Smith, Gary S Thompson & Geerten W Vuister")
__licence__ = ("CCPN licence. See https://ccpn.ac.uk/software/licensing/")
__reference__ = ("Skinner, S.P., Fogh, R.H., Boucher, W., Ragan, T.J., Mureddu, L.G., & Vuister, G.W.",
                 "CcpNmr AnalysisAssign: a flexible platform for integrated NMR analysis",
                 "J.Biomol.Nmr (2016), 66, 111-124, http://doi.org/10.1007/s10858-016-0060-y")
#=========================================================================================
# Last code modification
#=========================================================================================
__modifiedBy__ = "$Author: Luca Mureddu $"
__modifiedBy__ = "$modifiedBy: Luca Mureddu $"
__dateModified__ = "$Date: 2021-07-31 19:34:45 +0000 (,  31, 2021) $"
__dateModified__ = "$dateModified: 2022-04-04 17:25:23 +0100 (Mon, April 04, 2022) $"
__version__ = "$Revision: 3.1.0 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: Luca Mureddu $"
__date__ = "$Date: 2021-07-31 19:34:45 +0000 (,  31, 2021) $"
#=========================================================================================
# Start of code
#=========================================================================================

import jedi
import sys
from ccpn.ui.gui.modules.macroEditorUtil import IconDefinitions as iDef

_namespace = []


def _getCcpnNamespaceFromApplication():
    """
    Get the namespaces as a list of dicts. Used to complete the Editor on key-pressed.
    """
    from ccpn.framework.Application import getApplication
    application = getApplication()
    namespaceList = []
    if application:
        namespace = application.mainWindow.namespace
        namespaceList = [{i: namespace[i]} for i in list(namespace.keys())]
    return namespaceList

def _getCcpnNamespaceFromImports():
    """
    This function is called several times from external scrips, therefore it init the imports Only Once with global.
    Namespace are done with imports to get Call-Signatures and documentation string.
    """
    global _namespace
    if _namespace:
        return _namespace

    from ccpn.core.Project import Project
    from ccpn.framework.Framework import Framework
    from ccpn.framework.Application import getApplication
    from ccpn.framework.Preferences import getPreferences
    from ccpn.ui.gui.lib.GuiMainWindow import GuiMainWindow
    from ccpn.framework.Current import Current
    from ccpn.ui.Ui import Ui
    from ccpn.util.Logging import getLogger

    _namespace = [
                 {'application'     : Framework},
                 {'current'         : Current},
                 {'mainWindow'      : GuiMainWindow},
                 {'ui'              : Ui},
                 {'project'         : Project},
                 {'preferences'     : getPreferences()},
                 {'redo'            : GuiMainWindow.redo},
                 {'undo'            : GuiMainWindow.undo},
                 {'get'             : Framework.getByPid},
                 {'loadProject'     : Framework.loadProject},
                 {'loadData'        : Framework.loadData},
                 {'warning'         : getLogger().warning},
                 {'info'            : getLogger().info},
                 ]
    return _namespace

[docs]def getJediInterpreter(text, namespaces=None, useImports=False, **kwds): """ :type text: str. the text to parse and get the completions :type namespaces: list of dict. a list of namespaces dictionaries such as the one returned by :func:"locals". Other optional arguments are same as the ones for :class:"Script". If "line" and "column" are None, they are assumed be at the end of "text". """ if namespaces: _namespaces = namespaces else: if useImports: _namespaces = list(_getCcpnNamespaceFromImports()) else: _namespaces = list(_getCcpnNamespaceFromApplication()) try: interpreter = jedi.Interpreter(text, namespaces=_namespaces, **kwds) return interpreter except ValueError: return None
def _getAvailablePids() -> list: """ Get all the pids available in the current project """ from ccpn.framework.Application import getApplication result = None try: application = getApplication() if application: project = application.project ll = [i.values() for i in project._pid2Obj.values()] ids = [j.id for i in ll for j in i] result = list(set(ids)) except: sys.stderr.write('==> Completion warning. Pids not found!') return result or []
[docs]class CcpnCodeCompletionWorker(object): """ This is the worker associated with the code completion mode. The worker does not actually do anything smart, the real work of collecting code completions is accomplished by the completion providers (see the :class:`pyqode.core.backend.workers.CodeCompletionWorker.Provider` interface) listed in :attr:`pyqode.core.backend.workers.CompletionWorker.providers`. Completion providers must be installed on the CodeCompletionWorker at the beginning of the main server script, e.g.:: from pyqode.core.backend import CodeCompletionWorker CodeCompletionWorker.providers.insert(0, MyProvider()) """ #: The list of code completion provider to run on each completion request. providers = [] def __call__(self, data): """ Do the work (this will be called in the child process by the SubprocessServer). """ code = data['code'] line = data['line'] column = data['column'] path = data['path'] encoding = data['encoding'] prefix = data['prefix'] req_id = data['request_id'] completions = [] for prov in CcpnCodeCompletionWorker.providers: try: results = prov.complete( code, line, column, path, encoding, prefix) completions.append(results) if len(completions): break except: sys.stderr.write('Failed to get completions from provider %r' % prov) exc1, exc2, exc3 = sys.exc_info() return [(line, column, req_id)] + completions
[docs] def registerProvider(cls, provider): cls.providers.append(provider)
[docs]class CcpnNameSpacesProvider: """ Provides code completion for the Ccpn Namespace... """
[docs] def complete(self, code, line, column, path, encoding, prefix, *args): """ Completes python code using `jedi`_. :returns: a list of completion. """ ret_val = [] _namespaceAtts = [] try: namespaces = _getCcpnNamespaceFromApplication() _namespaceAtts = [k for dd in namespaces for k in dd.keys()] script = getJediInterpreter(text=code, namespaces=namespaces, encoding=encoding) completions = script.completions() except Exception as ex: completions = [] sys.stderr.write('==> Completion warning. ! %s' %ex) for completion in completions: iconType = '' ccpnTag = False if completion.type: if len(completion.type.split('.'))>0: iconType = completion.type.split('.')[0] if completion.name in _namespaceAtts: ccpnTag = True else: iconType = completion.type iconDef = iDef.iconFromTypename(completion.name, iconType, ccpnTag=ccpnTag) iconPath = '' if iconDef: if len(iconDef)==2: iconPath = iconDef[1] ret_val.append({ 'name': completion.name, 'tooltip': completion.description, 'icon': iconPath, }) return ret_val
[docs]class CcpnJediCompletionProvider: """ Provides code completion using the original Jedi library. https://github.com/davidhalter/jedi """
[docs] @staticmethod def complete(code, line, column, path, encoding, prefix): """ Completes python code using `jedi`_. :returns: a list of completion. """ ret_val = [] try: script = getJediInterpreter(text=code, encoding=encoding) completions = script.completions() except RuntimeError: completions = [] for completion in completions: ret_val.append({ 'name': completion.name, 'tooltip': completion.description, # 'icon': iDef.iconFromTypename(completion.name, completion.type), }) return ret_val
# setup completion providers from pyqode.core.modes.code_completion import backend as _backend _backend.CodeCompletionWorker = CcpnCodeCompletionWorker ccpnNameSpacesProvider = CcpnNameSpacesProvider() _backend.CodeCompletionWorker.registerProvider(CcpnCodeCompletionWorker, ccpnNameSpacesProvider) _backend.CodeCompletionWorker.registerProvider(CcpnCodeCompletionWorker, _backend.DocumentWordsProvider())