deepl-haystack 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. deepl_haystack-0.4.0/.github/CODEOWNERS +15 -0
  2. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.github/dependabot.yml +2 -2
  3. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.github/workflows/bump.yml +6 -6
  4. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.github/workflows/lint.yml +2 -2
  5. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.github/workflows/publish.yml +2 -2
  6. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.github/workflows/release.yml +4 -4
  7. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.github/workflows/test.yml +5 -5
  8. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.pre-commit-config.yaml +7 -3
  9. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/PKG-INFO +2 -4
  10. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/pyproject.toml +7 -8
  11. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/tests/test_deepl_document_translator.py +29 -3
  12. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/tests/test_deepl_text_translator.py +32 -7
  13. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/uv.lock +285 -227
  14. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/.gitignore +0 -0
  15. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/LICENSE +0 -0
  16. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/Makefile +0 -0
  17. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/README.md +0 -0
  18. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/deepl_haystack/__init__.py +0 -0
  19. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/deepl_haystack/components.py +0 -0
  20. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/tests/__init__.py +0 -0
  21. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/tests/conftest.py +0 -0
  22. {deepl_haystack-0.3.0 → deepl_haystack-0.4.0}/tests/test_deepl_haystack_init.py +0 -0
@@ -0,0 +1,15 @@
1
+ # Lines starting with '#' are comments.
2
+ # Each line is a file pattern followed by one or more owners.
3
+
4
+ # More details are here: https://help.github.com/articles/about-codeowners/
5
+
6
+ # The '*' pattern is global owners.
7
+
8
+ # Order is important. The last matching pattern has the most precedence.
9
+ # The folders are ordered as follows:
10
+
11
+ # In each subsection folders are ordered first by depth, then alphabetically.
12
+ # This should make it easy to add new rules without breaking existing ones.
13
+
14
+ # Global rule:
15
+ * @dribia/libraries-admin
@@ -16,7 +16,7 @@ updates:
16
16
  commit-message:
17
17
  prefix: ":arrow_up:"
18
18
 
19
- - package-ecosystem: "pip"
19
+ - package-ecosystem: "uv"
20
20
  target-branch: "main"
21
21
  directory: "/" # Location of package manifests
22
22
  schedule:
@@ -34,7 +34,7 @@ updates:
34
34
  prefix: ":arrow_up:"
35
35
  versioning-strategy: "lockfile-only"
36
36
 
37
- - package-ecosystem: "pip"
37
+ - package-ecosystem: "uv"
38
38
  directory: "/" # Location of package manifests
39
39
  schedule:
40
40
  interval: "weekly"
@@ -20,9 +20,9 @@ jobs:
20
20
  contents: 'write'
21
21
  id-token: 'write'
22
22
  steps:
23
- - uses: actions/checkout@v5
23
+ - uses: actions/checkout@v7
24
24
  - name: Install uv
25
- uses: astral-sh/setup-uv@v6
25
+ uses: astral-sh/setup-uv@v7
26
26
  with:
27
27
  enable-cache: true
28
28
  - name: Bump version
@@ -64,7 +64,7 @@ jobs:
64
64
  ENCRYPTED_SECRET=${{ needs.create-release-branch.outputs.encrypted-version }};
65
65
  VERSION=$(echo -n "$ENCRYPTED_SECRET" | base64 --decode | openssl enc -d -a -k "password");
66
66
  echo "version=$VERSION" >> $GITHUB_OUTPUT
67
- - uses: actions/checkout@v4
67
+ - uses: actions/checkout@v7
68
68
  with:
69
69
  ref: main
70
70
  - name: Reset release branch
@@ -72,14 +72,14 @@ jobs:
72
72
  git fetch origin release/${{ steps.decrypt-tag.outputs.version }}:release/${{ steps.decrypt-tag.outputs.version }}
73
73
  git reset --hard release/${{ steps.decrypt-tag.outputs.version }}
74
74
  - name: Generate token for release bot
