mypy icon indicating copy to clipboard operation
mypy copied to clipboard

AttributeError: attribute '_fullname' of 'TypeInfo' undefined

Open MarcSkovMadsen opened this issue 3 years ago • 1 comments

Crash Report

I'm running mypy on my code but it fails with an INTERNAL ERROR.

Traceback

$ mypy src/mt_devops tests --show-traceback
src/mt_devops/cli/tasks/test.py:167: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.991
Traceback (most recent call last):
  File "mypy/checkexpr.py", line 4665, in accept
  File "mypy/nodes.py", line 2121, in accept
  File "mypy/checkexpr.py", line 3903, in visit_list_expr
  File "mypy/checkexpr.py", line 3944, in check_lst_expr
  File "mypy/checkexpr.py", line 3934, in fast_container_type
  File "mypy/join.py", line 674, in join_type_list
  File "mypy/join.py", line 252, in join_types
  File "mypy/types.py", line 1283, in accept
  File "mypy/join.py", line 327, in visit_instance
  File "mypy/join.py", line 104, in join_instances
  File "mypy/subtypes.py", line 179, in is_subtype
  File "mypy/subtypes.py", line 329, in _is_subtype
  File "mypy/types.py", line 1283, in accept
  File "mypy/subtypes.py", line 466, in visit_instance
  File "mypy/nodes.py", line 2898, in fullname
AttributeError: attribute '_fullname' of 'TypeInfo' undefined
src/mt_devops/cli/tasks/test.py:167: : note: use --pdb to drop into pd

To Reproduce

I run mypy again.

Please note if I delete the .mypy_cache the problem goes away. But some time later it comes back.

The code of the current module is

"""Module of test tasks to check CODE QUALITY.
"""

import pathlib
from typing import Optional, Union

from invoke import task

from ...api.shared import FILES, PACKAGE_FOLDER, run_in_context
from . import autoformat
from . import docs as _docs

TEST_FOLDERS = "tests"
TEST_RESULTS_FOLDER = "test_results"
ON_LAPTOP = not pathlib.Path("/home/jovyan/shared").exists()


def _create_test_results_folder(
    cwd: Optional[Union[str, pathlib.Path]] = None, name=TEST_RESULTS_FOLDER
):
    """Creates a subfolder with the specific name in the cwd folder"""
    if not cwd:
        cwd = pathlib.Path.cwd()
    else:
        cwd = pathlib.Path(cwd)

    pathlib.Path(cwd / name).mkdir(exist_ok=True)


@task(name="bandit")
def _bandit(context, report=False):
    """Runs Bandit the security linter from PyCQA.

    Args:
        report (bool, optional): If True an xml report will be created. Defaults to False.
    """
    print(
        """
Running Bandit the Python Security Linter
to identify common security issues in Python code
=================================================
"""
    )
    command = "bandit -r ./ -c pyproject.toml --severity-level=medium"
    if report:
        command += " -f xml -o test_results/bandit-results.xml"
    run_in_context(command=command, context=context)


@task(name="pytest")
def _pytest(
    context,
    test_files=TEST_FOLDERS,
    fast=False,
    test_results=False,
    show_test_results=False,
    report=False,
):
    """Runs pytest to identify failing tests

    Keyword Arguments:
        root_dir {str} -- The directory from which to run the tests
        test_files {str} -- A space separated list of folders and files to test. (default: {'tests})
        fast {bool} -- If True tests marked slow will not be
            run. (default: False)
        test_results {bool} -- If True test reports will be generated in the test_results
            folder. (default: False)
        show_test_results {bool} -- If True test results will be generated in the test_results
            folder and opened in a browser. (default: False)
        report (bool, optional): If True an xml report will be created. Defaults to False.
    """
    print(
        """
Running pytest the test framework
=================================
"""
    )
    # Build the command_string
    command = f"pytest {test_files}"
    if fast:
        command += ' -m "not slow"'
    if test_results or show_test_results:
        _create_test_results_folder()
        command += f" --cov=src --cov-report html:{TEST_RESULTS_FOLDER}/cov_html"
    if report:
        command += (
            """ -m "not skip_in_azure_pipelines" """
            "--junitxml=test_results/pytest-results.xml "
            f"--cov={PACKAGE_FOLDER} --cov-report xml:test_results/coverage.xml"
            ""
        )

    # Run the command_string
    run_in_context(command=command, context=context)

    # Open the test coverage report in a browser
    if show_test_results:
        command = "start test_results/cov_html/index.html"
        run_in_context(command=command, context=context)


