diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ae62eb5..cb8c77c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,12 +27,12 @@ jobs: python-version: [3.6, 3.7, 3.8, 3.9, "3.10"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: "recursive" - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -45,7 +45,7 @@ jobs: - name: Install Poetry shell: bash run: | - curl -fsSL https://install.python-poetry.org | python - -y + curl -fsSL https://install.python-poetry.org | python - -y --version 1.1.15 - name: Update PATH if: ${{ matrix.os != 'Windows' }} run: echo "$HOME/.local/bin" >> $GITHUB_PATH @@ -59,7 +59,7 @@ jobs: run: | poetry config virtualenvs.in-project true - name: Set up cache - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache with: path: .venv diff --git a/tests/test_items.py b/tests/test_items.py index e6d7df7..e3f93c7 100644 --- a/tests/test_items.py +++ b/tests/test_items.py @@ -708,6 +708,14 @@ def test_strings_behave_like_strs(): assert doc.as_string() == 'str = "foo bar" # Comment' +def test_string_add_preserve_escapes(): + i = api.value('"foo\\"bar"') + i += " baz" + + assert i == 'foo"bar baz' + assert i.as_string() == '"foo\\"bar baz"' + + def test_tables_behave_like_dicts(): t = item({"foo": "bar"}) diff --git a/tomlkit/items.py b/tomlkit/items.py index 1d6fca0..48bdfc6 100644 --- a/tomlkit/items.py +++ b/tomlkit/items.py @@ -1779,18 +1779,16 @@ def value(self) -> str: def as_string(self) -> str: return f"{self._t.value}{decode(self._original)}{self._t.value}" - def __add__(self, other): + def __add__(self: ItemT, other: str) -> ItemT: + if not isinstance(other, str): + return NotImplemented result = super().__add__(other) + original = self._original + getattr(other, "_original", other) - return self._new(result) + return self._new(result, original) - def __sub__(self, other): - result = super().__sub__(other) - - return self._new(result) - - def _new(self, result): - return String(self._t, result, result, self._trivia) + def _new(self, result: str, original: str) -> "String": + return String(self._t, result, original, self._trivia) def _getstate(self, protocol=3): return self._t, str(self), self._original, self._trivia