BabelDOC 0.1.15__tar.gz → 0.1.16__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 (77) hide show
  1. {babeldoc-0.1.15 → babeldoc-0.1.16}/PKG-INFO +1 -1
  2. babeldoc-0.1.16/babeldoc/__init__.py +1 -0
  3. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/const.py +1 -1
  4. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/backend/pdf_creater.py +191 -2
  5. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/main.py +1 -1
  6. {babeldoc-0.1.15 → babeldoc-0.1.16}/pyproject.toml +2 -2
  7. {babeldoc-0.1.15 → babeldoc-0.1.16}/uv.lock +1 -1
  8. babeldoc-0.1.15/babeldoc/__init__.py +0 -1
  9. {babeldoc-0.1.15 → babeldoc-0.1.16}/.cursorignore +0 -0
  10. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/ISSUE_TEMPLATE/bug_report.yaml +0 -0
  11. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/ISSUE_TEMPLATE/feature_request.yaml +0 -0
  12. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/dependabot.yml +0 -0
  13. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/labels.yml +0 -0
  14. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/release-drafter.yml +0 -0
  15. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/workflows/codeql.yml +0 -0
  16. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/workflows/docs.yml +0 -0
  17. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/workflows/labeler.yml +0 -0
  18. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/workflows/publish-to-pypi.yml +0 -0
  19. {babeldoc-0.1.15 → babeldoc-0.1.16}/.github/workflows/test.yml +0 -0
  20. {babeldoc-0.1.15 → babeldoc-0.1.16}/.gitignore +0 -0
  21. {babeldoc-0.1.15 → babeldoc-0.1.16}/.pre-commit-config.yaml +0 -0
  22. {babeldoc-0.1.15 → babeldoc-0.1.16}/LICENSE +0 -0
  23. {babeldoc-0.1.15 → babeldoc-0.1.16}/README.md +0 -0
  24. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/asynchronize/__init__.py +0 -0
  25. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/converter.py +0 -0
  26. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/__init__.py +0 -0
  27. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/backend/__init__.py +0 -0
  28. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/frontend/__init__.py +0 -0
  29. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/frontend/il_creater.py +0 -0
  30. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.py +0 -0
  31. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.rnc +0 -0
  32. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.rng +0 -0
  33. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/il_version_1.xsd +0 -0
  34. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/__init__.py +0 -0
  35. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/add_debug_information.py +0 -0
  36. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/il_translator.py +0 -0
  37. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/layout_parser.py +0 -0
  38. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/paragraph_finder.py +0 -0
  39. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/remove_descent.py +0 -0
  40. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/styles_and_formulas.py +0 -0
  41. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/midend/typesetting.py +0 -0
  42. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/translator/__init__.py +0 -0
  43. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/translator/cache.py +0 -0
  44. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/translator/translator.py +0 -0
  45. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/utils/fontmap.py +0 -0
  46. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/utils/layout_helper.py +0 -0
  47. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/utils/style_helper.py +0 -0
  48. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/document_il/xml_converter.py +0 -0
  49. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/docvision/README.md +0 -0
  50. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/docvision/__init__.py +0 -0
  51. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/docvision/doclayout.py +0 -0
  52. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/docvision/rpc_doclayout.py +0 -0
  53. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/high_level.py +0 -0
  54. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/pdfinterp.py +0 -0
  55. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/progress_monitor.py +0 -0
  56. {babeldoc-0.1.15 → babeldoc-0.1.16}/babeldoc/translation_config.py +0 -0
  57. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/CODE_OF_CONDUCT.md +0 -0
  58. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/CONTRIBUTING.md +0 -0
  59. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/CONTRIBUTOR_REWARD.md +0 -0
  60. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/AsyncTranslate/AsyncTranslate.md +0 -0
  61. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/ILTranslator/ILTranslator.md +0 -0
  62. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/PDFCreation/PDFCreation.md +0 -0
  63. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/PDFParsing/PDFParsing.md +0 -0
  64. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/ParagraphFinding/ParagraphFinding.md +0 -0
  65. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/README.md +0 -0
  66. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/StylesAndFormulas/StylesAndFormulas.md +0 -0
  67. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/ImplementationDetails/Typesetting/Typesetting.md +0 -0
  68. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/README.md +0 -0
  69. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/deploy.sh +0 -0
  70. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/images/babeldoc-banner.png +0 -0
  71. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/images/babeldoc-contributor_reward_example.png +0 -0
  72. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/images/babeldoc-preview.gif +0 -0
  73. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/index.md +0 -0
  74. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/intro-to-pdf-object.md +0 -0
  75. {babeldoc-0.1.15 → babeldoc-0.1.16}/docs/requirements.txt +0 -0
  76. {babeldoc-0.1.15 → babeldoc-0.1.16}/mkdocs.yml +0 -0
  77. {babeldoc-0.1.15 → babeldoc-0.1.16}/tests/test_translation_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: BabelDOC
3
- Version: 0.1.15
3
+ Version: 0.1.16
4
4
  Summary: Yet Another Document Translator
