Skip to content

Commit 2836510

Browse files
authored
Merge branch 'master' into model_config
2 parents 0ad0232 + 2b7ae62 commit 2836510

File tree

72 files changed

+354
-606
lines changed

Some content is hidden

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

72 files changed

+354
-606
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## v2.129.0 (2023-01-19)
4+
5+
### Features
6+
7+
* add p2 deprecation for PT>=1.13
8+
* TF2.11 Update to PySDK
9+
10+
### Bug Fixes and Other Changes
11+
12+
* Improve Pipeline integ tests and fix resource leak
13+
* Update TF version to 2.8.4
14+
315
## v2.128.0 (2023-01-10)
416

517
### Features

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.128.1.dev0
1+
2.129.1.dev0

src/sagemaker/fw_utils.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,20 @@ def tar_and_upload_dir(
422422
script_name = script if directory else os.path.basename(script)
423423
dependencies = dependencies or []
424424
key = "%s/sourcedir.tar.gz" % s3_key_prefix
425-
tmp = tempfile.mkdtemp()
425+
if (
426+
settings is not None
427+
and settings.local_download_dir is not None
428+
and not (
429+
os.path.exists(settings.local_download_dir)
430+
and os.path.isdir(settings.local_download_dir)
431+
)
432+
):
433+
raise ValueError(
434+
"Inputted directory for storing newly generated temporary directory does "
435+
f"not exist: '{settings.local_download_dir}'"
436+
)
437+
local_download_dir = None if settings is None else settings.local_download_dir
438+
tmp = tempfile.mkdtemp(dir=local_download_dir)
426439
encrypt_artifact = True if settings is None else settings.encrypt_repacked_artifacts
427440

428441
try:

src/sagemaker/session_settings.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,25 @@
1818
class SessionSettings(object):
1919
"""Optional container class for settings to apply to a SageMaker session."""
2020

21-
def __init__(self, encrypt_repacked_artifacts=True) -> None:
21+
def __init__(self, encrypt_repacked_artifacts=True, local_download_dir=None) -> None:
2222
"""Initialize the ``SessionSettings`` of a SageMaker ``Session``.
2323
2424
Args:
2525
encrypt_repacked_artifacts (bool): Flag to indicate whether to encrypt the artifacts
2626
at rest in S3 using the default AWS managed KMS key for S3 when a custom KMS key
2727
is not provided (Default: True).
28+
local_download_dir (str): Optional. A path specifying the local directory
29+
for downloading artifacts. (Default: None).
2830
"""
2931
self._encrypt_repacked_artifacts = encrypt_repacked_artifacts
32+
self._local_download_dir = local_download_dir
3033

3134
@property
3235
def encrypt_repacked_artifacts(self) -> bool:
3336
"""Return True if repacked artifacts at rest in S3 should be encrypted by default."""
3437
return self._encrypt_repacked_artifacts
38+
39+
@property
40+
def local_download_dir(self) -> str:
41+
"""Return path specifying the local directory for downloading artifacts."""
42+
return self._local_download_dir

src/sagemaker/utils.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ def create_tar_file(source_files, target=None):
358358

359359

360360
@contextlib.contextmanager
361-
def _tmpdir(suffix="", prefix="tmp"):
361+
def _tmpdir(suffix="", prefix="tmp", directory=None):
362362
"""Create a temporary directory with a context manager.
363363
364364
The file is deleted when the context exits.
@@ -369,11 +369,18 @@ def _tmpdir(suffix="", prefix="tmp"):
369369
suffix, otherwise there will be no suffix.
370370
prefix (str): If prefix is specified, the file name will begin with that
371371
prefix; otherwise, a default prefix is used.
372+
directory (str): If a directory is specified, the file will be downloaded
373+
in this directory; otherwise, a default directory is used.
372374
373375
Returns:
374376
str: path to the directory
375377
"""
376-
tmp = tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=None)
378+
if directory is not None and not (os.path.exists(directory) and os.path.isdir(directory)):
379+
raise ValueError(
380+
"Inputted directory for storing newly generated temporary "
381+
f"directory does not exist: '{directory}'"
382+
)
383+
tmp = tempfile.mkdtemp(suffix=suffix, prefix=prefix, dir=directory)
377384
yield tmp
378385
shutil.rmtree(tmp)
379386

