arnmatch 2026.2.1__tar.gz → 2026.2.2__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 (44) hide show
  1. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/PKG-INFO +11 -1
  2. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/README.md +10 -0
  3. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/pyproject.toml +1 -0
  4. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/src/arnmatch/__init__.py +23 -1
  5. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/tests/test_arnmatch.py +30 -0
  6. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/uv.lock +81 -0
  7. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/.github/workflows/workflow.yml +0 -0
  8. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/.gitignore +0 -0
  9. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/.python-version +0 -0
  10. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/CLAUDE.md +0 -0
  11. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/LICENSE +0 -0
  12. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/Makefile +0 -0
  13. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/.gitignore +0 -0
  14. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/Makefile +0 -0
  15. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/cache/CloudFormationResourceSpecification.json +0 -0
  16. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/cache/CloudFormationResources.json +0 -0
  17. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/cache/CloudFormationServices.json +0 -0
  18. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/cache/SDKServices.json +0 -0
  19. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/codegen.py +0 -0
  20. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/codegen_python.py +0 -0
  21. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/index_arn.py +0 -0
  22. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/index_cfn.py +0 -0
  23. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/index_cfn_resources.py +0 -0
  24. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/index_sdk.py +0 -0
  25. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/index_sdk_resources.py +0 -0
  26. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/arn_excludes.json +0 -0
  27. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/arn_excludes_resources.json +0 -0
  28. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/arn_includes.json +0 -0
  29. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/arn_overrides.json +0 -0
  30. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/cfn_excludes.json +0 -0
  31. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/cfn_overrides.json +0 -0
  32. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/cfn_resources_excludes.json +0 -0
  33. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/cfn_resources_overrides.json +0 -0
  34. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/lowercase_transforms.json +0 -0
  35. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/sdk_excludes.json +0 -0
  36. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/sdk_overrides.json +0 -0
  37. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/sdk_resources_defaults.json +0 -0
  38. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/rules/sdk_resources_overrides.json +0 -0
  39. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/scraper.py +0 -0
  40. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/transform.py +0 -0
  41. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/codegen/utils.py +0 -0
  42. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/docs/CloudFormation.md +0 -0
  43. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/src/arnmatch/arn_patterns.py +0 -0
  44. {arnmatch-2026.2.1 → arnmatch-2026.2.2}/tests/integration/test_resource_explorer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arnmatch
3
- Version: 2026.2.1
3
+ Version: 2026.2.2
4
4
  Summary: Parse AWS ARNs into structured data (2000+ resource types)
5
5
  Author-email: Andrey Gubarev <andrey@andreygubarev.com>
6
6
  License-Expression: Apache-2.0
@@ -78,6 +78,10 @@ result.resource_id # "my-function"
78
78
  result.resource_name # "my-function"
79
79
  result.cloudformation_resource # "AWS::Lambda::Function"
80
80
  result.aws_sdk_service # "lambda"
81
+
82
+ # Get a boto3 client for the service
83
+ client = result.client()
84
+ client.get_function(FunctionName=result.resource_name)
81
85
  ```
82
86
 
83
87
  ## API Reference
@@ -112,6 +116,12 @@ Properties:
112
116
  | `resource_name` | Resource name (prefers attributes ending in `Name`, falls back to `resource_id`) |
113
117
  | `aws_sdk_services` | List of boto3 client names (e.g., `['elb', 'elbv2']` for elasticloadbalancing) |
114
118
 
119
+ Methods:
120
+
121
+ | Method | Description |
122
+ |--------|-------------|
123
+ | `client(session=None)` | Returns a boto3 client for the resource's service. Pass an optional `boto3.Session` or uses default. Raises `ValueError` if no SDK mapping exists. |
124
+
115
125
  ### `ARNError`
116
126
 
117
127
  Exception raised when ARN parsing fails. Inherits from `ValueError`.
@@ -68,6 +68,10 @@ result.resource_id # "my-function"
68
68
  result.resource_name # "my-function"
69
69
  result.cloudformation_resource # "AWS::Lambda::Function"
70
70
  result.aws_sdk_service # "lambda"
71
+
72
+ # Get a boto3 client for the service
73
+ client = result.client()
74
+ client.get_function(FunctionName=result.resource_name)
71
75
  ```
72
76
 
73
77
  ## API Reference
@@ -102,6 +106,12 @@ Properties:
102
106
  | `resource_name` | Resource name (prefers attributes ending in `Name`, falls back to `resource_id`) |
103
107
  | `aws_sdk_services` | List of boto3 client names (e.g., `['elb', 'elbv2']` for elasticloadbalancing) |
104
108
 
