pdfdancer-client-python 0.2.3__tar.gz → 0.2.4__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.

Potentially problematic release.


This version of pdfdancer-client-python might be problematic. Click here for more details.

Files changed (42) hide show
  1. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/.gitignore +1 -0
  2. {pdfdancer_client_python-0.2.3/src/pdfdancer_client_python.egg-info → pdfdancer_client_python-0.2.4}/PKG-INFO +1 -1
  3. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/pyproject.toml +1 -1
  4. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer/pdfdancer_v1.py +26 -0
  5. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4/src/pdfdancer_client_python.egg-info}/PKG-INFO +1 -1
  6. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer_client_python.egg-info/SOURCES.txt +1 -0
  7. pdfdancer_client_python-0.2.4/tests/test_authentication.py +36 -0
  8. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/.github/workflows/ci.yml +0 -0
  9. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/CLAUDE.md +0 -0
  10. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/README.md +0 -0
  11. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/docs/openapi.yml +0 -0
  12. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/release.py +0 -0
  13. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/requirements-dev.txt +0 -0
  14. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/requirements.txt +0 -0
  15. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/setup.cfg +0 -0
  16. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer/__init__.py +0 -0
  17. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer/exceptions.py +0 -0
  18. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer/image_builder.py +0 -0
  19. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer/models.py +0 -0
  20. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer/paragraph_builder.py +0 -0
  21. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer/types.py +0 -0
  22. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer_client_python.egg-info/dependency_links.txt +0 -0
  23. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer_client_python.egg-info/requires.txt +0 -0
  24. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/src/pdfdancer_client_python.egg-info/top_level.txt +0 -0
  25. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/__init__.py +0 -0
  26. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/__init__.py +0 -0
  27. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/test_acroform.py +0 -0
  28. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/test_form_x_objects.py +0 -0
  29. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/test_image.py +0 -0
  30. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/test_line.py +0 -0
  31. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/test_page.py +0 -0
  32. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/test_paragraph.py +0 -0
  33. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/e2e/test_path.py +0 -0
  34. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/fixtures/DancingScript-Regular.ttf +0 -0
  35. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/fixtures/JetBrainsMono-Regular.ttf +0 -0
  36. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/fixtures/ObviouslyAwesome.pdf +0 -0
  37. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/fixtures/basic-paths.pdf +0 -0
  38. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/fixtures/form-xobject-example.pdf +0 -0
  39. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/fixtures/logo-80.png +0 -0
  40. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/fixtures/mixed-form-types.pdf +0 -0
  41. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/test_models.py +0 -0
  42. {pdfdancer_client_python-0.2.3 → pdfdancer_client_python-0.2.4}/tests/test_openapi_compliance.py +0 -0
@@ -6,3 +6,4 @@ dist/
6
6
  src/pdfdancer_python.egg-info
7
7
  .aider*
8
8
  src/pdfdancer_client_python.egg-info
9
+ /logs/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdfdancer-client-python
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Python client for PDFDancer API
5
5
  Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pdfdancer-client-python"
7
- version = "0.2.3"
7
+ version = "0.2.4"
8
8
  description = "Python client for PDFDancer API"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -138,6 +138,12 @@ class PDFDancer:
138
138
  env_token = os.getenv("PDFDANCER_TOKEN")
139
139
  resolved_token = env_token.strip() if env_token and env_token.strip() else None
140
140
 
141
+ if resolved_token is None:
142
+ raise ValidationException(
143
+ "Missing PDFDancer API token. Pass a token via the `token` argument "
144
+ "or set the PDFDANCER_TOKEN environment variable."
145
+ )
146
+
141
147
  env_base_url = os.getenv("PDFDANCER_BASE_URL")
142
148
  resolved_base_url = base_url or (env_base_url.strip() if env_base_url and env_base_url.strip() else None)
143
149
  if resolved_base_url is None:
@@ -259,6 +265,22 @@ class PDFDancer:
259
265
  # If JSON parsing fails, return response content or status
260
266
  return response.text or f"HTTP {response.status_code}"
261
267
 
