Skip to content

Commit 1e5b158

Browse files
authored
Merge pull request #3028 from aws/release-v1.62.0
Release 1.62.0 (to main)
2 parents 3879ea7 + c91e1b3 commit 1e5b158

File tree

286 files changed

+4510
-129
lines changed

Some content is hidden

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

286 files changed

+4510
-129
lines changed

DEVELOPMENT_GUIDE.md

+1-1
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

+17-3
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

+42-30
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@
66
import shutil
77
import subprocess
88
import sys
9-
import tempfile
109
from pathlib import Path
1110
from typing import Any, Dict
1211

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

22+
iam_client = boto3.client("iam")
23+
1624
parser = argparse.ArgumentParser(description=__doc__)
1725
parser.add_argument(
1826
"--template-file",
@@ -40,7 +48,7 @@ def read_json_file(file_path: str) -> Dict[str, Any]:
4048

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

4553

4654
def add_regional_endpoint_configuration_if_needed(template: Dict[str, Any]) -> Dict[str, Any]:
@@ -66,38 +74,28 @@ def replace_aws_partition(partition: str, file_path: str) -> None:
6674
def generate_transform_test_output_files(input_file_path: str, file_basename: str) -> None:
6775
output_file_option = file_basename + ".json"
6876

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-
)
77+
with open(os.path.join(input_file_path), "r") as f:
78+
manifest = yaml_parse(f) # type: ignore[no-untyped-call]
79+
80+
transform_test_output_paths = {
81+
"aws": ("us-west-2", os.path.join(TRANSFORM_TEST_DIR, "output", output_file_option)),
82+
"aws-cn": ("cn-north-1 ", os.path.join(TRANSFORM_TEST_DIR, "output/aws-cn/", output_file_option)),
83+
"aws-us-gov": ("us-gov-west-1", os.path.join(TRANSFORM_TEST_DIR, "output/aws-us-gov/", output_file_option)),
84+
}
8285

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)
86+
for partition, (region, output_path) in transform_test_output_paths.items():
87+
# Set Boto Session Region to guarantee the same hash input as transform tests for API deployment id
88+
ArnGenerator.BOTO_SESSION_REGION_NAME = region
89+
output_fragment = transform(manifest, {}, ManagedPolicyLoader(iam_client))
8690

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-
}
91+
if not CLI_OPTIONS.disable_api_configuration and partition != "aws":
92+
output_fragment = add_regional_endpoint_configuration_if_needed(output_fragment)
9193

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)
94+
write_json_file(output_fragment, output_path)
9695

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)
96+
# Update arn partition if necessary
97+
if not CLI_OPTIONS.disable_update_partition:
98+
replace_aws_partition(partition, output_path)
10199

102100

103101
def get_input_file_path() -> str:
@@ -118,6 +116,18 @@ def verify_input_template(input_file_path: str): # type: ignore[no-untyped-def]
118116
)
119117

120118

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

146+
format_test_files()
147+
136148

137149
if __name__ == "__main__":
138150
main()

bin/parse_docs.py

+2-2
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

+2-4
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

+55
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()

requirements/dev.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pytest-xdist>=2.5,<4
44
pytest-env>=0.6,<1
55
pytest-rerunfailures>=9.1,<12
66
pyyaml~=6.0
7-
ruff==0.0.252 # loose the requirement once it is more stable
7+
ruff==0.0.253 # loose the requirement once it is more stable
88

99
# Test requirements
1010
pytest>=6.2,<8

ruff.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
line-length = 999
33