109
+ Methods:
110
+
111
+ | Method | Description |
112
+ |--------|-------------|
113
+ | `client(session=None)` | Returns a boto3 client for the resource's service. Pass an optional `boto3.Session` or uses default. Raises `ValueError` if no SDK mapping exists. |
114
+
105
115
  ### `ARNError`
106
116
 
107
117
  Exception raised when ARN parsing fails. Inherits from `ValueError`.
@@ -22,6 +22,7 @@ path = "src/arnmatch/__init__.py"
22
22
 
23
23
  [dependency-groups]
24
24
  dev = [
25
+ "boto3>=1.42.41",
25
26
  "pytest>=9.0.2",
26
27
  "ruff>=0.14.14",
27
28
  ]
@@ -1,6 +1,6 @@
1
1
  """ARN pattern matching using regex patterns."""
2
2
 
3
- __version__ = "2026.2.1"
3
+ __version__ = "2026.2.2"
4
4
 
5
5
  import sys
6
6
  from dataclasses import dataclass
@@ -90,6 +90,28 @@ class ARN:
90
90
  """
91
91
  return AWS_SDK_SERVICES.get(self.aws_service, [])
92
92
 
93
+ def client(self, session: "boto3.Session | None" = None): # noqa: F821
94
+ """Return a boto3 client for this resource's service.
95
+
96
+ Args:
97
+ session: Optional boto3 Session. If None, creates a new session.
98
+
99
+ Returns:
100
+ boto3 client for the service.
101
+
102
+ Raises:
103
+ ValueError: If no SDK service mapping exists for this ARN's service.
104
+ """
105
+ if self.aws_sdk_service is None:
106
+ raise ValueError(f"No SDK service mapping for service '{self.aws_service}'")
107
+
108
+ import boto3
109
+
110
+ if session is None:
111
+ session = boto3.Session()
112
+
113
+ return session.client(self.aws_sdk_service)
114
+
93
115
 
94
116
  def arnmatch(arn: str) -> ARN:
95
117
  """Match ARN against patterns.
@@ -1,5 +1,8 @@
1
1
  """Tests for ARN pattern matching."""
2
2
 
3
+ import boto3
4
+ import pytest
5
+
3
6
  from arnmatch import arnmatch
4
7
 
5
8
 
@@ -452,3 +455,30 @@ def test_wafv2():
452
455
  assert result.attributes["Scope"] == "regional"
453
456
  assert result.attributes["Name"] == "webacl-production-acl"
454
457
  assert result.attributes["Id"] == "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
458
+
459
+
460
+ class TestClient:
461
+ """Tests for ARN.client() method."""
462
+
463
+ def test_client_returns_correct_service(self):
464
+ """Test client() returns a client for the correct service."""
465
+ result = arnmatch(
466
+ "arn:aws:lambda:us-east-1:012345678901:function:my-function"
467
+ )
468
+ client = result.client()
469
+ assert client.meta.service_model.service_name == "lambda"
470
+
471
+ def test_client_uses_provided_session(self):
472
+ """Test client() uses the provided session."""
473
+ session = boto3.Session()
474
+ result = arnmatch("arn:aws:s3:::my-bucket")
475
+ client = result.client(session=session)
476
+ assert client.meta.service_model.service_name == "s3"
477
+
478
+ def test_client_raises_when_no_sdk_mapping(self):
479
+ """Test client() raises ValueError when no SDK service mapping exists."""
480
+ # 'a4b' (Alexa for Business) has no SDK mapping
481
+ result = arnmatch("arn:aws:a4b:us-east-1:012345678901:address-book/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")
482
+
483
+ with pytest.raises(ValueError, match="No SDK service mapping"):
484
+ result.client()
@@ -8,6 +8,7 @@ source = { editable = "." }
8
8
 
9
9
  [package.dev-dependencies]
10
10
  dev = [
11
+ { name = "boto3" },
11
12
  { name = "pytest" },
12
13
  { name = "ruff" },
13
14
  ]