75
- uses: actions/create-github-app-token@v2
75
+ uses: actions/create-github-app-token@v3
76
76
  id: generate-token
77
77
  with:
78
78
  app-id: ${{ secrets.RELEASE_BOT_APP_ID }}
79
79
  private-key: ${{ secrets.RELEASE_BOT_APP_PRIVATE_KEY }}
80
80
  - name: Create Pull Request
81
81
  id: cpr
82
- uses: peter-evans/create-pull-request@v7
82
+ uses: peter-evans/create-pull-request@v8
83
83
  with:
84
84
  token: ${{ steps.generate-token.outputs.token }}
85
85
  commit-message: ":label: Version bump to ${{ steps.decrypt-tag.outputs.version }}"
@@ -105,7 +105,7 @@ jobs:
105
105
  ENCRYPTED_SECRET=${{ needs.create-release-branch.outputs.encrypted-version }};
106
106
  VERSION=$(echo -n "$ENCRYPTED_SECRET" | base64 --decode | openssl enc -d -a -k "password");
107
107
  echo "version=$VERSION" >> $GITHUB_OUTPUT
108
- - uses: actions/checkout@v4
108
+ - uses: actions/checkout@v7
109
109
  with:
110
110
  fetch-depth: 0
111
111
  - name: Delete release branch
@@ -13,9 +13,9 @@ jobs:
13
13
  lint:
14
14
  runs-on: ubuntu-latest
15
15
  steps:
16
- - uses: actions/checkout@v4
16
+ - uses: actions/checkout@v7
17
17
  - name: Install uv
18
- uses: astral-sh/setup-uv@v6
18
+ uses: astral-sh/setup-uv@v7
19
19
  with:
20
20
  python-version: '3.12'
21
21
  enable-cache: true
@@ -9,9 +9,9 @@ jobs:
9
9
  publish:
10
10
  runs-on: ubuntu-latest
11
11
  steps:
12
- - uses: actions/checkout@v4
12
+ - uses: actions/checkout@v7
13
13
  - name: Install uv
14
- uses: astral-sh/setup-uv@v6
14
+ uses: astral-sh/setup-uv@v7
15
15
  with:
16
16
  enable-cache: true
17
17
  - name: Build
@@ -7,20 +7,20 @@ on:
7
7
 
8
8
  jobs:
9
9
  create-release:
10
- if: contains(github.event.head_commit.message, 'dribia/release/v') && contains(github.event.head_commit.message, '-merge')
10
+ if: contains(github.event.head_commit.message, 'Bumping version from')
11
11
  runs-on: ubuntu-latest
12
12
  permissions:
13
13
  contents: 'write'
14
14
  steps:
15
15
  - name: Checkout
16
- uses: actions/checkout@v4
16
+ uses: actions/checkout@v7
17
17
  - name: Get release tag
18
18
  id: get-tag
19
19
  run: |
20
- TAG=$(echo "${{ github.event.head_commit.message }}" | head -n1 | cut -d"/" -f3 | cut -d"-" -f1);
20
+ TAG=$(echo "${{ github.event.head_commit.message }}" | head -n1 | cut -d" " -f7);
21
21
  echo "tag=$TAG" >> $GITHUB_OUTPUT
22
22
  - name: Release
23
- uses: softprops/action-gh-release@v2
23
+ uses: softprops/action-gh-release@v3
24
24
  with:
25
25
  generate_release_notes: true
26
26
  make_latest: true
@@ -19,9 +19,9 @@ jobs:
19
19
  fail-fast: false
20
20
  runs-on: ${{ matrix.os }}
21
21
  steps:
22
- - uses: actions/checkout@v4
22
+ - uses: actions/checkout@v7
23
23
  - name: Install uv
24
- uses: astral-sh/setup-uv@v6
24
+ uses: astral-sh/setup-uv@v7
25
25
  with:
26
26
  python-version: ${{ matrix.python-version }}
27
27
  enable-cache: true
@@ -29,7 +29,7 @@ jobs:
29
29
  run: uv sync --no-default-groups --group ci --group test