5
5
  Project-URL: Homepage, https://github.com/funstory-ai/BabelDOC
6
6
  Project-URL: Issues, https://github.com/funstory-ai/BabelDOC/issues
@@ -0,0 +1 @@
1
+ __version__ = "0.1.16"
@@ -2,7 +2,7 @@ import shutil
2
2
  import subprocess
3
3
  from pathlib import Path
4
4
 
5
- __version__ = "0.1.15"
5
+ __version__ = "0.1.16"
6
6
 
7
7
  CACHE_FOLDER = Path.home() / ".cache" / "babeldoc"
8
8
 
@@ -38,6 +38,44 @@ def _subset_fonts_process(pdf_path, output_path):
38
38
  os._exit(1)
39
39
 
40
40
 
41
+ def _save_pdf_clean_process(
42
+ pdf_path,
43
+ output_path,
44
+ garbage=1,
45
+ deflate=True,
46
+ clean=True,
47
+ deflate_fonts=True,
48
+ linear=False,
49
+ ):
50
+ """Function to run in subprocess for saving PDF with clean=True which can be time-consuming.
51
+
52
+ Args:
53
+ pdf_path: Path to the PDF file to save
54
+ output_path: Path where to save the result
55
+ garbage: Garbage collection level (0, 1, 2, 3, 4)
56
+ deflate: Whether to deflate the PDF
57
+ clean: Whether to clean the PDF
58
+ deflate_fonts: Whether to deflate fonts
59
+ linear: Whether to linearize the PDF
60
+ """
61
+ try:
62
+ pdf = pymupdf.open(pdf_path)
63
+ pdf.save(
64
+ output_path,
65
+ garbage=garbage,
66
+ deflate=deflate,
67
+ clean=clean,
68
+ deflate_fonts=deflate_fonts,
69
+ linear=linear,
70
+ )
71
+ # 返回0表示成功
72
+ os._exit(0)
73
+ except Exception as e:
74
+ logger.error(f"Error in save PDF with clean=True subprocess: {e}")
75
+ # 返回1表示失败
76
+ os._exit(1)
77
+
78
+
41
79
  class PDFCreater:
42
80
  stage_name = "Generate drawing instructions"
43
81
 
@@ -425,6 +463,11 @@ class PDFCreater:
425
463
  if process.is_alive():
426
464
  logger.warning("Subprocess did not terminate, killing it")
427
465
  process.kill()
466
+ process.terminate()
467
+ process.kill()
468
+ process.terminate()
469
+ process.kill()
470
+ process.terminate()
428
471
  except Exception as e:
429
472
  logger.error(f"Error terminating font subsetting process: {e}")
430
473
 
@@ -450,6 +493,148 @@ class PDFCreater:
450
493
  )
451
494
  return original_pdf
452
495
 
