Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions python/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
[1.0.4] - 2026-XX-XX
--------------------

**Features**

- CLI commands that load a tree sequence now accept ``-`` as the input path to
read from stdin. (:issue:`3468`)

--------------------
[1.0.3] - 2026-05-14
--------------------
Expand Down
22 changes: 22 additions & 0 deletions python/tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ def capture_output(func, *args, **kwargs):
return stdout_output, stderr_output


class MockStdIn:
def __init__(self, buffer):
self.buffer = buffer


class TestCli(unittest.TestCase):
"""
Superclass of tests for the CLI needing temp files.
Expand Down Expand Up @@ -310,6 +315,16 @@ def test_vcf_allow_position_zero(self, flags, expected):
assert args.tree_sequence == tree_sequence
assert args.allow_position_zero == expected

def test_vcf_stdin_file(self):
parser = cli.get_tskit_parser()
args = parser.parse_args(["vcf", "-"])
assert args.tree_sequence == "-"

def test_vcf_requires_tree_sequence(self):
parser = cli.get_tskit_parser()
with pytest.raises(SystemExit):
parser.parse_args(["vcf"])

def test_info_default_values(self):
parser = cli.get_tskit_parser()
cmd = "info"
Expand Down Expand Up @@ -560,6 +575,13 @@ def test_vcf(self):
assert len(stderr) == 0
self.verify_vcf(stdout)

def test_vcf_stdin(self):
with open(self._tree_sequence_file, "rb") as f:
with mock.patch("sys.stdin", MockStdIn(f)):
stdout, stderr = capture_output(cli.tskit_main, ["vcf", "-0", "-"])
assert len(stderr) == 0
self.verify_vcf(stdout)

def verify_info(self, ts, output_info):
assert str(ts) == output_info

Expand Down
14 changes: 11 additions & 3 deletions python/tskit/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,15 @@ def sys_exit(message):


def load_tree_sequence(path):
if path in [None, "-"]:
path = getattr(sys.stdin, "buffer", sys.stdin)
try:
return tskit.load(path)
except OSError as e:
sys_exit(f"Load error: {e}")
except (OSError, EOFError, tskit.FileFormatError) as e:
message = str(e)
if isinstance(e, EOFError) and len(message) == 0:
message = "End of file"
sys_exit(f"Load error: {message}")


def run_info(args):
Expand Down Expand Up @@ -134,7 +139,10 @@ def run_vcf(args):


def add_tree_sequence_argument(parser):
parser.add_argument("tree_sequence", help="The tskit tree sequence file")
parser.add_argument(
"tree_sequence",
help="The tskit tree sequence file, or '-' for stdin",
)


def add_precision_argument(parser):
Expand Down