shellscripts 0.23.1__py3-none-any.whl → 0.24.0__py3-none-any.whl

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.
shell_scripts/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.23.1"
1
+ __version__ = "0.24.0"
2
2
 
3
3
  from .core import main # noqa: F401
4
4
 
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env python3
2
+ import errno
2
3
  import os
3
4
  import re
5
+ import shutil
4
6
  import subprocess
5
7
  import tempfile
6
8
 
@@ -102,7 +104,48 @@ def _extract_toc_for_range(data_file, start, end):
102
104
  return "\n".join(result)
103
105
 
104
106
 
107
+ def _promote_temp_output(temp_output, output_file):
108
+ """
109
+ @brief Promote one pdftk-produced temporary artifact onto the final output path.
110
+ @details Attempts same-device atomic replacement via `os.replace`. On
111
+ `OSError` with `errno.EXDEV` (temporary directory and output directory
112
+ located on different filesystems), falls back to `shutil.move`, which
113
+ copies the artifact content and removes the temporary source. All other
114
+ `OSError` values propagate unchanged to preserve pre-existing failure
115
+ semantics. Time complexity O(1) for same-device renames, O(n) over file
116
+ size for the cross-device copy fallback.
117
+ @param temp_output {str} Temporary artifact path produced by the external tool chain.
118
+ @param output_file {str} Final chunk path that must receive the artifact content.
119
+ @return {None} Applies destination filesystem mutation.
120
+ @throws {OSError} Propagated for non-EXDEV replacement failures.
121
+ @satisfies REQ-031, REQ-032
122
+ """
123
+ try:
124
+ os.replace(temp_output, output_file)
125
+ except OSError as error:
126
+ if error.errno != errno.EXDEV:
127
+ raise
128
+ shutil.move(temp_output, output_file)
129
+
130
+
105
131
  def _apply_toc(output_file, toc_content):
132
+ """
133
+ @brief Reapply in-range TOC data to one generated chunk file.
134
+ @details Writes `toc_content` into a temporary `.info` payload, prepares
135
+ temporary PDF artifacts, strips object streams from `output_file` via
136
+ `qpdf`, rebuilds the chunk with TOC metadata via `pdftk update_info`,
137
+ and promotes the artifact onto `output_file` through
138
+ `_promote_temp_output` so a temporary directory on a different
139
+ filesystem cannot silently drop the chunk TOC. Tool-chain failures are
140
+ contained without aborting the split loop. Time complexity O(m) over
141
+ TOC content size plus external process latency.
142
+ @param output_file {str} Generated chunk path receiving the TOC metadata.
143
+ @param toc_content {str} Range-filtered pdftk dump-data bookmark payload.
144
+ @return {None} Mutates `output_file` content on success.
145
+ @throws {OSError} Propagated when temporary payload creation, unlink, or
146
+ non-EXDEV promotion fails.
147
+ @satisfies REQ-032
148
+ """
106
149
  if not toc_content.strip():
107
150
  return
108
151
  with tempfile.NamedTemporaryFile(mode="w", suffix=".info", delete=False) as f:
@@ -124,7 +167,7 @@ def _apply_toc(output_file, toc_content):
124
167
  capture_output=True,
125
168
  )
126
169
  if r2.returncode == 0:
127
- os.replace(with_toc, output_file)
170
+ _promote_temp_output(with_toc, output_file)
128
171
  else:
129
172
  os.unlink(with_toc)
130
173
  print(f" [!] Warning: unable to update TOC for '{output_file}'.")
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env python3
2
+ import errno
2
3
  import os
3
4
  import re
5
+ import shutil
4
6
  import subprocess
5
7
  import tempfile
6
8
 
@@ -76,7 +78,48 @@ def _sanitize_title(title):
76
78
  return safe.strip("-")
77
79
 
78
80
 
