# maker


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Helpers

## Variable helpers

These functions let us find and modify the definitions of variables in
Python modules.

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L27"
target="_blank" style="float:right; font-size:smaller">source</a>

### find_var

``` python

def find_var(
    lines, varname
):

```

*Find the line numbers where `varname` is defined in `lines`*

``` python
t = '''a_=(1,
  2,
  3)

b_=3'''
test_eq(find_var(t.splitlines(), 'a_'), (0,3))
test_eq(find_var(t.splitlines(), 'b_'), (4,5))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L37"
target="_blank" style="float:right; font-size:smaller">source</a>

### read_var

``` python

def read_var(
    code, varname
):

```

*Eval and return the value of `varname` defined in `code`*

``` python
test_eq(read_var(t, 'a_'), (1,2,3))
test_eq(read_var(t, 'b_'), 3)
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L48"
target="_blank" style="float:right; font-size:smaller">source</a>

### update_var

``` python

def update_var(
    varname, func, fn:NoneType=None, code:NoneType=None
):

```

*Update the definition of `varname` in file `fn`, by calling `func` with
the current definition*

``` python
g = exec_new(t)
test_eq((g['a_'],g['b_']), ((1,2,3),3))
t2 = update_var('a_', lambda o:0, code=t)
exec(t2, g)
test_eq((g['a_'],g['b_']), (0,3))
t3 = update_var('b_', lambda o:0, code=t)
exec(t3, g)
test_eq((g['a_'],g['b_']), ((1,2,3),0))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L64"
target="_blank" style="float:right; font-size:smaller">source</a>

### ModuleMaker

``` python

def ModuleMaker(
    dest, name, nb_path, is_new:bool=True, parse:bool=True, solo_nb:bool=False
):

```

*Helper class to create exported library from notebook source cells*

In order to export a notebook, we need an way to create a Python file.
[`ModuleMaker`](https://nbdev.fast.ai/api/maker.html#modulemaker) fills
that role. Pass in the directory where you want to module created, the
name of the module, the path of the notebook source, and set `is_new` to
`True` if this is a new file being created (rather than an existing file
being added to). The location of the saved module will be in `fname`.
Finally, if the source in the notebooks should not be parsed by Python
(such as partial class declarations in cells), `parse` should be set to
`False`.

> Note: If doing so, then the `__all__` generation will be turned off as
> well.

``` python
mm = ModuleMaker(dest='tmp', name='test.testing', nb_path=Path.cwd()/'04_export.ipynb', is_new=True)
mm.fname
```

    Path('tmp/test/testing.py')

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L76"
target="_blank" style="float:right; font-size:smaller">source</a>

### decor_id

``` python

def decor_id(
    d
):

```

*`id` attr of decorator, regardless of whether called as function or
bare*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L95"
target="_blank" style="float:right; font-size:smaller">source</a>

### ModuleMaker.make_all

``` python

def make_all(
    cells
):

```

*Create `__all__` with all exports in `cells`*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L111"
target="_blank" style="float:right; font-size:smaller">source</a>

### make_code_cells

``` python

def make_code_cells(
    ss:VAR_POSITIONAL
):

```

*Call self as a function.*

We want to add an `__all__` to the top of the exported module. This
methods autogenerates it from all code in `cells`.

``` python
nb = make_code_cells("from __future__ import print_function", "def a():...", "def b():...",
                      "c=d=1", "_f=1", "_g=1", "_h=1", "_all_=['_g', _h]", "@patch\ndef h(self:ca):...")
test_eq(set(mm.make_all(nb)), set(['a','b','c','d', '_g', '_h']))
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L114"
target="_blank" style="float:right; font-size:smaller">source</a>

### relative_import

``` python

def relative_import(
    name, fname, level:int=0
):

```

*Convert a module `name` to a name relative to `fname`*

``` python
test_eq(relative_import('nbdev.core', "xyz"), 'nbdev.core')
test_eq(relative_import('nbdev.core', 'nbdev'), '.core')
_p = Path('fastai')
test_eq(relative_import('fastai.core', _p/'vision'), '..core')
test_eq(relative_import('fastai.core', _p/'vision/transform'), '...core')
test_eq(relative_import('fastai.vision.transform', _p/'vision'), '.transform')
test_eq(relative_import('fastai.notebook.core', _p/'data'), '..notebook.core')
test_eq(relative_import('fastai.vision', _p/'vision'), '.')
test_eq(relative_import('fastai', _p), '.')
test_eq(relative_import('fastai', _p/'vision'), '..')
test_eq(relative_import('fastai', _p/'vision/transform'), '...')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L159"
target="_blank" style="float:right; font-size:smaller">source</a>

### NbCell.import2relative

``` python

