Exemple #1
0
def test_pycodestyle_config(workspace):
    """ Test that we load config files properly.

    Config files are loaded in the following order:
        tox.ini pep8.cfg setup.cfg pycodestyle.cfg

    Each overriding the values in the last.

    These files are first looked for in the current document's
    directory and then each parent directory until any one is found
    terminating at the workspace root.

    If any section called 'pycodestyle' exists that will be solely used
    and any config in a 'pep8' section will be ignored
    """
    doc_uri = uris.from_fs_path(os.path.join(workspace.root_path, 'test.py'))
    workspace.put_document(doc_uri, DOC)
    doc = workspace.get_document(doc_uri)
    config = Config(workspace.root_uri, {}, 1234, {})

    # Make sure we get a warning for 'indentation contains tabs'
    diags = pycodestyle_lint.pyls_lint(config, doc)
    assert [d for d in diags if d['code'] == 'W191']

    content = {
        'setup.cfg': ('[pycodestyle]\nignore = W191, E201, E128', True),
        'tox.ini': ('', False)
    }

    for conf_file, (content, working) in list(content.items()):
        # Now we'll add config file to ignore it
        with open(os.path.join(workspace.root_path, conf_file), 'w+') as f:
            f.write(content)
        config.settings.cache_clear()

        # And make sure we don't get any warnings
        diags = pycodestyle_lint.pyls_lint(config, doc)
        assert len([d for d in diags
                    if d['code'] == 'W191']) == (0 if working else 1)
        assert len([d for d in diags
                    if d['code'] == 'E201']) == (0 if working else 1)
        assert [d for d in diags if d['code'] == 'W391']

        os.unlink(os.path.join(workspace.root_path, conf_file))

    # Make sure we can ignore via the PYLS config as well
    config.update({'plugins': {'pycodestyle': {'ignore': ['W191', 'E201']}}})
    # And make sure we only get one warning
    diags = pycodestyle_lint.pyls_lint(config, doc)
    assert not [d for d in diags if d['code'] == 'W191']
    assert not [d for d in diags if d['code'] == 'E201']
    assert [d for d in diags if d['code'] == 'W391']
Exemple #2
0
def pyls_lint(config: Config, workspace: Workspace, document: Document,
              is_saved: bool) -> List[Dict[str, Any]]:
    """
    Lints.

    Parameters
    ----------
    config : Config
        The pyls config.
    workspace : Workspace
        The pyls workspace.
    document : Document
        The document to be linted.
    is_saved : bool
        Weather the document is saved.

    Returns
    -------
    List[Dict[str, Any]]
        List of the linting data.

    """
    settings = config.plugin_settings('pyls_mypy')
    live_mode = settings.get('live_mode', True)
    args = settings.get('args', [])
    args.extend([
        '--incremental', '--show-column-numbers', '--follow-imports', 'silent'
    ])

    global tmpFile
    if live_mode and not is_saved and tmpFile:
        tmpFile = open(tmpFile.name, "w")
        tmpFile.write(document.source)
        tmpFile.close()
        args.extend(['--shadow-file', document.path, tmpFile.name])
    elif not is_saved:
        return []

    if mypyConfigFile:
        args.append('--config-file')
        args.append(mypyConfigFile)
    args.append(document.path)
    if settings.get('strict', False):
        args.append('--strict')

    report, errors, _ = mypy_api.run(args)

    diagnostics = []
    for line in report.splitlines():
        diag = parse_line(line, document)
        if diag:
            diagnostics.append(diag)

    return diagnostics
Exemple #3
0
def config(workspace):  # pylint: disable=redefined-outer-name
    """Return a config object."""
    return Config(workspace.root_uri, {}, 0, {})
Exemple #4
0
def workspace_other_root_path(tmpdir):
    """Return a workspace with a root_path other than tmpdir."""
    ws_path = str(tmpdir.mkdir('test123').mkdir('test456'))
    ws = Workspace(uris.from_fs_path(ws_path), Mock())
    ws._config = Config(ws.root_uri, {}, 0, {})
    return ws
Exemple #5
0
def workspace(tmpdir):
    """Return a workspace."""
    ws = Workspace(uris.from_fs_path(str(tmpdir)), Mock())
    ws._config = Config(ws.root_uri, {}, 0, {})
    return ws
Exemple #6
0
def config(workspace):
    """Return a config object."""
    return Config(workspace.root_uri, {})
