From 0ec527d546cad252ca42e04619a77220ed829670 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 15 Sep 2018 11:49:59 +0200 Subject: [PATCH 001/635] Remove implicit dependency to ipython_genutils. This was installed because we rely on traitlets. `indent` behavior is _slightly_ different in the sens that white lines may not have the same number of whitespace. --- docs/autogen_config.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/autogen_config.py b/docs/autogen_config.py index f7913488a49..e8af5f239bf 100755 --- a/docs/autogen_config.py +++ b/docs/autogen_config.py @@ -11,7 +11,36 @@ options = join(here, 'source', 'config', 'options') generated = join(options, 'config-generated.txt') -from ipython_genutils.text import indent, dedent +import textwrap +indent = lambda text,n: textwrap.indent(text,n*' ') + +def dedent(text): + """Equivalent of textwrap.dedent that ignores unindented first line. + + This means it will still dedent strings like: + '''foo + is a bar + ''' + + For use in wrap_paragraphs. + """ + + if text.startswith('\n'): + # text starts with blank line, don't ignore the first line + return textwrap.dedent(text) + + # split first line + splits = text.split('\n',1) + if len(splits) == 1: + # only one line + return textwrap.dedent(text) + + first, rest = splits + # dedent everything but the first line + rest = textwrap.dedent(rest) + return '\n'.join([first, rest]) + + def interesting_default_value(dv): if (dv is None) or (dv is Undefined): From 67eed53264b93d265ed1d4b136c7ba18076bc1d1 Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Wed, 15 Aug 2018 17:14:23 -0700 Subject: [PATCH 002/635] Fix `up` through generators in postmortem debugger By passing the lowest traceback element into the debugger, we require it to use frame.f_back to find older frames. However, f_back is always None for generator frames. By providing a higher-up traceback element, pdb can traverse down the traceback.tb_next links, which do work correctly across generator calls. Furthermore, pdb will not do the right thing if it is provided with a frame/traceback pair that do not correspond to each other - it will duplicate parts of the callstack. Instead, we provide None as a frame, which will cause the debugger to start at the deepest frame, which is the desired behavior here. --- IPython/core/ultratb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 3b97a82dd8d..78a4b3bf2c3 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1203,7 +1203,7 @@ def debugger(self, force=False): if etb and etb.tb_next: etb = etb.tb_next self.pdb.botframe = etb.tb_frame - self.pdb.interaction(self.tb.tb_frame, self.tb) + self.pdb.interaction(None, etb) if hasattr(self, 'tb'): del self.tb From 91ed424ecf22bf0d695feda22d44c2fc4c458858 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 21 Sep 2018 09:32:59 +0200 Subject: [PATCH 003/635] Allow anyone to tag/untag/close issues. This is (usually) reserved to people having commit right. I'm hopping to foster participation by giving people the ability to triage issue. --- .meeseeksdev.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .meeseeksdev.yml diff --git a/.meeseeksdev.yml b/.meeseeksdev.yml new file mode 100644 index 00000000000..56c33f87084 --- /dev/null +++ b/.meeseeksdev.yml @@ -0,0 +1,17 @@ +special: + everyone: + can: + - say + - tag + - untag + - close + config: + tag: + only: + - async/await + - backported + - help wanted + - documentation + - notebook + - tab-completion + - windows From 8af2a3f0f5ee7ad11b244dbbe6afb2d4031d8e3d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 23 Sep 2018 07:44:58 -0700 Subject: [PATCH 004/635] add info to contributing.md --- CONTRIBUTING.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 752486042b3..348425622ec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,31 @@ +## Triaging Issues + +On the IPython repository we strive to trust users and give them responsibility, +this is why than to one of our bot, any user can close issues, add and remove +labels by mentioning the bot and asking it to do things on your behalf. + +To close and issue (or PR), even if it is not your, use the following: + +> @meeseeksdev close + +This command can be in the middle of another comments, but must start a line. + +To add labels to an issue, as the bot to `tag` with a comma separated list of +tags to add: + +> @meeseeksdev tag windows, documentation + +Only already pre-created tags can be added, and the list is so far limitted to `async/await`, +`backported`, `help wanted`, `documentation`, `notebook`, `tab-completion`, `windows` + +To remove a label, use the `untag` command: + +> @meeseeksdev untag windows, documentation + +The list of commands that the bot can do is larger and we'll be experimenting +with what is possible. + + ## Opening an Issue When opening a new Issue, please take the following steps: From 3f86a49722008fd1d85f9c5c5f0d108ed1d70c1e Mon Sep 17 00:00:00 2001 From: hongshaoyang Date: Tue, 25 Sep 2018 22:27:07 +0800 Subject: [PATCH 005/635] Fix #11309 handles spaces or quotes in filename param --- IPython/core/magics/osm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 7e87b973ad2..033805ec70c 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -776,8 +776,9 @@ def writefile(self, line, cell): The file will be overwritten unless the -a (--append) flag is specified. """ + line = line if len(line.split())==1 else '"%s"' % line args = magic_arguments.parse_argstring(self.writefile, line) - filename = os.path.expanduser(args.filename) + filename = os.path.expanduser(args.filename.strip("\"\'")) if os.path.exists(filename): if args.append: From 90276eba1706957dc7e2bb48fba7d952dc6d6b50 Mon Sep 17 00:00:00 2001 From: hongshaoyang Date: Tue, 25 Sep 2018 22:40:31 +0800 Subject: [PATCH 006/635] Update osm.py --- IPython/core/magics/osm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 033805ec70c..f835361a4cf 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -776,7 +776,7 @@ def writefile(self, line, cell): The file will be overwritten unless the -a (--append) flag is specified. """ - line = line if len(line.split())==1 else '"%s"' % line + line = line if len(line.split())==1 else '"%s"' % line.strip("\"\'") args = magic_arguments.parse_argstring(self.writefile, line) filename = os.path.expanduser(args.filename.strip("\"\'")) From e870179290db5ccf1ced8340c136a0ce79735d8b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 25 Sep 2018 09:31:58 -0700 Subject: [PATCH 007/635] re-add the rprint and rprinte alias. They are used in IPykernel 4.9 and I can see users upgrading IPython w/o upgrading Ipykernel. --- IPython/utils/io.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IPython/utils/io.py b/IPython/utils/io.py index 3b518f2f54e..b59a1a11606 100644 --- a/IPython/utils/io.py +++ b/IPython/utils/io.py @@ -235,6 +235,11 @@ def raw_print_err(*args, **kw): file=sys.__stderr__) sys.__stderr__.flush() +# used by IPykernel <- 4.9. Removed during IPython 7-dev period and re-added +# Keep for a version or two then should remove +rprint = raw_print +rprinte = raw_print_err + @undoc def unicode_std_stream(stream='stdout'): """DEPRECATED, moved to nbconvert.utils.io""" From 82d5940ac2bc1a76b762156310df668c40d71412 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 26 Sep 2018 14:27:35 -0700 Subject: [PATCH 008/635] Take into account Carol Suggestions --- CONTRIBUTING.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 348425622ec..60a0bd2c1be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,30 +1,31 @@ ## Triaging Issues -On the IPython repository we strive to trust users and give them responsibility, -this is why than to one of our bot, any user can close issues, add and remove +On the IPython repository we strive to trust users and give them responsibility. +By using one of our bot, any user can close issues, add and remove labels by mentioning the bot and asking it to do things on your behalf. -To close and issue (or PR), even if it is not your, use the following: +To close and issue (or PR), even if you did not create it, use the following: > @meeseeksdev close -This command can be in the middle of another comments, but must start a line. +This command can be in the middle of another comments, but must start on its +own line. -To add labels to an issue, as the bot to `tag` with a comma separated list of +To add labels to an issue, ask the bot to `tag` with a comma separated list of tags to add: > @meeseeksdev tag windows, documentation -Only already pre-created tags can be added, and the list is so far limitted to `async/await`, -`backported`, `help wanted`, `documentation`, `notebook`, `tab-completion`, `windows` +Only already pre-created tags can be added, and the list is so far limited to +`async/await`, `backported`, `help wanted`, `documentation`, `notebook`, +`tab-completion`, `windows` To remove a label, use the `untag` command: > @meeseeksdev untag windows, documentation -The list of commands that the bot can do is larger and we'll be experimenting -with what is possible. - +e'll be adding additional capabilities for the bot and will share them here +when they are ready to be used. ## Opening an Issue @@ -39,8 +40,8 @@ When opening a new Issue, please take the following steps: python -c "import IPython; print(IPython.sys_info())" - And include any relevant package versions, depending on the issue, - such as matplotlib, numpy, Qt, Qt bindings (PyQt/PySide), tornado, web browser, etc. + And include any relevant package versions, depending on the issue, such as + matplotlib, numpy, Qt, Qt bindings (PyQt/PySide), tornado, web browser, etc. ## Pull Requests From 4030de4e0eb2da391f240899acdf1a70e7dd58fe Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 27 Sep 2018 08:04:48 -0700 Subject: [PATCH 009/635] back to development --- IPython/core/release.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 040948907fb..3e69c6fea3c 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -20,11 +20,11 @@ # release. 'dev' as a _version_extra string means this is a development # version _version_major = 7 -_version_minor = 0 +_version_minor = 1 _version_patch = 0 _version_extra = '.dev' # _version_extra = 'b1' -_version_extra = '' # Uncomment this for full releases +# _version_extra = '' # Uncomment this for full releases # Construct full version string from these. _ver = [_version_major, _version_minor, _version_patch] From 9d8832490689fe3d23a4d174ac5f7fa0376c4950 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 27 Sep 2018 08:56:22 -0700 Subject: [PATCH 010/635] Use readthedocs.yaml file as we need a recent version of sphinx --- docs/environment.yml | 11 +++++++++++ readthedocs.yml | 4 ++++ 2 files changed, 15 insertions(+) create mode 100644 docs/environment.yml create mode 100644 readthedocs.yml diff --git a/docs/environment.yml b/docs/environment.yml new file mode 100644 index 00000000000..3ccce04ca68 --- /dev/null +++ b/docs/environment.yml @@ -0,0 +1,11 @@ +name: ipython_docs +dependencies: +- python=3.6 +- setuptools>=18.5 +- sphinx>=1.8 +- sphinx_rtd_theme +- pip: + - docrepr + - prompt_toolkit + - ipython + - ipykernel diff --git a/readthedocs.yml b/readthedocs.yml new file mode 100644 index 00000000000..b9eadb806d6 --- /dev/null +++ b/readthedocs.yml @@ -0,0 +1,4 @@ +conda: + file: docs/environment.yml +python: + version: 3 From 3772d25dfddfd7abe76b602b6c636534996e0a8c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 27 Sep 2018 10:07:21 -0700 Subject: [PATCH 011/635] release 7.0.1 --- IPython/core/release.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 3e69c6fea3c..2daaccb9514 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -20,11 +20,11 @@ # release. 'dev' as a _version_extra string means this is a development # version _version_major = 7 -_version_minor = 1 -_version_patch = 0 +_version_minor = 0 +_version_patch = 1 _version_extra = '.dev' # _version_extra = 'b1' -# _version_extra = '' # Uncomment this for full releases +_version_extra = '' # Uncomment this for full releases # Construct full version string from these. _ver = [_version_major, _version_minor, _version_patch] From 43b46e55c5de7061d09d9657126c54ec57defb14 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 27 Sep 2018 10:08:14 -0700 Subject: [PATCH 012/635] back to dev --- IPython/core/release.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 2daaccb9514..3e69c6fea3c 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -20,11 +20,11 @@ # release. 'dev' as a _version_extra string means this is a development # version _version_major = 7 -_version_minor = 0 -_version_patch = 1 +_version_minor = 1 +_version_patch = 0 _version_extra = '.dev' # _version_extra = 'b1' -_version_extra = '' # Uncomment this for full releases +# _version_extra = '' # Uncomment this for full releases # Construct full version string from these. _ver = [_version_major, _version_minor, _version_patch] From 3b5e237f8fc96a359676d67e8d19ce9f615577a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roy=20Wellington=20=E2=85=A3?= Date: Fri, 28 Sep 2018 11:49:03 -0700 Subject: [PATCH 013/635] Touch up the grammar & wording on the shortcuts documentation --- docs/source/config/shortcuts/index.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/config/shortcuts/index.rst b/docs/source/config/shortcuts/index.rst index 29088f6d19e..4103d92a7bd 100755 --- a/docs/source/config/shortcuts/index.rst +++ b/docs/source/config/shortcuts/index.rst @@ -2,12 +2,12 @@ IPython shortcuts ================= -Available shortcut in IPython terminal. +Available shortcuts in an IPython terminal. .. warning:: - This list is automatically generated, and may not hold all the available - shortcut. In particular, it may depends on the version of ``prompt_toolkit`` + This list is automatically generated, and may not hold all available + shortcuts. In particular, it may depend on the version of ``prompt_toolkit`` installed during the generation of this page. @@ -22,7 +22,7 @@ Single Filtered shortcuts Multi Filtered shortcuts -========================= +======================== .. csv-table:: :header: Shortcut,Filter,Description From 84f64e5856817cf8923d0b02f20febda3ce646a0 Mon Sep 17 00:00:00 2001 From: Emil Hessman Date: Sat, 29 Sep 2018 19:00:51 +0200 Subject: [PATCH 014/635] Avoid modifying mutable default value --- IPython/extensions/autoreload.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/extensions/autoreload.py b/IPython/extensions/autoreload.py index 306bb8bd26a..ca6be10f35c 100644 --- a/IPython/extensions/autoreload.py +++ b/IPython/extensions/autoreload.py @@ -338,7 +338,7 @@ def __call__(self): return self.obj -def superreload(module, reload=reload, old_objects={}): +def superreload(module, reload=reload, old_objects=None): """Enhanced version of the builtin reload function. superreload remembers objects previously in the module, and @@ -348,6 +348,8 @@ def superreload(module, reload=reload, old_objects={}): - clears the module's namespace before reloading """ + if old_objects is None: + old_objects = {} # collect old objects in the module for name, obj in list(module.__dict__.items()): From 65eaef68a5a2689c60a38daf09ea4b3a7a2bc599 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Mon, 1 Oct 2018 21:38:28 +0900 Subject: [PATCH 015/635] Fix #9343: warn when using HTML instead of IFrame --- IPython/core/display.py | 5 +++++ IPython/core/tests/test_display.py | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/IPython/core/display.py b/IPython/core/display.py index ca5c3aa5b86..4a2e2817910 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -666,6 +666,11 @@ def _repr_pretty_(self, pp, cycle): class HTML(TextDisplayObject): + def __init__(self, data=None, url=None, filename=None, metadata=None): + if data and "') + m_warn.assert_called_with('Consider using IPython.display.IFrame instead') + def test_progress(): p = display.ProgressBar(10) nt.assert_in('0/10',repr(p)) From 19c262a992dbee6d9250e3b117b5d4e1a5820828 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Mon, 1 Oct 2018 22:15:36 +0900 Subject: [PATCH 016/635] Fix #9227: add documentation to integration tutorial --- docs/source/config/integrating.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/source/config/integrating.rst b/docs/source/config/integrating.rst index 1da4960700f..ded720fee19 100644 --- a/docs/source/config/integrating.rst +++ b/docs/source/config/integrating.rst @@ -65,6 +65,21 @@ There are also two more powerful display methods: Displays the object as a side effect; the return value is ignored. If this is defined, all other display methods are ignored. +To customize how the REPL pretty-prints your object, add a `_repr_pretty_` +method to the class. The method should accept a pretty printer, and a boolean +that indicates whether the printer detected a cycle. The method should act on +the printer to produce your customized pretty output. Here is an example:: + + class MyObject(object): + + def _repr_pretty_(self, p, cycle): + if cycle: + p.text('MyObject(...)') + else: + p.text('MyObject[...]') + +For details, see :py:mod:`IPython.lib.pretty`. + Formatters for third-party types -------------------------------- From b1afef3a0567cd2831a18c584973bc99a68a6244 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Mon, 1 Oct 2018 22:37:18 +0900 Subject: [PATCH 017/635] Fix #10973: improve documentation for _repr_ functions --- IPython/core/display.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index ca5c3aa5b86..8cecd71b7a7 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -238,16 +238,22 @@ def display(*objs, include=None, exclude=None, metadata=None, transient=None, di want to use. Here is a list of the names of the special methods and the values they must return: - - `_repr_html_`: return raw HTML as a string - - `_repr_json_`: return a JSONable dict - - `_repr_jpeg_`: return raw JPEG data - - `_repr_png_`: return raw PNG data - - `_repr_svg_`: return raw SVG data as a string - - `_repr_latex_`: return LaTeX commands in a string surrounded by "$". + - `_repr_html_`: return raw HTML as a string, or a tuple (see below). + - `_repr_json_`: return a JSONable dict, or a tuple (see below). + - `_repr_jpeg_`: return raw JPEG data, or a tuple (see below). + - `_repr_png_`: return raw PNG data, or a tuple (see below). + - `_repr_svg_`: return raw SVG data as a string, or a tuple (see below). + - `_repr_latex_`: return LaTeX commands in a string surrounded by "$", + or a tuple (see below). - `_repr_mimebundle_`: return a full mimebundle containing the mapping from all mimetypes to data. Use this for any mime-type not listed above. + The above functions may also return the object's metadata alonside the + data. If the metadata is available, the functions will return a tuple + containing the data and metadata, in that order. If there is no metadata + available, then the functions will return the data only. + When you are directly writing your own classes, you can adapt them for display in IPython by following the above approach. But in practice, you often need to work with existing classes that you can't easily modify. From 211ca17805a5febfbeb08abb242b523d862c568c Mon Sep 17 00:00:00 2001 From: Dominic Kuang Date: Mon, 1 Oct 2018 13:42:44 -0700 Subject: [PATCH 018/635] Add support for width and height arguments when displaying Video Closes #11328 --- IPython/core/display.py | 27 ++++++++++++++----- .../source/whatsnew/pr/video-width-height.rst | 1 + 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 docs/source/whatsnew/pr/video-width-height.rst diff --git a/IPython/core/display.py b/IPython/core/display.py index ca5c3aa5b86..4123c4d69f5 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -1256,7 +1256,8 @@ def _find_ext(self, s): class Video(DisplayObject): - def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None): + def __init__(self, data=None, url=None, filename=None, embed=False, + mimetype=None, width=None, height=None): """Create a video object given raw data or an URL. When this object is returned by an input cell or passed to the @@ -1288,6 +1289,12 @@ def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=Non mimetype: unicode Specify the mimetype for embedded videos. Default will be guessed from file extension, if available. + width : int + Width in pixels to which to constrain the video in HTML. + If not supplied, defaults to the width of the video. + height : int + Height in pixels to which to constrain the video in html. + If not supplied, defaults to the height of the video. Examples -------- @@ -1314,16 +1321,24 @@ def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=Non self.mimetype = mimetype self.embed = embed + self.width = width + self.height = height super(Video, self).__init__(data=data, url=url, filename=filename) def _repr_html_(self): + width = height = '' + if self.width: + width = ' width="%d"' % self.width + if self.height: + height = ' height="%d"' % self.height + # External URLs and potentially local files are not embedded into the # notebook output. if not self.embed: url = self.url if self.url is not None else self.filename - output = """""".format(url, width, height) return output # Embedded videos are base64-encoded. @@ -1342,10 +1357,10 @@ def _repr_html_(self): else: b64_video = b2a_base64(video).decode('ascii').rstrip() - output = """""".format(width, height, mimetype, b64_video) return output def reload(self): diff --git a/docs/source/whatsnew/pr/video-width-height.rst b/docs/source/whatsnew/pr/video-width-height.rst new file mode 100644 index 00000000000..84757f1b430 --- /dev/null +++ b/docs/source/whatsnew/pr/video-width-height.rst @@ -0,0 +1 @@ +``IPython.display.Video`` now supports ``width`` and ``height`` arguments, allowing a custom width and height to be set instead of using the video's width and height \ No newline at end of file From a6c064a0825fe6698eb624dbba564c2d5f3a5803 Mon Sep 17 00:00:00 2001 From: Bart Skowron Date: Tue, 2 Oct 2018 00:34:38 +0200 Subject: [PATCH 019/635] Fix #11334: Cannot make multi-line code blocks in ipython When codeop.compile_command() returns None it actually says "at least some part of the code was compiled successfully" which is not really important for checking if it's complete or not. Once we haven't got any errors during compilation process, we just want to check if there will be another nested block of code or not by checking a colon. --- IPython/core/inputtransformer2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 1abd2cf95cb..3c992d81046 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -636,7 +636,7 @@ def check_complete(self, cell: str): MemoryError, SyntaxWarning): return 'invalid', None else: - if res is None: + if not lines[-1].strip().endswith(':'): return 'incomplete', find_last_indent(lines) return 'complete', None From 0a42b8611675af719577fa2fa85ea9ddfa720452 Mon Sep 17 00:00:00 2001 From: Bart Skowron Date: Tue, 2 Oct 2018 01:30:28 +0200 Subject: [PATCH 020/635] Fix regression... --- IPython/core/inputtransformer2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 3c992d81046..63cf1d77dee 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -636,7 +636,7 @@ def check_complete(self, cell: str): MemoryError, SyntaxWarning): return 'invalid', None else: - if not lines[-1].strip().endswith(':'): + if len(lines) > 1 and not lines[-1].strip().endswith(':'): return 'incomplete', find_last_indent(lines) return 'complete', None From fde3f770a84f1815a47aa5f5a05c0622a7867b1a Mon Sep 17 00:00:00 2001 From: Bart Skowron Date: Tue, 2 Oct 2018 02:10:35 +0200 Subject: [PATCH 021/635] Add a new regression test and fix for it --- IPython/core/inputtransformer2.py | 3 ++- IPython/core/tests/test_inputtransformer2.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 63cf1d77dee..afe0e002dff 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -636,7 +636,8 @@ def check_complete(self, cell: str): MemoryError, SyntaxWarning): return 'invalid', None else: - if len(lines) > 1 and not lines[-1].strip().endswith(':'): + if len(lines) > 1 and not lines[-1].strip().endswith(':') \ + and not lines[-2][:-1].endswith('\\'): return 'incomplete', find_last_indent(lines) return 'complete', None diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index f78a0b37158..d1ef3dff42b 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -206,6 +206,7 @@ def test_check_complete(): nt.assert_equal(cc("a = '''\n hi"), ('incomplete', 3)) nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None)) nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash + nt.assert_equal(cc("1\\\n+2"), ('complete', None)) # no need to loop on all the letters/numbers. short = '12abAB'+string.printable[62:] From d0cad1f760c8e203dc4930fe6d2dffe1baeb33eb Mon Sep 17 00:00:00 2001 From: Bart Skowron Date: Tue, 2 Oct 2018 02:11:06 +0200 Subject: [PATCH 022/635] Remove unused assignment --- IPython/core/inputtransformer2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index afe0e002dff..ac76f05e93c 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -631,7 +631,7 @@ def check_complete(self, cell: str): try: with warnings.catch_warnings(): warnings.simplefilter('error', SyntaxWarning) - res = compile_command(''.join(lines), symbol='exec') + compile_command(''.join(lines), symbol='exec') except (SyntaxError, OverflowError, ValueError, TypeError, MemoryError, SyntaxWarning): return 'invalid', None From d4f41859f3d9080e99ac607a7f589e67c9805fd3 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Tue, 2 Oct 2018 00:03:58 -0400 Subject: [PATCH 023/635] Fix an IndexError in leading_indent --- IPython/core/inputtransformer2.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 1abd2cf95cb..c9aff48a53a 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -24,6 +24,8 @@ def leading_indent(lines): If the first line starts with a spaces or tabs, the same whitespace will be removed from each following line in the cell. """ + if not lines: + return lines m = _indent_re.match(lines[0]) if not m: return lines From 8b13c4b7353c3a2bdcddd27907ba3a50202baaec Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Tue, 2 Oct 2018 14:14:45 -0400 Subject: [PATCH 024/635] Add tests for null cleanup test. --- IPython/core/tests/test_inputtransformer2.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index f78a0b37158..77df22c2c22 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -101,6 +101,12 @@ [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"] ) +def null_cleanup_transformer(lines): + """ + A cleanup transform that returns an empty list. + """ + return [] + def check_make_token_by_line_never_ends_empty(): """ Check that not sequence of single or double characters ends up leading to en empty list of tokens @@ -215,3 +221,7 @@ def test_check_complete(): for k in short: cc(c+k) +def test_null_cleanup_transformer(): + manager = ipt2.TransformerManager() + manager.cleanup_transforms.insert(0, null_cleanup_transformer) + nt.assert_is(manager.transform_cell(""), "") From 5b3ce918a77bb16ec52b3097f4b3611b8847fa95 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Tue, 2 Oct 2018 14:14:57 -0400 Subject: [PATCH 025/635] Include empty lines condition in PromptStipper and cell_magic. --- IPython/core/inputtransformer2.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index c9aff48a53a..0a01100398d 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -20,11 +20,11 @@ def leading_indent(lines): """Remove leading indentation. - + If the first line starts with a spaces or tabs, the same whitespace will be removed from each following line in the cell. """ - if not lines: + if not lines: return lines m = _indent_re.match(lines[0]) if not m: @@ -36,7 +36,7 @@ def leading_indent(lines): class PromptStripper: """Remove matching input prompts from a block of input. - + Parameters ---------- prompt_re : regular expression @@ -47,7 +47,7 @@ class PromptStripper: If no initial expression is given, prompt_re will be used everywhere. Used mainly for plain Python prompts (``>>>``), where the continuation prompt ``...`` is a valid Python expression in Python 3, so shouldn't be stripped. - + If initial_re and prompt_re differ, only initial_re will be tested against the first line. If any prompt is found on the first two lines, @@ -61,6 +61,8 @@ def _strip(self, lines): return [self.prompt_re.sub('', l, count=1) for l in lines] def __call__(self, lines): + if not lines: + return lines if self.initial_re.match(lines[0]) or \ (len(lines) > 1 and self.prompt_re.match(lines[1])): return self._strip(lines) @@ -74,7 +76,7 @@ def __call__(self, lines): ipython_prompt = PromptStripper(re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)')) def cell_magic(lines): - if not lines[0].startswith('%%'): + if not lines or not lines[0].startswith('%%'): return lines if re.match('%%\w+\?', lines[0]): # This case will be handled by help_end @@ -94,7 +96,7 @@ def _find_assign_op(token_line): for i, ti in enumerate(token_line): s = ti.string if s == '=' and paren_level == 0: - return i + return i if s in '([{': paren_level += 1 elif s in ')]}': @@ -114,7 +116,7 @@ def find_end_of_continued_line(lines, start_line: int): return end_line def assemble_continued_line(lines, start: Tuple[int, int], end_line: int): - """Assemble a single line from multiple continued line pieces + """Assemble a single line from multiple continued line pieces Continued lines are lines ending in ``\``, and the line following the last ``\`` in the block. @@ -204,7 +206,7 @@ def find(cls, tokens_by_line): and (line[assign_ix+1].string == '%') \ and (line[assign_ix+2].type == tokenize.NAME): return cls(line[assign_ix+1].start) - + def transform(self, lines: List[str]): """Transform a magic assignment found by the ``find()`` classmethod. """ @@ -214,12 +216,12 @@ def transform(self, lines: List[str]): rhs = assemble_continued_line(lines, (start_line, start_col), end_line) assert rhs.startswith('%'), rhs magic_name, _, args = rhs[1:].partition(' ') - + lines_before = lines[:start_line] call = "get_ipython().run_line_magic({!r}, {!r})".format(magic_name, args) new_line = lhs + call + '\n' lines_after = lines[end_line+1:] - + return lines_before + [new_line] + lines_after @@ -466,7 +468,7 @@ def make_tokens_by_line(lines): pass if not tokens_by_line[-1]: tokens_by_line.pop() - + return tokens_by_line def show_linewise_tokens(s: str): @@ -503,12 +505,12 @@ def __init__(self): EscapedCommand, HelpEnd, ] - + def do_one_token_transform(self, lines): """Find and run the transform earliest in the code. - + Returns (changed, lines). - + This method is called repeatedly until changed is False, indicating that all available transformations are complete. From 5130108723256e656cc4f242e27f3164e28719f1 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Thu, 20 Sep 2018 18:29:19 +0200 Subject: [PATCH 026/635] Math display: change $$...$$ -> $\displaystyle ...$ --- IPython/core/display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 8cecd71b7a7..8d386277e9a 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -693,7 +693,7 @@ def _repr_markdown_(self): class Math(TextDisplayObject): def _repr_latex_(self): - s = "$$%s$$" % self.data.strip('$') + s = "$\displaystyle %s$" % self.data.strip('$') if self.metadata: return s, deepcopy(self.metadata) else: From 043b67794072c99746677d9431e97b01551c21ff Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 3 Oct 2018 10:29:46 -0700 Subject: [PATCH 027/635] add tests --- IPython/core/tests/test_inputtransformer2.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index d1ef3dff42b..28e0458fc20 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -10,6 +10,8 @@ from IPython.core import inputtransformer2 as ipt2 from IPython.core.inputtransformer2 import make_tokens_by_line +from textwrap import dedent + MULTILINE_MAGIC = ("""\ a = f() %foo \\ @@ -208,6 +210,14 @@ def test_check_complete(): nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash nt.assert_equal(cc("1\\\n+2"), ('complete', None)) + example = dedent(""" + if True: + a=1""" ) + + nt.assert_equal(cc(example), ('incomplete', 4)) + nt.assert_equal(cc(example+'\n'), ('complete', None)) + nt.assert_equal(cc(example+'\n '), ('complete', None)) + # no need to loop on all the letters/numbers. short = '12abAB'+string.printable[62:] for c in short: From 498f5f716d102a572cac3571e13426aa002f8454 Mon Sep 17 00:00:00 2001 From: Bart Skowron Date: Thu, 4 Oct 2018 00:26:28 +0200 Subject: [PATCH 028/635] always add a trailing newline --- IPython/core/inputtransformer2.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index ac76f05e93c..2c44ee11c01 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -571,8 +571,7 @@ def check_complete(self, cell: str): The number of spaces by which to indent the next line of code. If status is not 'incomplete', this is None. """ - if not cell.endswith('\n'): - cell += '\n' # Ensure the cell has a trailing newline + cell += '\n' # Ensure the cell has a trailing newline lines = cell.splitlines(keepends=True) if lines[-1][:-1].endswith('\\'): # Explicit backslash continuation From 186524bc08716d9457d0a4c45d2d33fb58482427 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Wed, 3 Oct 2018 21:53:13 -0400 Subject: [PATCH 029/635] Add some logic to pass all of the check_complete tests An assert statement needed to be commented out. I'm not sure what the statement was stating though. --- IPython/core/inputtransformer2.py | 49 ++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 503bbc1b321..d53f702a9a4 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -253,7 +253,7 @@ def transform(self, lines: List[str]): lhs = lines[start_line][:start_col] end_line = find_end_of_continued_line(lines, start_line) rhs = assemble_continued_line(lines, (start_line, start_col), end_line) - assert rhs.startswith('!'), rhs + # assert rhs.startswith('!'), rhs cmd = rhs[1:] lines_before = lines[:start_line] @@ -369,11 +369,15 @@ def transform(self, lines): end_line = find_end_of_continued_line(lines, start_line) line = assemble_continued_line(lines, (start_line, start_col), end_line) - if line[:2] in ESCAPE_DOUBLES: + if len(line) > 1 and line[:2] in ESCAPE_DOUBLES: escape, content = line[:2], line[2:] else: escape, content = line[:1], line[1:] - call = tr[escape](content) + + if escape in tr: + call = tr[escape](content) + else: + call = '' lines_before = lines[:start_line] new_line = indent + call + '\n' @@ -575,9 +579,11 @@ def check_complete(self, cell: str): The number of spaces by which to indent the next line of code. If status is not 'incomplete', this is None. """ - cell += '\n' # Ensure the cell has a trailing newline lines = cell.splitlines(keepends=True) - if lines[-1][:-1].endswith('\\'): + if not lines: + return 'complete', None + + if lines[-1].endswith('\\'): # Explicit backslash continuation return 'incomplete', find_last_indent(lines) @@ -604,44 +610,53 @@ def check_complete(self, cell: str): tokens_by_line = make_tokens_by_line(lines) if not tokens_by_line: return 'incomplete', find_last_indent(lines) + if tokens_by_line[-1][-1].type != tokenize.ENDMARKER: # We're in a multiline string or expression return 'incomplete', find_last_indent(lines) - if len(tokens_by_line) == 1: + + if len(tokens_by_line[-1]) == 1: return 'incomplete', find_last_indent(lines) # Find the last token on the previous line that's not NEWLINE or COMMENT - toks_last_line = tokens_by_line[-2] - ix = len(toks_last_line) - 1 - while ix >= 0 and toks_last_line[ix].type in {tokenize.NEWLINE, + toks_last_line = tokens_by_line[-1] + ix = len(tokens_by_line) - 1 + + + while ix >= 0 and toks_last_line[-1].type in {tokenize.NEWLINE, tokenize.COMMENT}: ix -= 1 - - if toks_last_line[ix].string == ':': + if tokens_by_line[ix][-2].string == ':': # The last line starts a block (e.g. 'if foo:') ix = 0 while toks_last_line[ix].type in {tokenize.INDENT, tokenize.DEDENT}: ix += 1 indent = toks_last_line[ix].start[1] return 'incomplete', indent + 4 + if tokens_by_line[ix][-2].string == '\\': + if not tokens_by_line[ix][-2].line.endswith('\\'): + return 'invalid', None - # If there's a blank line at the end, assume we're ready to execute. + # If there's a blank line at the end, assume we're ready to execute if not lines[-1].strip(): return 'complete', None # At this point, our checks think the code is complete (or invalid). - # We'll use codeop.compile_command to check this with the real parser. - + # We'll use codeop.compile_command to check this with the real parser try: with warnings.catch_warnings(): warnings.simplefilter('error', SyntaxWarning) - compile_command(''.join(lines), symbol='exec') + res = compile_command(''.join(lines), symbol='exec') except (SyntaxError, OverflowError, ValueError, TypeError, MemoryError, SyntaxWarning): return 'invalid', None else: - if len(lines) > 1 and not lines[-1].strip().endswith(':') \ - and not lines[-2][:-1].endswith('\\'): + if res is None: return 'incomplete', find_last_indent(lines) + + if toks_last_line[-2].type == tokenize.DEDENT: + if not lines[-1].endswith('\n'): + return 'incomplete', find_last_indent(lines) + return 'complete', None From 51d59bbbbe086ed93bbce430190a8cccfec17630 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Wed, 3 Oct 2018 23:46:06 -0400 Subject: [PATCH 030/635] Use tokenize.NL and tokenize.NEWLINE in the check_complete logic These changes are necessary for a failure on Python 3.7 dev https://bugs.python.org/issue33899 --- IPython/core/inputtransformer2.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index d53f702a9a4..64813ec7144 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -653,6 +653,9 @@ def check_complete(self, cell: str): if res is None: return 'incomplete', find_last_indent(lines) + if toks_last_line[-2].type in {tokenize.NEWLINE, tokenize.NL}: + return 'complete', None + if toks_last_line[-2].type == tokenize.DEDENT: if not lines[-1].endswith('\n'): return 'incomplete', find_last_indent(lines) From 4fdf684c44f2e0e087d064399dd33014ab1061c1 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Thu, 4 Oct 2018 10:28:41 -0400 Subject: [PATCH 031/635] Add 3.6-dev to the test. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 09e16146476..cf184a9d993 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ after_success: matrix: include: + - { python: "3.6-dev", dist: xenial, sudo: true } - { python: "3.7", dist: xenial, sudo: true } - { python: "3.7-dev", dist: xenial, sudo: true } - { python: "nightly", dist: xenial, sudo: true } From 06f2f2d39feb67e1cf92d0fe75150c3e2423562f Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Thu, 4 Oct 2018 23:30:51 -0400 Subject: [PATCH 032/635] A refactor to check_complete to pass the test cases. --- IPython/core/inputtransformer2.py | 69 +++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 64813ec7144..7be401f1175 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -470,9 +470,12 @@ def make_tokens_by_line(lines): except tokenize.TokenError: # Input ended in a multiline string or expression. That's OK for us. pass + + if not tokens_by_line[-1]: tokens_by_line.pop() + return tokens_by_line def show_linewise_tokens(s: str): @@ -579,7 +582,24 @@ def check_complete(self, cell: str): The number of spaces by which to indent the next line of code. If status is not 'incomplete', this is None. """ + # Remember if the lines ends in a new line. + ends_with_newline = False + for character in reversed(cell): + if character == '\n': + ends_with_newline = True + break + elif character.strip(): + break + else: + continue + + if ends_with_newline: + # Append an newline for consistent tokenization + # See https://bugs.python.org/issue33899 + cell += '\n' + lines = cell.splitlines(keepends=True) + if not lines: return 'complete', None @@ -608,6 +628,7 @@ def check_complete(self, cell: str): return 'invalid', None tokens_by_line = make_tokens_by_line(lines) + if not tokens_by_line: return 'incomplete', find_last_indent(lines) @@ -615,30 +636,33 @@ def check_complete(self, cell: str): # We're in a multiline string or expression return 'incomplete', find_last_indent(lines) - if len(tokens_by_line[-1]) == 1: - return 'incomplete', find_last_indent(lines) - # Find the last token on the previous line that's not NEWLINE or COMMENT - toks_last_line = tokens_by_line[-1] - ix = len(tokens_by_line) - 1 + newline_types = {tokenize.NEWLINE, tokenize.COMMENT, tokenize.ENDMARKER} + + # Remove newline_types for the list of tokens + while len(tokens_by_line) > 1 and len(tokens_by_line[-1]) == 1 \ + and tokens_by_line[-1][-1].type in newline_types: + tokens_by_line.pop() + last_line_token = tokens_by_line[-1] - while ix >= 0 and toks_last_line[-1].type in {tokenize.NEWLINE, - tokenize.COMMENT}: - ix -= 1 - if tokens_by_line[ix][-2].string == ':': + while tokens_by_line[-1][-1].type in newline_types: + last_line_token = tokens_by_line[-1].pop() + + if len(last_line_token) == 1 and not last_line_token[-1]: + return 'incomplete', 0 + + if last_line_token[-1].string == ':': # The last line starts a block (e.g. 'if foo:') ix = 0 - while toks_last_line[ix].type in {tokenize.INDENT, tokenize.DEDENT}: + while last_line_token[ix].type \ + in {tokenize.INDENT, tokenize.DEDENT}: ix += 1 - indent = toks_last_line[ix].start[1] + + indent = last_line_token[ix].start[1] return 'incomplete', indent + 4 - if tokens_by_line[ix][-2].string == '\\': - if not tokens_by_line[ix][-2].line.endswith('\\'): - return 'invalid', None - # If there's a blank line at the end, assume we're ready to execute - if not lines[-1].strip(): - return 'complete', None + if last_line_token[-1].line.endswith('\\'): + return 'incomplete', None # At this point, our checks think the code is complete (or invalid). # We'll use codeop.compile_command to check this with the real parser @@ -653,12 +677,13 @@ def check_complete(self, cell: str): if res is None: return 'incomplete', find_last_indent(lines) - if toks_last_line[-2].type in {tokenize.NEWLINE, tokenize.NL}: - return 'complete', None + if last_line_token[-1].type == tokenize.DEDENT: + if ends_with_newline: + return 'complete', None + return 'incomplete', find_last_indent(lines) - if toks_last_line[-2].type == tokenize.DEDENT: - if not lines[-1].endswith('\n'): - return 'incomplete', find_last_indent(lines) + if len(last_line_token) <= 1: + return 'incomplete', find_last_indent(lines) return 'complete', None From 246b492ec30bd240d58f03dc2f6176e3f0a1c213 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Thu, 4 Oct 2018 23:43:49 -0400 Subject: [PATCH 033/635] Fix check_complete with a more verbose approach. --- IPython/core/inputtransformer2.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 7be401f1175..fd7bc95a596 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -643,25 +643,23 @@ def check_complete(self, cell: str): and tokens_by_line[-1][-1].type in newline_types: tokens_by_line.pop() - last_line_token = tokens_by_line[-1] - while tokens_by_line[-1][-1].type in newline_types: - last_line_token = tokens_by_line[-1].pop() + while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types: + tokens_by_line[-1].pop() - if len(last_line_token) == 1 and not last_line_token[-1]: + if len(tokens_by_line) == 1 and not tokens_by_line[-1]: return 'incomplete', 0 - if last_line_token[-1].string == ':': + if tokens_by_line[-1][-1].string == ':': # The last line starts a block (e.g. 'if foo:') ix = 0 - while last_line_token[ix].type \ - in {tokenize.INDENT, tokenize.DEDENT}: + while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}: ix += 1 - indent = last_line_token[ix].start[1] + indent = tokens_by_line[-1][ix].start[1] return 'incomplete', indent + 4 - if last_line_token[-1].line.endswith('\\'): + if tokens_by_line[-1][0].line.endswith('\\'): return 'incomplete', None # At this point, our checks think the code is complete (or invalid). @@ -677,14 +675,18 @@ def check_complete(self, cell: str): if res is None: return 'incomplete', find_last_indent(lines) - if last_line_token[-1].type == tokenize.DEDENT: + if tokens_by_line[-1][-1].type == tokenize.DEDENT: if ends_with_newline: return 'complete', None return 'incomplete', find_last_indent(lines) - if len(last_line_token) <= 1: + if len(tokens_by_line[-1]) <= 1: return 'incomplete', find_last_indent(lines) + # If there's a blank line at the end, assume we're ready to execute + if not lines[-1].strip(): + return 'complete', None + return 'complete', None From 0407e91d9085587b84af622d15e48d5183e62a91 Mon Sep 17 00:00:00 2001 From: Kory Donati Date: Fri, 5 Oct 2018 14:01:43 -0700 Subject: [PATCH 034/635] added scandir and fixed how isexec is created --- IPython/core/magics/osm.py | 116 ++++++++++++++++++++++++------------- IPython/core/profileapp.py | 21 +++---- 2 files changed, 84 insertions(+), 53 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 7e87b973ad2..2bf8938977d 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -24,6 +24,7 @@ from IPython.utils.openpy import source_to_unicode from IPython.utils.process import abbrev_cwd from IPython.utils.terminal import set_term_title +from os import DirEntry @magics_class @@ -31,6 +32,51 @@ class OSMagics(Magics): """Magics to interact with the underlying OS (shell-type functionality). """ + def __init__(self, shell=None, **kwargs): + + # Now define isexec in a cross platform manner. + self.is_posix: bool = False + self.execre = None + if os.name == 'posix': + self.is_posix = True + else: + try: + winext = os.environ['pathext'].replace(';','|').replace('.','') + except KeyError: + winext = 'exe|com|bat|py' + + self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) + + # call up the chain + super(OSMagics, self).__init__(shell=shell, **kwargs) + + + @skip_doctest + def _isexec_POSIX(self, f:DirEntry) -> bool: + """ + Test for executible on a POSIX system + """ + return f.is_file() and os.access(f.path, os.X_OK) + + + @skip_doctest + def _isexec_WIN(self, f:DirEntry) -> int: + """ + Test for executible file on non POSIX system + """ + return f.is_file() and self.execre.match(f.name) is not None + + @skip_doctest + def isexec(self, f:DirEntry) -> bool: + """ + Test for executible file on non POSIX system + """ + if self.is_posix: + return self._isexec_POSIX(f) + else: + return self._isexec_WIN(f) + + @skip_doctest @line_magic def alias(self, parameter_s=''): @@ -160,19 +206,6 @@ def rehashx(self, parameter_s=''): os.environ.get('PATH','').split(os.pathsep)] syscmdlist = [] - # Now define isexec in a cross platform manner. - if os.name == 'posix': - isexec = lambda fname:os.path.isfile(fname) and \ - os.access(fname,os.X_OK) - else: - try: - winext = os.environ['pathext'].replace(';','|').replace('.','') - except KeyError: - winext = 'exe|com|bat|py' - if 'py' not in winext: - winext += '|py' - execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) - isexec = lambda fname:os.path.isfile(fname) and execre.match(fname) savedir = os.getcwd() # Now walk the paths looking for executables to alias. @@ -183,42 +216,44 @@ def rehashx(self, parameter_s=''): for pdir in path: try: os.chdir(pdir) - dirlist = os.listdir(pdir) except OSError: continue - for ff in dirlist: - if isexec(ff): - try: - # Removes dots from the name since ipython - # will assume names with dots to be python. - if not self.shell.alias_manager.is_alias(ff): - self.shell.alias_manager.define_alias( - ff.replace('.',''), ff) - except InvalidAliasError: - pass - else: - syscmdlist.append(ff) + with os.scandir(pdir) as dirlist: + for ff in dirlist: + if self.isexec(ff): + fname = ff.name + try: + # Removes dots from the name since ipython + # will assume names with dots to be python. + if not self.shell.alias_manager.is_alias(fname): + self.shell.alias_manager.define_alias( + fname.replace('.',''), fname) + except InvalidAliasError: + pass + else: + syscmdlist.append(fname) else: no_alias = Alias.blacklist for pdir in path: try: os.chdir(pdir) - dirlist = os.listdir(pdir) except OSError: continue - for ff in dirlist: - base, ext = os.path.splitext(ff) - if isexec(ff) and base.lower() not in no_alias: - if ext.lower() == '.exe': - ff = base - try: - # Removes dots from the name since ipython - # will assume names with dots to be python. - self.shell.alias_manager.define_alias( - base.lower().replace('.',''), ff) - except InvalidAliasError: - pass - syscmdlist.append(ff) + with os.scandir(pdir) as dirlist: + for ff in dirlist: + fname = ff.name + base, ext = os.path.splitext(fname) + if self.isexec(ff) and base.lower() not in no_alias: + if ext.lower() == '.exe': + fname = base + try: + # Removes dots from the name since ipython + # will assume names with dots to be python. + self.shell.alias_manager.define_alias( + base.lower().replace('.',''), fname) + except InvalidAliasError: + pass + syscmdlist.append(fname) self.shell.db['syscmdlist'] = syscmdlist finally: os.chdir(savedir) @@ -481,6 +516,7 @@ def dhist(self, parameter_s=''): dh = self.shell.user_ns['_dh'] if parameter_s: + args = [] try: args = map(int,parameter_s.split()) except: diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index 59282a2c111..700fcc7a008 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -96,27 +96,22 @@ def list_profiles_in(path): """list profiles in a given root directory""" - files = os.listdir(path) profiles = [] - for f in files: - try: - full_path = os.path.join(path, f) - except UnicodeError: - continue - if os.path.isdir(full_path) and f.startswith('profile_'): - profiles.append(f.split('_',1)[-1]) + with os.scandir(path) as files: + for f in files: + if f.is_dir() and f.name.startswith('profile_'): + profiles.append(f.name.split('_', 1)[-1]) return profiles def list_bundled_profiles(): """list profiles that are bundled with IPython.""" path = os.path.join(get_ipython_package_dir(), u'core', u'profile') - files = os.listdir(path) profiles = [] - for profile in files: - full_path = os.path.join(path, profile) - if os.path.isdir(full_path) and profile != "__pycache__": - profiles.append(profile) + with os.scandir(path) as files: + for profile in files: + if profile.is_dir() and profile.name != "__pycache__": + profiles.append(profile.name) return profiles From c11265e8456892eb8a2e0cf3b825127eab52c530 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Sat, 6 Oct 2018 10:41:45 -0400 Subject: [PATCH 035/635] Uncomment the ! assertion. Co-Authored-By: Nicholas Bollweg --- IPython/core/inputtransformer2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index fd7bc95a596..423c0fbf772 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -253,7 +253,7 @@ def transform(self, lines: List[str]): lhs = lines[start_line][:start_col] end_line = find_end_of_continued_line(lines, start_line) rhs = assemble_continued_line(lines, (start_line, start_col), end_line) - # assert rhs.startswith('!'), rhs + assert rhs.startswith('!'), rhs cmd = rhs[1:] lines_before = lines[:start_line] From f7642d4ecdcf172e6bcee5e6d8f23c259f8637c1 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Sat, 6 Oct 2018 11:47:04 -0400 Subject: [PATCH 036/635] Add an extra condition to SystemAssign. Co-Authored-By: Nicholas Bollweg --- IPython/core/inputtransformer2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 423c0fbf772..77b905c465d 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -234,6 +234,7 @@ def find(cls, tokens_by_line): for line in tokens_by_line: assign_ix = _find_assign_op(line) if (assign_ix is not None) \ + and not line[assign_ix].line.strip().startswith('=') \ and (len(line) >= assign_ix + 2) \ and (line[assign_ix + 1].type == tokenize.ERRORTOKEN): ix = assign_ix + 1 From 76599aed8f53e36c0ba30bb2f77433362ec24666 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Sat, 6 Oct 2018 12:18:39 -0400 Subject: [PATCH 037/635] Add check_complete test for exit. Co-Authored-By: Nicholas Bollweg --- IPython/core/tests/test_inputtransformer2.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index 839fe0e16c4..9c5a413955f 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -215,6 +215,8 @@ def test_check_complete(): nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None)) nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash nt.assert_equal(cc("1\\\n+2"), ('complete', None)) + nt.assert_equal(cc("1\\\n+2"), ('complete', None)) + nt.assert_equal(cc("exit"), ('complete', None)) example = dedent(""" if True: From bd7a4c2d4abf3e5b765cfc04eb7fde67fa6822ea Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Sat, 6 Oct 2018 12:32:44 -0400 Subject: [PATCH 038/635] Remove a condition from check_complete Co-Authored-By: Nicholas Bollweg --- IPython/core/inputtransformer2.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 77b905c465d..5777559fbd4 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -644,7 +644,6 @@ def check_complete(self, cell: str): and tokens_by_line[-1][-1].type in newline_types: tokens_by_line.pop() - while tokens_by_line[-1] and tokens_by_line[-1][-1].type in newline_types: tokens_by_line[-1].pop() @@ -681,9 +680,6 @@ def check_complete(self, cell: str): return 'complete', None return 'incomplete', find_last_indent(lines) - if len(tokens_by_line[-1]) <= 1: - return 'incomplete', find_last_indent(lines) - # If there's a blank line at the end, assume we're ready to execute if not lines[-1].strip(): return 'complete', None From d3d01a4b038de61169c5528211b9c60a7ac98c97 Mon Sep 17 00:00:00 2001 From: kd2718 Date: Sat, 6 Oct 2018 13:32:59 -0700 Subject: [PATCH 039/635] removed type hints to allow for python 3.5 support --- IPython/core/magics/osm.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 2bf8938977d..5fe268da4ba 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -24,7 +24,6 @@ from IPython.utils.openpy import source_to_unicode from IPython.utils.process import abbrev_cwd from IPython.utils.terminal import set_term_title -from os import DirEntry @magics_class @@ -35,7 +34,7 @@ class OSMagics(Magics): def __init__(self, shell=None, **kwargs): # Now define isexec in a cross platform manner. - self.is_posix: bool = False + self.is_posix = False self.execre = None if os.name == 'posix': self.is_posix = True @@ -52,29 +51,29 @@ def __init__(self, shell=None, **kwargs): @skip_doctest - def _isexec_POSIX(self, f:DirEntry) -> bool: + def _isexec_POSIX(self, file): """ Test for executible on a POSIX system """ - return f.is_file() and os.access(f.path, os.X_OK) + return file.is_file() and os.access(file.path, os.X_OK) @skip_doctest - def _isexec_WIN(self, f:DirEntry) -> int: + def _isexec_WIN(self, file): """ Test for executible file on non POSIX system """ - return f.is_file() and self.execre.match(f.name) is not None + return file.is_file() and self.execre.match(file.name) is not None @skip_doctest - def isexec(self, f:DirEntry) -> bool: + def isexec(self, file): """ Test for executible file on non POSIX system """ if self.is_posix: - return self._isexec_POSIX(f) + return self._isexec_POSIX(file) else: - return self._isexec_WIN(f) + return self._isexec_WIN(file) @skip_doctest @@ -212,7 +211,7 @@ def rehashx(self, parameter_s=''): try: # write the whole loop for posix/Windows so we don't have an if in # the innermost part - if os.name == 'posix': + if self.is_posix: for pdir in path: try: os.chdir(pdir) From 6bc0e768a8571adc5edc5ab1ebfe9bd5925f564c Mon Sep 17 00:00:00 2001 From: kd2718 Date: Sat, 6 Oct 2018 14:14:39 -0700 Subject: [PATCH 040/635] issue is with 'with'statetment --- IPython/core/magics/osm.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 5fe268da4ba..6a31076778c 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -212,25 +212,27 @@ def rehashx(self, parameter_s=''): # write the whole loop for posix/Windows so we don't have an if in # the innermost part if self.is_posix: + print(path) for pdir in path: try: os.chdir(pdir) except OSError: continue - with os.scandir(pdir) as dirlist: - for ff in dirlist: - if self.isexec(ff): - fname = ff.name - try: - # Removes dots from the name since ipython - # will assume names with dots to be python. - if not self.shell.alias_manager.is_alias(fname): - self.shell.alias_manager.define_alias( - fname.replace('.',''), fname) - except InvalidAliasError: - pass - else: - syscmdlist.append(fname) + dirlist = os.scandir(path=pdir) + #with os.scandir(pdir) as dirlist: + for ff in dirlist: + if self.isexec(ff): + fname = ff.name + try: + # Removes dots from the name since ipython + # will assume names with dots to be python. + if not self.shell.alias_manager.is_alias(fname): + self.shell.alias_manager.define_alias( + fname.replace('.',''), fname) + except InvalidAliasError: + pass + else: + syscmdlist.append(fname) else: no_alias = Alias.blacklist for pdir in path: From 54f7c6e0f884877f021361490e847812aea44312 Mon Sep 17 00:00:00 2001 From: kd2718 Date: Sat, 6 Oct 2018 19:40:46 -0700 Subject: [PATCH 041/635] removed with notation. This is not supported by python 3.5 --- IPython/core/magics/osm.py | 35 +++++++++++++++++++---------------- IPython/core/profileapp.py | 20 ++++++++++++-------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 6a31076778c..d77cf8a24ad 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -218,8 +218,9 @@ def rehashx(self, parameter_s=''): os.chdir(pdir) except OSError: continue + + # use with notation for python 3.6 onward dirlist = os.scandir(path=pdir) - #with os.scandir(pdir) as dirlist: for ff in dirlist: if self.isexec(ff): fname = ff.name @@ -240,21 +241,23 @@ def rehashx(self, parameter_s=''): os.chdir(pdir) except OSError: continue - with os.scandir(pdir) as dirlist: - for ff in dirlist: - fname = ff.name - base, ext = os.path.splitext(fname) - if self.isexec(ff) and base.lower() not in no_alias: - if ext.lower() == '.exe': - fname = base - try: - # Removes dots from the name since ipython - # will assume names with dots to be python. - self.shell.alias_manager.define_alias( - base.lower().replace('.',''), fname) - except InvalidAliasError: - pass - syscmdlist.append(fname) + + # use with notation for python 3.6 onward + dirlist = os.scandir(pdir) + for ff in dirlist: + fname = ff.name + base, ext = os.path.splitext(fname) + if self.isexec(ff) and base.lower() not in no_alias: + if ext.lower() == '.exe': + fname = base + try: + # Removes dots from the name since ipython + # will assume names with dots to be python. + self.shell.alias_manager.define_alias( + base.lower().replace('.',''), fname) + except InvalidAliasError: + pass + syscmdlist.append(fname) self.shell.db['syscmdlist'] = syscmdlist finally: os.chdir(savedir) diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index 700fcc7a008..2f66bd99a8c 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -97,10 +97,12 @@ def list_profiles_in(path): """list profiles in a given root directory""" profiles = [] - with os.scandir(path) as files: - for f in files: - if f.is_dir() and f.name.startswith('profile_'): - profiles.append(f.name.split('_', 1)[-1]) + + # use with notation for python 3.6 onward + files = os.scandir(path) + for f in files: + if f.is_dir() and f.name.startswith('profile_'): + profiles.append(f.name.split('_', 1)[-1]) return profiles @@ -108,10 +110,12 @@ def list_bundled_profiles(): """list profiles that are bundled with IPython.""" path = os.path.join(get_ipython_package_dir(), u'core', u'profile') profiles = [] - with os.scandir(path) as files: - for profile in files: - if profile.is_dir() and profile.name != "__pycache__": - profiles.append(profile.name) + + # use with notation for python 3.6 onward + files = os.scandir(path) + for profile in files: + if profile.is_dir() and profile.name != "__pycache__": + profiles.append(profile.name) return profiles From 3cdff565a9a98cd089d68e34c81854180b11224a Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Sun, 7 Oct 2018 11:49:28 +0900 Subject: [PATCH 042/635] don't warn if the iframe isn't the only thing in the data --- IPython/core/display.py | 2 +- IPython/core/tests/test_display.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 4a2e2817910..76281b189fc 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -667,7 +667,7 @@ def _repr_pretty_(self, pp, cycle): class HTML(TextDisplayObject): def __init__(self, data=None, url=None, filename=None, metadata=None): - if data and ""): warnings.warn("Consider using IPython.display.IFrame instead") super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata) diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index 7c1f978b42c..24cdc030091 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -200,6 +200,9 @@ def test_encourage_iframe_over_html(m_warn): display.HTML('
') m_warn.assert_not_called() + display.HTML('

