Skip to content

Commit e0b1244

Browse files
committed
Fixed logic of pulling examples from cli in edge cases of unreleased zenml
1 parent 86837d9 commit e0b1244

File tree

4 files changed

+165
-48
lines changed

4 files changed

+165
-48
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Post Execution Workflow
2+
3+
## Post-execution workflow
4+
5+
After executing a pipeline, the user needs to be able to fetch it from history and perform certain tasks. This page captures these workflows at an orbital level.
6+
7+
## Component Hierarchy
8+
9+
10+
In the context of a post-execution workflow, there is an implied hierarchy of some basic ZenML components:
11+
12+
```bash
13+
repository -> pipelines -> runs -> steps -> outputs
14+
15+
# where -> implies a 1-many relationship.
16+
```
17+
18+
### Repository
19+
20+
The highest level `repository` object is where to start from.
21+
22+
23+
### Define standard ML steps
24+
25+
```python
26+
@trainer
27+
def trainer(dataset: torch.Dataset) -> torch.nn.Module:
28+
...
29+
return model
30+
```
31+
32+
33+
34+
### Get pipelines and runs
35+
36+
```python
37+
pipelines = repo.get_pipelines() # get all pipelines from all stacks
38+
pipeline = repo.get_pipeline(pipeline_name=..., stack_key=...)
39+
```
40+
41+
```python
42+
runs = pipeline.get_runs() # all runs of a pipeline chronlogically ordered
43+
run = runs[-1] # latest run
44+
output = step.outputs[0] # get outputs
45+
```
46+
47+
### Materializing outputs (or inputs)
48+
49+
Once an output artifact is acquired from history, one can visualize it with any chosen `Materializer`.
50+
51+
```python
52+
df = output.read(materializer=PandasMaterializer) # get data
53+
54+
```
55+
56+
### Seeing statistics and schema
57+
58+
```python
59+
stats = output.read(materializer=StatisticsMaterializer) # get stats
60+
schema = output.read(materializer=SchemaMaterializer) # get schema
61+
```
62+
63+
### Retrieving Model
64+
65+
```python
66+
model = output.read(materializer=KerasModelMaterializer) # get model
67+
```
68+
69+
70+
71+
#### Pipelines
72+
73+
```python
74+
# get all pipelines from all stacks
75+
pipelines = repo.get_pipelines()
76+
77+
# or get one pipeline by name and/or stack key
78+
pipeline = repo.get_pipeline(pipeline_name=..., stack_key=...)
79+
```
80+
81+
#### Runs
82+
83+
```python
84+
85+
```
86+
87+
#### Steps
88+
89+
```python
90+
# at this point we switch from the `get_` paradigm to properties
91+
steps = run.steps # all steps of a pipeline
92+
step = steps[0]
93+
print(step.name)
94+
```
95+
96+
#### Outputs
97+
98+
```python
99+
# all outputs of a step
100+
# if one output, then its the first element in the list
101+
# if multiple output, then in the order defined with the `Output`
102+
103+
104+
# will get you the value from the original materializer used in the pipeline
105+
output.read()
106+
```
107+
108+
## Visuals
109+
110+

docs/interrogate.svg

Lines changed: 3 additions & 3 deletions
Loading

src/zenml/cli/example.py

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,16 @@
3434

3535

3636
class GitExamplesHandler(object):
37+
"""Handles logic related to cloning and checking out the ZenML Git
38+
repository, in relation to the `examples` dir."""
39+
3740
def __init__(self, redownload: str = "") -> None:
3841
"""Initialize the GitExamplesHandler class."""
3942
self.clone_repo(redownload)
4043

4144
def clone_repo(self, redownload_version: str = "") -> None:
42-
"""Clone ZenML git repo into global config directory if not already cloned"""
45+
"""Clone ZenML git repo into global config directory if not already
46+
cloned"""
4347
installed_version = zenml_version_installed
4448
repo_dir = click.get_app_dir(APP_NAME)
4549
examples_dir = os.path.join(repo_dir, EXAMPLES_GITHUB_REPO)
@@ -54,39 +58,55 @@ def clone_repo(self, redownload_version: str = "") -> None:
5458
redownload_version
5559
or EXAMPLES_GITHUB_REPO not in config_directory_files
5660
):
57-
self.clone_from_zero(GIT_REPO_URL, examples_dir, installed_version)
61+
self.clone_from_zero(GIT_REPO_URL, examples_dir)
62+
repo = Repo(examples_dir)
63+
self.checkout_repository(repo, installed_version)
5864

59-
def clone_from_zero(
60-
self, git_repo_url: str, local_dir: str, version: str
61-
) -> None:
65+
def clone_from_zero(self, git_repo_url: str, local_dir: str) -> None:
6266
"""Basic functionality to clone a repo."""
6367
try:
64-
Repo.clone_from(git_repo_url, local_dir, branch=version)
65-
except GitCommandError:
66-
error(
67-
f"You just tried to download examples for version {version}. "
68-
f"There is no corresponding release or version. Please try "
69-
f"again with a version number corresponding to an actual release."
70-
)
68+
Repo.clone_from(git_repo_url, local_dir, branch="main")
7169
except KeyboardInterrupt:
7270
self.delete_example_source_dir(local_dir)
71+
error("Cancelled download of repository.. Rolled back.")
72+
return
7373

