Skip to content

Commit 23abb53

Browse files
authored
Merge branch 'develop' into tmp/1678476371/main
2 parents 3879ea7 + b4474ad commit 23abb53

File tree

318 files changed

+6949
-841
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

318 files changed

+6949
-841
lines changed

.cfnlintrc.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,4 @@ ignore_checks:
125125
- E2531 # Deprecated runtime; not relevant for transform tests
126126
- W2531 # EOL runtime; not relevant for transform tests
127127
- E3001 # Invalid or unsupported Type; common in transform tests since they focus on SAM resources
128+
- W2001 # Parameter not used

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
- "3.8"
2323
- "3.9"
2424
- "3.10"
25+
- "3.11"
2526
steps:
2627
- uses: actions/checkout@v3
2728
- uses: actions/setup-python@v4

DEVELOPMENT_GUIDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ eval "$(pyenv virtualenv-init -)"
5959
We format our code using [Black](https://github.com/python/black) and verify the source code is black compliant
6060
during PR checks. Black will be installed automatically with `make init`.
6161

62-
After installing, you can run our formatting through our Makefile by `make black` or integrating Black directly in your favorite IDE (instructions
62+
After installing, you can run our formatting through our Makefile by `make format` or integrating Black directly in your favorite IDE (instructions
6363
can be found [here](https://black.readthedocs.io/en/stable/editor_integration.html))
6464

6565
##### (Workaround) Integrating Black directly in your favorite IDE

Makefile

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,37 @@ test-cov-report:
1717
integ-test:
1818
pytest --no-cov integration/
1919

20-
black:
20+
format:
2121
black setup.py samtranslator tests integration bin schema_source
22+
bin/transform-test-error-json-format.py --write tests/translator/output/error_*.json
2223
bin/json-format.py --write tests integration samtranslator/policy_templates_data
2324
bin/yaml-format.py --write tests
2425
bin/yaml-format.py --write integration --add-test-metadata
2526

26-
black-check:
27+
black:
28+
$(warning `make black` is deprecated, please use `make format`)
29+
# sleep for 5 seconds so the message can be seen.
30+
sleep 5
31+
make format
32+
33+
format-check:
2734
# Checking latest schema was generated (run `make schema` if this fails)
2835
mkdir -p .tmp
2936
python -m samtranslator.internal.schema_source.schema --sam-schema .tmp/sam.schema.json --cfn-schema schema_source/cloudformation.schema.json --unified-schema .tmp/schema.json
3037
diff -u schema_source/sam.schema.json .tmp/sam.schema.json
3138
diff -u samtranslator/schema/schema.json .tmp/schema.json
3239
black --check setup.py samtranslator tests integration bin schema_source
40+
bin/transform-test-error-json-format.py --check tests/translator/output/error_*.json
3341
bin/json-format.py --check tests integration samtranslator/policy_templates_data
3442
bin/yaml-format.py --check tests
3543
bin/yaml-format.py --check integration --add-test-metadata
3644

45+
black-check:
46+
$(warning `make black-check` is deprecated, please use `make format-check`)
47+
# sleep for 5 seconds so the message can be seen.
48+
sleep 5
49+
make format-check
50+
3751
lint:
3852
ruff samtranslator bin schema_source integration tests
3953
# mypy performs type check
@@ -76,7 +90,7 @@ schema-all: fetch-schema-data update-schema-data schema
7690
dev: test
7791

7892
# Verifications to run before sending a pull request
79-
pr: black-check lint init dev
93+
pr: format-check lint init dev
8094

8195
clean:
8296
rm -rf .tmp

bin/add_transform_test.py

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@
66
import shutil
77
import subprocess
88
import sys
9-
import tempfile
9+
from copy import deepcopy
1010
from pathlib import Path
1111
from typing import Any, Dict
1212

13+
import boto3
14+
15+
from samtranslator.translator.arn_generator import ArnGenerator
16+
from samtranslator.translator.managed_policy_translator import ManagedPolicyLoader
17+
from samtranslator.translator.transform import transform
18+
from samtranslator.yaml_helper import yaml_parse
19+
1320
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
1421
TRANSFORM_TEST_DIR = os.path.join(SCRIPT_DIR, "..", "tests", "translator")
1522

23+
iam_client = boto3.client("iam")
24+
1625
parser = argparse.ArgumentParser(description=__doc__)
1726
parser.add_argument(
1827
"--template-file",
@@ -40,7 +49,7 @@ def read_json_file(file_path: str) -> Dict[str, Any]:
4049

4150
def write_json_file(obj: Dict[str, Any], file_path: str) -> None:
4251
with open(file_path, "w", encoding="utf-8") as f:
43-
json.dump(obj, f, indent=2)
52+
json.dump(obj, f, indent=2, sort_keys=True)
4453

4554

4655
def add_regional_endpoint_configuration_if_needed(template: Dict[str, Any]) -> Dict[str, Any]:
@@ -66,38 +75,29 @@ def replace_aws_partition(partition: str, file_path: str) -> None:
6675
def generate_transform_test_output_files(input_file_path: str, file_basename: str) -> None:
6776
output_file_option = file_basename + ".json"
6877

69-
# run sam-translate.py and get the temporary output file
70-
with tempfile.NamedTemporaryFile() as temp_output_file:
71-
subprocess.run(
72-
[
73-
sys.executable,
74-
os.path.join(SCRIPT_DIR, "sam-translate.py"),
75-
"--template-file",
76-
input_file_path,
77-
"--output-template",
78-
temp_output_file.name,
79-
],
80-
check=True,
81-
)
78+
with open(os.path.join(input_file_path), "r") as f:
79+
manifest = yaml_parse(f) # type: ignore[no-untyped-call]
80+
81+
transform_test_output_paths = {
82+
"aws": ("us-west-2", os.path.join(TRANSFORM_TEST_DIR, "output", output_file_option)),
83+
"aws-cn": ("cn-north-1 ", os.path.join(TRANSFORM_TEST_DIR, "output/aws-cn/", output_file_option)),
84+
"aws-us-gov": ("us-gov-west-1", os.path.join(TRANSFORM_TEST_DIR, "output/aws-us-gov/", output_file_option)),
85+
}
8286

83-
# copy the output files into correct directories
84-
transform_test_output_path = os.path.join(TRANSFORM_TEST_DIR, "output", output_file_option)
85-
shutil.copyfile(temp_output_file.name, transform_test_output_path)
87+
for partition, (region, output_path) in transform_test_output_paths.items():
88+
# Set Boto Session Region to guarantee the same hash input as transform tests for API deployment id
89+
ArnGenerator.BOTO_SESSION_REGION_NAME = region
90+
# Implicit API Plugin may alter input template file, thus passing a copy here.
91+
output_fragment = transform(deepcopy(manifest), {}, ManagedPolicyLoader(iam_client))
8692

87-
regional_transform_test_output_paths = {
88-
"aws-cn": os.path.join(TRANSFORM_TEST_DIR, "output/aws-cn/", output_file_option),
89-
"aws-us-gov": os.path.join(TRANSFORM_TEST_DIR, "output/aws-us-gov/", output_file_option),
90-
}
93+
if not CLI_OPTIONS.disable_api_configuration and partition != "aws":
94+
output_fragment = add_regional_endpoint_configuration_if_needed(output_fragment)
9195

92-
if not CLI_OPTIONS.disable_api_configuration:
93-
template = read_json_file(temp_output_file.name)
94-
template = add_regional_endpoint_configuration_if_needed(template)
95-
write_json_file(template, temp_output_file.name)
96+
write_json_file(output_fragment, output_path)
9697

97-
for partition, output_path in regional_transform_test_output_paths.items():
98-
shutil.copyfile(temp_output_file.name, output_path)
99-
if not CLI_OPTIONS.disable_update_partition:
100-
replace_aws_partition(partition, output_path)
98+
# Update arn partition if necessary
99+
if not CLI_OPTIONS.disable_update_partition:
100+
replace_aws_partition(partition, output_path)
101101

102102

103103
def get_input_file_path() -> str:
@@ -118,6 +118,18 @@ def verify_input_template(input_file_path: str): # type: ignore[no-untyped-def]
118118
)
119119

120120

121+
def format_test_files() -> None:
122+
subprocess.run(
123+
[sys.executable, os.path.join(SCRIPT_DIR, "json-format.py"), "--write", "tests"],
124+
check=True,
125+
)
126+
127+
subprocess.run(
128+
[sys.executable, os.path.join(SCRIPT_DIR, "yaml-format.py"), "--write", "tests"],
129+
check=True,
130+
)
131+
132+
121133
def main() -> None:
122134
input_file_path = get_input_file_path()
123135
file_basename = Path(input_file_path).stem
@@ -133,6 +145,8 @@ def main() -> None:
133145
"Generating transform test input and output files complete. \n\nPlease check the generated output is as expected. This tool does not guarantee correct output."
134146
)
135147

148+
format_test_files()
149+
136150

137151
if __name__ == "__main__":
138152
main()

bin/parse_docs.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
def parse(s: str) -> Iterator[Tuple[str, str]]:
2121
"""Parse an AWS docs page in Markdown format, yielding each property."""
2222
# Prevent from parsing return values accidentally
23-
s = stringbetween(s, "#\s+Properties", "#\s+Return values")
23+
s = stringbetween(s, "#\\s+Properties", "#\\s+Return values")
2424
if not s:
2525
return
2626
parts = s.split("\n\n")
@@ -44,7 +44,7 @@ def remove_first_line(s: str) -> str:
4444

4545

4646
def convert_to_full_path(description: str, prefix: str) -> str:
47-
pattern = re.compile("\(([#\.a-zA-Z0-9_-]+)\)")
47+
pattern = re.compile("\\(([#\\.a-zA-Z0-9_-]+)\\)")
4848
matched_content = pattern.findall(description)
4949

5050
for path in matched_content:

bin/public_interface.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,8 @@ def _only_new_optional_arguments_or_existing_arguments_optionalized_or_var_argum
161161
return False
162162
# it is an optional argument when it has a default value:
163163
return all(
164-
[
165-
"default" in argument or argument["kind"] in ("VAR_KEYWORD", "VAR_POSITIONAL")
166-
for argument in arguments[len(original_arguments) :]
167-
]
164+
"default" in argument or argument["kind"] in ("VAR_KEYWORD", "VAR_POSITIONAL")
165+
for argument in arguments[len(original_arguments) :]
168166
)
169167

170168

bin/sam-translate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"--output-template",
4141
help="Location to store resulting CloudFormation template [default: transformed-template.json].",
4242
type=Path,
43-
default=Path("transformed-template.yaml"),
43+
default=Path("transformed-template.json"),
4444
)
4545
parser.add_argument(
4646
"--s3-bucket",
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python
2+
"""
3+
Transform test error JSON file formatter (without prettier).
4+
5+
It makes error json easier to review by breaking down "errorMessage"
6+
into list of strings (delimiter: ". ").
7+
"""
8+
import os
9+
import sys
10+
11+
from typing_extensions import Final
12+
13+
my_path = os.path.dirname(os.path.abspath(__file__))
14+
sys.path.insert(0, my_path + "/..")
15+
16+
import json
17+
from typing import Type
18+
19+
from bin._file_formatter import FileFormatter
20+
21+
22+
class TransformTestErrorJSONFormatter(FileFormatter):
23+
_ERROR_MESSAGE_KEY: Final[str] = "errorMessage"
24+
_BREAKDOWN_ERROR_MESSAGE_KEY: Final[str] = "_autoGeneratedBreakdownErrorMessage"
25+
_DELIMITER: Final[str] = ". "
26+
27+
@staticmethod
28+
def description() -> str:
29+
return "Transform test error JSON file formatter"
30+
31+
def format_str(self, input_str: str) -> str:
32+
"""
33+
It makes error json easier to review by breaking down "errorMessage"
34+
into list of strings (delimiter: ". ").
35+
"""
36+
obj = json.loads(input_str)
37+
error_message = obj.get(self._ERROR_MESSAGE_KEY)
38+
if isinstance(error_message, str):
39+
tokens = error_message.split(self._DELIMITER)
40+
obj[self._BREAKDOWN_ERROR_MESSAGE_KEY] = [
41+
token if index == len(tokens) - 1 else token + self._DELIMITER for index, token in enumerate(tokens)
42+
]
43+
return json.dumps(obj, indent=2, sort_keys=True) + "\n"
44+
45+
@staticmethod
46+
def decode_exception() -> Type[Exception]:
47+
return json.JSONDecodeError
48+
49+
@staticmethod
50+
def file_extension() -> str:
51+
return ".json"
52+
53+
54+
if __name__ == "__main__":
55+
TransformTestErrorJSONFormatter.main()

integration/combination/test_function_with_sns.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ def test_function_with_sns_intrinsics(self):
5151
subscription_arn = subscription["SubscriptionArn"]
5252
subscription_attributes = sns_client.get_subscription_attributes(SubscriptionArn=subscription_arn)
5353
self.assertEqual(subscription_attributes["Attributes"]["FilterPolicy"], '{"price_usd":[{"numeric":["<",100]}]}')
54+
self.assertEqual(subscription_attributes["Attributes"]["FilterPolicyScope"], "MessageAttributes")

0 commit comments

Comments
 (0)