30
30
  - name: Test
31
31
  run: make test-unit
32
- - uses: codecov/codecov-action@v4
32
+ - uses: codecov/codecov-action@v7
33
33
  with:
34
34
  fail_ci_if_error: true
35
35
  token: ${{ secrets.CODECOV_TOKEN }}
@@ -45,9 +45,9 @@ jobs:
45
45
  env:
46
46
  DEEPL_API_KEY: ${{ secrets.DEEPL_API_KEY }}
47
47
  steps:
48
- - uses: actions/checkout@v4
48
+ - uses: actions/checkout@v7
49
49
  - name: Install uv
50
- uses: astral-sh/setup-uv@v6
50
+ uses: astral-sh/setup-uv@v7
51
51
  with:
52
52
  python-version: ${{ matrix.python-version }}
53
53
  enable-cache: true
@@ -16,7 +16,7 @@ repos:
16
16
  - id: end-of-file-fixer
17
17
  - id: trailing-whitespace
18
18
  - repo: https://github.com/astral-sh/uv-pre-commit
19
- rev: 0.8.14
19
+ rev: 0.8.17
20
20
  hooks:
21
21
  - id: uv-lock
22
22
  - id: uv-sync
@@ -34,7 +34,7 @@ repos:
34
34
  hooks:
35
35
  - id: checkmake
36
36
  - repo: https://github.com/astral-sh/ruff-pre-commit
37
- rev: v0.12.11
37
+ rev: v0.13.0
38
38
  hooks:
39
39
  - id: ruff-check
40
40
  types_or: [ python, pyi ]
@@ -43,6 +43,10 @@ repos:
43
43
  - id: ruff-format
44
44
  types_or: [ python, pyi ]
45
45
  - repo: https://github.com/pre-commit/mirrors-mypy
46
- rev: v1.17.1
46
+ rev: v1.18.1
47
47
  hooks:
48
48
  - id: mypy
49
+
50
+ ci:
51
+ autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
52
+ autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: deepl-haystack
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Haystack integration with DeepL translation services provider.
5
5
  Project-URL: Homepage, https://github.com/dribia/deepl-haystack
6
6
  Project-URL: Repository, https://github.com/dribia/deepl-haystack
@@ -23,9 +23,7 @@ Classifier: Programming Language :: Python :: 3.13
23
23
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
24
  Requires-Python: <3.14,>=3.9
25
25
  Requires-Dist: deepl<2,>=1.19.1
26
- Requires-Dist: haystack-ai<3,>=2.0.0
27
- Requires-Dist: pytest-dotenv<0.6,>=0.5.2
28
- Requires-Dist: pytest<9,>=8.4.1
26
+ Requires-Dist: haystack-ai<4,>=2.0.0
29
27
  Description-Content-Type: text/markdown
30
28
 
31
29
  DeepL Haystack Integration
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "deepl-haystack"
3
- version = "0.3.0"
3
+ version = "0.4.0"
4
4
  description = "Haystack integration with DeepL translation services provider."
5
5
  authors = [{ name = "Albert Iribarne", email = "iribarne@dribia.com" }]
6
6
  requires-python = ">=3.9,<3.14"
@@ -30,9 +30,7 @@ classifiers = [
30
30
  ]
31
31
  dependencies = [
32
32
  "deepl>=1.19.1,<2",
33
- "haystack-ai>=2.0.0,<3",
34
- "pytest-dotenv>=0.5.2,<0.6",
35
- "pytest>=8.4.1,<9",
33
+ "haystack-ai>=2.0.0,<4",
36
34
  ]
37
35
 
38
36
  [project.urls]
@@ -43,16 +41,17 @@ Repository = "https://github.com/dribia/deepl-haystack"
43
41
  [dependency-groups]
44
42
  dev = ["pre-commit>=4.3.0,<5"]
45
43
  ci = [
46
- "setuptools>=80.9.0,<81",
44
+ "setuptools>=80.9.0,<83",
47
45
  ]
48
46
  test = [
49
47
  "pytest>=8.3.5,<9",
50
48
  "pytest-mock>=3.14.1,<4",
51
- "pytest-cov>=6.2.1,<7",
49
+ "pytest-cov>=7.0.0,<8",
50
+ "pytest-dotenv>=0.5.2,<0.6",
52
51
  ]
53
52
  lint = [
54
- "ruff==0.12.11",
55
- "mypy==1.17.1",
53
+ "ruff==0.15.10",
54
+ "mypy==1.19.1",
56
55
  ]
57
56
 
58
57
  [tool.uv]
@@ -1,11 +1,12 @@
1
1
  """Test cases for DeepL translator components."""
2
2
 
3
+ import inspect
3
4
  import os
4
5
  from typing import Any
5
6
 
6
7
  import pytest
7
8
  from deepl import DeepLException, Formality, SplitSentences, Translator
8
- from haystack import Document
9
+ from haystack import Document, Pipeline
9
10
  from haystack.utils import Secret
10
11
 
11
12
  from deepl_haystack import DeepLDocumentTranslator
@@ -44,7 +45,7 @@ class TestDeepLDocumentTranslator:
44
45
  def test_init_fail_wo_api_key(self, monkeypatch):
45
46
  monkeypatch.delenv("DEEPL_API_KEY", raising=False)
46
47
  with pytest.raises(
47
- ValueError, match="None of the .* environment variables are set"
48
+ ValueError, match=r"None of the .* environment variables are set"
48
49
  ):
49
50
  DeepLDocumentTranslator()
50
51
 
@@ -214,10 +215,35 @@ class TestDeepLDocumentTranslator:
214
215
  },
215
216
  }
216
217
  with pytest.raises(
217
- ValueError, match="None of the .* environment variables are set"
218
+ ValueError, match=r"None of the .* environment variables are set"
218
219
  ):
219
220
  DeepLDocumentTranslator.from_dict(data)
220
221
 
222
+ def test_pipeline_serialization_roundtrip(self, monkeypatch):
223
+ """The component survives a pipeline serialization round-trip.
224
+
225
+ Haystack 3.x gates pipeline deserialization through a trusted-module
226
+ allowlist that only covers Haystack's own namespaces, so loading a
227
+ pipeline that contains a component from this package requires listing
228
+ it in ``allowed_modules``. Haystack 2.x has no such parameter, so it is
229
+ only passed when supported.
230
+ """
231
+ monkeypatch.setenv("DEEPL_API_KEY", "test-api-key")
232
+ pipeline = Pipeline()
233
+ pipeline.add_component(
234
+ "translator", DeepLDocumentTranslator(target_lang=["ES", "FR"])
235
+ )
236
+
237
+ dumped = pipeline.dumps()
238
+ if "allowed_modules" in inspect.signature(Pipeline.loads).parameters:
239
+ loaded = Pipeline.loads(dumped, allowed_modules=["deepl_haystack"])
240
+ else:
241
+ loaded = Pipeline.loads(dumped)
242
+
243
+ component = loaded.get_component("translator")
244
+ assert isinstance(component, DeepLDocumentTranslator)
245
+ assert component.target_lang == ["ES", "FR"]
246
+
221
247
  def test_run_one_doc(self, monkeypatch, mock_translation, caplog):