44
select = [
5-
"E", # Pyflakes
5+
"E", # pycodestyle
6+
"W", # pycodestyle
67
"F", # Pyflakes
78
"PL", # pylint
89
"I", # isort
@@ -17,6 +18,7 @@ select = [
1718
"SIM", # flake8-simplify
1819
"TID", # flake8-tidy-imports
1920
"RUF", # Ruff-specific rules
21+
"YTT", # flake8-2020
2022
]
2123

2224
# Mininal python version we support is 3.7

samtranslator/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.61.0"
1+
__version__ = "1.62.0"

samtranslator/feature_toggle/dialup.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
class BaseDialup(ABC):
66
"""BaseDialup class to provide an interface for all dialup classes"""
77

8-
def __init__(self, region_config, **kwargs): # type: ignore[no-untyped-def]
8+
def __init__(self, region_config, **kwargs) -> None: # type: ignore[no-untyped-def]
99
self.region_config = region_config
1010

1111
@abstractmethod
@@ -23,8 +23,8 @@ class DisabledDialup(BaseDialup):
2323
A dialup that is never enabled
2424
"""
2525

26-
def __init__(self, region_config, **kwargs): # type: ignore[no-untyped-def]
27-
super().__init__(region_config) # type: ignore[no-untyped-call]
26+
def __init__(self, region_config, **kwargs) -> None: # type: ignore[no-untyped-def]
27+
super().__init__(region_config)
2828

2929
def is_enabled(self) -> bool:
3030
return False
@@ -36,8 +36,8 @@ class ToggleDialup(BaseDialup):
3636
Example of region_config: { "type": "toggle", "enabled": True }
3737
"""
3838

39-
def __init__(self, region_config, **kwargs): # type: ignore[no-untyped-def]
40-
super().__init__(region_config) # type: ignore[no-untyped-call]
39+
def __init__(self, region_config, **kwargs) -> None: # type: ignore[no-untyped-def]
40+
super().__init__(region_config)
4141
self.region_config = region_config
4242

4343
def is_enabled(self): # type: ignore[no-untyped-def]
@@ -50,8 +50,8 @@ class SimpleAccountPercentileDialup(BaseDialup):
5050
Example of region_config: { "type": "account-percentile", "enabled-%": 20 }
5151
"""
5252

53-
def __init__(self, region_config, account_id, feature_name, **kwargs): # type: ignore[no-untyped-def]
54-
super().__init__(region_config) # type: ignore[no-untyped-call]
53+
def __init__(self, region_config, account_id, feature_name, **kwargs) -> None: # type: ignore[no-untyped-def]
54+
super().__init__(region_config)
5555
self.account_id = account_id
5656
self.feature_name = feature_name
5757

samtranslator/feature_toggle/feature_toggle.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def _get_dialup(self, region_config, feature_name): # type: ignore[no-untyped-d
5656
region_config, account_id=self.account_id, feature_name=feature_name
5757
)
5858
LOG.warning("Dialup type '{}' is None or is not supported.".format(dialup_type))
59-
return DisabledDialup(region_config) # type: ignore[no-untyped-call]
59+
return DisabledDialup(region_config)
6060

6161
def is_enabled(self, feature_name: str) -> bool:
6262
"""
@@ -119,7 +119,7 @@ def config(self) -> Dict[str, Any]:
119119
class FeatureToggleLocalConfigProvider(FeatureToggleConfigProvider):
120120
"""Feature toggle config provider which uses a local file. This is to facilitate local testing."""
121121

122-
def __init__(self, local_config_path): # type: ignore[no-untyped-def]
122+
def __init__(self, local_config_path) -> None: # type: ignore[no-untyped-def]
123123
FeatureToggleConfigProvider.__init__(self)
124124
with open(local_config_path, "r", encoding="utf-8") as f:
125125
config_json = f.read()
@@ -134,7 +134,7 @@ class FeatureToggleAppConfigConfigProvider(FeatureToggleConfigProvider):
134134
"""Feature toggle config provider which loads config from AppConfig."""
135135

136136
@cw_timer(prefix="External", name="AppConfig")
137-
def __init__(self, application_id, environment_id, configuration_profile_id, app_config_client=None): # type: ignore[no-untyped-def]
137+
def __init__(self, application_id, environment_id, configuration_profile_id, app_config_client=None) -> None: # type: ignore[no-untyped-def]
138138
FeatureToggleConfigProvider.__init__(self)
139139
try:
140140
LOG.info("Loading feature toggle config from AppConfig...")

samtranslator/internal/schema_source/aws_serverless_api.py

+3
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class EndpointConfiguration(BaseModel):
172172
CanarySetting = Optional[PassThroughProp]
173173
TracingEnabled = Optional[PassThroughProp]
174174
OpenApiVersion = Optional[Union[float, str]] # TODO: float doesn't exist in documentation
175+
AlwaysDeploy = Optional[bool]
175176

176177

177178
class Properties(BaseModel):
@@ -202,6 +203,7 @@ class Properties(BaseModel):
202203
Tags: Optional[DictStrAny] = properties("Tags")
203204
TracingEnabled: Optional[TracingEnabled] = properties("TracingEnabled")
204205
Variables: Optional[Variables] = properties("Variables")
206+
AlwaysDeploy: Optional[AlwaysDeploy] # TODO: Add docs
205207

206208

207209
class Globals(BaseModel):
@@ -223,6 +225,7 @@ class Globals(BaseModel):
223225
TracingEnabled: Optional[TracingEnabled] = properties("TracingEnabled")
224226
OpenApiVersion: Optional[OpenApiVersion] = properties("OpenApiVersion")
225227
Domain: Optional[Domain] = properties("Domain")
228+
AlwaysDeploy: Optional[AlwaysDeploy] # TODO: Add docs
226229

227230

228231
class Resource(ResourceAttributes):

samtranslator/internal/schema_source/aws_serverless_function.py

+1
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ class MSKEvent(BaseModel):
405405
class MQEventProperties(BaseModel):
406406
BatchSize: Optional[PassThroughProp] = mqeventproperties("BatchSize")
407407
Broker: PassThroughProp = mqeventproperties("Broker")
408+
DynamicPolicyName: Optional[bool] # TODO: add docs
408409
Enabled: Optional[PassThroughProp] = mqeventproperties("Enabled")
409410
FilterCriteria: Optional[PassThroughProp] = mqeventproperties("FilterCriteria")
410411
MaximumBatchingWindowInSeconds: Optional[PassThroughProp] = mqeventproperties("MaximumBatchingWindowInSeconds")

0 commit comments

Comments
 (0)