@task(name="pylint")
def _pylint(context, files=FILES, report=False):
    """Runs pylint (linter) on all .py files recursively to identify coding errors

    Arguments:
        files {string} -- A space separated list of files and folders to lint
        report (bool, optional): If True an xml report will be created. Defaults to False.

    """
    # https://stackoverflow.com/questions/22241435/pylint-discard-cached-file-state
    # from astroid import MANAGER
    # MANAGER.astroid_cache.clear()
    print(
        """
Running pylint.
Pylint looks for programming errors, helps enforcing a coding standard,
sniffs for code smells and offers simple refactoring suggestions.
=======================================================================
"""
    )
    command = f"pylint {files} -f text"
    if report:
        _create_test_results_folder()
        command += (
            " --output-format=pylint2junit.JunitReporter 2>&1 > test_results/pylint-results.xml"
        )
    run_in_context(command=command, context=context)


@task(name="mypy")
def _mypy(context, files=FILES, report=False):
    """Runs mypy (static type checker) on all .py files recursively

    Arguments:
        files {string} -- A space separated list of files and folders to lint
        report (bool, optional): If True an xml report will be created. Defaults to False.

    """
    print(
        """
Running mypy for identifying python type errors
===============================================
"""
    )
    command = f"mypy {files}"
    if report:
        _create_test_results_folder()
        command += " --junit-xml test_results/mypy-results.xml"
    run_in_context(command=command, context=context)


@task(pre=[_docs.build])
def docs(context):
    """Checks for broken internal and external links and runs the doc8 .rst linter to identify
    problems.

    Runs
    - the Sphinx 'dummy' builder to identify internal problems.
    - the Sphinx 'linkcheck' build to identify broken external links.
    - doc8 linter to identify .rst syntax errors
    """
    _docs._test(context)  # pylint: disable=protected-access


@task(
    pre=[autoformat._all, _pylint, _mypy, _bandit, docs],  # pylint: disable=protected-access
    name="all",
)
def _all(context, fast=False, test_results=True, show_test_results=True):
    """Runs all tests, i.e. isort, autoflake, black, pylint, mypy, pytest and bandit

    Arguments:
        fast {bool} -- If True tests marked slow will not be
            run. (default: False)
        test_results {bool} -- If True test reports will be generated in the test_results
            folder. (default: False)
        show_test_results {bool} -- If True test results will be generated in the test_results
            folder and opened in a browser. (default: False)
    """
    show_test_results = show_test_results and ON_LAPTOP

    _pytest(context, fast=fast, test_results=test_results, show_test_results=show_test_results)
    # If we get to this point all tests listed in 'pre' have passed
    # unless we have run the task with the --warn flag
    if not context.config.run.warn:
        print(
            """
All Tests Passed Successfully
=============================
"""
        )

Your Environment

  • Mypy version used: 0.991
  • Mypy command-line flags: mypy src/mt_devops tests --show-traceback
  • Mypy configuration options from pyproject.toml:
[tool.mypy]
python_version = "3.9"
namespace_packages = true
explicit_package_bases = true
mypy_path = "src"
exclude = ["src/mt_devops/templates"]

[[tool.mypy.overrides]]
module = [
    "cookiecutter.main",
    "pyparsing",
]
ignore_missing_imports = true
  • Python version used: 3.10.6
  • Operating system and version: Ubuntu 22.04.1 LTS

MarcSkovMadsen avatar Dec 15 '22 06:12 MarcSkovMadsen

I'm not able to reproduce from the file you've shared. The expected directory structure was a little confusing to me too, so possibly I messed that up. Maybe you could provide a link to a git repo (or possible a script that constructs the directory structure you expect)?

hauntsaninja avatar Dec 19 '22 20:12 hauntsaninja