pdfdancer-client-python 0.2.23__tar.gz → 0.2.25__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 (74) hide show
  1. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/.github/workflows/ci.yml +1 -0
  2. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/.github/workflows/daily-tests.yml +2 -1
  3. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/PKG-INFO +10 -7
  4. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/README.md +6 -5
  5. pdfdancer_client_python-0.2.25/media/logo-orange-512h.webp +0 -0
  6. pdfdancer_client_python-0.2.25/media/logo-orange-60h.webp +0 -0
  7. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/pyproject.toml +4 -2
  8. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer_client_python.egg-info/PKG-INFO +10 -7
  9. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer_client_python.egg-info/SOURCES.txt +2 -0
  10. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/pdf_assertions.py +1 -1
  11. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_context_manager.py +1 -1
  12. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_page.py +1 -1
  13. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_paragraph.py +9 -9
  14. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_singular_selection.py +2 -2
  15. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_snapshot.py +1 -1
  16. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/.claude/commands/discuss.md +0 -0
  17. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/.flake8 +0 -0
  18. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/.gitignore +0 -0
  19. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/CLAUDE.md +0 -0
  20. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/LICENSE +0 -0
  21. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/NOTICE +0 -0
  22. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/TODO.md +0 -0
  23. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/check.py +0 -0
  24. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/docs/openapi.yml +0 -0
  25. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/release.py +0 -0
  26. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/setup.cfg +0 -0
  27. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/__init__.py +0 -0
  28. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/exceptions.py +0 -0
  29. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/fingerprint.py +0 -0
  30. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/image_builder.py +0 -0
  31. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/models.py +0 -0
  32. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/page_builder.py +0 -0
  33. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/paragraph_builder.py +0 -0
  34. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/path_builder.py +0 -0
  35. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/pdfdancer_v1.py +0 -0
  36. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer/types.py +0 -0
  37. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer_client_python.egg-info/dependency_links.txt +0 -0
  38. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer_client_python.egg-info/requires.txt +0 -0
  39. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/src/pdfdancer_client_python.egg-info/top_level.txt +0 -0
  40. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/test.sh +0 -0
  41. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/__init__.py +0 -0
  42. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/conftest.py +0 -0
  43. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/__init__.py +0 -0
  44. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_acroform.py +0 -0
  45. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_bezier_builder.py +0 -0
  46. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_form_x_objects.py +0 -0
  47. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_image.py +0 -0
  48. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_line.py +0 -0
  49. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_line_builder.py +0 -0
  50. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_new_pdf.py +0 -0
  51. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_path.py +0 -0
  52. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_path_builder.py +0 -0
  53. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_path_builder_rectangle.py +0 -0
  54. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_path_comprehensive.py +0 -0
  55. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_pdfdancer.py +0 -0
  56. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_positioning.py +0 -0
  57. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/e2e/test_rectangle_builder.py +0 -0
  58. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/DancingScript-Regular.ttf +0 -0
  59. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/Empty.pdf +0 -0
  60. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/JetBrainsMono-Regular.ttf +0 -0
  61. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/Showcase.pdf +0 -0
  62. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/basic-paths.pdf +0 -0
  63. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/form-xobject-example.pdf +0 -0
  64. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/logo-80.png +0 -0
  65. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/fixtures/mixed-form-types.pdf +0 -0
  66. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_anonymous_token.py +0 -0
  67. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_fingerprint.py +0 -0
  68. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_models.py +0 -0
  69. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_openapi_compliance.py +0 -0
  70. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_path_models.py +0 -0
  71. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_pdf_object_equality.py +0 -0
  72. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_rate_limit.py +0 -0
  73. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/tests/test_standard_fonts.py +0 -0
  74. {pdfdancer_client_python-0.2.23 → pdfdancer_client_python-0.2.25}/update-api-spec.sh +0 -0
@@ -14,6 +14,7 @@ jobs:
14
14
  runs-on: ubuntu-latest
15
15
  strategy:
16
16
  fail-fast: false
17
+ max-parallel: 4
17
18
  matrix:
18
19
  python-version: [ '3.12' ]
19
20
 
@@ -3,7 +3,7 @@ name: Daily Tests
3
3
  on:
4
4
  schedule:
5
5
  # Run daily at 9:00 PM UTC
6
- - cron: '0 21 * * *'
6
+ - cron: '40 10 * * *'
7
7
  workflow_dispatch: # Allow manual triggering
8
8
 
9
9
  jobs:
@@ -11,6 +11,7 @@ jobs:
11
11
  runs-on: ${{ matrix.os }}
12
12
  strategy:
13
13
  fail-fast: false
14
+ max-parallel: 4
14
15
  matrix:
15
16
  os: [ ubuntu-latest, windows-latest ]