7474
def checkout_repository(
75-
self, repository: Repo, desired_version: str
75+
self,
76+
repository: Repo,
77+
desired_version: str,
78+
fallback_to_latest: bool = True,
7679
) -> None:
7780
"""Checks out a branch or tag of a git repository
7881
7982
Args:
80-
desired_version: a valid ZenML release version number
83+
repository: a Git repository reference.
84+
desired_version: a valid ZenML release version number.
85+
fallback_to_latest: Whether to default to the latest released
86+
version or not if `desired_version` does not exist.
8187
"""
8288
try:
8389
repository.git.checkout(desired_version)
8490
except GitCommandError:
85-
error(
86-
f"You just tried to checkout the repository for version {desired_version}. "
87-
f"There is no corresponding release or version. Please try "
88-
f"again with a version number corresponding to an actual release."
89-
)
91+
if fallback_to_latest:
92+
last_release = parse(repository.tags[-1].name)
93+
repository.git.checkout(last_release)
94+
warning(
95+
f"You just tried to download examples for version "
96+
f"{desired_version}. "
97+
f"There is no corresponding release or version. We are "
98+
f"going to "
99+
f"default to the last release: {last_release}"
100+
)
101+
else:
102+
error(
103+
f"You just tried to checkout the repository for version "
104+
f"{desired_version}. "
105+
f"There is no corresponding release or version. Please try "
106+
f"again with a version number corresponding to an actual "
107+
f"release."
108+
)
109+
raise
90110

91111
def clone_when_examples_already_cloned(
92112
self, local_dir: str, version: str
@@ -95,20 +115,12 @@ def clone_when_examples_already_cloned(
95115
into the global config directory if they are already cloned."""
96116
local_dir_path = Path(local_dir)
97117
repo = Repo(str(local_dir_path))
98-
99-
last_release = parse(repo.tags[-1].name)
100118
desired_version = parse(version)
101-
102-
if last_release < desired_version:
103-
warning(
104-
f"You tried to download {desired_version}."
105-
f"The latest version you currently have available is {last_release}."
106-
f"Recloning the repository from scratch to try to obtain {desired_version}"
107-
)
108-
self.delete_example_source_dir(str(local_dir_path))
109-
self.clone_from_zero(GIT_REPO_URL, local_dir, str(desired_version))
110-
else:
111-
self.checkout_repository(repo, str(desired_version))
119+
self.delete_example_source_dir(str(local_dir_path))
120+
self.clone_from_zero(GIT_REPO_URL, local_dir)
121+
self.checkout_repository(
122+
repo, str(desired_version), fallback_to_latest=False
123+
)
112124

113125
def get_examples_dir(self) -> str:
114126
"""Return the examples dir"""
@@ -155,11 +167,13 @@ def delete_example_source_dir(self, source_path: str) -> None:
155167
path_utils.rm_dir(source_path)
156168
else:
157169
raise ValueError(
158-
"You can only delete the source directory from your ZenML config directory"
170+
"You can only delete the source directory from your ZenML "
171+
"config directory"
159172
)
160173

161174
def delete_working_directory_examples_folder(self) -> None:
162-
"""Delete the zenml_examples folder from the current working directory."""
175+
"""Delete the zenml_examples folder from the current working
176+
directory."""
163177
cwd_directory_path = os.path.join(os.getcwd(), EXAMPLES_GITHUB_REPO)
164178
if os.path.exists(cwd_directory_path):
165179
path_utils.rm_dir(str(cwd_directory_path))
@@ -193,7 +207,8 @@ def list(git_examples_handler: Any) -> None:
193207
# TODO: [MEDIUM] Use a better type for the git_examples_handler
194208
def info(git_examples_handler: Any, example_name: str) -> None:
195209
"""Find out more about an example."""
196-
# TODO: [MEDIUM] fix markdown formatting so that it looks nicer (not a pure .md dump)
210+
# TODO: [MEDIUM] fix markdown formatting so that it looks nicer (not a
211+
# pure .md dump)
197212
example_dir = os.path.join(
198213
git_examples_handler.get_examples_dir(), example_name
199214
)
@@ -221,7 +236,8 @@ def info(git_examples_handler: Any, example_name: str) -> None:
221236
"--force",
222237
"-f",
223238
is_flag=True,
224-
help="Force the redownload of the examples folder to the ZenML config folder.",
239+
help="Force the redownload of the examples folder to the ZenML config "
240+
"folder.",
225241
)
226242
@click.option(
227243
"--version",

tests/cli/test_example.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from click.testing import CliRunner
2020
from git.repo.base import Repo
2121

22-
from zenml import __version__ as running_zenml_version
2322
from zenml.cli.example import EXAMPLES_GITHUB_REPO, info, list, pull
2423
from zenml.constants import APP_NAME
2524
from zenml.logger import get_logger
@@ -56,14 +55,6 @@ def test_info_returns_zero_exit_code(example: str) -> None:
5655
assert result.exit_code == 0
5756

5857

59-
def test_pull_command_returns_zero_exit_code() -> None:
60-
"""Check pull command exits without errors"""
61-
runner = CliRunner()
62-
with runner.isolated_filesystem():
63-
result = runner.invoke(pull, ["-f", "-v", running_zenml_version])
64-
assert result.exit_code == 0
65-
66-
6758
def test_pull_earlier_version_returns_zero_exit_code() -> None:
6859
"""Check pull of earlier version exits without errors"""
6960
runner = CliRunner()

0 commit comments

Comments
 (0)