Dependency Management with PyDoit
Authors
Setup
Import Libraries
from doit import load_ipython_extension
load_ipython_extension()Download Data
import os
import owncloud
# Ensure the 'data' directory exists
if not os.path.exists('data'):
print('Creating directory for data')
os.mkdir('data')
# Ensure the 'notebooks' directory exists
if not os.path.exists('nb_active_trials.ipynb'):
print('Creating directory for notebooks')
os.mkdir('notebooks')
# Download steinmetz_all.csv
if not os.path.exists('data/steinmetz_all.csv'):
oc = owncloud.Client.from_public_link('https://uni-bonn.sciebo.de/s/CE4fcAAr3HE4naE', folder_password="ibots"
)
oc.get_file('/', 'data/steinmetz_all.csv')
# Download nb_active_trials.ipynb
if not os.path.exists('nb_active_trials.ipynb'):
oc = owncloud.Client.from_public_link('https://uni-bonn.sciebo.de/s/pJY34rKDq29E6EC', folder_password="ibots"
)
oc.get_file('/', 'nb_active_trials.ipynb')
# Download nb_stats.ipynb
if not os.path.exists('nb_stats.ipynb'):
oc = owncloud.Client.from_public_link('https://uni-bonn.sciebo.de/s/X8FjRFFmTRNa7zj', folder_password="ibots"
)
oc.get_file('/', 'nb_stats.ipynb')
# Download nb_plots.ipynb
if not os.path.exists('nb_plots.ipynb'):
oc = owncloud.Client.from_public_link('https://uni-bonn.sciebo.de/s/gJ8rPRtKqMQXfZg', folder_password="ibots"
)
oc.get_file('/', 'nb_plots.ipynb')In Pydoit, dependency management is a core feature that ensures tasks are executed only when necessary. Dependencies can be files, task results, or parameters, and Pydoit will automatically skip tasks if none of their dependencies have changed.
Section 1: File Dependency
In pydoit, file dependencies (file_dep) specify which files a task depends on to complete its action. A task will be executed only if one or more of its dependencies have changed since the last time the task ran. If none of the files have been modified, pydoit will skip the task.
def task_name():
return {
'actions': ['command to execute'],
'file_dep': ['file_name']
}Exercises
Example: Make process depend on file data/steinmetz_all.csv and run %doit.
def task_process():
return {
'actions': ['papermill nb_active_trials.ipynb process.ipynb']
}def task_process():
return {
'actions': ['papermill nb_active_trials.ipynb process.ipynb'],
'file_dep': ['data/steinmetz_all.csv']
}%doit processExercise: Run process again. What difference do you notice?
Solution
%doit processExample: Make stats depend on file data/active_trials.csv and run %doit.
def task_stats():
return {
'actions': ['papermill nb_stats.ipynb stats.ipynb']
}Solution
def task_stats():
return {
'actions': ['papermill nb_stats.ipynb stats.ipynb'],
'file_dep': ['data/active_trials.csv']
}%doit statsExercise: Run stats again. What do you see?
Solution
%doit statsExercise: Make plot depend on file data/active_trials.csv and run %doit.
def task_plot():
return {
'actions': ['papermill nb_plots.ipynb plots.ipynb']
}Solution
def task_plot():
return {
'actions': ['papermill nb_plots.ipynb plots.ipynb'],
'file_dep': ['data/active_trials.csv']
}%doit plotExercise: Run %doit again. What do you see?
Solution
%doit plotSection 2: Targets
In pydoit, targets (targets) specify the output files that a task is expected to create. The task will only run if the target files are missing or outdated based on file dependencies. Here’s how you can define the targets for each of your tasks
def task_name():
return {
'actions': ['command to execute'],
'file_dep': ['file_name'],
'targets': ['target_file_name']
}Exercises
Example: Make process task depend on its output data/active_trials.csv
def task_process():
return {
'actions': ['papermill nb_active_trials.ipynb process.ipynb'],
'file_dep': ['data/steinmetz_all.csv'],
'targets': ['data/active_trials.csv']
}%doit processExercise: Run process task again. Does it run?
Solution
%doit processDelete active_trials.csv file only which is the target of process task and run it again. Does it run now?
%doit processExercise: Make stats task depend on its output data/stats.csv. What do you see is happening here?
Solution
def task_stats():
return {
'actions': ['papermill nb_stats.ipynb stats.ipynb'],
'file_dep': ['data/active_trials.csv'],
'targets': ['data/stats.csv']
}%doit statsExercise: Run stats task again. What do you see?
Solution
%doit statsExercise: Delete stats.csv and run stats task again.
Solution
%doit statsExercise: Delete active_trials.csv and run stats process. What happened now?
Solution
%doit statsExercise: Make plot task depend on its output response_time_histogram.png.
Solution
def task_plot():
return {
'actions': ['papermill nb_plots.ipynb plots.ipynb'],
'file_dep': ['data/active_trials.csv'],
'targets': ['response_time_histogram.png']
}%doit plotExercise: Delete response_time_histogram.png and run plot task again.
Solution
%doit plotSection 3: Adding papermill output notebooks as targets
We can also add the output notebooks from papermill executions as targets since they are generated by the tasks.
Exercises
Example: Make process depend on its output process.ipynb and data/active_trials.csv
def task_process():
return {
'actions': ['papermill nb_active_trials.ipynb process.ipynb'],
'file_dep': ['data/steinmetz_all.csv'],
'targets': ['data/active_trials.csv', 'process.ipynb']
}Exercise: Make stats depend on its output stats.ipynb and data/stats.csv
Solution
def task_stats():
return {
'actions': ['papermill nb_stats.ipynb stats.ipynb'],
'file_dep': ['data/active_trials.csv'],
'targets': ['data/stats.csv', 'stats.ipynb']
}Exercise: Make stats depend on its output plots.ipynb and response_time_histogram.png
Solution
def task_plot():
return {
'actions': ['papermill nb_plots.ipynb plots.ipynb'],
'file_dep': ['data/active_trials.csv'],
'targets': ['response_time_histogram.png', 'plots.ipynb']
}