sagemaker-core 1.0.9__tar.gz → 1.0.11__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.

Potentially problematic release.


This version of sagemaker-core might be problematic. Click here for more details.

Files changed (43) hide show
  1. {sagemaker_core-1.0.9/src/sagemaker_core.egg-info → sagemaker_core-1.0.11}/PKG-INFO +1 -1
  2. sagemaker_core-1.0.11/VERSION +1 -0
  3. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/code_injection/shape_dag.py +15 -0
  4. sagemaker_core-1.0.11/src/sagemaker_core/main/logs.py +167 -0
  5. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/resources.py +200 -56
  6. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/shapes.py +18 -14
  7. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/utils.py +9 -3
  8. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/constants.py +2 -0
  9. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/resources_codegen.py +47 -0
  10. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/templates.py +42 -6
  11. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11/src/sagemaker_core.egg-info}/PKG-INFO +1 -1
  12. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core.egg-info/SOURCES.txt +1 -0
  13. sagemaker_core-1.0.9/VERSION +0 -1
  14. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/LICENSE +0 -0
  15. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/MANIFEST.in +0 -0
  16. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/README.rst +0 -0
  17. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/pyproject.toml +0 -0
  18. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/setup.cfg +0 -0
  19. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/__init__.py +0 -0
  20. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/_version.py +0 -0
  21. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/helper/__init__.py +0 -0
  22. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/helper/session_helper.py +0 -0
  23. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/__init__.py +0 -0
  24. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/code_injection/__init__.py +0 -0
  25. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/code_injection/base.py +0 -0
  26. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/code_injection/codec.py +0 -0
  27. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/code_injection/constants.py +0 -0
  28. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/config_schema.py +0 -0
  29. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/exceptions.py +0 -0
  30. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/intelligent_defaults_helper.py +0 -0
  31. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/main/user_agent.py +0 -0
  32. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/resources/__init__.py +0 -0
  33. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/shapes/__init__.py +0 -0
  34. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/__init__.py +0 -0
  35. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/codegen.py +0 -0
  36. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/data_extractor.py +0 -0
  37. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/method.py +0 -0
  38. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/resources_extractor.py +0 -0
  39. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/shapes_codegen.py +0 -0
  40. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core/tools/shapes_extractor.py +0 -0
  41. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core.egg-info/dependency_links.txt +0 -0
  42. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core.egg-info/requires.txt +0 -0
  43. {sagemaker_core-1.0.9 → sagemaker_core-1.0.11}/src/sagemaker_core.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sagemaker-core
3
- Version: 1.0.9
3
+ Version: 1.0.11
4
4
  Summary: An python package for sagemaker core functionalities
5
5
  Author-email: AWS <sagemaker-interests@amazon.com>
6
6
  Project-URL: Repository, https://github.com/aws/sagemaker-core.git
@@ -0,0 +1 @@
1
+ 1.0.11
@@ -1380,6 +1380,11 @@ SHAPE_DAG = {
1380
1380
  "shape": "AppLifecycleManagement",
1381
1381
  "type": "structure",
1382
1382
  },
1383
+ {
1384
+ "name": "BuiltInLifecycleConfigArn",
1385
+ "shape": "StudioLifecycleConfigArn",
1386
+ "type": "string",
1387
+ },
1383
1388
  ],
1384
1389
  "type": "structure",
1385
1390
  },
@@ -3793,6 +3798,11 @@ SHAPE_DAG = {
3793
3798
  {"name": "CreationTime", "shape": "Timestamp", "type": "timestamp"},
3794
3799
  {"name": "FailureReason", "shape": "FailureReason", "type": "string"},
3795
3800
  {"name": "ResourceSpec", "shape": "ResourceSpec", "type": "structure"},
3801
+ {
3802
+ "name": "BuiltInLifecycleConfigArn",
3803
+ "shape": "StudioLifecycleConfigArn",
3804
+ "type": "string",
3805
+ },
3796
3806
  ],
3797
3807
  "type": "structure",
3798
3808
  },
@@ -7699,6 +7709,11 @@ SHAPE_DAG = {
7699
7709
  "type": "structure",
7700
7710
  },
7701
7711
  {"name": "EmrSettings", "shape": "EmrSettings", "type": "structure"},
7712
+ {
7713
+ "name": "BuiltInLifecycleConfigArn",
7714
+ "shape": "StudioLifecycleConfigArn",
7715
+ "type": "string",
7716
+ },
7702
7717
  ],
7703
7718
  "type": "structure",
7704
7719
  },