Exemple #7
0
def pyls_document_symbols(config: Config, workspace: Workspace,
                          document: Document) -> List[Dict]:
    """Cell and block comment extraction."""

    settings = config.plugin_settings('pyls_spyder')
    group_cells = settings.get('group_cells', True)
    enable_block_comments = settings.get('enable_block_comments', True)
    lines = document.lines
    cells = []
    blocks = []

    cell_stack = []
    unnamed_cell = 1
    unnamed_block = 1

    for line_num, line in enumerate(lines):
        cell_rule, cell_match = CELL_REGEX.match(line)
        block_rule, block_match = BLOCK_REGEX.match(line)

        if cell_match is not None:
            percentages = cell_match.group(1)
            cell_name = cell_match.group(2).strip()

            if cell_name == '':
                cell_name = 'Unnamed cell {0}'.format(unnamed_cell)
                unnamed_cell += 1

            if not group_cells or cell_rule != CELL_PERCENTAGE:
                cells.append(
                    create_symbol(cell_name, document, line_num, line_num + 1))
            else:
                current_line, current_level, current_name = peek_symbol(
                    cell_stack)
                cell_level = len(percentages) - 1
                if cell_level > current_level:
                    cell_stack.insert(0, (line_num, cell_level, cell_name))
                else:
                    while current_level >= cell_level:
                        cell_stack.pop(0)
                        cells.append(
                            create_symbol(current_name, document, current_line,
                                          line_num))
                        (current_line, current_level,
                         current_name) = peek_symbol(cell_stack)
                    cell_stack.insert(0, (line_num, cell_level, cell_name))
        elif block_match is not None and enable_block_comments:
            block_name = block_match.group(1).strip()
            if block_name == '':
                block_name = 'Unnamed comment {0}'.format(unnamed_block)
                unnamed_block += 1
            blocks.append(
                create_symbol(block_name, document, line_num, line_num + 1,
                              False))

    for line, _, name in cell_stack:
        cells.append(create_symbol(name, document, line, line_num + 1))

    spyder_symbols = cells + blocks
    spyder_symbols = sorted(
        spyder_symbols, key=lambda x: x['location']['range']['start']['line'])
    return spyder_symbols
Exemple #8
0
def pyls_lint(config: Config, workspace: Workspace, document: Document,
              is_saved: bool) -> List[Dict[str, Any]]:
    """
    Lints.

    Parameters
    ----------
    config : Config
        The pyls config.
    workspace : Workspace
        The pyls workspace.
    document : Document
        The document to be linted.
    is_saved : bool
        Weather the document is saved.

    Returns
    -------
    List[Dict[str, Any]]
        List of the linting data.

    """
    settings = config.plugin_settings('mypy-ls')
    log.info(
        "lint settings = %s document.path = %s is_saved = %s",
        settings,
        document.path,
        is_saved
    )

    live_mode = settings.get('live_mode', True)
    dmypy = settings.get("dmypy", False)

    if dmypy and live_mode:
        # dmypy can only be efficiently run on files that have been saved, see:
        # https://github.com/python/mypy/issues/9309
        log.warning("live_mode is not supported with dmypy, disabling")
        live_mode = False

    args = ['--show-column-numbers']

    prepend = settings.get('prepend')
    if prepend:
        args = prepend + args

    modified_time = os.path.getmtime(document.path)

    global tmpFile
    if live_mode and not is_saved and tmpFile:
        log.info("live_mode tmpFile = %s", live_mode)
        tmpFile = open(tmpFile.name, "w")
        tmpFile.write(document.source)
        tmpFile.close()
        args.extend(['--shadow-file', document.path, tmpFile.name])
    elif (
        not is_saved
        and document.path in last_diagnostics
        and last_updated[document.path] == modified_time
    ):
        # On-launch the document isn't marked as saved, so fall through and run
        # the diagnostics anyway even if the file contents may be out of date.
        log.info(
            "non-live, returning cached diagnostics len(cached) = %s",
            last_diagnostics[document.path]
        )
        return last_diagnostics[document.path]

    last_updated[document.path] = modified_time

    if mypyConfigFile:
        args.append('--config-file')
        args.append(mypyConfigFile)

    args.append(document.path)

    if settings.get('strict', False):
        args.append('--strict')

    if not dmypy:
        args.extend([
            "--incremental",
            "--follow-imports",
            "silent"
        ])

        log.info(f"executing mypy {args=}")
        report, errors, _ = mypy_api.run(args)
    else:
        args = ["run", "--"] + args

        log.info(f"executing dmypy {args=}")
        report, errors, _ = mypy_api.run_dmypy(args)

    log.debug("report: \n" + report)
    log.debug("errors: \n" + errors)

    diagnostics = []
    for line in report.splitlines():
        log.debug(f"parsing: {line=}")
        diag = parse_line(line, document)
        if diag:
            diagnostics.append(diag)

    logging.info("mypy-ls len(diagnostics) = %s", len(diagnostics))

    last_diagnostics[document.path] = diagnostics
    return diagnostics
Exemple #9
0
def workspace(tmpdir):
    """Return a workspace."""
    rootUri = uris.from_fs_path(str(tmpdir))
    config = Config(rootUri, {})
    return Workspace(rootUri, Mock(), config)
Exemple #10
0
def config(tmpdir):
    config = Config(uris.from_fs_path(str(tmpdir)), {}, 0, {})
    config.update(pyls_settings())
    return config