diff --git a/IPython/core/magics/code.py b/IPython/core/magics/code.py index a865d68..4c1a40f 100644 --- a/IPython/core/magics/code.py +++ b/IPython/core/magics/code.py @@ -138,6 +138,36 @@ def extract_symbols(code, symbols): return blocks, not_found +def strip_initial_indent(lines): + """For %load, strip indent from lines until finding an unindented line. + + https://github.com/ipython/ipython/issues/9775 + """ + indent_re = re.compile(r'\s+') + + it = iter(lines) + first_line = next(it) + indent_match = indent_re.match(first_line) + + if indent_match: + # First line was indented + indent = indent_match.group() + yield first_line[len(indent):] + + for line in it: + if line.startswith(indent): + yield line[len(indent):] + else: + # Less indented than the first line - stop dedenting + yield line + break + else: + yield first_line + + # Pass the remaining lines through without dedenting + for line in it: + yield line + class InteractivelyDefined(Exception): """Exception for interactively defined variable in magic_edit""" @@ -341,7 +371,7 @@ class CodeMagics(Magics): lines = contents.split('\n') slices = extract_code_ranges(ranges) contents = [lines[slice(*slc)] for slc in slices] - contents = '\n'.join(chain.from_iterable(contents)) + contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents))) l = len(contents) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 17af507..4ac7744 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -1000,3 +1000,12 @@ def test_ls_magic(): j = json_formatter(lsmagic) nt.assert_equal(sorted(j), ['cell', 'line']) nt.assert_equal(w, []) # no warnings + +def test_strip_initial_indent(): + def sii(s): + lines = s.splitlines() + return '\n'.join(code.strip_initial_indent(lines)) + + nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2") + nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc") + nt.assert_equal(sii("a\n b\n"), "a\n b\n")