Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions py2nb.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
# Comment syntax patterns
CELL_SPLIT_CHARS = ['#-', '# -']
MARKDOWN_CHARS = ['#|', '# |']
COMMAND_CHARS = ['#!', '# !']
COMMAND_CHARS = ['#!', '# !', '#%', '# %']
ACCEPTED_CHARS = CELL_SPLIT_CHARS + MARKDOWN_CHARS + COMMAND_CHARS

def new_cell(nb, cell_content, cell_type='code'):
Expand Down Expand Up @@ -90,8 +90,11 @@ def get_comment_type(line):
def extract_content(line, comment_type):
"""Extract content from comment line based on type."""
if comment_type == 'command':
# Find first ! and return ! plus everything after it
return '!' + line[line.index('!') + 1:].lstrip()
# Find first ! or % and return the command marker plus everything after it
if '!' in line:
return '!' + line[line.index('!') + 1:].lstrip()
elif '%' in line:
return '%' + line[line.index('%') + 1:].lstrip()
elif comment_type == 'markdown':
# Find first | and return everything after it
return line[line.index('|') + 1:]
Expand Down
69 changes: 69 additions & 0 deletions test_py2nb.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,69 @@ def test_command_blocks(self):
self.assertIn('command', command_cell.get('metadata', {}).get('tags', []))
self.assertIn('!pip install numpy', ''.join(command_cell['source']))

def test_percent_command_blocks(self):
"""Test command block creation with #% syntax."""
script_content = """#| # Test Percent Magic Commands

#% matplotlib inline
#% load_ext autoreload
#% autoreload 2

import numpy as np
import matplotlib.pyplot as plt"""

script_path = self.create_test_script(script_content)
notebook_path = py2nb.convert(script_path)

with open(notebook_path, 'r') as f:
nb = json.load(f)

# Should have: markdown, command, code cells
self.assertEqual(len(nb['cells']), 3)
self.assertEqual(nb['cells'][0]['cell_type'], 'markdown')
self.assertEqual(nb['cells'][1]['cell_type'], 'code')
self.assertEqual(nb['cells'][2]['cell_type'], 'code')

# Check command cell has command tag
command_cell = nb['cells'][1]
self.assertIn('command', command_cell.get('metadata', {}).get('tags', []))
self.assertIn('%matplotlib inline', ''.join(command_cell['source']))
self.assertIn('%load_ext autoreload', ''.join(command_cell['source']))

def test_mixed_command_types(self):
"""Test mixing #! and #% command types."""
script_content = """#| # Mixed Command Types Test

#! pip install numpy
#% matplotlib inline
#% load_ext autoreload
#! pip install matplotlib
#% autoreload 2

import numpy as np"""

script_path = self.create_test_script(script_content)
notebook_path = py2nb.convert(script_path)

with open(notebook_path, 'r') as f:
nb = json.load(f)

# Should have: markdown, command, code cells
self.assertEqual(len(nb['cells']), 3)
self.assertEqual(nb['cells'][0]['cell_type'], 'markdown')
self.assertEqual(nb['cells'][1]['cell_type'], 'code')
self.assertEqual(nb['cells'][2]['cell_type'], 'code')

# Check command cell contains both ! and % commands
command_cell = nb['cells'][1]
self.assertIn('command', command_cell.get('metadata', {}).get('tags', []))
command_source = ''.join(command_cell['source'])
self.assertIn('!pip install numpy', command_source)
self.assertIn('%matplotlib inline', command_source)
self.assertIn('%load_ext autoreload', command_source)
self.assertIn('!pip install matplotlib', command_source)
self.assertIn('%autoreload 2', command_source)

def test_cell_splits(self):
"""Test code cell splitting with #- syntax."""
script_content = """x = 1
Expand All @@ -125,6 +188,7 @@ def test_mixed_syntax(self):
#| This tests all comment types together

#! pip install numpy
#% matplotlib inline

import numpy as np

Expand All @@ -135,6 +199,7 @@ def test_mixed_syntax(self):
#-

#! pip install matplotlib
#% load_ext autoreload

import matplotlib.pyplot as plt
plt.plot(x)"""
Expand Down Expand Up @@ -206,6 +271,8 @@ def test_comment_type_detection(self):
self.assertEqual(py2nb.get_comment_type('# | markdown'), 'markdown')
self.assertEqual(py2nb.get_comment_type('#! install'), 'command')
self.assertEqual(py2nb.get_comment_type('# ! install'), 'command')
self.assertEqual(py2nb.get_comment_type('#% magic'), 'command')
self.assertEqual(py2nb.get_comment_type('# % magic'), 'command')
self.assertEqual(py2nb.get_comment_type('#- split'), 'split')
self.assertEqual(py2nb.get_comment_type('# - split'), 'split')
self.assertIsNone(py2nb.get_comment_type('# regular comment'))
Expand All @@ -214,7 +281,9 @@ def test_content_extraction(self):
"""Test content extraction from comment lines."""
self.assertEqual(py2nb.extract_content('#| markdown text', 'markdown'), ' markdown text')
self.assertEqual(py2nb.extract_content('#! pip install numpy', 'command'), '!pip install numpy')
self.assertEqual(py2nb.extract_content('#% matplotlib inline', 'command'), '%matplotlib inline')
self.assertEqual(py2nb.extract_content('# | spaced markdown', 'markdown'), ' spaced markdown')
self.assertEqual(py2nb.extract_content('# % config InlineBackend', 'command'), '%config InlineBackend')

def test_file_not_found(self):
"""Test handling of non-existent files."""
Expand Down