81
+ def _promote_temp_output(temp_output, output_file):
82
+ """
83
+ @brief Promote one pdftk-produced temporary artifact onto the final output path.
84
+ @details Attempts same-device atomic replacement via `os.replace`. On
85
+ `OSError` with `errno.EXDEV` (temporary directory and output directory
86
+ located on different filesystems), falls back to `shutil.move`, which
87
+ copies the artifact content and removes the temporary source. All other
88
+ `OSError` values propagate unchanged to preserve pre-existing failure
89
+ semantics. Time complexity O(1) for same-device renames, O(n) over file
90
+ size for the cross-device copy fallback.
91
+ @param temp_output {str} Temporary artifact path produced by the external tool chain.
92
+ @param output_file {str} Final chunk path that must receive the artifact content.
93
+ @return {None} Applies destination filesystem mutation.
94
+ @throws {OSError} Propagated for non-EXDEV replacement failures.
95
+ @satisfies REQ-031, REQ-032
96
+ """
97
+ try:
98
+ os.replace(temp_output, output_file)
99
+ except OSError as error:
100
+ if error.errno != errno.EXDEV:
101
+ raise
102
+ shutil.move(temp_output, output_file)
103
+
104
+
79
105
  def _apply_toc_to_file(output_file, toc_content):
106
+ """
107
+ @brief Reapply rebased TOC data to one generated chunk file.
108
+ @details Writes `toc_content` into a temporary `.info` payload, strips
109
+ object streams from `output_file` via `qpdf`, rebuilds the chunk with
110
+ TOC metadata via `pdftk update_info`, and promotes the artifact onto
111
+ `output_file` through `_promote_temp_output` so a temporary directory
112
+ on a different filesystem cannot crash chunk generation. Emits a
113
+ warning and keeps the original chunk when the tool chain fails.
114
+ Time complexity O(m) over TOC content size plus external process
115
+ latency.
116
+ @param output_file {str} Generated chunk path receiving the TOC metadata.
117
+ @param toc_content {str} Rebased pdftk dump-data bookmark payload.
118
+ @return {None} Mutates `output_file` content on success.
119
+ @throws {OSError} Propagated when temporary payload creation, unlink, or
120
+ non-EXDEV promotion fails.
121
+ @satisfies REQ-031
122
+ """
80
123
  if not toc_content.strip():
81
124
  return
82
125
  with tempfile.NamedTemporaryFile(mode="w", suffix=".info", delete=False) as f:
@@ -95,7 +138,7 @@ def _apply_toc_to_file(output_file, toc_content):
95
138
  capture_output=True,
96
139
  )
97
140
  if r2.returncode == 0:
98
- os.replace(with_toc, output_file)
141
+ _promote_temp_output(with_toc, output_file)
99
142
  else:
100
143
  if os.path.exists(with_toc):
101
144
  os.unlink(with_toc)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shellscripts
3
- Version: 0.23.1
3
+ Version: 0.24.0
4
4
  Summary: Execute useful shell scripts via an uvx-compatible CLI interface.
5
5
  Author: Francesco Rolando
6
6
  License-Expression: GPL-3.0-only
@@ -31,7 +31,7 @@ Dynamic: license-file
31
31
  > * **No Support or Feature Requests:** Please **do not** open issues, bug reports, or feature requests. They will not be addressed or accepted at this stage of development.
32
32
  > * **No Warranty:** This software is provided **"AS IS"**, without warranty of any kind, express or implied. You may use it strictly for **testing and evaluation purposes** at your own sole risk.
33
33
 
34
- # s/shellScripts (0.23.1)
34
+ # s/shellScripts (0.24.0)
35
35
 
36
36
  <p align="center">
37
37
  <img src="https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python 3.11+">
@@ -1,4 +1,4 @@
1
- shell_scripts/__init__.py,sha256=tcta0Vrn-w5n4wRkcb6xWB5jcyslWz3oKUyNDDU4ago,96
1
+ shell_scripts/__init__.py,sha256=a6rN3qPobydw-A4eFoUNo6Srdf1OtkoPSloLLg3Yuic,96
2
2
  shell_scripts/__main__.py,sha256=-wEmwKTfeY5TphAH82E38XRPoB4KT5QDLDgRZz84PTs,83
3
3
  shell_scripts/config.py,sha256=YUs8QWsZ31lJPrMpFqvn7YLQdseQnlaiu7OXcXsKdEw,12640
4
4
  shell_scripts/core.py,sha256=rhgy9xduzkujsjD4NRL2AYvtNI3yTVnPThzEAzyMWUM,11204
