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.
Files changed (56) hide show
  1. better_aws_tags-0.6.0/.claude/rules/python.md +12 -0
  2. better_aws_tags-0.6.0/CLAUDE.md +101 -0
  3. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/Makefile +4 -0
  4. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/PKG-INFO +18 -2
  5. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/README.md +16 -1
  6. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/pyproject.toml +2 -0
  7. better_aws_tags-0.4.0/scratchpad/tags/tagging_resources.py → better_aws_tags-0.6.0/scratchpad/get_supported_resources.py +21 -4
  8. better_aws_tags-0.6.0/scratchpad/supported_resources.py +1146 -0
  9. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/src/better_aws_tags/__init__.py +1 -1
  10. better_aws_tags-0.6.0/src/better_aws_tags/handlers/__init__.py +45 -0
  11. better_aws_tags-0.6.0/src/better_aws_tags/handlers/asg.py +54 -0
  12. better_aws_tags-0.6.0/src/better_aws_tags/handlers/base.py +13 -0
  13. better_aws_tags-0.6.0/src/better_aws_tags/handlers/cloudfront.py +27 -0
  14. better_aws_tags-0.6.0/src/better_aws_tags/handlers/glue.py +25 -0
  15. better_aws_tags-0.6.0/src/better_aws_tags/handlers/iam.py +79 -0
  16. better_aws_tags-0.6.0/src/better_aws_tags/handlers/inspector.py +26 -0
  17. better_aws_tags-0.6.0/src/better_aws_tags/handlers/rds.py +26 -0
  18. better_aws_tags-0.6.0/src/better_aws_tags/handlers/resource_explorer.py +25 -0
  19. better_aws_tags-0.6.0/src/better_aws_tags/handlers/ses.py +26 -0
  20. better_aws_tags-0.6.0/src/better_aws_tags/handlers/tagging_api.py +48 -0
  21. better_aws_tags-0.6.0/src/better_aws_tags/handlers/wafv2.py +27 -0
  22. better_aws_tags-0.6.0/src/better_aws_tags/supported_resources.py +1146 -0
  23. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/src/better_aws_tags/tags.py +18 -9
  24. better_aws_tags-0.6.0/src/better_aws_tags/unsupported_resources.py +29 -0
  25. better_aws_tags-0.6.0/tests/integration/check_coverage.py +80 -0
  26. better_aws_tags-0.6.0/tests/test_dispatch.py +63 -0
  27. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/uv.lock +14 -1
  28. better_aws_tags-0.4.0/scratchpad/arn/.gitignore +0 -3
  29. better_aws_tags-0.4.0/scratchpad/arn/Makefile +0 -16
  30. better_aws_tags-0.4.0/scratchpad/arn/arn_patterns.py +0 -2797
  31. better_aws_tags-0.4.0/scratchpad/arn/arn_patterns_test.py +0 -203
  32. better_aws_tags-0.4.0/scratchpad/arn/stage_01_aws_services.py +0 -57
  33. better_aws_tags-0.4.0/scratchpad/arn/stage_02_aws_resources.py +0 -88
  34. better_aws_tags-0.4.0/scratchpad/arn/stage_03_aws_tag_actions.py +0 -112
  35. better_aws_tags-0.4.0/scratchpad/arn/stage_04_arn_index.py +0 -77
  36. better_aws_tags-0.4.0/scratchpad/arn/stage_05_arn_matcher.py +0 -92
  37. better_aws_tags-0.4.0/scratchpad/arn/stage_06_arn_regex.py +0 -213
  38. better_aws_tags-0.4.0/scratchpad/tags/aws_cloudformation.py +0 -47
  39. better_aws_tags-0.4.0/scratchpad/tags/aws_services.py +0 -30
  40. better_aws_tags-0.4.0/scratchpad/tags/mapping_resource_tagging.py +0 -110
  41. better_aws_tags-0.4.0/scratchpad/tags/mapping_resources.py +0 -57
  42. better_aws_tags-0.4.0/scratchpad/tags/mapping_services.py +0 -292
  43. better_aws_tags-0.4.0/scratchpad/tags/mapping_services_next.py +0 -88
  44. better_aws_tags-0.4.0/scratchpad/tags/tagging_apis.py +0 -99
  45. better_aws_tags-0.4.0/src/better_aws_tags/arnmatch/__init__.py +0 -108
  46. better_aws_tags-0.4.0/src/better_aws_tags/arnmatch/patterns.py +0 -2797
  47. better_aws_tags-0.4.0/src/better_aws_tags/arnparse.py +0 -147
  48. better_aws_tags-0.4.0/src/better_aws_tags/handlers.py +0 -139
  49. better_aws_tags-0.4.0/tests/test_arnmatch.py +0 -403
  50. better_aws_tags-0.4.0/tests/test_arnparse.py +0 -427
  51. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/.github/workflows/release.yml +0 -0
  52. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/.gitignore +0 -0
  53. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/.python-version +0 -0
  54. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/CHANGELOG.md +0 -0
  55. {better_aws_tags-0.4.0 → better_aws_tags-0.6.0}/scratchpad/.gitignore +0 -0
  56. {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.4.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, tag validation, and error reporting automatically.
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, tag validation, and error reporting automatically.
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
@@ -8,6 +8,7 @@ authors = [
8
8
  ]
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
11
+ "arnmatch>=2026.2.2",
11
12
  "boto3~=1.0",
12
13
  ]
13
14
 
@@ -23,3 +24,4 @@ dev = [
23
24
  "pytest~=9.0",
24
25
  "ruff~=0.14",
25
26
  ]
27
+
@@ -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 = list(sorted(set(resource_types)))
82
- # resource_types = fetch_resource_types(query_type="CLOUDFORMATION_STACK_1_0")
83
- with open("tagging_resource.json", "w") as f:
84
- json.dump(resource_types, f, indent=2)
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__":