268
+ def _handle_authentication_error(self, response: Optional[requests.Response]) -> None:
269
+ """
270
+ Translate authentication failures into a clear, actionable validation error.
271
+ """
272
+ if response is None:
273
+ return
274
+
275
+ if response.status_code in (401, 403):
276
+ details = self._extract_error_message(response)
277
+ raise ValidationException(
278
+ "Authentication with the PDFDancer API failed. "
279
+ "Confirm that your API token is valid, has not expired, and is supplied via "
280
+ "the `token` argument or the PDFDANCER_TOKEN environment variable. "
281
+ f"Server response: {details}"
282
+ )
283
+
262
284
  def _create_session(self) -> str:
263
285
  """
264
286
  Creates a new PDF processing session by uploading the PDF data.
@@ -274,6 +296,7 @@ class PDFDancer:
274
296
  timeout=self._read_timeout if self._read_timeout > 0 else None
275
297
  )
276
298
 
299
+ self._handle_authentication_error(response)
277
300
  response.raise_for_status()
278
301
  session_id = response.text.strip()
279
302
 
@@ -283,6 +306,7 @@ class PDFDancer:
283
306
  return session_id
284
307
 
285
308
  except requests.exceptions.RequestException as e:
309
+ self._handle_authentication_error(getattr(e, 'response', None))
286
310
  error_message = self._extract_error_message(getattr(e, 'response', None))
287
311
  raise HttpClientException(f"Failed to create session: {error_message}",
288
312
  response=getattr(e, 'response', None), cause=e) from None
@@ -316,10 +340,12 @@ class PDFDancer:
316
340
  except (json.JSONDecodeError, KeyError):
317
341
  pass
318
342
 
343
+ self._handle_authentication_error(response)
319
344
  response.raise_for_status()
320
345
  return response
321
346
 
322
347
  except requests.exceptions.RequestException as e:
348
+ self._handle_authentication_error(getattr(e, 'response', None))
323
349
  error_message = self._extract_error_message(getattr(e, 'response', None))
324
350
  raise HttpClientException(f"API request failed: {error_message}", response=getattr(e, 'response', None),
325
351
  cause=e) from None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdfdancer-client-python
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Python client for PDFDancer API
5
5
  Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
6
  License: MIT
@@ -20,6 +20,7 @@ src/pdfdancer_client_python.egg-info/dependency_links.txt
20
20
  src/pdfdancer_client_python.egg-info/requires.txt
21
21
  src/pdfdancer_client_python.egg-info/top_level.txt
22
22
  tests/__init__.py
23
+ tests/test_authentication.py
23
24
  tests/test_models.py
24
25
  tests/test_openapi_compliance.py
25
26
  tests/e2e/__init__.py
@@ -0,0 +1,36 @@
1
+ import requests
2
+ import pytest
3
+
4
+ from pdfdancer import ValidationException
5
+ from pdfdancer.pdfdancer_v1 import PDFDancer
6
+
7
+
8
+ def test_open_without_token_reports_actionable_message():
9
+ with pytest.raises(ValidationException) as exc_info:
10
+ PDFDancer.open(pdf_data=b"%PDF", token="")
11
+
12
+ message = str(exc_info.value)
13
+ assert "Missing PDFDancer API token" in message
14
+ assert "PDFDANCER_TOKEN" in message
15
+
16
+
17
+ def test_create_session_unauthorized_reports_guidance(monkeypatch):
18
+ class FakeResponse:
19
+ status_code = 401
20
+ text = "Unauthorized"
21
+
22
+ def json(self):
23
+ return {"message": "Unauthorized"}
24
+
25
+ def fake_post(self, *args, **kwargs):
26
+ return FakeResponse()
27
+
28
+ monkeypatch.setattr(requests.Session, "post", fake_post)
29
+
30
+ with pytest.raises(ValidationException) as exc_info:
31
+ PDFDancer(token="bad-token", pdf_data=b"%PDF", base_url="https://api.example.com")
32
+
33
+ message = str(exc_info.value)
34
+ assert "Authentication with the PDFDancer API failed" in message
35
+ assert "Server response: Unauthorized" in message
36
+ assert "PDFDANCER_TOKEN" in message