Skip to content

Commit

Permalink
Merge pull request #3 from artste/feat_in_cell_functions_definition
Browse files Browse the repository at this point in the history
functions definitions inside cell
  • Loading branch information
artste committed May 13, 2023
2 parents 2a61b0e + 1075d82 commit 747712c
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 13 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,37 @@ available: + `__builtins__` : built in python’s functions. +
`_test_cell_` : `%%testcell` wrapped function executed (we can’t avoid
this).

``` python
%%testcell
def my_function(x):
print(aaa) # global variable
return x

try:
my_function(123)
except Exception as e:
print(e)
```

global variable

``` python
%%testcelln
def my_function(x):
print(aaa) # global variable
return x

try:
my_function(123)
except Exception as e:
print(e)
```

name 'aaa' is not defined

As you can see from this last example, `%%testcelln` helps you to
identify that `my_function` refers global variable `aaa`.

**IMPORTANT**: this is *just wrapping your cell* and so it’s still
running on your main kernel. If you modify variables that has been
created outside of this cell (aka: if you have side effects) this will
Expand Down
21 changes: 20 additions & 1 deletion nbs/01_ast.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@
"#| export\n",
"def last_node(code):\n",
" tree = ast.parse(code)\n",
" if len(tree.body)==0: return None\n",
" src = tree.body[-1]\n",
" last_node = None\n",
" for node in ast.walk(tree):\n",
" for node in ast.walk(src):\n",
" if isinstance(node, ast.stmt):\n",
" last_node = node\n",
" return last_node"
Expand Down Expand Up @@ -100,6 +102,23 @@
"test_eq(node_source(last_node(sample_code),sample_code), 'c = a+b')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#| test\n",
"sample_code = '''\n",
"def my_function(x):\n",
" print(aaa)\n",
" return x\n",
" \n",
"my_function(123)\n",
"'''\n",
"test_eq(node_source(last_node(sample_code),sample_code), 'my_function(123)')"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down
93 changes: 93 additions & 0 deletions nbs/index.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,99 @@
"+ `_test_cell_` : `%%testcell` wrapped function executed (we can't avoid this)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```python\n",
"%%testcell\n",
"def my_function(x):\n",
" print(aaa) # global variable\n",
" return x\n",
"\n",
"try:\n",
" my_function(123)\n",
"except Exception as e:\n",
" print(e)\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"global variable\n"
]
}
],
"source": [
"%%testcell\n",
"#| echo: false\n",
"def my_function(x):\n",
" print(aaa) # global variable\n",
" return x\n",
"\n",
"try:\n",
" my_function(123)\n",
"except Exception as e:\n",
" print(e)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```python\n",
"%%testcelln\n",
"def my_function(x):\n",
" print(aaa) # global variable\n",
" return x\n",
"\n",
"try:\n",
" my_function(123)\n",
"except Exception as e:\n",
" print(e)\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"name 'aaa' is not defined\n"
]
}
],
"source": [
"%%testcelln\n",
"#| echo: false\n",
"def my_function(x):\n",
" print(aaa) # global variable\n",
" return x\n",
"\n",
"try:\n",
" my_function(123)\n",
"except Exception as e:\n",
" print(e)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see from this last example, `%%testcelln` helps you to identify that `my_function` refers global variable `aaa`."
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down
2 changes: 1 addition & 1 deletion settings.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
### Python library ###
repo = testcell
lib_name = %(repo)s
version = 0.0.3
version = 0.0.4
min_python = 3.7
license = apache2
black_formatting = False
Expand Down
2 changes: 1 addition & 1 deletion testcell/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.0.3"
__version__ = "0.0.4"
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/02_testcell.ipynb.

# %% auto 0
Expand Down
22 changes: 12 additions & 10 deletions testcell/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
# %% ../nbs/01_ast.ipynb 5
def last_node(code):
tree = ast.parse(code)
if len(tree.body)==0: return None
src = tree.body[-1]
last_node = None
for node in ast.walk(tree):
for node in ast.walk(src):
if isinstance(node, ast.stmt):
last_node = node
return last_node
Expand All @@ -20,11 +22,11 @@ def last_node(code):
def node_source(node,code):
return ast.get_source_segment(code,node)

# %% ../nbs/01_ast.ipynb 9
# %% ../nbs/01_ast.ipynb 10
def is_assignment(node):
return isinstance(node, ast.Assign)

# %% ../nbs/01_ast.ipynb 11
# %% ../nbs/01_ast.ipynb 12
def extract_call(node):
if not isinstance(node, ast.Expr): return None
node = node.value # step in
Expand All @@ -35,24 +37,24 @@ def extract_call(node):
if isinstance(n, ast.Attribute): return n.attr
return None # all the rest is not supported

# %% ../nbs/01_ast.ipynb 13
# %% ../nbs/01_ast.ipynb 14
def is_function_call(node,names):
function_name = extract_call(node)
if function_name is None: return False # this is not a function call
return function_name in names

# %% ../nbs/01_ast.ipynb 15
# %% ../nbs/01_ast.ipynb 16
def is_import_statement(node):
return isinstance(node, (ast.Import, ast.ImportFrom))

# %% ../nbs/01_ast.ipynb 17
# %% ../nbs/01_ast.ipynb 18
def need_display(node):
if node is None: return False
if is_function_call(node,names=['print','display']): return False
if is_import_statement(node): return False
return True

# %% ../nbs/01_ast.ipynb 19
# %% ../nbs/01_ast.ipynb 20
def wrap_node(node,function_name):
return ast.Expr(
value=ast.Call(
Expand All @@ -61,21 +63,21 @@ def wrap_node(node,function_name):
keywords=[])
)

# %% ../nbs/01_ast.ipynb 22
# %% ../nbs/01_ast.ipynb 23
def last_statement_has_semicolon(code):
t = [x.strip() for x in code.splitlines()]
t = [x for x in t if not x.startswith('#')]
return t[-1].endswith(';')

# %% ../nbs/01_ast.ipynb 24
# %% ../nbs/01_ast.ipynb 25
def code_till_node(code:str,node):
t = code.splitlines()
t = t[:node.lineno]
t[-1] = t[-1][:node.col_offset]
if len(t[-1])==0: t = t[:-1]
return '\n'.join(t)

# %% ../nbs/01_ast.ipynb 27
# %% ../nbs/01_ast.ipynb 28
def auto_display(code):
if last_statement_has_semicolon(code): return code

Expand Down

0 comments on commit 747712c

Please sign in to comment.