flyte 0.2.0b8__py3-none-any.whl → 0.2.0b9__py3-none-any.whl

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 flyte might be problematic. Click here for more details.

flyte/cli/__init__.py CHANGED
@@ -1,10 +1,3 @@
1
- """
2
- # CLI for Flyte
3
-
4
- The flyte cli follows a simple verb based structure, where the top-level commands are verbs that describe the action
5
- to be taken, and the subcommands are nouns that describe the object of the action.
6
- """
7
-
8
1
  from flyte.cli.main import main
9
2
 
10
3
  __all__ = ["main"]
flyte/cli/_abort.py CHANGED
@@ -6,7 +6,7 @@ from flyte.cli import _common as common
6
6
  @click.group(name="abort")
7
7
  def abort():
8
8
  """
9
- Abort a run.
9
+ Abort an ongoing process.
10
10
  """
11
11
 
12
12
 
flyte/cli/_common.py CHANGED
@@ -58,7 +58,7 @@ DRY_RUN_OPTION = click.Option(
58
58
 
59
59
  def _common_options() -> List[click.Option]:
60
60
  """
61
- Common options for that will be added to all commands and groups that inherit from CommandBase or GroupBase.
61
+ Common options that will be added to all commands and groups that inherit from CommandBase or GroupBase.
62
62
  """
63
63
  return [PROJECT_OPTION, DOMAIN_OPTION]
64
64
 
@@ -110,8 +110,8 @@ class CLIConfig:
110
110
 
111
111
  class InvokeBaseMixin:
112
112
  """
113
- Mixin to catch grpc.RpcError, flyte.RpcError, other errors and other exceptions and raise them as
114
- gclick.ClickException.
113
+ Mixin to catch grpc.RpcError, flyte.RpcError, other errors and other exceptions
114
+ and raise them as gclick.ClickException.
115
115
  """
116
116
 
117
117
  def invoke(self, ctx):
flyte/cli/_create.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from pathlib import Path
2
- from typing import get_args
2
+ from typing import Any, Dict, get_args
3
3
 
4
4
  import rich_click as click
5
5
 
@@ -10,7 +10,7 @@ from flyte.remote._secret import SecretTypes
10
10
  @click.group(name="create")
11
11
  def create():
12
12
  """
13
- The create subcommand allows you to create resources in a Flyte deployment.
13
+ Create resources in a Flyte deployment.
14
14
  """
15
15
 
16
16
 
@@ -32,22 +32,26 @@ def secret(
32
32
  domain: str | None = None,
33
33
  ):
34
34
  """
35
- Create a new secret, the name of the secret is required.
35
+ Create a new secret. The name of the secret is required. For example:
36
36
 
37
- Examples:
38
37
  ```bash
39
- flyte create secret my_secret --value my_value
38
+ $ flyte create secret my_secret --value my_value
40
39
  ```
41
- If `--from-file` is specified, the value will be read from the file instead of being provided directly.
42
- Example:
40
+
41
+ If `--from-file` is specified, the value will be read from the file instead of being provided directly:
42
+
43
43
  ```bash
44
- flyte create secret my_secret --from-file /path/to/secret_file
44
+ $ flyte create secret my_secret --from-file /path/to/secret_file
45
45
  ```
46
- Secret types can be used to create specific types of secrets. Some secrets are useful for image pull, while some
47
- are `regular` / general purpose secrets.
48
- Example:
46
+
47
+ The `--type` option can be used to create specific types of secrets.
48
+ Either `regular` or `image_pull` can be specified.
49
+ Secrets intended to access container images should be specified as `image_pull`.
50
+ Other secrets should be specified as `regular`.
51
+ If no type is specified, `regular` is assumed.
52
+
49
53
  ```bash
50
- flyte create secret my_secret --type image_pull
54
+ $ flyte create secret my_secret --type image_pull
51
55
  ```
52
56
  """
53
57
  from flyte.remote import Secret
@@ -61,28 +65,28 @@ def secret(
61
65
 
62
66
  @create.command(cls=common.CommandBase)
63
67
  @click.option("--endpoint", type=str, help="Endpoint of the Flyte backend.")
64
- @click.option("--insecure", is_flag=True, help="Use insecure connection to the Flyte backend.")
68
+ @click.option("--insecure", is_flag=True, help="Use an insecure connection to the Flyte backend.")
65
69
  @click.option(
66
70
  "--org",
67
71
  type=str,
68
72
  required=False,
69
- help="Organization to use, this will override the organization in the config file.",
73
+ help="Organization to use, this will override the organization in the configusraion file.",
70
74
  )
71
75
  @click.option(
72
76
  "-o",
73
77
  "--output",
74
78
  type=click.Path(exists=False, writable=True),
75
79
  default=Path.cwd() / "config.yaml",
76
- help="Path to the output dir where the config will be saved, defaults to current directory.",
80
+ help="Path to the output directory where the configuration will be saved. Defaults to current directory.",
77
81
  show_default=True,
78
82
  )
79
83
  @click.option(
80
84
  "--force",
81
85
  is_flag=True,
82
86
  default=False,
83
- help="Force overwrite the config file if it already exists.",
87
+ help="Force overwrite of the configuration file if it already exists.",
84
88
  show_default=True,
85
- prompt="Are you sure you want to overwrite the config file?",
89
+ prompt="Are you sure you want to overwrite the configuration file?",
86
90
  confirmation_prompt=True,
87
91
  )
88
92
  def config(
@@ -95,7 +99,7 @@ def config(
95
99
  force: bool = False,
96
100
  ):
97
101
  """
98
- This command creates a configuration file for Flyte CLI.
102
+ Creates a configuration file for Flyte CLI.
99
103
  If the `--output` option is not specified, it will create a file named `config.yaml` in the current directory.
100
104
  If the file already exists, it will raise an error unless the `--force` option is used.
101
105
  """
@@ -104,18 +108,29 @@ def config(
104
108
  if output.exists() and not force:
105
109
  raise click.BadParameter(f"Output file {output} already exists. Use --force to overwrite.")
106
110
 
111
+ admin: Dict[str, Any] = {}
112
+ if endpoint:
113
+ admin["endpoint"] = endpoint
114
+ if insecure:
115
+ admin["insecure"] = insecure
116
+
117
+ task: Dict[str, str] = {}
118
+ if org:
119
+ task["org"] = org
120
+ if project:
121
+ task["project"] = project
122
+ if domain:
123
+ task["domain"] = domain
124
+
125
+ if not admin and not task:
126
+ raise click.BadParameter("At least one of --endpoint or --org must be provided.")
127
+
107
128
  with open(output, "w") as f:
108
- d = {
109
- "admin": {
110
- "endpoint": endpoint,
111
- "insecure": insecure,
112
- },
113
- "task": {
114
- "org": org,
115
- "project": project,
116
- "domain": domain,
117
- },
118
- }
129
+ d: Dict[str, Any] = {}
130
+ if admin:
131
+ d["admin"] = admin
132
+ if task:
133
+ d["task"] = task
119
134
  yaml.dump(d, f)
120
135
 
121
136
  click.echo(f"Config file created at {output}")
flyte/cli/_delete.py CHANGED
@@ -6,7 +6,7 @@ import flyte.cli._common as common
6
6
  @click.group(name="delete")
7
7
  def delete():
8
8
  """
9
- The delete subcommand allows you to remove resources from a Flyte deployment.
9
+ Remove resources from a Flyte deployment.
10
10
  """
11
11
 
12
12
 
@@ -15,7 +15,7 @@ def delete():
15
15
  @click.pass_obj
16
16
  def secret(cfg: common.CLIConfig, name: str, project: str | None = None, domain: str | None = None):
17
17
  """
18
- Delete a secret, the name of the secret is required.
18
+ Delete a secret. The name of the secret is required.
19
19
  """
20
20
  from flyte.remote import Secret
21
21
 
flyte/cli/_deploy.py CHANGED
@@ -61,7 +61,7 @@ class DeployArguments:
61
61
  @classmethod
62
62
  def options(cls) -> List[click.Option]:
63
63
  """
64
- Return the set of base parameters added to every pyflyte run workflow subcommand.
64
+ Return the set of base parameters added to every flyte run workflow subcommand.
65
65
  """
66
66
  return [common.get_option_from_metadata(f.metadata) for f in fields(cls) if f.metadata]
67
67
 
@@ -87,7 +87,7 @@ class DeployEnvCommand(click.Command):
87
87
 
88
88
  class EnvPerFileGroup(common.ObjectsPerFileGroup):
89
89
  """
90
- Group that creates a command for each task in the current directory that is not __init__.py.
90
+ Group that creates a command for each task in the current directory that is not `__init__.py`.
91
91
  """
92
92
 
93
93
  def __init__(self, filename: Path, deploy_args: DeployArguments, *args, **kwargs):
@@ -111,7 +111,7 @@ class EnvPerFileGroup(common.ObjectsPerFileGroup):
111
111
 
112
112
  class EnvFiles(common.FileGroup):
113
113
  """
114
- Group that creates a command for each file in the current directory that is not __init__.py.
114
+ Group that creates a command for each file in the current directory that is not `__init__.py`.
115
115
  """
116
116
 
117
117
  common_options_enabled = False
flyte/cli/_gen.py CHANGED
@@ -1,3 +1,4 @@
1
+ import textwrap
1
2
  from os import getcwd
2
3
  from typing import Generator, Tuple
3
4
 
@@ -9,7 +10,7 @@ import flyte.cli._common as common
9
10
  @click.group(name="gen")
10
11
  def gen():
11
12
  """
12
- Generate documentation
13
+ Generate documentation.
13
14
  """
14
15
 
15
16
 
@@ -18,7 +19,7 @@ def gen():
18
19
  @click.pass_obj
19
20
  def docs(cfg: common.CLIConfig, doc_type: str, project: str | None = None, domain: str | None = None):
20
21
  """
21
- Generate documentation
22
+ Generate documentation.
22
23
  """
23
24
  if doc_type == "markdown":
24
25
  markdown(cfg)
@@ -82,7 +83,7 @@ def markdown(cfg: common.CLIConfig):
82
83
  output.append(f"{'#' * (len(cmd_path_parts) + 1)} {cmd_path}")
83
84
  if cmd.help:
84
85
  output.append("")
85
- output.append(f"{cmd.help.strip()}")
86
+ output.append(f"{dedent(cmd.help)}")
86
87
 
87
88
  if not cmd.params:
88
89
  continue
@@ -109,7 +110,7 @@ def markdown(cfg: common.CLIConfig):
109
110
  if param.default is not None:
110
111
  default_value = f"`{param.default}`"
111
112
  default_value = default_value.replace(f"{getcwd()}/", "")
112
- help_text = param.help.strip() if param.help else ""
113
+ help_text = dedent(param.help) if param.help else ""
113
114
  table_data.append([opts, f"`{param.type.name}`", default_value, help_text])
114
115
 
115
116
  if not table_data:
@@ -153,3 +154,10 @@ def markdown(cfg: common.CLIConfig):
153
154
  print("{{< /grid >}}")
154
155
  print()
155
156
  print("\n".join(output))
157
+
158
+
159
+ def dedent(text: str) -> str:
160
+ """
161
+ Remove leading whitespace from a string.
162
+ """
163
+ return textwrap.dedent(text).strip("\n")
flyte/cli/_get.py CHANGED
@@ -11,16 +11,23 @@ from . import _common as common
11
11
  @click.group(name="get")
12
12
  def get():
13
13
  """
14
- The `get` subcommand allows you to retrieve various resources from a Flyte deployment.
14
+ Retrieve resources from a Flyte deployment.
15
+
16
+ You can get information about projects, runs, tasks, actions, secrets, logs and input/output values.
15
17
 
16
- You can get information about projects, runs, tasks, actions, secrets, and more.
17
18
  Each command supports optional parameters to filter or specify the resource you want to retrieve.
18
19
 
19
- Every `get` subcommand for example ``get project` without any arguments will list all projects.
20
- `get project my_project` will return the details of the project named `my_project`.
20
+ Using a `get` subcommand without any arguments will retrieve a list of available resources to get.
21
+ For example:
22
+
23
+ * `get project` (without specifiying aproject), will list all projects.
24
+ * `get project my_project` will return the details of the project named `my_project`.
25
+
26
+ In some cases, a partially specified command will act as a filter and return available further parameters.
27
+ For example:
21
28
 
22
- In some cases `get action my_run` will return all actions for the run named `my_run` and
23
- `get action my_run my_action` will return the details of the action named `my_action` for the run `my_run`.
29
+ * `get action my_run` will return all actions for the run named `my_run`.
30
+ * `get action my_run my_action` will return the details of the action named `my_action` for the run `my_run`.
24
31
  """
25
32
 
26
33
 
@@ -29,7 +36,7 @@ def get():
29
36
  @click.pass_obj
30
37
  def project(cfg: common.CLIConfig, name: str | None = None):
31
38
  """
32
- Retrieve a list of all projects or details of a specific project by name.
39
+ Get a list of all projects, or details of a specific project by name.
33
40
  """
34
41
  from flyte.remote import Project
35
42
 
@@ -48,7 +55,7 @@ def project(cfg: common.CLIConfig, name: str | None = None):
48
55
  @click.pass_obj
49
56
  def run(cfg: common.CLIConfig, name: str | None = None, project: str | None = None, domain: str | None = None):
50
57
  """
51
- Get list of all runs or details of a specific run by name.
58
+ Get a list of all runs, or details of a specific run by name.
52
59
 
53
60
  The run details will include information about the run, its status, but only the root action will be shown.
54
61
 
@@ -78,9 +85,9 @@ def task(
78
85
  domain: str | None = None,
79
86
  ):
80
87
  """
81
- Retrieve a list of all tasks or details of a specific task by name and version.
88
+ Retrieve a list of all tasks, or details of a specific task by name and version.
82
89
 
83
- Currently name+version are required to get a specific task.
90
+ Currently, both `name` and `version` are required to get a specific task.
84
91
  """
85
92
  from flyte.remote import Task
86
93
 
@@ -156,23 +163,24 @@ def logs(
156
163
  ):
157
164
  """
158
165
  Stream logs for the provided run or action.
159
- If only the run is provided, only the logs for the parent action will be streamed.
166
+ If only the run is provided, only the logs for the parent action will be streamed:
160
167
 
161
- Example:
162
168
  ```bash
163
- flyte get logs my_run
169
+ $ flyte get logs my_run
164
170
  ```
165
171
 
166
- But, if you want to see the logs for a specific action, you can provide the action name as well:
172
+ If you want to see the logs for a specific action, you can provide the action name as well:
173
+
167
174
  ```bash
168
- flyte get logs my_run my_action
175
+ $ flyte get logs my_run my_action
169
176
  ```
170
- By default logs will be shown in the raw format, will scroll on the terminal. If automatic scrolling and only
171
- tailing --lines lines is desired, use the `--pretty` flag:
177
+
178
+ By default, logs will be shown in the raw format and will scroll the terminal.
179
+ If automatic scrolling and only tailing `--lines` number of lines is desired, use the `--pretty` flag:
180
+
172
181
  ```bash
173
- flyte get logs my_run my_action --pretty --lines 50
182
+ $ flyte get logs my_run my_action --pretty --lines 50
174
183
  ```
175
-
176
184
  """
177
185
  import flyte.remote as remote
178
186
 
@@ -206,7 +214,7 @@ def secret(
206
214
  domain: str | None = None,
207
215
  ):
208
216
  """
209
- Retrieve a list of all secrets or details of a specific secret by name.
217
+ Get a list of all secrets, or details of a specific secret by name.
210
218
  """
211
219
  import flyte.remote as remote
212
220
 
@@ -236,18 +244,18 @@ def io(
236
244
  ):
237
245
  """
238
246
  Get the inputs and outputs of a run or action.
239
- if only the run name is provided, it will show the inputs and outputs of the root action of that run.
247
+ If only the run name is provided, it will show the inputs and outputs of the root action of that run.
240
248
  If an action name is provided, it will show the inputs and outputs for that action.
241
-
242
249
  If `--inputs-only` or `--outputs-only` is specified, it will only show the inputs or outputs respectively.
243
250
 
244
- Example:
251
+ Examples:
252
+
245
253
  ```bash
246
- flyte get io my_run
254
+ $ flyte get io my_run
247
255
  ```
248
- or
256
+
249
257
  ```bash
250
- flyte get io my_run my_action
258
+ $ flyte get io my_run my_action
251
259
  ```
252
260
  """
253
261
  if inputs_only and outputs_only:
@@ -293,7 +301,7 @@ def io(
293
301
  @click.pass_obj
294
302
  def config(cfg: common.CLIConfig):
295
303
  """
296
- Shows the automatically detected configuration to connect with remote Flyte services.
304
+ Shows the automatically detected configuration to connect with the remote backend.
297
305
 
298
306
  The configuration will include the endpoint, organization, and other settings that are used by the CLI.
299
307
  """
flyte/cli/main.py CHANGED
@@ -13,7 +13,7 @@ from ._run import run
13
13
  click.rich_click.COMMAND_GROUPS = {
14
14
  "flyte": [
15
15
  {
16
- "name": "Running Workflows",
16
+ "name": "Running workflows",
17
17
  "commands": ["run", "abort"],
18
18
  },
19
19
  {
@@ -21,7 +21,7 @@ click.rich_click.COMMAND_GROUPS = {
21
21
  "commands": ["create", "deploy", "get"],
22
22
  },
23
23
  {
24
- "name": "Documentation Generation",
24
+ "name": "Documentation generation",
25
25
  "commands": ["gen"],
26
26
  },
27
27
  ]
@@ -58,13 +58,13 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
58
58
  "--endpoint",
59
59
  type=str,
60
60
  required=False,
61
- help="The endpoint to connect to, this will override any config and simply used pkce to connect.",
61
+ help="The endpoint to connect to. This will override any configuration file and simply use `pkce` to connect.",
62
62
  )
63
63
  @click.option(
64
- "--insecure/--secure",
64
+ "--insecure",
65
65
  is_flag=True,
66
66
  required=False,
67
- help="Use insecure connection to the endpoint. If secure is specified, the CLI will use TLS.",
67
+ help="Use an insecure connection to the endpoint. If not specified, the CLI will use TLS.",
68
68
  type=bool,
69
69
  default=None,
70
70
  show_default=True,
@@ -73,7 +73,7 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
73
73
  "-v",
74
74
  "--verbose",
75
75
  required=False,
76
- help="Show verbose messages and exception traces, multiple times increases verbosity (e.g., -vvv).",
76
+ help="Show verbose messages and exception traces. Repeating multiple times increases the verbosity (e.g., -vvv).",
77
77
  count=True,
78
78
  default=0,
79
79
  type=int,
@@ -82,7 +82,7 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
82
82
  "--org",
83
83
  type=str,
84
84
  required=False,
85
- help="Organization to use",
85
+ help="The organization to which the command applies.",
86
86
  )
87
87
  @click.option(
88
88
  "-c",
@@ -90,8 +90,7 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
90
90
  "config_file",
91
91
  required=False,
92
92
  type=click.Path(exists=True),
93
- help="Path to config file (YAML format) to use for the CLI. If not specified,"
94
- " the default config file will be used.",
93
+ help="Path to the configuration file to use. If not specified, the default configuration file is used."
95
94
  )
96
95
  @click.rich_config(help_config=help_config)
97
96
  @click.pass_context
@@ -104,34 +103,38 @@ def main(
104
103
  config_file: str | None,
105
104
  ):
106
105
  """
107
- ### Flyte entrypoint for the CLI
108
- The Flyte CLI is a command line interface for interacting with Flyte.
106
+ The Flyte CLI is the the command line interface for working with the Flyte SDK and backend.
109
107
 
110
- The flyte cli follows a simple verb based structure, where the top-level commands are verbs that describe the action
111
- to be taken, and the subcommands are nouns that describe the object of the action.
108
+ It follows a simple verb/noun structure,
109
+ where the top-level commands are verbs that describe the action to be taken,
110
+ and the subcommands are nouns that describe the object of the action.
112
111
 
113
- The root command can be used to configure the CLI for most commands, such as setting the endpoint,
114
- organization, and verbosity level.
112
+ The root command can be used to configure the CLI for persistent settings,
113
+ such as the endpoint, organization, and verbosity level.
115
114
 
116
- Example: Set endpoint and organization
117
- ```bash
118
- flyte --endpoint <endpoint> --org <org> get project <project_name>
119
- ```
115
+ Set endpoint and organization:
120
116
 
121
- Example: Increase verbosity level (This is useful for debugging, this will show more logs and exception traces)
122
- ```bash
123
- flyte -vvv get logs <run-name>
124
- ```
117
+ ```bash
118
+ $ flyte --endpoint <endpoint> --org <org> get project <project_name>
119
+ ```
120
+
121
+ Increase verbosity level (This is useful for debugging,
122
+ this will show more logs and exception traces):
123
+
124
+ ```bash
125
+ $ flyte -vvv get logs <run-name>
126
+ ```
127
+
128
+ Override the default config file:
125
129
 
126
- Example: Override the default config file
127
130
  ```bash
128
- flyte --config /path/to/config.yaml run ...
131
+ $ flyte --config /path/to/config.yaml run ...
129
132
  ```
130
133
 
131
- 👉 [Documentation](https://www.union.ai/docs/flyte/user-guide/) \n
132
- 👉 [GitHub](https://github.com/flyteorg/flyte) - Please leave a ⭐. \n
133
- 👉 [Slack](https://slack.flyte.org) - Join the community and ask questions.
134
- 👉 [Issues](https://github.com/flyteorg/flyte/issues)
134
+ * [Documentation](https://www.union.ai/docs/flyte/user-guide/)
135
+ * [GitHub](https://github.com/flyteorg/flyte): Please leave a star if you like Flyte!
136
+ * [Slack](https://slack.flyte.org): Join the community and ask questions.
137
+ * [Issues](https://github.com/flyteorg/flyte/issues)
135
138
 
136
139
  """
137
140
  import flyte.config as config
flyte/models.py CHANGED
@@ -5,7 +5,9 @@ import os
5
5
  import pathlib
6
6
  import tempfile
7
7
  from dataclasses import dataclass, field, replace
8
- from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Type
8
+ from typing import TYPE_CHECKING, Any, Callable, Dict, Literal, Optional, Tuple, Type
9
+
10
+ import rich.repr
9
11
 
10
12
  from flyte._docstring import Docstring
11
13
  from flyte._interface import extract_return_annotation
@@ -27,6 +29,7 @@ def generate_random_name() -> str:
27
29
  return str(uuid4()) # Placeholder for actual random name generation logic
28
30
 
29
31
 
32
+ @rich.repr.auto
30
33
  @dataclass(frozen=True, kw_only=True)
31
34
  class ActionID:
32
35
  """
@@ -68,6 +71,7 @@ class ActionID:
68
71
  return self.new_sub_action(new_name)
69
72
 
70
73
 
74
+ @rich.repr.auto
71
75
  @dataclass(frozen=True, kw_only=True)
72
76
  class RawDataPath:
73
77
  """
@@ -133,11 +137,13 @@ class RawDataPath:
133
137
  return remote_path
134
138
 
135
139
 
140
+ @rich.repr.auto
136
141
  @dataclass(frozen=True)
137
142
  class GroupData:
138
143
  name: str
139
144
 
140
145
 
146
+ @rich.repr.auto
141
147
  @dataclass(frozen=True, kw_only=True)
142
148
  class TaskContext:
143
149
  """
@@ -160,6 +166,7 @@ class TaskContext:
160
166
  code_bundle: CodeBundle | None = None
161
167
  compiled_image_cache: ImageCache | None = None
162
168
  data: Dict[str, Any] = field(default_factory=dict)
169
+ mode: Literal["local", "remote", "hybrid"] = "remote"
163
170
 
164
171
  def replace(self, **kwargs) -> TaskContext:
165
172
  if "data" in kwargs:
@@ -177,6 +184,7 @@ class TaskContext:
177
184
  return self.data.get(key)
178
185
 
179
186
 
187
+ @rich.repr.auto
180
188
  @dataclass(frozen=True, kw_only=True)
181
189
  class CodeBundle:
182
190
  """
@@ -211,6 +219,7 @@ class CodeBundle:
211
219
  return replace(self, downloaded_path=path)
212
220
 
213
221
 
222
+ @rich.repr.auto
214
223
  @dataclass(frozen=True)
215
224
  class Checkpoints:
216
225
  """