def import2relative(
    cell:NbCell, libname
):

```

*Call self as a function.*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L144"
target="_blank" style="float:right; font-size:smaller">source</a>

### update_import

``` python

def update_import(
    source, tree, libname, f:function=relative_import
):

```

*Call self as a function.*

``` python
ss = "from nbdev.export import *\nfrom nbdev.a.b import *"
cell = make_code_cells([ss])[0]
cell.import2relative('nbdev')
test_eq(cell.source, 'from .export import *\nfrom .a.b import *')

cell = make_code_cells([ss])[0]
cell.import2relative('nbdev/a')
test_eq(cell.source, 'from ..export import *\nfrom .b import *')
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/nbdev/blob/main/nbdev/maker.py#L194"
target="_blank" style="float:right; font-size:smaller">source</a>

### ModuleMaker.make

``` python

def make(
    cells, all_cells:NoneType=None, lib_path:NoneType=None
):

```

*Write module containing `cells` with `__all__` generated from
`all_cells`*

``` python
cells = make_code_cells("from __future__ import print_function",
                        "#| export\ndef a(): ...", "def b(): ...")
mm.make(cells, L([cells[2]]))
show_src(Path('tmp/test/testing.py').read_text(encoding='utf-8'))
```

<div class="prose" markdown="1">

``` python
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../04_export.ipynb.

# %% ../../04_export.ipynb #dec4cd88
from __future__ import print_function

# %% auto #0
__all__ = ['b']

# %% ../../04_export.ipynb #b2a73a89
#| export
def a(): ...

# %% ../../04_export.ipynb #470e0aea
def b(): ...
```

</div>

Pass `all_cells=[]` or `parse=False` if you don’t want any `__all__`
added.

Passing `parse=False` is also handy for when writing broken up functions
or classes that
[`ast.parse`](https://docs.python.org/3/library/ast.html#ast.parse)
might not like but still want it to be exported, such as having a cell
with:

``` python
#| export
class A:
```

Note that by doing so we cannot properly generate a `__all__`, so we
assume that it is unwanted.

``` python
am = ModuleMaker(dest='tmp', name='test.testing_noall', nb_path=Path.cwd()/'01_export.ipynb', is_new=True, parse=False)
am.fname
```

    Path('tmp/test/testing_noall.py')

``` python
cells = make_code_cells("from __future__ import print_function", "#| export\ndef a(): ...", "#| export\nclass A:")
am.make(cells)
show_src(Path('tmp/test/testing_noall.py').read_text(encoding='utf-8'))
```

<div class="prose" markdown="1">

``` python
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../01_export.ipynb.

# %% ../../01_export.ipynb #65e15f2e
from __future__ import print_function

# %% ../../01_export.ipynb #1e9ea7e8
#| export
def a(): ...

# %% ../../01_export.ipynb #d73c328f
#| export
class A:
```

</div>

If `is_new=False` then the additional definitions are added to the
bottom, and any existing `__all__` is updated with the newly-added
symbols.

``` python
c2 = make_code_cells("def c(): ...", "def d(): ...")
mm = ModuleMaker(dest='tmp', name='test.testing', nb_path=Path.cwd()/'04_export.ipynb', is_new=False)
mm.make(c2, c2)
```

``` python
show_src(Path('tmp/test/testing.py').read_text(encoding='utf-8'))
```

<div class="prose" markdown="1">

``` python
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../04_export.ipynb.

# %% ../../04_export.ipynb #dec4cd88
from __future__ import print_function

# %% auto #0
__all__ = ['b', 'c', 'd']

# %% ../../04_export.ipynb #b2a73a89
#| export
def a(): ...

# %% ../../04_export.ipynb #470e0aea
def b(): ...

# %% ../../04_export.ipynb #4e1e1d2e
def c(): ...

# %% ../../04_export.ipynb #7199ab8d
def d(): ...
```

</div>

``` python
try:
    sys.path.append('')
    g = exec_import('tmp.test.testing', '*')
    sys.path.pop()
    for s in "b c d".split(): assert s in g, s
    assert 'a' not in g
    assert g['b']() is None
finally: shutil.rmtree('tmp')
```