@@ -16,10 +17,39 @@ dev = [
16
17
 
17
18
  [package.metadata.requires-dev]
18
19
  dev = [
20
+ { name = "boto3", specifier = ">=1.42.41" },
19
21
  { name = "pytest", specifier = ">=9.0.2" },
20
22
  { name = "ruff", specifier = ">=0.14.14" },
21
23
  ]
22
24
 
25
+ [[package]]
26
+ name = "boto3"
27
+ version = "1.42.41"
28
+ source = { registry = "https://pypi.org/simple" }
29
+ dependencies = [
30
+ { name = "botocore" },
31
+ { name = "jmespath" },
32
+ { name = "s3transfer" },
33
+ ]
34
+ sdist = { url = "https://files.pythonhosted.org/packages/85/b0/f2a371146877b4d60cd2a6f51c440503cbf77a73c85347ad282eebe90269/boto3-1.42.41.tar.gz", hash = "sha256:86dd2bc577e33da5cd9f10e21b22cdda01a24f83f31ca1bb5ac1f5f8b8e9e67e", size = 112806, upload-time = "2026-02-03T20:38:58.004Z" }
35
+ wheels = [
36
+ { url = "https://files.pythonhosted.org/packages/7b/e8/e671b9aed3e8f6bb5f85aed7fd9dd4e79074798b2a14391fab6b6da04ff7/boto3-1.42.41-py3-none-any.whl", hash = "sha256:32470b1d32208e03b47cf6ce4a7adb337b8a1730aaefb97c336cfd4e2be2577f", size = 140602, upload-time = "2026-02-03T20:38:56.352Z" },
37
+ ]
38
+
39
+ [[package]]
40
+ name = "botocore"
41
+ version = "1.42.41"
42
+ source = { registry = "https://pypi.org/simple" }
43
+ dependencies = [
44
+ { name = "jmespath" },
45
+ { name = "python-dateutil" },
46
+ { name = "urllib3" },
47
+ ]
48
+ sdist = { url = "https://files.pythonhosted.org/packages/27/1d/5fd43319250a5a484bcbde334da2e2297956cdae40de8eb0808759538a7c/botocore-1.42.41.tar.gz", hash = "sha256:0698967741d873d819134bea1ffe9c35decc00c741f49a42885dbd7ad8198fbc", size = 14923189, upload-time = "2026-02-03T20:38:47.957Z" }
49
+ wheels = [
50
+ { url = "https://files.pythonhosted.org/packages/e4/84/df765c7942f52eab12540ef1880b9489d45b364b777fad522fa84435ed11/botocore-1.42.41-py3-none-any.whl", hash = "sha256:567530f7d4da668af891c1259fb80c01578ab8d9f1098127cc250451a46fb54f", size = 14597792, upload-time = "2026-02-03T20:38:45.058Z" },
51
+ ]
52
+
23
53
  [[package]]
24
54
  name = "colorama"
25
55
  version = "0.4.6"
@@ -50,6 +80,15 @@ wheels = [
50
80
  { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
51
81
  ]
52
82
 
83
+ [[package]]
84
+ name = "jmespath"
85
+ version = "1.1.0"
86
+ source = { registry = "https://pypi.org/simple" }
87
+ sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" }
88
+ wheels = [
89
+ { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" },
90
+ ]
91
+
53
92
  [[package]]
54
93
  name = "packaging"
55
94
  version = "26.0"
@@ -95,6 +134,18 @@ wheels = [
95
134
  { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
96
135
  ]
97
136
 
137
+ [[package]]
138
+ name = "python-dateutil"
139
+ version = "2.9.0.post0"
140
+ source = { registry = "https://pypi.org/simple" }
141
+ dependencies = [
142
+ { name = "six" },
143
+ ]
144
+ sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
145
+ wheels = [
146
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
147
+ ]
148
+
98
149
  [[package]]
99
150
  name = "ruff"
100
151
  version = "0.14.14"
@@ -121,6 +172,27 @@ wheels = [
121
172
  { url = "https://files.pythonhosted.org/packages/9e/6a/40fee331a52339926a92e17ae748827270b288a35ef4a15c9c8f2ec54715/ruff-0.14.14-py3-none-win_arm64.whl", hash = "sha256:56e6981a98b13a32236a72a8da421d7839221fa308b223b9283312312e5ac76c", size = 10920448, upload-time = "2026-01-22T22:30:15.417Z" },
122
173
  ]
123
174
 
175
+ [[package]]
176
+ name = "s3transfer"
177
+ version = "0.16.0"
178
+ source = { registry = "https://pypi.org/simple" }
179
+ dependencies = [
180
+ { name = "botocore" },
181
+ ]
182
+ sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" }
183
+ wheels = [
184
+ { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" },
185
+ ]
186
+
187
+ [[package]]
188
+ name = "six"
189
+ version = "1.17.0"
190
+ source = { registry = "https://pypi.org/simple" }
191
+ sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
192
+ wheels = [
193
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
194
+ ]
195
+
124
196
  [[package]]
125
197
  name = "tomli"
126
198
  version = "2.4.0"
@@ -183,3 +255,12 @@ sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac8
183
255
  wheels = [
184
256
  { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
185
257
  ]
258
+
259
+ [[package]]
260
+ name = "urllib3"
261
+ version = "2.6.3"
262
+ source = { registry = "https://pypi.org/simple" }
263
+ sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
264
+ wheels = [
265
+ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
266
+ ]
File without changes
File without changes
File without changes
File without changes
File without changes