@@ -0,0 +1,167 @@
1
+ import boto3
2
+ import botocore
3
+
4
+ from boto3.session import Session
5
+ import botocore.client
6
+ from botocore.config import Config
7
+ from typing import Generator, Tuple, List
8
+ from sagemaker_core.main.utils import SingletonMeta
9
+
10
+
11
+ class CloudWatchLogsClient(metaclass=SingletonMeta):
12
+ """
13
+ A singleton class for creating a CloudWatchLogs client.
14
+ """
15
+
16
+ client: botocore.client = None
17
+
18
+ def __init__(self):
19
+ if not self.client:
20
+ session = Session()
21
+ self.client = session.client(
22
+ "logs",
23
+ session.region_name,
24
+ config=Config(retries={"max_attempts": 10, "mode": "standard"}),
25
+ )
26
+
27
+
28
+ class LogStreamHandler:
29
+ log_group_name: str = None
30
+ log_stream_name: str = None
31
+ stream_id: int = None
32
+ next_token: str = None
33
+ cw_client = None
34
+
35
+ def __init__(self, log_group_name: str, log_stream_name: str, stream_id: int):
36
+ self.log_group_name = log_group_name
37
+ self.log_stream_name = log_stream_name
38
+ self.cw_client = CloudWatchLogsClient().client
39
+ self.stream_id = stream_id
40
+
41
+ def get_latest_log_events(self) -> Generator[Tuple[str, dict], None, None]:
42
+ """
43
+ This method gets all the latest log events for this stream that exist at this moment in time.
44
+
45
+ cw_client.get_log_events() always returns a nextForwardToken even if the current batch of events is empty.
46
+ You can keep calling cw_client.get_log_events() with the same token until a new batch of log events exist.
47
+
48
+ API Reference: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs/client/get_log_events.html
49
+
50
+ Returns:
51
+ Generator[tuple[str, dict], None, None]: Generator that yields a tuple that consists for two values
52
+ str: stream_name,
53
+ dict: event dict in format
54
+ {
55
+ "ingestionTime": number,
56
+ "message": "string",
57
+ "timestamp": number
58
+ }
59
+ """
60
+ while True:
61
+ if not self.next_token:
62
+ token_args = {}
63
+ else:
64
+ token_args = {"nextToken": self.next_token}
65
+
66
+ response = self.cw_client.get_log_events(
67
+ logGroupName=self.log_group_name,
68
+ logStreamName=self.log_stream_name,
69
+ startFromHead=True,
70
+ **token_args,
71
+ )
72
+
73
+ self.next_token = response["nextForwardToken"]
74
+ if not response["events"]:
75
+ break
76
+
77
+ for event in response["events"]:
78
+ yield self.log_stream_name, event
79
+
80
+
81
+ class MultiLogStreamHandler:
82
+ log_group_name: str = None
83
+ log_stream_name_prefix: str = None
84
+ expected_stream_count: int = None
85
+ streams: List[LogStreamHandler] = []
86
+ cw_client = None
87
+
88
+ def __init__(
89
+ self, log_group_name: str, log_stream_name_prefix: str, expected_stream_count: int
90
+ ):
91
+ self.log_group_name = log_group_name
92
+ self.log_stream_name_prefix = log_stream_name_prefix
93
+ self.expected_stream_count = expected_stream_count
94
+ self.cw_client = CloudWatchLogsClient().client
95
+
96
+ def get_latest_log_events(self) -> Generator[Tuple[str, dict], None, None]:
97
+ """
98
+ This method gets all the latest log events from each stream that exist at this moment.
99
+
100
+ Returns:
101
+ Generator[tuple[str, dict], None, None]: Generator that yields a tuple that consists for two values
102
+ str: stream_name,
103
+ dict: event dict in format -
104
+ {
105
+ "ingestionTime": number,
106
+ "message": "string",
107
+ "timestamp": number
108
+ }
109
+ """
110
+ if not self.ready():
111
+ return []
112
+
113
+ for stream in self.streams:
114
+ yield from stream.get_latest_log_events()
115
+
116
+ def ready(self) -> bool:
117
+ """
118
+ Checks whether or not MultiLogStreamHandler is ready to serve new log events at this moment.
119
+
120
+ If self.streams is already set, return True.
121
+ Otherwise, check if the current number of log streams in the log group match the exptected stream count.
122
+
123
+ Returns:
124
+ bool: Whether or not MultiLogStreamHandler is ready to serve new log events.
125
+ """
126
+
127
+ if len(self.streams) >= self.expected_stream_count:
128
+ return True
129
+
130
+ try:
131
+ response = self.cw_client.describe_log_streams(
132
+ logGroupName=self.log_group_name,
133
+ logStreamNamePrefix=self.log_stream_name_prefix + "/",
134
+ orderBy="LogStreamName",
135
+ )
136
+ stream_names = [stream["logStreamName"] for stream in response["logStreams"]]
137
+
138
+ next_token = response.get("nextToken")
139
+ while next_token:
140
+ response = self.cw_client.describe_log_streams(
141
+ logGroupName=self.log_group_name,
142
+ logStreamNamePrefix=self.log_stream_name_prefix + "/",
143
+ orderBy="LogStreamName",
144
+ nextToken=next_token,
145
+ )
146
+ stream_names.extend([stream["logStreamName"] for stream in response["logStreams"]])
147
+ next_token = response.get("nextToken", None)
148
+
149
+ if len(stream_names) >= self.expected_stream_count:
150
+ self.streams = [
151
+ LogStreamHandler(self.log_group_name, log_stream_name, index)
152
+ for index, log_stream_name in enumerate(stream_names)
153
+ ]
154
+
155
+ return True
156
+ else:
157
+ # Log streams are created whenever a container starts writing to stdout/err,
158
+ # so if the stream count is less than the expected number, return False
159
+ return False
160
+
161
+ except botocore.exceptions.ClientError as e:
162
+ # On the very first training job run on an account, there's no log group until
163
+ # the container starts logging, so ignore any errors thrown about that
164
+ if e.response["Error"]["Code"] == "ResourceNotFoundException":
165
+ return False
166
+ else:
167
+ raise