From 98ac04cfb402675d36f9126f1fbec0532540e9e5 Mon Sep 17 00:00:00 2001 From: Maxim Kurnikov Date: Wed, 24 Jul 2019 21:57:16 +0300 Subject: [PATCH] allow to set additional mypy config per test (#6) --- pytest_mypy/collect.py | 4 +++- pytest_mypy/item.py | 25 +++++++++++++++++++++---- pytest_mypy/tests/test-simple-cases.yml | 15 +++++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/pytest_mypy/collect.py b/pytest_mypy/collect.py index 06570e1..de16342 100644 --- a/pytest_mypy/collect.py +++ b/pytest_mypy/collect.py @@ -71,6 +71,7 @@ def collect(self): extra_environment_variables = parse_environment_variables(raw_test.get('env', [])) disable_cache = raw_test.get('disable_cache', False) expected_output_lines = raw_test.get('out', '').split('\n') + additional_mypy_config = raw_test.get('mypy_config', '') yield YamlTestItem(name=test_name, collector=self, @@ -80,7 +81,8 @@ def collect(self): environment_variables=extra_environment_variables, disable_cache=disable_cache, expected_output_lines=output_from_comments + expected_output_lines, - parsed_test_data=raw_test) + parsed_test_data=raw_test, + mypy_config=additional_mypy_config) def pytest_collect_file(path, parent): diff --git a/pytest_mypy/item.py b/pytest_mypy/item.py index f0f7993..d57adf8 100644 --- a/pytest_mypy/item.py +++ b/pytest_mypy/item.py @@ -3,8 +3,9 @@ import subprocess import sys import tempfile +from configparser import ConfigParser from pathlib import Path -from typing import Any, Dict, List, Tuple, Callable +from typing import Any, Dict, List, Tuple, Callable, Optional import capturer import pytest @@ -96,6 +97,7 @@ def __init__(self, expected_output_lines: List[str], environment_variables: Dict[str, Any], disable_cache: bool, + mypy_config: str, parsed_test_data: Dict[str, Any]) -> None: super().__init__(name, collector, config) self.files = files @@ -103,6 +105,7 @@ def __init__(self, self.disable_cache = disable_cache self.expected_output_lines = expected_output_lines self.starting_lineno = starting_lineno + self.additional_mypy_config = mypy_config self.parsed_test_data = parsed_test_data self.same_process = self.config.option.mypy_same_process @@ -201,7 +204,7 @@ def runtest(self): with utils.cd(execution_path): # start from main.py main_file = str(execution_path / 'main.py') - mypy_cmd_options = self.prepare_mypy_cmd_options() + mypy_cmd_options = self.prepare_mypy_cmd_options(execution_path) mypy_cmd_options.append(main_file) # extension point for derived packages @@ -242,7 +245,7 @@ def runtest(self): assert not os.path.exists(temp_dir.name) - def prepare_mypy_cmd_options(self) -> List[str]: + def prepare_mypy_cmd_options(self, execution_path: Path) -> List[str]: mypy_cmd_options = [ '--show-traceback', '--no-silence-site-packages', @@ -255,8 +258,22 @@ def prepare_mypy_cmd_options(self) -> List[str]: python_version = '.'.join([str(part) for part in sys.version_info[:2]]) mypy_cmd_options.append(f'--python-version={python_version}') + + # merge self.base_ini_fpath and self.additional_mypy_config into one file and copy to the typechecking folder + mypy_ini_config = ConfigParser() if self.base_ini_fpath: - mypy_cmd_options.append(f'--config-file={self.base_ini_fpath}') + mypy_ini_config.read(self.base_ini_fpath) + if self.additional_mypy_config: + additional_config = self.additional_mypy_config + if '[mypy]' not in additional_config: + additional_config = '[mypy]\n' + additional_config + mypy_ini_config.read_string(additional_config) + + if mypy_ini_config.sections(): + mypy_config_file_path = execution_path / 'mypy.ini' + with mypy_config_file_path.open('w') as f: + mypy_ini_config.write(f) + mypy_cmd_options.append(f'--config-file={str(mypy_config_file_path)}') return mypy_cmd_options diff --git a/pytest_mypy/tests/test-simple-cases.yml b/pytest_mypy/tests/test-simple-cases.yml index 6f862a2..655c2b2 100644 --- a/pytest_mypy/tests/test-simple-cases.yml +++ b/pytest_mypy/tests/test-simple-cases.yml @@ -49,8 +49,15 @@ pass - path: myapp/apps.py -- case: error_case - main: | - a = 1 - a.lower() # E: "int" has no attribute "lower" +- case: error_case + main: | + a = 1 + a.lower() # E: "int" has no attribute "lower" +- case: custom_mypy_config_strict_optional_true_set + main: | + from typing import Optional + a: Optional[int] = None + a + 1 + mypy_config: | + strict_optional = False