Skip to content

Commit

Permalink
Merge pull request #4 from BookletAI/dir-functions
Browse files Browse the repository at this point in the history
Adds whisk.data_dir and whisk.artfacts_dir attributes
  • Loading branch information
itsderek23 committed May 12, 2020
2 parents 9c14fe8 + 7741efd commit 197c5c1
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 26 deletions.
6 changes: 6 additions & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ It's easy to add files to version control but forget to include in the MANIFEST.
$ check-manifest


Updating the getting started notebook
-------------------------------------

The project contains a notebook to help orientate new users. You can modify this notebook in the demo project and update the template with:

$ make update-notebook


Deploying
Expand Down
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ bump-push: ## bump and push a patch release to Git
git push --tags

FULL_PROJECT_DEMO_DIR = $(PROJECT_DEMO_DIR)$(PROJECT_DEMO_NAME)
NB_PATH = notebooks/getting_started.ipynb

update-notebook: ## Copies the demo project notebook back and replaces with the cookiecutter project name
cp $(FULL_PROJECT_DEMO_DIR)/$(NB_PATH) whisk/template/\{\{\ cookiecutter.repo_name\ \}\}/notebooks/
sed -i '' -e 's/$(PROJECT_DEMO_NAME)/{{cookiecutter.project_name}}/g' whisk/template/\{\{\ cookiecutter.repo_name\ \}\}/$(NB_PATH)


create-demo: ## creates a demo whisk app for testing. destroys the existing one.
# I think whisk create --force only adds new files ... it may not create new ones.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ source venv/bin/activate
Take a quick tour the project you just created:

```
jupyter-notebook notebooks/getting_stated.ipynb
jupyter-notebook notebooks/getting_started.ipynb
```

The notebook shows how to save your trained model to disk, use the saved model to generate predictions, how to load Python functions and classes from the project's `src` directory for a cleaner notebook, and more. It's the guide rails for your own ML project.
Expand Down
17 changes: 17 additions & 0 deletions whisk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,20 @@
__author__ = """Derek Haynes"""
__email__ = 'derek@dlite.cc'
__version__ = '0.1.21'

"""
Reference to the current whisk.Project. Set when whisk is loaded from
within a created project.
"""
project = None

"""
The location of the data directory. This is set from the Project instance and made
available as a top-level attribute since it is frequently used.
"""
data_dir = None
"""
The location of the artifacts directory. This is set from the Project instance and made
available as a top-level attribute since it is frequently used.
"""
artifacts_dir = None
2 changes: 1 addition & 1 deletion whisk/cli/commands/project/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ def cli():
"""
Sets up the project environment.
"""
nbenv = Project().slug()
nbenv = Project().name
exec_setup(nbenv)
print("Install completed ✓.")
38 changes: 30 additions & 8 deletions whisk/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ class Project:

@classmethod
def from_module(cls,path):
"""
Takes a path from a generated project's src/{{name}}/__init__.py file
and returns a Project object Initialized w/that path.
"""
path_obj = Path(path)
obj = cls(path_obj.parents[2],module_dir=path_obj.parents[0])
return obj
Expand All @@ -19,29 +23,47 @@ def __init__(self, dir=os.getcwd(), module_dir=None):
Initializes a project from the existing whisk project directory `dir`.
"""
self.dir = dir
"""The top-level project directory (str)"""
self.path = Path(self.dir)
"""The top-level project directory as a pathlib.Path"""
self.name = self.path.stem
"""Name of the project derived from the top-level directory (str)"""
self.module_dir = module_dir
"""
Location of the project's module directory as a pathlib.Path.
This is derived from `path` if not provided.
"""
if not self.module_dir:
self.module_dir = self.path / "src/{}".format(self.slug())
self.module_dir = self.path / "src/{}".format(self.name)
self.artifacts_dir = self.module_dir / "artifacts"
"""
Location of the project's artifacts directory as a pathlib.Path.
This is derived from `path` if not provided.
"""
if self.in_project():
self.data_dir = self.path / "data"
"""
Location of the project's data directory as a pathlib.Path.
This is only set if with a valid whisk project.
"""
self.commands_dir = self.path / "whisk_commands"
"""
Location of the project's whisk commands directory as a pathlib.Path.
This is only set if with a valid whisk project.
"""

def validate_in_project(self):
"""
Raises an `OSError` if this is not a whisk project.
"""
if not self.in_project():
raise OSError("{} is not a whisk project directory.".format(self.dir))

def in_project(self):
"""
Returns True if the current working directory is root whisk
Returns True if the project's path is the root whisk
project directory.
"""
return (self.path / ".whisk").is_dir()
def slug(self):
"""
Returns the project slug derived from the project directory name.
This is deteremined by the presence of the ".whisk/" directory.
"""
return self.path.stem
return (self.path / ".whisk").is_dir()
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"metadata": {},
"source": [
"# Getting Started with Whisk\n",
"Whisk makes it easy to create reproducible, collobarative machine learning projects. It provides the project guide rails so you can focus on the data science. Here's what you need to know get started."
"Whisk makes it easy to create reproducible, collaborative machine learning projects. It provides the project guide rails so you can focus on the data science. Here's what you need to know get started."
]
},
{
Expand Down Expand Up @@ -49,9 +49,7 @@
"%load_ext autoreload\n",
"\n",
"# OPTIONAL: always reload modules so that as you change code in src, it gets loaded\n",
"%autoreload 2\n",
"\n",
"from {{cookiecutter.project_name}}.models.model import Model\n"
"%autoreload 2"
]
},
{
Expand Down Expand Up @@ -87,8 +85,8 @@
"metadata": {},
"outputs": [],
"source": [
"import {{cookiecutter.project_name}}\n",
"{{cookiecutter.project_name}}.project.data_dir"
"import whisk\n",
"whisk.data_dir"
]
},
{
Expand All @@ -113,14 +111,14 @@
"metadata": {},
"outputs": [],
"source": [
"import whisk\n",
"from whisk.model_stub import ModelStub # A fake model\n",
"# This example uses pickle to serialize a Python object. \n",
"# Use the preferred serialization approach for your ML framework.\n",
"import pickle\n",
"from whisk.model_stub import ModelStub # A fake model\n",
"from {{cookiecutter.project_name}} import project\n",
"\n",
"model = ModelStub()\n",
"file_path = project.artifacts_dir / \"model.pkl\"\n",
"file_path = whisk.artifacts_dir / \"model.pkl\"\n",
"pickle.dump(model, open(file_path,\"wb\"))"
]
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
from os.path import realpath
import whisk
from whisk.project import Project

project = Project.from_module(realpath(__file__))
"""
Initializes the whisk.project attribute so project helpers can be accessed via
whisk.project.*.
"""
whisk.project = Project.from_module(realpath(__file__))
whisk.data_dir = whisk.project.data_dir
whisk.artifacts_dir = whisk.project.artifacts_dir
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import whisk
import pickle
from whisk.model_stub import ModelStub
import {{cookiecutter.project_name}}

class Model:
"""
Expand All @@ -15,15 +14,15 @@ def __init__(self):
Tensorflow example:
self.model = load_model({{cookiecutter.project_name}}.project.artifacts_dir / "model.h5")
self.model = load_model(whisk.artifacts_dir / "model.h5")
Pickle example:
with open({{cookiecutter.project_name}}.project.artifacts_dir / 'tokenizer.pickle', 'rb') as file:
with open(whisk.artifacts_dir / 'tokenizer.pickle', 'rb') as file:
self.tokenizer = pickle.load(file)
"""
# REPLACE ME - add your loading logic
with open({{cookiecutter.project_name}}.project.artifacts_dir / "model.pkl", 'rb') as file:
with open(whisk.artifacts_dir / "model.pkl", 'rb') as file:
self.model = pickle.load(file)

def predict(self,data):
Expand Down
4 changes: 3 additions & 1 deletion whisk/whisk.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ def create(project_name, output_dir=".", setup=None, force=False):
"""
Creates a whisk project.
"""
whisk_version = "whisk>={}".format(whisk.__version__)
# Locks to a specific version as earlier and later versions of whisk could expect a different
# template structure.
whisk_version = "whisk=={}".format(whisk.__version__)
# `whisk_dependency` is more flexible (for example, specifying a local install)
# than `whisk_install_requires` and is used in testing to require the local version of whisk.
extra_content = {
Expand Down

0 comments on commit 197c5c1

Please sign in to comment.