Skip to content

Commit 7d3b2b5

Browse files
author
Haonian Wang
committed
feature: Add business details and hyper parameters fields and update test_model_card.py
1 parent 9cf3a04 commit 7d3b2b5

20 files changed

+287
-12
lines changed

awscli-bundle.zip

19.8 MB
Binary file not shown.

awscli-bundle/install

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
#!/usr/bin/env python
2+
# We're using optparse because we need to support 2.6
3+
# which doesn't have argparse. Given that argparse is
4+
# a dependency that eventually gets installed, we could
5+
# try to bootstrap, but using optparse is just easier.
6+
from __future__ import print_function
7+
8+
import optparse
9+
import os
10+
import platform
11+
import shutil
12+
import subprocess
13+
import sys
14+
import tarfile
15+
import tempfile
16+
17+
from contextlib import contextmanager
18+
19+
PACKAGES_DIR = os.path.join(
20+
os.path.dirname(os.path.abspath(__file__)), 'packages')
21+
INSTALL_DIR = os.path.expanduser(os.path.join(
22+
'~', '.local', 'lib', 'aws'))
23+
UNSUPPORTED_PYTHON = (
24+
(2,6),
25+
(2,7),
26+
(3,3),
27+
(3,4),
28+
(3,5),
29+
(3,6),
30+
)
31+
INSTALL_ARGS = (
32+
'--no-binary :all: --no-build-isolation --no-cache-dir --no-index '
33+
)
34+
35+
36+
class BadRCError(Exception):
37+
pass
38+
39+
40+
class MultipleBundlesError(Exception):
41+
pass
42+
43+
44+
class PythonDeprecationWarning(Warning):
45+
"""
46+
Python version being used is scheduled to become unsupported
47+
in an future release. See warning for specifics.
48+
"""
49+
pass
50+
51+
52+
def _build_deprecations():
53+
py_36_params = {
54+
'date': 'May 30, 2022',
55+
'blog_link': (
56+
'https://aws.amazon.com/blogs/developer/'
57+
'python-support-policy-updates-for-aws-sdks-and-tools/'
58+
)
59+
}
60+
61+
return {
62+
# Example for future deprecations
63+
# (3, 6): py_36_params
64+
}
65+
66+
67+
DEPRECATED_PYTHON = _build_deprecations()
68+
69+
70+
@contextmanager
71+
def cd(dirname):
72+
original = os.getcwd()
73+
os.chdir(dirname)
74+
try:
75+
yield
76+
finally:
77+
os.chdir(original)
78+
79+
80+
def run(cmd):
81+
sys.stdout.write("Running cmd: %s\n" % cmd)
82+
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
83+
stderr=subprocess.PIPE)
84+
stdout, stderr = p.communicate()
85+
if p.returncode != 0:
86+
output = (stdout + stderr).decode("utf-8")
87+
raise BadRCError("Bad rc (%s) for cmd '%s': %s" % (
88+
p.returncode, cmd, output))
89+
return stdout
90+
91+
92+
def bin_path():
93+
"""
94+
Get the system's binary path, either `bin` on reasonable
95+
systems or `Scripts` on Windows.
96+
"""
97+
path = 'bin'
98+
99+
if platform.system() == 'Windows':
100+
path = 'Scripts'
101+
102+
return path
103+
104+
105+
def create_install_structure(working_dir, install_dir):
106+
if not os.path.isdir(install_dir):
107+
os.makedirs(install_dir)
108+
create_virtualenv(location=install_dir, working_dir=working_dir)
109+
110+
111+
def _create_virtualenv_internal(location, working_dir):
112+
# On py3 we use the built in venv to create our virtualenv.
113+
# There's a bug with sys.executable on external virtualenv
114+
# that causes installation failures.
115+
run('%s -m venv %s' % (sys.executable, location))
116+
117+
118+
def _get_package_tarball(package_dir, package_prefix):
119+
package_filenames = sorted([p for p in os.listdir(package_dir)
120+
if p.startswith(package_prefix)])
121+
return package_filenames[-1]
122+
123+
124+
def _get_venv_package_tarball(package_dir):
125+
return _get_package_tarball(package_dir, 'virtualenv')
126+
127+
128+
def create_working_dir():
129+
d = tempfile.mkdtemp()
130+
return d
131+
132+
133+
def pip_install_packages(install_dir):
134+
cli_tarball = [p for p in os.listdir(PACKAGES_DIR)
135+
if p.startswith('awscli')]
136+
if len(cli_tarball) != 1:
137+
message = (
138+
"Multiple versions of the CLI were found in %s. Please clear "
139+
"out this directory before proceeding."
140+
)
141+
raise MultipleBundlesError(message % PACKAGES_DIR)
142+
cli_tarball = cli_tarball[0]
143+
python = os.path.join(install_dir, bin_path(), 'python')
144+
145+
setup_requires_dir = os.path.join(PACKAGES_DIR, 'setup')
146+
with cd(setup_requires_dir):
147+
_install_setup_deps(python, '.')
148+
149+
with cd(PACKAGES_DIR):
150+
run(
151+
'{} -m pip install {} --find-links file://{} {}'.format(
152+
python, INSTALL_ARGS, PACKAGES_DIR, cli_tarball
153+
)
154+
)
155+
156+
157+
def _install_setup_deps(python, setup_package_dir):
158+
# Some packages declare `setup_requires`, which is a list of dependencies
159+
# to be used at setup time. These need to be installed before anything
160+
# else, and pip doesn't manage them. We have to manage this ourselves
161+
# so for now we're explicitly installing the one setup_requires package
162+
# we need. This comes from python-dateutils.
163+
setuptools_scm_tarball = _get_package_tarball(
164+
setup_package_dir, 'setuptools_scm'
165+
)
166+
run(
167+
(
168+
'{} -m pip install --no-binary :all: --no-cache-dir --no-index '
169+
'--find-links file://{} {}'
170+
).format(python, setup_package_dir, setuptools_scm_tarball)
171+
)
172+
wheel_tarball = _get_package_tarball(setup_package_dir, 'wheel')
173+
run(
174+
(
175+
'{} -m pip install --no-binary :all: --no-cache-dir --no-index '
176+
'--find-links file://{} {}'
177+
).format(python, setup_package_dir, wheel_tarball)
178+
)
179+
180+
181+
def create_symlink(real_location, symlink_name):
182+
if os.path.isfile(symlink_name):
183+
print("Symlink already exists: %s" % symlink_name)
184+
print("Removing symlink.")
185+
os.remove(symlink_name)
186+
symlink_dir_name = os.path.dirname(symlink_name)
187+
if not os.path.isdir(symlink_dir_name):
188+
os.makedirs(symlink_dir_name)
189+
os.symlink(real_location, symlink_name)
190+
return True
191+
192+
193+
def main():
194+
parser = optparse.OptionParser()
195+
parser.add_option('-i', '--install-dir', help="The location to install "
196+
"the AWS CLI. The default value is ~/.local/lib/aws",
197+
default=INSTALL_DIR)
198+
parser.add_option('-b', '--bin-location', help="If this argument is "
199+
"provided, then a symlink will be created at this "
200+
"location that points to the aws executable. "
201+
"This argument is useful if you want to put the aws "
202+
"executable somewhere already on your path, e.g. "
203+
"-b /usr/local/bin/aws. This is an optional argument. "
204+
"If you do not provide this argument you will have to "
205+
"add INSTALL_DIR/bin to your PATH.")
206+
py_version = sys.version_info[:2]
207+
if py_version in UNSUPPORTED_PYTHON:
208+
unsupported_python_msg = (
209+
"Unsupported Python version detected: Python {}.{}\n"
210+
"To continue using this installer you must use Python 3.7 "
211+
"or later.\n"
212+
"For more information see the following blog post: "
213+
"https://aws.amazon.com/blogs/developer/announcing-end-"
214+
"of-support-for-python-2-7-in-aws-sdk-for-python-and-"
215+
"aws-cli-v1/\n"
216+
).format(py_version[0], py_version[1])
217+
print(unsupported_python_msg, file=sys.stderr)
218+
sys.exit(1)
219+
220+
if py_version in DEPRECATED_PYTHON:
221+
params = DEPRECATED_PYTHON[py_version]
222+
deprecated_python_msg = (
223+
"Deprecated Python version detected: Python {}.{}\n"
224+
"Starting {}, the AWS CLI will no longer support "
225+
"this version of Python. To continue receiving service updates, "
226+
"bug fixes, and security updates please upgrade to Python 3.7 or "
227+
"later. More information can be found here: {}"
228+
).format(
229+
py_version[0], py_version[1], params['date'], params['blog_link']
230+
)
231+
print(deprecated_python_msg, file=sys.stderr)
232+
233+
opts = parser.parse_args()[0]
234+
working_dir = create_working_dir()
235+
try:
236+
create_install_structure(working_dir, opts.install_dir)
237+
pip_install_packages(opts.install_dir)
238+
real_location = os.path.join(opts.install_dir, bin_path(), 'aws')
239+
if opts.bin_location and create_symlink(real_location,
240+
opts.bin_location):
241+
print("You can now run: %s --version" % opts.bin_location)
242+
else:
243+
print("You can now run: %s --version" % real_location)
244+
print('\nNote: AWS CLI version 2, the latest major version '
245+
'of the AWS CLI, is now stable and recommended for general '
246+
'use. For more information, see the AWS CLI version 2 '
247+
'installation instructions at: https://docs.aws.amazon.com/cli/'
248+
'latest/userguide/install-cliv2.html')
249+
finally:
250+
shutil.rmtree(working_dir)
251+
252+
253+
create_virtualenv = _create_virtualenv_internal
254+
255+
256+
if __name__ == '__main__':
257+
main()
171 KB
Binary file not shown.
1.56 MB
Binary file not shown.
10.3 MB
Binary file not shown.
27.2 KB
Binary file not shown.
1.87 MB
Binary file not shown.
21.1 KB
Binary file not shown.
25.2 KB
Binary file not shown.
143 KB
Binary file not shown.
Binary file not shown.
38.8 KB
Binary file not shown.
132 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
33.2 KB
Binary file not shown.
294 KB
Binary file not shown.
4.88 MB
Binary file not shown.

src/sagemaker/model_card/model_card.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,10 +387,7 @@ def __init__(
387387

388388

389389
class HyperParameter(_DefaultToRequestDict, _DefaultFromDict):
390-
"""Hyper-Parameters data.
391-
392-
Should only be used during auto-population of parameters details.
393-
"""
390+
"""Hyper-Parameters data."""
394391

395392
def __init__(
396393
self,

tests/unit/test_model_card.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,29 @@
361361
"Timestamp": datetime.datetime(2022, 9, 5, 19, 18, 40),
362362
},
363363
],
364+
"HyperParameters": [
365+
{
366+
"feature_dim": "2",
367+
"mini_batch_size": "10",
368+
"predictor_type": "binary_classifier",
369+
},
370+
{
371+
"_kfold": "5",
372+
"_tuning_objective_metric": "validation:accuracy",
373+
"alpha": "0.0037170512924477993",
374+
"colsample_bytree": "0.7476726040667319",
375+
"eta": "0.011391935592233605",
376+
"eval_metric": "accuracy,f1,balanced_accuracy,precision_macro,recall_macro,mlogloss",
377+
"gamma": "1.8903517751689445",
378+
"lambda": "0.5098604662224621",
379+
"max_depth": "3",
380+
"min_child_weight": "5.081388147234708e-06",
381+
"num_class": "28",
382+
"num_round": "165",
383+
"objective": "multi:softprob",
384+
"subsample": "0.8828549481113146",
385+
},
386+
],
364387
"CreatedBy": {},
365388
}
366389
}
@@ -891,14 +914,6 @@ def __init__(self, attr1): # pylint: disable=C0116
891914
):
892915
ExampleClass(attr1=IntendedUses())
893916