16
17
  python-version: [ '3.10', '3.11', '3.12', '3.13' ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdfdancer-client-python
3
- Version: 0.2.23
3
+ Version: 0.2.25
4
4
  Summary: Python client for PDFDancer API
5
5
  Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
6
  License:
@@ -207,7 +207,9 @@ License:
207
207
  limitations under the License.
208
208
 
209
209
  Project-URL: Homepage, https://www.pdfdancer.com/
210
- Project-URL: Repository, https://github.com/MenschMachine/pdfdancer-client-python
210
+ Project-URL: Documentation, https://www.pdfdancer.com/
211
+ Project-URL: Source, https://github.com/MenschMachine/pdfdancer-client-python
212
+ Project-URL: Issues, https://github.com/MenschMachine/pdfdancer-client-python/issues
211
213
  Classifier: Development Status :: 4 - Beta
212
214
  Classifier: Intended Audience :: Developers
213
215
  Classifier: License :: OSI Approved :: Apache Software License
@@ -237,11 +239,12 @@ Dynamic: license-file
237
239
 
238
240
  # PDFDancer Python Client
239
241
 
240
- **Getting Started with PDFDancer**
242
+ ![PDFDancer logo](media/logo-orange-60h.webp)
241
243
 
242
- PDFDancer gives you pixel-perfect programmatic control over any PDF document from Python. Locate existing elements by
243
- coordinates or text, adjust them precisely, add brand-new content, and ship the modified PDF in memory or on disk. The
244
- same API is also available for TypeScript and Java, so teams can orchestrate identical PDF workflows across stacks.
244
+ **Stop fighting PDFs. Start editing them.**
245
+
246
+ Edit text in real-world PDFs—even ones you didn't create. Move images, reposition headers, and change fonts with
247
+ pixel-perfect control from Python. The same API is also available for TypeScript and Java.
245
248
 
246
249
  > Need the raw API schema? The latest OpenAPI description lives in `docs/openapi.yml` and is published at
247
250
  > https://bucket.pdfdancer.com/api-doc/development-0.0.yml.
@@ -256,7 +259,7 @@ same API is also available for TypeScript and Java, so teams can orchestrate ide
256
259
 
257
260
  ## What Makes PDFDancer Different
258
261
 
259
- - **Edit any PDF**: Work with documents from customers, governments, or vendors—not just ones you generated.
262
+ - **Edit text in real-world PDFs**: Work with documents from customers, governments, or vendors—even ones you didn't create.
260
263
  - **Pixel-perfect positioning**: Move or add elements at exact coordinates and keep the original layout intact.
261
264
  - **Surgical text replacement**: Swap or rewrite paragraphs without reflowing the rest of the page.
262
265
  - **Form manipulation**: Inspect, fill, and update AcroForm fields programmatically.
@@ -1,10 +1,11 @@
1
1
  # PDFDancer Python Client
2
2
 
3
- **Getting Started with PDFDancer**
3
+ ![PDFDancer logo](media/logo-orange-60h.webp)
4
4
 
5
- PDFDancer gives you pixel-perfect programmatic control over any PDF document from Python. Locate existing elements by
6
- coordinates or text, adjust them precisely, add brand-new content, and ship the modified PDF in memory or on disk. The
7
- same API is also available for TypeScript and Java, so teams can orchestrate identical PDF workflows across stacks.
5
+ **Stop fighting PDFs. Start editing them.**
6
+
7
+ Edit text in real-world PDFs—even ones you didn't create. Move images, reposition headers, and change fonts with
8
+ pixel-perfect control from Python. The same API is also available for TypeScript and Java.
8
9
 
9
10
  > Need the raw API schema? The latest OpenAPI description lives in `docs/openapi.yml` and is published at
10
11
  > https://bucket.pdfdancer.com/api-doc/development-0.0.yml.
@@ -19,7 +20,7 @@ same API is also available for TypeScript and Java, so teams can orchestrate ide
19
20
 
20
21
  ## What Makes PDFDancer Different
21
22
 
22
- - **Edit any PDF**: Work with documents from customers, governments, or vendors—not just ones you generated.
23
+ - **Edit text in real-world PDFs**: Work with documents from customers, governments, or vendors—even ones you didn't create.
23
24
  - **Pixel-perfect positioning**: Move or add elements at exact coordinates and keep the original layout intact.
24
25
  - **Surgical text replacement**: Swap or rewrite paragraphs without reflowing the rest of the page.
25
26
  - **Form manipulation**: Inspect, fill, and update AcroForm fields programmatically.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pdfdancer-client-python"
7
- version = "0.2.23"
7
+ version = "0.2.25"
8
8
  description = "Python client for PDFDancer API"
9
9
  readme = "README.md"
10
10
  authors = [
@@ -43,7 +43,9 @@ dev = [
43
43
 
44
44
  [project.urls]
45
45
  Homepage = "https://www.pdfdancer.com/"
46
- Repository = "https://github.com/MenschMachine/pdfdancer-client-python"
46
+ Documentation = "https://www.pdfdancer.com/"
47
+ Source = "https://github.com/MenschMachine/pdfdancer-client-python"
48
+ Issues = "https://github.com/MenschMachine/pdfdancer-client-python/issues"
47
49
 
48
50
  [tool.setuptools.packages.find]
49
51
  where = ["src"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdfdancer-client-python
3
- Version: 0.2.23
3
+ Version: 0.2.25
4
4
  Summary: Python client for PDFDancer API
5
5
  Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
6
  License:
@@ -207,7 +207,9 @@ License:
207
207
  limitations under the License.
208
208
 
209
209
  Project-URL: Homepage, https://www.pdfdancer.com/
210
- Project-URL: Repository, https://github.com/MenschMachine/pdfdancer-client-python
210
+ Project-URL: Documentation, https://www.pdfdancer.com/
211
+ Project-URL: Source, https://github.com/MenschMachine/pdfdancer-client-python
212
+ Project-URL: Issues, https://github.com/MenschMachine/pdfdancer-client-python/issues
211
213
  Classifier: Development Status :: 4 - Beta
212
214
  Classifier: Intended Audience :: Developers
213
215
  Classifier: License :: OSI Approved :: Apache Software License
@@ -237,11 +239,12 @@ Dynamic: license-file
237
239
 
238
240
  # PDFDancer Python Client
239
241
 
240
- **Getting Started with PDFDancer**
242
+ ![PDFDancer logo](media/logo-orange-60h.webp)
241
243
 
242
- PDFDancer gives you pixel-perfect programmatic control over any PDF document from Python. Locate existing elements by
243
- coordinates or text, adjust them precisely, add brand-new content, and ship the modified PDF in memory or on disk. The
244
- same API is also available for TypeScript and Java, so teams can orchestrate identical PDF workflows across stacks.
244
+ **Stop fighting PDFs. Start editing them.**
245
+
246
+ Edit text in real-world PDFs—even ones you didn't create. Move images, reposition headers, and change fonts with
247
+ pixel-perfect control from Python. The same API is also available for TypeScript and Java.
245
248
 
246
249
  > Need the raw API schema? The latest OpenAPI description lives in `docs/openapi.yml` and is published at
247
250
  > https://bucket.pdfdancer.com/api-doc/development-0.0.yml.
@@ -256,7 +259,7 @@ same API is also available for TypeScript and Java, so teams can orchestrate ide
256
259
 
257
260
  ## What Makes PDFDancer Different
258
261
 
259
- - **Edit any PDF**: Work with documents from customers, governments, or vendors—not just ones you generated.
262
+ - **Edit text in real-world PDFs**: Work with documents from customers, governments, or vendors—even ones you didn't create.
260
263
  - **Pixel-perfect positioning**: Move or add elements at exact coordinates and keep the original layout intact.
261
264
  - **Surgical text replacement**: Swap or rewrite paragraphs without reflowing the rest of the page.
262
265
  - **Form manipulation**: Inspect, fill, and update AcroForm fields programmatically.
@@ -14,6 +14,8 @@ update-api-spec.sh
14
14
  .github/workflows/ci.yml
15
15
  .github/workflows/daily-tests.yml
16
16
  docs/openapi.yml
17
+ media/logo-orange-512h.webp
18
+ media/logo-orange-60h.webp
17
19
  src/pdfdancer/__init__.py
18
20
  src/pdfdancer/exceptions.py
19
21
  src/pdfdancer/fingerprint.py
@@ -43,7 +43,7 @@ class PDFAssertions(object):
43
43
 
44
44
  return self
45
45
 
46
- def assert_paragraph_is_at(self, text, x, y, page=0, epsilon=1e-6):
46
+ def assert_paragraph_is_at(self, text, x, y, page=0, epsilon=2): # adjust for baseline vs bounding box differences
47
47
  paragraphs = self.pdf.page(page).select_paragraphs_matching(f".*{text}.*")
48
48
  assert len(paragraphs) == 1, f"Expected 1 paragraph but got {len(paragraphs)}"
49
49
  reference = paragraphs[0].object_ref()
@@ -12,7 +12,7 @@ def test_context_manager_basic_usage():
12
12
 
13
13
  with PDFDancer.open(pdf_path, token=token, base_url=base_url) as pdf:
14
14
  paragraphs = pdf.select_paragraphs()
15
- assert len(paragraphs) == 24
15
+ assert len(paragraphs) == 20
16
16
 
17
17
 
18
18
  def test_context_manager_edit_text_only():
@@ -7,7 +7,7 @@ def test_get_all_elements():
7
7
  base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
8
8
 
9
9
  with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
10
- expected_total = 99
10
+ expected_total = 95
11
11
  assert (
12
12
  len(pdf.select_elements()) == expected_total
13
13
  ), f"{len(pdf.select_elements())} elements found but {expected_total} elements expected"
@@ -1,7 +1,7 @@
1
1
  import pytest
2
-
3
2
  from pdfdancer import Color, FontType, StandardFonts
4
3
  from pdfdancer.pdfdancer_v1 import PDFDancer
4
+
5
5
  from tests.e2e import _require_env_and_fixture
6
6
  from tests.e2e.pdf_assertions import PDFAssertions
7
7
 
@@ -11,19 +11,19 @@ def test_find_paragraphs_by_position():
11
11
 
12
12
  with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
13
13
  paras = pdf.select_paragraphs()
14
- assert len(paras) == 24
14
+ assert len(paras) == 20
15
15
 
16
16
  paras_page0 = pdf.page(0).select_paragraphs()
17
- assert len(paras_page0) == 4
17
+ assert len(paras_page0) == 3
18
18
 
19
19
  first = paras_page0[0]
20
- assert first.internal_id == "PARAGRAPH_000005"
20
+ assert first.internal_id == "PARAGRAPH_000004"
21
21
  assert first.position is not None
22
22
  assert pytest.approx(first.position.x(), rel=0, abs=1) == 180
23
- assert pytest.approx(first.position.y(), rel=0, abs=1) == 755.2
23
+ assert pytest.approx(first.position.y(), rel=0, abs=1) == 749 # adjusted for baseline/bounding box
24
24
 
25
25
  last = paras_page0[-1]
26
- assert last.internal_id == "PARAGRAPH_000008"
26
+ assert last.internal_id == "PARAGRAPH_000006"
27
27
  assert last.position is not None
28
28
  assert pytest.approx(last.position.x(), rel=0, abs=1) == 69.3
29
29
  assert pytest.approx(last.position.y(), rel=0, abs=2) == 46.7
@@ -43,9 +43,9 @@ def test_find_paragraphs_by_text():
43
43
  )
44
44
  assert len(paras) == 1
45
45
  p = paras[0]
46
- assert p.internal_id == "PARAGRAPH_000006"
46
+ assert p.internal_id == "PARAGRAPH_000005"
47
47
  assert pytest.approx(p.position.x(), rel=0, abs=1) == 64.7
48
- assert pytest.approx(p.position.y(), rel=0, abs=2) == 661.2
48
+ assert pytest.approx(p.position.y(), rel=0, abs=2) == 642 # adjust for baseline/bounding box
49
49
 
50
50
 
51
51
  def test_select_paragraphs_matching_document_level():
@@ -114,7 +114,7 @@ def test_select_paragraphs_matching_multiple_pages():
114
114
  base_url, token, _ = _require_env_and_fixture("Showcase.pdf")
115
115
 
116
116
  with PDFDancer.new(
117
- token=token, base_url=base_url, timeout=30.0, initial_page_count=3
117
+ token=token, base_url=base_url, timeout=30.0, initial_page_count=3
118
118
  ) as pdf:
119
119
  # Add paragraphs to different pages
120
120
  pdf.new_paragraph().text("Chapter 1: Introduction").font(
@@ -51,9 +51,9 @@ def test_select_paragraph_starting_with():
51
51
  "This is regular Sans text showing alignment and styles."
52
52
  )
53
53
  assert paragraph is not None
54
- assert paragraph.internal_id == "PARAGRAPH_000006"
54
+ assert paragraph.internal_id == "PARAGRAPH_000005"
55
55
  assert pytest.approx(paragraph.position.x(), rel=0, abs=1) == 64.7
56
- assert pytest.approx(paragraph.position.y(), rel=0, abs=2) == 661.2
56
+ assert pytest.approx(paragraph.position.y(), rel=0, abs=2) == 642 # adjust for baseline/bounding box
57
57
 
58
58
 
59
59
  def test_select_paragraph_starting_with_no_match():
@@ -239,7 +239,7 @@ def test_total_element_count_matches_expected():
239
239
  with PDFDancer.open(pdf_path, token=token, base_url=base_url) as pdf:
240
240
  # Showcase.pdf - Python API filters certain types (638)
241
241
  all_elements = pdf.select_elements()
242
- assert len(all_elements) == 99, "Showcase.pdf should have 99 total elements"
242
+ assert len(all_elements) == 95, "Showcase.pdf should have 95 total elements"
243
243
 
244
244
  doc_snapshot = pdf.get_document_snapshot()
245
245
  snapshot_total = sum(len(p.elements) for p in doc_snapshot.pages)