@@ -427,7 +434,13 @@ def repack_model(
427434
"""
428435
dependencies = dependencies or []
429436

430-
with _tmpdir() as tmp:
437+
local_download_dir = (
438+
None
439+
if sagemaker_session.settings is None
440+
or sagemaker_session.settings.local_download_dir is None
441+
else sagemaker_session.settings.local_download_dir
442+
)
443+
with _tmpdir(directory=local_download_dir) as tmp:
431444
model_dir = _extract_model(model_uri, sagemaker_session, tmp)
432445

433446
_create_or_update_code_dir(
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
from __future__ import absolute_import
14+
15+
from botocore.exceptions import WaiterError
16+
17+
from sagemaker.workflow.pipeline import _PipelineExecution
18+
19+
20+
def wait_pipeline_execution(execution: _PipelineExecution, delay: int = 30, max_attempts: int = 60):
21+
try:
22+
execution.wait(delay=delay, max_attempts=max_attempts)
23+
except WaiterError:
24+
pass

tests/integ/sagemaker/workflow/test_automl_steps.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import re
1717

1818
import pytest
19-
from botocore.exceptions import WaiterError
2019

20+
from tests.integ.sagemaker.workflow.helpers import wait_pipeline_execution
2121
from sagemaker.workflow import ParameterString
2222
from sagemaker.workflow.automl_step import AutoMLStep
2323
from sagemaker.automl.automl import AutoML, AutoMLInput
@@ -133,10 +133,7 @@ def test_automl_step(pipeline_session, role, pipeline_name):
133133
try:
134134
_ = pipeline.create(role)
135135
execution = pipeline.start(parameters={})
136-
try:
137-
execution.wait(delay=30, max_attempts=60)
138-
except WaiterError:
139-
pass
136+
wait_pipeline_execution(execution=execution)
140137

141138
execution_steps = execution.list_steps()
142139
has_automl_job = False

tests/integ/sagemaker/workflow/test_clarify_check_steps.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
import os
1818

1919
import pytest
20-
from botocore.exceptions import WaiterError
2120

21+
from tests.integ.sagemaker.workflow.helpers import wait_pipeline_execution
2222
from sagemaker.clarify import (
2323
BiasConfig,
2424
DataConfig,
@@ -182,10 +182,7 @@ def test_one_step_data_bias_pipeline_happycase(
182182

183183
assert response["PipelineArn"] == create_arn
184184

185-
try:
186-
execution.wait(delay=30, max_attempts=60)
187-
except WaiterError:
188-
pass
185+
wait_pipeline_execution(execution=execution)
189186
execution_steps = execution.list_steps()
190187

191188
assert len(execution_steps) == 1
@@ -272,10 +269,7 @@ def test_one_step_data_bias_pipeline_constraint_violation(
272269

273270
assert response["PipelineArn"] == create_arn
274271

275-
try:
276-
execution.wait(delay=30, max_attempts=60)
277-
except WaiterError:
278-
pass
272+
wait_pipeline_execution(execution=execution)
279273
execution_steps = execution.list_steps()
280274

281275
assert len(execution_steps) == 1

tests/integ/sagemaker/workflow/test_experiment.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import pytest
1919

20-
from botocore.exceptions import WaiterError
20+
from tests.integ.sagemaker.workflow.helpers import wait_pipeline_execution
2121
from sagemaker.processing import ProcessingInput
2222
from sagemaker.session import get_execution_role
2323
from sagemaker.sklearn.processing import SKLearnProcessor
@@ -120,10 +120,7 @@ def test_pipeline_execution_with_default_experiment_config(
120120
pipeline.create(role)
121121
execution = pipeline.start(parameters={})
122122

123-
try:
124-
execution.wait(delay=30, max_attempts=3)
125-
except WaiterError:
126-
pass
123+
wait_pipeline_execution(execution=execution, max_attempts=3)
127124
execution_steps = execution.list_steps()
128125
assert len(execution_steps) == 1
129126
assert execution_steps[0]["StepName"] == "sklearn-process"
@@ -195,10 +192,7 @@ def test_pipeline_execution_with_custom_experiment_config(
195192
pipeline.create(role)
196193
execution = pipeline.start(parameters={})
197194

198-
try:
199-
execution.wait(delay=30, max_attempts=3)
200-
except WaiterError:
201-
pass
195+
wait_pipeline_execution(execution=execution, max_attempts=3)
202196
execution_steps = execution.list_steps()
203197
assert len(execution_steps) == 1
204198
assert execution_steps[0]["StepName"] == "sklearn-process"

tests/integ/sagemaker/workflow/test_fail_steps.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
from __future__ import absolute_import
1414

1515
import pytest
16-
from botocore.exceptions import WaiterError
1716

17+
from tests.integ.sagemaker.workflow.helpers import wait_pipeline_execution
1818
from sagemaker import get_execution_role, utils
1919
from sagemaker.workflow.condition_step import ConditionStep
2020
from sagemaker.workflow.conditions import ConditionEquals
@@ -62,10 +62,7 @@ def test_two_step_fail_pipeline_with_str_err_msg(sagemaker_session, role, pipeli
6262
response = execution.describe()
6363
assert response["PipelineArn"] == pipeline_arn
6464

65-
try:
66-
execution.wait(delay=30, max_attempts=60)
67-
except WaiterError:
68-
pass
65+
wait_pipeline_execution(execution=execution)
6966
execution_steps = execution.list_steps()
7067

7168
assert len(execution_steps) == 2
@@ -130,10 +127,7 @@ def test_two_step_fail_pipeline_with_parameter_err_msg(sagemaker_session, role,
130127
response = execution.describe()
131128
assert response["PipelineArn"] == pipeline_arn
132129

133-
try:
134-
execution.wait(delay=30, max_attempts=60)
135-
except WaiterError:
136-
pass
130+
wait_pipeline_execution(execution=execution)
137131
execution_steps = execution.list_steps()
138132

139133
assert len(execution_steps) == 2
@@ -196,10 +190,7 @@ def test_two_step_fail_pipeline_with_join_fn(sagemaker_session, role, pipeline_n
196190
response = execution.describe()
197191
assert response["PipelineArn"] == pipeline_arn
198192

199-
try:
200-
execution.wait(delay=30, max_attempts=60)
201-
except WaiterError:
202-
pass
193+
wait_pipeline_execution(execution=execution)
203194
execution_steps = execution.list_steps()
204195

205196
assert len(execution_steps) == 2
@@ -257,10 +248,7 @@ def test_two_step_fail_pipeline_with_no_err_msg(sagemaker_session, role, pipelin
257248
response = execution.describe()
258249
assert response["PipelineArn"] == pipeline_arn
259250

260-
try:
261-
execution.wait(delay=30, max_attempts=60)
262-
except WaiterError:
263-
pass
251+
wait_pipeline_execution(execution=execution)
264252
execution_steps = execution.list_steps()
265253

266254
assert len(execution_steps) == 2

tests/integ/sagemaker/workflow/test_model_create_and_registration.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
import re
2424

2525
import pytest
26-
from botocore.exceptions import WaiterError
2726

2827
import tests
28+
from tests.integ.sagemaker.workflow.helpers import wait_pipeline_execution
2929
from sagemaker.tensorflow import TensorFlow, TensorFlowModel
3030
from tests.integ.retry import retries
3131
from sagemaker.drift_check_baselines import DriftCheckBaselines
@@ -180,12 +180,14 @@ def test_conditional_pytorch_training_model_registration(
180180
)
181181

182182
execution = pipeline.start(parameters={})
183+
wait_pipeline_execution(execution=execution)
183184
assert re.match(
184185
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
185186
execution.arn,
186187
)
187188

188189
execution = pipeline.start(parameters={"GoodEnoughInput": 0})
190+
wait_pipeline_execution(execution=execution)
189191
assert re.match(
190192
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
191193
execution.arn,
@@ -259,12 +261,14 @@ def test_mxnet_model_registration(
259261
)
260262

261263
execution = pipeline.start(parameters={})
264+
wait_pipeline_execution(execution=execution)
262265
assert re.match(
263266
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
264267
execution.arn,
265268
)
266269

267270
execution = pipeline.start()
271+
wait_pipeline_execution(execution=execution)
268272
assert re.match(
269273
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
270274
execution.arn,
@@ -470,12 +474,14 @@ def test_sklearn_xgboost_sip_model_registration(
470474
)
471475

472476
execution = pipeline.start(parameters={})
477+
wait_pipeline_execution(execution=execution)
473478
assert re.match(
474479
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
475480
execution.arn,
476481
)
477482

478483
execution = pipeline.start()
484+
wait_pipeline_execution(execution=execution)
479485
assert re.match(
480486
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
481487
execution.arn,
@@ -656,10 +662,7 @@ def test_model_registration_with_drift_check_baselines(
656662

657663
assert response["PipelineArn"] == create_arn
658664

659-
try:
660-
execution.wait(delay=30, max_attempts=60)
661-
except WaiterError:
662-
pass
665+
wait_pipeline_execution(execution=execution)
663666
execution_steps = execution.list_steps()
664667

665668
assert len(execution_steps) == 1
@@ -797,12 +800,14 @@ def test_model_registration_with_model_repack(
797800
)
798801

799802
execution = pipeline.start(parameters={})
803+
wait_pipeline_execution(execution=execution)
800804
assert re.match(
801805
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
802806
execution.arn,
803807
)
804808

805809
execution = pipeline.start(parameters={"GoodEnoughInput": 0})
810+
wait_pipeline_execution(execution=execution)
806811
assert re.match(
807812
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
808813
execution.arn,
@@ -889,10 +894,7 @@ def test_model_registration_with_tensorflow_model_with_pipeline_model(
889894
rf"arn:aws:sagemaker:{region_name}:\d{{12}}:pipeline/{pipeline_name}/execution/",
890895
execution.arn,
891896
)
892-
try:
893-
execution.wait(delay=30, max_attempts=60)
894-
except WaiterError:
895-
pass
897+
wait_pipeline_execution(execution=execution)
896898
execution_steps = execution.list_steps()
897899

898900
for step in execution_steps:

0 commit comments

Comments
 (0)