@@ -22,8 +22,8 @@ shell_scripts/commands/kiro.py,sha256=NuD2Zx76azDQAWbJ8YcewshEogLmrd-Avu9feisqHy
22
22
  shell_scripts/commands/opencode.py,sha256=64I3IHrliAZ7C4jTU4WLxQcJHJohJcKex09yhegWUoc,1900
23
23
  shell_scripts/commands/pdf_crop.py,sha256=VliRAMHMjnSQK9mZhNoghftZAVGZeJG6xhrihcuuawQ,15135
24
24
  shell_scripts/commands/pdf_merge.py,sha256=vTTlUv8oVYUo9U45b4yUpK4x0unIwctgXV7g5exvihc,5996
25
- shell_scripts/commands/pdf_split_by_format.py,sha256=kWID9sadX9cf0jMWFqTyCFMRHwAFNZVmnp24IlcN1H8,7573
26
- shell_scripts/commands/pdf_split_by_toc.py,sha256=I027ldWXat8ODafn3KRD1X52yeUP2xez1PX-kFNptAg,6674
25
+ shell_scripts/commands/pdf_split_by_format.py,sha256=yG4Vbv1oPaHEElMK-TUqDVoqM6G1O3UY0nVcO5RsqMY,9789
26
+ shell_scripts/commands/pdf_split_by_toc.py,sha256=Q9VNqBoPQQOd4Dm14dm2S8W2JPc3I3WuhQYMxXKX55Q,8848
27
27
  shell_scripts/commands/pdf_tiler_090.py,sha256=1eLCw9rqGN8LELB5lBvx6xfaTYc4Kci5YDK2EvnHG6E,1781
28
28
  shell_scripts/commands/pdf_tiler_100.py,sha256=U-DlX_PJPHL2P2p0wvWMzb-XkxVYn5-Jb1vqlBzIAqA,1805
29
29
  shell_scripts/commands/pdf_toc_clean.py,sha256=7GroNjVbOoh184AbYoqXSVdK_RHqA3y5urjkZ4lcJbw,5907
@@ -37,9 +37,9 @@ shell_scripts/commands/video2h265.py,sha256=Sr_UWGz_V77x4anmuy8kiWZv5I_AOFlV0WDn
37
37
  shell_scripts/commands/view_cmd.py,sha256=qHEivQHZpZCTE3VSFP1ay2SuqgancQlEKxJcKtyeqNA,1827
38
38
  shell_scripts/commands/vscode_cmd.py,sha256=Rkcjt5A1HMzqJoh2Yz9VRGoLP-L3qpRO5hkcSrzOmvA,1461
39
39
  shell_scripts/commands/vsinsider_cmd.py,sha256=KTTv1cVpJO-u1ktxOE0W_o4AAmz20pAvkDtyhpU9XBg,1548
40
- shellscripts-0.23.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
41
- shellscripts-0.23.1.dist-info/METADATA,sha256=BihFSRKVrmcCCAiiJLu0B5seR0Unkn0W2-WCrrgWo0A,10985
42
- shellscripts-0.23.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
43
- shellscripts-0.23.1.dist-info/entry_points.txt,sha256=9ICAgH87fxHBzi3f6JXIVcsPWzAKsCh4_1xS8JThQ0M,85
44
- shellscripts-0.23.1.dist-info/top_level.txt,sha256=7bDVqjcR5CfCCArCP4X4e9gYJ-ua8z-GfQeHbAo8rCY,14
45
- shellscripts-0.23.1.dist-info/RECORD,,
40
+ shellscripts-0.24.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
41
+ shellscripts-0.24.0.dist-info/METADATA,sha256=93w8nhYX9LfkcAQxSMCwdBYXNnkYdwjUgTjCG4HNIoo,10985
42
+ shellscripts-0.24.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
43
+ shellscripts-0.24.0.dist-info/entry_points.txt,sha256=9ICAgH87fxHBzi3f6JXIVcsPWzAKsCh4_1xS8JThQ0M,85
44
+ shellscripts-0.24.0.dist-info/top_level.txt,sha256=7bDVqjcR5CfCCArCP4X4e9gYJ-ua8z-GfQeHbAo8rCY,14
45
+ shellscripts-0.24.0.dist-info/RECORD,,