better-aws-tags 0.4.0__tar.gz → 0.6.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.
- better_aws_tags-0.6.0/.claude/rules/python.md +12 -0
- better_aws_tags-0.6.0/CLAUDE.md +101 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/Makefile +4 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/PKG-INFO +18 -2
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/README.md +16 -1
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/pyproject.toml +2 -0
- better_aws_tags-0.4.0/scratchpad/tags/tagging_resources.py → better_aws_tags-0.6.0/scratchpad/get_supported_resources.py +21 -4
- better_aws_tags-0.6.0/scratchpad/supported_resources.py +1146 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/src/better_aws_tags/__init__.py +1 -1
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/__init__.py +45 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/asg.py +54 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/base.py +13 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/cloudfront.py +27 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/glue.py +25 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/iam.py +79 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/inspector.py +26 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/rds.py +26 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/resource_explorer.py +25 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/ses.py +26 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/tagging_api.py +48 -0
- better_aws_tags-0.6.0/src/better_aws_tags/handlers/wafv2.py +27 -0
- better_aws_tags-0.6.0/src/better_aws_tags/supported_resources.py +1146 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/src/better_aws_tags/tags.py +18 -9
- better_aws_tags-0.6.0/src/better_aws_tags/unsupported_resources.py +29 -0
- better_aws_tags-0.6.0/tests/integration/check_coverage.py +80 -0
- better_aws_tags-0.6.0/tests/test_dispatch.py +63 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/uv.lock +14 -1
- better_aws_tags-0.4.0/scratchpad/arn/.gitignore +0 -3
- better_aws_tags-0.4.0/scratchpad/arn/Makefile +0 -16
- better_aws_tags-0.4.0/scratchpad/arn/arn_patterns.py +0 -2797
- better_aws_tags-0.4.0/scratchpad/arn/arn_patterns_test.py +0 -203
- better_aws_tags-0.4.0/scratchpad/arn/stage_01_aws_services.py +0 -57
- better_aws_tags-0.4.0/scratchpad/arn/stage_02_aws_resources.py +0 -88
- better_aws_tags-0.4.0/scratchpad/arn/stage_03_aws_tag_actions.py +0 -112
- better_aws_tags-0.4.0/scratchpad/arn/stage_04_arn_index.py +0 -77
- better_aws_tags-0.4.0/scratchpad/arn/stage_05_arn_matcher.py +0 -92
- better_aws_tags-0.4.0/scratchpad/arn/stage_06_arn_regex.py +0 -213
- better_aws_tags-0.4.0/scratchpad/tags/aws_cloudformation.py +0 -47
- better_aws_tags-0.4.0/scratchpad/tags/aws_services.py +0 -30
- better_aws_tags-0.4.0/scratchpad/tags/mapping_resource_tagging.py +0 -110
- better_aws_tags-0.4.0/scratchpad/tags/mapping_resources.py +0 -57
- better_aws_tags-0.4.0/scratchpad/tags/mapping_services.py +0 -292
- better_aws_tags-0.4.0/scratchpad/tags/mapping_services_next.py +0 -88
- better_aws_tags-0.4.0/scratchpad/tags/tagging_apis.py +0 -99
- better_aws_tags-0.4.0/src/better_aws_tags/arnmatch/__init__.py +0 -108
- better_aws_tags-0.4.0/src/better_aws_tags/arnmatch/patterns.py +0 -2797
- better_aws_tags-0.4.0/src/better_aws_tags/arnparse.py +0 -147
- better_aws_tags-0.4.0/src/better_aws_tags/handlers.py +0 -139
- better_aws_tags-0.4.0/tests/test_arnmatch.py +0 -403
- better_aws_tags-0.4.0/tests/test_arnparse.py +0 -427
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/.github/workflows/release.yml +0 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/.gitignore +0 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/.python-version +0 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/CHANGELOG.md +0 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/scratchpad/.gitignore +0 -0
- {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/tests/test_import.py +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.py"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Python Rules
|
|
7
|
+
|
|
8
|
+
## Naming
|
|
9
|
+
|
|
10
|
+
- Never use type suffixes in variable names (`_list`, `_dict`, `_map`, `_str`, `_int`, etc.)
|
|
11
|
+
- Bad: `users_list`, `config_dict`, `name_str`, `handler_map`, `count_int`
|
|
12
|
+
- Good: `users`, `config`, `name`, `handlers`, `count`
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## EXTREMELY IMPORTANT
|
|
6
|
+
|
|
7
|
+
- NEVER use bare `try...except` or `except Exception`. ALWAYS catch specific exceptions.
|
|
8
|
+
- NEVER do defensive programming. Let code FAIL if there is an unhandled exception.
|
|
9
|
+
- ALWAYS validate results of API calls (boto3, HTTP, etc.). Check the response to confirm the operation succeeded.
|
|
10
|
+
|
|
11
|
+
## Build and Development Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
make dev # Run in development mode (uv run python -m better_aws_tags)
|
|
15
|
+
make run # Run debug script (uv run python -i debug_bats.py)
|
|
16
|
+
make test # Run tests on Python 3.10-3.13
|
|
17
|
+
make lint # Run ruff linter
|
|
18
|
+
make fmt # Format code with ruff
|
|
19
|
+
make check # Run lint and tests
|
|
20
|
+
make build # Build package
|
|
21
|
+
make publish # Build and publish to PyPI
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Run a single test:
|
|
25
|
+
```bash
|
|
26
|
+
uv run pytest tests/test_dispatch.py::test_dispatch_supported_resource -v
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Architecture
|
|
30
|
+
|
|
31
|
+
This library provides a unified API for AWS resource tagging that abstracts away the differences between AWS's various tagging APIs.
|
|
32
|
+
|
|
33
|
+
### Core Flow
|
|
34
|
+
|
|
35
|
+
1. **Entry points** (`src/better_aws_tags/tags.py`): `get_tags()` and `set_tags()` accept ARNs and optional boto3 session
|
|
36
|
+
2. **Dispatch** (`tags.py:dispatch()`): Routes ARNs to appropriate handlers based on resource type
|
|
37
|
+
3. **Handlers** (`src/better_aws_tags/handlers.py`): Execute AWS API calls
|
|
38
|
+
|
|
39
|
+
### Handlers
|
|
40
|
+
|
|
41
|
+
- `TaggingAPIHandler`: Uses Resource Groups Tagging API for resources in `SUPPORTED_RESOURCES`
|
|
42
|
+
- `IAMRoleHandler`: IAM roles (`arn:aws:iam::*:role/*`)
|
|
43
|
+
- `IAMUserHandler`: IAM users (`arn:aws:iam::*:user/*`)
|
|
44
|
+
- `IAMPolicyHandler`: IAM policies (`arn:aws:iam::*:policy/*`)
|
|
45
|
+
|
|
46
|
+
The `HANDLERS` dict maps `(service, resource_type)` tuples to handler classes for resources not covered by the Tagging API.
|
|
47
|
+
|
|
48
|
+
### Handler Routing Logic
|
|
49
|
+
|
|
50
|
+
The `dispatch()` function determines which handler to use:
|
|
51
|
+
1. If CloudFormation resource type is in `SUPPORTED_RESOURCES` → `TaggingAPIHandler`
|
|
52
|
+
2. If `(service, resource_type)` is in `HANDLERS` → specific handler
|
|
53
|
+
3. Otherwise → raises `NotImplementedError`
|
|
54
|
+
|
|
55
|
+
### Dependencies
|
|
56
|
+
|
|
57
|
+
- `arnmatch`: Parses ARNs and extracts service, resource type, and CloudFormation resource type
|
|
58
|
+
- `boto3`: AWS SDK for Python
|
|
59
|
+
|
|
60
|
+
## Adding Support for New Resources
|
|
61
|
+
|
|
62
|
+
1. **Run integration tests** to identify unsupported resources:
|
|
63
|
+
```bash
|
|
64
|
+
uv run python tests/integration/check_coverage.py
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
2. **Get sample ARN** and parse with arnmatch:
|
|
68
|
+
```python
|
|
69
|
+
from arnmatch import arnmatch
|
|
70
|
+
data = arnmatch(arn)
|
|
71
|
+
print('aws_service:', data.aws_service)
|
|
72
|
+
print('resource_type:', data.resource_type)
|
|
73
|
+
print('tagging_resource:', data.tagging_resource)
|
|
74
|
+
```
|
|
75
|
+
If `tagging_resource` is not `None` and is in `SUPPORTED_RESOURCES` → TaggingAPIHandler works.
|
|
76
|
+
If `tagging_resource` is `None` → need custom handler or mark unsupported.
|
|
77
|
+
|
|
78
|
+
3. **Check if boto client exists**:
|
|
79
|
+
```python
|
|
80
|
+
client = data.client()
|
|
81
|
+
```
|
|
82
|
+
If no client exists → resource is not taggable.
|
|
83
|
+
|
|
84
|
+
4. **Check if tagging methods exist**:
|
|
85
|
+
```python
|
|
86
|
+
tag_methods = [m for m in dir(client) if 'tag' in m.lower()]
|
|
87
|
+
```
|
|
88
|
+
If no tag methods → add to `unsupported_resources.py`.
|
|
89
|
+
|
|
90
|
+
5. **Test if tagging works for this resource type**:
|
|
91
|
+
```python
|
|
92
|
+
client.list_tags_for_resource(resourceArn=arn) # or similar
|
|
93
|
+
```
|
|
94
|
+
If fails with "invalid resource" → add to `unsupported_resources.py`.
|
|
95
|
+
|
|
96
|
+
6. **If taggable, write a handler**:
|
|
97
|
+
- Create `src/better_aws_tags/handlers/{service}.py`
|
|
98
|
+
- Implement `get_tags` and `set_tags` methods
|
|
99
|
+
- Register in `handlers/__init__.py` with `(service, resource_type)` key
|
|
100
|
+
|
|
101
|
+
7. **Re-run integration tests** to verify coverage.
|
|
@@ -19,6 +19,10 @@ test: ## Run tests on all Python versions
|
|
|
19
19
|
uv run --python 3.12 pytest -v
|
|
20
20
|
uv run --python 3.13 pytest -v
|
|
21
21
|
|
|
22
|
+
.PHONY: test-integration
|
|
23
|
+
test-integration: ## Run integration tests (requires AWS credentials)
|
|
24
|
+
uv run python tests/integration/check_coverage.py
|
|
25
|
+
|
|
22
26
|
.PHONY: lint
|
|
23
27
|
lint: ## Run linter
|
|
24
28
|
uv run ruff check .
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: better-aws-tags
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A unified Python interface for managing AWS resource tags
|
|
5
5
|
Author-email: Andrey Gubarev <andrey@andreygubarev.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: arnmatch>=2026.2.2
|
|
7
8
|
Requires-Dist: boto3~=1.0
|
|
8
9
|
Description-Content-Type: text/markdown
|
|
9
10
|
|
|
@@ -11,14 +12,29 @@ Description-Content-Type: text/markdown
|
|
|
11
12
|
|
|
12
13
|
A unified Python interface for managing AWS resource tags.
|
|
13
14
|
|
|
14
|
-
AWS provides multiple tagging APIs across services, including the Resource Groups Tagging API and service-specific implementations such as EC2, S3, and IAM. This library abstracts these differences behind a single API that accepts any valid ARN and handles service routing
|
|
15
|
+
AWS provides multiple tagging APIs across services, including the Resource Groups Tagging API and service-specific implementations such as EC2, S3, and IAM. This library abstracts these differences behind a single API that accepts any valid ARN and handles service routing automatically.
|
|
15
16
|
|
|
16
17
|
## Getting Started
|
|
17
18
|
|
|
18
19
|
```python
|
|
19
20
|
import better_aws_tags as bats
|
|
21
|
+
|
|
22
|
+
# Get tags for resources
|
|
23
|
+
tags = bats.get_tags(["arn:aws:s3:::my-bucket", "arn:aws:iam::123456789012:role/my-role"])
|
|
24
|
+
|
|
25
|
+
# Set tags on resources
|
|
26
|
+
bats.set_tags(["arn:aws:s3:::my-bucket"], {"Environment": "prod", "Team": "platform"})
|
|
20
27
|
```
|
|
21
28
|
|
|
29
|
+
## How It Works
|
|
30
|
+
|
|
31
|
+
The library routes ARNs to the appropriate handler:
|
|
32
|
+
|
|
33
|
+
1. Most resources use the **Resource Groups Tagging API** (1000+ supported resource types)
|
|
34
|
+
2. Some IAM resources (roles, users, policies) require **IAM-specific APIs**
|
|
35
|
+
|
|
36
|
+
This routing is transparent - just pass ARNs and the library handles the rest.
|
|
37
|
+
|
|
22
38
|
## Reference
|
|
23
39
|
|
|
24
40
|
- https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/overview.html
|
|
@@ -2,14 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
A unified Python interface for managing AWS resource tags.
|
|
4
4
|
|
|
5
|
-
AWS provides multiple tagging APIs across services, including the Resource Groups Tagging API and service-specific implementations such as EC2, S3, and IAM. This library abstracts these differences behind a single API that accepts any valid ARN and handles service routing
|
|
5
|
+
AWS provides multiple tagging APIs across services, including the Resource Groups Tagging API and service-specific implementations such as EC2, S3, and IAM. This library abstracts these differences behind a single API that accepts any valid ARN and handles service routing automatically.
|
|
6
6
|
|
|
7
7
|
## Getting Started
|
|
8
8
|
|
|
9
9
|
```python
|
|
10
10
|
import better_aws_tags as bats
|
|
11
|
+
|
|
12
|
+
# Get tags for resources
|
|
13
|
+
tags = bats.get_tags(["arn:aws:s3:::my-bucket", "arn:aws:iam::123456789012:role/my-role"])
|
|
14
|
+
|
|
15
|
+
# Set tags on resources
|
|
16
|
+
bats.set_tags(["arn:aws:s3:::my-bucket"], {"Environment": "prod", "Team": "platform"})
|
|
11
17
|
```
|
|
12
18
|
|
|
19
|
+
## How It Works
|
|
20
|
+
|
|
21
|
+
The library routes ARNs to the appropriate handler:
|
|
22
|
+
|
|
23
|
+
1. Most resources use the **Resource Groups Tagging API** (1000+ supported resource types)
|
|
24
|
+
2. Some IAM resources (roles, users, policies) require **IAM-specific APIs**
|
|
25
|
+
|
|
26
|
+
This routing is transparent - just pass ARNs and the library handles the rest.
|
|
27
|
+
|
|
13
28
|
## Reference
|
|
14
29
|
|
|
15
30
|
- https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/overview.html
|
|
@@ -76,12 +76,29 @@ def fetch_resource_types(
|
|
|
76
76
|
return resource_types
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
def generate_python(resource_types: list[str]) -> str:
|
|
80
|
+
"""Generate Python module with SUPPORTED_RESOURCES constant."""
|
|
81
|
+
lines = [
|
|
82
|
+
'"""Resource types supported by AWS Resource Groups Tagging API."""',
|
|
83
|
+
"",
|
|
84
|
+
"SUPPORTED_RESOURCES: list[str] = [",
|
|
85
|
+
]
|
|
86
|
+
for rt in resource_types:
|
|
87
|
+
lines.append(f' "{rt}",')
|
|
88
|
+
lines.append("]")
|
|
89
|
+
lines.append("")
|
|
90
|
+
return "\n".join(lines)
|
|
91
|
+
|
|
92
|
+
|
|
79
93
|
def main():
|
|
80
94
|
resource_types = fetch_resource_types(query_type="TAG_FILTERS_1_0")
|
|
81
|
-
resource_types =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
95
|
+
resource_types = sorted(set(resource_types))
|
|
96
|
+
|
|
97
|
+
output = generate_python(resource_types)
|
|
98
|
+
with open("supported_resources.py", "w") as f:
|
|
99
|
+
f.write(output)
|
|
100
|
+
|
|
101
|
+
print(f"Generated supported_resources.py with {len(resource_types)} resource types")
|
|
85
102
|
|
|
86
103
|
|
|
87
104
|
if __name__ == "__main__":
|