Add pos3 CLI (ls, download, upload) and bump to 0.3.1#11
Conversation
Introduces a console-script entry point so common pos3 operations are one-liners from the shell instead of requiring a Python script. - pos3 ls <prefix> [-r] [--profile NAME] — one full s3:// URL per line on stdout. - pos3 download <url> [--local PATH] [--delete] [--exclude PATTERN]... [--profile NAME] — prints only the resulting local path to stdout (progress + logs go to stderr), so data_dir=$(pos3 download s3://bucket/dataset/) is safe. - pos3 upload <url> [--local PATH] [--delete] [--exclude PATTERN]... [--profile NAME] — one-shot upload (no background loop, no interval). Source defaults to the cache path pos3 download would have produced; errors if the source is missing. --delete defaults OFF in the CLI even though the Python API defaults to True: CLI defaults are conservative for interactive shell use. --profile is honored alongside the URL form s3://<profile>@bucket/...; URL wins on conflict, matching existing Python precedence. https://claude.ai/code/session_01QoQaZ2G6FsNpSZyStqTXas
v0.3.0 is already released; the pos3 CLI added in the previous commit ships as 0.3.1. CHANGELOG section moves from [Unreleased] to [0.3.1]. https://claude.ai/code/session_01QoQaZ2G6FsNpSZyStqTXas
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9da3a7b6be
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| local_path = download( | ||
| args.url, | ||
| local=args.local, | ||
| delete=args.delete, |
There was a problem hiding this comment.
Reject non-S3 source URLs in
download
_cmd_download forwards args.url directly to download() without validating the s3:// scheme, but download() treats non-S3 inputs as local passthrough (_Mirror.download returns the resolved path and does no transfer). As a result, pos3 download bucket/path exits 0 and prints a local path even though nothing was downloaded, which can silently break shell pipelines that rely on success status and stdout path.
Useful? React with 👍 / 👎.
| upload( | ||
| args.url, | ||
| local=source, |
There was a problem hiding this comment.
Reject non-S3 destination URLs in
upload
When --local is provided, _cmd_upload never validates that args.url is an S3 URL before calling upload(). For non-S3 destinations, upload() takes the local-path passthrough branch (_Mirror.upload), creates that local directory, and returns success without any remote upload. This makes commands like pos3 upload ./dst --local ./src report success while performing no S3 operation.
Useful? React with 👍 / 👎.
The flag is accepted only on the two transfer subcommands (ls rejects it). Dry-run reuses the existing _compute_sync_diff so the plan reflects what a real run would do; output is `aws s3 sync --dryrun`-style one-line-per-file on stdout. No transfers, deletes, or directory creation happen. Synthesized directory entries from _scan_s3 are skipped so the output is file-level. https://claude.ai/code/session_01QoQaZ2G6FsNpSZyStqTXas
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db93dd27a0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| with mirror(show_progress=False): | ||
| _print_download_plan(args) |
There was a problem hiding this comment.
Avoid creating cache dirs in dry-run path
download -n is documented as performing no directory creation, but this branch still enters mirror(), and mirror constructs _Mirror, which unconditionally calls cache_root.mkdir(...) in pos3/__init__.py. So even a dry run mutates the local filesystem (typically ~/.cache/positronic/s3), which can break workflows that rely on dry-run being side-effect free.
Useful? React with 👍 / 👎.
Summary
pos3console-script CLI with three subcommands:ls,download,upload. Uses the existing profile registry so URLs and auth resolve the same way they do for the Python API.0.3.0→0.3.1and add a[0.3.1]CHANGELOG entry covering the CLI.requires-python(stays>=3.11).Test plan
pip install -e .and confirmpos3 --helplistsls,download,uploadpos3 ls <path>against a configured profile prints expected entriespos3 download <remote> <local>writes the file and exits 0pos3 upload <local> <remote>uploads and is visible vialshttps://claude.ai/code/session_01QoQaZ2G6FsNpSZyStqTXas
Generated by Claude Code