222
248
  """Test the run method of the DeepLDocumentTranslator class.
223
249
 
@@ -1,11 +1,13 @@
1
1
  """Test cases for DeepL translator components."""
2
2
 
3
+ import inspect
3
4
  import os
4
5
  from typing import Any
5
6
  from unittest.mock import patch
6
7
 
7
8
  import pytest
8
9
  from deepl import DeepLException, Formality, SplitSentences, Translator
10
+ from haystack import Pipeline
9
11
  from haystack.utils import Secret
10
12
 
11
13
  from deepl_haystack import DeepLTextTranslator
@@ -43,7 +45,7 @@ class TestDeepLTextTranslator:
43
45
  def test_init_fail_wo_api_key(self, monkeypatch):
44
46
  monkeypatch.delenv("DEEPL_API_KEY", raising=False)
45
47
  with pytest.raises(
46
- ValueError, match="None of the .* environment variables are set"
48
+ ValueError, match=r"None of the .* environment variables are set"
47
49
  ):
48
50
  DeepLTextTranslator()
49
51
 
@@ -51,7 +53,7 @@ class TestDeepLTextTranslator:
51
53
  monkeypatch.setenv("DEEPL_API_KEY", "test-api-key")
52
54
  with pytest.raises(
53
55
  ValueError,
54
- match="`target_lang` must be a string representing a language code.",
56
+ match=r"`target_lang` must be a string representing a language code.",
55
57
  ):
56
58
  DeepLTextTranslator(target_lang=None)
57
59
 
@@ -207,10 +209,33 @@ class TestDeepLTextTranslator:
207
209
  },
208
210
  }
209
211
  with pytest.raises(
210
- ValueError, match="None of the .* environment variables are set"
212
+ ValueError, match=r"None of the .* environment variables are set"
211
213
  ):
212
214
  DeepLTextTranslator.from_dict(data)
213
215
 
216
+ def test_pipeline_serialization_roundtrip(self, monkeypatch):
217
+ """The component survives a pipeline serialization round-trip.
218
+
219
+ Haystack 3.x gates pipeline deserialization through a trusted-module
220
+ allowlist that only covers Haystack's own namespaces, so loading a
221
+ pipeline that contains a component from this package requires listing
222
+ it in ``allowed_modules``. Haystack 2.x has no such parameter, so it is
223
+ only passed when supported.
224
+ """
225
+ monkeypatch.setenv("DEEPL_API_KEY", "test-api-key")
226
+ pipeline = Pipeline()
227
+ pipeline.add_component("translator", DeepLTextTranslator(target_lang="ES"))
228
+
229
+ dumped = pipeline.dumps()
230
+ if "allowed_modules" in inspect.signature(Pipeline.loads).parameters:
231
+ loaded = Pipeline.loads(dumped, allowed_modules=["deepl_haystack"])
232
+ else:
233
+ loaded = Pipeline.loads(dumped)
234
+
235
+ component = loaded.get_component("translator")
236
+ assert isinstance(component, DeepLTextTranslator)
237
+ assert component.target_lang == "ES"
238
+
214
239
  def test_run(self, monkeypatch, mock_translation):
215
240
  """Test the run method of the DeepLTextTranslator class."""
216
241
  monkeypatch.setenv("DEEPL_API_KEY", "fake-api-key")
@@ -254,7 +279,7 @@ class TestDeepLTextTranslator:
254
279
  source_lang=DEFAULT_SOURCE_LANG,
255
280
  target_lang="ES",
256
281
  )
257
- with pytest.raises(ValueError, match="Empty text provided."):
282
+ with pytest.raises(ValueError, match=r"Empty text provided."):
258
283
  component.run("")
259
284
 
260
285
  mock_translation.assert_not_called()
@@ -271,7 +296,7 @@ class TestDeepLTextTranslator:
271
296
  source_lang=DEFAULT_SOURCE_LANG,
272
297
  target_lang="ES",
273
298
  )
274
- with pytest.raises(DeepLException, match="Error translating"):
299
+ with pytest.raises(DeepLException, match=r"Error translating"):
275
300
  component.run("Error translating")
276
301
 
277
302
  def test_run_with_source_lang(self, monkeypatch, mock_translation):
@@ -326,9 +351,9 @@ class TestDeepLTextTranslator:
326
351
  with pytest.raises(
327
352
  TypeError,
328
353
  match=(
329
- "DeepLTextTranslator expects a string as an input. "
354
+ r"DeepLTextTranslator expects a string as an input. "
330
355
  "In case you want to translate a list of Documents, "
331
- "please use the DeepLDocumentTranslator."
356
+ r"please use the DeepLDocumentTranslator."
332
357
  ),
333
358
  ):
334
359
  component.run(wrong_input)