894-
with pytest.raises(
895-
ValueError,
896-
match=re.escape(
897-
"Expected <class 'sagemaker.model_card.model_card.BusinessDetails'> instance to be of class ModelOverview" # noqa E501 # pylint: disable=c0301
898-
),
899-
):
900-
ExampleClass(attr1=BusinessDetails())
901-
902917
# decode object from json data
903918
assert ExampleClass({"model_name": "test"})
904919

@@ -1050,6 +1065,9 @@ def test_training_details_autodiscovery_from_model_overview(
10501065
assert len(training_details.training_job_details.training_metrics) == len(
10511066
SEARCH_TRAINING_JOB_EXAMPLE["Results"][0]["TrainingJob"]["FinalMetricDataList"]
10521067
)
1068+
assert len(training_details.training_job_details.training_metrics) == len(
1069+
SEARCH_TRAINING_JOB_EXAMPLE["Results"][0]["TrainingJob"]["HyperParameters"]
1070+
)
10531071
assert training_details.training_job_details.training_environment.container_image == [
10541072
TRAINING_IMAGE
10551073
]
@@ -1097,6 +1115,9 @@ def test_training_details_autodiscovery_from_job_name(session):
10971115
assert len(training_details.training_job_details.training_metrics) == len(
10981116
SEARCH_TRAINING_JOB_EXAMPLE["Results"][0]["TrainingJob"]["FinalMetricDataList"]
10991117
)
1118+
assert len(training_details.training_job_details.training_metrics) == len(
1119+
SEARCH_TRAINING_JOB_EXAMPLE["Results"][0]["TrainingJob"]["HyperParameters"]
1120+
)
11001121
assert training_details.training_job_details.training_environment.container_image == [
11011122
TRAINING_IMAGE
11021123
]

0 commit comments

Comments
 (0)