Skip to content

Commit ad48b2a

Browse files
committed
Enhance _exec_cmd function to improve error handling and output collection; add unit test for this issue #35
1 parent 27d541e commit ad48b2a

File tree

2 files changed

+49
-26
lines changed

2 files changed

+49
-26
lines changed

sling/sling/__init__.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -492,34 +492,40 @@ def cli(*args, return_output=False):
492492
return 0
493493

494494

495-
def _exec_cmd(cmd, stdin=None, stdout=PIPE, stderr=STDOUT, env:dict=None):
496-
lines = []
497-
498-
env = env or {}
499-
for k,v in os.environ.items():
500-
env[k] = env.get(k, v)
501-
502-
env['SLING_PACKAGE'] = 'python'
503-
for pkg in ['dagster', 'airflow', 'temporal', 'orkes']:
504-
if is_package(pkg):
505-
env['SLING_PACKAGE'] = pkg
506-
507-
with Popen(cmd, shell=True, env=env, stdin=stdin, stdout=stdout, stderr=stderr) as proc:
508-
if stdout and stdout != STDOUT and proc.stdout:
509-
for line in proc.stdout:
510-
line = str(line.strip(), 'utf-8', errors='replace')
511-
yield line
495+
def _exec_cmd(
496+
cmd: str, stdin=None, stdout=PIPE, stderr=STDOUT, env: dict[str, str] | None = None
497+
):
498+
lines: list[str] = []
512499

513-
proc.wait()
514-
515-
if stderr and stderr != STDOUT and proc.stderr:
516-
lines = '\n'.join(list(proc.stderr))
517-
518-
if proc.returncode != 0:
519-
if len(lines) > 0:
520-
raise Exception(f'Sling command failed:\n{lines}')
521-
raise Exception(f'Sling command failed')
500+
env = env or {}
501+
for k, v in os.environ.items():
502+
env[k] = env.get(k, v)
522503

504+
env["SLING_PACKAGE"] = "python"
505+
for pkg in ["dagster", "airflow", "temporal", "orkes"]:
506+
if is_package(pkg):
507+
env["SLING_PACKAGE"] = pkg
508+
509+
with Popen(
510+
cmd, shell=True, env=env, stdin=stdin, stdout=stdout, stderr=stderr
511+
) as proc:
512+
if stdout and stdout != STDOUT and proc.stdout:
513+
for line in proc.stdout:
514+
line = str(line.strip(), "utf-8", errors="replace")
515+
lines.append(line)
516+
yield line
517+
518+
proc.wait()
519+
520+
if stderr and stderr != STDOUT and proc.stderr:
521+
lines.extend(
522+
str(line.strip(), "utf-8", errors="replace") for line in proc.stderr
523+
)
524+
525+
if proc.returncode != 0:
526+
if len(lines) > 0:
527+
raise Exception(f"Sling command failed:\n{'\n'.join(lines)}")
528+
raise Exception("Sling command failed")
523529

524530

525531
class SlingError(Exception):

sling/tests/test_sling_class.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,23 @@ def test_stream_arrow_from_polars_input(self, temp_dir, sample_data):
763763
assert abs(actual - expected) < 0.001, f"Salary mismatch at index {i}: {actual} != {expected}"
764764

765765

766+
class TestExecCmd:
767+
"""Tests for the internal command execution helper."""
768+
769+
def test_exec_cmd_includes_stdout_on_error(self):
770+
"""When a subprocess prints an error to STDOUT and exits non-zero
771+
the helper should include that output in the raised exception.
772+
"""
773+
from sling import _exec_cmd
774+
775+
cmd = "bash -c 'echo fatal: invalid stream; exit 1'"
776+
777+
with pytest.raises(Exception) as excinfo:
778+
list(_exec_cmd(cmd))
779+
780+
assert 'fatal:' in str(excinfo.value)
781+
782+
766783
if __name__ == "__main__":
767784
# Run tests if executed directly
768785
pytest.main([__file__, "-v"])

0 commit comments

Comments
 (0)