Skip to content

Add pos3 CLI (ls, download, upload) and bump to 0.3.1#11

Open
vertix wants to merge 3 commits into
mainfrom
claude/add-documentation-trVyZ
Open

Add pos3 CLI (ls, download, upload) and bump to 0.3.1#11
vertix wants to merge 3 commits into
mainfrom
claude/add-documentation-trVyZ

Conversation

@vertix
Copy link
Copy Markdown
Contributor

@vertix vertix commented May 23, 2026

Summary

  • Add a pos3 console-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.
  • Bump version 0.3.00.3.1 and add a [0.3.1] CHANGELOG entry covering the CLI.
  • No changes to existing public Python API or to requires-python (stays >=3.11).

Test plan

  • pip install -e . and confirm pos3 --help lists ls, download, upload
  • pos3 ls <path> against a configured profile prints expected entries
  • pos3 download <remote> <local> writes the file and exits 0
  • pos3 upload <local> <remote> uploads and is visible via ls
  • Run the existing test suite — no regressions

https://claude.ai/code/session_01QoQaZ2G6FsNpSZyStqTXas


Generated by Claude Code

claude added 2 commits May 21, 2026 15:32
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
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread pos3/cli.py
Comment on lines +76 to +79
local_path = download(
args.url,
local=args.local,
delete=args.delete,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment thread pos3/cli.py
Comment on lines +106 to +108
upload(
args.url,
local=source,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread pos3/cli.py
Comment on lines +98 to +99
with mirror(show_progress=False):
_print_download_plan(args)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants