Source code for ini2toml.plugins.pytest

# https://docs.pytest.org/en/latest/reference/reference.html#configuration-options
# https://docs.pytest.org/en/latest/reference/customize.html#config-file-formats
import logging
from collections.abc import MutableMapping
from functools import partial
from typing import TypeVar, Union

from ..transformations import coerce_scalar, remove_comments, split_comment, split_list
from ..types import Commented, IntermediateRepr, Translator

R = TypeVar("R", bound=IntermediateRepr)

_logger = logging.getLogger(__name__)

_split_spaces = partial(split_list, sep=" ")
_split_lines = partial(split_list, sep="\n")
# ^ most of the list values in pytest use whitespace separators,
#   but markers/filterwarnings are a special case.


[docs] def activate(translator: Translator): plugin = Pytest() for file in ("setup.cfg", "tox.ini", "pytest.ini"): translator[file].intermediate_processors.append(plugin.process_values) translator["pytest.ini"].help_text = plugin.__doc__ or ""
class Pytest: """Convert settings to 'pyproject.toml' ('ini_options' table)""" LINE_SEPARATED_LIST_VALUES = ( "markers", "filterwarnings", ) SPACE_SEPARATED_LIST_VALUES = ( "norecursedirs", "python_classes", "python_files", "python_functions", "required_plugins", "testpaths", "usefixtures", ) DONT_TOUCH = ("minversion",) def process_values(self, doc: R) -> R: candidates = [ (("pytest", "ini_options"), "pytest", doc), (("tool", "pytest", "ini_options"), "tool:pytest", doc), (("tool", "pytest", "ini_options"), ("tool", "pytest"), doc), (("pytest", "ini_options"), "pytest", doc.get("tool", {})), ] for new_key, old_key, parent in candidates: section = parent.get(old_key) if section: self.process_section(section) parent.rename(old_key, new_key) return doc def process_section(self, section: MutableMapping): for field in section: if field in self.DONT_TOUCH: continue if field in self.LINE_SEPARATED_LIST_VALUES: section[field] = _split_lines(section[field]) elif field in self.SPACE_SEPARATED_LIST_VALUES: section[field] = _split_spaces(section[field]) elif hasattr(self, f"_process_{field}"): section[field] = getattr(self, f"_process_{field}")(section[field]) else: section[field] = coerce_scalar(section[field]) def _process_addopts(self, content: str) -> Union[Commented[str], str]: # pytest-dev/pytest#12228: pytest maintainers recommend addopts as string. # However, it cannot handle embedded comments, so we have to strip them. if "\n" not in content: # It is easy to handle inline comments for a single line. return split_comment(content) if "#" not in content: return content msg = ( "Stripping comments from `tool.pytest.ini_options.addopts`.\n" "This field is recommended to be a string, however it cannot " "contain embedded comments (ref: pytest-dev/pytest#12228)." ) _logger.warning(msg) return remove_comments(content)