deepctl-shared-utils 0.1.12__tar.gz → 0.1.14__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.
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/PKG-INFO +1 -1
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/pyproject.toml +1 -1
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/__init__.py +1 -1
- deepctl_shared_utils-0.1.14/src/deepctl_shared_utils/diagnostics.py +52 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/ffprobe.py +53 -10
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/validation.py +7 -2
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils.egg-info/PKG-INFO +1 -1
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils.egg-info/SOURCES.txt +1 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/README.md +0 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/setup.cfg +0 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/ffprobe_models.py +0 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/models.py +0 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/py.typed +0 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils.egg-info/dependency_links.txt +0 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils.egg-info/requires.txt +0 -0
- {deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deepctl-shared-utils"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.14" # x-release-please-version
|
|
8
8
|
description = "Shared utilities for deepctl"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Plain-text diagnostic output shared by utilities outside deepctl-core."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from typing import TextIO
|
|
6
|
+
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def is_non_interactive() -> bool:
|
|
11
|
+
"""Mirror deepctl-core's agent and non-interactive output policy.
|
|
12
|
+
|
|
13
|
+
Shared utilities intentionally do not depend on deepctl-core, so keep this
|
|
14
|
+
lightweight detection aligned with ``deepctl_core.output.is_agentic``.
|
|
15
|
+
"""
|
|
16
|
+
env = os.environ
|
|
17
|
+
|
|
18
|
+
if "--non-interactive" in sys.argv or "--agent-friendly" in sys.argv:
|
|
19
|
+
return True
|
|
20
|
+
if env.get("CI") in ("true", "1"):
|
|
21
|
+
return True
|
|
22
|
+
if env.get("CLAUDECODE") or env.get("CLAUDE_CODE_ENTRYPOINT"):
|
|
23
|
+
return True
|
|
24
|
+
if env.get("CODEX_SANDBOX") or env.get("CODEX_SANDBOX_NETWORK_DISABLED"):
|
|
25
|
+
return True
|
|
26
|
+
if env.get("OR_APP_NAME") == "Aider" or "aider" in env.get("OR_SITE_URL", ""):
|
|
27
|
+
return True
|
|
28
|
+
|
|
29
|
+
score = 0
|
|
30
|
+
if not sys.stdin.isatty():
|
|
31
|
+
score += 1
|
|
32
|
+
if not sys.stdout.isatty():
|
|
33
|
+
score += 1
|
|
34
|
+
if not env.get("TERM") or env.get("TERM") == "dumb":
|
|
35
|
+
score += 1
|
|
36
|
+
if "NO_COLOR" in env:
|
|
37
|
+
score += 1
|
|
38
|
+
|
|
39
|
+
return score >= 3
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def create_diagnostic_console(
|
|
43
|
+
*, file: TextIO | None = None, force_terminal: bool | None = None
|
|
44
|
+
) -> Console:
|
|
45
|
+
"""Create a stderr diagnostic console with the shared plain-text policy."""
|
|
46
|
+
non_interactive = is_non_interactive()
|
|
47
|
+
return Console(
|
|
48
|
+
file=file or sys.stderr,
|
|
49
|
+
force_terminal=force_terminal,
|
|
50
|
+
no_color=non_interactive,
|
|
51
|
+
highlight=not non_interactive,
|
|
52
|
+
)
|
{deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/ffprobe.py
RENAMED
|
@@ -5,38 +5,81 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
7
|
import platform
|
|
8
|
-
import shutil
|
|
9
8
|
import subprocess
|
|
10
9
|
import tempfile
|
|
11
10
|
from typing import TYPE_CHECKING
|
|
12
11
|
|
|
13
|
-
from rich.console import Console
|
|
14
12
|
from rich.panel import Panel
|
|
15
13
|
|
|
14
|
+
from .diagnostics import create_diagnostic_console
|
|
16
15
|
from .ffprobe_models import AudioFormatInfo, AudioProbeResult, AudioStreamInfo
|
|
17
16
|
|
|
18
17
|
if TYPE_CHECKING:
|
|
19
18
|
from deepctl_core import Config
|
|
20
19
|
|
|
21
|
-
console
|
|
20
|
+
# Diagnostics only: every console.print below is an error, a warning or a
|
|
21
|
+
# progress line -- never a payload -- so it goes to stderr and can never
|
|
22
|
+
# corrupt the machine-readable result a command writes to stdout (#104).
|
|
23
|
+
# deepctl-shared-utils does not depend on deepctl-core, so this local factory
|
|
24
|
+
# mirrors core's agentic/no-color policy instead of importing `stderr_console`.
|
|
25
|
+
console = create_diagnostic_console()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ffprobe_input(file_path: str | os.PathLike[str]) -> str:
|
|
29
|
+
"""Name ``file_path`` for ffprobe as an input file, never as an option.
|
|
30
|
+
|
|
31
|
+
ffprobe has no ``--`` end-of-options marker, so a file named ``-f lavfi``
|
|
32
|
+
would be read as options. The ``file:`` protocol prefix with an absolute
|
|
33
|
+
path makes ffprobe treat it as a plain file, whatever it is called.
|
|
34
|
+
"""
|
|
35
|
+
return "file:" + os.path.abspath(os.fspath(file_path))
|
|
22
36
|
|
|
23
37
|
|
|
24
38
|
def get_ffprobe_path(config: Config | None = None) -> str | None:
|
|
25
39
|
"""Get the ffprobe binary path.
|
|
26
40
|
|
|
27
|
-
Checks stored config path first, then falls back to
|
|
28
|
-
|
|
41
|
+
Checks the stored config path first, then falls back to a PATH lookup.
|
|
42
|
+
A stored path is used only when it is absolute, and the PATH lookup
|
|
43
|
+
skips relative and empty entries and the current directory itself (on
|
|
44
|
+
every OS), so a binary inside the current directory is never picked up
|
|
45
|
+
implicitly. The result is always an absolute path.
|
|
29
46
|
"""
|
|
30
47
|
if config is not None:
|
|
31
48
|
stored_path = config.get("tools.ffprobe_path")
|
|
32
49
|
if (
|
|
33
|
-
stored_path
|
|
50
|
+
isinstance(stored_path, str)
|
|
51
|
+
and os.path.isabs(stored_path)
|
|
34
52
|
and os.path.isfile(stored_path)
|
|
35
53
|
and os.access(stored_path, os.X_OK)
|
|
36
54
|
):
|
|
37
|
-
return
|
|
55
|
+
return stored_path
|
|
56
|
+
return _find_on_path("ffprobe")
|
|
38
57
|
|
|
39
|
-
|
|
58
|
+
|
|
59
|
+
def _find_on_path(name: str) -> str | None:
|
|
60
|
+
"""Absolute path of ``name`` from PATH, never from the current directory.
|
|
61
|
+
|
|
62
|
+
Mirrors ``deepctl_core.tools.find_executable`` (this package does not
|
|
63
|
+
depend on deepctl-core).
|
|
64
|
+
"""
|
|
65
|
+
try:
|
|
66
|
+
cwd: str | None = os.path.realpath(os.getcwd())
|
|
67
|
+
except OSError:
|
|
68
|
+
cwd = None
|
|
69
|
+
names = [name]
|
|
70
|
+
if platform.system() == "Windows" and not os.path.splitext(name)[1]:
|
|
71
|
+
exts = os.environ.get("PATHEXT", ".COM;.EXE;.BAT;.CMD").split(os.pathsep)
|
|
72
|
+
names = [name + ext for ext in exts if ext]
|
|
73
|
+
for entry in os.environ.get("PATH", os.defpath).split(os.pathsep):
|
|
74
|
+
if not entry or not os.path.isabs(entry):
|
|
75
|
+
continue
|
|
76
|
+
if cwd is not None and os.path.realpath(entry) == cwd:
|
|
77
|
+
continue
|
|
78
|
+
for candidate in names:
|
|
79
|
+
path = os.path.join(entry, candidate)
|
|
80
|
+
if os.path.isfile(path) and os.access(path, os.X_OK):
|
|
81
|
+
return path
|
|
82
|
+
return None
|
|
40
83
|
|
|
41
84
|
|
|
42
85
|
def check_ffprobe(config: Config | None = None) -> bool:
|
|
@@ -157,7 +200,7 @@ def probe_file(file_path: str, config: Config | None = None) -> AudioProbeResult
|
|
|
157
200
|
"json",
|
|
158
201
|
"-show_format",
|
|
159
202
|
"-show_streams",
|
|
160
|
-
file_path,
|
|
203
|
+
ffprobe_input(file_path),
|
|
161
204
|
]
|
|
162
205
|
|
|
163
206
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
@@ -204,7 +247,7 @@ def probe_buffer(
|
|
|
204
247
|
"json",
|
|
205
248
|
"-show_format",
|
|
206
249
|
"-show_streams",
|
|
207
|
-
tmp_name,
|
|
250
|
+
ffprobe_input(tmp_name),
|
|
208
251
|
]
|
|
209
252
|
|
|
210
253
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
{deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/validation.py
RENAMED
|
@@ -6,11 +6,16 @@ from pathlib import Path
|
|
|
6
6
|
from urllib.parse import urlparse
|
|
7
7
|
|
|
8
8
|
import httpx
|
|
9
|
-
from rich.console import Console
|
|
10
9
|
|
|
10
|
+
from .diagnostics import create_diagnostic_console
|
|
11
11
|
from .models import FileInfo
|
|
12
12
|
|
|
13
|
-
console
|
|
13
|
+
# Diagnostics only: every console.print below is an error, a warning or a
|
|
14
|
+
# progress line -- never a payload -- so it goes to stderr and can never
|
|
15
|
+
# corrupt the machine-readable result a command writes to stdout (#104).
|
|
16
|
+
# deepctl-shared-utils does not depend on deepctl-core, so this local factory
|
|
17
|
+
# mirrors core's agentic/no-color policy instead of importing `stderr_console`.
|
|
18
|
+
console = create_diagnostic_console()
|
|
14
19
|
|
|
15
20
|
# Supported audio file extensions
|
|
16
21
|
SUPPORTED_AUDIO_EXTENSIONS = {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/models.py
RENAMED
|
File without changes
|
{deepctl_shared_utils-0.1.12 → deepctl_shared_utils-0.1.14}/src/deepctl_shared_utils/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|