Skip to content

Commit

Permalink
Avoid problems with duplicated augmentation
Browse files Browse the repository at this point in the history
  • Loading branch information
abravalheri committed Feb 7, 2022
1 parent 543c5b6 commit 0a91662
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
6 changes: 4 additions & 2 deletions src/ini2toml/base_translator.py
@@ -1,6 +1,6 @@
from functools import reduce
from types import MappingProxyType
from typing import Dict, Generic, List, Mapping, Sequence, TypeVar
from typing import Dict, Generic, List, Mapping, Sequence, TypeVar, cast

from . import types # Structural/Abstract types
from .errors import (
Expand Down Expand Up @@ -144,7 +144,9 @@ def translate(
active_augmentations: Mapping[str, bool] = EMPTY,
) -> T:
UndefinedProfile.check(profile_name, list(self.profiles.keys()))
profile = self._add_augmentations(self[profile_name], active_augmentations)
profile = cast(Profile, self[profile_name])._copy()
# ^--- avoid permanent changes and conflicts with duplicated augmentation
self._add_augmentations(profile, active_augmentations)

ini = reduce(apply, profile.pre_processors, ini)
irepr = self.loads(ini)
Expand Down
15 changes: 13 additions & 2 deletions src/ini2toml/profile.py
@@ -1,4 +1,5 @@
import inspect
from copy import deepcopy
from typing import Optional, Sequence, TypeVar

from .types import IntermediateProcessor, ProfileAugmentationFn, TextProcessor
Expand Down Expand Up @@ -37,6 +38,16 @@ def __init__(

replace = replace

def _copy(self: P) -> P:
return self.__class__(
name=self.name,
help_text=self.help_text,
pre_processors=self.pre_processors[:],
intermediate_processors=self.intermediate_processors[:],
post_processors=self.post_processors[:],
ini_parser_opts=deepcopy(self.ini_parser_opts),
)


class ProfileAugmentation:
def __init__(
Expand All @@ -48,8 +59,8 @@ def __init__(
):
self.fn = fn
self.active_by_default = active_by_default
self.name = name
self.help_text = help_text
self.name = name or getattr(fn, "__name__", "")
self.help_text = help_text or getattr(fn, "__doc__", "")

def is_active(self, explicitly_active: Optional[bool] = None) -> bool:
"""``explicitly_active`` is a tree-state variable: ``True`` if the user
Expand Down
42 changes: 42 additions & 0 deletions tests/test_translator.py
Expand Up @@ -3,6 +3,8 @@
import pytest

from ini2toml.errors import UndefinedProfile
from ini2toml.plugins import profile_independent_tasks
from ini2toml.profile import Profile, ProfileAugmentation
from ini2toml.translator import Translator


Expand Down Expand Up @@ -88,3 +90,43 @@ def test_undefined_profile():
translator = Translator()
with pytest.raises(UndefinedProfile):
translator.translate("", "!!--UNDEFINED ??? PROFILE--!!")


simple_setupcfg = """\
[metadata]
summary = Automatically translates .cfg/.ini files into TOML
author_email = example@example
license-file = LICENSE.txt
long_description_content_type = text/x-rst; charset=UTF-8
home_page = https://github.com/abravalheri/ini2toml/
classifier = Development Status :: 4 - Beta
platform = any
"""


def test_reuse_object():
"""Make sure the same translator object can be reused multiple times"""
profile = Profile("setup.cfg")
augmentations = []
for task in ("normalise_newlines", "remove_empty_table_headers"):
fn = getattr(profile_independent_tasks, task)
aug = ProfileAugmentation(
profile_independent_tasks.post_process(fn), active_by_default=True
)
augmentations.append(aug)

translator = Translator(
profiles=[profile], plugins=(), profile_augmentations=augmentations
)
active_augmentations = {aug.name: True for aug in augmentations}
for _ in range(5):
out = translator.translate(simple_setupcfg, "setup.cfg", active_augmentations)
assert len(out) > 0
processors = [
*profile.post_processors,
*profile.intermediate_processors,
*profile.pre_processors,
]
deduplicated = {getattr(p, "__name__", ""): p for p in processors}
# Make sure there is no duplication in the processors
assert len(processors) == len(deduplicated)

0 comments on commit 0a91662

Please sign in to comment.