Ejemplo n.º 1
0
    def include_multiple_styles(self, chosen_styles: StrOrList) -> None:
        """Include a list of styles (or just one) into this style tree."""
        style_uris = [chosen_styles] if isinstance(
            chosen_styles, str) else chosen_styles  # type: List[str]
        for style_uri in style_uris:
            style_path = self.get_style_path(style_uri)  # type: Optional[Path]
            if not style_path:
                continue

            toml = TomlFormat(path=style_path)
            try:
                toml_dict = toml.as_data
            except TomlDecodeError as err:
                Nitpick.current_app().add_style_error(
                    style_path.name, pretty_exception(err, "Invalid TOML"))
                # If the TOML itself could not be parsed, we can't go on
                return

            try:
                display_name = str(
                    style_path.relative_to(Nitpick.current_app().root_dir))
            except ValueError:
                display_name = style_uri
            self.validate_style(display_name, toml_dict)
            self._all_styles.add(toml_dict)

            sub_styles = search_dict(NITPICK_STYLES_INCLUDE_JMEX, toml_dict,
                                     [])  # type: StrOrList
            if sub_styles:
                self.include_multiple_styles(sub_styles)
Ejemplo n.º 2
0
    def check_exists(self) -> YieldFlake8Error:
        """Check if the file should exist."""
        for _ in self.multiple_files:
            config_data_exists = bool(self.file_dict or self.nitpick_file_dict)
            should_exist = Nitpick.current_app(
            ).config.nitpick_files_section.get(
                TomlFormat.group_name_for(self.file_name), True)  # type: bool
            file_exists = self.file_path.exists()

            if config_data_exists and not file_exists:
                suggestion = self.suggest_initial_contents()
                phrases = [" was not found"]
                message = Nitpick.current_app(
                ).config.nitpick_files_section.get(self.file_name)
                if message and isinstance(message, str):
                    phrases.append(message)
                if suggestion:
                    phrases.append("Create it with this content:")
                yield self.flake8_error(1, ". ".join(phrases), suggestion)
            elif not should_exist and file_exists:
                # Only display this message if the style is valid.
                if not Nitpick.current_app().style_errors:
                    yield self.flake8_error(2, " should be deleted")
            elif file_exists and config_data_exists:
                yield from self.check_rules()
Ejemplo n.º 3
0
 def validate_pyproject_tool_nitpick(self) -> bool:
     """Validate the ``pyroject.toml``'s ``[tool.nitpick]`` section against a Marshmallow schema."""
     pyproject_path = Nitpick.current_app().root_dir / PyProjectTomlFile.file_name  # type: Path
     if pyproject_path.exists():
         self.pyproject_toml = TomlFormat(path=pyproject_path)
         self.tool_nitpick_dict = search_dict(TOOL_NITPICK_JMEX, self.pyproject_toml.as_data, {})
         pyproject_errors = ToolNitpickSectionSchema().validate(self.tool_nitpick_dict)
         if pyproject_errors:
             Nitpick.current_app().add_style_error(
                 PyProjectTomlFile.file_name,
                 "Invalid data in [{}]:".format(TOOL_NITPICK),
                 flatten_marshmallow_errors(pyproject_errors),
             )
             return False
     return True
Ejemplo n.º 4
0
    def _set_current_data(self, file_name: str) -> None:
        """Set data for the current file name, either if there are multiple or single files."""
        if self.has_multiple_files:
            self.file_name = file_name

        self.error_prefix = "File {}".format(self.file_name)
        self.file_path = Nitpick.current_app().root_dir / self.file_name

        # Configuration for this file as a TOML dict, taken from the style file.
        self.file_dict = Nitpick.current_app().config.style_dict.get(
            TomlFormat.group_name_for(self.file_name), {})

        # Nitpick configuration for this file as a TOML dict, taken from the style file.
        self.nitpick_file_dict = search_dict(
            'files."{}"'.format(self.file_name),
            Nitpick.current_app().config.nitpick_section, {})
Ejemplo n.º 5
0
    def file_field_pair(
            file_name: str,
            base_file_class: Type[BaseFile]) -> Dict[str, fields.Field]:
        """Return a schema field with info from a config file class."""
        valid_toml_key = TomlFormat.group_name_for(file_name)
        unique_file_name_with_underscore = slugify(file_name, separator="_")

        kwargs = {"data_key": valid_toml_key}
        if base_file_class.nested_field:
            field = fields.Nested(base_file_class.nested_field, **kwargs)
        else:
            # For default files (pyproject.toml, setup.cfg...), there is no strict schema;
            # it can be anything they allow.
            # It's out of Nitpick's scope to validate those files.
            field = fields.Dict(fields.String, **kwargs)
        return {unique_file_name_with_underscore: field}
Ejemplo n.º 6
0
    def include_multiple_styles(self, chosen_styles: StrOrList) -> None:
        """Include a list of styles (or just one) into this style tree."""
        style_uris = [chosen_styles] if isinstance(
            chosen_styles, str) else chosen_styles  # type: List[str]
        for style_uri in style_uris:
            style_path = self.get_style_path(style_uri)  # type: Optional[Path]
            if not style_path:
                continue

            toml = TomlFormat(path=style_path)
            self._all_styles.add(toml.as_data)

            sub_styles = search_dict(NITPICK_STYLES_INCLUDE_JMEX, toml.as_data,
                                     [])  # type: StrOrList
            if sub_styles:
                self.include_multiple_styles(sub_styles)
Ejemplo n.º 7
0
    def merge_toml_dict(self) -> JsonDict:
        """Merge all included styles into a TOML (actually JSON) dictionary."""
        if not self.config.cache_dir:
            return {}
        merged_dict = self._all_styles.merge()
        merged_style_path = self.config.cache_dir / MERGED_STYLE_TOML  # type: Path
        toml = TomlFormat(data=merged_dict)

        attempt = 1
        while attempt < 5:
            try:
                self.config.cache_dir.mkdir(parents=True, exist_ok=True)
                merged_style_path.write_text(toml.reformatted)
                break
            except OSError:
                attempt += 1

        return merged_dict
Ejemplo n.º 8
0
    def merge_styles(self) -> YieldFlake8Error:
        """Merge one or multiple style files."""
        pyproject_path = self.root_dir / PyProjectTomlFile.file_name  # type: Path
        if pyproject_path.exists():
            self.pyproject_toml = TomlFormat(path=pyproject_path)
            self.tool_nitpick_dict = search_dict(TOOL_NITPICK_JMEX,
                                                 self.pyproject_toml.as_data,
                                                 {})
            schema = ToolNitpickSchema()
            pyproject_errors = schema.validate(self.tool_nitpick_dict)
            if pyproject_errors:
                self.has_style_errors = True
                yield self.style_error(
                    PyProjectTomlFile.file_name,
                    "Invalid data in [{}]:".format(TOOL_NITPICK),
                    schema.flatten_errors(pyproject_errors),
                )
                return

        configured_styles = self.tool_nitpick_dict.get("style",
                                                       "")  # type: StrOrList
        style = Style(self)
        style.find_initial_styles(configured_styles)
        self.style_dict = style.merge_toml_dict()

        from nitpick.plugin import NitpickChecker

        minimum_version = search_dict(NITPICK_MINIMUM_VERSION_JMEX,
                                      self.style_dict, None)
        if minimum_version and version_to_tuple(
                NitpickChecker.version) < version_to_tuple(minimum_version):
            yield self.flake8_error(
                3,
                "The style file you're using requires {}>={}".format(
                    PROJECT_NAME, minimum_version) +
                " (you have {}). Please upgrade".format(
                    NitpickChecker.version),
            )

        self.nitpick_dict = self.style_dict.get("nitpick", {})
        self.files = self.nitpick_dict.get("files", {})
Ejemplo n.º 9
0
 def assert_merged_style(self, toml_string: str):
     """Assert the contents of the merged style file."""
     expected = TomlFormat(path=self.cache_dir / MERGED_STYLE_TOML)
     actual = TomlFormat(string=dedent(toml_string))
     compare(expected.as_data, actual.as_data)