496
+ def save_pdf_with_timeout(
497
+ self,
498
+ pdf: pymupdf.Document,
499
+ output_path: str,
500
+ translation_config: TranslationConfig,
501
+ garbage: int = 1,
502
+ deflate: bool = True,
503
+ clean: bool = True,
504
+ deflate_fonts: bool = True,
505
+ linear: bool = False,
506
+ timeout: int = 120,
507
+ ) -> bool:
508
+ """Save a PDF document with a timeout for the clean=True operation.
509
+
510
+ Args:
511
+ pdf: The PDF document object
512
+ output_path: Path where to save the PDF
513
+ translation_config: Translation configuration
514
+ garbage: Garbage collection level (0, 1, 2, 3, 4)
515
+ deflate: Whether to deflate the PDF
516
+ clean: Whether to clean the PDF
517
+ deflate_fonts: Whether to deflate fonts
518
+ linear: Whether to linearize the PDF
519
+ timeout: Timeout in seconds (default: 2 minutes)
520
+
521
+ Returns:
522
+ True if saved with clean=True successfully, False if fallback to clean=False was used
523
+ """
524
+ # Create temporary file paths
525
+ temp_input = str(
526
+ translation_config.get_working_file_path(
527
+ f"temp_save_input_{int(time.time())}.pdf"
528
+ )
529
+ )
530
+ temp_output = str(
531
+ translation_config.get_working_file_path(
532
+ f"temp_save_output_{int(time.time())}.pdf"
533
+ )
534
+ )
535
+
536
+ # Save PDF to temporary file first
537
+ pdf.save(temp_input)
538
+
539
+ # Try to save with clean=True in a subprocess
540
+ process = Process(
541
+ target=_save_pdf_clean_process,
542
+ args=(
543
+ temp_input,
544
+ temp_output,
545
+ garbage,
546
+ deflate,
547
+ clean,
548
+ deflate_fonts,
549
+ linear,
550
+ ),
551
+ )
552
+ process.start()
553
+
554
+ # Wait for subprocess with timeout
555
+ start_time = time.time()
556
+
557
+ while process.is_alive():
558
+ if time.time() - start_time > timeout:
559
+ logger.warning(
560
+ f"PDF save with clean=True timeout after {timeout} seconds, terminating subprocess"
561
+ )
562
+ process.terminate()
563
+ try:
564
+ process.join(5) # Give it 5 seconds to clean up
565
+ if process.is_alive():
566
+ logger.warning("Subprocess did not terminate, killing it")
567
+ process.kill()
568
+ process.terminate()
569
+ process.kill()
570
+ process.terminate()
571
+ process.kill()
572
+ process.terminate()
573
+ except Exception as e:
574
+ logger.error(f"Error terminating PDF save process: {e}")
575
+
576
+ # Fallback to save without clean parameter
577
+ logger.info("Falling back to save without clean=True")
578
+ try:
579
+ pdf.save(
580
+ output_path,
581
+ garbage=garbage,
582
+ deflate=deflate,
583
+ clean=False,
584
+ deflate_fonts=deflate_fonts,
585
+ linear=linear,
586
+ )
587
+ return False
588
+ except Exception as e:
589
+ logger.error(f"Error in fallback save: {e}")
590
+ # Last resort: basic save
591
+ pdf.save(output_path)
592
+ return False
593
+
594
+ time.sleep(0.5) # Check every half second
595
+
596
+ # Process completed, check exit code
597
+ exit_code = process.exitcode
598
+ success = exit_code == 0
599
+
600
+ # Check if save was successful
601
+ if (
602
+ success
603
+ and Path(temp_output).exists()
604
+ and Path(temp_output).stat().st_size > 0
605
+ ):
606
+ logger.info("PDF save with clean=True completed successfully")
607
+ # Copy the successfully created file to the target path
608
+ try:
609
+ import shutil
610
+
611
+ shutil.copy2(temp_output, output_path)
612
+ return True
613
+ except Exception as e:
614
+ logger.error(f"Error copying saved PDF: {e}")
615
+ pdf.save(output_path) # Fallback to direct save
616
+ return False
617
+ else:
618
+ logger.warning(
619
+ f"PDF save with clean=True failed with exit code {exit_code} or produced empty file"
620
+ )
621
+ # Fallback to save without clean parameter
622
+ try:
623
+ pdf.save(
624
+ output_path,
625
+ garbage=garbage,
626
+ deflate=deflate,
627
+ clean=False,
628
+ deflate_fonts=deflate_fonts,
629
+ linear=linear,
630
+ )
631
+ except Exception as e:
632
+ logger.error(f"Error in fallback save: {e}")
633
+ # Last resort: basic save
634
+ pdf.save(output_path)
635
+
636
+ return False
637
+
453
638
  def write(self, translation_config: TranslationConfig) -> TranslateResult:
454
639
  basename = Path(translation_config.input_file).stem
455
640
  debug_suffix = ".debug" if translation_config.debug else ""
@@ -579,8 +764,10 @@ class PDFCreater:
579
764
  pretty=True,
580
765
  )
581
766
  translation_config.raise_if_cancelled()
582
- pdf.save(
767
+ self.save_pdf_with_timeout(
768
+ pdf,
583
769
  mono_out_path,
770
+ translation_config,
584
771
  garbage=1,
585
772
  deflate=True,
586
773
  clean=not translation_config.skip_clean,
@@ -627,8 +814,10 @@ class PDFCreater:
627
814
  exc_info=True,
628
815
  )
629
816
 
630
- dual.save(
817
+ self.save_pdf_with_timeout(
818
+ dual,
631
819
  dual_out_path,
820
+ translation_config,
632
821
  garbage=1,
633
822
  deflate=True,
634
823
  clean=not translation_config.skip_clean,
@@ -23,7 +23,7 @@ from babeldoc.docvision.rpc_doclayout import RpcDocLayoutModel
23
23
  from babeldoc.translation_config import TranslationConfig
24
24
 
25
25
  logger = logging.getLogger(__name__)
26
- __version__ = "0.1.15"
26
+ __version__ = "0.1.16"
27
27
 
28
28
 
29
29
  def create_parser():
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "BabelDOC"
3
- version = "0.1.15"
3
+ version = "0.1.16"
4
4
  description = "Yet Another Document Translator"
5
5
  license = "AGPL-3.0"
6
6
  readme = "README.md"
@@ -132,7 +132,7 @@ pythonpath = [".", "src"]
132
132
  testpaths = ["tests"]
133
133
 
134
134
  [bumpver]
135
- current_version = "0.1.15"
135
+ current_version = "0.1.16"
136
136
  version_pattern = "MAJOR.MINOR.PATCH[.PYTAGNUM]"
137
137
 
138
138
  [bumpver.file_patterns]
@@ -48,7 +48,7 @@ wheels = [
48
48
 
49
49
  [[package]]
50
50
  name = "babeldoc"
51
- version = "0.1.15"
51
+ version = "0.1.16"
52
52
  source = { editable = "." }
53
53
  dependencies = [
54
54
  { name = "bitstring" },
@@ -1 +0,0 @@
1
- __version__ = "0.1.15"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes