awsquery 1.1.0__tar.gz → 1.2.0__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.
- {awsquery-1.1.0 → awsquery-1.2.0}/.github/workflows/quality.yml +5 -1
- {awsquery-1.1.0 → awsquery-1.2.0}/.gitignore +8 -1
- awsquery-1.2.0/AGENTS.md +62 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/Makefile +35 -0
- {awsquery-1.1.0/src/awsquery.egg-info → awsquery-1.2.0}/PKG-INFO +412 -18
- {awsquery-1.1.0 → awsquery-1.2.0}/README.md +406 -12
- awsquery-1.2.0/llms-full.txt +390 -0
- awsquery-1.2.0/llms.txt +21 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/pyproject.toml +13 -7
- awsquery-1.2.0/src/awsquery/agent-reference.md +390 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/cli.py +440 -211
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/config.py +36 -1
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/core.py +84 -64
- awsquery-1.2.0/src/awsquery/data_fields.yaml +41 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/default_filters.yaml +339 -602
- awsquery-1.2.0/src/awsquery/errors.py +245 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/filter_validator.py +2 -2
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/formatters.py +191 -99
- awsquery-1.2.0/src/awsquery/introspection.py +222 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/security.py +34 -2
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/shapes.py +170 -28
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/utils.py +8 -1
- {awsquery-1.1.0 → awsquery-1.2.0/src/awsquery.egg-info}/PKG-INFO +412 -18
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery.egg-info/SOURCES.txt +11 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/conftest.py +18 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_feature_combinations.py +37 -31
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_keys_behavior.py +30 -12
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_multi_level.py +4 -4
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_session_management.py +69 -4
- awsquery-1.2.0/tests/unit/test_agent_reference.py +201 -0
- awsquery-1.2.0/tests/unit/test_cli_flags.py +1197 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_cli_help_output.py +28 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_cli_session_args.py +3 -1
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_config_loading_simple.py +0 -1
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_core.py +116 -8
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_default_column_filters.py +273 -6
- awsquery-1.2.0/tests/unit/test_errors.py +500 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_formatters.py +562 -23
- awsquery-1.2.0/tests/unit/test_introspection.py +393 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_keys_display_fix.py +4 -8
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_security.py +6 -5
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_security_edge_cases.py +2 -1
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_shapes.py +209 -10
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_tags_transformation.py +5 -8
- awsquery-1.2.0/uv.lock +3395 -0
- awsquery-1.1.0/tests/unit/test_cli_flags.py +0 -386
- {awsquery-1.1.0 → awsquery-1.2.0}/.claude/agents/code-reviewer.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.claude/agents/makefile-optimizer.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.claude/agents/python-infra-automator.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.claude/agents/test-writer.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.claude/settings.local.json +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.coveragerc +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.devcontainer/devcontainer.json +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.dockerignore +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.flake8 +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.github/workflows/release.yml +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.github/workflows/test.yml +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/e1bzl-fix-remaining-15-broken-suffix-entries-surfaced-by-audit/EXECUTION.html +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/e1bzl-fix-remaining-15-broken-suffix-entries-surfaced-by-audit/EXECUTION.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/e1bzl-fix-remaining-15-broken-suffix-entries-surfaced-by-audit/ISSUE.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/e1bzl-fix-remaining-15-broken-suffix-entries-surfaced-by-audit/PLAN.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/CONTEXT.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/EXECUTION.html +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/EXECUTION.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/ISSUE.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/PLAN.html +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/PLAN.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/RESEARCH.html +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/RESEARCH.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/research/codebase.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/research/ecosystem.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/archive/sue5t-fix-tags-default-filters-and-add-additive-column-syntax/research/pitfalls.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action/CONTEXT.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action/EXECUTION.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action/ISSUE.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action/PLAN.html +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action/PLAN.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action/RESEARCH.html +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/.issues/ty5dx-add-per-service-default-actions-so-awsquery-ec2-runs-without-an-action/RESEARCH.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/CLAUDE.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/Dockerfile +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/Dockerfile.prod +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/LICENSE +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/compose.yaml +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/coverage.json +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/debug-output.txt +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/docs/DOCKER.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/docs/mutation-testing.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/policy.json +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/pytest.ini +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/requirements.txt +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/scripts/README.md +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/scripts/audit_default_filters.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/scripts/validate-awsquery.sh +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/setup.cfg +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/__init__.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/auto_filters.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/case_utils.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/default_actions.yaml +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/filters.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery/policy.json +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery.egg-info/dependency_links.txt +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery.egg-info/entry_points.txt +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery.egg-info/requires.txt +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/src/awsquery.egg-info/top_level.txt +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/__init__.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/fixtures/__init__.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/fixtures/aws_responses.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/fixtures/policy_samples.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/__init__.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_autocomplete_resilience.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_end_to_end.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_multi_level_calls.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_parameter_option_integration.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_parameter_type_auto_wrapping.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/integration/test_shape_aware_integration.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/__init__.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_auto_filters.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_case_utils.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_cli_arg_processing.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_cli_parser.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_column_ordering.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_core_inference.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_core_string_handling.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_critical_mutations.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_cross_service_hints.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_filter_edge_cases.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_filter_implementation.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_filter_parameter_extraction.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_filter_validator.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_formatter_edge_cases.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_formatters_data_processing.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_input_hint_parameter.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_messaging_enhancements.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_parameter_option.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_parameter_type_validation.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_preemptive_multi_step.py +0 -0
- {awsquery-1.1.0 → awsquery-1.2.0}/tests/unit/test_smart_prefix_matching.py +0 -0
awsquery-1.2.0/AGENTS.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Conventions for agents working **on this repository**. If you are an agent *using* awsquery to query
|
|
4
|
+
AWS, you want `awsquery --docs` instead (source: `src/awsquery/agent-reference.md`).
|
|
5
|
+
|
|
6
|
+
## Setup and commands
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
uv sync --extra dev # create .venv with dev dependencies (or: make uv-sync)
|
|
10
|
+
uv run pytest tests/ -q # full suite, ~1700 tests, under a minute (or: make uv-test)
|
|
11
|
+
make format # black + isort, line length 100
|
|
12
|
+
make lint # flake8 + pylint
|
|
13
|
+
make type-check # mypy
|
|
14
|
+
make ci # everything CI runs
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`make install-dev` / `make test` are the pip equivalents and work the same.
|
|
18
|
+
|
|
19
|
+
Run a single test with `uv run pytest tests/unit/test_x.py::TestClass::test_method -v`.
|
|
20
|
+
|
|
21
|
+
## Layout
|
|
22
|
+
|
|
23
|
+
- `src/awsquery/cli.py` — argument parsing, filter-group splitting, the `main()` flow
|
|
24
|
+
- `src/awsquery/core.py` — API execution, multi-level parameter resolution
|
|
25
|
+
- `src/awsquery/shapes.py` — botocore service-model introspection (credential-free field discovery)
|
|
26
|
+
- `src/awsquery/security.py` — read-only enforcement by operation prefix
|
|
27
|
+
- `src/awsquery/filters.py`, `formatters.py` — filtering and output rendering
|
|
28
|
+
- `src/awsquery/default_filters.yaml`, `default_actions.yaml` — curated per-service defaults
|
|
29
|
+
- `src/awsquery/agent-reference.md` — the agent/LLM reference printed by `--docs`
|
|
30
|
+
|
|
31
|
+
## Non-negotiables
|
|
32
|
+
|
|
33
|
+
- **The CLI is the only stable contract.** Never change the behaviour or output of an existing flag.
|
|
34
|
+
Internal APIs have no consumers: change signatures, return types and module boundaries freely, and
|
|
35
|
+
delete dead code rather than deprecating it.
|
|
36
|
+
- **No pytest markers.** `@pytest.mark.parametrize` is the sole exception; every other
|
|
37
|
+
`@pytest.mark.*` is banned and the whole suite always runs. Test selection is directory-based
|
|
38
|
+
(`tests/unit/`, `tests/integration/`).
|
|
39
|
+
- **Test real code.** Mock only external boundaries (boto3, filesystem, network). A test that mocks
|
|
40
|
+
the function it claims to cover, or that only asserts `mock.assert_called()`, does not count.
|
|
41
|
+
- **No filler test docstrings.** No restating the test name, no TDD placeholders, no narration.
|
|
42
|
+
Comment only genuinely non-obvious cases.
|
|
43
|
+
- **Check for an existing test file before creating one.** Flags belong in `test_cli_flags.py`,
|
|
44
|
+
parser behaviour in `test_cli_parser.py`, filters in `test_filter_implementation.py`.
|
|
45
|
+
- **Coverage floor is 80%** (`pytest.ini`).
|
|
46
|
+
|
|
47
|
+
## Documentation sync
|
|
48
|
+
|
|
49
|
+
`src/awsquery/agent-reference.md` is the single source of truth for the agent-facing reference. After
|
|
50
|
+
editing it, regenerate the mirror and keep the two byte-identical:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
make llms # copies it to llms-full.txt
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
A test asserts they match, and that every flag the reference documents exists in the parser. Update
|
|
57
|
+
the reference in the same commit as any CLI change.
|
|
58
|
+
|
|
59
|
+
## Commits
|
|
60
|
+
|
|
61
|
+
Single-line summary, imperative mood, 72 characters maximum, no body. Group related changes into one
|
|
62
|
+
commit; keep unrelated changes apart.
|
|
@@ -13,6 +13,8 @@ NC := \033[0m
|
|
|
13
13
|
|
|
14
14
|
.PHONY: help clean install-dev test test-unit test-integration test-critical test-slow test-fast test-unit-fast \
|
|
15
15
|
test-integration-fast coverage coverage-report lint format format-check type-check security-check ci build \
|
|
16
|
+
uv-sync uv-test uv-run uv-lock tool-install tool-uninstall \
|
|
17
|
+
llms llms-check \
|
|
16
18
|
publish-test publish watch-tests version release update-policy validate-policy all ec2-instances s3-buckets \
|
|
17
19
|
iam-users iam-roles lambda-functions cloudformation-stacks dynamodb-tables ec2-volumes \
|
|
18
20
|
ec2-security-groups s3-bucket-versioning cloudwatch-alarms route53-zones shell \
|
|
@@ -36,6 +38,32 @@ help: ## Show this help message
|
|
|
36
38
|
install-dev: ## Install development dependencies
|
|
37
39
|
pip3 install --user --break-system-packages -e ".[dev]" || pip3 install -e ".[dev]"
|
|
38
40
|
|
|
41
|
+
# =============================================================================
|
|
42
|
+
# UV TARGETS
|
|
43
|
+
# =============================================================================
|
|
44
|
+
|
|
45
|
+
uv-sync: ## Install project + dev dependencies into .venv with uv
|
|
46
|
+
uv sync --extra dev
|
|
47
|
+
|
|
48
|
+
uv-test: ## Run all tests with uv
|
|
49
|
+
uv run --extra dev pytest tests/ -v
|
|
50
|
+
|
|
51
|
+
uv-run: ## Run awsquery from the local checkout (use ARGS="ec2 describe-instances")
|
|
52
|
+
uv run awsquery $(ARGS)
|
|
53
|
+
|
|
54
|
+
uv-lock: ## Regenerate uv.lock
|
|
55
|
+
uv lock
|
|
56
|
+
|
|
57
|
+
tool-install: ## Install awsquery as a global uv tool from this checkout
|
|
58
|
+
uv tool install --force --editable .
|
|
59
|
+
|
|
60
|
+
tool-uninstall: ## Remove the globally installed awsquery uv tool
|
|
61
|
+
uv tool uninstall awsquery
|
|
62
|
+
|
|
63
|
+
# =============================================================================
|
|
64
|
+
# TEST TARGETS
|
|
65
|
+
# =============================================================================
|
|
66
|
+
|
|
39
67
|
test: ## Run all tests
|
|
40
68
|
python3 -m pytest tests/ -v
|
|
41
69
|
|
|
@@ -181,6 +209,13 @@ validate-policy: ## Validate that policy.json is a valid AWS policy document
|
|
|
181
209
|
echo "$(GREEN)✓ policy.json validation passed$(NC)" || \
|
|
182
210
|
echo "$(RED)✗ policy.json validation failed$(NC)"
|
|
183
211
|
|
|
212
|
+
llms: ## Regenerate llms-full.txt from the packaged agent reference
|
|
213
|
+
cp src/awsquery/agent-reference.md llms-full.txt
|
|
214
|
+
|
|
215
|
+
llms-check: ## Verify llms-full.txt matches the packaged agent reference
|
|
216
|
+
@cmp -s src/awsquery/agent-reference.md llms-full.txt || \
|
|
217
|
+
{ echo "llms-full.txt is out of date with src/awsquery/agent-reference.md - run 'make llms'"; exit 1; }
|
|
218
|
+
|
|
184
219
|
# =============================================================================
|
|
185
220
|
# AWS API RESPONSE SAMPLING TARGETS (PRESERVED)
|
|
186
221
|
# =============================================================================
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: awsquery
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Advanced CLI tool for querying AWS APIs with flexible filtering and automatic parameter resolution
|
|
5
5
|
Author-email: Florian Motlik <flo@flomotlik.me>
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
-
Project-URL: Documentation, https://awsquery
|
|
9
|
-
Project-URL: Repository, https://github.com/
|
|
10
|
-
Project-URL: Issues, https://github.com/
|
|
11
|
-
Project-URL: Changelog, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://github.com/flomotlik/awsquery
|
|
8
|
+
Project-URL: Documentation, https://github.com/flomotlik/awsquery#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/flomotlik/awsquery.git
|
|
10
|
+
Project-URL: Issues, https://github.com/flomotlik/awsquery/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/flomotlik/awsquery/releases
|
|
12
12
|
Keywords: aws,cli,query,cloud,devops,boto3
|
|
13
13
|
Classifier: Development Status :: 4 - Beta
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
@@ -74,6 +74,25 @@ awsquery ec2 describe-instances prod web -- Tags.Name State InstanceId vpcid
|
|
|
74
74
|
This creates endless flexibility to shape your aws cli calls, filter any output and present exactly
|
|
75
75
|
the data you need during review, debugging or development.
|
|
76
76
|
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
With [uv](https://docs.astral.sh/uv/) installed, there is nothing else to set up — no virtualenv, no
|
|
80
|
+
`pip install`, not even a Python of your own:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uvx awsquery ec2 describe-instances prod web -- Tags.Name State InstanceId
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Want it as a permanent command with tab completion?
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv tool install awsquery
|
|
90
|
+
awsquery ec2 describe-instances
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
See [Installation](#installation) for aliases, version pinning, running straight from GitHub, and CI
|
|
94
|
+
usage.
|
|
95
|
+
|
|
77
96
|
## Features
|
|
78
97
|
|
|
79
98
|
- **Smart Multi-Level Calls**: Automatically resolves missing parameters by inferring and calling list operations
|
|
@@ -94,32 +113,229 @@ the data you need during review, debugging or development.
|
|
|
94
113
|
== `awsquery ec2 describe-instances` (e.g. `awsquery s3 -- Name`)
|
|
95
114
|
- **Parameter Passing**: Direct parameter passing to AWS APIs with `-p`/`--parameter` for advanced use cases
|
|
96
115
|
- **Hint-Based Resolution**: Function selection hints with `-i`/`--input` for multi-step calls, including cross-service support and field extraction targeting
|
|
116
|
+
- **Agent/LLM Mode**: `--docs` prints the complete reference in one call; `--schema`, `--list-services` and `--list-actions` answer offline with no AWS credentials
|
|
117
|
+
- **Token-Efficient Output**: `--format csv|tsv|ndjson` and `--limit` keep results small enough for a context window
|
|
118
|
+
- **Predictable Exit Codes**: documented codes 0-4, structured JSON errors, and no interactive prompts when stdin is not a TTY
|
|
97
119
|
|
|
98
120
|
## Installation
|
|
99
121
|
|
|
100
|
-
|
|
122
|
+
`awsquery` is on PyPI, so the fastest way to use it is [uv](https://docs.astral.sh/uv/): no
|
|
123
|
+
virtualenv, no `pip install`, no Python version juggling. uv downloads a matching Python for you if
|
|
124
|
+
you don't have one.
|
|
125
|
+
|
|
126
|
+
| You want to... | Command |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| Try it once, install nothing | `uvx awsquery ec2 describe-instances` |
|
|
129
|
+
| Use it every day (and get tab completion) | `uv tool install awsquery` |
|
|
130
|
+
| Run a specific version | `uvx awsquery@1.2.0 ec2 describe-instances` |
|
|
131
|
+
| Run unreleased code from GitHub | `uvx --from git+https://github.com/flomotlik/awsquery awsquery ec2` |
|
|
132
|
+
| Hack on it locally | `uv run awsquery ec2` inside a checkout |
|
|
133
|
+
|
|
134
|
+
### Install uv (one time)
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# macOS / Linux
|
|
138
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
139
|
+
|
|
140
|
+
# Homebrew
|
|
141
|
+
brew install uv
|
|
142
|
+
|
|
143
|
+
# Windows (PowerShell)
|
|
144
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
That is the only thing anyone on your team has to install. uv itself is a single binary and brings
|
|
148
|
+
its own Python.
|
|
149
|
+
|
|
150
|
+
### Run without installing: `uvx`
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
uvx awsquery ec2 describe-instances
|
|
154
|
+
uvx awsquery s3 list-buckets backup -- Name CreationDate
|
|
155
|
+
uvx awsquery -j cloudformation describe-stacks prod
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The first run downloads awsquery and its dependencies into uv's cache (a few seconds). Every run
|
|
159
|
+
after that starts in about a tenth of a second. Nothing is added to your `PATH`, no virtualenv is
|
|
160
|
+
created, and nothing is left behind in your project.
|
|
161
|
+
|
|
162
|
+
Pin an exact version when you want reproducibility, or force a check for the newest release:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
uvx awsquery@1.2.0 ec2 describe-instances # pinned, fully reproducible
|
|
166
|
+
uvx awsquery@latest ec2 describe-instances # re-checks PyPI for a newer version
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Make it feel like a normal command: alias
|
|
170
|
+
|
|
171
|
+
Add one line to your shell config and the whole team is running the same tool without installing
|
|
172
|
+
anything:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# ~/.bashrc or ~/.zshrc
|
|
176
|
+
alias awsquery='uvx awsquery@latest'
|
|
177
|
+
|
|
178
|
+
# pin the version instead, if you want everyone on the same release
|
|
179
|
+
alias awsquery='uvx awsquery@1.2.0'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```fish
|
|
183
|
+
# ~/.config/fish/config.fish
|
|
184
|
+
alias --save awsquery 'uvx awsquery@latest'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```powershell
|
|
188
|
+
# PowerShell $PROFILE
|
|
189
|
+
function awsquery { uvx awsquery@latest @args }
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Then use it exactly as documented everywhere else in this README:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
awsquery ec2 describe-instances prod web -- Tags.Name State InstanceId
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Two things to know about the alias route: `@latest` contacts PyPI on every invocation (so it needs
|
|
199
|
+
network and adds a moment of latency), and shell tab completion does not work through an alias
|
|
200
|
+
because argcomplete needs a real executable on `PATH`. If either matters to you, use
|
|
201
|
+
`uv tool install` instead — it gives you the same command with neither drawback.
|
|
202
|
+
|
|
203
|
+
### Install as a persistent tool: `uv tool install`
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
uv tool install awsquery # installs the awsquery command into ~/.local/bin
|
|
207
|
+
awsquery ec2 describe-instances
|
|
208
|
+
|
|
209
|
+
uv tool upgrade awsquery # upgrade later
|
|
210
|
+
uv tool uninstall awsquery # remove it again
|
|
211
|
+
uv tool list # see what's installed
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
uv keeps awsquery in its own isolated environment, so it can never conflict with your project
|
|
215
|
+
virtualenvs or your system Python. If the command isn't found afterwards, run `uv tool update-shell`
|
|
216
|
+
(it adds uv's bin directory to your `PATH`) and restart your shell.
|
|
217
|
+
|
|
218
|
+
This is the recommended setup for daily use and the one that supports
|
|
219
|
+
[shell autocomplete](#enable-shell-autocomplete).
|
|
220
|
+
|
|
221
|
+
### Run unreleased code straight from GitHub
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# latest commit on main, run once
|
|
225
|
+
uvx --from git+https://github.com/flomotlik/awsquery awsquery ec2 describe-instances
|
|
226
|
+
|
|
227
|
+
# a specific branch, tag or commit
|
|
228
|
+
uvx --from git+https://github.com/flomotlik/awsquery@main awsquery ec2 describe-instances
|
|
229
|
+
uvx --from git+https://github.com/flomotlik/awsquery@v1.2.0 awsquery ec2 describe-instances
|
|
230
|
+
|
|
231
|
+
# install that version persistently
|
|
232
|
+
uv tool install git+https://github.com/flomotlik/awsquery
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`--from` is needed because the package name (`awsquery`) has to be resolved from the repository
|
|
236
|
+
while the command to execute is still `awsquery`.
|
|
237
|
+
|
|
238
|
+
### Run from a local checkout
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
git clone https://github.com/flomotlik/awsquery.git
|
|
242
|
+
cd awsquery
|
|
243
|
+
|
|
244
|
+
# run the working tree directly - uv creates and syncs .venv on the fly
|
|
245
|
+
uv run awsquery ec2 describe-instances
|
|
246
|
+
|
|
247
|
+
# or via make
|
|
248
|
+
make uv-run ARGS="ec2 describe-instances"
|
|
249
|
+
|
|
250
|
+
# put your local checkout on PATH as the global awsquery command
|
|
251
|
+
uv tool install --editable . # same as: make tool-install
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`uv run` resolves dependencies from `uv.lock`, which is committed to this repository, so every
|
|
255
|
+
contributor gets an identical environment. Use `uv run --frozen awsquery ...` to fail instead of
|
|
256
|
+
silently re-locking if the lockfile is out of date.
|
|
257
|
+
|
|
258
|
+
### Python versions
|
|
259
|
+
|
|
260
|
+
awsquery requires Python 3.10 or newer. uv fetches a suitable interpreter automatically, so you do
|
|
261
|
+
not need a system Python at all. To force a specific version:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
uvx --python 3.12 awsquery ec2 describe-instances
|
|
265
|
+
uv tool install --python 3.12 awsquery
|
|
266
|
+
uv run --python 3.12 awsquery ec2 describe-instances
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### AWS credentials with uv
|
|
270
|
+
|
|
271
|
+
uvx does not sandbox anything: the tool runs as you, with your environment and your `~/.aws`
|
|
272
|
+
directory, so credentials, SSO sessions, profiles, assumed roles and `AWS_*` environment variables
|
|
273
|
+
all behave exactly as they do with the AWS CLI.
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
AWS_PROFILE=prod uvx awsquery ec2 describe-instances
|
|
277
|
+
uvx awsquery --profile prod --region eu-central-1 ec2 describe-instances
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Using awsquery in CI
|
|
281
|
+
|
|
282
|
+
No install step is needed beyond uv itself:
|
|
283
|
+
|
|
284
|
+
```yaml
|
|
285
|
+
# GitHub Actions
|
|
286
|
+
- uses: astral-sh/setup-uv@v6
|
|
287
|
+
- run: uvx awsquery@1.2.0 -j cloudformation describe-stacks -- StackName StackStatus
|
|
288
|
+
env:
|
|
289
|
+
AWS_REGION: eu-central-1
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Pin the version (`awsquery@1.2.0`) in CI so a new release can never change your output format
|
|
293
|
+
underneath a pipeline.
|
|
294
|
+
|
|
295
|
+
### Via pip
|
|
296
|
+
|
|
297
|
+
If your team does not use uv, the classic routes still work:
|
|
101
298
|
|
|
102
299
|
```bash
|
|
103
|
-
pip install awsquery
|
|
300
|
+
pip install awsquery # into the current environment
|
|
301
|
+
pipx install awsquery # isolated, like uv tool install
|
|
104
302
|
```
|
|
105
303
|
|
|
106
|
-
### Development
|
|
304
|
+
### Development installation
|
|
107
305
|
|
|
108
306
|
```bash
|
|
109
|
-
git clone https://github.com/
|
|
307
|
+
git clone https://github.com/flomotlik/awsquery.git
|
|
110
308
|
cd awsquery
|
|
111
|
-
|
|
309
|
+
uv sync --extra dev # or: make uv-sync
|
|
310
|
+
uv run pytest tests/ -v # or: make uv-test
|
|
112
311
|
```
|
|
113
312
|
|
|
313
|
+
The pip equivalent is `pip install -e ".[dev]"` (`make install-dev`).
|
|
314
|
+
|
|
114
315
|
### Enable Shell Autocomplete
|
|
115
316
|
|
|
116
317
|
awsquery supports tab completion for AWS services and actions through argcomplete.
|
|
117
318
|
|
|
319
|
+
Completion requires a real `awsquery` executable on your `PATH`, because the shell calls that
|
|
320
|
+
executable to compute the candidates. So it works with `uv tool install awsquery`, `pipx install`
|
|
321
|
+
and `pip install` — but **not** with a `uvx` alias, since the alias is expanded by your shell after
|
|
322
|
+
completion has already run.
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
uv tool install awsquery # the setup below assumes this (or pip/pipx)
|
|
326
|
+
```
|
|
327
|
+
|
|
118
328
|
#### Setup
|
|
119
329
|
|
|
330
|
+
The `register-python-argcomplete` helper comes from argcomplete. With uv you never have to install
|
|
331
|
+
it: `uvx --from argcomplete register-python-argcomplete` runs it on demand.
|
|
332
|
+
|
|
120
333
|
##### Bash
|
|
121
334
|
```bash
|
|
122
335
|
# Add to ~/.bashrc or ~/.bash_profile
|
|
336
|
+
eval "$(uvx --from argcomplete register-python-argcomplete awsquery)"
|
|
337
|
+
|
|
338
|
+
# If argcomplete is already installed in your environment (pip/pipx users):
|
|
123
339
|
eval "$(register-python-argcomplete awsquery)"
|
|
124
340
|
```
|
|
125
341
|
|
|
@@ -127,13 +343,21 @@ eval "$(register-python-argcomplete awsquery)"
|
|
|
127
343
|
```bash
|
|
128
344
|
# Add to ~/.zshrc
|
|
129
345
|
autoload -U bashcompinit && bashcompinit
|
|
130
|
-
eval "$(register-python-argcomplete awsquery)"
|
|
346
|
+
eval "$(uvx --from argcomplete register-python-argcomplete awsquery)"
|
|
131
347
|
```
|
|
132
348
|
|
|
133
349
|
##### Fish
|
|
134
350
|
```bash
|
|
135
351
|
# Add to ~/.config/fish/config.fish
|
|
136
|
-
register-python-argcomplete --shell fish awsquery | source
|
|
352
|
+
uvx --from argcomplete register-python-argcomplete --shell fish awsquery | source
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
To keep shell startup instant, write the completion script to a file once and source that instead of
|
|
356
|
+
calling uvx on every new shell:
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
uvx --from argcomplete register-python-argcomplete awsquery > ~/.awsquery-complete.sh
|
|
360
|
+
echo 'source ~/.awsquery-complete.sh' >> ~/.zshrc # or ~/.bashrc
|
|
137
361
|
```
|
|
138
362
|
|
|
139
363
|
After adding the appropriate line to your shell configuration, restart your shell or source the file:
|
|
@@ -195,7 +419,8 @@ awsquery -d ec2 describe-instances
|
|
|
195
419
|
## Command Structure
|
|
196
420
|
|
|
197
421
|
```
|
|
198
|
-
awsquery [-j|--json] [-k|--keys] [-d|--debug] [-p PARAM] [-i HINT] [--region REGION] [--profile PROFILE] SERVICE ACTION [VALUE_FILTERS...] [-- TABLE_OUTPUT_FILTERS...]
|
|
422
|
+
awsquery [-j|--json] [--format FMT] [--limit N] [-k|--keys] [-d|--debug] [-p PARAM] [-i HINT] [--region REGION] [--profile PROFILE] SERVICE ACTION [VALUE_FILTERS...] [-- TABLE_OUTPUT_FILTERS...]
|
|
423
|
+
awsquery --docs | --list-services | [SERVICE] --list-actions | --schema SERVICE ACTION
|
|
199
424
|
```
|
|
200
425
|
|
|
201
426
|
- **SERVICE**: AWS service name (ec2, s3, iam, etc.)
|
|
@@ -209,6 +434,12 @@ awsquery [-j|--json] [-k|--keys] [-d|--debug] [-p PARAM] [-i HINT] [--region REG
|
|
|
209
434
|
- **-i, --input HINT**: Multi-step control with cross-service support and function/field/limit hints (e.g., "ec2:desc-inst:instanceid", "desc-clus", ":arn", "::5")
|
|
210
435
|
- **--region REGION**: AWS region to use for requests (e.g., us-west-2)
|
|
211
436
|
- **--profile PROFILE**: AWS profile to use from ~/.aws/credentials
|
|
437
|
+
- **--format FMT**: Output format - `table` (default), `json`, `csv`, `tsv`, `ndjson`
|
|
438
|
+
- **--limit N**: Truncate printed rows to N (independent of the `-i ::N` resource cap)
|
|
439
|
+
- **--docs**: Print the complete agent/LLM reference and exit (no AWS call)
|
|
440
|
+
- **--schema**: Print an operation's input parameters and output fields (no AWS call)
|
|
441
|
+
- **--list-services / --list-actions**: Enumerate services or a service's read-only actions (no AWS call)
|
|
442
|
+
- **--allow-unsafe**: Permit a non-read-only operation without prompting
|
|
212
443
|
|
|
213
444
|
## Security
|
|
214
445
|
|
|
@@ -410,8 +641,148 @@ arguments). A service with no curated entry prints its available ReadOnly action
|
|
|
410
641
|
and exits non-zero; `awsquery` with no service at all is unchanged — it still lists available
|
|
411
642
|
services on stdout and exits 0.
|
|
412
643
|
|
|
644
|
+
## Using awsquery with AI Agents and LLMs
|
|
645
|
+
|
|
646
|
+
awsquery is built to be driven by coding agents and LLM tool calls, not just typed by hand. Three
|
|
647
|
+
things make that work: the tool documents itself, it can describe any AWS operation without calling
|
|
648
|
+
AWS, and its output can be made cheap in tokens.
|
|
649
|
+
|
|
650
|
+
### The tool explains itself
|
|
651
|
+
|
|
652
|
+
```bash
|
|
653
|
+
awsquery --docs
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
Prints the complete agent reference - filter grammar, every flag, output formats, exit codes, the
|
|
657
|
+
safety model, recipes and failure modes - as Markdown on stdout, in one call, with no AWS access.
|
|
658
|
+
About 16 KB, sized to drop straight into a context window. This is the one command to give an agent
|
|
659
|
+
that has never seen awsquery before.
|
|
660
|
+
|
|
661
|
+
The same text is mirrored at [`llms-full.txt`](llms-full.txt) with an [`llms.txt`](llms.txt) index
|
|
662
|
+
([llmstxt.org](https://llmstxt.org/) convention) for agents that fetch from GitHub rather than run
|
|
663
|
+
the binary. [`AGENTS.md`](AGENTS.md) is the separate file for agents working *on* this repository.
|
|
664
|
+
|
|
665
|
+
### Discovery without credentials
|
|
666
|
+
|
|
667
|
+
These make no AWS API call, need no credentials and no region, and answer in well under a second -
|
|
668
|
+
so an agent can plan a query before it has any access at all:
|
|
669
|
+
|
|
670
|
+
```bash
|
|
671
|
+
awsquery --list-services # every supported service
|
|
672
|
+
awsquery ec2 --list-actions # that service's read-only operations
|
|
673
|
+
awsquery --schema ec2 describe-instances # inputs, and every field the API can return
|
|
674
|
+
awsquery --schema -j ec2 describe-instances # the same as JSON
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
`--schema` reads botocore's service model, so it lists all 213 output field paths for
|
|
678
|
+
`ec2 describe-instances` with their types - including fields that happen to be absent from your
|
|
679
|
+
account right now. It also tells you how to turn those paths into column filters.
|
|
680
|
+
|
|
681
|
+
That is the difference from `-k`/`--keys`, which is still there and still useful:
|
|
682
|
+
|
|
683
|
+
| | `--schema` | `-k` / `--keys` |
|
|
684
|
+
| --- | --- | --- |
|
|
685
|
+
| Answers | what the API **can** return | what your account **did** return |
|
|
686
|
+
| AWS call | none | yes |
|
|
687
|
+
| Needs credentials | no | yes |
|
|
688
|
+
| Completeness | every field | only fields populated in existing resources |
|
|
689
|
+
|
|
690
|
+
Use `--schema` to choose columns; use `-k` to inspect real data. `-k` follows `--format` too.
|
|
691
|
+
|
|
692
|
+
### Token-efficient output
|
|
693
|
+
|
|
694
|
+
Table borders and indented JSON are expensive to read. Measured on 50 rows by 5 columns: grid table
|
|
695
|
+
~2340 tokens, `--format json` ~2440, `--format csv` ~790.
|
|
696
|
+
|
|
697
|
+
```bash
|
|
698
|
+
awsquery --format csv --limit 50 ec2 describe-instances prod -- InstanceId Tags.Name State.Name
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
- `--format table` (default), `json`, `csv`, `tsv`, `ndjson`
|
|
702
|
+
- `-j`/`--json` is equivalent to `--format json`
|
|
703
|
+
- `csv`, `tsv`, `ndjson` and `json` are faithful: values are not truncated, falsy values are
|
|
704
|
+
preserved, native types survive in the JSON formats (csv/tsv cells are text), and one resource
|
|
705
|
+
is always one row. `table` is a display format - it truncates long values, summarises repeats as
|
|
706
|
+
`(+N more)`, renders falsy cells blank and drops all-blank rows, so never parse it
|
|
707
|
+
- An empty result set prints nothing at all under `csv`/`tsv`/`ndjson` (headers come from the
|
|
708
|
+
data); only `json` still returns `{"results": []}`. Exit status is 0 either way
|
|
709
|
+
- `--limit N` truncates the printed resources in any format and notes the truncation on stderr
|
|
710
|
+
- `--limit` is independent of `-i ::N`, which caps resources fed into multi-level resolution
|
|
711
|
+
(note `-i ::0` means unlimited, while `--limit 0` means zero rows)
|
|
712
|
+
|
|
713
|
+
### Predictable in a tool-call loop
|
|
714
|
+
|
|
715
|
+
```bash
|
|
716
|
+
export AWSQUERY_NON_INTERACTIVE=1
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
A non-read-only operation is then refused immediately with exit 2 instead of prompting - awsquery
|
|
720
|
+
never blocks on stdin and never returns a traceback for it. The same applies automatically whenever
|
|
721
|
+
stdin is not a TTY.
|
|
722
|
+
|
|
723
|
+
stdout carries data only; notices and errors go to stderr, so stdout stays parseable.
|
|
724
|
+
|
|
725
|
+
| Exit code | Meaning |
|
|
726
|
+
| --- | --- |
|
|
727
|
+
| 0 | success, including an empty result set |
|
|
728
|
+
| 1 | general or unexpected error |
|
|
729
|
+
| 2 | usage error, unknown service/action, or unsafe operation refused |
|
|
730
|
+
| 3 | AWS API error |
|
|
731
|
+
| 4 | credentials, region or authentication failure |
|
|
732
|
+
|
|
733
|
+
Unknown services and actions are caught offline, before any AWS call, so a typo costs nothing and
|
|
734
|
+
comes back with the command that fixes it. Under `--format json` and `--format ndjson`, errors are
|
|
735
|
+
also emitted to stderr as one compact JSON object:
|
|
736
|
+
|
|
737
|
+
```json
|
|
738
|
+
{"error": {"code": 2, "type": "UnknownService", "message": "Unknown service 'ec3'",
|
|
739
|
+
"hint": "Run: awsquery --list-services"}}
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
A successful run with nothing to report uses a `notice` key instead, so branching on the presence
|
|
743
|
+
of `error` is safe.
|
|
744
|
+
|
|
745
|
+
`AWS_REGION` is honoured as a fallback when `AWS_DEFAULT_REGION` is unset, since agents commonly set
|
|
746
|
+
the former and plain boto3 ignores it.
|
|
747
|
+
|
|
748
|
+
### Recommended agent workflow
|
|
749
|
+
|
|
750
|
+
```bash
|
|
751
|
+
awsquery --docs # once, to learn the tool
|
|
752
|
+
awsquery --schema -j ec2 describe-instances # pick fields, no credentials needed
|
|
753
|
+
awsquery --format csv --limit 50 \
|
|
754
|
+
ec2 describe-instances prod -- InstanceId Tags.Name State.Name # one narrow query
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
Combined with `uvx`, an agent needs no install step at all: `uvx awsquery --docs`.
|
|
758
|
+
|
|
413
759
|
## Development
|
|
414
760
|
|
|
761
|
+
### Environment setup with uv
|
|
762
|
+
|
|
763
|
+
```bash
|
|
764
|
+
# Create .venv and install the project plus dev dependencies from uv.lock
|
|
765
|
+
uv sync --extra dev # or: make uv-sync
|
|
766
|
+
|
|
767
|
+
# Run anything inside that environment without activating it
|
|
768
|
+
uv run awsquery ec2 describe-instances # or: make uv-run ARGS="ec2 describe-instances"
|
|
769
|
+
uv run pytest tests/ -v # or: make uv-test
|
|
770
|
+
uv run black src tests
|
|
771
|
+
uv run mypy src
|
|
772
|
+
|
|
773
|
+
# Update the lockfile after changing dependencies in pyproject.toml
|
|
774
|
+
uv lock # or: make uv-lock
|
|
775
|
+
|
|
776
|
+
# Install your working tree as the global awsquery command
|
|
777
|
+
uv tool install --editable . # or: make tool-install
|
|
778
|
+
uv tool uninstall awsquery # or: make tool-uninstall
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
`uv.lock` is committed, so `uv sync` gives every contributor byte-identical dependency versions.
|
|
782
|
+
Regenerate it with `uv lock` whenever `pyproject.toml` dependencies change and commit the result.
|
|
783
|
+
|
|
784
|
+
The `make` targets below use pip and the system Python; they work unchanged if you prefer that.
|
|
785
|
+
|
|
415
786
|
### Running Tests
|
|
416
787
|
|
|
417
788
|
```bash
|
|
@@ -502,9 +873,11 @@ All filters in awsquery use **case-insensitive matching** with optional anchorin
|
|
|
502
873
|
- No operators: matches values that CONTAIN the pattern (partial match)
|
|
503
874
|
|
|
504
875
|
#### Value Filters (before `--`)
|
|
505
|
-
- Match against ANY field in the response data
|
|
876
|
+
- Match against ANY field in the response data - both the values **and the field names**
|
|
506
877
|
- ALL specified filters must match (AND logic)
|
|
507
878
|
- Case-insensitive matching with optional anchoring
|
|
879
|
+
- Because names are searched too, a field name used as a value filter matches every resource
|
|
880
|
+
(`awsquery ec2 describe-instances InstanceId` returns everything). Column names belong after `--`
|
|
508
881
|
|
|
509
882
|
```bash
|
|
510
883
|
# "prod" matches: "production", "prod-server", "my-prod-app" (contains)
|
|
@@ -527,6 +900,9 @@ awsquery ec2 describe-instances ^prod web$
|
|
|
527
900
|
- Match against column/field names in the output
|
|
528
901
|
- Case-insensitive matching with optional anchoring
|
|
529
902
|
- Multiple columns can be specified
|
|
903
|
+
- Anchors apply to the full flattened key (`Instances.0.State.Name`), not the displayed header, so
|
|
904
|
+
prefer suffix anchors (`State.Name$`) for nested fields - which is why the curated defaults in
|
|
905
|
+
`default_filters.yaml` are all `$`-anchored
|
|
530
906
|
|
|
531
907
|
```bash
|
|
532
908
|
# "Instance" matches: "InstanceId", "InstanceType", "InstanceName" (contains)
|
|
@@ -538,8 +914,10 @@ awsquery ec2 describe-instances -- ^Instance
|
|
|
538
914
|
# "Name$" matches: "InstanceName", "GroupName", "Tags.Name" (ends with)
|
|
539
915
|
awsquery ec2 describe-instances -- Name$
|
|
540
916
|
|
|
541
|
-
#
|
|
542
|
-
|
|
917
|
+
# Anchors apply to the FULL flattened key, which includes list indices
|
|
918
|
+
# (e.g. "Instances.0.State.Name"), so "^State.Name$" matches nothing here.
|
|
919
|
+
# Use a suffix anchor for nested fields:
|
|
920
|
+
awsquery ec2 describe-instances -- State.Name$
|
|
543
921
|
|
|
544
922
|
# Multiple patterns
|
|
545
923
|
awsquery ec2 describe-instances -- ^Instance Name$ State
|
|
@@ -616,7 +994,7 @@ awsquery elbv2 describe-tags -i desc-clus:clusterarn prod
|
|
|
616
994
|
# Result limiting - control how many resources are processed (default: 10)
|
|
617
995
|
awsquery ssm get-parameters -i ::5 # Limit to 5 parameters
|
|
618
996
|
awsquery ec2 describe-instances -i ::20 # Limit to 20 instances
|
|
619
|
-
awsquery
|
|
997
|
+
awsquery s3 list-objects-v2 -i ::0 # Unlimited (remove default limit)
|
|
620
998
|
|
|
621
999
|
# Field override without function (uses inferred function)
|
|
622
1000
|
awsquery ecs describe-tasks -i :clusterarn # Extract ClusterArn field
|
|
@@ -690,8 +1068,24 @@ awsquery s3 list-buckets backup -- Name Creation
|
|
|
690
1068
|
- Use more specific filters to reduce data volume
|
|
691
1069
|
- Consider using `--region` to target specific regions
|
|
692
1070
|
|
|
1071
|
+
**`awsquery: command not found` after `uv tool install`**
|
|
1072
|
+
- Run `uv tool update-shell` and restart your shell; uv's bin directory (`~/.local/bin`) has to be on `PATH`
|
|
1073
|
+
- `uv tool list` shows what is installed
|
|
1074
|
+
|
|
1075
|
+
**uvx keeps running an old version**
|
|
1076
|
+
- `uvx awsquery` reuses the cached version; use `uvx awsquery@latest` to re-check PyPI
|
|
1077
|
+
- `uv cache clean awsquery` drops the cached build entirely
|
|
1078
|
+
- For an installed tool use `uv tool upgrade awsquery`
|
|
1079
|
+
|
|
1080
|
+
**Tab completion does not work**
|
|
1081
|
+
- Completion needs a real executable on `PATH`: use `uv tool install awsquery`, not a `uvx` alias
|
|
1082
|
+
- See [Enable Shell Autocomplete](#enable-shell-autocomplete)
|
|
1083
|
+
|
|
693
1084
|
## Requirements
|
|
694
1085
|
|
|
1086
|
+
- Python 3.10 or newer - or just [uv](https://docs.astral.sh/uv/), which supplies its own Python
|
|
1087
|
+
- AWS credentials configured the same way the AWS CLI expects them
|
|
1088
|
+
|
|
695
1089
|
The package dependencies are:
|
|
696
1090
|
|
|
697
1091
|
- boto3>=1.35.0
|