= TmpDir() tmpdir
core
TmpDir
TmpDir ()
Create temporary workspaces.
The main way to use TmpDir
is through the exported object:
We start out in our project dir:
= Path.cwd(); d0 d0
Path('/Users/seem/code/sketch-tmpdir')
Switch to path foo/bar
under a temp dir:
'foo/bar')
tmpdir.new(= tmpdir.dir
d1 Path.cwd()
Path('/private/var/folders/ft/0gnvc3ts5jz4ddqtttp6tjvm0000gn/T/tmp19y8l0h4/foo/bar')
If we switch again, the previous dir is removed:
'foo/bar')
tmpdir.new(assert not d1.exists()
= tmpdir.dir
d2 Path.cwd()
Path('/private/var/folders/ft/0gnvc3ts5jz4ddqtttp6tjvm0000gn/T/tmpnjqprlft/foo/bar')
Finally, revert to the original working directory, which also removes the remaining temporary directory:
tmpdir.close()assert not d2.exists()
test_eq(Path.cwd(), d0)
You can also use it as a context manager to automatically revert to the original working directory at the end:
with tmpdir() as p:
= tmpdir.dir
d3
test_eq(Path.cwd().name, p.name)assert not d3.exists()
test_eq(Path.cwd(), d0)
The primary use-case is to write executable documentation for code that interacts with its workspace, as described in the examples below.
Example 1: Python git interface
def git_repo():
"Remote repo from git config."
= 'git config --get remote.origin.url'
cmd = subprocess.run(cmd, shell=True, capture_output=True, text=True)
proc if proc.returncode: return
return proc.stdout.strip().split('/', 1)[1].split('.')[0]
Let’s initialise a minimal repo to demonstrate:
tmpdir.new()
git init -q
git remote add origin git@github.com:my-user/my-repo.git
Get the repo name:
'my-repo') test_eq(git_repo(),
Returns None
if you’re not in a git repo:
with tmpdir(): test_is(git_repo(), None)
And you’re back to your original working directory:
Path.cwd()
Path('/Users/seem/code/sketch-tmpdir')
Example 2: nbdev hooks
This section shows what the end-to-end nbdev hooks test could look like with tmpdir
. The test checks that nbdev’s notebook-aware merge driver works. In order to do that we need to simulate a merge conflict, which involves some back-and-forth with git.
from copy import deepcopy
from execnb.nbio import dict2nb, mk_cell, read_nb, write_nb
from fastcore.foundation import Config
from nbdev.read import create_output, show_src
Start a new workspace:
tmpdir.new()
Init a git repo and checkout our main branch – this is where we’ll run our tests:
git init
Initialized empty Git repository in /private/var/folders/ft/0gnvc3ts5jz4ddqtttp6tjvm0000gn/T/tmpggvpu_sy/.git/
git checkout -b main
Switched to a new branch 'main'
Install nbdev hooks:
nbdev_install_hooks
Hooks are installed.
Next, we’ll simulate a merge conflict. First we add random.ipynb
notebook to main
. Here’s what it looks like to start with:
= 'random.ipynb'
fn = {'nbformat': 4,'metadata':{'kernelspec':{'display_name':'Python 3','language': 'python','name': 'python3'}}}
meta = dict2nb({'cells':[mk_cell('import random'), mk_cell('random.random()')], **meta})
base -1].output = create_output('0.3314001088639852\n0.20280244713400464', 'plain')
base.cells[
write_nb(base, fn) show_nb(fn)
# random.ipynb
# %%
import random
# %%
random.random()# 0.3314001088639852
# 0.20280244713400464
Commit it:
git add .
git commit -q -m 'add random.ipynb'
Next, checkout a new branch add-heading
:
git checkout -b add-heading
Switched to a new branch 'add-heading'
Make a change. We added a new markdown cell Calculate a random number:
, imported os
, and got different random.random()
outputs – the perfect recipe for a merge conflict:
= deepcopy(base)
ours 0].source+=',os' # Change first cell
ours.cells[1, mk_cell('Calculate a random number:', cell_type='markdown')) # New cell
ours.cells.insert(-1].output = create_output('0.3379097372590093\n0.7379492349993123', 'plain') # Change outputs
ours.cells[
write_nb(ours, fn) show_nb(fn)
# random.ipynb
# %%
import random,os
# %%
Calculate a random number:
# %%
random.random()# 0.3379097372590093
# 0.7379492349993123
Commit it:
git commit -am heading
[add-heading 5b71b21] heading
1 file changed, 10 insertions(+), 3 deletions(-)
Go back to main:
git checkout main
Switched to branch 'main'
Make a different change:
show_nb(fn)
# random.ipynb
# %%
# Random numbers
# %%
import random,sys
# %%
random.random()# 0.6587181429602441
# 0.5962200692415515
Commit it:
git commit -am docs
[main d3b0252] docs
1 file changed, 10 insertions(+), 3 deletions(-)
And finally try to merge:
-heading git merge add
One or more conflict remains in the notebook, please inspect manually.
Auto-merging random.ipynb
CONFLICT (content): Merge conflict in random.ipynb
Automatic merge failed; fix conflicts and then commit the result.
We have a merge conflict! But thanks to nbdev:
- Conflicting outputs are automatically resolved
- The notebook is left in a readable state.
show_nb(fn)
# random.ipynb
# %%
# Random numbers
# %%
<<<<<<< HEAD`
`
# %%
import random,sys
# %%
=======`
`
# %%
import random,os
# %%
Calculate a random number:
# %%
>>>>>>> add-heading`
`
# %%
random.random()# 0.6587181429602441
# 0.5962200692415515
Close tmpdir
, and you’re back to your original working directory:
tmpdir.close() Path.cwd()