Lots of content here

') + m_warn.assert_not_called() + display.HTML('') m_warn.assert_called_with('Consider using IPython.display.IFrame instead') From 5e391e0c816ad043a8a5dd1151eb63f525385354 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Sun, 7 Oct 2018 11:59:47 +0900 Subject: [PATCH 043/635] handle case-insensitivity --- IPython/core/display.py | 14 +++++++++++++- IPython/core/tests/test_display.py | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 76281b189fc..84c18e51c43 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -667,7 +667,19 @@ def _repr_pretty_(self, pp, cycle): class HTML(TextDisplayObject): def __init__(self, data=None, url=None, filename=None, metadata=None): - if data and data.startswith("") + + if warn(): warnings.warn("Consider using IPython.display.IFrame instead") super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata) diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index 24cdc030091..1fed51127a1 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -197,6 +197,9 @@ def test_displayobject_repr(): @mock.patch('warnings.warn') def test_encourage_iframe_over_html(m_warn): + display.HTML() + m_warn.assert_not_called() + display.HTML('
') m_warn.assert_not_called() @@ -206,6 +209,10 @@ def test_encourage_iframe_over_html(m_warn): display.HTML('') m_warn.assert_called_with('Consider using IPython.display.IFrame instead') + m_warn.reset_mock() + display.HTML('') + m_warn.assert_called_with('Consider using IPython.display.IFrame instead') + def test_progress(): p = display.ProgressBar(10) nt.assert_in('0/10',repr(p)) From bdaec6ffae6f8f4dfa644bffeab93c1e5ad30f99 Mon Sep 17 00:00:00 2001 From: Tony Fast Date: Sat, 6 Oct 2018 23:41:04 -0400 Subject: [PATCH 044/635] Remove redundant test Nice catch @bartskowron --- IPython/core/tests/test_inputtransformer2.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index 9c5a413955f..6a57b681c64 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -215,7 +215,6 @@ def test_check_complete(): nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None)) nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash nt.assert_equal(cc("1\\\n+2"), ('complete', None)) - nt.assert_equal(cc("1\\\n+2"), ('complete', None)) nt.assert_equal(cc("exit"), ('complete', None)) example = dedent(""" From 90eadf9f123185bfb15e021606fea349e14861e4 Mon Sep 17 00:00:00 2001 From: Shashank Kumar Date: Mon, 8 Oct 2018 15:51:40 +0530 Subject: [PATCH 045/635] docs(CONTRIBUTING): Minor fix --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60a0bd2c1be..576f1ae7800 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ To remove a label, use the `untag` command: > @meeseeksdev untag windows, documentation -e'll be adding additional capabilities for the bot and will share them here +We'll be adding additional capabilities for the bot and will share them here when they are ready to be used. ## Opening an Issue From 43e857d948594ec7e5a2c3f1ec865574b5fe4792 Mon Sep 17 00:00:00 2001 From: ammarmallik Date: Mon, 8 Oct 2018 19:31:16 +0500 Subject: [PATCH 046/635] Replace depricated time.clock with time.perf_counter issue#11375 --- IPython/utils/timing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/utils/timing.py b/IPython/utils/timing.py index 3d4d9f8d9bc..6bb176f338c 100644 --- a/IPython/utils/timing.py +++ b/IPython/utils/timing.py @@ -59,12 +59,12 @@ def clock2(): except ImportError: # There is no distinction of user/system time under windows, so we just use # time.clock() for everything... - clocku = clocks = clock = time.clock + clocku = clocks = clock = time.perf_counter def clock2(): """Under windows, system CPU time can't be measured. This just returns clock() and zero.""" - return time.clock(),0.0 + return time.perf_counter(),0.0 def timings_out(reps,func,*args,**kw): From 1d0e132d78ee6c66a119c1d12aaa83eca4da326e Mon Sep 17 00:00:00 2001 From: ammarmallik Date: Mon, 8 Oct 2018 22:23:52 +0500 Subject: [PATCH 047/635] Update comments issue#11375 --- IPython/utils/timing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/utils/timing.py b/IPython/utils/timing.py index 6bb176f338c..9a31affadf0 100644 --- a/IPython/utils/timing.py +++ b/IPython/utils/timing.py @@ -58,12 +58,12 @@ def clock2(): return resource.getrusage(resource.RUSAGE_SELF)[:2] except ImportError: # There is no distinction of user/system time under windows, so we just use - # time.clock() for everything... + # time.perff_counter() for everything... clocku = clocks = clock = time.perf_counter def clock2(): """Under windows, system CPU time can't be measured. - This just returns clock() and zero.""" + This just returns perf_counter() and zero.""" return time.perf_counter(),0.0 From 79f4369879e11a76d4694ad099b10295d8a11e3b Mon Sep 17 00:00:00 2001 From: kd2718 Date: Mon, 8 Oct 2018 21:05:09 -0700 Subject: [PATCH 048/635] quick doc change --- IPython/core/magics/execution.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 9fabc43d5a4..6f7ddea516a 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -188,7 +188,7 @@ def prun(self, parameter_s='', cell=None): """Run a statement through the python code profiler. - Usage, in line mode: + Usage, in line mode:run %prun [options] statement Usage, in cell mode: @@ -507,6 +507,8 @@ def run(self, parameter_s='', runner=None, *two* back slashes (e.g. ``\\\\*``) to suppress expansions. To completely disable these expansions, you can use -G flag. + On Windows systems, the use of double quotes `"` is required. + Options: -n From d02e73a61e94d24611cdf6bbf68736e860abed8a Mon Sep 17 00:00:00 2001 From: Christopher Moura Date: Tue, 9 Oct 2018 13:37:44 -0300 Subject: [PATCH 049/635] Update README.rst Fixed a minor typo. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index eb21641997f..0ce6166b6f4 100644 --- a/README.rst +++ b/README.rst @@ -95,7 +95,7 @@ As well as the following Pull-Request for discussion: This error does also occur if you are invoking ``setup.py`` directly – which you should not – or are using ``easy_install`` If this is the case, use ``pip -install .`` (instead of ``setup.py install`` , and ``pip install -e .`` instead +install .`` instead of ``setup.py install`` , and ``pip install -e .`` instead of ``setup.py develop`` If you are depending on IPython as a dependency you may also want to have a conditional dependency on IPython depending on the Python version:: From 9fe8eab4f00d6cd25e850a714d1690a629674f95 Mon Sep 17 00:00:00 2001 From: hongshaoyang Date: Wed, 10 Oct 2018 01:19:45 +0800 Subject: [PATCH 050/635] Update osm.py --- IPython/core/magics/osm.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index f835361a4cf..b3fda954f4b 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -776,10 +776,12 @@ def writefile(self, line, cell): The file will be overwritten unless the -a (--append) flag is specified. """ - line = line if len(line.split())==1 else '"%s"' % line.strip("\"\'") args = magic_arguments.parse_argstring(self.writefile, line) - filename = os.path.expanduser(args.filename.strip("\"\'")) - + if re.match(r'[\'*\']|["*"]', args.filename): + filename = os.path.expanduser(args.filename[1:-1]) + else: + filename = os.path.expanduser(args.filename) + if os.path.exists(filename): if args.append: print("Appending to %s" % filename) From 3d766d48950ab70b3266a51f827c14e1272f39fa Mon Sep 17 00:00:00 2001 From: felixzhuologist Date: Tue, 9 Oct 2018 17:13:34 -0400 Subject: [PATCH 051/635] check for nonlocal inside toplevel functions --- IPython/core/async_helpers.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/IPython/core/async_helpers.py b/IPython/core/async_helpers.py index a6ff86031d0..d2d639c4f6b 100644 --- a/IPython/core/async_helpers.py +++ b/IPython/core/async_helpers.py @@ -97,19 +97,25 @@ class _AsyncSyntaxErrorVisitor(ast.NodeVisitor): the implementation involves wrapping the repl in an async function, it is erroneously allowed (e.g. yield or return at the top level) """ + def __init__(self, is_toplevel=True): + self.is_toplevel = is_toplevel + super().__init__() def generic_visit(self, node): func_types = (ast.FunctionDef, ast.AsyncFunctionDef) - invalid_types = (ast.Return, ast.Yield, ast.YieldFrom) + toplevel_invalid_types = (ast.Return, ast.Yield, ast.YieldFrom) + inner_invalid_types = (ast.Nonlocal,) - if isinstance(node, func_types): - return # Don't recurse into functions - elif isinstance(node, invalid_types): + if isinstance(node, func_types) and self.is_toplevel: + self.is_toplevel = False + super().generic_visit(node) + elif self.is_toplevel and isinstance(node, toplevel_invalid_types): + raise SyntaxError() + elif not self.is_toplevel and isinstance(node, inner_invalid_types): raise SyntaxError() else: super().generic_visit(node) - def _async_parse_cell(cell: str) -> ast.AST: """ This is a compatibility shim for pre-3.7 when async outside of a function From 8e7c5f093ba469e6dffdff4bd9bf63abeac1ba60 Mon Sep 17 00:00:00 2001 From: felixzhuologist Date: Tue, 9 Oct 2018 17:16:53 -0400 Subject: [PATCH 052/635] generalize to arbitrary errors by depth --- IPython/core/async_helpers.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/IPython/core/async_helpers.py b/IPython/core/async_helpers.py index d2d639c4f6b..c9ba18225d5 100644 --- a/IPython/core/async_helpers.py +++ b/IPython/core/async_helpers.py @@ -97,25 +97,27 @@ class _AsyncSyntaxErrorVisitor(ast.NodeVisitor): the implementation involves wrapping the repl in an async function, it is erroneously allowed (e.g. yield or return at the top level) """ - def __init__(self, is_toplevel=True): - self.is_toplevel = is_toplevel + def __init__(self): + self.depth = 0 super().__init__() def generic_visit(self, node): func_types = (ast.FunctionDef, ast.AsyncFunctionDef) - toplevel_invalid_types = (ast.Return, ast.Yield, ast.YieldFrom) - inner_invalid_types = (ast.Nonlocal,) - - if isinstance(node, func_types) and self.is_toplevel: - self.is_toplevel = False + invalid_types_by_depth = { + 0: (ast.Return, ast.Yield, ast.YieldFrom), + 1: (ast.Nonlocal,) + } + + should_traverse = self.depth < max(invalid_types_by_depth.keys()) + if isinstance(node, func_types) and should_traverse: + self.depth += 1 super().generic_visit(node) - elif self.is_toplevel and isinstance(node, toplevel_invalid_types): - raise SyntaxError() - elif not self.is_toplevel and isinstance(node, inner_invalid_types): + elif isinstance(node, invalid_types_by_depth[self.depth]): raise SyntaxError() else: super().generic_visit(node) + def _async_parse_cell(cell: str) -> ast.AST: """ This is a compatibility shim for pre-3.7 when async outside of a function From a562329af4c842d00d3e93767c4576f91849de15 Mon Sep 17 00:00:00 2001 From: felixzhuologist Date: Tue, 9 Oct 2018 18:39:09 -0400 Subject: [PATCH 053/635] add test for nonlocal case --- IPython/core/tests/test_async_helpers.py | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/IPython/core/tests/test_async_helpers.py b/IPython/core/tests/test_async_helpers.py index 6bf64e2115f..20ad3d0fc5b 100644 --- a/IPython/core/tests/test_async_helpers.py +++ b/IPython/core/tests/test_async_helpers.py @@ -227,6 +227,35 @@ def nest_case(context, case): else: iprc(cell) + def test_nonlocal(self): + # fails if outer scope is not a function scope or if var not defined + with self.assertRaises(SyntaxError): + iprc("nonlocal x") + iprc(""" + x = 1 + def f(): + nonlocal x + x = 10000 + yield x + """) + iprc(""" + def f(): + def g(): + nonlocal x + x = 10000 + yield x + """) + + # works if outer scope is a function scope and var exists + iprc(""" + def f(): + x = 20 + def g(): + nonlocal x + x = 10000 + yield x + """) + def test_execute(self): iprc(""" From d5a746e1c0515220c3cc6672c4feaa9c5f7170a2 Mon Sep 17 00:00:00 2001 From: Kory Donati Date: Wed, 10 Oct 2018 13:40:12 -0700 Subject: [PATCH 054/635] removed args initializer that is not used and removed unneeded code in osm init super call --- IPython/core/magics/osm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index d77cf8a24ad..ab3c4e3320e 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -47,7 +47,7 @@ def __init__(self, shell=None, **kwargs): self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) # call up the chain - super(OSMagics, self).__init__(shell=shell, **kwargs) + super().__init__(shell=shell, **kwargs) @skip_doctest @@ -520,7 +520,6 @@ def dhist(self, parameter_s=''): dh = self.shell.user_ns['_dh'] if parameter_s: - args = [] try: args = map(int,parameter_s.split()) except: From 1b0793cf32e8a5f57ca49c6991861c66d5f8e6db Mon Sep 17 00:00:00 2001 From: koryd Date: Wed, 10 Oct 2018 14:27:40 -0700 Subject: [PATCH 055/635] better update for the docs --- IPython/core/magics/execution.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 6f7ddea516a..74a9e6a264f 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -507,7 +507,8 @@ def run(self, parameter_s='', runner=None, *two* back slashes (e.g. ``\\\\*``) to suppress expansions. To completely disable these expansions, you can use -G flag. - On Windows systems, the use of double quotes `"` is required. + On Windows systems, the use of single quotes `'` when specifing + a file is not supported. Use double quotes `"`. Options: From d2a9a9d7254ea6a0402134c293ed99251e448f81 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Thu, 11 Oct 2018 12:57:34 +0200 Subject: [PATCH 056/635] Same highlighting for %%file as for %%writefile ... because former is an alias for latter. --- IPython/lib/lexers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/lib/lexers.py b/IPython/lib/lexers.py index b8dec7e43b9..fd42880a9fd 100644 --- a/IPython/lib/lexers.py +++ b/IPython/lib/lexers.py @@ -98,6 +98,7 @@ def build_ipy_lexer(python3): (r'(?s)(\s*)(%%time)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PyLexer))), (r'(?s)(\s*)(%%timeit)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PyLexer))), (r'(?s)(\s*)(%%writefile)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PyLexer))), + (r'(?s)(\s*)(%%file)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PyLexer))), (r"(?s)(\s*)(%%)(\w+)(.*)", bygroups(Text, Operator, Keyword, Text)), (r'(?s)(^\s*)(%%!)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(BashLexer))), (r"(%%?)(\w+)(\?\??)$", bygroups(Operator, Keyword, Operator)), From a2a029f058577ae807b674154c370ee84b51a858 Mon Sep 17 00:00:00 2001 From: Matthias Geier Date: Thu, 11 Oct 2018 12:58:31 +0200 Subject: [PATCH 057/635] Fix %%perl highlighting --- IPython/lib/lexers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/lib/lexers.py b/IPython/lib/lexers.py index fd42880a9fd..a8c871098a0 100644 --- a/IPython/lib/lexers.py +++ b/IPython/lib/lexers.py @@ -88,7 +88,7 @@ def build_ipy_lexer(python3): (r'(?s)(\s*)(%%javascript)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(JavascriptLexer))), (r'(?s)(\s*)(%%js)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(JavascriptLexer))), (r'(?s)(\s*)(%%latex)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(TexLexer))), - (r'(?s)(\s*)(%%pypy)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PerlLexer))), + (r'(?s)(\s*)(%%perl)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PerlLexer))), (r'(?s)(\s*)(%%prun)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PyLexer))), (r'(?s)(\s*)(%%pypy)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PyLexer))), (r'(?s)(\s*)(%%python)([^\n]*\n)(.*)', bygroups(Text, Operator, Text, using(PyLexer))), From 1c7897a268b3e5ea80df669774d84835c92fd666 Mon Sep 17 00:00:00 2001 From: ammarmallik Date: Thu, 11 Oct 2018 18:29:18 +0500 Subject: [PATCH 058/635] Replace deprecated time.time() with time.perf_counter() issue#11375 --- IPython/core/magics/execution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 9fabc43d5a4..cb1cb2b3cb3 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -912,7 +912,7 @@ def _run_with_timing(run, nruns): Number of times to execute `run`. """ - twall0 = time.time() + twall0 = time.perf_counter() if nruns == 1: t0 = clock2() run() @@ -935,7 +935,7 @@ def _run_with_timing(run, nruns): print(" Times : %10s %10s" % ('Total', 'Per run')) print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)) print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)) - twall1 = time.time() + twall1 = time.perf_counter() print("Wall time: %10.2f s." % (twall1 - twall0)) @skip_doctest From 977474a07f211739ad5d1724967db2dafe052299 Mon Sep 17 00:00:00 2001 From: wim glenn Date: Thu, 11 Oct 2018 11:00:24 -0500 Subject: [PATCH 059/635] Fix a paragraph that read very poorly --- docs/source/whatsnew/version7.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/whatsnew/version7.rst b/docs/source/whatsnew/version7.rst index 1a8e1eff67c..19352cc0d95 100644 --- a/docs/source/whatsnew/version7.rst +++ b/docs/source/whatsnew/version7.rst @@ -118,11 +118,11 @@ Jupyter Protocol will need further updates of the IPykernel package. Non-Asynchronous code ~~~~~~~~~~~~~~~~~~~~~ -As the internal API of IPython are now asynchronous, IPython need to run under -an even loop. In order to allow many workflow, (like using the :magic:`%run` +As the internal API of IPython is now asynchronous, IPython needs to run under +an event loop. In order to allow many workflows, (like using the :magic:`%run` magic, or copy_pasting code that explicitly starts/stop event loop), when top-level code is detected as not being asynchronous, IPython code is advanced -via a pseudo-synchronous runner, and will not may not advance pending tasks. +via a pseudo-synchronous runner, and may not advance pending tasks. Change to Nested Embed ~~~~~~~~~~~~~~~~~~~~~~ From 391ef36d08f8492c0df5a8153de59a51d8cc5e19 Mon Sep 17 00:00:00 2001 From: Shao Yang Date: Fri, 12 Oct 2018 22:55:00 +0800 Subject: [PATCH 060/635] add test to core/tests/test_magic --- IPython/core/tests/test_magic.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index dfeabca1f21..7d5fa13a020 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -27,7 +27,8 @@ from IPython.testing import decorators as dec from IPython.testing import tools as tt from IPython.utils.io import capture_output -from IPython.utils.tempdir import TemporaryDirectory +from IPython.utils.tempdir import (TemporaryDirectory, + TemporaryWorkingDirectory) from IPython.utils.process import find_cmd @@ -797,7 +798,20 @@ def test_file_amend(): s = f.read() nt.assert_in('line1\n', s) nt.assert_in('line3\n', s) - + +def test_file_spaces(): + """%%file with spaces in filename""" + ip = get_ipython() + with TemporaryWorkingDirectory() as td: + fname = 'file name' + ip.run_cell_magic("file", "'%s'"%fname, u'\n'.join([ + 'line1', + 'line2', + ])) + with open(fname) as f: + s = f.read() + nt.assert_in('line1\n', s) + nt.assert_in('line2', s) def test_script_config(): ip = get_ipython() From 50c9ae6b40c2c0ebaa86d087a90982eec61a1352 Mon Sep 17 00:00:00 2001 From: hongshaoyang Date: Fri, 12 Oct 2018 23:05:13 +0800 Subject: [PATCH 061/635] Update test_magic.py --- IPython/core/tests/test_magic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 7d5fa13a020..74d2604fa67 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -803,7 +803,7 @@ def test_file_spaces(): """%%file with spaces in filename""" ip = get_ipython() with TemporaryWorkingDirectory() as td: - fname = 'file name' + fname = "file name" ip.run_cell_magic("file", "'%s'"%fname, u'\n'.join([ 'line1', 'line2', From 0ca8ce4b1a4e380fe4afcb48574901c36c055119 Mon Sep 17 00:00:00 2001 From: Shao Yang Date: Fri, 12 Oct 2018 23:19:38 +0800 Subject: [PATCH 062/635] change magics from %%file to %%writefile --- IPython/core/tests/test_magic.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index dfeabca1f21..b9c1533905b 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -738,11 +738,11 @@ def cellm33(self, line, cell): nt.assert_equal(c33, None) def test_file(): - """Basic %%file""" + """Basic %%writefile""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file1') - ip.run_cell_magic("file", fname, u'\n'.join([ + ip.run_cell_magic("writefile", fname, u'\n'.join([ 'line1', 'line2', ])) @@ -752,12 +752,12 @@ def test_file(): nt.assert_in('line2', s) def test_file_var_expand(): - """%%file $filename""" + """%%writefile $filename""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file1') ip.user_ns['filename'] = fname - ip.run_cell_magic("file", '$filename', u'\n'.join([ + ip.run_cell_magic("writefile", '$filename', u'\n'.join([ 'line1', 'line2', ])) @@ -767,11 +767,11 @@ def test_file_var_expand(): nt.assert_in('line2', s) def test_file_unicode(): - """%%file with unicode cell""" + """%%writefile with unicode cell""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file1') - ip.run_cell_magic("file", fname, u'\n'.join([ + ip.run_cell_magic("writefile", fname, u'\n'.join([ u'liné1', u'liné2', ])) @@ -781,15 +781,15 @@ def test_file_unicode(): nt.assert_in(u'liné2', s) def test_file_amend(): - """%%file -a amends files""" + """%%writefile -a amends files""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file2') - ip.run_cell_magic("file", fname, u'\n'.join([ + ip.run_cell_magic("writefile", fname, u'\n'.join([ 'line1', 'line2', ])) - ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([ + ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([ 'line3', 'line4', ])) From a5731aa33cd94e2441215eae55d1db1516b2474d Mon Sep 17 00:00:00 2001 From: Shao Yang Date: Fri, 12 Oct 2018 23:42:18 +0800 Subject: [PATCH 063/635] wrong quotes --- IPython/core/tests/test_magic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 74d2604fa67..f975076ca1f 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -804,7 +804,7 @@ def test_file_spaces(): ip = get_ipython() with TemporaryWorkingDirectory() as td: fname = "file name" - ip.run_cell_magic("file", "'%s'"%fname, u'\n'.join([ + ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([ 'line1', 'line2', ])) From b73398c4a228f8e8cb6e55f0f18956d1df766590 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 12 Oct 2018 09:35:39 -0700 Subject: [PATCH 064/635] Use ansi code for soon-to-be released prompt_toolkit. Prompt toolkit use to try to map 256 colors code to closest ansi code but does not do that anymore. This should fix (some of) the occurrences. --- IPython/terminal/interactiveshell.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 35cb0697849..fed68c67864 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -297,9 +297,9 @@ def _make_style_from_name_or_cls(self, name_or_cls): Token.Name.Class: 'bold #2080D0', Token.Name.Namespace: 'bold #2080D0', Token.Prompt: '#009900', - Token.PromptNum: '#00ff00 bold', + Token.PromptNum: '#ansibrightgreen bold', Token.OutPrompt: '#990000', - Token.OutPromptNum: '#ff0000 bold', + Token.OutPromptNum: '#ansibrightred bold', }) # Hack: Due to limited color support on the Windows console @@ -323,9 +323,9 @@ def _make_style_from_name_or_cls(self, name_or_cls): style_cls = name_or_cls style_overrides = { Token.Prompt: '#009900', - Token.PromptNum: '#00ff00 bold', + Token.PromptNum: '#ansibrightgreen bold', Token.OutPrompt: '#990000', - Token.OutPromptNum: '#ff0000 bold', + Token.OutPromptNum: '#ansibrightred bold', } style_overrides.update(self.highlighting_style_overrides) style = merge_styles([ From 5cc53e88f34d82c96dca26cf708d1d78f19cea82 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 12 Oct 2018 15:58:09 -0700 Subject: [PATCH 065/635] Add test that %depug pass through generators. --- IPython/terminal/tests/test_debug_magic.py | 74 ++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 IPython/terminal/tests/test_debug_magic.py diff --git a/IPython/terminal/tests/test_debug_magic.py b/IPython/terminal/tests/test_debug_magic.py new file mode 100644 index 00000000000..650ba7f9ab9 --- /dev/null +++ b/IPython/terminal/tests/test_debug_magic.py @@ -0,0 +1,74 @@ +"""Test embedding of IPython""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2013 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +import os +import sys +from IPython.testing.decorators import skip_win32 + +#----------------------------------------------------------------------------- +# Tests +#----------------------------------------------------------------------------- + +@skip_win32 +def test_debug_magic_passes_through_generators(): + """ + This test that we can correctly pass through frames of a generator post-mortem. + """ + import pexpect + import re + in_prompt = re.compile(b'In ?\[\\d+\]:') + ipdb_prompt = 'ipdb>' + env = os.environ.copy() + child = pexpect.spawn(sys.executable, ['-m', 'IPython', '--colors=nocolor', '--simple-prompt'], + env=env) + child.timeout = 2 + + child.expect(in_prompt) + child.sendline("def f(x):") + child.sendline(" raise Exception") + child.sendline("") + + child.expect(in_prompt) + child.sendline("gen = (f(x) for x in [0])") + child.sendline("") + + child.expect(in_prompt) + child.sendline("for x in gen:") + child.sendline(" pass") + child.sendline("") + + child.expect('Exception:') + + child.expect(in_prompt) + child.sendline(r'%debug') + child.expect('----> 2 raise Exception') + + child.expect(ipdb_prompt) + child.sendline('u') + child.expect_exact(r'----> 1 gen = (f(x) for x in [0])') + + child.expect(ipdb_prompt) + child.sendline('u') + child.expect_exact('----> 1 for x in gen:') + + child.expect(ipdb_prompt) + child.sendline('u') + child.expect_exact('*** Oldest frame') + + child.expect(ipdb_prompt) + child.sendline('exit') + + child.expect(in_prompt) + child.sendline('exit') + + child.close() From 5c6aa5ea5ad94ae0f40d8e04faa348a7003ef8cb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 12 Oct 2018 17:03:06 -0700 Subject: [PATCH 066/635] Give some love to the VI mode. Improve #11329, still likely need a magic to make editign mode easier to toggle --- IPython/terminal/interactiveshell.py | 19 ++++++++++++++++++- IPython/terminal/prompts.py | 7 +++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 35cb0697849..e26008a02ee 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -12,7 +12,7 @@ from IPython.utils.process import abbrev_cwd from traitlets import ( Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union, - Any, + Any, validate ) from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode @@ -131,6 +131,23 @@ def debugger_cls(self): highlighting. To see available styles, run `pygmentize -L styles`.""" ).tag(config=True) + @validate('editing_mode') + def _validate_editing_mode(self, proposal): + if proposal['value'].lower() == 'vim': + proposal['value']= 'vi' + elif proposal['value'].lower() == 'default': + proposal['value']= 'emacs' + + if hasattr(EditingMode, proposal['value'].upper()): + return proposal['value'].lower() + + return self.editing_mode + + + @observe('editing_mode') + def _editing_mode(self, change): + u_mode = change.new.upper() + self.pt_app.editing_mode = u_mode @observe('highlighting_style') @observe('colors') diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index ce8c169f408..6b7b7cc9dc3 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -13,8 +13,15 @@ class Prompts(object): def __init__(self, shell): self.shell = shell + def vi_mode(self): + if self.shell.pt_app.editing_mode == 'VI': + return '['+str(self.shell.pt_app.app.vi_state.input_mode)[3:6]+'] ' + return '' + + def in_prompt_tokens(self): return [ + (Token.Prompt, self.vi_mode() ), (Token.Prompt, 'In ['), (Token.PromptNum, str(self.shell.execution_count)), (Token.Prompt, ']: '), From cb9cbcae51ea247525796a18fa7ae7cd5a6af2c0 Mon Sep 17 00:00:00 2001 From: kd2718 Date: Fri, 12 Oct 2018 18:09:39 -0700 Subject: [PATCH 067/635] updated comments. removed debug print statement --- IPython/core/magics/osm.py | 6 +++--- IPython/core/profileapp.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index d77cf8a24ad..c20b8397660 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -212,14 +212,13 @@ def rehashx(self, parameter_s=''): # write the whole loop for posix/Windows so we don't have an if in # the innermost part if self.is_posix: - print(path) for pdir in path: try: os.chdir(pdir) except OSError: continue - # use with notation for python 3.6 onward + # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist: dirlist = os.scandir(path=pdir) for ff in dirlist: if self.isexec(ff): @@ -242,7 +241,7 @@ def rehashx(self, parameter_s=''): except OSError: continue - # use with notation for python 3.6 onward + # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist: dirlist = os.scandir(pdir) for ff in dirlist: fname = ff.name @@ -258,6 +257,7 @@ def rehashx(self, parameter_s=''): except InvalidAliasError: pass syscmdlist.append(fname) + self.shell.db['syscmdlist'] = syscmdlist finally: os.chdir(savedir) diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index 2f66bd99a8c..97434e3d0b5 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -98,7 +98,7 @@ def list_profiles_in(path): """list profiles in a given root directory""" profiles = [] - # use with notation for python 3.6 onward + # for python 3.6+ rewrite to: with os.scandir(path) as dirlist: files = os.scandir(path) for f in files: if f.is_dir() and f.name.startswith('profile_'): @@ -111,7 +111,7 @@ def list_bundled_profiles(): path = os.path.join(get_ipython_package_dir(), u'core', u'profile') profiles = [] - # use with notation for python 3.6 onward + # for python 3.6+ rewrite to: with os.scandir(path) as dirlist: files = os.scandir(path) for profile in files: if profile.is_dir() and profile.name != "__pycache__": From dc0ceb16f92e0e943435106e863a5cfccd724a2d Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 13 Oct 2018 17:14:22 +0300 Subject: [PATCH 068/635] Replace simplegeneric.generic with functools.singledispatch --- IPython/core/tests/test_completer.py | 2 +- IPython/external/__init__.py | 2 +- IPython/utils/generics.py | 10 +++------- IPython/utils/text.py | 4 ++-- setup.py | 1 - 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 56428bad2c8..74c53ade984 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -115,7 +115,7 @@ def test_custom_completion_error(): class A(object): pass ip.user_ns['a'] = A() - @complete_object.when_type(A) + @complete_object.register(A) def complete_A(a, existing_completions): raise TypeError("this should be silenced") diff --git a/IPython/external/__init__.py b/IPython/external/__init__.py index 3104c194622..1c8c546f118 100644 --- a/IPython/external/__init__.py +++ b/IPython/external/__init__.py @@ -2,4 +2,4 @@ This package contains all third-party modules bundled with IPython. """ -__all__ = ["simplegeneric"] +__all__ = [] diff --git a/IPython/utils/generics.py b/IPython/utils/generics.py index 5ffdc86ebda..fcada6f44df 100644 --- a/IPython/utils/generics.py +++ b/IPython/utils/generics.py @@ -1,20 +1,18 @@ # encoding: utf-8 """Generic functions for extending IPython. - -See http://pypi.python.org/pypi/simplegeneric. """ from IPython.core.error import TryNext -from simplegeneric import generic +from functools import singledispatch -@generic +@singledispatch def inspect_object(obj): """Called when you do obj?""" raise TryNext -@generic +@singledispatch def complete_object(obj, prev_completions): """Custom completer dispatching for python objects. @@ -30,5 +28,3 @@ def complete_object(obj, prev_completions): own_attrs + prev_completions. """ raise TryNext - - diff --git a/IPython/utils/text.py b/IPython/utils/text.py index 0c0d82f6323..e844203ca0e 100644 --- a/IPython/utils/text.py +++ b/IPython/utils/text.py @@ -81,7 +81,7 @@ def get_paths(self): # print arg # # -# print_lsstring = result_display.when_type(LSString)(print_lsstring) +# print_lsstring = result_display.register(LSString)(print_lsstring) class SList(list): @@ -243,7 +243,7 @@ def sort(self,field= None, nums = False): # # nlprint(arg) # This was a nested list printer, now removed. # -# print_slist = result_display.when_type(SList)(print_slist) +# print_slist = result_display.register(SList)(print_slist) def indent(instr,nspaces=4, ntabs=0, flatten=False): diff --git a/setup.py b/setup.py index 78529cf6dbc..47c9af24307 100755 --- a/setup.py +++ b/setup.py @@ -188,7 +188,6 @@ 'jedi>=0.10', 'decorator', 'pickleshare', - 'simplegeneric>0.8', 'traitlets>=4.2', 'prompt_toolkit>=2.0.0,<2.1.0', 'pygments', From fde1eec1668b8d3b2d1e9b6b1fc2b7c6175f0885 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 12 Oct 2018 17:11:53 -0700 Subject: [PATCH 069/635] support simple prompt --- IPython/terminal/prompts.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index 6b7b7cc9dc3..a108ca754c9 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -14,6 +14,8 @@ def __init__(self, shell): self.shell = shell def vi_mode(self): + if not hasattr(self.shell.pt_app, 'editing_mode'): + return '' if self.shell.pt_app.editing_mode == 'VI': return '['+str(self.shell.pt_app.app.vi_state.input_mode)[3:6]+'] ' return '' From de447e5100faea067062cb87792ca16b7404c418 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 13 Oct 2018 08:59:52 -0700 Subject: [PATCH 070/635] typo --- IPython/core/magics/execution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 74a9e6a264f..d04ace80c10 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -188,7 +188,7 @@ def prun(self, parameter_s='', cell=None): """Run a statement through the python code profiler. - Usage, in line mode:run + Usage, in line mode: %prun [options] statement Usage, in cell mode: From 8c11a03eaee54010dc0190c61dd9302d99f4bb4d Mon Sep 17 00:00:00 2001 From: luciana Date: Sun, 14 Oct 2018 12:49:53 -0300 Subject: [PATCH 071/635] added filter warnings for older versions of python (<3.7) This is a "squash" of three commits into one. This means that the intermediate history has been rewritten. --- IPython/core/interactiveshell.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index c88423db238..de4a262c347 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -803,7 +803,9 @@ def init_deprecation_warnings(self): This will allow deprecation warning of function used interactively to show warning to users, and still hide deprecation warning from libraries import. """ - warnings.filterwarnings("default", category=DeprecationWarning, module=self.user_ns.get("__name__")) + if sys.version_info < (3,7): + warnings.filterwarnings("default", category=DeprecationWarning, module=self.user_ns.get("__name__")) + def init_builtins(self): # A single, static flag that we set to True. Its presence indicates From ba8538e5afb3c46e742f3a31e6046f936777d1a6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 14 Oct 2018 18:23:42 -0700 Subject: [PATCH 072/635] Fix to allow entering docstring into IPython. The EscapeTransformer find method was assuming incorrectly that every line would end with either a NEWLINE or EOF, while this is not the case when encountering multiple line string. This fixes that by making sure we don't index outside of bounds. With this IPython will correctly add a newline at the CLI. Closes #11391 --- IPython/core/inputtransformer2.py | 7 ++++++- IPython/core/tests/test_inputtransformer2.py | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 5777559fbd4..e2dd2d08773 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -355,9 +355,14 @@ def find(cls, tokens_by_line): """Find the first escaped command (%foo, !foo, etc.) in the cell. """ for line in tokens_by_line: + if not line: + continue ix = 0 - while line[ix].type in {tokenize.INDENT, tokenize.DEDENT}: + ll = len(line) + while ll > ix and line[ix].type in {tokenize.INDENT, tokenize.DEDENT}: ix += 1 + if ix >= ll: + continue if line[ix].string in ESCAPE_SINGLES: return cls(line[ix].start) diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index 6a57b681c64..d6c2fa3bd6b 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -233,6 +233,17 @@ def test_check_complete(): for k in short: cc(c+k) +def test_check_complete_II(): + """ + Test that multiple line strings are properly handled. + + Separate test function for convenience + + """ + cc = ipt2.TransformerManager().check_complete + nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4)) + + def test_null_cleanup_transformer(): manager = ipt2.TransformerManager() manager.cleanup_transforms.insert(0, null_cleanup_transformer) From e5ec6eb286615660dee78a6a8cf0b1268649f880 Mon Sep 17 00:00:00 2001 From: Massimo Santini Date: Mon, 15 Oct 2018 23:15:39 +0200 Subject: [PATCH 073/635] Attempt to fix latex symbols in the completer --- IPython/core/latex_symbols.py | 2143 +++++++++++++++++---------------- tools/gen_latex_symbols.py | 42 +- 2 files changed, 1095 insertions(+), 1090 deletions(-) diff --git a/IPython/core/latex_symbols.py b/IPython/core/latex_symbols.py index ca7200bb59f..164d917beb6 100644 --- a/IPython/core/latex_symbols.py +++ b/IPython/core/latex_symbols.py @@ -11,6 +11,7 @@ latex_symbols = { + "\\euler" : "ℯ", "\\^a" : "ᵃ", "\\^b" : "ᵇ", "\\^c" : "ᶜ", @@ -90,9 +91,9 @@ "\\_chi" : "ᵪ", "\\hbar" : "ħ", "\\sout" : "̶", - "\\textordfeminine" : "ª", + "\\ordfeminine" : "ª", "\\cdotp" : "·", - "\\textordmasculine" : "º", + "\\ordmasculine" : "º", "\\AA" : "Å", "\\AE" : "Æ", "\\DH" : "Ð", @@ -102,68 +103,68 @@ "\\aa" : "å", "\\ae" : "æ", "\\eth" : "ð", + "\\dh" : "ð", "\\o" : "ø", "\\th" : "þ", "\\DJ" : "Đ", "\\dj" : "đ", - "\\Elzxh" : "ħ", "\\imath" : "ı", + "\\jmath" : "ȷ", "\\L" : "Ł", "\\l" : "ł", "\\NG" : "Ŋ", "\\ng" : "ŋ", "\\OE" : "Œ", "\\oe" : "œ", - "\\texthvlig" : "ƕ", - "\\textnrleg" : "ƞ", - "\\textdoublepipe" : "ǂ", - "\\Elztrna" : "ɐ", - "\\Elztrnsa" : "ɒ", - "\\Elzopeno" : "ɔ", - "\\Elzrtld" : "ɖ", - "\\Elzschwa" : "ə", - "\\varepsilon" : "ɛ", - "\\Elzpgamma" : "ɣ", - "\\Elzpbgam" : "ɤ", - "\\Elztrnh" : "ɥ", - "\\Elzbtdl" : "ɬ", - "\\Elzrtll" : "ɭ", - "\\Elztrnm" : "ɯ", - "\\Elztrnmlr" : "ɰ", - "\\Elzltlmr" : "ɱ", - "\\Elzltln" : "ɲ", - "\\Elzrtln" : "ɳ", - "\\Elzclomeg" : "ɷ", - "\\textphi" : "ɸ", - "\\Elztrnr" : "ɹ", - "\\Elztrnrl" : "ɺ", - "\\Elzrttrnr" : "ɻ", - "\\Elzrl" : "ɼ", - "\\Elzrtlr" : "ɽ", - "\\Elzfhr" : "ɾ", - "\\Elzrtls" : "ʂ", - "\\Elzesh" : "ʃ", - "\\Elztrnt" : "ʇ", - "\\Elzrtlt" : "ʈ", - "\\Elzpupsil" : "ʊ", - "\\Elzpscrv" : "ʋ", - "\\Elzinvv" : "ʌ", - "\\Elzinvw" : "ʍ", - "\\Elztrny" : "ʎ", - "\\Elzrtlz" : "ʐ", - "\\Elzyogh" : "ʒ", - "\\Elzglst" : "ʔ", - "\\Elzreglst" : "ʕ", - "\\Elzinglst" : "ʖ", - "\\textturnk" : "ʞ", - "\\Elzdyogh" : "ʤ", - "\\Elztesh" : "ʧ", + "\\hvlig" : "ƕ", + "\\nrleg" : "ƞ", + "\\doublepipe" : "ǂ", + "\\trna" : "ɐ", + "\\trnsa" : "ɒ", + "\\openo" : "ɔ", + "\\rtld" : "ɖ", + "\\schwa" : "ə", + "\\varepsilon" : "ε", + "\\pgamma" : "ɣ", + "\\pbgam" : "ɤ", + "\\trnh" : "ɥ", + "\\btdl" : "ɬ", + "\\rtll" : "ɭ", + "\\trnm" : "ɯ", + "\\trnmlr" : "ɰ", + "\\ltlmr" : "ɱ", + "\\ltln" : "ɲ", + "\\rtln" : "ɳ", + "\\clomeg" : "ɷ", + "\\ltphi" : "ɸ", + "\\trnr" : "ɹ", + "\\trnrl" : "ɺ", + "\\rttrnr" : "ɻ", + "\\rl" : "ɼ", + "\\rtlr" : "ɽ", + "\\fhr" : "ɾ", + "\\rtls" : "ʂ", + "\\esh" : "ʃ", + "\\trnt" : "ʇ", + "\\rtlt" : "ʈ", + "\\pupsil" : "ʊ", + "\\pscrv" : "ʋ", + "\\invv" : "ʌ", + "\\invw" : "ʍ", + "\\trny" : "ʎ", + "\\rtlz" : "ʐ", + "\\yogh" : "ʒ", + "\\glst" : "ʔ", + "\\reglst" : "ʕ", + "\\inglst" : "ʖ", + "\\turnk" : "ʞ", + "\\dyogh" : "ʤ", + "\\tesh" : "ʧ", "\\rasp" : "ʼ", - "\\textasciicaron" : "ˇ", - "\\Elzverts" : "ˈ", - "\\Elzverti" : "ˌ", - "\\Elzlmrk" : "ː", - "\\Elzhlmrk" : "ˑ", + "\\verts" : "ˈ", + "\\verti" : "ˌ", + "\\lmrk" : "ː", + "\\hlmrk" : "ˑ", "\\grave" : "̀", "\\acute" : "́", "\\hat" : "̂", @@ -175,13 +176,12 @@ "\\ocirc" : "̊", "\\H" : "̋", "\\check" : "̌", - "\\Elzpalh" : "̡", - "\\Elzrh" : "̢", + "\\palh" : "̡", + "\\rh" : "̢", "\\c" : "̧", "\\k" : "̨", - "\\Elzsbbrg" : "̪", - "\\Elzxl" : "̵", - "\\Elzbar" : "̶", + "\\sbbrg" : "̪", + "\\strike" : "̶", "\\Alpha" : "Α", "\\Beta" : "Β", "\\Gamma" : "Γ", @@ -236,7 +236,7 @@ "\\Sampi" : "Ϡ", "\\varkappa" : "ϰ", "\\varrho" : "ϱ", - "\\textTheta" : "ϴ", + "\\varTheta" : "ϴ", "\\epsilon" : "ϵ", "\\dddot" : "⃛", "\\ddddot" : "⃜", @@ -249,7 +249,7 @@ "\\beth" : "ℶ", "\\gimel" : "ℷ", "\\daleth" : "ℸ", - "\\BbbPi" : "ℿ", + "\\bbPi" : "ℿ", "\\Zbar" : "Ƶ", "\\overbar" : "̅", "\\ovhook" : "̉", @@ -258,7 +258,6 @@ "\\ocommatopright" : "̕", "\\droang" : "̚", "\\wideutilde" : "̰", - "\\underbar" : "̱", "\\not" : "̸", "\\upMu" : "Μ", "\\upNu" : "Ν", @@ -281,1019 +280,1021 @@ "\\annuity" : "⃧", "\\threeunderdot" : "⃨", "\\widebridgeabove" : "⃩", - "\\BbbC" : "ℂ", - "\\Eulerconst" : "ℇ", - "\\mscrg" : "ℊ", - "\\mscrH" : "ℋ", - "\\mfrakH" : "ℌ", - "\\BbbH" : "ℍ", - "\\Planckconst" : "ℎ", - "\\mscrI" : "ℐ", - "\\mscrL" : "ℒ", - "\\BbbN" : "ℕ", - "\\BbbP" : "ℙ", - "\\BbbQ" : "ℚ", - "\\mscrR" : "ℛ", - "\\BbbR" : "ℝ", - "\\BbbZ" : "ℤ", - "\\mfrakZ" : "ℨ", + "\\bbC" : "ℂ", + "\\eulermascheroni" : "ℇ", + "\\scrg" : "ℊ", + "\\scrH" : "ℋ", + "\\frakH" : "ℌ", + "\\bbH" : "ℍ", + "\\planck" : "ℎ", + "\\scrI" : "ℐ", + "\\scrL" : "ℒ", + "\\bbN" : "ℕ", + "\\bbP" : "ℙ", + "\\bbQ" : "ℚ", + "\\scrR" : "ℛ", + "\\bbR" : "ℝ", + "\\bbZ" : "ℤ", + "\\frakZ" : "ℨ", "\\Angstrom" : "Å", - "\\mscrB" : "ℬ", - "\\mfrakC" : "ℭ", - "\\mscre" : "ℯ", - "\\mscrE" : "ℰ", - "\\mscrF" : "ℱ", + "\\scrB" : "ℬ", + "\\frakC" : "ℭ", + "\\scre" : "ℯ", + "\\scrE" : "ℰ", + "\\scrF" : "ℱ", "\\Finv" : "Ⅎ", - "\\mscrM" : "ℳ", - "\\mscro" : "ℴ", - "\\Bbbgamma" : "ℽ", - "\\BbbGamma" : "ℾ", - "\\mitBbbD" : "ⅅ", - "\\mitBbbd" : "ⅆ", - "\\mitBbbe" : "ⅇ", - "\\mitBbbi" : "ⅈ", - "\\mitBbbj" : "ⅉ", - "\\mbfA" : "𝐀", - "\\mbfB" : "𝐁", - "\\mbfC" : "𝐂", - "\\mbfD" : "𝐃", - "\\mbfE" : "𝐄", - "\\mbfF" : "𝐅", - "\\mbfG" : "𝐆", - "\\mbfH" : "𝐇", - "\\mbfI" : "𝐈", - "\\mbfJ" : "𝐉", - "\\mbfK" : "𝐊", - "\\mbfL" : "𝐋", - "\\mbfM" : "𝐌", - "\\mbfN" : "𝐍", - "\\mbfO" : "𝐎", - "\\mbfP" : "𝐏", - "\\mbfQ" : "𝐐", - "\\mbfR" : "𝐑", - "\\mbfS" : "𝐒", - "\\mbfT" : "𝐓", - "\\mbfU" : "𝐔", - "\\mbfV" : "𝐕", - "\\mbfW" : "𝐖", - "\\mbfX" : "𝐗", - "\\mbfY" : "𝐘", - "\\mbfZ" : "𝐙", - "\\mbfa" : "𝐚", - "\\mbfb" : "𝐛", - "\\mbfc" : "𝐜", - "\\mbfd" : "𝐝", - "\\mbfe" : "𝐞", - "\\mbff" : "𝐟", - "\\mbfg" : "𝐠", - "\\mbfh" : "𝐡", - "\\mbfi" : "𝐢", - "\\mbfj" : "𝐣", - "\\mbfk" : "𝐤", - "\\mbfl" : "𝐥", - "\\mbfm" : "𝐦", - "\\mbfn" : "𝐧", - "\\mbfo" : "𝐨", - "\\mbfp" : "𝐩", - "\\mbfq" : "𝐪", - "\\mbfr" : "𝐫", - "\\mbfs" : "𝐬", - "\\mbft" : "𝐭", - "\\mbfu" : "𝐮", - "\\mbfv" : "𝐯", - "\\mbfw" : "𝐰", - "\\mbfx" : "𝐱", - "\\mbfy" : "𝐲", - "\\mbfz" : "𝐳", - "\\mitA" : "𝐴", - "\\mitB" : "𝐵", - "\\mitC" : "𝐶", - "\\mitD" : "𝐷", - "\\mitE" : "𝐸", - "\\mitF" : "𝐹", - "\\mitG" : "𝐺", - "\\mitH" : "𝐻", - "\\mitI" : "𝐼", - "\\mitJ" : "𝐽", - "\\mitK" : "𝐾", - "\\mitL" : "𝐿", - "\\mitM" : "𝑀", - "\\mitN" : "𝑁", - "\\mitO" : "𝑂", - "\\mitP" : "𝑃", - "\\mitQ" : "𝑄", - "\\mitR" : "𝑅", - "\\mitS" : "𝑆", - "\\mitT" : "𝑇", - "\\mitU" : "𝑈", - "\\mitV" : "𝑉", - "\\mitW" : "𝑊", - "\\mitX" : "𝑋", - "\\mitY" : "𝑌", - "\\mitZ" : "𝑍", - "\\mita" : "𝑎", - "\\mitb" : "𝑏", - "\\mitc" : "𝑐", - "\\mitd" : "𝑑", - "\\mite" : "𝑒", - "\\mitf" : "𝑓", - "\\mitg" : "𝑔", - "\\miti" : "𝑖", - "\\mitj" : "𝑗", - "\\mitk" : "𝑘", - "\\mitl" : "𝑙", - "\\mitm" : "𝑚", - "\\mitn" : "𝑛", - "\\mito" : "𝑜", - "\\mitp" : "𝑝", - "\\mitq" : "𝑞", - "\\mitr" : "𝑟", - "\\mits" : "𝑠", - "\\mitt" : "𝑡", - "\\mitu" : "𝑢", - "\\mitv" : "𝑣", - "\\mitw" : "𝑤", - "\\mitx" : "𝑥", - "\\mity" : "𝑦", - "\\mitz" : "𝑧", - "\\mbfitA" : "𝑨", - "\\mbfitB" : "𝑩", - "\\mbfitC" : "𝑪", - "\\mbfitD" : "𝑫", - "\\mbfitE" : "𝑬", - "\\mbfitF" : "𝑭", - "\\mbfitG" : "𝑮", - "\\mbfitH" : "𝑯", - "\\mbfitI" : "𝑰", - "\\mbfitJ" : "𝑱", - "\\mbfitK" : "𝑲", - "\\mbfitL" : "𝑳", - "\\mbfitM" : "𝑴", - "\\mbfitN" : "𝑵", - "\\mbfitO" : "𝑶", - "\\mbfitP" : "𝑷", - "\\mbfitQ" : "𝑸", - "\\mbfitR" : "𝑹", - "\\mbfitS" : "𝑺", - "\\mbfitT" : "𝑻", - "\\mbfitU" : "𝑼", - "\\mbfitV" : "𝑽", - "\\mbfitW" : "𝑾", - "\\mbfitX" : "𝑿", - "\\mbfitY" : "𝒀", - "\\mbfitZ" : "𝒁", - "\\mbfita" : "𝒂", - "\\mbfitb" : "𝒃", - "\\mbfitc" : "𝒄", - "\\mbfitd" : "𝒅", - "\\mbfite" : "𝒆", - "\\mbfitf" : "𝒇", - "\\mbfitg" : "𝒈", - "\\mbfith" : "𝒉", - "\\mbfiti" : "𝒊", - "\\mbfitj" : "𝒋", - "\\mbfitk" : "𝒌", - "\\mbfitl" : "𝒍", - "\\mbfitm" : "𝒎", - "\\mbfitn" : "𝒏", - "\\mbfito" : "𝒐", - "\\mbfitp" : "𝒑", - "\\mbfitq" : "𝒒", - "\\mbfitr" : "𝒓", - "\\mbfits" : "𝒔", - "\\mbfitt" : "𝒕", - "\\mbfitu" : "𝒖", - "\\mbfitv" : "𝒗", - "\\mbfitw" : "𝒘", - "\\mbfitx" : "𝒙", - "\\mbfity" : "𝒚", - "\\mbfitz" : "𝒛", - "\\mscrA" : "𝒜", - "\\mscrC" : "𝒞", - "\\mscrD" : "𝒟", - "\\mscrG" : "𝒢", - "\\mscrJ" : "𝒥", - "\\mscrK" : "𝒦", - "\\mscrN" : "𝒩", - "\\mscrO" : "𝒪", - "\\mscrP" : "𝒫", - "\\mscrQ" : "𝒬", - "\\mscrS" : "𝒮", - "\\mscrT" : "𝒯", - "\\mscrU" : "𝒰", - "\\mscrV" : "𝒱", - "\\mscrW" : "𝒲", - "\\mscrX" : "𝒳", - "\\mscrY" : "𝒴", - "\\mscrZ" : "𝒵", - "\\mscra" : "𝒶", - "\\mscrb" : "𝒷", - "\\mscrc" : "𝒸", - "\\mscrd" : "𝒹", - "\\mscrf" : "𝒻", - "\\mscrh" : "𝒽", - "\\mscri" : "𝒾", - "\\mscrj" : "𝒿", - "\\mscrk" : "𝓀", - "\\mscrm" : "𝓂", - "\\mscrn" : "𝓃", - "\\mscrp" : "𝓅", - "\\mscrq" : "𝓆", - "\\mscrr" : "𝓇", - "\\mscrs" : "𝓈", - "\\mscrt" : "𝓉", - "\\mscru" : "𝓊", - "\\mscrv" : "𝓋", - "\\mscrw" : "𝓌", - "\\mscrx" : "𝓍", - "\\mscry" : "𝓎", - "\\mscrz" : "𝓏", - "\\mbfscrA" : "𝓐", - "\\mbfscrB" : "𝓑", - "\\mbfscrC" : "𝓒", - "\\mbfscrD" : "𝓓", - "\\mbfscrE" : "𝓔", - "\\mbfscrF" : "𝓕", - "\\mbfscrG" : "𝓖", - "\\mbfscrH" : "𝓗", - "\\mbfscrI" : "𝓘", - "\\mbfscrJ" : "𝓙", - "\\mbfscrK" : "𝓚", - "\\mbfscrL" : "𝓛", - "\\mbfscrM" : "𝓜", - "\\mbfscrN" : "𝓝", - "\\mbfscrO" : "𝓞", - "\\mbfscrP" : "𝓟", - "\\mbfscrQ" : "𝓠", - "\\mbfscrR" : "𝓡", - "\\mbfscrS" : "𝓢", - "\\mbfscrT" : "𝓣", - "\\mbfscrU" : "𝓤", - "\\mbfscrV" : "𝓥", - "\\mbfscrW" : "𝓦", - "\\mbfscrX" : "𝓧", - "\\mbfscrY" : "𝓨", - "\\mbfscrZ" : "𝓩", - "\\mbfscra" : "𝓪", - "\\mbfscrb" : "𝓫", - "\\mbfscrc" : "𝓬", - "\\mbfscrd" : "𝓭", - "\\mbfscre" : "𝓮", - "\\mbfscrf" : "𝓯", - "\\mbfscrg" : "𝓰", - "\\mbfscrh" : "𝓱", - "\\mbfscri" : "𝓲", - "\\mbfscrj" : "𝓳", - "\\mbfscrk" : "𝓴", - "\\mbfscrl" : "𝓵", - "\\mbfscrm" : "𝓶", - "\\mbfscrn" : "𝓷", - "\\mbfscro" : "𝓸", - "\\mbfscrp" : "𝓹", - "\\mbfscrq" : "𝓺", - "\\mbfscrr" : "𝓻", - "\\mbfscrs" : "𝓼", - "\\mbfscrt" : "𝓽", - "\\mbfscru" : "𝓾", - "\\mbfscrv" : "𝓿", - "\\mbfscrw" : "𝔀", - "\\mbfscrx" : "𝔁", - "\\mbfscry" : "𝔂", - "\\mbfscrz" : "𝔃", - "\\mfrakA" : "𝔄", - "\\mfrakB" : "𝔅", - "\\mfrakD" : "𝔇", - "\\mfrakE" : "𝔈", - "\\mfrakF" : "𝔉", - "\\mfrakG" : "𝔊", - "\\mfrakJ" : "𝔍", - "\\mfrakK" : "𝔎", - "\\mfrakL" : "𝔏", - "\\mfrakM" : "𝔐", - "\\mfrakN" : "𝔑", - "\\mfrakO" : "𝔒", - "\\mfrakP" : "𝔓", - "\\mfrakQ" : "𝔔", - "\\mfrakS" : "𝔖", - "\\mfrakT" : "𝔗", - "\\mfrakU" : "𝔘", - "\\mfrakV" : "𝔙", - "\\mfrakW" : "𝔚", - "\\mfrakX" : "𝔛", - "\\mfrakY" : "𝔜", - "\\mfraka" : "𝔞", - "\\mfrakb" : "𝔟", - "\\mfrakc" : "𝔠", - "\\mfrakd" : "𝔡", - "\\mfrake" : "𝔢", - "\\mfrakf" : "𝔣", - "\\mfrakg" : "𝔤", - "\\mfrakh" : "𝔥", - "\\mfraki" : "𝔦", - "\\mfrakj" : "𝔧", - "\\mfrakk" : "𝔨", - "\\mfrakl" : "𝔩", - "\\mfrakm" : "𝔪", - "\\mfrakn" : "𝔫", - "\\mfrako" : "𝔬", - "\\mfrakp" : "𝔭", - "\\mfrakq" : "𝔮", - "\\mfrakr" : "𝔯", - "\\mfraks" : "𝔰", - "\\mfrakt" : "𝔱", - "\\mfraku" : "𝔲", - "\\mfrakv" : "𝔳", - "\\mfrakw" : "𝔴", - "\\mfrakx" : "𝔵", - "\\mfraky" : "𝔶", - "\\mfrakz" : "𝔷", - "\\BbbA" : "𝔸", - "\\BbbB" : "𝔹", - "\\BbbD" : "𝔻", - "\\BbbE" : "𝔼", - "\\BbbF" : "𝔽", - "\\BbbG" : "𝔾", - "\\BbbI" : "𝕀", - "\\BbbJ" : "𝕁", - "\\BbbK" : "𝕂", - "\\BbbL" : "𝕃", - "\\BbbM" : "𝕄", - "\\BbbO" : "𝕆", - "\\BbbS" : "𝕊", - "\\BbbT" : "𝕋", - "\\BbbU" : "𝕌", - "\\BbbV" : "𝕍", - "\\BbbW" : "𝕎", - "\\BbbX" : "𝕏", - "\\BbbY" : "𝕐", - "\\Bbba" : "𝕒", - "\\Bbbb" : "𝕓", - "\\Bbbc" : "𝕔", - "\\Bbbd" : "𝕕", - "\\Bbbe" : "𝕖", - "\\Bbbf" : "𝕗", - "\\Bbbg" : "𝕘", - "\\Bbbh" : "𝕙", - "\\Bbbi" : "𝕚", - "\\Bbbj" : "𝕛", - "\\Bbbk" : "𝕜", - "\\Bbbl" : "𝕝", - "\\Bbbm" : "𝕞", - "\\Bbbn" : "𝕟", - "\\Bbbo" : "𝕠", - "\\Bbbp" : "𝕡", - "\\Bbbq" : "𝕢", - "\\Bbbr" : "𝕣", - "\\Bbbs" : "𝕤", - "\\Bbbt" : "𝕥", - "\\Bbbu" : "𝕦", - "\\Bbbv" : "𝕧", - "\\Bbbw" : "𝕨", - "\\Bbbx" : "𝕩", - "\\Bbby" : "𝕪", - "\\Bbbz" : "𝕫", - "\\mbffrakA" : "𝕬", - "\\mbffrakB" : "𝕭", - "\\mbffrakC" : "𝕮", - "\\mbffrakD" : "𝕯", - "\\mbffrakE" : "𝕰", - "\\mbffrakF" : "𝕱", - "\\mbffrakG" : "𝕲", - "\\mbffrakH" : "𝕳", - "\\mbffrakI" : "𝕴", - "\\mbffrakJ" : "𝕵", - "\\mbffrakK" : "𝕶", - "\\mbffrakL" : "𝕷", - "\\mbffrakM" : "𝕸", - "\\mbffrakN" : "𝕹", - "\\mbffrakO" : "𝕺", - "\\mbffrakP" : "𝕻", - "\\mbffrakQ" : "𝕼", - "\\mbffrakR" : "𝕽", - "\\mbffrakS" : "𝕾", - "\\mbffrakT" : "𝕿", - "\\mbffrakU" : "𝖀", - "\\mbffrakV" : "𝖁", - "\\mbffrakW" : "𝖂", - "\\mbffrakX" : "𝖃", - "\\mbffrakY" : "𝖄", - "\\mbffrakZ" : "𝖅", - "\\mbffraka" : "𝖆", - "\\mbffrakb" : "𝖇", - "\\mbffrakc" : "𝖈", - "\\mbffrakd" : "𝖉", - "\\mbffrake" : "𝖊", - "\\mbffrakf" : "𝖋", - "\\mbffrakg" : "𝖌", - "\\mbffrakh" : "𝖍", - "\\mbffraki" : "𝖎", - "\\mbffrakj" : "𝖏", - "\\mbffrakk" : "𝖐", - "\\mbffrakl" : "𝖑", - "\\mbffrakm" : "𝖒", - "\\mbffrakn" : "𝖓", - "\\mbffrako" : "𝖔", - "\\mbffrakp" : "𝖕", - "\\mbffrakq" : "𝖖", - "\\mbffrakr" : "𝖗", - "\\mbffraks" : "𝖘", - "\\mbffrakt" : "𝖙", - "\\mbffraku" : "𝖚", - "\\mbffrakv" : "𝖛", - "\\mbffrakw" : "𝖜", - "\\mbffrakx" : "𝖝", - "\\mbffraky" : "𝖞", - "\\mbffrakz" : "𝖟", - "\\msansA" : "𝖠", - "\\msansB" : "𝖡", - "\\msansC" : "𝖢", - "\\msansD" : "𝖣", - "\\msansE" : "𝖤", - "\\msansF" : "𝖥", - "\\msansG" : "𝖦", - "\\msansH" : "𝖧", - "\\msansI" : "𝖨", - "\\msansJ" : "𝖩", - "\\msansK" : "𝖪", - "\\msansL" : "𝖫", - "\\msansM" : "𝖬", - "\\msansN" : "𝖭", - "\\msansO" : "𝖮", - "\\msansP" : "𝖯", - "\\msansQ" : "𝖰", - "\\msansR" : "𝖱", - "\\msansS" : "𝖲", - "\\msansT" : "𝖳", - "\\msansU" : "𝖴", - "\\msansV" : "𝖵", - "\\msansW" : "𝖶", - "\\msansX" : "𝖷", - "\\msansY" : "𝖸", - "\\msansZ" : "𝖹", - "\\msansa" : "𝖺", - "\\msansb" : "𝖻", - "\\msansc" : "𝖼", - "\\msansd" : "𝖽", - "\\msanse" : "𝖾", - "\\msansf" : "𝖿", - "\\msansg" : "𝗀", - "\\msansh" : "𝗁", - "\\msansi" : "𝗂", - "\\msansj" : "𝗃", - "\\msansk" : "𝗄", - "\\msansl" : "𝗅", - "\\msansm" : "𝗆", - "\\msansn" : "𝗇", - "\\msanso" : "𝗈", - "\\msansp" : "𝗉", - "\\msansq" : "𝗊", - "\\msansr" : "𝗋", - "\\msanss" : "𝗌", - "\\msanst" : "𝗍", - "\\msansu" : "𝗎", - "\\msansv" : "𝗏", - "\\msansw" : "𝗐", - "\\msansx" : "𝗑", - "\\msansy" : "𝗒", - "\\msansz" : "𝗓", - "\\mbfsansA" : "𝗔", - "\\mbfsansB" : "𝗕", - "\\mbfsansC" : "𝗖", - "\\mbfsansD" : "𝗗", - "\\mbfsansE" : "𝗘", - "\\mbfsansF" : "𝗙", - "\\mbfsansG" : "𝗚", - "\\mbfsansH" : "𝗛", - "\\mbfsansI" : "𝗜", - "\\mbfsansJ" : "𝗝", - "\\mbfsansK" : "𝗞", - "\\mbfsansL" : "𝗟", - "\\mbfsansM" : "𝗠", - "\\mbfsansN" : "𝗡", - "\\mbfsansO" : "𝗢", - "\\mbfsansP" : "𝗣", - "\\mbfsansQ" : "𝗤", - "\\mbfsansR" : "𝗥", - "\\mbfsansS" : "𝗦", - "\\mbfsansT" : "𝗧", - "\\mbfsansU" : "𝗨", - "\\mbfsansV" : "𝗩", - "\\mbfsansW" : "𝗪", - "\\mbfsansX" : "𝗫", - "\\mbfsansY" : "𝗬", - "\\mbfsansZ" : "𝗭", - "\\mbfsansa" : "𝗮", - "\\mbfsansb" : "𝗯", - "\\mbfsansc" : "𝗰", - "\\mbfsansd" : "𝗱", - "\\mbfsanse" : "𝗲", - "\\mbfsansf" : "𝗳", - "\\mbfsansg" : "𝗴", - "\\mbfsansh" : "𝗵", - "\\mbfsansi" : "𝗶", - "\\mbfsansj" : "𝗷", - "\\mbfsansk" : "𝗸", - "\\mbfsansl" : "𝗹", - "\\mbfsansm" : "𝗺", - "\\mbfsansn" : "𝗻", - "\\mbfsanso" : "𝗼", - "\\mbfsansp" : "𝗽", - "\\mbfsansq" : "𝗾", - "\\mbfsansr" : "𝗿", - "\\mbfsanss" : "𝘀", - "\\mbfsanst" : "𝘁", - "\\mbfsansu" : "𝘂", - "\\mbfsansv" : "𝘃", - "\\mbfsansw" : "𝘄", - "\\mbfsansx" : "𝘅", - "\\mbfsansy" : "𝘆", - "\\mbfsansz" : "𝘇", - "\\mitsansA" : "𝘈", - "\\mitsansB" : "𝘉", - "\\mitsansC" : "𝘊", - "\\mitsansD" : "𝘋", - "\\mitsansE" : "𝘌", - "\\mitsansF" : "𝘍", - "\\mitsansG" : "𝘎", - "\\mitsansH" : "𝘏", - "\\mitsansI" : "𝘐", - "\\mitsansJ" : "𝘑", - "\\mitsansK" : "𝘒", - "\\mitsansL" : "𝘓", - "\\mitsansM" : "𝘔", - "\\mitsansN" : "𝘕", - "\\mitsansO" : "𝘖", - "\\mitsansP" : "𝘗", - "\\mitsansQ" : "𝘘", - "\\mitsansR" : "𝘙", - "\\mitsansS" : "𝘚", - "\\mitsansT" : "𝘛", - "\\mitsansU" : "𝘜", - "\\mitsansV" : "𝘝", - "\\mitsansW" : "𝘞", - "\\mitsansX" : "𝘟", - "\\mitsansY" : "𝘠", - "\\mitsansZ" : "𝘡", - "\\mitsansa" : "𝘢", - "\\mitsansb" : "𝘣", - "\\mitsansc" : "𝘤", - "\\mitsansd" : "𝘥", - "\\mitsanse" : "𝘦", - "\\mitsansf" : "𝘧", - "\\mitsansg" : "𝘨", - "\\mitsansh" : "𝘩", - "\\mitsansi" : "𝘪", - "\\mitsansj" : "𝘫", - "\\mitsansk" : "𝘬", - "\\mitsansl" : "𝘭", - "\\mitsansm" : "𝘮", - "\\mitsansn" : "𝘯", - "\\mitsanso" : "𝘰", - "\\mitsansp" : "𝘱", - "\\mitsansq" : "𝘲", - "\\mitsansr" : "𝘳", - "\\mitsanss" : "𝘴", - "\\mitsanst" : "𝘵", - "\\mitsansu" : "𝘶", - "\\mitsansv" : "𝘷", - "\\mitsansw" : "𝘸", - "\\mitsansx" : "𝘹", - "\\mitsansy" : "𝘺", - "\\mitsansz" : "𝘻", - "\\mbfitsansA" : "𝘼", - "\\mbfitsansB" : "𝘽", - "\\mbfitsansC" : "𝘾", - "\\mbfitsansD" : "𝘿", - "\\mbfitsansE" : "𝙀", - "\\mbfitsansF" : "𝙁", - "\\mbfitsansG" : "𝙂", - "\\mbfitsansH" : "𝙃", - "\\mbfitsansI" : "𝙄", - "\\mbfitsansJ" : "𝙅", - "\\mbfitsansK" : "𝙆", - "\\mbfitsansL" : "𝙇", - "\\mbfitsansM" : "𝙈", - "\\mbfitsansN" : "𝙉", - "\\mbfitsansO" : "𝙊", - "\\mbfitsansP" : "𝙋", - "\\mbfitsansQ" : "𝙌", - "\\mbfitsansR" : "𝙍", - "\\mbfitsansS" : "𝙎", - "\\mbfitsansT" : "𝙏", - "\\mbfitsansU" : "𝙐", - "\\mbfitsansV" : "𝙑", - "\\mbfitsansW" : "𝙒", - "\\mbfitsansX" : "𝙓", - "\\mbfitsansY" : "𝙔", - "\\mbfitsansZ" : "𝙕", - "\\mbfitsansa" : "𝙖", - "\\mbfitsansb" : "𝙗", - "\\mbfitsansc" : "𝙘", - "\\mbfitsansd" : "𝙙", - "\\mbfitsanse" : "𝙚", - "\\mbfitsansf" : "𝙛", - "\\mbfitsansg" : "𝙜", - "\\mbfitsansh" : "𝙝", - "\\mbfitsansi" : "𝙞", - "\\mbfitsansj" : "𝙟", - "\\mbfitsansk" : "𝙠", - "\\mbfitsansl" : "𝙡", - "\\mbfitsansm" : "𝙢", - "\\mbfitsansn" : "𝙣", - "\\mbfitsanso" : "𝙤", - "\\mbfitsansp" : "𝙥", - "\\mbfitsansq" : "𝙦", - "\\mbfitsansr" : "𝙧", - "\\mbfitsanss" : "𝙨", - "\\mbfitsanst" : "𝙩", - "\\mbfitsansu" : "𝙪", - "\\mbfitsansv" : "𝙫", - "\\mbfitsansw" : "𝙬", - "\\mbfitsansx" : "𝙭", - "\\mbfitsansy" : "𝙮", - "\\mbfitsansz" : "𝙯", - "\\mttA" : "𝙰", - "\\mttB" : "𝙱", - "\\mttC" : "𝙲", - "\\mttD" : "𝙳", - "\\mttE" : "𝙴", - "\\mttF" : "𝙵", - "\\mttG" : "𝙶", - "\\mttH" : "𝙷", - "\\mttI" : "𝙸", - "\\mttJ" : "𝙹", - "\\mttK" : "𝙺", - "\\mttL" : "𝙻", - "\\mttM" : "𝙼", - "\\mttN" : "𝙽", - "\\mttO" : "𝙾", - "\\mttP" : "𝙿", - "\\mttQ" : "𝚀", - "\\mttR" : "𝚁", - "\\mttS" : "𝚂", - "\\mttT" : "𝚃", - "\\mttU" : "𝚄", - "\\mttV" : "𝚅", - "\\mttW" : "𝚆", - "\\mttX" : "𝚇", - "\\mttY" : "𝚈", - "\\mttZ" : "𝚉", - "\\mtta" : "𝚊", - "\\mttb" : "𝚋", - "\\mttc" : "𝚌", - "\\mttd" : "𝚍", - "\\mtte" : "𝚎", - "\\mttf" : "𝚏", - "\\mttg" : "𝚐", - "\\mtth" : "𝚑", - "\\mtti" : "𝚒", - "\\mttj" : "𝚓", - "\\mttk" : "𝚔", - "\\mttl" : "𝚕", - "\\mttm" : "𝚖", - "\\mttn" : "𝚗", - "\\mtto" : "𝚘", - "\\mttp" : "𝚙", - "\\mttq" : "𝚚", - "\\mttr" : "𝚛", - "\\mtts" : "𝚜", - "\\mttt" : "𝚝", - "\\mttu" : "𝚞", - "\\mttv" : "𝚟", - "\\mttw" : "𝚠", - "\\mttx" : "𝚡", - "\\mtty" : "𝚢", - "\\mttz" : "𝚣", - "\\mbfAlpha" : "𝚨", - "\\mbfBeta" : "𝚩", - "\\mbfGamma" : "𝚪", - "\\mbfDelta" : "𝚫", - "\\mbfEpsilon" : "𝚬", - "\\mbfZeta" : "𝚭", - "\\mbfEta" : "𝚮", - "\\mbfTheta" : "𝚯", - "\\mbfIota" : "𝚰", - "\\mbfKappa" : "𝚱", - "\\mbfLambda" : "𝚲", - "\\mbfMu" : "𝚳", - "\\mbfNu" : "𝚴", - "\\mbfXi" : "𝚵", - "\\mbfOmicron" : "𝚶", - "\\mbfPi" : "𝚷", - "\\mbfRho" : "𝚸", - "\\mbfvarTheta" : "𝚹", - "\\mbfSigma" : "𝚺", - "\\mbfTau" : "𝚻", - "\\mbfUpsilon" : "𝚼", - "\\mbfPhi" : "𝚽", - "\\mbfChi" : "𝚾", - "\\mbfPsi" : "𝚿", - "\\mbfOmega" : "𝛀", - "\\mbfalpha" : "𝛂", - "\\mbfbeta" : "𝛃", - "\\mbfgamma" : "𝛄", - "\\mbfdelta" : "𝛅", - "\\mbfepsilon" : "𝛆", - "\\mbfzeta" : "𝛇", - "\\mbfeta" : "𝛈", - "\\mbftheta" : "𝛉", - "\\mbfiota" : "𝛊", - "\\mbfkappa" : "𝛋", - "\\mbflambda" : "𝛌", - "\\mbfmu" : "𝛍", - "\\mbfnu" : "𝛎", - "\\mbfxi" : "𝛏", - "\\mbfomicron" : "𝛐", - "\\mbfpi" : "𝛑", - "\\mbfrho" : "𝛒", - "\\mbfvarsigma" : "𝛓", - "\\mbfsigma" : "𝛔", - "\\mbftau" : "𝛕", - "\\mbfupsilon" : "𝛖", - "\\mbfvarphi" : "𝛗", - "\\mbfchi" : "𝛘", - "\\mbfpsi" : "𝛙", - "\\mbfomega" : "𝛚", - "\\mbfvarepsilon" : "𝛜", - "\\mbfvartheta" : "𝛝", - "\\mbfvarkappa" : "𝛞", - "\\mbfphi" : "𝛟", - "\\mbfvarrho" : "𝛠", - "\\mbfvarpi" : "𝛡", - "\\mitAlpha" : "𝛢", - "\\mitBeta" : "𝛣", - "\\mitGamma" : "𝛤", - "\\mitDelta" : "𝛥", - "\\mitEpsilon" : "𝛦", - "\\mitZeta" : "𝛧", - "\\mitEta" : "𝛨", - "\\mitTheta" : "𝛩", - "\\mitIota" : "𝛪", - "\\mitKappa" : "𝛫", - "\\mitLambda" : "𝛬", - "\\mitMu" : "𝛭", - "\\mitNu" : "𝛮", - "\\mitXi" : "𝛯", - "\\mitOmicron" : "𝛰", - "\\mitPi" : "𝛱", - "\\mitRho" : "𝛲", - "\\mitvarTheta" : "𝛳", - "\\mitSigma" : "𝛴", - "\\mitTau" : "𝛵", - "\\mitUpsilon" : "𝛶", - "\\mitPhi" : "𝛷", - "\\mitChi" : "𝛸", - "\\mitPsi" : "𝛹", - "\\mitOmega" : "𝛺", - "\\mitalpha" : "𝛼", - "\\mitbeta" : "𝛽", - "\\mitgamma" : "𝛾", - "\\mitdelta" : "𝛿", - "\\mitepsilon" : "𝜀", - "\\mitzeta" : "𝜁", - "\\miteta" : "𝜂", - "\\mittheta" : "𝜃", - "\\mitiota" : "𝜄", - "\\mitkappa" : "𝜅", - "\\mitlambda" : "𝜆", - "\\mitmu" : "𝜇", - "\\mitnu" : "𝜈", - "\\mitxi" : "𝜉", - "\\mitomicron" : "𝜊", - "\\mitpi" : "𝜋", - "\\mitrho" : "𝜌", - "\\mitvarsigma" : "𝜍", - "\\mitsigma" : "𝜎", - "\\mittau" : "𝜏", - "\\mitupsilon" : "𝜐", - "\\mitphi" : "𝜑", - "\\mitchi" : "𝜒", - "\\mitpsi" : "𝜓", - "\\mitomega" : "𝜔", - "\\mitvarepsilon" : "𝜖", - "\\mitvartheta" : "𝜗", - "\\mitvarkappa" : "𝜘", - "\\mitvarphi" : "𝜙", - "\\mitvarrho" : "𝜚", - "\\mitvarpi" : "𝜛", - "\\mbfitAlpha" : "𝜜", - "\\mbfitBeta" : "𝜝", - "\\mbfitGamma" : "𝜞", - "\\mbfitDelta" : "𝜟", - "\\mbfitEpsilon" : "𝜠", - "\\mbfitZeta" : "𝜡", - "\\mbfitEta" : "𝜢", - "\\mbfitTheta" : "𝜣", - "\\mbfitIota" : "𝜤", - "\\mbfitKappa" : "𝜥", - "\\mbfitLambda" : "𝜦", - "\\mbfitMu" : "𝜧", - "\\mbfitNu" : "𝜨", - "\\mbfitXi" : "𝜩", - "\\mbfitOmicron" : "𝜪", - "\\mbfitPi" : "𝜫", - "\\mbfitRho" : "𝜬", - "\\mbfitvarTheta" : "𝜭", - "\\mbfitSigma" : "𝜮", - "\\mbfitTau" : "𝜯", - "\\mbfitUpsilon" : "𝜰", - "\\mbfitPhi" : "𝜱", - "\\mbfitChi" : "𝜲", - "\\mbfitPsi" : "𝜳", - "\\mbfitOmega" : "𝜴", - "\\mbfitalpha" : "𝜶", - "\\mbfitbeta" : "𝜷", - "\\mbfitgamma" : "𝜸", - "\\mbfitdelta" : "𝜹", - "\\mbfitepsilon" : "𝜺", - "\\mbfitzeta" : "𝜻", - "\\mbfiteta" : "𝜼", - "\\mbfittheta" : "𝜽", - "\\mbfitiota" : "𝜾", - "\\mbfitkappa" : "𝜿", - "\\mbfitlambda" : "𝝀", - "\\mbfitmu" : "𝝁", - "\\mbfitnu" : "𝝂", - "\\mbfitxi" : "𝝃", - "\\mbfitomicron" : "𝝄", - "\\mbfitpi" : "𝝅", - "\\mbfitrho" : "𝝆", - "\\mbfitvarsigma" : "𝝇", - "\\mbfitsigma" : "𝝈", - "\\mbfittau" : "𝝉", - "\\mbfitupsilon" : "𝝊", - "\\mbfitphi" : "𝝋", - "\\mbfitchi" : "𝝌", - "\\mbfitpsi" : "𝝍", - "\\mbfitomega" : "𝝎", - "\\mbfitvarepsilon" : "𝝐", - "\\mbfitvartheta" : "𝝑", - "\\mbfitvarkappa" : "𝝒", - "\\mbfitvarphi" : "𝝓", - "\\mbfitvarrho" : "𝝔", - "\\mbfitvarpi" : "𝝕", - "\\mbfsansAlpha" : "𝝖", - "\\mbfsansBeta" : "𝝗", - "\\mbfsansGamma" : "𝝘", - "\\mbfsansDelta" : "𝝙", - "\\mbfsansEpsilon" : "𝝚", - "\\mbfsansZeta" : "𝝛", - "\\mbfsansEta" : "𝝜", - "\\mbfsansTheta" : "𝝝", - "\\mbfsansIota" : "𝝞", - "\\mbfsansKappa" : "𝝟", - "\\mbfsansLambda" : "𝝠", - "\\mbfsansMu" : "𝝡", - "\\mbfsansNu" : "𝝢", - "\\mbfsansXi" : "𝝣", - "\\mbfsansOmicron" : "𝝤", - "\\mbfsansPi" : "𝝥", - "\\mbfsansRho" : "𝝦", - "\\mbfsansvarTheta" : "𝝧", - "\\mbfsansSigma" : "𝝨", - "\\mbfsansTau" : "𝝩", - "\\mbfsansUpsilon" : "𝝪", - "\\mbfsansPhi" : "𝝫", - "\\mbfsansChi" : "𝝬", - "\\mbfsansPsi" : "𝝭", - "\\mbfsansOmega" : "𝝮", - "\\mbfsansalpha" : "𝝰", - "\\mbfsansbeta" : "𝝱", - "\\mbfsansgamma" : "𝝲", - "\\mbfsansdelta" : "𝝳", - "\\mbfsansepsilon" : "𝝴", - "\\mbfsanszeta" : "𝝵", - "\\mbfsanseta" : "𝝶", - "\\mbfsanstheta" : "𝝷", - "\\mbfsansiota" : "𝝸", - "\\mbfsanskappa" : "𝝹", - "\\mbfsanslambda" : "𝝺", - "\\mbfsansmu" : "𝝻", - "\\mbfsansnu" : "𝝼", - "\\mbfsansxi" : "𝝽", - "\\mbfsansomicron" : "𝝾", - "\\mbfsanspi" : "𝝿", - "\\mbfsansrho" : "𝞀", - "\\mbfsansvarsigma" : "𝞁", - "\\mbfsanssigma" : "𝞂", - "\\mbfsanstau" : "𝞃", - "\\mbfsansupsilon" : "𝞄", - "\\mbfsansphi" : "𝞅", - "\\mbfsanschi" : "𝞆", - "\\mbfsanspsi" : "𝞇", - "\\mbfsansomega" : "𝞈", - "\\mbfsansvarepsilon" : "𝞊", - "\\mbfsansvartheta" : "𝞋", - "\\mbfsansvarkappa" : "𝞌", - "\\mbfsansvarphi" : "𝞍", - "\\mbfsansvarrho" : "𝞎", - "\\mbfsansvarpi" : "𝞏", - "\\mbfitsansAlpha" : "𝞐", - "\\mbfitsansBeta" : "𝞑", - "\\mbfitsansGamma" : "𝞒", - "\\mbfitsansDelta" : "𝞓", - "\\mbfitsansEpsilon" : "𝞔", - "\\mbfitsansZeta" : "𝞕", - "\\mbfitsansEta" : "𝞖", - "\\mbfitsansTheta" : "𝞗", - "\\mbfitsansIota" : "𝞘", - "\\mbfitsansKappa" : "𝞙", - "\\mbfitsansLambda" : "𝞚", - "\\mbfitsansMu" : "𝞛", - "\\mbfitsansNu" : "𝞜", - "\\mbfitsansXi" : "𝞝", - "\\mbfitsansOmicron" : "𝞞", - "\\mbfitsansPi" : "𝞟", - "\\mbfitsansRho" : "𝞠", - "\\mbfitsansvarTheta" : "𝞡", - "\\mbfitsansSigma" : "𝞢", - "\\mbfitsansTau" : "𝞣", - "\\mbfitsansUpsilon" : "𝞤", - "\\mbfitsansPhi" : "𝞥", - "\\mbfitsansChi" : "𝞦", - "\\mbfitsansPsi" : "𝞧", - "\\mbfitsansOmega" : "𝞨", - "\\mbfitsansalpha" : "𝞪", - "\\mbfitsansbeta" : "𝞫", - "\\mbfitsansgamma" : "𝞬", - "\\mbfitsansdelta" : "𝞭", - "\\mbfitsansepsilon" : "𝞮", - "\\mbfitsanszeta" : "𝞯", - "\\mbfitsanseta" : "𝞰", - "\\mbfitsanstheta" : "𝞱", - "\\mbfitsansiota" : "𝞲", - "\\mbfitsanskappa" : "𝞳", - "\\mbfitsanslambda" : "𝞴", - "\\mbfitsansmu" : "𝞵", - "\\mbfitsansnu" : "𝞶", - "\\mbfitsansxi" : "𝞷", - "\\mbfitsansomicron" : "𝞸", - "\\mbfitsanspi" : "𝞹", - "\\mbfitsansrho" : "𝞺", - "\\mbfitsansvarsigma" : "𝞻", - "\\mbfitsanssigma" : "𝞼", - "\\mbfitsanstau" : "𝞽", - "\\mbfitsansupsilon" : "𝞾", - "\\mbfitsansphi" : "𝞿", - "\\mbfitsanschi" : "𝟀", - "\\mbfitsanspsi" : "𝟁", - "\\mbfitsansomega" : "𝟂", - "\\mbfitsansvarepsilon" : "𝟄", - "\\mbfitsansvartheta" : "𝟅", - "\\mbfitsansvarkappa" : "𝟆", - "\\mbfitsansvarphi" : "𝟇", - "\\mbfitsansvarrho" : "𝟈", - "\\mbfitsansvarpi" : "𝟉", - "\\mbfzero" : "𝟎", - "\\mbfone" : "𝟏", - "\\mbftwo" : "𝟐", - "\\mbfthree" : "𝟑", - "\\mbffour" : "𝟒", - "\\mbffive" : "𝟓", - "\\mbfsix" : "𝟔", - "\\mbfseven" : "𝟕", - "\\mbfeight" : "𝟖", - "\\mbfnine" : "𝟗", - "\\Bbbzero" : "𝟘", - "\\Bbbone" : "𝟙", - "\\Bbbtwo" : "𝟚", - "\\Bbbthree" : "𝟛", - "\\Bbbfour" : "𝟜", - "\\Bbbfive" : "𝟝", - "\\Bbbsix" : "𝟞", - "\\Bbbseven" : "𝟟", - "\\Bbbeight" : "𝟠", - "\\Bbbnine" : "𝟡", - "\\msanszero" : "𝟢", - "\\msansone" : "𝟣", - "\\msanstwo" : "𝟤", - "\\msansthree" : "𝟥", - "\\msansfour" : "𝟦", - "\\msansfive" : "𝟧", - "\\msanssix" : "𝟨", - "\\msansseven" : "𝟩", - "\\msanseight" : "𝟪", - "\\msansnine" : "𝟫", - "\\mbfsanszero" : "𝟬", - "\\mbfsansone" : "𝟭", - "\\mbfsanstwo" : "𝟮", - "\\mbfsansthree" : "𝟯", - "\\mbfsansfour" : "𝟰", - "\\mbfsansfive" : "𝟱", - "\\mbfsanssix" : "𝟲", - "\\mbfsansseven" : "𝟳", - "\\mbfsanseight" : "𝟴", - "\\mbfsansnine" : "𝟵", - "\\mttzero" : "𝟶", - "\\mttone" : "𝟷", - "\\mtttwo" : "𝟸", - "\\mttthree" : "𝟹", - "\\mttfour" : "𝟺", - "\\mttfive" : "𝟻", - "\\mttsix" : "𝟼", - "\\mttseven" : "𝟽", - "\\mtteight" : "𝟾", - "\\mttnine" : "𝟿", + "\\scrM" : "ℳ", + "\\scro" : "ℴ", + "\\bbgamma" : "ℽ", + "\\bbGamma" : "ℾ", + "\\bbiD" : "ⅅ", + "\\bbid" : "ⅆ", + "\\bbie" : "ⅇ", + "\\bbii" : "ⅈ", + "\\bbij" : "ⅉ", + "\\bfA" : "𝐀", + "\\bfB" : "𝐁", + "\\bfC" : "𝐂", + "\\bfD" : "𝐃", + "\\bfE" : "𝐄", + "\\bfF" : "𝐅", + "\\bfG" : "𝐆", + "\\bfH" : "𝐇", + "\\bfI" : "𝐈", + "\\bfJ" : "𝐉", + "\\bfK" : "𝐊", + "\\bfL" : "𝐋", + "\\bfM" : "𝐌", + "\\bfN" : "𝐍", + "\\bfO" : "𝐎", + "\\bfP" : "𝐏", + "\\bfQ" : "𝐐", + "\\bfR" : "𝐑", + "\\bfS" : "𝐒", + "\\bfT" : "𝐓", + "\\bfU" : "𝐔", + "\\bfV" : "𝐕", + "\\bfW" : "𝐖", + "\\bfX" : "𝐗", + "\\bfY" : "𝐘", + "\\bfZ" : "𝐙", + "\\bfa" : "𝐚", + "\\bfb" : "𝐛", + "\\bfc" : "𝐜", + "\\bfd" : "𝐝", + "\\bfe" : "𝐞", + "\\bff" : "𝐟", + "\\bfg" : "𝐠", + "\\bfh" : "𝐡", + "\\bfi" : "𝐢", + "\\bfj" : "𝐣", + "\\bfk" : "𝐤", + "\\bfl" : "𝐥", + "\\bfm" : "𝐦", + "\\bfn" : "𝐧", + "\\bfo" : "𝐨", + "\\bfp" : "𝐩", + "\\bfq" : "𝐪", + "\\bfr" : "𝐫", + "\\bfs" : "𝐬", + "\\bft" : "𝐭", + "\\bfu" : "𝐮", + "\\bfv" : "𝐯", + "\\bfw" : "𝐰", + "\\bfx" : "𝐱", + "\\bfy" : "𝐲", + "\\bfz" : "𝐳", + "\\itA" : "𝐴", + "\\itB" : "𝐵", + "\\itC" : "𝐶", + "\\itD" : "𝐷", + "\\itE" : "𝐸", + "\\itF" : "𝐹", + "\\itG" : "𝐺", + "\\itH" : "𝐻", + "\\itI" : "𝐼", + "\\itJ" : "𝐽", + "\\itK" : "𝐾", + "\\itL" : "𝐿", + "\\itM" : "𝑀", + "\\itN" : "𝑁", + "\\itO" : "𝑂", + "\\itP" : "𝑃", + "\\itQ" : "𝑄", + "\\itR" : "𝑅", + "\\itS" : "𝑆", + "\\itT" : "𝑇", + "\\itU" : "𝑈", + "\\itV" : "𝑉", + "\\itW" : "𝑊", + "\\itX" : "𝑋", + "\\itY" : "𝑌", + "\\itZ" : "𝑍", + "\\ita" : "𝑎", + "\\itb" : "𝑏", + "\\itc" : "𝑐", + "\\itd" : "𝑑", + "\\ite" : "𝑒", + "\\itf" : "𝑓", + "\\itg" : "𝑔", + "\\iti" : "𝑖", + "\\itj" : "𝑗", + "\\itk" : "𝑘", + "\\itl" : "𝑙", + "\\itm" : "𝑚", + "\\itn" : "𝑛", + "\\ito" : "𝑜", + "\\itp" : "𝑝", + "\\itq" : "𝑞", + "\\itr" : "𝑟", + "\\its" : "𝑠", + "\\itt" : "𝑡", + "\\itu" : "𝑢", + "\\itv" : "𝑣", + "\\itw" : "𝑤", + "\\itx" : "𝑥", + "\\ity" : "𝑦", + "\\itz" : "𝑧", + "\\biA" : "𝑨", + "\\biB" : "𝑩", + "\\biC" : "𝑪", + "\\biD" : "𝑫", + "\\biE" : "𝑬", + "\\biF" : "𝑭", + "\\biG" : "𝑮", + "\\biH" : "𝑯", + "\\biI" : "𝑰", + "\\biJ" : "𝑱", + "\\biK" : "𝑲", + "\\biL" : "𝑳", + "\\biM" : "𝑴", + "\\biN" : "𝑵", + "\\biO" : "𝑶", + "\\biP" : "𝑷", + "\\biQ" : "𝑸", + "\\biR" : "𝑹", + "\\biS" : "𝑺", + "\\biT" : "𝑻", + "\\biU" : "𝑼", + "\\biV" : "𝑽", + "\\biW" : "𝑾", + "\\biX" : "𝑿", + "\\biY" : "𝒀", + "\\biZ" : "𝒁", + "\\bia" : "𝒂", + "\\bib" : "𝒃", + "\\bic" : "𝒄", + "\\bid" : "𝒅", + "\\bie" : "𝒆", + "\\bif" : "𝒇", + "\\big" : "𝒈", + "\\bih" : "𝒉", + "\\bii" : "𝒊", + "\\bij" : "𝒋", + "\\bik" : "𝒌", + "\\bil" : "𝒍", + "\\bim" : "𝒎", + "\\bin" : "𝒏", + "\\bio" : "𝒐", + "\\bip" : "𝒑", + "\\biq" : "𝒒", + "\\bir" : "𝒓", + "\\bis" : "𝒔", + "\\bit" : "𝒕", + "\\biu" : "𝒖", + "\\biv" : "𝒗", + "\\biw" : "𝒘", + "\\bix" : "𝒙", + "\\biy" : "𝒚", + "\\biz" : "𝒛", + "\\scrA" : "𝒜", + "\\scrC" : "𝒞", + "\\scrD" : "𝒟", + "\\scrG" : "𝒢", + "\\scrJ" : "𝒥", + "\\scrK" : "𝒦", + "\\scrN" : "𝒩", + "\\scrO" : "𝒪", + "\\scrP" : "𝒫", + "\\scrQ" : "𝒬", + "\\scrS" : "𝒮", + "\\scrT" : "𝒯", + "\\scrU" : "𝒰", + "\\scrV" : "𝒱", + "\\scrW" : "𝒲", + "\\scrX" : "𝒳", + "\\scrY" : "𝒴", + "\\scrZ" : "𝒵", + "\\scra" : "𝒶", + "\\scrb" : "𝒷", + "\\scrc" : "𝒸", + "\\scrd" : "𝒹", + "\\scrf" : "𝒻", + "\\scrh" : "𝒽", + "\\scri" : "𝒾", + "\\scrj" : "𝒿", + "\\scrk" : "𝓀", + "\\scrm" : "𝓂", + "\\scrn" : "𝓃", + "\\scrp" : "𝓅", + "\\scrq" : "𝓆", + "\\scrr" : "𝓇", + "\\scrs" : "𝓈", + "\\scrt" : "𝓉", + "\\scru" : "𝓊", + "\\scrv" : "𝓋", + "\\scrw" : "𝓌", + "\\scrx" : "𝓍", + "\\scry" : "𝓎", + "\\scrz" : "𝓏", + "\\bscrA" : "𝓐", + "\\bscrB" : "𝓑", + "\\bscrC" : "𝓒", + "\\bscrD" : "𝓓", + "\\bscrE" : "𝓔", + "\\bscrF" : "𝓕", + "\\bscrG" : "𝓖", + "\\bscrH" : "𝓗", + "\\bscrI" : "𝓘", + "\\bscrJ" : "𝓙", + "\\bscrK" : "𝓚", + "\\bscrL" : "𝓛", + "\\bscrM" : "𝓜", + "\\bscrN" : "𝓝", + "\\bscrO" : "𝓞", + "\\bscrP" : "𝓟", + "\\bscrQ" : "𝓠", + "\\bscrR" : "𝓡", + "\\bscrS" : "𝓢", + "\\bscrT" : "𝓣", + "\\bscrU" : "𝓤", + "\\bscrV" : "𝓥", + "\\bscrW" : "𝓦", + "\\bscrX" : "𝓧", + "\\bscrY" : "𝓨", + "\\bscrZ" : "𝓩", + "\\bscra" : "𝓪", + "\\bscrb" : "𝓫", + "\\bscrc" : "𝓬", + "\\bscrd" : "𝓭", + "\\bscre" : "𝓮", + "\\bscrf" : "𝓯", + "\\bscrg" : "𝓰", + "\\bscrh" : "𝓱", + "\\bscri" : "𝓲", + "\\bscrj" : "𝓳", + "\\bscrk" : "𝓴", + "\\bscrl" : "𝓵", + "\\bscrm" : "𝓶", + "\\bscrn" : "𝓷", + "\\bscro" : "𝓸", + "\\bscrp" : "𝓹", + "\\bscrq" : "𝓺", + "\\bscrr" : "𝓻", + "\\bscrs" : "𝓼", + "\\bscrt" : "𝓽", + "\\bscru" : "𝓾", + "\\bscrv" : "𝓿", + "\\bscrw" : "𝔀", + "\\bscrx" : "𝔁", + "\\bscry" : "𝔂", + "\\bscrz" : "𝔃", + "\\frakA" : "𝔄", + "\\frakB" : "𝔅", + "\\frakD" : "𝔇", + "\\frakE" : "𝔈", + "\\frakF" : "𝔉", + "\\frakG" : "𝔊", + "\\frakJ" : "𝔍", + "\\frakK" : "𝔎", + "\\frakL" : "𝔏", + "\\frakM" : "𝔐", + "\\frakN" : "𝔑", + "\\frakO" : "𝔒", + "\\frakP" : "𝔓", + "\\frakQ" : "𝔔", + "\\frakS" : "𝔖", + "\\frakT" : "𝔗", + "\\frakU" : "𝔘", + "\\frakV" : "𝔙", + "\\frakW" : "𝔚", + "\\frakX" : "𝔛", + "\\frakY" : "𝔜", + "\\fraka" : "𝔞", + "\\frakb" : "𝔟", + "\\frakc" : "𝔠", + "\\frakd" : "𝔡", + "\\frake" : "𝔢", + "\\frakf" : "𝔣", + "\\frakg" : "𝔤", + "\\frakh" : "𝔥", + "\\fraki" : "𝔦", + "\\frakj" : "𝔧", + "\\frakk" : "𝔨", + "\\frakl" : "𝔩", + "\\frakm" : "𝔪", + "\\frakn" : "𝔫", + "\\frako" : "𝔬", + "\\frakp" : "𝔭", + "\\frakq" : "𝔮", + "\\frakr" : "𝔯", + "\\fraks" : "𝔰", + "\\frakt" : "𝔱", + "\\fraku" : "𝔲", + "\\frakv" : "𝔳", + "\\frakw" : "𝔴", + "\\frakx" : "𝔵", + "\\fraky" : "𝔶", + "\\frakz" : "𝔷", + "\\bbA" : "𝔸", + "\\bbB" : "𝔹", + "\\bbD" : "𝔻", + "\\bbE" : "𝔼", + "\\bbF" : "𝔽", + "\\bbG" : "𝔾", + "\\bbI" : "𝕀", + "\\bbJ" : "𝕁", + "\\bbK" : "𝕂", + "\\bbL" : "𝕃", + "\\bbM" : "𝕄", + "\\bbO" : "𝕆", + "\\bbS" : "𝕊", + "\\bbT" : "𝕋", + "\\bbU" : "𝕌", + "\\bbV" : "𝕍", + "\\bbW" : "𝕎", + "\\bbX" : "𝕏", + "\\bbY" : "𝕐", + "\\bba" : "𝕒", + "\\bbb" : "𝕓", + "\\bbc" : "𝕔", + "\\bbd" : "𝕕", + "\\bbe" : "𝕖", + "\\bbf" : "𝕗", + "\\bbg" : "𝕘", + "\\bbh" : "𝕙", + "\\bbi" : "𝕚", + "\\bbj" : "𝕛", + "\\bbk" : "𝕜", + "\\bbl" : "𝕝", + "\\bbm" : "𝕞", + "\\bbn" : "𝕟", + "\\bbo" : "𝕠", + "\\bbp" : "𝕡", + "\\bbq" : "𝕢", + "\\bbr" : "𝕣", + "\\bbs" : "𝕤", + "\\bbt" : "𝕥", + "\\bbu" : "𝕦", + "\\bbv" : "𝕧", + "\\bbw" : "𝕨", + "\\bbx" : "𝕩", + "\\bby" : "𝕪", + "\\bbz" : "𝕫", + "\\bfrakA" : "𝕬", + "\\bfrakB" : "𝕭", + "\\bfrakC" : "𝕮", + "\\bfrakD" : "𝕯", + "\\bfrakE" : "𝕰", + "\\bfrakF" : "𝕱", + "\\bfrakG" : "𝕲", + "\\bfrakH" : "𝕳", + "\\bfrakI" : "𝕴", + "\\bfrakJ" : "𝕵", + "\\bfrakK" : "𝕶", + "\\bfrakL" : "𝕷", + "\\bfrakM" : "𝕸", + "\\bfrakN" : "𝕹", + "\\bfrakO" : "𝕺", + "\\bfrakP" : "𝕻", + "\\bfrakQ" : "𝕼", + "\\bfrakR" : "𝕽", + "\\bfrakS" : "𝕾", + "\\bfrakT" : "𝕿", + "\\bfrakU" : "𝖀", + "\\bfrakV" : "𝖁", + "\\bfrakW" : "𝖂", + "\\bfrakX" : "𝖃", + "\\bfrakY" : "𝖄", + "\\bfrakZ" : "𝖅", + "\\bfraka" : "𝖆", + "\\bfrakb" : "𝖇", + "\\bfrakc" : "𝖈", + "\\bfrakd" : "𝖉", + "\\bfrake" : "𝖊", + "\\bfrakf" : "𝖋", + "\\bfrakg" : "𝖌", + "\\bfrakh" : "𝖍", + "\\bfraki" : "𝖎", + "\\bfrakj" : "𝖏", + "\\bfrakk" : "𝖐", + "\\bfrakl" : "𝖑", + "\\bfrakm" : "𝖒", + "\\bfrakn" : "𝖓", + "\\bfrako" : "𝖔", + "\\bfrakp" : "𝖕", + "\\bfrakq" : "𝖖", + "\\bfrakr" : "𝖗", + "\\bfraks" : "𝖘", + "\\bfrakt" : "𝖙", + "\\bfraku" : "𝖚", + "\\bfrakv" : "𝖛", + "\\bfrakw" : "𝖜", + "\\bfrakx" : "𝖝", + "\\bfraky" : "𝖞", + "\\bfrakz" : "𝖟", + "\\sansA" : "𝖠", + "\\sansB" : "𝖡", + "\\sansC" : "𝖢", + "\\sansD" : "𝖣", + "\\sansE" : "𝖤", + "\\sansF" : "𝖥", + "\\sansG" : "𝖦", + "\\sansH" : "𝖧", + "\\sansI" : "𝖨", + "\\sansJ" : "𝖩", + "\\sansK" : "𝖪", + "\\sansL" : "𝖫", + "\\sansM" : "𝖬", + "\\sansN" : "𝖭", + "\\sansO" : "𝖮", + "\\sansP" : "𝖯", + "\\sansQ" : "𝖰", + "\\sansR" : "𝖱", + "\\sansS" : "𝖲", + "\\sansT" : "𝖳", + "\\sansU" : "𝖴", + "\\sansV" : "𝖵", + "\\sansW" : "𝖶", + "\\sansX" : "𝖷", + "\\sansY" : "𝖸", + "\\sansZ" : "𝖹", + "\\sansa" : "𝖺", + "\\sansb" : "𝖻", + "\\sansc" : "𝖼", + "\\sansd" : "𝖽", + "\\sanse" : "𝖾", + "\\sansf" : "𝖿", + "\\sansg" : "𝗀", + "\\sansh" : "𝗁", + "\\sansi" : "𝗂", + "\\sansj" : "𝗃", + "\\sansk" : "𝗄", + "\\sansl" : "𝗅", + "\\sansm" : "𝗆", + "\\sansn" : "𝗇", + "\\sanso" : "𝗈", + "\\sansp" : "𝗉", + "\\sansq" : "𝗊", + "\\sansr" : "𝗋", + "\\sanss" : "𝗌", + "\\sanst" : "𝗍", + "\\sansu" : "𝗎", + "\\sansv" : "𝗏", + "\\sansw" : "𝗐", + "\\sansx" : "𝗑", + "\\sansy" : "𝗒", + "\\sansz" : "𝗓", + "\\bsansA" : "𝗔", + "\\bsansB" : "𝗕", + "\\bsansC" : "𝗖", + "\\bsansD" : "𝗗", + "\\bsansE" : "𝗘", + "\\bsansF" : "𝗙", + "\\bsansG" : "𝗚", + "\\bsansH" : "𝗛", + "\\bsansI" : "𝗜", + "\\bsansJ" : "𝗝", + "\\bsansK" : "𝗞", + "\\bsansL" : "𝗟", + "\\bsansM" : "𝗠", + "\\bsansN" : "𝗡", + "\\bsansO" : "𝗢", + "\\bsansP" : "𝗣", + "\\bsansQ" : "𝗤", + "\\bsansR" : "𝗥", + "\\bsansS" : "𝗦", + "\\bsansT" : "𝗧", + "\\bsansU" : "𝗨", + "\\bsansV" : "𝗩", + "\\bsansW" : "𝗪", + "\\bsansX" : "𝗫", + "\\bsansY" : "𝗬", + "\\bsansZ" : "𝗭", + "\\bsansa" : "𝗮", + "\\bsansb" : "𝗯", + "\\bsansc" : "𝗰", + "\\bsansd" : "𝗱", + "\\bsanse" : "𝗲", + "\\bsansf" : "𝗳", + "\\bsansg" : "𝗴", + "\\bsansh" : "𝗵", + "\\bsansi" : "𝗶", + "\\bsansj" : "𝗷", + "\\bsansk" : "𝗸", + "\\bsansl" : "𝗹", + "\\bsansm" : "𝗺", + "\\bsansn" : "𝗻", + "\\bsanso" : "𝗼", + "\\bsansp" : "𝗽", + "\\bsansq" : "𝗾", + "\\bsansr" : "𝗿", + "\\bsanss" : "𝘀", + "\\bsanst" : "𝘁", + "\\bsansu" : "𝘂", + "\\bsansv" : "𝘃", + "\\bsansw" : "𝘄", + "\\bsansx" : "𝘅", + "\\bsansy" : "𝘆", + "\\bsansz" : "𝘇", + "\\isansA" : "𝘈", + "\\isansB" : "𝘉", + "\\isansC" : "𝘊", + "\\isansD" : "𝘋", + "\\isansE" : "𝘌", + "\\isansF" : "𝘍", + "\\isansG" : "𝘎", + "\\isansH" : "𝘏", + "\\isansI" : "𝘐", + "\\isansJ" : "𝘑", + "\\isansK" : "𝘒", + "\\isansL" : "𝘓", + "\\isansM" : "𝘔", + "\\isansN" : "𝘕", + "\\isansO" : "𝘖", + "\\isansP" : "𝘗", + "\\isansQ" : "𝘘", + "\\isansR" : "𝘙", + "\\isansS" : "𝘚", + "\\isansT" : "𝘛", + "\\isansU" : "𝘜", + "\\isansV" : "𝘝", + "\\isansW" : "𝘞", + "\\isansX" : "𝘟", + "\\isansY" : "𝘠", + "\\isansZ" : "𝘡", + "\\isansa" : "𝘢", + "\\isansb" : "𝘣", + "\\isansc" : "𝘤", + "\\isansd" : "𝘥", + "\\isanse" : "𝘦", + "\\isansf" : "𝘧", + "\\isansg" : "𝘨", + "\\isansh" : "𝘩", + "\\isansi" : "𝘪", + "\\isansj" : "𝘫", + "\\isansk" : "𝘬", + "\\isansl" : "𝘭", + "\\isansm" : "𝘮", + "\\isansn" : "𝘯", + "\\isanso" : "𝘰", + "\\isansp" : "𝘱", + "\\isansq" : "𝘲", + "\\isansr" : "𝘳", + "\\isanss" : "𝘴", + "\\isanst" : "𝘵", + "\\isansu" : "𝘶", + "\\isansv" : "𝘷", + "\\isansw" : "𝘸", + "\\isansx" : "𝘹", + "\\isansy" : "𝘺", + "\\isansz" : "𝘻", + "\\bisansA" : "𝘼", + "\\bisansB" : "𝘽", + "\\bisansC" : "𝘾", + "\\bisansD" : "𝘿", + "\\bisansE" : "𝙀", + "\\bisansF" : "𝙁", + "\\bisansG" : "𝙂", + "\\bisansH" : "𝙃", + "\\bisansI" : "𝙄", + "\\bisansJ" : "𝙅", + "\\bisansK" : "𝙆", + "\\bisansL" : "𝙇", + "\\bisansM" : "𝙈", + "\\bisansN" : "𝙉", + "\\bisansO" : "𝙊", + "\\bisansP" : "𝙋", + "\\bisansQ" : "𝙌", + "\\bisansR" : "𝙍", + "\\bisansS" : "𝙎", + "\\bisansT" : "𝙏", + "\\bisansU" : "𝙐", + "\\bisansV" : "𝙑", + "\\bisansW" : "𝙒", + "\\bisansX" : "𝙓", + "\\bisansY" : "𝙔", + "\\bisansZ" : "𝙕", + "\\bisansa" : "𝙖", + "\\bisansb" : "𝙗", + "\\bisansc" : "𝙘", + "\\bisansd" : "𝙙", + "\\bisanse" : "𝙚", + "\\bisansf" : "𝙛", + "\\bisansg" : "𝙜", + "\\bisansh" : "𝙝", + "\\bisansi" : "𝙞", + "\\bisansj" : "𝙟", + "\\bisansk" : "𝙠", + "\\bisansl" : "𝙡", + "\\bisansm" : "𝙢", + "\\bisansn" : "𝙣", + "\\bisanso" : "𝙤", + "\\bisansp" : "𝙥", + "\\bisansq" : "𝙦", + "\\bisansr" : "𝙧", + "\\bisanss" : "𝙨", + "\\bisanst" : "𝙩", + "\\bisansu" : "𝙪", + "\\bisansv" : "𝙫", + "\\bisansw" : "𝙬", + "\\bisansx" : "𝙭", + "\\bisansy" : "𝙮", + "\\bisansz" : "𝙯", + "\\ttA" : "𝙰", + "\\ttB" : "𝙱", + "\\ttC" : "𝙲", + "\\ttD" : "𝙳", + "\\ttE" : "𝙴", + "\\ttF" : "𝙵", + "\\ttG" : "𝙶", + "\\ttH" : "𝙷", + "\\ttI" : "𝙸", + "\\ttJ" : "𝙹", + "\\ttK" : "𝙺", + "\\ttL" : "𝙻", + "\\ttM" : "𝙼", + "\\ttN" : "𝙽", + "\\ttO" : "𝙾", + "\\ttP" : "𝙿", + "\\ttQ" : "𝚀", + "\\ttR" : "𝚁", + "\\ttS" : "𝚂", + "\\ttT" : "𝚃", + "\\ttU" : "𝚄", + "\\ttV" : "𝚅", + "\\ttW" : "𝚆", + "\\ttX" : "𝚇", + "\\ttY" : "𝚈", + "\\ttZ" : "𝚉", + "\\tta" : "𝚊", + "\\ttb" : "𝚋", + "\\ttc" : "𝚌", + "\\ttd" : "𝚍", + "\\tte" : "𝚎", + "\\ttf" : "𝚏", + "\\ttg" : "𝚐", + "\\tth" : "𝚑", + "\\tti" : "𝚒", + "\\ttj" : "𝚓", + "\\ttk" : "𝚔", + "\\ttl" : "𝚕", + "\\ttm" : "𝚖", + "\\ttn" : "𝚗", + "\\tto" : "𝚘", + "\\ttp" : "𝚙", + "\\ttq" : "𝚚", + "\\ttr" : "𝚛", + "\\tts" : "𝚜", + "\\ttt" : "𝚝", + "\\ttu" : "𝚞", + "\\ttv" : "𝚟", + "\\ttw" : "𝚠", + "\\ttx" : "𝚡", + "\\tty" : "𝚢", + "\\ttz" : "𝚣", + "\\bfAlpha" : "𝚨", + "\\bfBeta" : "𝚩", + "\\bfGamma" : "𝚪", + "\\bfDelta" : "𝚫", + "\\bfEpsilon" : "𝚬", + "\\bfZeta" : "𝚭", + "\\bfEta" : "𝚮", + "\\bfTheta" : "𝚯", + "\\bfIota" : "𝚰", + "\\bfKappa" : "𝚱", + "\\bfLambda" : "𝚲", + "\\bfMu" : "𝚳", + "\\bfNu" : "𝚴", + "\\bfXi" : "𝚵", + "\\bfOmicron" : "𝚶", + "\\bfPi" : "𝚷", + "\\bfRho" : "𝚸", + "\\bfvarTheta" : "𝚹", + "\\bfSigma" : "𝚺", + "\\bfTau" : "𝚻", + "\\bfUpsilon" : "𝚼", + "\\bfPhi" : "𝚽", + "\\bfChi" : "𝚾", + "\\bfPsi" : "𝚿", + "\\bfOmega" : "𝛀", + "\\bfalpha" : "𝛂", + "\\bfbeta" : "𝛃", + "\\bfgamma" : "𝛄", + "\\bfdelta" : "𝛅", + "\\bfepsilon" : "𝛆", + "\\bfzeta" : "𝛇", + "\\bfeta" : "𝛈", + "\\bftheta" : "𝛉", + "\\bfiota" : "𝛊", + "\\bfkappa" : "𝛋", + "\\bflambda" : "𝛌", + "\\bfmu" : "𝛍", + "\\bfnu" : "𝛎", + "\\bfxi" : "𝛏", + "\\bfomicron" : "𝛐", + "\\bfpi" : "𝛑", + "\\bfrho" : "𝛒", + "\\bfvarsigma" : "𝛓", + "\\bfsigma" : "𝛔", + "\\bftau" : "𝛕", + "\\bfupsilon" : "𝛖", + "\\bfvarphi" : "𝛗", + "\\bfchi" : "𝛘", + "\\bfpsi" : "𝛙", + "\\bfomega" : "𝛚", + "\\bfvarepsilon" : "𝛜", + "\\bfvartheta" : "𝛝", + "\\bfvarkappa" : "𝛞", + "\\bfphi" : "𝛟", + "\\bfvarrho" : "𝛠", + "\\bfvarpi" : "𝛡", + "\\itAlpha" : "𝛢", + "\\itBeta" : "𝛣", + "\\itGamma" : "𝛤", + "\\itDelta" : "𝛥", + "\\itEpsilon" : "𝛦", + "\\itZeta" : "𝛧", + "\\itEta" : "𝛨", + "\\itTheta" : "𝛩", + "\\itIota" : "𝛪", + "\\itKappa" : "𝛫", + "\\itLambda" : "𝛬", + "\\itMu" : "𝛭", + "\\itNu" : "𝛮", + "\\itXi" : "𝛯", + "\\itOmicron" : "𝛰", + "\\itPi" : "𝛱", + "\\itRho" : "𝛲", + "\\itvarTheta" : "𝛳", + "\\itSigma" : "𝛴", + "\\itTau" : "𝛵", + "\\itUpsilon" : "𝛶", + "\\itPhi" : "𝛷", + "\\itChi" : "𝛸", + "\\itPsi" : "𝛹", + "\\itOmega" : "𝛺", + "\\italpha" : "𝛼", + "\\itbeta" : "𝛽", + "\\itgamma" : "𝛾", + "\\itdelta" : "𝛿", + "\\itepsilon" : "𝜀", + "\\itzeta" : "𝜁", + "\\iteta" : "𝜂", + "\\ittheta" : "𝜃", + "\\itiota" : "𝜄", + "\\itkappa" : "𝜅", + "\\itlambda" : "𝜆", + "\\itmu" : "𝜇", + "\\itnu" : "𝜈", + "\\itxi" : "𝜉", + "\\itomicron" : "𝜊", + "\\itpi" : "𝜋", + "\\itrho" : "𝜌", + "\\itvarsigma" : "𝜍", + "\\itsigma" : "𝜎", + "\\ittau" : "𝜏", + "\\itupsilon" : "𝜐", + "\\itphi" : "𝜑", + "\\itchi" : "𝜒", + "\\itpsi" : "𝜓", + "\\itomega" : "𝜔", + "\\itvarepsilon" : "𝜖", + "\\itvartheta" : "𝜗", + "\\itvarkappa" : "𝜘", + "\\itvarphi" : "𝜙", + "\\itvarrho" : "𝜚", + "\\itvarpi" : "𝜛", + "\\biAlpha" : "𝜜", + "\\biBeta" : "𝜝", + "\\biGamma" : "𝜞", + "\\biDelta" : "𝜟", + "\\biEpsilon" : "𝜠", + "\\biZeta" : "𝜡", + "\\biEta" : "𝜢", + "\\biTheta" : "𝜣", + "\\biIota" : "𝜤", + "\\biKappa" : "𝜥", + "\\biLambda" : "𝜦", + "\\biMu" : "𝜧", + "\\biNu" : "𝜨", + "\\biXi" : "𝜩", + "\\biOmicron" : "𝜪", + "\\biPi" : "𝜫", + "\\biRho" : "𝜬", + "\\bivarTheta" : "𝜭", + "\\biSigma" : "𝜮", + "\\biTau" : "𝜯", + "\\biUpsilon" : "𝜰", + "\\biPhi" : "𝜱", + "\\biChi" : "𝜲", + "\\biPsi" : "𝜳", + "\\biOmega" : "𝜴", + "\\bialpha" : "𝜶", + "\\bibeta" : "𝜷", + "\\bigamma" : "𝜸", + "\\bidelta" : "𝜹", + "\\biepsilon" : "𝜺", + "\\bizeta" : "𝜻", + "\\bieta" : "𝜼", + "\\bitheta" : "𝜽", + "\\biiota" : "𝜾", + "\\bikappa" : "𝜿", + "\\bilambda" : "𝝀", + "\\bimu" : "𝝁", + "\\binu" : "𝝂", + "\\bixi" : "𝝃", + "\\biomicron" : "𝝄", + "\\bipi" : "𝝅", + "\\birho" : "𝝆", + "\\bivarsigma" : "𝝇", + "\\bisigma" : "𝝈", + "\\bitau" : "𝝉", + "\\biupsilon" : "𝝊", + "\\biphi" : "𝝋", + "\\bichi" : "𝝌", + "\\bipsi" : "𝝍", + "\\biomega" : "𝝎", + "\\bivarepsilon" : "𝝐", + "\\bivartheta" : "𝝑", + "\\bivarkappa" : "𝝒", + "\\bivarphi" : "𝝓", + "\\bivarrho" : "𝝔", + "\\bivarpi" : "𝝕", + "\\bsansAlpha" : "𝝖", + "\\bsansBeta" : "𝝗", + "\\bsansGamma" : "𝝘", + "\\bsansDelta" : "𝝙", + "\\bsansEpsilon" : "𝝚", + "\\bsansZeta" : "𝝛", + "\\bsansEta" : "𝝜", + "\\bsansTheta" : "𝝝", + "\\bsansIota" : "𝝞", + "\\bsansKappa" : "𝝟", + "\\bsansLambda" : "𝝠", + "\\bsansMu" : "𝝡", + "\\bsansNu" : "𝝢", + "\\bsansXi" : "𝝣", + "\\bsansOmicron" : "𝝤", + "\\bsansPi" : "𝝥", + "\\bsansRho" : "𝝦", + "\\bsansvarTheta" : "𝝧", + "\\bsansSigma" : "𝝨", + "\\bsansTau" : "𝝩", + "\\bsansUpsilon" : "𝝪", + "\\bsansPhi" : "𝝫", + "\\bsansChi" : "𝝬", + "\\bsansPsi" : "𝝭", + "\\bsansOmega" : "𝝮", + "\\bsansalpha" : "𝝰", + "\\bsansbeta" : "𝝱", + "\\bsansgamma" : "𝝲", + "\\bsansdelta" : "𝝳", + "\\bsansepsilon" : "𝝴", + "\\bsanszeta" : "𝝵", + "\\bsanseta" : "𝝶", + "\\bsanstheta" : "𝝷", + "\\bsansiota" : "𝝸", + "\\bsanskappa" : "𝝹", + "\\bsanslambda" : "𝝺", + "\\bsansmu" : "𝝻", + "\\bsansnu" : "𝝼", + "\\bsansxi" : "𝝽", + "\\bsansomicron" : "𝝾", + "\\bsanspi" : "𝝿", + "\\bsansrho" : "𝞀", + "\\bsansvarsigma" : "𝞁", + "\\bsanssigma" : "𝞂", + "\\bsanstau" : "𝞃", + "\\bsansupsilon" : "𝞄", + "\\bsansphi" : "𝞅", + "\\bsanschi" : "𝞆", + "\\bsanspsi" : "𝞇", + "\\bsansomega" : "𝞈", + "\\bsansvarepsilon" : "𝞊", + "\\bsansvartheta" : "𝞋", + "\\bsansvarkappa" : "𝞌", + "\\bsansvarphi" : "𝞍", + "\\bsansvarrho" : "𝞎", + "\\bsansvarpi" : "𝞏", + "\\bisansAlpha" : "𝞐", + "\\bisansBeta" : "𝞑", + "\\bisansGamma" : "𝞒", + "\\bisansDelta" : "𝞓", + "\\bisansEpsilon" : "𝞔", + "\\bisansZeta" : "𝞕", + "\\bisansEta" : "𝞖", + "\\bisansTheta" : "𝞗", + "\\bisansIota" : "𝞘", + "\\bisansKappa" : "𝞙", + "\\bisansLambda" : "𝞚", + "\\bisansMu" : "𝞛", + "\\bisansNu" : "𝞜", + "\\bisansXi" : "𝞝", + "\\bisansOmicron" : "𝞞", + "\\bisansPi" : "𝞟", + "\\bisansRho" : "𝞠", + "\\bisansvarTheta" : "𝞡", + "\\bisansSigma" : "𝞢", + "\\bisansTau" : "𝞣", + "\\bisansUpsilon" : "𝞤", + "\\bisansPhi" : "𝞥", + "\\bisansChi" : "𝞦", + "\\bisansPsi" : "𝞧", + "\\bisansOmega" : "𝞨", + "\\bisansalpha" : "𝞪", + "\\bisansbeta" : "𝞫", + "\\bisansgamma" : "𝞬", + "\\bisansdelta" : "𝞭", + "\\bisansepsilon" : "𝞮", + "\\bisanszeta" : "𝞯", + "\\bisanseta" : "𝞰", + "\\bisanstheta" : "𝞱", + "\\bisansiota" : "𝞲", + "\\bisanskappa" : "𝞳", + "\\bisanslambda" : "𝞴", + "\\bisansmu" : "𝞵", + "\\bisansnu" : "𝞶", + "\\bisansxi" : "𝞷", + "\\bisansomicron" : "𝞸", + "\\bisanspi" : "𝞹", + "\\bisansrho" : "𝞺", + "\\bisansvarsigma" : "𝞻", + "\\bisanssigma" : "𝞼", + "\\bisanstau" : "𝞽", + "\\bisansupsilon" : "𝞾", + "\\bisansphi" : "𝞿", + "\\bisanschi" : "𝟀", + "\\bisanspsi" : "𝟁", + "\\bisansomega" : "𝟂", + "\\bisansvarepsilon" : "𝟄", + "\\bisansvartheta" : "𝟅", + "\\bisansvarkappa" : "𝟆", + "\\bisansvarphi" : "𝟇", + "\\bisansvarrho" : "𝟈", + "\\bisansvarpi" : "𝟉", + "\\bfzero" : "𝟎", + "\\bfone" : "𝟏", + "\\bftwo" : "𝟐", + "\\bfthree" : "𝟑", + "\\bffour" : "𝟒", + "\\bffive" : "𝟓", + "\\bfsix" : "𝟔", + "\\bfseven" : "𝟕", + "\\bfeight" : "𝟖", + "\\bfnine" : "𝟗", + "\\bbzero" : "𝟘", + "\\bbone" : "𝟙", + "\\bbtwo" : "𝟚", + "\\bbthree" : "𝟛", + "\\bbfour" : "𝟜", + "\\bbfive" : "𝟝", + "\\bbsix" : "𝟞", + "\\bbseven" : "𝟟", + "\\bbeight" : "𝟠", + "\\bbnine" : "𝟡", + "\\sanszero" : "𝟢", + "\\sansone" : "𝟣", + "\\sanstwo" : "𝟤", + "\\sansthree" : "𝟥", + "\\sansfour" : "𝟦", + "\\sansfive" : "𝟧", + "\\sanssix" : "𝟨", + "\\sansseven" : "𝟩", + "\\sanseight" : "𝟪", + "\\sansnine" : "𝟫", + "\\bsanszero" : "𝟬", + "\\bsansone" : "𝟭", + "\\bsanstwo" : "𝟮", + "\\bsansthree" : "𝟯", + "\\bsansfour" : "𝟰", + "\\bsansfive" : "𝟱", + "\\bsanssix" : "𝟲", + "\\bsansseven" : "𝟳", + "\\bsanseight" : "𝟴", + "\\bsansnine" : "𝟵", + "\\ttzero" : "𝟶", + "\\ttone" : "𝟷", + "\\tttwo" : "𝟸", + "\\ttthree" : "𝟹", + "\\ttfour" : "𝟺", + "\\ttfive" : "𝟻", + "\\ttsix" : "𝟼", + "\\ttseven" : "𝟽", + "\\tteight" : "𝟾", + "\\ttnine" : "𝟿", + "\\underbar" : "̲", + "\\underleftrightarrow" : "͍", } diff --git a/tools/gen_latex_symbols.py b/tools/gen_latex_symbols.py index 7eb684425d9..038d8ea2e5a 100644 --- a/tools/gen_latex_symbols.py +++ b/tools/gen_latex_symbols.py @@ -18,28 +18,33 @@ # Import the Julia LaTeX symbols print('Importing latex_symbols.js from Julia...') import requests -url = 'https://raw.githubusercontent.com/JuliaLang/julia/master/base/latex_symbols.jl' +url = 'https://raw.githubusercontent.com/JuliaLang/julia/master/stdlib/REPL/src/latex_symbols.jl' r = requests.get(url) # Build a list of key, value pairs print('Building a list of (latex, unicode) key-value pairs...') -lines = r.text.splitlines()[60:] -lines = [line for line in lines if '=>' in line] -lines = [line.replace('=>',':') for line in lines] - -def line_to_tuple(line): - """Convert a single line of the .jl file to a 2-tuple of strings like ("\\alpha", "α")""" - kv = line.split(',')[0].split(':') -# kv = tuple(line.strip(', ').split(':')) - k, v = kv[0].strip(' "'), kv[1].strip(' "') -# if not test_ident(v): -# print(line) - return k, v - -assert line_to_tuple(' "\\sqrt" : "\u221A",') == ('\\sqrt', '\u221A') -lines = [line_to_tuple(line) for line in lines] - +lines = r.text.splitlines() + +prefixes_line = lines.index('# "font" prefixes') +symbols_line = lines.index('# manual additions:') + +prefix_dict = {} +for l in lines[prefixes_line + 1: symbols_line]: + p = l.split() + if not p or p[1] == 'latex_symbols': continue + prefix_dict[p[1]] = p[3] + +idents = [] +for l in lines[symbols_line:]: + if not '=>' in l: continue # if it's not a def, skip + if '#' in l: l = l[:l.index('#')] # get rid of eol comments + x, y = l.strip().split('=>') + if '*' in x: # if a prefix is present substitute it with its value + p, x = x.split('*') + x = prefix_dict[p][:-1] + x[1:] + x, y = x.split('"')[1], y.split('"')[1] # get the values in quotes + idents.append((x, y)) # Filter out non-valid identifiers print('Filtering out characters that are not valid Python 3 identifiers') @@ -53,8 +58,7 @@ def test_ident(i): assert test_ident("α") assert not test_ident('‴') -valid_idents = [line for line in lines if test_ident(line[1])] - +valid_idents = [line for line in idents if test_ident(line[1])] # Write the `latex_symbols.py` module in the cwd From 6830e3d44cb82733ed32777743e033dd2faa487c Mon Sep 17 00:00:00 2001 From: luciana Date: Mon, 15 Oct 2018 19:58:21 -0300 Subject: [PATCH 074/635] added skipif for sqlite3 version > 3.24.0 --- IPython/core/tests/test_history.py | 39 +++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index fcc22f1c00a..c3a2007c739 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -1,9 +1,9 @@ # coding: utf-8 """Tests for the IPython tab-completion machinery. """ -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # Module imports -#----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # stdlib import io @@ -11,6 +11,7 @@ import sys import tempfile from datetime import datetime +import sqlite3 # third party import nose.tools as nt @@ -20,9 +21,14 @@ from IPython.utils.tempdir import TemporaryDirectory from IPython.core.history import HistoryManager, extract_hist_ranges +from testing.decorators import skipif + + def setUp(): nt.assert_equal(sys.getdefaultencoding(), "utf-8") + +@skipif(sqlite3.version_info > (3, 24, 0)) def test_history(): ip = get_ipython() with TemporaryDirectory() as tmpdir: @@ -40,17 +46,17 @@ def test_history(): ip.history_manager.store_output(3) nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist) - + # Detailed tests for _get_range_session grs = ip.history_manager._get_range_session - nt.assert_equal(list(grs(start=2,stop=-1)), list(zip([0], [2], hist[1:-1]))) - nt.assert_equal(list(grs(start=-2)), list(zip([0,0], [2,3], hist[-2:]))) - nt.assert_equal(list(grs(output=True)), list(zip([0,0,0], [1,2,3], zip(hist, [None,None,'spam'])))) + nt.assert_equal(list(grs(start=2, stop=-1)), list(zip([0], [2], hist[1:-1]))) + nt.assert_equal(list(grs(start=-2)), list(zip([0, 0], [2, 3], hist[-2:]))) + nt.assert_equal(list(grs(output=True)), list(zip([0, 0, 0], [1, 2, 3], zip(hist, [None, None, 'spam'])))) # Check whether specifying a range beyond the end of the current # session results in an error (gh-804) ip.magic('%hist 2-500') - + # Check that we can write non-ascii characters to a file ip.magic("%%hist -f %s" % os.path.join(tmpdir, "test1")) ip.magic("%%hist -pf %s" % os.path.join(tmpdir, "test2")) @@ -66,18 +72,18 @@ def test_history(): for i, cmd in enumerate(newcmds, start=1): ip.history_manager.store_inputs(i, cmd) gothist = ip.history_manager.get_range(start=1, stop=4) - nt.assert_equal(list(gothist), list(zip([0,0,0],[1,2,3], newcmds))) + nt.assert_equal(list(gothist), list(zip([0, 0, 0], [1, 2, 3], newcmds))) # Previous session: gothist = ip.history_manager.get_range(-1, 1, 4) - nt.assert_equal(list(gothist), list(zip([1,1,1],[1,2,3], hist))) + nt.assert_equal(list(gothist), list(zip([1, 1, 1], [1, 2, 3], hist))) newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)] # Check get_hist_tail gothist = ip.history_manager.get_tail(5, output=True, - include_latest=True) + include_latest=True) expected = [(1, 3, (hist[-1], "spam"))] \ - + [(s, n, (c, None)) for (s, n, c) in newhist] + + [(s, n, (c, None)) for (s, n, c) in newhist] nt.assert_equal(list(gothist), expected) gothist = ip.history_manager.get_tail(2) @@ -85,8 +91,9 @@ def test_history(): nt.assert_equal(list(gothist), expected) # Check get_hist_search + gothist = ip.history_manager.search("*test*") - nt.assert_equal(list(gothist), [(1,2,hist[1])] ) + nt.assert_equal(list(gothist), [(1, 2, hist[1])]) gothist = ip.history_manager.search("*=*") nt.assert_equal(list(gothist), @@ -119,14 +126,14 @@ def test_history(): newhist[3]]) gothist = ip.history_manager.search("b*", output=True) - nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] ) + nt.assert_equal(list(gothist), [(1, 3, (hist[2], "spam"))]) # Cross testing: check that magic %save can get previous session. testfilename = os.path.realpath(os.path.join(tmpdir, "test.py")) ip.magic("save " + testfilename + " ~1/1-3") with io.open(testfilename, encoding='utf-8') as testfile: nt.assert_equal(testfile.read(), - u"# coding: utf-8\n" + u"\n".join(hist)+u"\n") + u"# coding: utf-8\n" + u"\n".join(hist) + u"\n") # Duplicate line numbers - check that it doesn't crash, and # gets a new session @@ -155,6 +162,7 @@ def test_extract_hist_ranges(): actual = list(extract_hist_ranges(instr)) nt.assert_equal(actual, expected) + def test_magic_rerun(): """Simple test for %rerun (no args -> rerun last line)""" ip = get_ipython() @@ -164,11 +172,13 @@ def test_magic_rerun(): ip.run_cell("%rerun", store_history=True) nt.assert_equal(ip.user_ns["a"], 12) + def test_timestamp_type(): ip = get_ipython() info = ip.history_manager.get_session_info() nt.assert_true(isinstance(info[1], datetime)) + def test_hist_file_config(): cfg = Config() tfile = tempfile.NamedTemporaryFile(delete=False) @@ -185,6 +195,7 @@ def test_hist_file_config(): # delete it. I have no clue why pass + def test_histmanager_disabled(): """Ensure that disabling the history manager doesn't create a database.""" cfg = Config() From 6acfa6fe9b76d0f2c133da438b1f9a1cc6df3a38 Mon Sep 17 00:00:00 2001 From: luciana Date: Mon, 15 Oct 2018 20:19:52 -0300 Subject: [PATCH 075/635] added skipif for sqlite3 version > 3.24.0 --- IPython/core/tests/test_history.py | 35 ++++++++++++------------------ 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index c3a2007c739..a6815edd131 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -1,9 +1,9 @@ # coding: utf-8 """Tests for the IPython tab-completion machinery. """ -# ----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # Module imports -# ----------------------------------------------------------------------------- +#----------------------------------------------------------------------------- # stdlib import io @@ -20,15 +20,12 @@ from traitlets.config.loader import Config from IPython.utils.tempdir import TemporaryDirectory from IPython.core.history import HistoryManager, extract_hist_ranges - -from testing.decorators import skipif - +from IPython.testing.decorators import skipif def setUp(): nt.assert_equal(sys.getdefaultencoding(), "utf-8") - -@skipif(sqlite3.version_info > (3, 24, 0)) +@skipif(sqlite3.version_info > (3,24,0)) def test_history(): ip = get_ipython() with TemporaryDirectory() as tmpdir: @@ -49,9 +46,9 @@ def test_history(): # Detailed tests for _get_range_session grs = ip.history_manager._get_range_session - nt.assert_equal(list(grs(start=2, stop=-1)), list(zip([0], [2], hist[1:-1]))) - nt.assert_equal(list(grs(start=-2)), list(zip([0, 0], [2, 3], hist[-2:]))) - nt.assert_equal(list(grs(output=True)), list(zip([0, 0, 0], [1, 2, 3], zip(hist, [None, None, 'spam'])))) + nt.assert_equal(list(grs(start=2,stop=-1)), list(zip([0], [2], hist[1:-1]))) + nt.assert_equal(list(grs(start=-2)), list(zip([0,0], [2,3], hist[-2:]))) + nt.assert_equal(list(grs(output=True)), list(zip([0,0,0], [1,2,3], zip(hist, [None,None,'spam'])))) # Check whether specifying a range beyond the end of the current # session results in an error (gh-804) @@ -72,18 +69,18 @@ def test_history(): for i, cmd in enumerate(newcmds, start=1): ip.history_manager.store_inputs(i, cmd) gothist = ip.history_manager.get_range(start=1, stop=4) - nt.assert_equal(list(gothist), list(zip([0, 0, 0], [1, 2, 3], newcmds))) + nt.assert_equal(list(gothist), list(zip([0,0,0],[1,2,3], newcmds))) # Previous session: gothist = ip.history_manager.get_range(-1, 1, 4) - nt.assert_equal(list(gothist), list(zip([1, 1, 1], [1, 2, 3], hist))) + nt.assert_equal(list(gothist), list(zip([1,1,1],[1,2,3], hist))) newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)] # Check get_hist_tail gothist = ip.history_manager.get_tail(5, output=True, - include_latest=True) + include_latest=True) expected = [(1, 3, (hist[-1], "spam"))] \ - + [(s, n, (c, None)) for (s, n, c) in newhist] + + [(s, n, (c, None)) for (s, n, c) in newhist] nt.assert_equal(list(gothist), expected) gothist = ip.history_manager.get_tail(2) @@ -93,7 +90,7 @@ def test_history(): # Check get_hist_search gothist = ip.history_manager.search("*test*") - nt.assert_equal(list(gothist), [(1, 2, hist[1])]) + nt.assert_equal(list(gothist), [(1,2,hist[1])] ) gothist = ip.history_manager.search("*=*") nt.assert_equal(list(gothist), @@ -126,14 +123,14 @@ def test_history(): newhist[3]]) gothist = ip.history_manager.search("b*", output=True) - nt.assert_equal(list(gothist), [(1, 3, (hist[2], "spam"))]) + nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] ) # Cross testing: check that magic %save can get previous session. testfilename = os.path.realpath(os.path.join(tmpdir, "test.py")) ip.magic("save " + testfilename + " ~1/1-3") with io.open(testfilename, encoding='utf-8') as testfile: nt.assert_equal(testfile.read(), - u"# coding: utf-8\n" + u"\n".join(hist) + u"\n") + u"# coding: utf-8\n" + u"\n".join(hist)+u"\n") # Duplicate line numbers - check that it doesn't crash, and # gets a new session @@ -162,7 +159,6 @@ def test_extract_hist_ranges(): actual = list(extract_hist_ranges(instr)) nt.assert_equal(actual, expected) - def test_magic_rerun(): """Simple test for %rerun (no args -> rerun last line)""" ip = get_ipython() @@ -172,13 +168,11 @@ def test_magic_rerun(): ip.run_cell("%rerun", store_history=True) nt.assert_equal(ip.user_ns["a"], 12) - def test_timestamp_type(): ip = get_ipython() info = ip.history_manager.get_session_info() nt.assert_true(isinstance(info[1], datetime)) - def test_hist_file_config(): cfg = Config() tfile = tempfile.NamedTemporaryFile(delete=False) @@ -195,7 +189,6 @@ def test_hist_file_config(): # delete it. I have no clue why pass - def test_histmanager_disabled(): """Ensure that disabling the history manager doesn't create a database.""" cfg = Config() From 8cd973c7c37e3571d06748e323b724ed5292d6fe Mon Sep 17 00:00:00 2001 From: ammarmallik Date: Mon, 8 Oct 2018 19:31:16 +0500 Subject: [PATCH 076/635] Replace depricated time.clock with time.perf_counter issue#11375 --- IPython/utils/timing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/utils/timing.py b/IPython/utils/timing.py index 3d4d9f8d9bc..6bb176f338c 100644 --- a/IPython/utils/timing.py +++ b/IPython/utils/timing.py @@ -59,12 +59,12 @@ def clock2(): except ImportError: # There is no distinction of user/system time under windows, so we just use # time.clock() for everything... - clocku = clocks = clock = time.clock + clocku = clocks = clock = time.perf_counter def clock2(): """Under windows, system CPU time can't be measured. This just returns clock() and zero.""" - return time.clock(),0.0 + return time.perf_counter(),0.0 def timings_out(reps,func,*args,**kw): From 375d066bd09171dba6839a19dc3c12d92192f8af Mon Sep 17 00:00:00 2001 From: ammarmallik Date: Mon, 8 Oct 2018 22:23:52 +0500 Subject: [PATCH 077/635] Update comments issue#11375 --- IPython/utils/timing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/utils/timing.py b/IPython/utils/timing.py index 6bb176f338c..9a31affadf0 100644 --- a/IPython/utils/timing.py +++ b/IPython/utils/timing.py @@ -58,12 +58,12 @@ def clock2(): return resource.getrusage(resource.RUSAGE_SELF)[:2] except ImportError: # There is no distinction of user/system time under windows, so we just use - # time.clock() for everything... + # time.perff_counter() for everything... clocku = clocks = clock = time.perf_counter def clock2(): """Under windows, system CPU time can't be measured. - This just returns clock() and zero.""" + This just returns perf_counter() and zero.""" return time.perf_counter(),0.0 From 7603d7fac72d37089f73c59048417fab9268281d Mon Sep 17 00:00:00 2001 From: ammarmallik Date: Thu, 11 Oct 2018 18:29:18 +0500 Subject: [PATCH 078/635] Replace deprecated time.time() with time.perf_counter() issue#11375 --- IPython/core/magics/execution.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index d04ace80c10..152950ea1d5 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -915,7 +915,7 @@ def _run_with_timing(run, nruns): Number of times to execute `run`. """ - twall0 = time.time() + twall0 = time.perf_counter() if nruns == 1: t0 = clock2() run() @@ -938,7 +938,7 @@ def _run_with_timing(run, nruns): print(" Times : %10s %10s" % ('Total', 'Per run')) print(" User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)) print(" System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)) - twall1 = time.time() + twall1 = time.perf_counter() print("Wall time: %10.2f s." % (twall1 - twall0)) @skip_doctest From 952e3ad6e35b44fbbe24e128fc8949c93c51ba45 Mon Sep 17 00:00:00 2001 From: Shao Yang Date: Fri, 12 Oct 2018 23:19:38 +0800 Subject: [PATCH 079/635] change magics from %%file to %%writefile --- IPython/core/tests/test_magic.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index dfeabca1f21..b9c1533905b 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -738,11 +738,11 @@ def cellm33(self, line, cell): nt.assert_equal(c33, None) def test_file(): - """Basic %%file""" + """Basic %%writefile""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file1') - ip.run_cell_magic("file", fname, u'\n'.join([ + ip.run_cell_magic("writefile", fname, u'\n'.join([ 'line1', 'line2', ])) @@ -752,12 +752,12 @@ def test_file(): nt.assert_in('line2', s) def test_file_var_expand(): - """%%file $filename""" + """%%writefile $filename""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file1') ip.user_ns['filename'] = fname - ip.run_cell_magic("file", '$filename', u'\n'.join([ + ip.run_cell_magic("writefile", '$filename', u'\n'.join([ 'line1', 'line2', ])) @@ -767,11 +767,11 @@ def test_file_var_expand(): nt.assert_in('line2', s) def test_file_unicode(): - """%%file with unicode cell""" + """%%writefile with unicode cell""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file1') - ip.run_cell_magic("file", fname, u'\n'.join([ + ip.run_cell_magic("writefile", fname, u'\n'.join([ u'liné1', u'liné2', ])) @@ -781,15 +781,15 @@ def test_file_unicode(): nt.assert_in(u'liné2', s) def test_file_amend(): - """%%file -a amends files""" + """%%writefile -a amends files""" ip = get_ipython() with TemporaryDirectory() as td: fname = os.path.join(td, 'file2') - ip.run_cell_magic("file", fname, u'\n'.join([ + ip.run_cell_magic("writefile", fname, u'\n'.join([ 'line1', 'line2', ])) - ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([ + ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([ 'line3', 'line4', ])) From 73f493f520bb79e2f7e693d8116849d311177e3f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 15 Oct 2018 18:04:42 -0700 Subject: [PATCH 080/635] Restore some functionality of the sphinx directive. See #11362 The issue is in 2 part, before IPython 7.0 the input splitter was state full, this was (in part) due to readline. The second part is that because of this, we had to be a bit adressive of what was considered complete code (it had to have 2 new line). This is now not required anymore as we can submit stuff as a whole. I hope that this fixes that. I have another fix in mind that count (and reset) the number of consecutive blank line, but that will be more complicated end code. --- IPython/sphinxext/ipython_directive.py | 47 +++++++++++--------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index 6fcf9d848df..70e2f5bd631 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -201,7 +201,6 @@ from IPython import InteractiveShell from IPython.core.profiledir import ProfileDir - use_matpltolib = False try: import matplotlib @@ -356,7 +355,6 @@ def __init__(self, exec_lines=None): self.user_ns = self.IP.user_ns self.user_global_ns = self.IP.user_global_ns - self.lines_waiting = [] self.input = '' self.output = '' self.tmp_profile_dir = tmp_profile_dir @@ -387,16 +385,16 @@ def clear_cout(self): self.cout.seek(0) self.cout.truncate(0) - def process_input_line(self, line, store_history=True): + def process_input_line(self, line, store_history): + return self.process_input_lines([line], store_history=store_history) + + def process_input_lines(self, lines, store_history=True): """process the input, capturing stdout""" stdout = sys.stdout + source_raw = '\n'.join(lines) try: sys.stdout = self.cout - self.lines_waiting.append(line) - source_raw = ''.join(self.lines_waiting) - if self.IP.check_complete(source_raw)[0] != 'incomplete': - self.lines_waiting = [] - self.IP.run_cell(source_raw, store_history=store_history) + self.IP.run_cell(source_raw, store_history=store_history) finally: sys.stdout = stdout @@ -470,28 +468,25 @@ def process_input(self, data, input_prompt, lineno): # Note: catch_warnings is not thread safe with warnings.catch_warnings(record=True) as ws: - for i, line in enumerate(input_lines): - if line.endswith(';'): - is_semicolon = True + if input_lines[0].endswith(';'): + is_semicolon = True + #for i, line in enumerate(input_lines): + + # process the first input line + if is_verbatim: + self.process_input_lines(['']) + self.IP.execution_count += 1 # increment it anyway + else: + # only submit the line in non-verbatim mode + self.process_input_lines(input_lines, store_history=store_history) + if not is_suppress: + for i, line in enumerate(input_lines): if i == 0: - # process the first input line - if is_verbatim: - self.process_input_line('') - self.IP.execution_count += 1 # increment it anyway - else: - # only submit the line in non-verbatim mode - self.process_input_line(line, store_history=store_history) formatted_line = '%s %s'%(input_prompt, line) else: - # process a continuation line - if not is_verbatim: - self.process_input_line(line, store_history=store_history) - formatted_line = '%s %s'%(continuation, line) - - if not is_suppress: - ret.append(formatted_line) + ret.append(formatted_line) if not is_suppress and len(rest.strip()) and is_verbatim: # The "rest" is the standard output of the input. This needs to be @@ -582,7 +577,6 @@ def process_input(self, data, input_prompt, lineno): raise RuntimeError('Non Expected warning in `{}` line {}'.format(filename, lineno)) self.cout.truncate(0) - return (ret, input_lines, processed_output, is_doctest, decorator, image_file, image_directive) @@ -734,7 +728,6 @@ def process_block(self, block): # will truncate tracebacks. sys.stdout.write(e) raise RuntimeError('An invalid block was detected.') - out_data = \ self.process_output(data, output_prompt, input_lines, output, is_doctest, decorator, From d12f0c8fdbbdf63ef8299af9f459df956d045815 Mon Sep 17 00:00:00 2001 From: Massimo Santini Date: Tue, 16 Oct 2018 08:45:18 +0200 Subject: [PATCH 081/635] Skipped a test about \\jmath that now is completed --- IPython/core/tests/test_completer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 56428bad2c8..4f90c9b7244 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -182,6 +182,7 @@ def test_forward_unicode_completion(): nt.assert_equal(len(matches), 1) nt.assert_equal(matches[0], 'Ⅴ') +@nt.nottest # now we have a completion for \jmath @dec.knownfailureif(sys.platform == 'win32', 'Fails if there is a C:\\j... path') def test_no_ascii_back_completion(): ip = get_ipython() From 11fc3682b4db84211b90673157c0a8f2b77c7e3f Mon Sep 17 00:00:00 2001 From: luciana Date: Tue, 16 Oct 2018 11:15:47 -0300 Subject: [PATCH 082/635] changed syntax --- IPython/core/tests/test_history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index a6815edd131..1760e4681f9 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -25,7 +25,7 @@ def setUp(): nt.assert_equal(sys.getdefaultencoding(), "utf-8") -@skipif(sqlite3.version_info > (3,24,0)) +@skipif(sqlite3.sqlite_version_info > (3,24,0)) def test_history(): ip = get_ipython() with TemporaryDirectory() as tmpdir: From ac5788009da4123f0fa38c49c4de4e2ff1348e35 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 15 Oct 2018 20:32:22 -0700 Subject: [PATCH 083/635] Add an option (`ipython_warning_is_error`) to not stop on error. The behavior pre-6.5 was to keep on going even if unexpected exceptions or warnings were shown, on 7.x the default is to abort the build. For compat reasons (and convenience), you can now set back the behavior to the original one to just log to stderr and move on. --- IPython/sphinxext/ipython_directive.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index 70e2f5bd631..1e4f0d85610 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -84,6 +84,10 @@ The compiled regular expression to denote the start of IPython input lines. The default is ``re.compile('In \[(\d+)\]:\s?(.*)\s*')``. You shouldn't need to change this. +ipython_warning_is_error: [default to True] + Fail the build if something unexpected happen, for example if a block raise + an exception but does not have the `:okexcept:` flag. The exact behavior of + what is considered strict, may change between the sphinx directive version. ipython_rgxout: The compiled regular expression to denote the start of IPython output lines. The default is ``re.compile('Out\[(\d+)\]:\s?(.*)\s*')``. You @@ -559,7 +563,8 @@ def process_input(self, data, input_prompt, lineno): sys.stdout.write(s) sys.stdout.write(processed_output) sys.stdout.write('<<<' + ('-' * 73) + '\n\n') - raise RuntimeError('Non Expected exception in `{}` line {}'.format(filename, lineno)) + if self.warning_is_error: + raise RuntimeError('Non Expected exception in `{}` line {}'.format(filename, lineno)) # output any warning raised during execution to stdout # unless :okwarning: has been specified. @@ -574,7 +579,8 @@ def process_input(self, data, input_prompt, lineno): w.filename, w.lineno, w.line) sys.stdout.write(s) sys.stdout.write('<<<' + ('-' * 73) + '\n') - raise RuntimeError('Non Expected warning in `{}` line {}'.format(filename, lineno)) + if self.shell.warning_is_error: + raise RuntimeError('Non Expected warning in `{}` line {}'.format(filename, lineno)) self.cout.truncate(0) return (ret, input_lines, processed_output, @@ -899,6 +905,7 @@ def get_config_options(self): # get regex and prompt stuff rgxin = config.ipython_rgxin rgxout = config.ipython_rgxout + warning_is_error= config.ipython_warning_is_error promptin = config.ipython_promptin promptout = config.ipython_promptout mplbackend = config.ipython_mplbackend @@ -906,12 +913,12 @@ def get_config_options(self): hold_count = config.ipython_holdcount return (savefig_dir, source_dir, rgxin, rgxout, - promptin, promptout, mplbackend, exec_lines, hold_count) + promptin, promptout, mplbackend, exec_lines, hold_count, warning_is_error) def setup(self): # Get configuration values. (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout, - mplbackend, exec_lines, hold_count) = self.get_config_options() + mplbackend, exec_lines, hold_count, warning_is_error) = self.get_config_options() try: os.makedirs(savefig_dir) @@ -951,6 +958,7 @@ def setup(self): self.shell.savefig_dir = savefig_dir self.shell.source_dir = source_dir self.shell.hold_count = hold_count + self.shell.warning_is_error = warning_is_error # setup bookmark for saving figures directory self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir, @@ -1028,6 +1036,7 @@ def setup(app): app.add_directive('ipython', IPythonDirective) app.add_config_value('ipython_savefig_dir', 'savefig', 'env') + app.add_config_value('ipython_warning_is_error', True, 'env') app.add_config_value('ipython_rgxin', re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env') app.add_config_value('ipython_rgxout', From 8852ac6d44c37a78b6a4084f0d60f45a8ee65c79 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 16 Oct 2018 09:00:19 -0700 Subject: [PATCH 084/635] Catch Syntax error as exceptions, get doc from history --- IPython/sphinxext/ipython_directive.py | 2 +- docs/source/development/index.rst | 1 + docs/source/development/ipython_directive.rst | 435 ++++++++++++++++++ 3 files changed, 437 insertions(+), 1 deletion(-) create mode 100644 docs/source/development/ipython_directive.rst diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index 1e4f0d85610..72d3d4f7a2e 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -556,7 +556,7 @@ def process_input(self, data, input_prompt, lineno): # output any exceptions raised during execution to stdout # unless :okexcept: has been specified. - if not is_okexcept and "Traceback" in processed_output: + if not is_okexcept and (("Traceback" in processed_output) or ("SyntaxError" in processed_output)): s = "\nException in %s at block ending on line %s\n" % (filename, lineno) s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n" sys.stdout.write('\n\n>>>' + ('-' * 73)) diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index a75cafdc178..a01673fa935 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -19,3 +19,4 @@ Developer's guide for third party tools and libraries lexer config inputhook_app + ipython_directive diff --git a/docs/source/development/ipython_directive.rst b/docs/source/development/ipython_directive.rst new file mode 100644 index 00000000000..7beaa503818 --- /dev/null +++ b/docs/source/development/ipython_directive.rst @@ -0,0 +1,435 @@ + +.. _ipython_directive: + +======================== +IPython Sphinx Directive +======================== + +.. note:: + + This has been salvadged from history, so information may be approximate or + duplicated. Fixes welcome. + +The ipython directive is a stateful ipython shell for embedding in +sphinx documents. It knows about standard ipython prompts, and +extracts the input and output lines. These prompts will be renumbered +starting at ``1``. The inputs will be fed to an embedded ipython +interpreter and the outputs from that interpreter will be inserted as +well. For example, code blocks like the following:: + + .. ipython:: + + In [136]: x = 2 + + In [137]: x**3 + Out[137]: 8 + +will be rendered as + +.. ipython:: + + In [136]: x = 2 + + In [137]: x**3 + Out[137]: 8 + +.. note:: + + This tutorial should be read side-by-side with the Sphinx source + for this document because otherwise you will see only the rendered + output and not the code that generated it. Excepting the example + above, we will not in general be showing the literal ReST in this + document that generates the rendered output. + + +The state from previous sessions is stored, and standard error is +trapped. At doc build time, ipython's output and std err will be +inserted, and prompts will be renumbered. So the prompt below should +be renumbered in the rendered docs, and pick up where the block above +left off. + +.. ipython:: + :verbatim: + + In [138]: z = x*3 # x is recalled from previous block + + In [139]: z + Out[139]: 6 + + In [142]: print z + --------> print(z) + 6 + + In [141]: q = z[) # this is a syntax error -- we trap ipy exceptions + ------------------------------------------------------------ + File "", line 1 + q = z[) # this is a syntax error -- we trap ipy exceptions + ^ + SyntaxError: invalid syntax + + +The embedded interpreter supports some limited markup. For example, +you can put comments in your ipython sessions, which are reported +verbatim. There are some handy "pseudo-decorators" that let you +doctest the output. The inputs are fed to an embedded ipython +session and the outputs from the ipython session are inserted into +your doc. If the output in your doc and in the ipython session don't +match on a doctest assertion, an error will be + + +.. ipython:: + + In [1]: x = 'hello world' + + # this will raise an error if the ipython output is different + @doctest + In [2]: x.upper() + Out[2]: 'HELLO WORLD' + + # some readline features cannot be supported, so we allow + # "verbatim" blocks, which are dumped in verbatim except prompts + # are continuously numbered + @verbatim + In [3]: x.st + x.startswith x.strip + + +Multi-line input is supported. + +.. ipython:: + :verbatim: + + In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\ + .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv' + + In [131]: print url.split('&') + --------> print(url.split('&')) + ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', + +You can do doctesting on multi-line output as well. Just be careful +when using non-deterministic inputs like random numbers in the ipython +directive, because your inputs are ruin through a live interpreter, so +if you are doctesting random output you will get an error. Here we +"seed" the random number generator for deterministic output, and we +suppress the seed line so it doesn't show up in the rendered output + +.. ipython:: + + In [133]: import numpy.random + + @suppress + In [134]: numpy.random.seed(2358) + + @doctest + In [135]: numpy.random.rand(10,2) + Out[135]: + array([[0.64524308, 0.59943846], + [0.47102322, 0.8715456 ], + [0.29370834, 0.74776844], + [0.99539577, 0.1313423 ], + [0.16250302, 0.21103583], + [0.81626524, 0.1312433 ], + [0.67338089, 0.72302393], + [0.7566368 , 0.07033696], + [0.22591016, 0.77731835], + [0.0072729 , 0.34273127]]) + + +Another demonstration of multi-line input and output + +.. ipython:: + :verbatim: + + In [106]: print x + --------> print(x) + jdh + + In [109]: for i in range(10): + .....: print i + .....: + .....: + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + + +Most of the "pseudo-decorators" can be used an options to ipython +mode. For example, to setup matplotlib pylab but suppress the output, +you can do. When using the matplotlib ``use`` directive, it should +occur before any import of pylab. This will not show up in the +rendered docs, but the commands will be executed in the embedded +interpreter and subsequent line numbers will be incremented to reflect +the inputs:: + + + .. ipython:: + :suppress: + + In [144]: from pylab import * + + In [145]: ion() + +.. ipython:: + :suppress: + + In [144]: from pylab import * + + In [145]: ion() + +Likewise, you can set ``:doctest:`` or ``:verbatim:`` to apply these +settings to the entire block. For example, + +.. ipython:: + :verbatim: + + In [9]: cd mpl/examples/ + /home/jdhunter/mpl/examples + + In [10]: pwd + Out[10]: '/home/jdhunter/mpl/examples' + + + In [14]: cd mpl/examples/ + mpl/examples/animation/ mpl/examples/misc/ + mpl/examples/api/ mpl/examples/mplot3d/ + mpl/examples/axes_grid/ mpl/examples/pylab_examples/ + mpl/examples/event_handling/ mpl/examples/widgets + + In [14]: cd mpl/examples/widgets/ + /home/msierig/mpl/examples/widgets + + In [15]: !wc * + 2 12 77 README.txt + 40 97 884 buttons.py + 26 90 712 check_buttons.py + 19 52 416 cursor.py + 180 404 4882 menu.py + 16 45 337 multicursor.py + 36 106 916 radio_buttons.py + 48 226 2082 rectangle_selector.py + 43 118 1063 slider_demo.py + 40 124 1088 span_selector.py + 450 1274 12457 total + +You can create one or more pyplot plots and insert them with the +``@savefig`` decorator. + +.. ipython:: + + @savefig plot_simple.png width=4in + In [151]: plot([1,2,3]); + + # use a semicolon to suppress the output + @savefig hist_simple.png width=4in + In [151]: hist(np.random.randn(10000), 100); + +In a subsequent session, we can update the current figure with some +text, and then resave + +.. ipython:: + + + In [151]: ylabel('number') + + In [152]: title('normal distribution') + + @savefig hist_with_text.png width=4in + In [153]: grid(True) + +You can also have function definitions included in the source. + +.. ipython:: + + In [3]: def square(x): + ...: """ + ...: An overcomplicated square function as an example. + ...: """ + ...: if x < 0: + ...: x = abs(x) + ...: y = x * x + ...: return y + ...: + +Then call it from a subsequent section. + +.. ipython:: + + In [4]: square(3) + Out [4]: 9 + + In [5]: square(-2) + Out [5]: 4 + + +Writing Pure Python Code +------------------------ + +Pure python code is supported by the optional argument `python`. In this pure +python syntax you do not include the output from the python interpreter. The +following markup:: + + .. ipython:: python + + foo = 'bar' + print(foo) + foo = 2 + foo**2 + +Renders as + +.. ipython:: python + + foo = 'bar' + print(foo) + foo = 2 + foo**2 + +We can even plot from python, using the savefig decorator, as well as, suppress +output with a semicolon + +.. ipython:: python + + @savefig plot_simple_python.png width=4in + plot([1,2,3]); + +Similarly, std err is inserted + +.. ipython:: python + :okexcept: + + foo = 'bar' + foo[) + +Comments are handled and state is preserved + +.. ipython:: python + + # comments are handled + print(foo) + +If you don't see the next code block then the options work. + +.. ipython:: python + :suppress: + + ioff() + ion() + +Multi-line input is handled. + +.. ipython:: python + + line = 'Multi\ + line &\ + support &\ + works' + print(line.split('&')) + +Functions definitions are correctly parsed + +.. ipython:: python + + def square(x): + """ + An overcomplicated square function as an example. + """ + if x < 0: + x = abs(x) + y = x * x + return y + +And persist across sessions + +.. ipython:: python + + print(square(3)) + print(square(-2)) + +Pretty much anything you can do with the ipython code, you can do with +with a simple python script. Obviously, though it doesn't make sense +to use the doctest option. + +Pseudo-Decorators +================= + +Here are the supported decorators, and any optional arguments they +take. Some of the decorators can be used as options to the entire +block (eg ``verbatim`` and ``suppress``), and some only apply to the +line just below them (eg ``savefig``). + +@suppress + + execute the ipython input block, but suppress the input and output + block from the rendered output. Also, can be applied to the entire + ``.. ipython`` block as a directive option with ``:suppress:``. + +@verbatim + + insert the input and output block in verbatim, but auto-increment + the line numbers. Internally, the interpreter will be fed an empty + string, so it is a no-op that keeps line numbering consistent. + Also, can be applied to the entire ``.. ipython`` block as a + directive option with ``:verbatim:``. + +@savefig OUTFILE [IMAGE_OPTIONS] + + save the figure to the static directory and insert it into the + document, possibly binding it into a minipage and/or putting + code/figure label/references to associate the code and the + figure. Takes args to pass to the image directive (*scale*, + *width*, etc can be kwargs); see `image options + `_ + for details. + +@doctest + + Compare the pasted in output in the ipython block with the output + generated at doc build time, and raise errors if they don't + match. Also, can be applied to the entire ``.. ipython`` block as a + directive option with ``:doctest:``. + +Configuration Options +===================== + +ipython_savefig_dir + + The directory in which to save the figures. This is relative to the + Sphinx source directory. The default is `html_static_path`. + +ipython_rgxin + + The compiled regular expression to denote the start of IPython input + lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You + shouldn't need to change this. + +ipython_rgxout + + The compiled regular expression to denote the start of IPython output + lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You + shouldn't need to change this. + + +ipython_promptin + + The string to represent the IPython input prompt in the generated ReST. + The default is 'In [%d]:'. This expects that the line numbers are used + in the prompt. + +ipython_promptout + + The string to represent the IPython prompt in the generated ReST. The + default is 'Out [%d]:'. This expects that the line numbers are used + in the prompt. + + +Automatically generated documentation +===================================== + +.. automodule:: IPython.sphinxext.ipython_directive From bdcb05ed18153efb37a843cebedd8cded79a1953 Mon Sep 17 00:00:00 2001 From: luciana Date: Mon, 15 Oct 2018 19:58:21 -0300 Subject: [PATCH 085/635] Added skipif for sqlite3 version > 3.24.0 --- IPython/core/tests/test_history.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index fcc22f1c00a..1760e4681f9 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -11,6 +11,7 @@ import sys import tempfile from datetime import datetime +import sqlite3 # third party import nose.tools as nt @@ -19,10 +20,12 @@ from traitlets.config.loader import Config from IPython.utils.tempdir import TemporaryDirectory from IPython.core.history import HistoryManager, extract_hist_ranges +from IPython.testing.decorators import skipif def setUp(): nt.assert_equal(sys.getdefaultencoding(), "utf-8") +@skipif(sqlite3.sqlite_version_info > (3,24,0)) def test_history(): ip = get_ipython() with TemporaryDirectory() as tmpdir: @@ -40,7 +43,7 @@ def test_history(): ip.history_manager.store_output(3) nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist) - + # Detailed tests for _get_range_session grs = ip.history_manager._get_range_session nt.assert_equal(list(grs(start=2,stop=-1)), list(zip([0], [2], hist[1:-1]))) @@ -50,7 +53,7 @@ def test_history(): # Check whether specifying a range beyond the end of the current # session results in an error (gh-804) ip.magic('%hist 2-500') - + # Check that we can write non-ascii characters to a file ip.magic("%%hist -f %s" % os.path.join(tmpdir, "test1")) ip.magic("%%hist -pf %s" % os.path.join(tmpdir, "test2")) @@ -85,6 +88,7 @@ def test_history(): nt.assert_equal(list(gothist), expected) # Check get_hist_search + gothist = ip.history_manager.search("*test*") nt.assert_equal(list(gothist), [(1,2,hist[1])] ) From 8c9ec3ae61e0b08c0fb2daa3f64007c4321ef3df Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 17 Oct 2018 17:15:29 -0700 Subject: [PATCH 086/635] Fix starting IPython in vi editing mode closes #11404 --- IPython/terminal/interactiveshell.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 77ef445169b..e9f16494354 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -147,7 +147,8 @@ def _validate_editing_mode(self, proposal): @observe('editing_mode') def _editing_mode(self, change): u_mode = change.new.upper() - self.pt_app.editing_mode = u_mode + if self.pt_app: + self.pt_app.editing_mode = u_mode @observe('highlighting_style') @observe('colors') From f4ce5c669b10f7396fc8026e4869b5a552c5bbb6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 17 Oct 2018 17:25:25 -0700 Subject: [PATCH 087/635] fix minimal issues --- docs/source/development/ipython_directive.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/development/ipython_directive.rst b/docs/source/development/ipython_directive.rst index 7beaa503818..f3f262d4b5f 100644 --- a/docs/source/development/ipython_directive.rst +++ b/docs/source/development/ipython_directive.rst @@ -108,7 +108,7 @@ Multi-line input is supported. You can do doctesting on multi-line output as well. Just be careful when using non-deterministic inputs like random numbers in the ipython -directive, because your inputs are ruin through a live interpreter, so +directive, because your inputs are run through a live interpreter, so if you are doctesting random output you will get an error. Here we "seed" the random number generator for deterministic output, and we suppress the seed line so it doesn't show up in the rendered output @@ -172,14 +172,14 @@ the inputs:: .. ipython:: :suppress: - In [144]: from pylab import * + In [144]: from matplotlib.pylab import * In [145]: ion() .. ipython:: :suppress: - In [144]: from pylab import * + In [144]: from matplotlib.pylab import * In [145]: ion() @@ -406,26 +406,26 @@ ipython_savefig_dir ipython_rgxin The compiled regular expression to denote the start of IPython input - lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You + lines. The default is `re.compile('In \[(\d+)\]:\s?(.*)\s*')`. You shouldn't need to change this. ipython_rgxout The compiled regular expression to denote the start of IPython output - lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You + lines. The default is `re.compile('Out\[(\d+)\]:\s?(.*)\s*')`. You shouldn't need to change this. ipython_promptin The string to represent the IPython input prompt in the generated ReST. - The default is 'In [%d]:'. This expects that the line numbers are used + The default is `'In [%d]:'`. This expects that the line numbers are used in the prompt. ipython_promptout The string to represent the IPython prompt in the generated ReST. The - default is 'Out [%d]:'. This expects that the line numbers are used + default is `'Out [%d]:'`. This expects that the line numbers are used in the prompt. From 2e22c3eed952470db51f61e7004b6b2eb2864998 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 17 Oct 2018 17:36:52 -0700 Subject: [PATCH 088/635] install matplotlib to build docs --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 56a50838476..1ede58d111f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,3 +4,4 @@ setuptools>=18.5 sphinx sphinx-rtd-theme docrepr +matplotlib From bea9c99bad3e88e9175a0195c2195236832763d4 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 17 Oct 2018 17:47:29 -0700 Subject: [PATCH 089/635] try to fix nightly --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index cf184a9d993..2bccb56180a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,11 @@ install: - sudo apt-get install graphviz script: - check-manifest + - | + if [[ "$TRAVIS_PYTHON_VERSION" == "nightly" ]]; then + # on nightly fake parso known the grammar + cp /home/travis/virtualenv/python3.8-dev/lib/python3.8/site-packages/parso/python/grammar37.txt /home/travis/virtualenv/python3.8-dev/lib/python3.8/site-packages/parso/python/grammar38.txt + fi - cd /tmp && iptest --coverage xml && cd - # On the latest Python only, make sure that the docs build. - | From 5dd44c947c6fe89d2f3f902d4ae3375ef1fa3b33 Mon Sep 17 00:00:00 2001 From: Nguyen Duy Hai Date: Sat, 20 Oct 2018 22:53:25 +0700 Subject: [PATCH 090/635] Fix indentation for nested block --- IPython/core/inputtransformer2.py | 10 +++++++++- IPython/core/tests/test_inputtransformer2.py | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index e2dd2d08773..b6bbcb1e1fc 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -655,7 +655,15 @@ def check_complete(self, cell: str): if len(tokens_by_line) == 1 and not tokens_by_line[-1]: return 'incomplete', 0 - if tokens_by_line[-1][-1].string == ':': + new_block = False + for token in reversed(tokens_by_line[-1]): + if token.type == tokenize.DEDENT: + continue + elif token.string == ':': + new_block = True + break + + if new_block: # The last line starts a block (e.g. 'if foo:') ix = 0 while tokens_by_line[-1][ix].type in {tokenize.INDENT, tokenize.DEDENT}: diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index d6c2fa3bd6b..ea0645238ef 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -207,6 +207,7 @@ def test_check_complete(): cc = ipt2.TransformerManager().check_complete nt.assert_equal(cc("a = 1"), ('complete', None)) nt.assert_equal(cc("for a in range(5):"), ('incomplete', 4)) + nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ('incomplete', 8)) nt.assert_equal(cc("raise = 2"), ('invalid', None)) nt.assert_equal(cc("a = [1,\n2,"), ('incomplete', 0)) nt.assert_equal(cc(")"), ('incomplete', 0)) From dd15f28f49472efd20a10805cf04d17f2d6154f9 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 20 Oct 2018 10:45:27 -0700 Subject: [PATCH 091/635] Fix miss-capturing of assign statement after a dedent. closes #11415 This fixes a bug where assign statement were miscaptured when occuring after a dedent. This was due to the fact that : >>> '' in '({[' True That is to say the empty string is in any strings. Add a couple of integration tests and unit tests as well, and also add a warning to public function when not used properly, in particular, check that lines passed to make_tokens_by_line do end with an endline marker (at least for the first line), otherwise the function does not behave properly. --- IPython/core/inputtransformer2.py | 19 ++++++----- IPython/core/tests/test_inputtransformer2.py | 33 +++++++++++++++++++- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index e2dd2d08773..b73d701215b 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -13,7 +13,7 @@ from codeop import compile_command import re import tokenize -from typing import List, Tuple +from typing import List, Tuple, Union import warnings _indent_re = re.compile(r'^[ \t]+') @@ -87,7 +87,7 @@ def cell_magic(lines): % (magic_name, first_line, body)] -def _find_assign_op(token_line): +def _find_assign_op(token_line) -> Union[int, None]: """Get the index of the first assignment in the line ('=' not inside brackets) Note: We don't try to support multiple special assignment (a = b = %foo) @@ -97,9 +97,9 @@ def _find_assign_op(token_line): s = ti.string if s == '=' and paren_level == 0: return i - if s in '([{': + if s in {'(','[','{'}: paren_level += 1 - elif s in ')]}': + elif s in {')', ']', '}'}: if paren_level > 0: paren_level -= 1 @@ -449,11 +449,14 @@ def transform(self, lines): return lines_before + [new_line] + lines_after -def make_tokens_by_line(lines): +def make_tokens_by_line(lines:List[str]): """Tokenize a series of lines and group tokens by line. - The tokens for a multiline Python string or expression are - grouped as one line. + The tokens for a multiline Python string or expression are grouped as one + line. All lines except the last lines should keep their line ending ('\\n', + '\\r\\n') for this to properly work. Use `.splitlines(keeplineending=True)` + for example when passing block of text to this function. + """ # NL tokens are used inside multiline expressions, but also after blank # lines or comments. This is intentional - see https://bugs.python.org/issue17061 @@ -461,6 +464,8 @@ def make_tokens_by_line(lines): # track parentheses level, similar to the internals of tokenize. NEWLINE, NL = tokenize.NEWLINE, tokenize.NL tokens_by_line = [[]] + if len(lines) > 1 and not lines[0].endswith(('\n', '\r', '\r\n', '\x0b', '\x0c')): + warnings.warn("`make_tokens_by_line` received a list of lines which do not have lineending markers ('\\n', '\\r', '\\r\\n', '\\x0b', '\\x0c'), behavior will be unspecified") parenlev = 0 try: for token in tokenize.generate_tokens(iter(lines).__next__): diff --git a/IPython/core/tests/test_inputtransformer2.py b/IPython/core/tests/test_inputtransformer2.py index d6c2fa3bd6b..9c92c394e50 100644 --- a/IPython/core/tests/test_inputtransformer2.py +++ b/IPython/core/tests/test_inputtransformer2.py @@ -8,7 +8,7 @@ import string from IPython.core import inputtransformer2 as ipt2 -from IPython.core.inputtransformer2 import make_tokens_by_line +from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op from textwrap import dedent @@ -53,6 +53,22 @@ g() """.splitlines(keepends=True)) +##### + +MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\ +def test(): + for i in range(1): + print(i) + res =! ls +""".splitlines(keepends=True), (4, 7), '''\ +def test(): + for i in range(1): + print(i) + res =get_ipython().getoutput(\' ls\') +'''.splitlines(keepends=True)) + +###### + AUTOCALL_QUOTE = ( [",f 1 2 3\n"], (1, 0), ['f("1", "2", "3")\n'] @@ -103,6 +119,7 @@ [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"] ) + def null_cleanup_transformer(lines): """ A cleanup transform that returns an empty list. @@ -144,18 +161,21 @@ def test_continued_line(): def test_find_assign_magic(): check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN) check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False) + check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False) def test_transform_assign_magic(): check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN) def test_find_assign_system(): check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN) + check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT) check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None)) check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None)) check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False) def test_transform_assign_system(): check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN) + check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT) def test_find_magic_escape(): check_find(ipt2.EscapedCommand, MULTILINE_MAGIC) @@ -203,6 +223,17 @@ def test_transform_help(): tf = ipt2.HelpEnd((1, 0), (2, 8)) nt.assert_equal(tf.transform(HELP_MULTILINE[0]), HELP_MULTILINE[2]) +def test_find_assign_op_dedent(): + """ + be carefull that empty token like dedent are not counted as parens + """ + class Tk: + def __init__(self, s): + self.string = s + + nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2) + nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6) + def test_check_complete(): cc = ipt2.TransformerManager().check_complete nt.assert_equal(cc("a = 1"), ('complete', None)) From e3c0214ffa95e3d493fc3dc3ca3078101393c6c9 Mon Sep 17 00:00:00 2001 From: Elyashiv <> Date: Sat, 20 Oct 2018 21:44:23 +0300 Subject: [PATCH 092/635] removed expansion of function name when copleting kw-args --- IPython/core/completer.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 9858236905d..c8393f72267 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -1538,24 +1538,20 @@ def python_func_kw_matches(self,text): usedNamedArgs.add(token) - # lookup the candidate callable matches either using global_matches - # or attr_matches for dotted names - if len(ids) == 1: - callableMatches = self.global_matches(ids[0]) - else: - callableMatches = self.attr_matches('.'.join(ids[::-1])) argMatches = [] - for callableMatch in callableMatches: - try: - namedArgs = self._default_arguments(eval(callableMatch, - self.namespace)) - except: - continue + try: + callableObj = '.'.join(ids[::-1]) + print(callableObj) + namedArgs = self._default_arguments(eval(callableObj, + self.namespace)) # Remove used named arguments from the list, no need to show twice for namedArg in set(namedArgs) - usedNamedArgs: if namedArg.startswith(text): argMatches.append(u"%s=" %namedArg) + except: + pass + return argMatches def dict_key_matches(self, text): From da83b1b4c7fd423ab7bfca711dd7778bd69b6d7c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 20 Oct 2018 11:54:59 -0700 Subject: [PATCH 093/635] Update what's new for 7.1.0 --- .../source/whatsnew/pr/video-width-height.rst | 1 - docs/source/whatsnew/version7.rst | 73 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) delete mode 100644 docs/source/whatsnew/pr/video-width-height.rst diff --git a/docs/source/whatsnew/pr/video-width-height.rst b/docs/source/whatsnew/pr/video-width-height.rst deleted file mode 100644 index 84757f1b430..00000000000 --- a/docs/source/whatsnew/pr/video-width-height.rst +++ /dev/null @@ -1 +0,0 @@ -``IPython.display.Video`` now supports ``width`` and ``height`` arguments, allowing a custom width and height to be set instead of using the video's width and height \ No newline at end of file diff --git a/docs/source/whatsnew/version7.rst b/docs/source/whatsnew/version7.rst index 19352cc0d95..17b3275145d 100644 --- a/docs/source/whatsnew/version7.rst +++ b/docs/source/whatsnew/version7.rst @@ -2,6 +2,79 @@ 7.x Series ============ +.. _whatsnew710: + +IPython 7.1.0 +============= + + +IPython 7.1.0 is the first minor release after 7.0.0 and mostly bring fixes to +new feature, internal refactor and regressions that happen during the 6.x->7.x +transition. It also bring **Compatibility with Python 3.7.1**, as were +unwillingly relying on a bug in CPython. + +New Core Dev: + + - We welcome Jonathan Slenders to the commiters. Jonathan has done a fantastic + work on Prompt toolkit, and we'd like to recognise his impact by giving him + commit rights. :ghissue:`11397` + +Notable New Features: + + - Restore functionality and documentation of the **sphinx directive**, which is + now stricter (fail on error by default), gained configuration options, have a + brand new documentation page :ref:`ipython_directive`, which need some cleanup. + It is also now *tested* so we hope to have less regressions. + :ghpull:`11402` + + - ``IPython.display.Video`` now supports ``width`` and ``height`` arguments, + allowing a custom width and height to be set instead of using the video's + width and height. :ghpull:`11353` + + - Warn when using ``HTML('