Format: text/x-python
⬇ Download File (45.3 KB)
   1  # -*- coding: utf-8 -*-
   2  """Tests for various magic functions."""
   3  
   4  import gc
   5  import io
   6  import os
   7  import re
   8  import shlex
   9  import signal
  10  import sys
  11  import warnings
  12  from importlib import invalidate_caches
  13  from io import StringIO
  14  from pathlib import Path
  15  from time import sleep
  16  from threading import Thread
  17  from subprocess import CalledProcessError
  18  from textwrap import dedent
  19  from time import sleep
  20  from threading import Thread
  21  from unittest import TestCase, mock
  22  
  23  import pytest
  24  
  25  from IPython import get_ipython
  26  from IPython.core import magic
  27  from IPython.core.error import UsageError
  28  from IPython.core.magic import (
  29      Magics,
  30      cell_magic,
  31      line_magic,
  32      magics_class,
  33      register_cell_magic,
  34      register_line_magic,
  35  )
  36  from IPython.core.magics import code, execution, logging, osm, script
  37  from IPython.testing import decorators as dec
  38  from IPython.testing import tools as tt
  39  from IPython.utils.io import capture_output
  40  from IPython.utils.process import find_cmd
  41  from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
  42  from IPython.utils.syspathcontext import prepended_to_syspath
  43  
  44  from .test_debugger import PdbTestInput
  45  
  46  from tempfile import NamedTemporaryFile
  47  
  48  @magic.magics_class
  49  class DummyMagics(magic.Magics): pass
  50  
  51  def test_extract_code_ranges():
  52      instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
  53      expected = [
  54          (0, 1),
  55          (2, 3),
  56          (4, 6),
  57          (6, 9),
  58          (9, 14),
  59          (16, None),
  60          (None, 9),
  61          (9, None),
  62          (None, 13),
  63          (None, None),
  64      ]
  65      actual = list(code.extract_code_ranges(instr))
  66      assert actual == expected
  67  
  68  def test_extract_symbols():
  69      source = """import foo\na = 10\ndef b():\n    return 42\n\n\nclass A: pass\n\n\n"""
  70      symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
  71      expected = [([], ['a']),
  72                  (["def b():\n    return 42\n"], []),
  73                  (["class A: pass\n"], []),
  74                  (["class A: pass\n", "def b():\n    return 42\n"], []),
  75                  (["class A: pass\n"], ['a']),
  76                  ([], ['z'])]
  77      for symbols, exp in zip(symbols_args, expected):
  78          assert code.extract_symbols(source, symbols) == exp
  79  
  80  
  81  def test_extract_symbols_raises_exception_with_non_python_code():
  82      source = ("=begin A Ruby program :)=end\n"
  83                "def hello\n"
  84                "puts 'Hello world'\n"
  85                "end")
  86      with pytest.raises(SyntaxError):
  87          code.extract_symbols(source, "hello")
  88  
  89  
  90  def test_magic_not_found():
  91      # magic not found raises UsageError
  92      with pytest.raises(UsageError):
  93          _ip.run_line_magic("doesntexist", "")
  94  
  95      # ensure result isn't success when a magic isn't found
  96      result = _ip.run_cell('%doesntexist')
  97      assert isinstance(result.error_in_exec, UsageError)
  98  
  99  
 100  def test_cell_magic_not_found():
 101      # magic not found raises UsageError
 102      with pytest.raises(UsageError):
 103          _ip.run_cell_magic('doesntexist', 'line', 'cell')
 104  
 105      # ensure result isn't success when a magic isn't found
 106      result = _ip.run_cell('%%doesntexist')
 107      assert isinstance(result.error_in_exec, UsageError)
 108  
 109  
 110  def test_magic_error_status():
 111      def fail(shell):
 112          1/0
 113      _ip.register_magic_function(fail)
 114      result = _ip.run_cell('%fail')
 115      assert isinstance(result.error_in_exec, ZeroDivisionError)
 116  
 117  
 118  def test_config():
 119      """ test that config magic does not raise
 120      can happen if Configurable init is moved too early into
 121      Magics.__init__ as then a Config object will be registered as a
 122      magic.
 123      """
 124      ## should not raise.
 125      _ip.run_line_magic("config", "")
 126  
 127  
 128  def test_config_available_configs():
 129      """ test that config magic prints available configs in unique and
 130      sorted order. """
 131      with capture_output() as captured:
 132          _ip.run_line_magic("config", "")
 133  
 134      stdout = captured.stdout
 135      config_classes = stdout.strip().split('\n')[1:]
 136      assert config_classes == sorted(set(config_classes))
 137  
 138  def test_config_print_class():
 139      """ test that config with a classname prints the class's options. """
 140      with capture_output() as captured:
 141          _ip.run_line_magic("config", "TerminalInteractiveShell")
 142  
 143      stdout = captured.stdout
 144      assert re.match(
 145          "TerminalInteractiveShell.* options", stdout.splitlines()[0]
 146      ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
 147  
 148  
 149  def test_rehashx():
 150      # clear up everything
 151      _ip.alias_manager.clear_aliases()
 152      del _ip.db['syscmdlist']
 153  
 154      _ip.run_line_magic("rehashx", "")
 155      # Practically ALL ipython development systems will have more than 10 aliases
 156  
 157      assert len(_ip.alias_manager.aliases) > 10
 158      for name, cmd in _ip.alias_manager.aliases:
 159          # we must strip dots from alias names
 160          assert "." not in name
 161  
 162      # rehashx must fill up syscmdlist
 163      scoms = _ip.db['syscmdlist']
 164      assert len(scoms) > 10
 165  
 166  
 167  def test_magic_parse_options():
 168      """Test that we don't mangle paths when parsing magic options."""
 169      ip = get_ipython()
 170      path = 'c:\\x'
 171      m = DummyMagics(ip)
 172      opts = m.parse_options('-f %s' % path,'f:')[0]
 173      # argv splitting is os-dependent
 174      if os.name == 'posix':
 175          expected = 'c:x'
 176      else:
 177          expected = path
 178      assert opts["f"] == expected
 179  
 180  
 181  def test_magic_parse_long_options():
 182      """Magic.parse_options can handle --foo=bar long options"""
 183      ip = get_ipython()
 184      m = DummyMagics(ip)
 185      opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
 186      assert "foo" in opts
 187      assert "bar" in opts
 188      assert opts["bar"] == "bubble"
 189  
 190  
 191  def doctest_hist_f():
 192      """Test %hist -f with temporary filename.
 193  
 194      In [9]: import tempfile
 195  
 196      In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
 197  
 198      In [11]: %hist -nl -f $tfile 3
 199  
 200      In [13]: import os; os.unlink(tfile)
 201      """
 202  
 203  
 204  def doctest_hist_op():
 205      """Test %hist -op
 206  
 207      In [1]: class b(float):
 208         ...:     pass
 209         ...:
 210  
 211      In [2]: class s(object):
 212         ...:     def __str__(self):
 213         ...:         return 's'
 214         ...:
 215  
 216      In [3]:
 217  
 218      In [4]: class r(b):
 219         ...:     def __repr__(self):
 220         ...:         return 'r'
 221         ...:
 222  
 223      In [5]: class sr(s,r): pass
 224         ...:
 225  
 226      In [6]:
 227  
 228      In [7]: bb=b()
 229  
 230      In [8]: ss=s()
 231  
 232      In [9]: rr=r()
 233  
 234      In [10]: ssrr=sr()
 235  
 236      In [11]: 4.5
 237      Out[11]: 4.5
 238  
 239      In [12]: str(ss)
 240      Out[12]: 's'
 241  
 242      In [13]:
 243  
 244      In [14]: %hist -op
 245      >>> class b:
 246      ...     pass
 247      ...
 248      >>> class s(b):
 249      ...     def __str__(self):
 250      ...         return 's'
 251      ...
 252      >>>
 253      >>> class r(b):
 254      ...     def __repr__(self):
 255      ...         return 'r'
 256      ...
 257      >>> class sr(s,r): pass
 258      >>>
 259      >>> bb=b()
 260      >>> ss=s()
 261      >>> rr=r()
 262      >>> ssrr=sr()
 263      >>> 4.5
 264      4.5
 265      >>> str(ss)
 266      's'
 267      >>>
 268      """
 269  
 270  def test_hist_pof():
 271      ip = get_ipython()
 272      ip.run_cell("1+2", store_history=True)
 273      #raise Exception(ip.history_manager.session_number)
 274      #raise Exception(list(ip.history_manager._get_range_session()))
 275      with TemporaryDirectory() as td:
 276          tf = os.path.join(td, 'hist.py')
 277          ip.run_line_magic('history', '-pof %s' % tf)
 278          assert os.path.isfile(tf)
 279  
 280  
 281  def test_macro():
 282      ip = get_ipython()
 283      ip.history_manager.reset()   # Clear any existing history.
 284      cmds = ["a=1", "def b():\n  return a**2", "print(a,b())"]
 285      for i, cmd in enumerate(cmds, start=1):
 286          ip.history_manager.store_inputs(i, cmd)
 287      ip.run_line_magic("macro", "test 1-3")
 288      assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
 289  
 290      # List macros
 291      assert "test" in ip.run_line_magic("macro", "")
 292  
 293  
 294  def test_macro_run():
 295      """Test that we can run a multi-line macro successfully."""
 296      ip = get_ipython()
 297      ip.history_manager.reset()
 298      cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
 299      for cmd in cmds:
 300          ip.run_cell(cmd, store_history=True)
 301      assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
 302      with tt.AssertPrints("12"):
 303          ip.run_cell("test")
 304      with tt.AssertPrints("13"):
 305          ip.run_cell("test")
 306  
 307  
 308  def test_magic_magic():
 309      """Test %magic"""
 310      ip = get_ipython()
 311      with capture_output() as captured:
 312          ip.run_line_magic("magic", "")
 313  
 314      stdout = captured.stdout
 315      assert "%magic" in stdout
 316      assert "IPython" in stdout
 317      assert "Available" in stdout
 318  
 319  
 320  @dec.skipif_not_numpy
 321  def test_numpy_reset_array_undec():
 322      "Test '%reset array' functionality"
 323      _ip.ex("import numpy as np")
 324      _ip.ex("a = np.empty(2)")
 325      assert "a" in _ip.user_ns
 326      _ip.run_line_magic("reset", "-f array")
 327      assert "a" not in _ip.user_ns
 328  
 329  
 330  def test_reset_out():
 331      "Test '%reset out' magic"
 332      _ip.run_cell("parrot = 'dead'", store_history=True)
 333      # test '%reset -f out', make an Out prompt
 334      _ip.run_cell("parrot", store_history=True)
 335      assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
 336      _ip.run_line_magic("reset", "-f out")
 337      assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
 338      assert len(_ip.user_ns["Out"]) == 0
 339  
 340  
 341  def test_reset_in():
 342      "Test '%reset in' magic"
 343      # test '%reset -f in'
 344      _ip.run_cell("parrot", store_history=True)
 345      assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
 346      _ip.run_line_magic("reset", "-f in")
 347      assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
 348      assert len(set(_ip.user_ns["In"])) == 1
 349  
 350  
 351  def test_reset_dhist():
 352      "Test '%reset dhist' magic"
 353      _ip.run_cell("tmp = [d for d in _dh]")  # copy before clearing
 354      _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
 355      _ip.run_line_magic("cd", "-")
 356      assert len(_ip.user_ns["_dh"]) > 0
 357      _ip.run_line_magic("reset", "-f dhist")
 358      assert len(_ip.user_ns["_dh"]) == 0
 359      _ip.run_cell("_dh = [d for d in tmp]")  # restore
 360  
 361  
 362  def test_reset_in_length():
 363      "Test that '%reset in' preserves In[] length"
 364      _ip.run_cell("print 'foo'")
 365      _ip.run_cell("reset -f in")
 366      assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
 367  
 368  
 369  class TestResetErrors(TestCase):
 370  
 371      def test_reset_redefine(self):
 372  
 373          @magics_class
 374          class KernelMagics(Magics):
 375                @line_magic
 376                def less(self, shell): pass
 377  
 378          _ip.register_magics(KernelMagics)
 379  
 380          with self.assertLogs() as cm:
 381              # hack, we want to just capture logs, but assertLogs fails if not
 382              # logs get produce.
 383              # so log one things we ignore.
 384              import logging as log_mod
 385              log = log_mod.getLogger()
 386              log.info('Nothing')
 387              # end hack.
 388              _ip.run_cell("reset -f")
 389  
 390          assert len(cm.output) == 1
 391          for out in cm.output:
 392              assert "Invalid alias" not in out
 393  
 394  def test_tb_syntaxerror():
 395      """test %tb after a SyntaxError"""
 396      ip = get_ipython()
 397      ip.run_cell("for")
 398  
 399      # trap and validate stdout
 400      save_stdout = sys.stdout
 401      try:
 402          sys.stdout = StringIO()
 403          ip.run_cell("%tb")
 404          out = sys.stdout.getvalue()
 405      finally:
 406          sys.stdout = save_stdout
 407      # trim output, and only check the last line
 408      last_line = out.rstrip().splitlines()[-1].strip()
 409      assert last_line == "SyntaxError: invalid syntax"
 410  
 411  
 412  def test_time():
 413      ip = get_ipython()
 414  
 415      with tt.AssertPrints("Wall time: "):
 416          ip.run_cell("%time None")
 417  
 418      ip.run_cell("def f(kmjy):\n"
 419                  "    %time print (2*kmjy)")
 420  
 421      with tt.AssertPrints("Wall time: "):
 422          with tt.AssertPrints("hihi", suppress=False):
 423              ip.run_cell("f('hi')")
 424  
 425  
 426  # ';' at the end of %time prevents instruction value to be printed.
 427  # This tests fix for #13837.
 428  def test_time_no_output_with_semicolon():
 429      ip = get_ipython()
 430  
 431      # Test %time cases
 432      with tt.AssertPrints(" 123456"):
 433          with tt.AssertPrints("Wall time: ", suppress=False):
 434              with tt.AssertPrints("CPU times: ", suppress=False):
 435                  ip.run_cell("%time 123000+456")
 436  
 437      with tt.AssertNotPrints(" 123456"):
 438          with tt.AssertPrints("Wall time: ", suppress=False):
 439              with tt.AssertPrints("CPU times: ", suppress=False):
 440                  ip.run_cell("%time 123000+456;")
 441  
 442      with tt.AssertPrints(" 123456"):
 443          with tt.AssertPrints("Wall time: ", suppress=False):
 444              with tt.AssertPrints("CPU times: ", suppress=False):
 445                  ip.run_cell("%time 123000+456 # Comment")
 446  
 447      with tt.AssertNotPrints(" 123456"):
 448          with tt.AssertPrints("Wall time: ", suppress=False):
 449              with tt.AssertPrints("CPU times: ", suppress=False):
 450                  ip.run_cell("%time 123000+456; # Comment")
 451  
 452      with tt.AssertPrints(" 123456"):
 453          with tt.AssertPrints("Wall time: ", suppress=False):
 454              with tt.AssertPrints("CPU times: ", suppress=False):
 455                  ip.run_cell("%time 123000+456 # ;Comment")
 456  
 457      # Test %%time cases
 458      with tt.AssertPrints("123456"):
 459          with tt.AssertPrints("Wall time: ", suppress=False):
 460              with tt.AssertPrints("CPU times: ", suppress=False):
 461                  ip.run_cell("%%time\n123000+456\n\n\n")
 462  
 463      with tt.AssertNotPrints("123456"):
 464          with tt.AssertPrints("Wall time: ", suppress=False):
 465              with tt.AssertPrints("CPU times: ", suppress=False):
 466                  ip.run_cell("%%time\n123000+456;\n\n\n")
 467  
 468      with tt.AssertPrints("123456"):
 469          with tt.AssertPrints("Wall time: ", suppress=False):
 470              with tt.AssertPrints("CPU times: ", suppress=False):
 471                  ip.run_cell("%%time\n123000+456  # Comment\n\n\n")
 472  
 473      with tt.AssertNotPrints("123456"):
 474          with tt.AssertPrints("Wall time: ", suppress=False):
 475              with tt.AssertPrints("CPU times: ", suppress=False):
 476                  ip.run_cell("%%time\n123000+456;  # Comment\n\n\n")
 477  
 478      with tt.AssertPrints("123456"):
 479          with tt.AssertPrints("Wall time: ", suppress=False):
 480              with tt.AssertPrints("CPU times: ", suppress=False):
 481                  ip.run_cell("%%time\n123000+456  # ;Comment\n\n\n")
 482  
 483  
 484  def test_time_last_not_expression():
 485      ip.run_cell("%%time\n"
 486                  "var_1 = 1\n"
 487                  "var_2 = 2\n")
 488      assert ip.user_ns['var_1'] == 1
 489      del ip.user_ns['var_1']
 490      assert ip.user_ns['var_2'] == 2
 491      del ip.user_ns['var_2']
 492  
 493  
 494  @dec.skip_win32
 495  def test_time2():
 496      ip = get_ipython()
 497  
 498      with tt.AssertPrints("CPU times: user "):
 499          ip.run_cell("%time None")
 500  
 501  def test_time3():
 502      """Erroneous magic function calls, issue gh-3334"""
 503      ip = get_ipython()
 504      ip.user_ns.pop('run', None)
 505  
 506      with tt.AssertNotPrints("not found", channel='stderr'):
 507          ip.run_cell("%%time\n"
 508                      "run = 0\n"
 509                      "run += 1")
 510  
 511  def test_multiline_time():
 512      """Make sure last statement from time return a value."""
 513      ip = get_ipython()
 514      ip.user_ns.pop('run', None)
 515  
 516      ip.run_cell(
 517          dedent(
 518              """\
 519          %%time
 520          a = "ho"
 521          b = "hey"
 522          a+b
 523          """
 524          )
 525      )
 526      assert ip.user_ns_hidden["_"] == "hohey"
 527  
 528  
 529  def test_time_local_ns():
 530      """
 531      Test that local_ns is actually global_ns when running a cell magic
 532      """
 533      ip = get_ipython()
 534      ip.run_cell("%%time\n" "myvar = 1")
 535      assert ip.user_ns["myvar"] == 1
 536      del ip.user_ns["myvar"]
 537  
 538  
 539  def test_time_microseconds_display():
 540      """Ensure ASCII is used when necessary"""
 541      with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="utf-8")):
 542          assert execution._format_time(0.000001) == "1 \u03bcs"
 543      with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="ascii")):
 544          assert execution._format_time(0.000001) == "1 us"
 545  
 546  
 547  # Test %%capture magic. Added to test issue #13926
 548  def test_capture():
 549      ip = get_ipython()
 550  
 551      # Test %%capture nominal case
 552      ip.run_cell("%%capture abc\n1+2")
 553      with tt.AssertPrints("True", suppress=False):
 554          ip.run_cell("'abc' in locals()")
 555      with tt.AssertPrints("True", suppress=False):
 556          ip.run_cell("'outputs' in dir(abc)")
 557      with tt.AssertPrints("3", suppress=False):
 558          ip.run_cell("abc.outputs[0]")
 559  
 560      # Test %%capture with ';' at end of expression
 561      ip.run_cell("%%capture abc\n7+8;")
 562      with tt.AssertPrints("False", suppress=False):
 563          ip.run_cell("'abc' in locals()")
 564  
 565  
 566  def test_doctest_mode():
 567      "Toggle doctest_mode twice, it should be a no-op and run without error"
 568      _ip.run_line_magic("doctest_mode", "")
 569      _ip.run_line_magic("doctest_mode", "")
 570  
 571  
 572  def test_parse_options():
 573      """Tests for basic options parsing in magics."""
 574      # These are only the most minimal of tests, more should be added later.  At
 575      # the very least we check that basic text/unicode calls work OK.
 576      m = DummyMagics(_ip)
 577      assert m.parse_options("foo", "")[1] == "foo"
 578      assert m.parse_options("foo", "")[1] == "foo"
 579  
 580  
 581  def test_parse_options_preserve_non_option_string():
 582      """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
 583      m = DummyMagics(_ip)
 584      opts, stmt = m.parse_options(
 585          " -n1  -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
 586      )
 587      assert opts == {"n": "1", "r": "13"}
 588      assert stmt == "_ = 314 + foo"
 589  
 590  
 591  def test_run_magic_preserve_code_block():
 592      """Test to assert preservation of non-option part of magic-block, while running magic."""
 593      _ip.user_ns["spaces"] = []
 594      _ip.run_line_magic(
 595          "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
 596      )
 597      assert _ip.user_ns["spaces"] == [[0]]
 598  
 599  
 600  def test_dirops():
 601      """Test various directory handling operations."""
 602      # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
 603      curpath = os.getcwd
 604      startdir = os.getcwd()
 605      ipdir = os.path.realpath(_ip.ipython_dir)
 606      try:
 607          _ip.run_line_magic("cd", '"%s"' % ipdir)
 608          assert curpath() == ipdir
 609          _ip.run_line_magic("cd", "-")
 610          assert curpath() == startdir
 611          _ip.run_line_magic("pushd", '"%s"' % ipdir)
 612          assert curpath() == ipdir
 613          _ip.run_line_magic("popd", "")
 614          assert curpath() == startdir
 615      finally:
 616          os.chdir(startdir)
 617  
 618  
 619  def test_cd_force_quiet():
 620      """Test OSMagics.cd_force_quiet option"""
 621      _ip.config.OSMagics.cd_force_quiet = True
 622      osmagics = osm.OSMagics(shell=_ip)
 623  
 624      startdir = os.getcwd()
 625      ipdir = os.path.realpath(_ip.ipython_dir)
 626  
 627      try:
 628          with tt.AssertNotPrints(ipdir):
 629              osmagics.cd('"%s"' % ipdir)
 630          with tt.AssertNotPrints(startdir):
 631              osmagics.cd('-')
 632      finally:
 633          os.chdir(startdir)
 634  
 635  
 636  def test_xmode():
 637      # Calling xmode three times should be a no-op
 638      xmode = _ip.InteractiveTB.mode
 639      for i in range(4):
 640          _ip.run_line_magic("xmode", "")
 641      assert _ip.InteractiveTB.mode == xmode
 642  
 643  def test_reset_hard():
 644      monitor = []
 645      class A(object):
 646          def __del__(self):
 647              monitor.append(1)
 648          def __repr__(self):
 649              return "<A instance>"
 650  
 651      _ip.user_ns["a"] = A()
 652      _ip.run_cell("a")
 653  
 654      assert monitor == []
 655      _ip.run_line_magic("reset", "-f")
 656      assert monitor == [1]
 657  
 658  class TestXdel(tt.TempFileMixin):
 659      def test_xdel(self):
 660          """Test that references from %run are cleared by xdel."""
 661          src = ("class A(object):\n"
 662                 "    monitor = []\n"
 663                 "    def __del__(self):\n"
 664                 "        self.monitor.append(1)\n"
 665                 "a = A()\n")
 666          self.mktmp(src)
 667          # %run creates some hidden references...
 668          _ip.run_line_magic("run", "%s" % self.fname)
 669          # ... as does the displayhook.
 670          _ip.run_cell("a")
 671  
 672          monitor = _ip.user_ns["A"].monitor
 673          assert monitor == []
 674  
 675          _ip.run_line_magic("xdel", "a")
 676  
 677          # Check that a's __del__ method has been called.
 678          gc.collect(0)
 679          assert monitor == [1]
 680  
 681  def doctest_who():
 682      """doctest for %who
 683  
 684      In [1]: %reset -sf
 685  
 686      In [2]: alpha = 123
 687  
 688      In [3]: beta = 'beta'
 689  
 690      In [4]: %who int
 691      alpha
 692  
 693      In [5]: %who str
 694      beta
 695  
 696      In [6]: %whos
 697      Variable   Type    Data/Info
 698      ----------------------------
 699      alpha      int     123
 700      beta       str     beta
 701  
 702      In [7]: %who_ls
 703      Out[7]: ['alpha', 'beta']
 704      """
 705  
 706  def test_whos():
 707      """Check that whos is protected against objects where repr() fails."""
 708      class A(object):
 709          def __repr__(self):
 710              raise Exception()
 711      _ip.user_ns['a'] = A()
 712      _ip.run_line_magic("whos", "")
 713  
 714  def doctest_precision():
 715      """doctest for %precision
 716  
 717      In [1]: f = get_ipython().display_formatter.formatters['text/plain']
 718  
 719      In [2]: %precision 5
 720      Out[2]: '%.5f'
 721  
 722      In [3]: f.float_format
 723      Out[3]: '%.5f'
 724  
 725      In [4]: %precision %e
 726      Out[4]: '%e'
 727  
 728      In [5]: f(3.1415927)
 729      Out[5]: '3.141593e+00'
 730      """
 731  
 732  
 733  def test_debug_magic():
 734      """Test debugging a small code with %debug
 735  
 736      In [1]: with PdbTestInput(['c']):
 737         ...:     %debug print("a b") #doctest: +ELLIPSIS
 738         ...:
 739      ...
 740      ipdb> c
 741      a b
 742      In [2]:
 743      """
 744  
 745  
 746  def test_debug_magic_locals():
 747      """Test debugging a small code with %debug with locals
 748  
 749      In [1]: with PdbTestInput(['c']):
 750         ...:     def fun():
 751         ...:         res = 1
 752         ...:         %debug print(res)
 753         ...:     fun()
 754         ...:
 755      ...
 756      ipdb> c
 757      1
 758      In [2]:
 759      """
 760  
 761  def test_psearch():
 762      with tt.AssertPrints("dict.fromkeys"):
 763          _ip.run_cell("dict.fr*?")
 764      with tt.AssertPrints("π.is_integer"):
 765          _ip.run_cell("π = 3.14;\nπ.is_integ*?")
 766  
 767  def test_timeit_shlex():
 768      """test shlex issues with timeit (#1109)"""
 769      _ip.ex("def f(*a,**kw): pass")
 770      _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
 771      _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
 772      _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
 773      _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
 774      _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
 775      _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
 776  
 777  
 778  def test_timeit_special_syntax():
 779      "Test %%timeit with IPython special syntax"
 780      @register_line_magic
 781      def lmagic(line):
 782          ip = get_ipython()
 783          ip.user_ns['lmagic_out'] = line
 784  
 785      # line mode test
 786      _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
 787      assert _ip.user_ns["lmagic_out"] == "my line"
 788      # cell mode test
 789      _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
 790      assert _ip.user_ns["lmagic_out"] == "my line2"
 791  
 792  
 793  def test_timeit_return():
 794      """
 795      test whether timeit -o return object
 796      """
 797  
 798      res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
 799      assert(res is not None)
 800  
 801  def test_timeit_quiet():
 802      """
 803      test quiet option of timeit magic
 804      """
 805      with tt.AssertNotPrints("loops"):
 806          _ip.run_cell("%timeit -n1 -r1 -q 1")
 807  
 808  def test_timeit_return_quiet():
 809      with tt.AssertNotPrints("loops"):
 810          res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
 811      assert (res is not None)
 812  
 813  def test_timeit_invalid_return():
 814      with pytest.raises(SyntaxError):
 815          _ip.run_line_magic('timeit', 'return')
 816  
 817  @dec.skipif(execution.profile is None)
 818  def test_prun_special_syntax():
 819      "Test %%prun with IPython special syntax"
 820      @register_line_magic
 821      def lmagic(line):
 822          ip = get_ipython()
 823          ip.user_ns['lmagic_out'] = line
 824  
 825      # line mode test
 826      _ip.run_line_magic("prun", "-q %lmagic my line")
 827      assert _ip.user_ns["lmagic_out"] == "my line"
 828      # cell mode test
 829      _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
 830      assert _ip.user_ns["lmagic_out"] == "my line2"
 831  
 832  
 833  @dec.skipif(execution.profile is None)
 834  def test_prun_quotes():
 835      "Test that prun does not clobber string escapes (GH #1302)"
 836      _ip.run_line_magic("prun", r"-q x = '\t'")
 837      assert _ip.user_ns["x"] == "\t"
 838  
 839  
 840  def test_extension():
 841      # Debugging information for failures of this test
 842      print('sys.path:')
 843      for p in sys.path:
 844          print(' ', p)
 845      print('CWD', os.getcwd())
 846  
 847      pytest.raises(ImportError, _ip.run_line_magic, "load_ext", "daft_extension")
 848      daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
 849      sys.path.insert(0, daft_path)
 850      try:
 851          _ip.user_ns.pop('arq', None)
 852          invalidate_caches()   # Clear import caches
 853          _ip.run_line_magic("load_ext", "daft_extension")
 854          assert _ip.user_ns["arq"] == 185
 855          _ip.run_line_magic("unload_ext", "daft_extension")
 856          assert 'arq' not in _ip.user_ns
 857      finally:
 858          sys.path.remove(daft_path)
 859  
 860  
 861  def test_notebook_export_json():
 862      pytest.importorskip("nbformat")
 863      _ip = get_ipython()
 864      _ip.history_manager.reset()   # Clear any existing history.
 865      cmds = ["a=1", "def b():\n  return a**2", "print('noël, été', b())"]
 866      for i, cmd in enumerate(cmds, start=1):
 867          _ip.history_manager.store_inputs(i, cmd)
 868      with TemporaryDirectory() as td:
 869          outfile = os.path.join(td, "nb.ipynb")
 870          _ip.run_line_magic("notebook", "%s" % outfile)
 871  
 872  
 873  class TestEnv(TestCase):
 874  
 875      def test_env(self):
 876          env = _ip.run_line_magic("env", "")
 877          self.assertTrue(isinstance(env, dict))
 878  
 879      def test_env_secret(self):
 880          env = _ip.run_line_magic("env", "")
 881          hidden = "<hidden>"
 882          with mock.patch.dict(
 883              os.environ,
 884              {
 885                  "API_KEY": "abc123",
 886                  "SECRET_THING": "ssshhh",
 887                  "JUPYTER_TOKEN": "",
 888                  "VAR": "abc"
 889              }
 890          ):
 891              env = _ip.run_line_magic("env", "")
 892          assert env["API_KEY"] == hidden
 893          assert env["SECRET_THING"] == hidden
 894          assert env["JUPYTER_TOKEN"] == hidden
 895          assert env["VAR"] == "abc"
 896  
 897      def test_env_get_set_simple(self):
 898          env = _ip.run_line_magic("env", "var val1")
 899          self.assertEqual(env, None)
 900          self.assertEqual(os.environ["var"], "val1")
 901          self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
 902          env = _ip.run_line_magic("env", "var=val2")
 903          self.assertEqual(env, None)
 904          self.assertEqual(os.environ['var'], 'val2')
 905  
 906      def test_env_get_set_complex(self):
 907          env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
 908          self.assertEqual(env, None)
 909          self.assertEqual(os.environ['var'], "'val1 '' 'val2")
 910          self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
 911          env = _ip.run_line_magic("env", 'var=val2 val3="val4')
 912          self.assertEqual(env, None)
 913          self.assertEqual(os.environ['var'], 'val2 val3="val4')
 914  
 915      def test_env_set_bad_input(self):
 916          self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
 917  
 918      def test_env_set_whitespace(self):
 919          self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
 920  
 921  
 922  class CellMagicTestCase(TestCase):
 923  
 924      def check_ident(self, magic):
 925          # Manually called, we get the result
 926          out = _ip.run_cell_magic(magic, "a", "b")
 927          assert out == ("a", "b")
 928          # Via run_cell, it goes into the user's namespace via displayhook
 929          _ip.run_cell("%%" + magic + " c\nd\n")
 930          assert _ip.user_ns["_"] == ("c", "d\n")
 931  
 932      def test_cell_magic_func_deco(self):
 933          "Cell magic using simple decorator"
 934          @register_cell_magic
 935          def cellm(line, cell):
 936              return line, cell
 937  
 938          self.check_ident('cellm')
 939  
 940      def test_cell_magic_reg(self):
 941          "Cell magic manually registered"
 942          def cellm(line, cell):
 943              return line, cell
 944  
 945          _ip.register_magic_function(cellm, 'cell', 'cellm2')
 946          self.check_ident('cellm2')
 947  
 948      def test_cell_magic_class(self):
 949          "Cell magics declared via a class"
 950          @magics_class
 951          class MyMagics(Magics):
 952  
 953              @cell_magic
 954              def cellm3(self, line, cell):
 955                  return line, cell
 956  
 957          _ip.register_magics(MyMagics)
 958          self.check_ident('cellm3')
 959  
 960      def test_cell_magic_class2(self):
 961          "Cell magics declared via a class, #2"
 962          @magics_class
 963          class MyMagics2(Magics):
 964  
 965              @cell_magic('cellm4')
 966              def cellm33(self, line, cell):
 967                  return line, cell
 968  
 969          _ip.register_magics(MyMagics2)
 970          self.check_ident('cellm4')
 971          # Check that nothing is registered as 'cellm33'
 972          c33 = _ip.find_cell_magic('cellm33')
 973          assert c33 == None
 974  
 975  def test_file():
 976      """Basic %%writefile"""
 977      ip = get_ipython()
 978      with TemporaryDirectory() as td:
 979          fname = os.path.join(td, "file1")
 980          ip.run_cell_magic(
 981              "writefile",
 982              fname,
 983              "\n".join(
 984                  [
 985                      "line1",
 986                      "line2",
 987                  ]
 988              ),
 989          )
 990          s = Path(fname).read_text(encoding="utf-8")
 991          assert "line1\n" in s
 992          assert "line2" in s
 993  
 994  
 995  @dec.skip_win32
 996  def test_file_single_quote():
 997      """Basic %%writefile with embedded single quotes"""
 998      ip = get_ipython()
 999      with TemporaryDirectory() as td:
1000          fname = os.path.join(td, "'file1'")
1001          ip.run_cell_magic(
1002              "writefile",
1003              fname,
1004              "\n".join(
1005                  [
1006                      "line1",
1007                      "line2",
1008                  ]
1009              ),
1010          )
1011          s = Path(fname).read_text(encoding="utf-8")
1012          assert "line1\n" in s
1013          assert "line2" in s
1014  
1015  
1016  @dec.skip_win32
1017  def test_file_double_quote():
1018      """Basic %%writefile with embedded double quotes"""
1019      ip = get_ipython()
1020      with TemporaryDirectory() as td:
1021          fname = os.path.join(td, '"file1"')
1022          ip.run_cell_magic(
1023              "writefile",
1024              fname,
1025              "\n".join(
1026                  [
1027                      "line1",
1028                      "line2",
1029                  ]
1030              ),
1031          )
1032          s = Path(fname).read_text(encoding="utf-8")
1033          assert "line1\n" in s
1034          assert "line2" in s
1035  
1036  
1037  def test_file_var_expand():
1038      """%%writefile $filename"""
1039      ip = get_ipython()
1040      with TemporaryDirectory() as td:
1041          fname = os.path.join(td, "file1")
1042          ip.user_ns["filename"] = fname
1043          ip.run_cell_magic(
1044              "writefile",
1045              "$filename",
1046              "\n".join(
1047                  [
1048                      "line1",
1049                      "line2",
1050                  ]
1051              ),
1052          )
1053          s = Path(fname).read_text(encoding="utf-8")
1054          assert "line1\n" in s
1055          assert "line2" in s
1056  
1057  
1058  def test_file_unicode():
1059      """%%writefile with unicode cell"""
1060      ip = get_ipython()
1061      with TemporaryDirectory() as td:
1062          fname = os.path.join(td, 'file1')
1063          ip.run_cell_magic("writefile", fname, u'\n'.join([
1064              u'liné1',
1065              u'liné2',
1066          ]))
1067          with io.open(fname, encoding='utf-8') as f:
1068              s = f.read()
1069          assert "liné1\n" in s
1070          assert "liné2" in s
1071  
1072  
1073  def test_file_amend():
1074      """%%writefile -a amends files"""
1075      ip = get_ipython()
1076      with TemporaryDirectory() as td:
1077          fname = os.path.join(td, "file2")
1078          ip.run_cell_magic(
1079              "writefile",
1080              fname,
1081              "\n".join(
1082                  [
1083                      "line1",
1084                      "line2",
1085                  ]
1086              ),
1087          )
1088          ip.run_cell_magic(
1089              "writefile",
1090              "-a %s" % fname,
1091              "\n".join(
1092                  [
1093                      "line3",
1094                      "line4",
1095                  ]
1096              ),
1097          )
1098          s = Path(fname).read_text(encoding="utf-8")
1099          assert "line1\n" in s
1100          assert "line3\n" in s
1101  
1102  
1103  def test_file_spaces():
1104      """%%file with spaces in filename"""
1105      ip = get_ipython()
1106      with TemporaryWorkingDirectory() as td:
1107          fname = "file name"
1108          ip.run_cell_magic(
1109              "file",
1110              '"%s"' % fname,
1111              "\n".join(
1112                  [
1113                      "line1",
1114                      "line2",
1115                  ]
1116              ),
1117          )
1118          s = Path(fname).read_text(encoding="utf-8")
1119          assert "line1\n" in s
1120          assert "line2" in s
1121  
1122  
1123  def test_script_config():
1124      ip = get_ipython()
1125      ip.config.ScriptMagics.script_magics = ['whoda']
1126      sm = script.ScriptMagics(shell=ip)
1127      assert "whoda" in sm.magics["cell"]
1128  
1129  
1130  def _interrupt_after_1s():
1131      sleep(1)
1132      signal.raise_signal(signal.SIGINT)
1133  
1134  
1135  def test_script_raise_on_interrupt():
1136      ip = get_ipython()
1137  
1138      with pytest.raises(CalledProcessError):
1139          thread = Thread(target=_interrupt_after_1s)
1140          thread.start()
1141          ip.run_cell_magic(
1142              "script", f"{sys.executable}", "from time import sleep; sleep(2)"
1143          )
1144          thread.join()
1145  
1146  
1147  def test_script_do_not_raise_on_interrupt():
1148      ip = get_ipython()
1149  
1150      thread = Thread(target=_interrupt_after_1s)
1151      thread.start()
1152      ip.run_cell_magic(
1153          "script",
1154          f"--no-raise-error {sys.executable}",
1155          "from time import sleep; sleep(2)",
1156      )
1157      thread.join()
1158  
1159  
1160  def test_script_out():
1161      ip = get_ipython()
1162      ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1163      assert ip.user_ns["output"].strip() == "hi"
1164  
1165  
1166  def test_script_err():
1167      ip = get_ipython()
1168      ip.run_cell_magic(
1169          "script",
1170          f"--err error {sys.executable}",
1171          "import sys; print('hello', file=sys.stderr)",
1172      )
1173      assert ip.user_ns["error"].strip() == "hello"
1174  
1175  
1176  def test_script_out_err():
1177      ip = get_ipython()
1178      ip.run_cell_magic(
1179          "script",
1180          f"--out output --err error {sys.executable}",
1181          "\n".join(
1182              [
1183                  "import sys",
1184                  "print('hi')",
1185                  "print('hello', file=sys.stderr)",
1186              ]
1187          ),
1188      )
1189      assert ip.user_ns["output"].strip() == "hi"
1190      assert ip.user_ns["error"].strip() == "hello"
1191  
1192  
1193  async def test_script_bg_out():
1194      ip = get_ipython()
1195      ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1196      assert (await ip.user_ns["output"].read()).strip() == b"hi"
1197      assert ip.user_ns["output"].at_eof()
1198  
1199  
1200  async def test_script_bg_err():
1201      ip = get_ipython()
1202      ip.run_cell_magic(
1203          "script",
1204          f"--bg --err error {sys.executable}",
1205          "import sys; print('hello', file=sys.stderr)",
1206      )
1207      assert (await ip.user_ns["error"].read()).strip() == b"hello"
1208      assert ip.user_ns["error"].at_eof()
1209  
1210  
1211  async def test_script_bg_out_err():
1212      ip = get_ipython()
1213      ip.run_cell_magic(
1214          "script",
1215          f"--bg --out output --err error {sys.executable}",
1216          "\n".join(
1217              [
1218                  "import sys",
1219                  "print('hi')",
1220                  "print('hello', file=sys.stderr)",
1221              ]
1222          ),
1223      )
1224      assert (await ip.user_ns["output"].read()).strip() == b"hi"
1225      assert (await ip.user_ns["error"].read()).strip() == b"hello"
1226      assert ip.user_ns["output"].at_eof()
1227      assert ip.user_ns["error"].at_eof()
1228  
1229  
1230  async def test_script_bg_proc():
1231      ip = get_ipython()
1232      ip.run_cell_magic(
1233          "script",
1234          f"--bg --out output --proc p {sys.executable}",
1235          "\n".join(
1236              [
1237                  "import sys",
1238                  "print('hi')",
1239                  "print('hello', file=sys.stderr)",
1240              ]
1241          ),
1242      )
1243      p = ip.user_ns["p"]
1244      await p.wait()
1245      assert p.returncode == 0
1246      assert (await p.stdout.read()).strip() == b"hi"
1247      # not captured, so empty
1248      assert (await p.stderr.read()) == b""
1249      assert p.stdout.at_eof()
1250      assert p.stderr.at_eof()
1251  
1252  
1253  def test_script_defaults():
1254      ip = get_ipython()
1255      for cmd in ['sh', 'bash', 'perl', 'ruby']:
1256          try:
1257              find_cmd(cmd)
1258          except Exception:
1259              pass
1260          else:
1261              assert cmd in ip.magics_manager.magics["cell"]
1262  
1263  
1264  async def test_script_streams_continiously(capsys):
1265      ip = get_ipython()
1266      # Windows is slow to start up a thread on CI
1267      is_windows = os.name == "nt"
1268      step = 3 if is_windows else 1
1269      code = dedent(
1270          f"""\
1271      import time
1272      for _ in range(3):
1273          time.sleep({step})
1274          print(".", flush=True, end="")
1275      """
1276      )
1277  
1278      def print_numbers():
1279          for i in range(3):
1280              sleep(step)
1281              print(i, flush=True, end="")
1282  
1283      thread = Thread(target=print_numbers)
1284      thread.start()
1285      sleep(step / 2)
1286      ip.run_cell_magic("script", f"{sys.executable}", code)
1287      thread.join()
1288  
1289      captured = capsys.readouterr()
1290      # If the streaming was line-wise or broken
1291      # we would get `012...`
1292      assert captured.out == "0.1.2."
1293  
1294  
1295  @magics_class
1296  class FooFoo(Magics):
1297      """class with both %foo and %%foo magics"""
1298      @line_magic('foo')
1299      def line_foo(self, line):
1300          "I am line foo"
1301          pass
1302  
1303      @cell_magic("foo")
1304      def cell_foo(self, line, cell):
1305          "I am cell foo, not line foo"
1306          pass
1307  
1308  def test_line_cell_info():
1309      """%%foo and %foo magics are distinguishable to inspect"""
1310      ip = get_ipython()
1311      ip.magics_manager.register(FooFoo)
1312      oinfo = ip.object_inspect("foo")
1313      assert oinfo["found"] is True
1314      assert oinfo["ismagic"] is True
1315  
1316      oinfo = ip.object_inspect("%%foo")
1317      assert oinfo["found"] is True
1318      assert oinfo["ismagic"] is True
1319      assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1320  
1321      oinfo = ip.object_inspect("%foo")
1322      assert oinfo["found"] is True
1323      assert oinfo["ismagic"] is True
1324      assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1325  
1326  
1327  def test_multiple_magics():
1328      ip = get_ipython()
1329      foo1 = FooFoo(ip)
1330      foo2 = FooFoo(ip)
1331      mm = ip.magics_manager
1332      mm.register(foo1)
1333      assert mm.magics["line"]["foo"].__self__ is foo1
1334      mm.register(foo2)
1335      assert mm.magics["line"]["foo"].__self__ is foo2
1336  
1337  
1338  def test_alias_magic():
1339      """Test %alias_magic."""
1340      ip = get_ipython()
1341      mm = ip.magics_manager
1342  
1343      # Basic operation: both cell and line magics are created, if possible.
1344      ip.run_line_magic("alias_magic", "timeit_alias timeit")
1345      assert "timeit_alias" in mm.magics["line"]
1346      assert "timeit_alias" in mm.magics["cell"]
1347  
1348      # --cell is specified, line magic not created.
1349      ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1350      assert "timeit_cell_alias" not in mm.magics["line"]
1351      assert "timeit_cell_alias" in mm.magics["cell"]
1352  
1353      # Test that line alias is created successfully.
1354      ip.run_line_magic("alias_magic", "--line env_alias env")
1355      assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1356  
1357      # Test that line alias with parameters passed in is created successfully.
1358      ip.run_line_magic(
1359          "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1360      )
1361      assert "history_alias" in mm.magics["line"]
1362  
1363  
1364  def test_save():
1365      """Test %save."""
1366      ip = get_ipython()
1367      ip.history_manager.reset()   # Clear any existing history.
1368      cmds = ["a=1", "def b():\n  return a**2", "print(a, b())"]
1369      for i, cmd in enumerate(cmds, start=1):
1370          ip.history_manager.store_inputs(i, cmd)
1371      with TemporaryDirectory() as tmpdir:
1372          file = os.path.join(tmpdir, "testsave.py")
1373          ip.run_line_magic("save", "%s 1-10" % file)
1374          content = Path(file).read_text(encoding="utf-8")
1375          assert content.count(cmds[0]) == 1
1376          assert "coding: utf-8" in content
1377          ip.run_line_magic("save", "-a %s 1-10" % file)
1378          content = Path(file).read_text(encoding="utf-8")
1379          assert content.count(cmds[0]) == 2
1380          assert "coding: utf-8" in content
1381  
1382  
1383  def test_save_with_no_args():
1384      ip = get_ipython()
1385      ip.history_manager.reset()  # Clear any existing history.
1386      cmds = ["a=1", "def b():\n    return a**2", "print(a, b())", "%save"]
1387      for i, cmd in enumerate(cmds, start=1):
1388          ip.history_manager.store_inputs(i, cmd)
1389  
1390      with TemporaryDirectory() as tmpdir:
1391          path = os.path.join(tmpdir, "testsave.py")
1392          ip.run_line_magic("save", path)
1393          content = Path(path).read_text(encoding="utf-8")
1394          expected_content = dedent(
1395              """\
1396              # coding: utf-8
1397              a=1
1398              def b():
1399                  return a**2
1400              print(a, b())
1401              """
1402          )
1403          assert content == expected_content
1404  
1405  
1406  def test_store():
1407      """Test %store."""
1408      ip = get_ipython()
1409      ip.run_line_magic('load_ext', 'storemagic')
1410  
1411      # make sure the storage is empty
1412      ip.run_line_magic("store", "-z")
1413      ip.user_ns["var"] = 42
1414      ip.run_line_magic("store", "var")
1415      ip.user_ns["var"] = 39
1416      ip.run_line_magic("store", "-r")
1417      assert ip.user_ns["var"] == 42
1418  
1419      ip.run_line_magic("store", "-d var")
1420      ip.user_ns["var"] = 39
1421      ip.run_line_magic("store", "-r")
1422      assert ip.user_ns["var"] == 39
1423  
1424  
1425  def _run_edit_test(arg_s, exp_filename=None,
1426                          exp_lineno=-1,
1427                          exp_contents=None,
1428                          exp_is_temp=None):
1429      ip = get_ipython()
1430      M = code.CodeMagics(ip)
1431      last_call = ['','']
1432      opts,args = M.parse_options(arg_s,'prxn:')
1433      filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1434  
1435      if exp_filename is not None:
1436          assert exp_filename == filename
1437      if exp_contents is not None:
1438          with io.open(filename, 'r', encoding='utf-8') as f:
1439              contents = f.read()
1440          assert exp_contents == contents
1441      if exp_lineno != -1:
1442          assert exp_lineno == lineno
1443      if exp_is_temp is not None:
1444          assert exp_is_temp == is_temp
1445  
1446  
1447  def test_edit_interactive():
1448      """%edit on interactively defined objects"""
1449      ip = get_ipython()
1450      n = ip.execution_count
1451      ip.run_cell("def foo(): return 1", store_history=True)
1452  
1453      with pytest.raises(code.InteractivelyDefined) as e:
1454          _run_edit_test("foo")
1455      assert e.value.index == n
1456  
1457  
1458  def test_edit_cell():
1459      """%edit [cell id]"""
1460      ip = get_ipython()
1461  
1462      ip.run_cell("def foo(): return 1", store_history=True)
1463  
1464      # test
1465      _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1466  
1467  def test_edit_fname():
1468      """%edit file"""
1469      # test
1470      _run_edit_test("test file.py", exp_filename="test file.py")
1471  
1472  def test_bookmark():
1473      ip = get_ipython()
1474      ip.run_line_magic('bookmark', 'bmname')
1475      with tt.AssertPrints('bmname'):
1476          ip.run_line_magic('bookmark', '-l')
1477      ip.run_line_magic('bookmark', '-d bmname')
1478  
1479  def test_ls_magic():
1480      ip = get_ipython()
1481      json_formatter = ip.display_formatter.formatters['application/json']
1482      json_formatter.enabled = True
1483      lsmagic = ip.run_line_magic("lsmagic", "")
1484      with warnings.catch_warnings(record=True) as w:
1485          j = json_formatter(lsmagic)
1486      assert sorted(j) == ["cell", "line"]
1487      assert w == []  # no warnings
1488  
1489  
1490  def test_strip_initial_indent():
1491      def sii(s):
1492          lines = s.splitlines()
1493          return '\n'.join(code.strip_initial_indent(lines))
1494  
1495      assert sii("  a = 1\nb = 2") == "a = 1\nb = 2"
1496      assert sii("  a\n    b\nc") == "a\n  b\nc"
1497      assert sii("a\n  b") == "a\n  b"
1498  
1499  def test_logging_magic_quiet_from_arg():
1500      _ip.config.LoggingMagics.quiet = False
1501      lm = logging.LoggingMagics(shell=_ip)
1502      with TemporaryDirectory() as td:
1503          try:
1504              with tt.AssertNotPrints(re.compile("Activating.*")):
1505                  lm.logstart('-q {}'.format(
1506                          os.path.join(td, "quiet_from_arg.log")))
1507          finally:
1508              _ip.logger.logstop()
1509  
1510  def test_logging_magic_quiet_from_config():
1511      _ip.config.LoggingMagics.quiet = True
1512      lm = logging.LoggingMagics(shell=_ip)
1513      with TemporaryDirectory() as td:
1514          try:
1515              with tt.AssertNotPrints(re.compile("Activating.*")):
1516                  lm.logstart(os.path.join(td, "quiet_from_config.log"))
1517          finally:
1518              _ip.logger.logstop()
1519  
1520  
1521  def test_logging_magic_not_quiet():
1522      _ip.config.LoggingMagics.quiet = False
1523      lm = logging.LoggingMagics(shell=_ip)
1524      with TemporaryDirectory() as td:
1525          try:
1526              with tt.AssertPrints(re.compile("Activating.*")):
1527                  lm.logstart(os.path.join(td, "not_quiet.log"))
1528          finally:
1529              _ip.logger.logstop()
1530  
1531  
1532  def test_time_no_var_expand():
1533      _ip.user_ns["a"] = 5
1534      _ip.user_ns["b"] = []
1535      _ip.run_line_magic("time", 'b.append("{a}")')
1536      assert _ip.user_ns["b"] == ["{a}"]
1537  
1538  
1539  # this is slow, put at the end for local testing.
1540  def test_timeit_arguments():
1541      "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1542      _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1543  
1544  
1545  MINIMAL_LAZY_MAGIC = """
1546  from IPython.core.magic import (
1547      Magics,
1548      magics_class,
1549      line_magic,
1550      cell_magic,
1551  )
1552  
1553  
1554  @magics_class
1555  class LazyMagics(Magics):
1556      @line_magic
1557      def lazy_line(self, line):
1558          print("Lazy Line")
1559  
1560      @cell_magic
1561      def lazy_cell(self, line, cell):
1562          print("Lazy Cell")
1563  
1564  
1565  def load_ipython_extension(ipython):
1566      ipython.register_magics(LazyMagics)
1567  """
1568  
1569  
1570  def test_lazy_magics():
1571      with pytest.raises(UsageError):
1572          ip.run_line_magic("lazy_line", "")
1573  
1574      startdir = os.getcwd()
1575  
1576      with TemporaryDirectory() as tmpdir:
1577          with prepended_to_syspath(tmpdir):
1578              ptempdir = Path(tmpdir)
1579              tf = ptempdir / "lazy_magic_module.py"
1580              tf.write_text(MINIMAL_LAZY_MAGIC)
1581              ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1582              with tt.AssertPrints("Lazy Line"):
1583                  ip.run_line_magic("lazy_line", "")
1584  
1585  
1586  TEST_MODULE = """
1587  print('Loaded my_tmp')
1588  if __name__ == "__main__":
1589      print('I just ran a script')
1590  """
1591  
1592  def test_run_module_from_import_hook():
1593      "Test that a module can be loaded via an import hook"
1594      with TemporaryDirectory() as tmpdir:
1595          fullpath = os.path.join(tmpdir, "my_tmp.py")
1596          Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1597  
1598          import importlib.abc
1599          import importlib.util
1600  
1601          class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1602              def find_spec(self, fullname, path, target=None):
1603                  if fullname == "my_tmp":
1604                      return importlib.util.spec_from_loader(fullname, self)
1605  
1606              def get_filename(self, fullname):
1607                  assert fullname == "my_tmp"
1608                  return fullpath
1609  
1610              def get_data(self, path):
1611                  assert Path(path).samefile(fullpath)
1612                  return Path(fullpath).read_text(encoding="utf-8")
1613  
1614          sys.meta_path.insert(0, MyTempImporter())
1615  
1616          with capture_output() as captured:
1617              _ip.run_line_magic("run", "-m my_tmp")
1618              _ip.run_cell("import my_tmp")
1619  
1620          output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1621          assert output == captured.stdout
1622  
1623          sys.meta_path.pop(0)
1624