Converts `docment` docstrings to Numpy styled
/mnt/d/jupyter/anaconda3/envs/nbagile/lib/python3.7/site-packages/fastprogress/fastprogress.py:102: UserWarning: Couldn't import ipywidgets properly, progress bar will use console behavior
  warn("Couldn't import ipywidgets properly, progress bar will use console behavior")

The goal of this module is to take code that looks like the following:

def addition(
    a:int, # The first number to add
    b:int=2, # The second number to add
) -> int: # The sum of a and b
    "Adds two numbers together"
    return a+b

And convert it to be the following:

def addition(a,b) -> int:
    """Adds two numbers together
    
    Parameters
    ---------
    a : int
        The first number to add
    b : int
        The second number to add
        
    Returns
    -------
    int
        The sum of a and b
    """
    return a + b

Documentation Strings

Below we have an example string repsentation of the above docments style:

source = '''def addition(
    a:(int, float), # The first number to add
    # The second number to add
    b:int = 2,
) -> (int,float): # The sum of a and b
    "Adds two numbers together"
    return a+b'''

get_annotations[source]

get_annotations(source:str)

Extracts the type annotations from source code

Parameters:

  • source : str

    Source code of function or class

test_eq(get_annotations(source), (['(int, float)', 'int'], '(int, float)'))
test_eq(_get_leading('  Hello my name is Zach'), (2, ' '))

apply[source]

apply(func:callable, x:any, *args, **kwargs)

Apply func recursively to x, passing on args. Originally from fastai.torch_core

Parameters:

  • func : callable

    A callable function

  • x : any

    Something to apply `func` on

  • args : <class 'inspect._empty'>

  • kwargs : <class 'inspect._empty'>

reformat_function[source]

reformat_function(source:str)

Takes messy source code and refactors it into a readable PEP-8 standard style

Parameters:

  • source : str

    Source code

source = """@delegates()
def addition(
    a:(int, float), # The first number to add
    # The second number to add
    b:int = 2,
) -> (int,float): # The sum of a and b
    "Adds two numbers together"
    def _inner(): return a+b
    return _inner()"""
print(source)
@delegates()
def addition(
    a:(int, float), # The first number to add
    # The second number to add
    b:int = 2,
) -> (int,float): # The sum of a and b
    "Adds two numbers together"
    def _inner(): return a+b
    return _inner()
print(reformat_function(source))
@delegates()
def addition(a:(int, float), b:int=2):
    """Adds two numbers together

    Parameters
    ----------
    a : (int, float)
      The first number to add
    b : int
      The second number to add

    Returns
    -------
    (int, float)
      The sum of a and b
    """

    def _inner():
        return (a + b)
    return _inner()

reformat_class[source]

reformat_class(source:str, recursion_level:int=1)

Takes messy class code and refactors it into a readable PEP-8 standard style

Parameters:

  • source : str

    Source code of a full class

  • recursion_level : int, optional

    Depth of recursion

source = '''class Arithmetic:
    "A class that can perform basic arithmetic on ops"
    _o = 2
    _b = 5
    
    _c = 3
    
    class A:
        def __init__(
          self, 
          o:int # An integer
        ):
            self.o = o
    
    def __init__(
        self,
        a:int, # The first number to use
        b:(int, float), # The second number to use
    ):
        self.a = a
        self.b = b
        
    @delegates()
    def add(
        self
    ) -> (int,float): # Sum of a and b
        "Adds self.a and self.b"
        return self.a + self.b'''
print(reformat_class(source))
class Arithmetic():
    """A class that can perform basic arithmetic on ops"""
    _o = 2
    _b = 5
    _c = 3
    class A():
        def __init__(self, o:int):
            """
            Parameters
            ----------
            o : int
              An integer
            """
            self.o = o
        
    def __init__(self, a:int, b:(int, float)):
        """
        Parameters
        ----------
        a : int
          The first number to use
        b : (int, float)
          The second number to use
        """
        self.a = a
        self.b = b
    
    @delegates()
    def add(self):
        """Adds self.a and self.b
    
        Returns
        -------
        (int, float)
          Sum of a and b
        """
        return (self.a + self.b)
    
multiple_funcs = '''from fastai.vision.all import *

import numpy as np

class Arithmetic:
    "A class that can perform basic arithmetic on ops"
    _o = 2
    _b = 5
    
    _c = 3
    
    class A:
        def __init__(
          self, 
          o:int # An integer
        ):
            self.o = o
    
    def __init__(
        self,
        a:int, # The first number to use
        b:(int, float), # The second number to use
    ):
        self.a = a
        self.b = b
        
    @delegates()
    def add(
        self
    ) -> (int,float): # Sum of a and b
        "Adds self.a and self.b"
        return self.a + self.b

def foo(
    a:int, # First
    b:int, # Second
) -> (int, float): # Sum of a and b
    "Adds"
    return a+b
    
def baz(
    a:int, # First
    b:int, # Second
) -> (int, float): # Difference of a and b
    "Subtracts"
    return a-b
    
myConst = 22

def bar(
    a:int, # First
    b:int, # Second
) -> (int, float): # Product of a and b
    "Multiplies"
    return a*b'''

Cleaning and Transforming Files

Given the above's usage of AST trees to rebuild your code, it automatically looks very similar to something that would come out of a code formatter, such as Black or Flake8. However, we still need to convert individual files, not just handling certain capabilities.

This is what the below functionality does

clean_file[source]

clean_file(fname:(Path, str), use_all:bool)

Cleans an individual file from docment-style annotation to numpy-style

Parameters:

  • fname : (Path, str)

    The location of a filename to clean

  • use_all : bool

    Whether to add a '__all__' to the file

nbagile_build_lib[source]

nbagile_build_lib()

Export notebooks matching fname to python modules

nbagile_build_docs[source]

nbagile_build_docs()

Builds documentation from notebooks

nbagile_diff_nbs[source]

nbagile_diff_nbs()

Prints the diff between an export of the library in notebooks and the actual modules