From bcf1c2ac5538cd20a8cea87a071dcb16d64f0b38 Mon Sep 17 00:00:00 2001 From: dickmao Date: Fri, 8 Nov 2019 12:47:06 -0500 Subject: [PATCH] purge purge align pm:get-span no major mode error with diagnostic purge --- .gitignore | 27 +- .travis.yml | 4 +- COPYING | 674 ---------- Cask | 4 - Demo.ipynb | 490 ------- Development Ideas.ipynb | 833 ------------ EIN_Manual.org | 1105 --------------- Makefile | 6 +- README.in.rst | 1 - README.rst | 14 +- The Emacs IPython Notebook.ipynb | 1193 ----------------- _images/ein_logo.jpg | Bin 14523 -> 0 bytes doc/source/index.rst | 3 - features/connect.feature | 26 - features/notebook.feature | 55 - features/support/env.el | 12 +- features/undo.feature | 10 +- features/undo.ipynb | 15 + lisp/ein-ac.el | 253 ---- lisp/ein-cell-edit.el | 273 ---- lisp/ein-cell.el | 30 +- lisp/ein-classes.el | 28 +- lisp/ein-company.el | 124 -- lisp/ein-completer.el | 32 +- lisp/ein-connect.el | 13 +- lisp/ein-contents-api.el | 65 - lisp/ein-core.el | 3 +- lisp/ein-dev.el | 7 +- lisp/ein-hy.el | 52 - lisp/ein-inspector.el | 125 -- lisp/ein-jupyter.el | 23 +- lisp/ein-kernelinfo.el | 61 +- lisp/ein-multilang.el | 4 - lisp/ein-notebook.el | 201 +-- lisp/ein-notebooklist.el | 88 +- lisp/ein-notification.el | 17 - lisp/ein-pkg.el | 4 +- lisp/ein-python.el | 82 -- lisp/ein-pytools.el | 3 - lisp/ein-skewer.el | 98 -- lisp/ein-smartrep.el | 55 - lisp/ein-subpackages.el | 6 +- lisp/ein-utils.el | 1 - lisp/ein-worksheet.el | 10 +- lisp/ein_inspector.py | 46 - lisp/ein_remote_safe.py | 120 -- lisp/ob-ein.el | 53 +- lisp/poly-ein.el | 13 +- ...e9bae2984f33a8dd1b990b80b91ab1a662cf49.png | Bin 482 -> 0 bytes ...2848837248c7931a943cbbd4b70188a0935854.png | Bin 614 -> 0 bytes org_demo.org | 132 -- test/ein-testing-notebook.el | 10 +- test/test-ein-ac.el | 17 - test/test-ein-kernel.el | 44 +- test/test-ein-notification.el | 2 - test/test-ein-smartrep.el | 8 - test/test-func.el | 239 ---- test/test-poly.el | 2 +- test/{test-ein-poly.el => test-uncompiled.el} | 7 +- test/testein.el | 4 + test/testfunc.el | 29 - test_requirements.txt | 6 - 62 files changed, 130 insertions(+), 6732 deletions(-) delete mode 100644 COPYING delete mode 100644 Demo.ipynb delete mode 100644 Development Ideas.ipynb delete mode 100644 EIN_Manual.org delete mode 100644 The Emacs IPython Notebook.ipynb delete mode 100644 _images/ein_logo.jpg delete mode 100644 lisp/ein-ac.el delete mode 100644 lisp/ein-cell-edit.el delete mode 100644 lisp/ein-company.el delete mode 100644 lisp/ein-hy.el delete mode 100644 lisp/ein-inspector.el delete mode 100644 lisp/ein-python.el delete mode 100644 lisp/ein-skewer.el delete mode 100644 lisp/ein-smartrep.el delete mode 100644 lisp/ein_inspector.py delete mode 100644 lisp/ein_remote_safe.py delete mode 100644 ltxpng/Enhancements_99e9bae2984f33a8dd1b990b80b91ab1a662cf49.png delete mode 100644 ltxpng/Enhancements_a52848837248c7931a943cbbd4b70188a0935854.png delete mode 100644 org_demo.org delete mode 100644 test/test-ein-ac.el delete mode 100644 test/test-ein-smartrep.el delete mode 100644 test/test-func.el rename test/{test-ein-poly.el => test-uncompiled.el} (62%) delete mode 100644 test/testfunc.el delete mode 100644 test_requirements.txt diff --git a/.gitignore b/.gitignore index eb60e6d..037b50c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,12 @@ doc/build/ -env .cask/* -Cask.tmp -index_error.py -redirecting_server.py -wiener_filtering.py -UTF-8-demo.txt -.gitmodules -*.stackdump -*.elc -*.el# -*.el~ -lisp/ein-autoloads.el -*.py~ -*.org~ *.pyc -*.ipynb~ -Makefile~ -*.ipynb_checkpoints* -*.png -tests/notebook -*.log log/* -_images -_static -.travis.yml.swp *.zip .gitattributes .ecukes* dist -.*ein*.ipynb +.*ein*ipynb .Rhistory +.ipynb_checkpoints +ein-autoloads.el diff --git a/.travis.yml b/.travis.yml index 963b0e5..0ee0c0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,8 +38,6 @@ matrix: include: - os: linux env: EMACS_CI=emacs-25-1 IPYTHON=5.8.0 PY=python PIP="${PY} -m pip install --user" - - os: linux - env: EMACS_CI=emacs-26-1 IPYTHON=6.5.0 PY=python3 PIP="${PY} -m pip install --user" - os: linux env: EMACS_CI=emacs-26-3 IPYTHON=7.5.0 PY=python3 PIP="${PY} -m pip install --user" - os: osx @@ -56,7 +54,7 @@ install: pyenv activate $TOXENV ; fi - ${PIP} --upgrade pip - - ${PIP} wheel jupyter ipython\<=$IPYTHON jedi\>=0.15.1 ipykernel numpy\<=1.16.0 matplotlib\<=3.0.2 + - ${PIP} wheel jupyter ipython\<=$IPYTHON ipykernel numpy\<=1.16.0 matplotlib\<=3.0.2 - ${PY} -m ipykernel install --user - sh tools/install-R.sh - sh tools/install-julia.sh diff --git a/COPYING b/COPYING deleted file mode 100644 index 94a9ed0..0000000 --- a/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/Cask b/Cask index 13832ef..35e5476 100644 --- a/Cask +++ b/Cask @@ -11,13 +11,9 @@ (depends-on "ert-runner") (depends-on "ecukes") (depends-on "espuds") - ;; (depends-on "org-plus-contrib") ;; see https://github.com/cask/cask/issues/119 (depends-on "mocker") - (depends-on "skewer-mode") (depends-on "deferred") - (depends-on "auto-complete") (depends-on "company") - (depends-on "smartrep") (depends-on "polymode") (depends-on "markdown-mode") (depends-on "julia-mode") diff --git a/Demo.ipynb b/Demo.ipynb deleted file mode 100644 index 4e5ca3c..0000000 --- a/Demo.ipynb +++ /dev/null @@ -1,490 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-05T22:48:49.882723Z", - "2018-11-05T22:48:49.898378Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "import ast" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "ast.literal_eval()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-05T22:49:00.227520Z", - "2018-11-05T22:49:00.243212Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'3.6.6 | packaged by conda-forge | (default, Jul 26 2018, 11:48:23) [MSC v.1900 64 bit (AMD64)]'" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import sys\n", - "sys.version\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "c:/Users/mille/Miniconda3/envs/datascience/Library/bin/" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-05T22:34:50.809004Z", - "2018-11-05T22:34:50.824630Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "sys.path.append('C:\\\\Users\\\\Miniconda3\\\\envs\\\\datascience\\\\Library\\\\bin\\\\')" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-05T22:49:41.133042Z", - "2018-11-05T22:49:41.164290Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\python36.zip',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\DLLs',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\lib',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\lib\\\\site-packages',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\lib\\\\site-packages\\\\win32',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\lib\\\\site-packages\\\\win32\\\\lib',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\lib\\\\site-packages\\\\Pythonwin',\n 'C:\\\\Users\\\\mille\\\\Miniconda3\\\\envs\\\\datascience\\\\lib\\\\site-packages\\\\IPython\\\\extensions',\n 'C:\\\\Users\\\\mille\\\\.ipython']" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sys.path" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-05T22:50:28.971341Z", - "2018-11-05T22:50:28.986926Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "a = np.zeros((10,10))" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-05T22:49:25.379578Z", - "2018-11-05T22:49:27.232239Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": [ - "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\n" - ], - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib inline\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "def plotnormal():\n", - " return plt.plot(np.random.randn(1000), np.random.randn(1000), 'o', alpha=0.3)\n", - "plotnormal()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "np.zeros_like()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "Errors are shown in informative ways:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ERROR: File `'non_existent_file.py'` not found.\n" - ] - } - ], - "source": [ - "%run non_existent_file" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "ename": "ZeroDivisionError", - "evalue": "division by zero", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0my\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mz\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" - ] - } - ], - "source": [ - "x = 1\n", - "y = 4\n", - "z = y/(1-x)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "ip = get_ipython()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Installed hierarchymagic.py. To use it, type:\n", - " %load_ext hierarchymagic\n" - ] - } - ], - "source": [ - "%install_ext https://raw.github.com/anaderi/ipython-hierarchymagic/master/hierarchymagic.py" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%load_ext hierarchymagic" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "You need graphviz installed and on your PATH for the following to work." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "ename": "FileNotFoundError", - "evalue": "[WinError 2] The system cannot find the file specified", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mget_ipython\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmagic\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'hierarchy get_ipython()'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;32mC:\\Users\\millejoh\\Anaconda3\\lib\\site-packages\\IPython\\core\\interactiveshell.py\u001b[0m in \u001b[0;36mmagic\u001b[1;34m(self, arg_s)\u001b[0m\n\u001b[0;32m 2161\u001b[0m \u001b[0mmagic_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0m_\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmagic_arg_s\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0marg_s\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpartition\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m' '\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2162\u001b[0m \u001b[0mmagic_name\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmagic_name\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlstrip\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mprefilter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mESC_MAGIC\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 2163\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_line_magic\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmagic_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmagic_arg_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2164\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2165\u001b[0m \u001b[1;31m#-------------------------------------------------------------------------\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Users\\millejoh\\Anaconda3\\lib\\site-packages\\IPython\\core\\interactiveshell.py\u001b[0m in \u001b[0;36mrun_line_magic\u001b[1;34m(self, magic_name, line)\u001b[0m\n\u001b[0;32m 2082\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'local_ns'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_getframe\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstack_depth\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mf_locals\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2083\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuiltin_trap\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 2084\u001b[1;33m \u001b[0mresult\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2085\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2086\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32m\u001b[0m in \u001b[0;36mhierarchy\u001b[1;34m(self, parameter_s)\u001b[0m\n", - "\u001b[1;32mC:\\Users\\millejoh\\Anaconda3\\lib\\site-packages\\IPython\\core\\magic.py\u001b[0m in \u001b[0;36m\u001b[1;34m(f, *a, **k)\u001b[0m\n\u001b[0;32m 191\u001b[0m \u001b[1;31m# but it's overkill for just that one bit of state.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 192\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mmagic_deco\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0marg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 193\u001b[1;33m \u001b[0mcall\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mlambda\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mk\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mk\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 194\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 195\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mcallable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0marg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Users\\millejoh\\.ipython\\extensions\\hierarchymagic.py\u001b[0m in \u001b[0;36mhierarchy\u001b[1;34m(self, parameter_s)\u001b[0m\n\u001b[0;32m 245\u001b[0m graph_attrs={'rankdir': args.rankdir,\n\u001b[0;32m 246\u001b[0m 'size': '\"{0}\"'.format(args.size)})\n\u001b[1;32m--> 247\u001b[1;33m \u001b[0mstdout\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mrun_dot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcode\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mformat\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'png'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 248\u001b[0m \u001b[0mdisplay_png\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstdout\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mraw\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 249\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Users\\millejoh\\.ipython\\extensions\\hierarchymagic.py\u001b[0m in \u001b[0;36mrun_dot\u001b[1;34m(code, options, format)\u001b[0m\n\u001b[0;32m 111\u001b[0m \u001b[1;31m# * http://stackoverflow.com/a/2935727/727827\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 112\u001b[0m p = Popen(dot_args, stdout=PIPE, stdin=PIPE, stderr=PIPE,\n\u001b[1;32m--> 113\u001b[1;33m creationflags=0x08000000)\n\u001b[0m\u001b[0;32m 114\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 115\u001b[0m \u001b[0mp\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mPopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdot_args\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstdout\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mPIPE\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstdin\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mPIPE\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstderr\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mPIPE\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Users\\millejoh\\Anaconda3\\lib\\subprocess.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds)\u001b[0m\n\u001b[0;32m 948\u001b[0m \u001b[0mc2pread\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mc2pwrite\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 949\u001b[0m \u001b[0merrread\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0merrwrite\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 950\u001b[1;33m restore_signals, start_new_session)\n\u001b[0m\u001b[0;32m 951\u001b[0m \u001b[1;32mexcept\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 952\u001b[0m \u001b[1;31m# Cleanup if the child failed starting.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Users\\millejoh\\Anaconda3\\lib\\subprocess.py\u001b[0m in \u001b[0;36m_execute_child\u001b[1;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, unused_restore_signals, unused_start_new_session)\u001b[0m\n\u001b[0;32m 1218\u001b[0m \u001b[0menv\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1219\u001b[0m \u001b[0mcwd\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m-> 1220\u001b[1;33m startupinfo)\n\u001b[0m\u001b[0;32m 1221\u001b[0m \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 1222\u001b[0m \u001b[1;31m# Child is launched. Close the parent's copy of those pipe\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mFileNotFoundError\u001b[0m: [WinError 2] The system cannot find the file specified" - ] - } - ], - "source": [ - "%hierarchy get_ipython()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "EIN also supports pretty printing from SymPy." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "from sympy.interactive import printing\n", - "printing.init_printing()\n", - "\n", - "import sympy as sym\n", - "from sympy import *\n", - "x, y, z = symbols(\"x y z\")\n", - "\n", - "Rational(3,2)*pi + exp(I*x) / (x**2 + y)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "If you install px can you get the below to work?\n", - "\n", - "$a^2=b$\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hy_cell": true, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Data Science (py36)", - "name": "datascience" - }, - "name": "Demo.ipynb" - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/Development Ideas.ipynb b/Development Ideas.ipynb deleted file mode 100644 index 24a5ac1..0000000 --- a/Development Ideas.ipynb +++ /dev/null @@ -1,833 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "# Object Inspector" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "Need to get python objects from strings. Is eval the best way?" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-01T21:27:17.435516Z", - "2018-11-01T21:27:17.469860Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "import inspect" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-01T21:33:50.033296Z", - "2018-11-01T21:33:50.064574Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "import ein" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "ein.pyto" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-01T21:33:55.629201Z", - "2018-11-01T21:33:55.663747Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['CodeMagics',\n '__builtins__',\n '__cached__',\n '__doc__',\n '__file__',\n '__loader__',\n '__name__',\n '__package__',\n '__spec__',\n '_find_edit_target',\n '_find_edit_target_012',\n '_find_edit_target_013',\n '_find_edit_target_python',\n 'eval_hy_string',\n 'export_nb',\n 'find_source',\n 'print_object_info_for',\n 'run_docstring_examples',\n 'set_figure_size']" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dir(ein)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-11-01T21:34:15.247868Z", - "2018-11-01T21:34:15.283595Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\"type_name\": \"module\", \"base_class\": \"\", \"string_form\": \"\", \"namespace\": null, \"length\": null, \"file\": \"c:\\\\users\\\\mille\\\\miniconda3\\\\lib\\\\inspect.py\", \"definition\": null, \"docstring\": \"Get useful information from live Python objects.\\n\\nThis module encapsulates the interface provided by the internal special\\nattributes (co_*, im_*, tb_*, etc.) in a friendlier fashion.\\nIt also provides some help for examining source code and class layout.\\n\\nHere are some of the useful functions provided by this module:\\n\\n ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),\\n isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),\\n isroutine() - check object types\\n getmembers() - get members of an object that satisfy a given condition\\n\\n getfile(), getsourcefile(), getsource() - find an object's source code\\n getdoc(), getcomments() - get documentation on an object\\n getmodule() - determine the module that an object came from\\n getclasstree() - arrange classes so as to represent their hierarchy\\n\\n getargvalues(), getcallargs() - get info about function arguments\\n getfullargspec() - same, with support for Python 3 features\\n formatargspec(), formatargvalues() - format an argument spec\\n getouterframes(), getinnerframes() - get info about frames\\n currentframe() - get the current stack frame\\n stack(), trace() - get info about frames on the stack or in a traceback\\n\\n signature() - get a Signature object for the callable\", \"source\": null, \"init_definition\": null, \"class_docstring\": null, \"init_docstring\": null, \"call_def\": null, \"call_docstring\": null, \"ismagic\": false, \"isalias\": false, \"isclass\": null, \"argspec\": null, \"found\": true, \"name\": \"\"}\n" - ] - } - ], - "source": [ - "__import__('ein').print_object_info_for(inspect)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "inspect.B" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "a=10" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'error': 'Object ax not found.', 'name': 'ax'}" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\"name\": \"ax\", \"error\": \"Object ax not found.\"}\n" - ] - } - ], - "source": [ - "__import__('ein_inspector').generate_inspector_data('ax', globals(), locals())" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "module" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mylst = [1, 2, 3]\n", - "type(inspect)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "ename": "TypeError", - "evalue": "[1, 2, 3] is not a module, class, method, function, traceback, frame, or code object", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0minspect\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetsourcefile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmylst\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32mc:\\Users\\mille\\Miniconda3\\envs\\anaconda\\lib\\inspect.py\u001b[0m in \u001b[0;36mgetsourcefile\u001b[0;34m(object)\u001b[0m\n\u001b[1;32m 658\u001b[0m \u001b[0mReturn\u001b[0m \u001b[1;32mNone\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mno\u001b[0m \u001b[0mway\u001b[0m \u001b[0mcan\u001b[0m \u001b[0mbe\u001b[0m \u001b[0midentified\u001b[0m \u001b[0mto\u001b[0m \u001b[0mget\u001b[0m \u001b[0mthe\u001b[0m \u001b[0msource\u001b[0m\u001b[1;33m.\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 659\u001b[0m \"\"\"\n\u001b[0;32m--> 660\u001b[0;31m \u001b[0mfilename\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgetfile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 661\u001b[0m \u001b[0mall_bytecode_suffixes\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimportlib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmachinery\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mDEBUG_BYTECODE_SUFFIXES\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 662\u001b[0m \u001b[0mall_bytecode_suffixes\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mimportlib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmachinery\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mOPTIMIZED_BYTECODE_SUFFIXES\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[0;32mc:\\Users\\mille\\Miniconda3\\envs\\anaconda\\lib\\inspect.py\u001b[0m in \u001b[0;36mgetfile\u001b[0;34m(object)\u001b[0m\n\u001b[1;32m 623\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mobject\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mco_filename\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 624\u001b[0m raise TypeError('{!r} is not a module, class, method, '\n\u001b[0;32m--> 625\u001b[0;31m 'function, traceback, frame, or code object'.format(object))\n\u001b[0m\u001b[1;32m 626\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 627\u001b[0m \u001b[0mModuleInfo\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnamedtuple\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'ModuleInfo'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'name suffix mode module_type'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: [1, 2, 3] is not a module, class, method, function, traceback, frame, or code object" - ] - } - ], - "source": [ - "inspect.getsourcefile(mylst)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "eval('inspect')" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "ename": "TypeError", - "evalue": "10 is not a module, class, method, function, traceback, frame, or code object", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0minspect\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetsource\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32mc:\\Users\\mille\\Anaconda3\\lib\\inspect.py\u001b[0m in \u001b[0;36mgetsource\u001b[0;34m(object)\u001b[0m\n\u001b[1;32m 942\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0mcode\u001b[0m \u001b[0mobject\u001b[0m\u001b[1;33m.\u001b[0m \u001b[0mThe\u001b[0m \u001b[0msource\u001b[0m \u001b[0mcode\u001b[0m \u001b[1;32mis\u001b[0m \u001b[0mreturned\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0ma\u001b[0m \u001b[0msingle\u001b[0m \u001b[0mstring\u001b[0m\u001b[1;33m.\u001b[0m \u001b[0mAn\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 943\u001b[0m OSError is raised if the source code cannot be retrieved.\"\"\"\n\u001b[0;32m--> 944\u001b[0;31m \u001b[0mlines\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlnum\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgetsourcelines\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 945\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlines\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 946\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[0;32mc:\\Users\\mille\\Anaconda3\\lib\\inspect.py\u001b[0m in \u001b[0;36mgetsourcelines\u001b[0;34m(object)\u001b[0m\n\u001b[1;32m 929\u001b[0m raised if the source code cannot be retrieved.\"\"\"\n\u001b[1;32m 930\u001b[0m \u001b[0mobject\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0munwrap\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 931\u001b[0;31m \u001b[0mlines\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlnum\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfindsource\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 932\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 933\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mismodule\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[0;32mc:\\Users\\mille\\Anaconda3\\lib\\inspect.py\u001b[0m in \u001b[0;36mfindsource\u001b[0;34m(object)\u001b[0m\n\u001b[1;32m 742\u001b[0m is raised if the source code cannot be retrieved.\"\"\"\n\u001b[1;32m 743\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m--> 744\u001b[0;31m \u001b[0mfile\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgetsourcefile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 745\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mfile\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 746\u001b[0m \u001b[1;31m# Invalidate cache if needed.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[0;32mc:\\Users\\mille\\Anaconda3\\lib\\inspect.py\u001b[0m in \u001b[0;36mgetsourcefile\u001b[0;34m(object)\u001b[0m\n\u001b[1;32m 658\u001b[0m \u001b[0mReturn\u001b[0m \u001b[1;32mNone\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mno\u001b[0m \u001b[0mway\u001b[0m \u001b[0mcan\u001b[0m \u001b[0mbe\u001b[0m \u001b[0midentified\u001b[0m \u001b[0mto\u001b[0m \u001b[0mget\u001b[0m \u001b[0mthe\u001b[0m \u001b[0msource\u001b[0m\u001b[1;33m.\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 659\u001b[0m \"\"\"\n\u001b[0;32m--> 660\u001b[0;31m \u001b[0mfilename\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgetfile\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mobject\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 661\u001b[0m \u001b[0mall_bytecode_suffixes\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimportlib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmachinery\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mDEBUG_BYTECODE_SUFFIXES\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 662\u001b[0m \u001b[0mall_bytecode_suffixes\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mimportlib\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmachinery\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mOPTIMIZED_BYTECODE_SUFFIXES\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[0;32mc:\\Users\\mille\\Anaconda3\\lib\\inspect.py\u001b[0m in \u001b[0;36mgetfile\u001b[0;34m(object)\u001b[0m\n\u001b[1;32m 623\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mobject\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mco_filename\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 624\u001b[0m raise TypeError('{!r} is not a module, class, method, '\n\u001b[0;32m--> 625\u001b[0;31m 'function, traceback, frame, or code object'.format(object))\n\u001b[0m\u001b[1;32m 626\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m 627\u001b[0m \u001b[0mModuleInfo\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnamedtuple\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'ModuleInfo'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'name suffix mode module_type'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: 10 is not a module, class, method, function, traceback, frame, or code object" - ] - } - ], - "source": [ - "inspect.getsource(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "inspect.isbuiltin(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "image/png": "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\nGXaFQqEYMv4/kyesq/afEWYAAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib inline\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "ax = plt.plot(np.random.randn(1000), np.random.randn(1000), 'o', alpha=0.3)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ax" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "eval('ax')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "\"list() -> new empty list\\nlist(iterable) -> new list initialized from iterable's items\"" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "inspect.getdoc(ax)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[('__abs__', ),\n", - " ('__add__', ),\n", - " ('__and__', ),\n", - " ('__bool__', ),\n", - " ('__ceil__', ),\n", - " ('__class__', int),\n", - " ('__delattr__',\n", - " ),\n", - " ('__dir__', ),\n", - " ('__divmod__',\n", - " ),\n", - " ('__doc__',\n", - " \"int(x=0) -> integer\\nint(x, base=10) -> integer\\n\\nConvert a number or string to an integer, or return 0 if no arguments\\nare given. If x is a number, return x.__int__(). For floating point\\nnumbers, this truncates towards zero.\\n\\nIf x is not a number or if base is given, then x must be a string,\\nbytes, or bytearray instance representing an integer literal in the\\ngiven base. The literal can be preceded by '+' or '-' and be surrounded\\nby whitespace. The base defaults to 10. Valid bases are 0 and 2-36.\\nBase 0 means to interpret the base from the string as an integer literal.\\n>>> int('0b100', base=0)\\n4\"),\n", - " ('__eq__', ),\n", - " ('__float__',\n", - " ),\n", - " ('__floor__', ),\n", - " ('__floordiv__',\n", - " ),\n", - " ('__format__', ),\n", - " ('__ge__', ),\n", - " ('__getattribute__',\n", - " ),\n", - " ('__getnewargs__', ),\n", - " ('__gt__', ),\n", - " ('__hash__', ),\n", - " ('__index__',\n", - " ),\n", - " ('__init__', ),\n", - " ('__int__', ),\n", - " ('__invert__',\n", - " ),\n", - " ('__le__', ),\n", - " ('__lshift__',\n", - " ),\n", - " ('__lt__', ),\n", - " ('__mod__', ),\n", - " ('__mul__', ),\n", - " ('__ne__', ),\n", - " ('__neg__', ),\n", - " ('__new__', ),\n", - " ('__or__', ),\n", - " ('__pos__', ),\n", - " ('__pow__', ),\n", - " ('__radd__', ),\n", - " ('__rand__', ),\n", - " ('__rdivmod__',\n", - " ),\n", - " ('__reduce__', ),\n", - " ('__reduce_ex__', ),\n", - " ('__repr__', ),\n", - " ('__rfloordiv__',\n", - " ),\n", - " ('__rlshift__',\n", - " ),\n", - " ('__rmod__', ),\n", - " ('__rmul__', ),\n", - " ('__ror__', ),\n", - " ('__round__', ),\n", - " ('__rpow__', ),\n", - " ('__rrshift__',\n", - " ),\n", - " ('__rshift__',\n", - " ),\n", - " ('__rsub__', ),\n", - " ('__rtruediv__',\n", - " ),\n", - " ('__rxor__', ),\n", - " ('__setattr__',\n", - " ),\n", - " ('__sizeof__', ),\n", - " ('__str__', ),\n", - " ('__sub__', ),\n", - " ('__subclasshook__', ),\n", - " ('__truediv__',\n", - " ),\n", - " ('__trunc__', ),\n", - " ('__xor__', ),\n", - " ('bit_length', ),\n", - " ('conjugate', ),\n", - " ('denominator', 1),\n", - " ('from_bytes', ),\n", - " ('imag', 0),\n", - " ('numerator', 10),\n", - " ('real', 10),\n", - " ('to_bytes', )]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "inspect.getmembers(a)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "# Adding Imenu Support" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "## Subheader" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "Seems to be a couple ways of doing this:\n", - "\n", - "1. Configuring a [imenu-generic-expression](http://emacswiki.org/emacs/ImenuMode#toc12) regex's.\n", - "\n", - "2. Redifining imenu-create-index ala python.el.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def func():\n", - " pass\n", - "\n", - "\n", - "class my_class(object):\n", - " def __init__(self):\n", - " pass\n", - "\n", - "\n", - "class my_class(object):\n", - " def __init__(self):\n", - " pass\n", - "\n", - " def funcme(arg1):\n", - " pass\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "# Another Header" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "ename": "ZeroDivisionError", - "evalue": "division by zero", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;36m1\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" - ] - } - ], - "source": [ - "1/0" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "import inspect" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1+1" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "inspect" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.4.3" - }, - "name": "Development Ideas.ipynb" - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/EIN_Manual.org b/EIN_Manual.org deleted file mode 100644 index c1f9fb4..0000000 --- a/EIN_Manual.org +++ /dev/null @@ -1,1105 +0,0 @@ -#+TITLE: The Emacs IPython Notebook Design Manual -#+STARTUP: indent -#+TYP_TODO: TODAY WEEK LATER - -* Overview -** [ANN] The Continued Existence of the Emacs IPython Notebook - -After the recent, exciting announcement of the eminent [[https://conferences.oreilly.com/jupyter/jup-ny][JupyterCon]], I was -somewhat saddened to see no mention of the EIN, or the Emacs IPython Notebook, -as an available client to the Jupyter notebook server. Drama queen that I am, I -quickly wrote a note to Fernando, who patiently and kindly explained that not -many were aware that this project still existed and that perhaps an announcement -or note to the main Jupyter list might be warranted. Hence the following, brief -history. I also promise not to be a drama queen. - -Some of you may remember, from back when the Jupyter project was still known as -the [[http://ipython.org/ipython-doc/rel-0.12/interactive/htmlnotebook.html][IPython notebook]], a talented and prolific coder of the name Takafumi -Arakaki, or tkf, who created an alternative client to the notebook server's -default web browser interface. - -This client, which he called the Emacs IPython Notebook (which you can still -find his project on [[https://github.com/tkf/emacs-ipython-notebook][github]]), or EIN, provided a complete ipython notebook -experience in the venerable Emacs editor. Not only was EIN nearly [[https://github.com/tkf/emacs-ipython-notebook/wiki/Screenshots][feature -complete]] when compared to the browser interface it also provided some useful -features for the Python programmer, like allowing one to [[https://github.com/tkf/emacs-ipython-notebook/wiki/Screenshots#connected-buffer][connect]] Python buffers -to a notebook and using jedi for autocompletion in the notebook buffer. - -Around March/April of 2014, just as IPython was advancing towards 1.0 and making -big changes in the notebook/contents API and the kernel communication protocol, -tkf mysteriously stopped pushing commits to his github repository. - -I did not know tkf other than from a couple brief conversations. I sincerely -hope tkf's story has a happy end (he does appear to still push the occasional -[[https://github.com/tkf/comparatist][commit]]); he is clearly a talented programmer and without him this impressive -piece of software would not exist. - -This is the point where yours truly enters the story. I had discovered the -IPython notebook the previous year and had found it an exteremly useful for -analyzing the performance of catalytic process units in the refining industry -and working with Python in general, but being a long-time Emacs user I had -somewhat bounced of the web interface. Discovering EIN was a godsend, and it -quickly became a mainstay in my set of analytic tools. - -Unfortunately the changes in going to v1.0 of the ipython notebook broke EIN, -and with tkf apparently out of the picture there did not seem much hope in EIN -staying compatible. Considering that I am a father of two with a full-time job -that has absolutely nothing to do with programming (and yet I am a long-time -Emacs user - it's complicated, don't ask), I can only describe what happened -next as an act of complete insanity: I decided to fork tkf's code, dig in and -try to keep up with the changes in ipython. - -Truthfully, no one was more surprised than I when I was actually able to keep -ein working with versions 1.0 and, soon after, 2.0 of IPython. In fact that -compatibility, in theory, is still in the code. One, again in theory, should be -able to fire up a 1.x or 2.x version of the IPython notebook and connect to it -using my fork of EIN. I say in theory, though, as I haven't touched that part of -the code in some time and it undoubtedly has suffered some bit rot in the -intervening years. - -The rest of the story is less interesting. Eventually I managed to convince -github and MELPA to treat my repository as the official version of ein. There -was some short-lived talk of renaming my fork to 'zwei', but the consensus was -that things were confusing enough with the change in ownership and to keep the -name as ein. - -Currently one can download ein through either [[http://melpa.org/#/ein][MELPA]] or [[https://github.com/dimitri/el-get][el-get]], and someone has -even been kind enough to create a spacemacs [[http://spacemacs.org/layers/+lang/ipython-notebook/README.html][layer]] with convenient VIM -keybindings for the heathens. - -At the moment EIN supports the recent incarnations of Jupyter, v4.3.1, token -authentication, _xsrf cookies and all. By the time you read this I may even have -pushed some commits that allow one to start and automatically log in to a -jupyter notebook server all from Emacs without having to drop into the terminal. - -In all, EIN continues to be a viable alternative to the web browser client. It -is not 100% feature complete, though, as it notably does not support widgets and -quite possibly never will. - -I haven't kept close track of who is using EIN, but it has 341 stars on github -and 28,175 downloads from MELPA. I know EIN is being used in at least a couple -businesses and from what I have heard it tends to be more popular among those -with a programming background - scientists and engineers tend to prefer the web -client which is not surprising since Emacs is not so much a text editor as it is -a Way of Life. - -I encourage anyone who is interested in trying out ein to install it via MELPA -or from the spacemacs ipython-notebook layer. There is [[http://millejoh.github.io/emacs-ipython-notebook/][documentation]], but it is -not perfect and I cannot guarantee it is 100% correct. Do not hesitate to open -an [[https://github.com/millejoh/emacs-ipython-notebook/issues][issue]] on github if you run into troubles, this is a hobby project but I do my -best to support it. - -If you have made it this far then my sincere thanks for staying patient through -my ramblings. As a parting thought I want to express my sincere thanks to -Takafumi Arakaki, wherever he may be, and to the [[http://jupyter.org/about.html][Jupyter]] team for their -fantastic work in creating this amazing piece of software. - -* Reference -** [[https://cask.readthedocs.io/en/latest/index.html][Cask]] -** Learning Git -https://help.github.com/articles/about-pull-requests/ -https://yangsu.github.io/pull-request-tutorial/ - -** Testing -ert. - -[[https://github.com/ecukes/ecukes][ecukes]]. - -Travis token: 2yP9mWPstlPi9kUoK9DIKw 2yP9mWPstlPi9kUoK9DIKw - -* Design -** Version update checklist: - -- ein.el -- ein-pkg.el -- ein-core.el -- doc/source/conf.py - -** Notebook Security -Life gets more complicated with jupyter notebook [[https://blog.jupyter.org/2016/12/21/jupyter-notebook-4-3-1/][v4.3.1]], though the intentions -are purely altruistic. The notebook server now requires a -~[[http://www.tornadoweb.org/en/stable/guide/security.html#cross-site-request-forgery-protection][xsrf]]~ -token via cookies to validate requests. - -If I interpret the documentation correctly, a successful login should set a -_xsrf cookie, which then needs to be included in the header with all additional -REST queries. - -What is supposed to happen when EIN connects to a token-enabled notebook server. - -If we are using the curl backend for request: - -Once a user succesfully authenticates against a running jupyter server via -either ~ein:notebooklist-login~ curl will store two cookies in the -~curl-cookie-jar~ file. The location of this file is set by the variable -~[[help:request-storage-directory][request-storage-directory]]~. One cookie is -for the token authentication, and the other is the xsrf token. [[*Example curl cookie jar file][Below]] is an -example of cookies that were set after authenticating against a jupyter notebook -server running on my personal aws instance. On subsequent calls to the content -API request/curl will automatically supply the correct cookies. The websocket -package uses the ~[[info:url#Top][url]]~ package to set cookies, and so will not -know about the authentication and ~xsrf~ tokens unless EIN does some extra work. -EIN does this in the -~[[file:c:/Users/mille/Dropbox/Projects/emacs-ipython-notebook/lisp/ein-websocket.el::(defun -ein:websocket--prepare-cookies (url)][ein:websocket--prepare-cookies]]~ -function. The function does some extra work to only copy over cookies pertaining -to the host the websocket is connecting on. - - -*** Example curl cookie jar file - -ec2-13-58-41-203.us-east-2.compute.amazonaws.com FALSE / FALSE 0 _xsrf 2|164f26da|390fef85a22a21f913024720d16e0328|1535314712 -#HttpOnly_ec2-13-58-41-203.us-east-2.compute.amazonaws.com FALSE / TRUE 1539117935 username-ec2-13-58-41-203-us-east-2-compute-amazonaws-com-8888 "2|1:0|10:1536525935|62:username-ec2-13-58-41-203-us-east-2-compute-amazonaws-com-8888|44:NmMwYzg5NDA2MDBkNDVjNzk1MmY3ZGEwMzg0ZDUwNTA=|b975a41e86cea678fd2b97be9e447254bdb109e7e04e8f72f74fe6a151812c4d" - -** Notebook Format - -Version 4.0 [[http://nbformat.readthedocs.org/en/latest/][documented]]. - -Earlier versions might be documented less formally on the wiki. Can -also look at the IPython source in the json files. - -** Notebook Buffer - -Notebook information is stored as a [[file:lisp/ein-notebook.el::ein:$notebook][struct]]. Always associated with a buffer, -[[file:lisp/ein-notebook.el::ein:notebook-buffer][ein:notebook-buffer]] is used to find buffer associated with a notebook. - -Notebook does not hold cells, that is delegated to instances of the [[file:emacs-ipython-notebook/lisp/ein-worksheet.el::ein:worksheet][worksheet]] -class. Instances are stored as a list in the ~ein:$notebook-worksheets~ slot. - -Opened notebooks are kept in the ~ein:notebook--opened-map~ hash -table. Keys are cons cells of ~url-or-port~ and ~path~. - -There are a number of helper functions for returning the struct for an opened notebook: - - - ~[[file:lisp/ein-notebook.el::(defun ein:notebook-get-opened-notebook (url-or-port path)][ein:notebook-get-opened-notebook]]~ :: - - ~[[file:lisp/ein-notebook.el::(defun ein:notebook-get-opened-buffer (url-or-port path)][ein:notebook-get-opened-buffer]]~ :: - -** Notebooklist Buffer -** Cell Execution -Entry point is usually -~[[file:~/Dropbox/Projects/emacs-ipython-notebook/lisp/ein-worksheet.el::(defun ein:worksheet-execute-cell (ws cell)][ein:worksheet-execute-cell-and-goto-next]]~, -but the fun doesn't really start until we get to ~ein:cell-execute~. - -The cell [[file:~/Dropbox/Projects/emacs-ipython-notebook/lisp/ein-classes.el::(defclass%20ein:basecell%20()][class]] (if it is a codecell) will know the kernel it is associated with, -and the actual code gets run via ~ein:kernel-execute~. The callbacks are set via -~ein:cell-make-callbacks~, which make sure the cell output is updated -appropriate after the kernel finishes executing the code. - - -*** Patching to automatically detect hy code - -We could subclass ein:codecell and make an ein:hy-codecell class. Then we could have a -specialized ein:cell-execute-internal which run a pytools helper that parses and -evaluates the hy code. - -** Kernel communication - -The [[https://jupyter-client.readthedocs.io/en/latest/messaging.html#messaging][messaging protocol]]. - -** Contents API - -Documented at the IPython Github [[https://github.com/ipython/ipython/wiki/IPEP-27%253A-Contents-Service][wiki.]] - -There is also [[http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml][another]] great online resource for session and kernel -REST API. - -** Connecting to a running Kernel -Entry point is ~[[file:lisp/ein-notebook.el::ein:notebook-start-kernel][ein:notebook-start-kernel]]~ which is called from -~ein:notebook-request-open-callback~ after successful call to the notebook -server requesting the contents of a given notebook. - -~[[file:lisp/ein-kernel.el::ein:kernel-start][ein:kernel-start]]~ starts/gets a session with a running kernel using the REST API. - -On a [[file:lisp/ein-kernel.el::ein:kernel--kernel-s][successful]] return ein [[file:lisp/ein-websocket.el::ein:websocket][creates]] a websocket channel (channels for -IPython 2.x) via a call to ~websocket-open~ in the [[https://github.com/ahyatt/emacs-websocket][emacs-websocket]] -package. The URL request is of the form: - -#+BEGIN_QUOTE -ws://{server_address}:{port}/api/kernels/{kernel id from previous REST query}/channels?session_id={session id} -#+END_QUOTE - -** How a Worksheet is Displayed -EIN relies heavily on EIEIO and EWOC. - -EWOC information is stored as part of the ~[[file:emacs-ipython-notebook/lisp/ein-cell.el::(defclass ein:basecell ()][ein:basecell]]~ class. Presumably there -are cells for input and output (when input is code) nodes??? - -EWOC PP eventually calls ~[[file:lisp/ein-cell.el::ein:cell-append-mime-type][ein:cell-append-mime-type]]~ for output. Latex is -considered text, but should be able to convert to image using dvitopng, -imagemagick, other? - -** Jupyterhub Integration - -REST API [[http://jupyterhub.readthedocs.io/en/latest/api/index.html][documentation]] (and in [[http://petstore.swagger.io/?url%3Dhttps://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#!/default][swagger]]). - -There is a login request (http[s]://{url}/hub/login). But it doesn't seem to -work so well unless you are in a browser. - -Jupyterhub requires authentication using username/password, as opposed to just -providing a secret when logging into ipython 3.x and earlier. - -On logging in a cookie of form "jupyter-hub-token-" is generated and -propogated with all calls to server. Emacs request should automatically handle -this. - -Also looks like the content REST API has been modified so that queries are of the -form: /user//. - -*** [[https://jupyterhub.readthedocs.io/en/latest/howitworks.html][How Jupyterhub works]] - -Steps: - -1. +Log in at the hub via ~/hub/login~+. Get a token from the authenticator by - POST'ing to ~[[https://jupyterhub.readthedocs.io/en/latest/_static/rest-api/index.html#path--authorizations-token][/authorizations/token]]~. The authenticator returns an API token if - succesful. Doesn't work with OAuth. -2. Logging in sets two cookies, one for ~/hub~ and other for ~/user/[username]~ - with encrypted token. (Also for ~/authorizations/token~?) -3. Access the user's single instance jupyter via ~/user/[username]~. This will - return a [[https://jupyterhub.readthedocs.io/en/latest/_static/rest-api/index.html#/definitions/User][user]] json object that has the address of the user's notebook server. - -To use the REST API need to have an [[https://jupyterhub.readthedocs.io/en/latest/rest.html][API token]]? - -*** Sample Code -#+BEGIN_SRC ein :session 8888/JupyterHub.ipynb :results drawer - import requests - - api_login = 'http://192.168.0.13:8000/hub/login' - user = 'millejoh' - password = 'number10ox' - - r = requests.post(api_login, - data={ - 'username':user, - 'password':password - } - ) - - r.raise_for_status() - r -#+END_SRC - -#+RESULTS: - - -Per the documentation you need to supply an authorization token with requests to -server: - -#+BEGIN_SRC ein :session 8888/Untitled.ipynb - import requests - - api_url = 'http://192.168.0.13:8000/hub/api' - token = '' - - r = requests.get(api_url + '/users', - headers={ - 'Authorization': 'token %s' % token, - } - ) - - r.raise_for_status() - users = r.json() - users -#+END_SRC - -#+RESULTS: - -* Enhancements/Fixes - -** Refactor Kernel Communication - -New module to start kernel session and handle communication built off deferred. - -** Seamless Jupyterhub and ssh support -For jupyterhub need to support its multiple authentication methods. - -For ssh need to figure out how to set cookies when tunneling. - -See [[https://elpa.gnu.org/packages/oauth2.html][emacs-oauth2]]. - -** Integrate with eldoc - -Hook is through buffer local variable ~eldoc-documentation-function~, which is a -function of no variables that returns the docstring for the object at point. - -** Inspector -The way it works: - - 1. Get the object at point, which will be a string representing a python object. - 2. Send that string via the kernel to python code that does some introspection - and returns a json representation of the object. - 3. Create a buffer and prettily display the data returned by the kernel. - -The way that pycharm does it is that each variable has it's own line with the format: - -#+BEGIN_CENTER -~/variable name/ = {/type/} /value/~ -#+END_CENTER - -If the object is made up of many items- like a module, list, class- then you can -expand the object and see its individual elements. Hence why we are so -interested in a easy to use folding overlay system thingy. - -Spyder has a [[https://pythonhosted.org/spyder/variableexplorer.html][variable explorer]] and its UI is a modal dialog that displays a -table of information. - -The active console variables of Pycharm is neat, we should borrow and steal. - -*** LATER Prototype Folding Overlay -Maybe first adapt abstract display [[info:elisp#Abstract%20Display%20Example][example]] to current inspector display code? - -Or adapt magit [[file:c:/Users/mille/OneDrive/Documents/GitHub/magit/lisp/magit-section.el::(defgroup%20magit-section%20nil][sections]]. - -Use the [[info:elisp#Abstract%20Display][abstract display]] and [[info:elisp#Overlays][overlays]] for displaying, managing the buffer? - -Should take some time to understand how magit manages its buffers. Magic seems to happen -in ~[[magit-insert-section][magit-insert-section]]~. - -Magit's sections are interesting, but I do not think I am smart enough to use -them. I really would like to avoid reinventing the wheel, but maybe I can get by -just reinventing the spokes. - -#+BEGIN_SRC elisp - (require 'cl-lib) - (require 'dash) - - (cl-defstruct $section - type content parent children) - - (defun section:new () - - ) -#+END_SRC - -#+RESULTS: -: section:new - -*** Introspection -For inspecting, think of something like in [[https://common-lisp.net/project/slime/doc/html/Inspector.html#Inspector][SLIME]]. No good pictures there, but -this [[http://malisper.me/2015/07/14/debugging-lisp-part-2-inspecting/][blog]] does a bit better. - -Python has facilities for [[https://docs.python.org/3/library/inspect.html][introspection]]. There is also the [[https://docs.python.org/3/library/pyclbr.html#module-pyclbr][pyclbr]], a module for -implementing a class browser. Jedi has excellent facilities for static analysis -of code. - -IPython wraps the python inspector with ~IPython.core.oinspect~ module. - -First let's create a few inspectable objects: -#+NAME: cee67d1f-dc69-41e8-a109-a3fb78e2990b -#+BEGIN_SRC ein :session 8888/Brain/Inspector.ipynb - import numpy as np - - num = 1.0 - lst = [0,1,2,3] - hash = {'a':0, 'b':1, 'c':2} - - def fn(a,b): - return a+b - - class Hello(object): - def __init__(self): - self.num = 1.0 - self.lst = [0,1,2,3] - self.hash = {'a':0, 'b':1, 'c':2} - - def fn(self, a, b): - return a+b - - def fn2(a, b): - return Hello().fn(a,b) -#+END_SRC - -#+RESULTS: cee67d1f-dc69-41e8-a109-a3fb78e2990b -: --------------------------------------------------------------------------- -ModuleNotFoundError Traceback (most recent call last) - in -----> 1 import numpy as np - 2 - 3 num = 1.0 - 4 lst = [0,1,2,3] - 5 hash = {'a':0, 'b':1, 'c':2} - -ModuleNotFoundError: No module named 'numpy' - - -#+RESULTS: -#+begin_example ---------------------------------------------------------------------------- -ModuleNotFoundError Traceback (most recent call last) - in () -----> 1 import numpy as np - 2 - 3 num = 1.0 - 4 lst = [0,1,2,3] - 5 hash = {'a':0, 'b':1, 'c':2} - -ModuleNotFoundError: No module named 'numpy' -#+end_example - -Now let's inspect: - -#+BEGIN_SRC ein :session 8888/emacs-ipython-notebook/Inspector.ipynb - import inspect - - hello = Hello() - - sig = inspect.signature(fn) - dir(sig) -#+END_SRC - -#+RESULTS: -#+begin_example ---------------------------------------------------------------------------- -NameError Traceback (most recent call last) - in () - 1 import inspect - 2 -----> 3 hello = Hello() - 4 - 5 sig = inspect.signature(fn) - -NameError: name 'Hello' is not defined -#+end_example - -Tactic is to wrap information returned by the inspect module. - -#+BEGIN_SRC elisp :session t - (defclass ein:iobject () - ((name :accessor ein:iobject-name :documentation "String representation can be evaluated in python to generate the object being inspected.") - (kernel :accessor ein:iobject-kernel :documentation "Kernel where the object exists.")) - :documentation "Class to hold information returned by Python `inspect` module for a Python object identified in the `name` slot.") -#+END_SRC - -#+RESULTS: -: ein:iobject - -Is it time to use deferred for kernel execute queries? - -#+BEGIN_SRC elisp :session t - (ein:kernel-execute (ein:iobject-kernel)) - - ein:iobject -#+END_SRC - -*** Mockup for inspector - -**** Classes - <--- Hyperlink to source definition? -------------------------------- -Class: -Module defined in? -------------------------------- -Collapsable documentation? -------------------------------- - -All slots: - -[set] slot_name = slot_value -[set] slot2_name = slot2_value - -**** Functions/Callables -**** Generator -**** Coroutine -**** Builtin -**** Module -*** Variable watchlist - -** Pymacs w/ein-kernel as a backend - -Not sure if pymacs still works, but wouldn't it be cool to have Pymacs -have the ability to interact with Jupyter kernels? - -What we want is to translate Python datastructures to lisp and vice versa. Not -sure what the wire protocol is for pymacs, but for ein the intermediary is JSON. - -Do this like in - -** A Tramp backend for EIN -*** Finding files for remote session ([[https://github.com/millejoh/emacs-ipython-notebook/issues/263][#263]]) -sam-s suggests using tramp. -*** Make notebooks more file-like? - -Start by setting ~[[help:set-visited-file-name][set-visitied-file-name]]~, but what about notebooks from remote -servers? This is dangerous as it could result in the buffer accidentally getting -written to disk using Emacs, bypassing conversion into JSON and irreparably -corrupting the notebook. - -Make EIN buffer/notebook names "[[info:elisp#Magic%20File%20Names][magic]]"? - -Is is it possible to define new type of [[info:emacs#Remote%20Files][remote]] files? For jupyter have something -like ~/ein:HOST:FILENAME~. Sounds possible by configuring ~[[help:tramp-methods][tramp-methods]]~. NO! -Won't work as TRAMP calls out to external processes. -** Integrating other Emacs python tools -*** Integrate with [[https://github.com/donkirkby/live-py-plugin][live-py-plugin]] -*** Refactoring support? -Via [[https://github.com/python-rope/rope/blob/master/docs/library.rst][rope]]? -** Proper command history -[[http://jupyter-client.readthedocs.io/en/latest/messaging.html#history][Documentation]] for the jupyter protocol. - -EIN's interface is through [[file:emacs-ipython-notebook/lisp/ein-worksheet.el::(defun%20ein:worksheet-previous-input-history%20(ws%20cell%20index)][ein:worksheet-previous-input-history]]. - -Looks like EIN is using history protocol supplied by kernel, but I don't fully -understand difference betwee 'range', 'tail' and 'search' access types. - -** Run dynamic javascript - -The development [[ipynb:(:url-or-port%208888%20:name%20"emacs-ipython-notebook/Embedding%20Altair%20Graphs.ipynb")][notebook]]. - -Emacs is not a web browser, hence does not know how to execute javascript. - -Maybe we can get around this using [[https://github.com/skeeto/skewer-mode][skewer-mode]] or [[http://js-comint-el.sourceforge.net/][js-comint.el]]. - -Skewer-mode uses JS client provided by a web browser, while js-comint depends on -nodejs (you understand this difference, right? Right?). - -Skewer mode seems to work for basic javascript evaluation, and according to -comments in [[https://github.com/millejoh/emacs-ipython-notebook/issues/65#issuecomment-322084969][github]] it might be possible to get things like bokeh graphs working. - -Another thought is to get python to do this for us. The packages [[][naked]] (an -unfortunate name given my corporate firewall) and [[https://github.com/doloopwhile/PyExecJs][PyExecJs]]. - -What does the html for a notebook cell output look like? - -#+BEGIN_SRC html - - -
-
-
-
-
Out[3]:
-
<tf.Tensor 'MatMul:0' shape=(1, 1) dtype=float32>
-
-
-
- -
-#+END_SRC -*** Embedding [[https://github.com/ellisonbg/altair][Altair]] plots - -First get [[*Run dynamic javascript][dynamic javascript]] working... - -Relevant [[https://github.com/vega/ipyvega/issues/31][issue]], [[https://github.com/vega/ipyvega/pull/32][pull request]] and [[https://github.com/ellisonbg/ipyvega/blob/be19059068557c44cbdcbcf5ad509c3312b25763/src/index.js][code]]. - -Appears the code has capability of returning javascript and png output. When -calling from ein all that gets returned is javascript, which -`ein:cell-append-mime-type` chokes on. - -Somehow, when running [[https://nbconvert.readthedocs.io/en/latest/][nbconvert]], the javascript gets turned into a png. How to trigger -that when normally executing cells? -*** XWidget Support/Interactive Widgets - -For the most part this is a non-starter since in Jupyter this is built on web -and javascript, but maybe with emacs 25's coming integration with [[https://www.emacswiki.org/emacs/EmacsXWidgets][xwidgets]] there -is hope? - -**** What Does ipywidgets.interact() return? - -A call to `ipywidgets.interact()` creates a [[http://jupyter-client.readthedocs.org/en/latest/messaging.html#custom-messages][custom communications channel]] -with the jupyter server. - -1. What are message types (msg_type) comm_msg and comm_open for? - - These are received when calling interact(). - -***** Websocket data for comm_open -#+BEGIN_SRC -[WS] Received: {"msg_id": "56821eaa-cc32-4a34-bac3-8468ea08b7a0", "content": {"execution_state": "busy"}, "channel": "iopub", "metadata": {}, "msg_type": "status", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "56821eaa-cc32-4a34-bac3-8468ea08b7a0", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "status"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} {"msg_id": "95f88fb5-2e4b-45b5-b78b-79d9274d392a", "content": {"execution_count": 3, "code": "interact(f, x=10)"}, "channel": "iopub", "metadata": {}, "msg_type": "execute_input", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "95f88fb5-2e4b-45b5-b78b-79d9274d392a", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_input"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} {"msg_id": "ef75371f-9047-46de-8eda-2c8697e2b60b", "content": {"data": {"width": "", "_model_name": "BoxModel", "font_size": "", "children": [], "overflow_x": "", "padding": "", "font_style": "", "_dom_classes": ["widget-interact"], "box_style": "", "height": "", "_view_module": "", "margin": "", "color": null, "msg_throttle": 3, "border_color": null, "font_family": "", "_view_name": "BoxView", "_model_module": null, "version": 0, "overflow_y": "", "background_color": null, "font_weight": "", "_css": [], "border_width": "", "visible": true, "border_style": "", "border_radius": ""}, "target_name": "ipython.widget", "comm_id": "237329515cca473985d6fa52ec0c93a1", "target_module": null}, "channel": "iopub", "metadata": {}, "msg_type": "comm_open", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "ef75371f-9047-46de-8eda-2c8697e2b60b", "date": "2016-03-24T07:24:50.910702", "version": "5.0", "msg_type": "comm_open"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} -#+END_SRC - -***** Websocket data for comm_msg -#+BEGIN_SRC emacs-lisp -[WS] Received: {"msg_id": "fe357d60-e83a-49ac-821f-7d99cdf20b8a", "content": {"data": {"description": "", "orientation": "horizontal", "continuous_update": true, "_model_name": "WidgetModel", "font_size": "", "step": 1, "background_color": null, "padding": "", "slider_color": null, "height": "", "_view_module": "", "margin": "", "color": null, "width": "", "font_family": "", "border_color": null, "_dom_classes": [], "min": -10, "_range": false, "disabled": false, "_model_module": null, "_view_name": "IntSliderView", "max": 30, "version": 0, "font_style": "", "msg_throttle": 3, "value": 10, "readout": true, "font_weight": "", "_css": [], "border_width": "", "visible": true, "border_style": "", "border_radius": ""}, "target_name": "ipython.widget", "comm_id": "c1059008e6d046209c9d63de036c1aff", "target_module": null}, "channel": "iopub", "metadata": {}, "msg_type": "comm_open", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "fe357d60-e83a-49ac-821f-7d99cdf20b8a", "date": "2016-03-24T07:24:50.948495", "version": "5.0", "msg_type": "comm_open"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} {"msg_id": "30514644-45e1-45c7-a5db-42c9ee22e9ec", "content": {"data": {"buffers": [], "state": {"description": "x"}, "method": "update"}, "comm_id": "c1059008e6d046209c9d63de036c1aff"}, "channel": "iopub", "metadata": {}, "msg_type": "comm_msg", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "30514644-45e1-45c7-a5db-42c9ee22e9ec", "date": "2016-03-24T07:24:50.964124", "version": "5.0", "msg_type": "comm_msg"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} {"msg_id": "fc005b54-774c-4920-860f-cec08cb5b5ba", "content": {"data": {"buffers": [], "state": {"children": ["IPY_MODEL_c1059008e6d046209c9d63de036c1aff"]}, "method": "update"}, "comm_id": "237329515cca473985d6fa52ec0c93a1"}, "channel": "iopub", "metadata": {}, "msg_type": "comm_msg", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "fc005b54-774c-4920-860f-cec08cb5b5ba", "date": "2016-03-24T07:24:50.964124", "version": "5.0", "msg_type": "comm_msg"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} {"msg_id": "65240518-737e-4614-8ad1-7d9fcfc567bd", "content": {"data": {"method": "display"}, "comm_id": "237329515cca473985d6fa52ec0c93a1"}, "channel": "iopub", "metadata": {}, "msg_type": "comm_msg", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "65240518-737e-4614-8ad1-7d9fcfc567bd", "date": "2016-03-24T07:24:50.964124", "version": "5.0", "msg_type": "comm_msg"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} {"msg_id": "6b0b41e2-5af0-4690-9902-9e73a61cf0e3", "content": {"wait": true}, "channel": "iopub", "metadata": {}, "msg_type": "clear_output", "buffers": [], "header": {"username": "username", "session": "eb518e76-61af-4bff-9fb0-49fb78883056", "msg_id": "6b0b41e2-5af0-4690-9902-9e73a61cf0e3", "date": "2016-03-24T07:24:50.964124", "version": "5.0", "msg_type": "clear_output"}, "parent_header": {"username": "username", "session": "5b01e727-3ce9-416f-bb67-f9400b719e33", "msg_id": "6dd8ea4c-325a-4938-8ad9-d68e2e4dbb0b", "date": "2016-03-24T07:24:50.879558", "version": "5.0", "msg_type": "execute_request"}} -#+END_SRC -** Inline latex -See issue [[https://github.com/millejoh/emacs-ipython-notebook/issues/88][#88]]. - -*** For Further Investigation - -- [[https://github.com/zk-phi/magic-latex-buffer][magic-latex-buffer.el]] -- [[https://www.gnu.org/software/auctex/preview-latex.html][preview-latex.el]] -- Another [[https://github.com/aaptel/preview-latex/][preview-latex]] package (based on org-latex-preview). - -*** Inline using org-latex-preview - -[[http://orgmode.org/manual/Previewing-LaTeX-fragments.html#Previewing-LaTeX-fragments][Documentation]] for this facility in org. - -Does it work here? - -\begin{equation} -x=\sqrt{b} -\end{equation} - -Some inline Latex math $a^2=b$. - -Yes, but nedd MiKTeX installed if on windows. - -If org-latex-preview is working then [[https://github.com/aaptel/preview-latex][p]]x will also work, though the code for -~[[file:~/.emacs.d/elpa/px-20141006.548/px.el::(defun px--create-preview (at)][px--create-preview]]~ needs to be patched as the signature for `org-format-latex` -has changed. - -*** Using magic-latex-buffer -Per the [[https://github.com/zk-phi/magic-latex-buffer][documentation]] all you need to do to configure is to add a hook: - -#+BEGIN_SRC emacs-lisp - (add-hook 'latex-mode-hook 'magic-latex-buffer) -#+END_SRC - -#+RESULTS: - -Or manually activate by calling ~M-x magic-latex-buffer~. - -Use variable ~ein:notebook-first-open-hook~ to enable? - -This works, at least for viewing, but the images that get inserted confuse ein -when saving a notebook and generate errors in Jupter. Can be worked around by -disabling ~magic-latex-buffer~ before saving. One hack is to advise -~ein:notebook-save-notebook-command~? - -#+BEGIN_SRC emacs-lisp - (defvar ein:magic-latex-enabled-p nil) - - (defun ein:disable-magic-latex-maybe (&rest args) - (when ein:magic-latex-enabled-p - (ein:log 'debug "Disabling magic-latex.") - (magic-latex-buffer -1))) - - (defun ein:enable-magic-latex-maybe (&rest args) - (when ein:magic-latex-enabled-p - (ein:log 'debug "Enabling magic-latex.") - (magic-latex-buffer t))) - - (advice-add #'ein:notebook-save-notebook :before #'ein:disable-magic-latex-maybe) - (advice-add #'ein:notebook-save-notebook :after #'ein:enable-magic-latex-maybe) - - (advice-add #'ein:cell-execute-internal :before #'ein:disable-magic-latex-maybe) - (advice-add #'ein:cell-execute-internal :after #'ein:enable-magic-latex-maybe) - -#+END_SRC -** The Return of Worksheets - -tkf/ein and IPython 2.x allowed for multiple worksheets within an individual -notebook. This feature was removed in 3.0 since multiple worksheets do not make -much sense in the context of a tabbed web browser interface. EIN's legacy code -still supports worksheets, though at the moment that information is lost upon -saving a notebook. - -Having multiple worksheet support makes some sense for ein; below is thinking on -how to reimplement this feature. - -IPython nbformat 4 specifies a [[http://ipython.org/ipython-doc/3/notebook/nbformat.html#metadata][metadata]] key which can be used to store general -information. Cell metadad has a tag key which is a "A list of string tags on the -cell. Commas are not allowed in a tag." - -Best place to set the tag key is when generating [[content]] for saving a notebook. -** Outside Wish and Bug List -*** Wishlist - -- [X] switch kernel (4 hours) - -- [X] getting a true Python mode when editing code in cells, without messing up the - other formatting (8 hours) - -- [X] Auto-saving and checkpoints (4 hours) - -- [X] Save a copy of the notebook (1 hour) - -- [ ] If one cuts and pastes read-only text into a cell it can’t be edited - -- [ ] A full undo history - -- [ ] Command history / autocomplete like one gets in regular ipython - -- [ ] Image resizing - -- [X] Better debug support (maybe via [[https://github.com/realgud/realgud][realgud]]?) - -*** Bugs - -- [X] emacs ipython notebook fails to follow redirects properly - This is mainly - due to the fact that it holds on the original site name internally. - -- [X] cookie expiration for long running notebooks - On long running notebooks - tornado's default cookie expiration is 30 days. After the cookie expires emacs - will continue to attempt autosave, but the notebook will not save. The - workaround is to run ein:notebooklist-open to generate a new GET request - against /login to get another cookie. -** Implemented/Archived -*** Tracebacks in ob-ein blocks -Error/traceback information should be communicated when executing ein blocks -from org buffers. -*** Issue #126: Support checkpoints/autosave -Per the REST [[http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyter/notebook/master/notebook/services/api/api.yaml][api]] this is supported via /contents/path/checkpoints. GET to -retrieve checkpoints for notebook, POST to create one. Current -FileContentsManager implementation only keeps one checkpoint at a time. - -Work this as a [[info:elisp#Timers][timer]] that runs after user customizable period of time. - -#+BEGIN_SRC elisp - (setq ein:force-sync t) - (setq content (ein:content-query-contents "Untitled.ipynb" 8888)) - (ein:content-query-checkpoints content) - (list (ein:$content-path content) - (ein:$content-checkpoints content)) - -#+END_SRC - -#+RESULTS: -| Untitled.ipynb | ((:id checkpoint :last_modified 2016-10-19T18:35:39.391740+00:00)) | - -Create a checkpoint: - -#+BEGIN_SRC elisp - (ein:content-create-checkpoint content) - (ein:$content-checkpoints content) -#+END_SRC - -#+RESULTS: -| :id | checkpoint | :last_modified | 2016-10-19T18:35:39.391740+00:00 | - - -Delete a checkpoint: - -#+BEGIN_SRC elisp - (ein:content-delete-checkpoint content "checkpoint") - (ein:content-query-checkpoints content) - (ein:$content-checkpoints content) -#+END_SRC - -#+RESULTS: -*** Edit cells ala ~org-edit-src-code~ -#+BEGIN_SRC python -#+END_SRC - -anaconda-mode breaks unless the following change is made: -#+BEGIN_SRC elisp - (defun anaconda-mode-jsonrpc-request-data (command) - "Prepare buffer data for COMMAND call." - `((jsonrpc . "2.0") - (id . 1) - (method . ,command) - (params . ((source . ,(buffer-substring-no-properties (point-min) (point-max))) - (line . ,(line-number-at-pos (point))) - (column . ,(- (point) (line-beginning-position))) - (path . ,(if (buffer-file-name) - (progn - (if (pythonic-remote-p) - (and - (tramp-tramp-file-p (buffer-file-name)) - (equal (tramp-file-name-host - (tramp-dissect-file-name - (pythonic-tramp-connection))) - (tramp-file-name-host - (tramp-dissect-file-name - (buffer-file-name)))) - (pythonic-file-name (buffer-file-name))) - (buffer-file-name))) - "")))))) ;; So simple, but so necessary. -#+END_SRC -*** Org Babel Support -Should be doable through ~[[file:emacs-ipython-notebook/lisp/ein-shared-output.el::(defun ein:shared-output-eval-string (code &optional popup verbose kernel][ein:shared-output-eval-string]]~. - -Need to specify session and/or a kernel. Kernel will be via the :kernelspec -argument. In case of :session the argument is path (including url or port) for -notebook to use for executing code. In case just a kernel ein will generate a -notebook using the value of the ~~ variable. - -To get result can call ~ein:get-cell-at-point--shared-output~?. For sure needs -to be done as a callback. Questionable how to insert output into results - -**** Test blocks - -#+BEGIN_SRC ein :session 8888/Untitled.ipynb - import sys - - a = 14500 - b = a+1000 - sys.version -#+END_SRC - -#+RESULTS: -| '3.5.2 | Anaconda 4.2.0 (64-bit) | (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)]' | - - -#+BEGIN_SRC ein :session 8888/Untitled.ipynb - a -#+END_SRC - -#+RESULTS: -| 14500 | - -#+BEGIN_SRC ein :session 8888 - a -#+END_SRC - -#+RESULTS: - -#+BEGIN_SRC ein :session 8888/Untitled.ipynb :file C:/Temp/img.png :kernelspec conda-env-anaconda-py - import sys - from scipy.spatial import Voronoi, voronoi_plot_2d, KDTree - - import numpy as np - import matplotlib.pyplot as plt - - - %matplotlib inline - - points = np.array([[0., 0.], [0., 1.], [0., 2.], [1., 0.], [1., 1.], [1., 2.], - [2., 0.], [2., 1.], [2., 2.]]) - - plt.plot(points[:,0], points[:,1], 'ko') - plt.show() -#+END_SRC - -#+RESULTS: -[[file:C:/Temp/img.png]] -*** Imenu/Speedbar Cooperation -Seems to be a couple ways of doing this: - - 1. Configuring ~[[http://emacswiki.org/emacs/ImenuMode#toc12][imenu-generic-expression]]~ regex's. - - 2. Redefining imenu-create-index ala python.el. - -(2) seems to be the more elegant solution. - -EIN currently has minimal support for imenu through -~[[file:lisp/ein-worksheet.el::ein:worksheet-imenu-create-index][ein:worksheet-imenu-create-index]]~, but all it does is look for -headings. Somehow this fails to work with speedbar and also does not handle -indexing Python code (i.e. variables, function, classes, etc.). - -To get the speedbar working we will need to define a minor mode per the -following [[http://www.gnu.org/software/emacs/manual/html_node/speedbar/Minor-Display-Modes.html#Minor-Display-Modes][instructions]]. - -For /name/~-speedbar-menu-items~ can I just use ~imenu-generic-expression~? - -Maybe the way to do this is for each ~[[file:lisp/ein-cell.el::ein:codecell][codecell]]~ create a temp buffer with the text -of that cell and call ~ein:imenu-create-index~. - -#+BEGIN_SRC elisp - (let ((text (ein:cell-get-text cell))) - (with-temp-buffer - (insert text) - (ein:imenu-create-index))) -#+END_SRC - -Still will need way to map temp buffer positions to actual positions in the -notebook buffer (~ein:cell-input-pos-min~ and ~ein:cell-input-pos-max~) -*** Access password protected notebooks (issue [[https://github.com/millejoh/emacs-ipython-notebook/issues/57][#57]]) -This is what I have found out so far: - -You can authenticate with the IPython/Jupyter notebook server using -ein:notebooklist-login. After calling this a cookie is generated (very easy to -see if you are using curl as the backend for emacs-request) and you can then use -the REST API to list and get notebook data. - -Once authenticated REST calls to get notebook json data and create sessions work -fine. After EIN starts a session one can see the kernel is running from the web -interface. The problem starts when ein tries to open a websocket connection to -the kernel. The notebook server generates a 403 forbidden response. I think -because emacs-websocket doesn't know anything about the security cookie -generated during the curl request. - -Not sure if that makes sense, but for the moment that is my theory on what's -happening. Somehow we need to provide the security cookie with the websocket -connect request. - -<2015-06-09 Tue> SOLVED(?) - issue is that emacs-websocket needs to provide more -info with the connection header: - -1. Specify the port along with the url. -2. Pass along a security cookie. -*** Jump to notebook code in traceback (issue [[https://github.com/millejoh/emacs-ipython-notebook/issues/42][#42]]) - -What needs to be done: - -1. Carry notebook reference in the ~[[file:lisp/ein-traceback.el::ein:traceback][ein:traceback]]~ structure. -2. Look for ~ in ()~. The number 3 means - input #3 in the notebook. -3. Find cell based on input number. Can iterate through list of cells () and look for matching - ~input-prompt-number~. -4. Call ~ein:cell-goto~ on that cell. May need to swap buffers first. -*** MuMaMo or Polymode or mmm-mode - -For better support of Python editing either of these may be the way to go. EIN -already supports MuMaMo, but the project is no longer maintained. I could -incorporate it into ein-mumamo. Unfortunately it seems MuMaMo is broken under -emacs 25.1. Not sure where it is breaking, but something is causing redisplay -function to error out due to too many args (600+) - -Other option is to support [[https://github.com/vspinu/polymode][Polymode]], which uses indirect buffers, which may or -may not be a good solution for ein notebooks (why did I write this - JMM -<2016-10-05 Wed>?). I think this is what nxhtml is doing... - -The problem with Polymode is that it seems to depend on regex's to determine -start and end of chunks and to support this in EIN I would have to make -adjustments to how the buffer is displayed. - -One thought would be to do away with the cell's metaphor and make things more -freeform - more like an org-mode buffer? - -**** Using org-edit-src-code - -Check the [[help:org-edit-src-code][documentation]] and read the [[file:c:/Users/millejoh/emacs25/share/emacs/25.1/lisp/org/org-src.el::(defun%20org-edit-src-code%20(&optional%20context%20code%20edit-buffer-name)][source]]. - -**** Understanding Polymode - -Inner modes are defined as pm-hbtchunkmode objects. Need to specify regex's for -head and tail, but appears that these can be functions of one argument ~(lambda -(ahead) )~. See ~[[file:~/.emacs.d/elpa/polymode-20160805.448/polymode-methods.el::(defun pm--span-at-point (head-matcher tail-matcher &optional pos)][pm--span-at-point]]~. If ahead is -1 search backwords, otherwise -search forwards. Return is (cons BEG END) where BEG and END mark span of head or -tail. - -Default behavior for polymode is to call re-search-forward or -re-search-backward. These functions set point and return position at beginning -of regex. Setting point is not necessary for polymode to work, I think. - -polymode may not work well since it uses indirect buffers. This seems to cause -problems with ein's ewoc data structures. - -**** Understanding [[info:mmm#Top][mmm-mode]] - -Does not appear to use indirect buffers, so may work better. - -*** Support %load ([[https://github.com/millejoh/emacs-ipython-notebook/issues/104][#104]]) - -Support was already there, just needed to get the source name right in the code. - -*** Better debug interface - -Something like what Inferior Python mode [[file:c:/emacs26/share/emacs/26.0.50/lisp/progmodes/python.el.gz::;;;%20PDB%20Track%20integration][implements]]. - -Could we make [[file:emacs-ipython-notebook/lisp/ein-ipdb.el::(define-derived-mode%20ein:ipdb-mode%20comint-mode%20"EIN:IPDB"][ipdb]] buffer mode derive from [[file:c:/emacs26/share/emacs/26.0.50/lisp/progmodes/python.el.gz::(define-derived-mode%20inferior-python-mode%20comint-mode%20"Inferior%20Python"][inferior-python-mode]]? - -*** Support other python and text files -Allow ein to open, edit and save python and other text files. This will likely -involve similar tactics as required for notebook/buffer integration [[*Make notebooks more file-like?][enhancment]]. -*** Integrate with [[http://docs.hylang.org/en/master/index.html][hy]] -Initial support in v0.14! - -We can get read-eval via [[http://docs.hylang.org/en/master/language/interop.html][this]]. Just need to wrap kernel calls with some -appropriate python code? - -Need to have two 'types' of python notebooks, however. Difference between -notebooks will be a flag in the header metadata. That way EIN will know when to -call the right wrapping function. - -Doing autocomplete may also be possible, but will need to figure out how to -mangle and unmangle on the fly. Trick will be dealing with modules, as the -[[http://docs.hylang.org/en/master/language/interop.html#using-python-from-hy][syntax]] in hy is not as simple and EIN will have to do more to determine context. - -Also look into a [[https://github.com/dsblank/simple_kernel][custom kernel]] that implement's hy read-eval-print. - - -Running hy code from python appears to be a two-step process: - -#+BEGIN_SRC python - import hy - import hy.cmdline - - def hy_read_eval(string): - hy.cmdline.hy_eval(hy.read_str(string) -#+END_SRC -*** Fixing Tests -Testing is beyond broken at this point. I barely understand the code, async is -causing far too much instability and travis never works. I think it is time to -completely redo testing, i.e. throw out all the existing code and start anew. - -First is to take advantage of modern testing tools in Emacs -**** Emacs Testing Frameworks - -There is the venerable [[https://www.emacswiki.org/emacs/ErtTestLibrary][ERT]]. - -For working with asyn frameworks: [[https://github.com/rejeep/ert-async.el][ert-async]]. - -Mocking: [[https://github.com/rejeep/el-mock.el][el-mock]]. - -Thens there is [[http://cask.readthedocs.io/en/latest/][Cask]] + [[https://github.com/rejeep/ert-runner.el][ert-runner]]. [[https://github.com/tonini/overseer.el][Overseer]] lets you use ert-runner. from within emacs - -[[https://en.wikipedia.org/wiki/Integration_testing][Integration testing]] using [[https://github.com/ecukes/ecukes][ecukes]]. There is a lot to learn with this one, though. -*** Asynchronous org-babel -As inspiration should look at [[https://github.com/khinsen/ob-ipython-async/blob/master/ob-ipython-async.el][@khinsen's]] implementation -for ob-ipython. - -Implemented in v0.14! - -* Tests - -This is a [[ipynb:(:url-or-port%20"http://localhost:8888"%20:name%20"emacs-ipython-notebook/The%20Emacs%20IPython%20Notebook.ipynb")][link]] to an ein notebook. - -#+BEGIN_SRC elisp :session - (setq str0 "8888/Untitled.ipynb") - (setq str1 "8888/Path/Untitled.ipynb") -#+END_SRC - -#+RESULTS: -: 8888/Path/Untitled.ipynb - -#+BEGIN_SRC elisp :session -(ein:trim-left str0 "\/") -#+END_SRC - -#+RESULTS: -: 8888/Untitled.ipynb - -#+NAME: 29cc91f8-fcad-4afa-9dc7-e2bbb9821870 -#+BEGIN_SRC ein :session http://localhost:8888/Untitled.ipynb - import sys - import time - - time.sleep(10) - print("Hello dood!") - -#+END_SRC - -#+RESULTS: 29cc91f8-fcad-4afa-9dc7-e2bbb9821870 -: Hello dood! - -#+NAME: 87f665e5-0314-4491-9666-edf15604aa21 -#+BEGIN_SRC ein :session http://localhost:8888/Untitled.ipynb - 1+4 -#+END_SRC - -#+RESULTS: 87f665e5-0314-4491-9666-edf15604aa21 -: 5 - -#+NAME: d934f2ea-e2fe-4a8f-9db0-c0496dbfc013 -#+BEGIN_SRC ein :session http://localhost:8888/Untitled.ipynb :results output drawer - 1/0 -#+END_SRC - -#+RESULTS: d934f2ea-e2fe-4a8f-9db0-c0496dbfc013 -:RESULTS: ---------------------------------------------------------------------------- -ZeroDivisionError Traceback (most recent call last) - in () -----> 1 1/0 - -ZeroDivisionError: division by zero - -:END: - -#+NAME: 26e1891a-abaf-4a6b-831e-59d73fcf5170 -#+BEGIN_SRC ein :session http://localhost:8888/Untitled.ipynb :results output drawer - import matplotlib.pyplot as plt - import numpy as np - - %matplotlib inline - x = np.linspace(0, 1, 100) - y = np.random.rand(100,1) - plt.plot(x,y) - x - -#+END_SRC - - -#+NAME: 36a8b735-8e7d-4503-addc-57165c651d7d -#+BEGIN_SRC ein :session http://localhost:8888/Untitled.ipynb :results output - from sympy import * - - init_printing() - x = symbols('x') - x - -#+END_SRC diff --git a/Makefile b/Makefile index bab2782..33c84d7 100644 --- a/Makefile +++ b/Makefile @@ -69,9 +69,9 @@ test-jupyterhub: test-compile -cask exec ecukes --tags @jupyterhub --reporter magnars .PHONY: test -test: quick test-int test-poly +test: quick test-int -.PHONY: test-poly +.PHONY: test-unpoly test-poly: cask exec ert-runner -L ./lisp -L ./test -l test/testfunc.el test/test-poly.el test/test-func.el cp test/test-poly.el features/support/test-poly.el @@ -79,12 +79,12 @@ test-poly: .PHONY: test-int test-int: - cask exec ert-runner -L ./lisp -L ./test -l test/testfunc.el test/test-func.el cask exec ecukes --reporter magnars .PHONY: test-unit test-unit: cask exec ert-runner -L ./lisp -L ./test -l test/testein.el test/test-ein*.el + cask exec ert-runner -L ./lisp -L ./test test/test-uncompiled.el .PHONY: test-ob-ein-recurse test-ob-ein-recurse: diff --git a/README.in.rst b/README.in.rst index fd44d03..353a05b 100644 --- a/README.in.rst +++ b/README.in.rst @@ -62,7 +62,6 @@ Notebook server ``M-x ein:log-pop-to-request-buffer``. Kernel messaging (must be run from notebook buffer) ``M-x ein:dev-pop-to-debug-channels``. .. _spacemacs layer: https://github.com/syl20bnr/spacemacs/tree/master/layers/%2Blang/ipython-notebook -.. _auto-complete: https://github.com/auto-complete/auto-complete .. _company-mode: https://github.com/company-mode/company-mode .. _jupyterhub: https://github.com/jupyterhub/jupyterhub diff --git a/README.rst b/README.rst index 5526542..1de59ba 100644 --- a/README.rst +++ b/README.rst @@ -121,7 +121,7 @@ Keymap (C-h m) key binding --- ------- - + C-c Prefix Command C-x Prefix Command ESC Prefix Command @@ -131,16 +131,16 @@ Keymap (C-h m) ein:worksheet-execute-cell-and-insert-below ein:worksheet-move-cell-down ein:worksheet-move-cell-up - + C-x C-s ein:notebook-save-notebook-command C-x C-w ein:notebook-rename-command - + M-RET ein:worksheet-execute-cell-and-goto-next M-, ein:pytools-jump-back-command M-. ein:pytools-jump-to-source-command M-n ein:worksheet-next-input-history M-p ein:worksheet-previous-input-history - + C-c C-a ein:worksheet-insert-cell-above C-c C-b ein:worksheet-insert-cell-below C-c C-c ein:worksheet-execute-cell @@ -166,7 +166,6 @@ Keymap (C-h m) C-c C-z ein:notebook-kernel-interrupt-command C-c ESC Prefix Command C-c ! ein:worksheet-rename-sheet - C-c ' ein:edit-cell-contents C-c + ein:notebook-worksheet-insert-next C-c - ein:notebook-worksheet-delete C-c 1 ein:notebook-worksheet-open-1th @@ -179,7 +178,6 @@ Keymap (C-h m) C-c 8 ein:notebook-worksheet-open-8th C-c 9 ein:notebook-worksheet-open-last C-c S ein:worksheet-toggle-slide-type - C-c i ein:inspect-object C-c { ein:notebook-worksheet-open-prev-or-last C-c } ein:notebook-worksheet-open-next-or-first C-c C-S-l ein:worksheet-clear-all-output @@ -192,10 +190,10 @@ Keymap (C-h m) C-c C-; ein:shared-output-show-code-cell-at-point C-c ein:worksheet-move-cell-down C-c ein:worksheet-move-cell-up - + C-c C-x C-l ein:notebook-toggle-latex-fragment C-c C-x C-r ein:notebook-restart-session-command - + C-c M-+ ein:notebook-worksheet-insert-prev C-c M-w ein:worksheet-copy-cell C-c M-{ ein:notebook-worksheet-move-prev diff --git a/The Emacs IPython Notebook.ipynb b/The Emacs IPython Notebook.ipynb deleted file mode 100644 index bc53c3d..0000000 --- a/The Emacs IPython Notebook.ipynb +++ /dev/null @@ -1,1193 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# The Emacs IPython Notebook\n", - "### JupyterCon 2018\n", - "\n", - "John Miller ([email](millejoh@mac.com) / [github](https://github.com/millejoh/) / [linkedin](www.linkedin.com/in/john-miller-3720a811\n", - ")) ![The Mascot](_images/ein_logo.jpg)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# The Plan" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Thanks\n", - "- About me\n", - "- Introducing EIN\n", - "- About Emacs\n", - "- A Short History\n", - "- Feature dive\n", - "- What's next\n", - "- Demo?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Disclaimer" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- This work is not sponsored by my employer (Honeywell UOP)\n", - "- I am not representing my employer (today)\n", - "- UOP does some cools things, find me later if you want to learn more!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Thanks!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "- Takafumi Arakami ([@tkf](https://github.com/tkf))\n", - "\n", - " - EIN does not exist without tkf" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "- Fernando and the rest at Jupyter\n", - "- O'Reilly - Andre Morrow in particular!\n", - "- D.E. Shaw - supporting some work back in 2016-2017.\n", - "- My kind, patient crew of Github ein [stargazers](https://github.com/millejoh/emacs-ipython-notebook/stargazers) (all 660 of you!)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "# About John" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- 1997: BS Chemical Engineering / Computer Science from CSU\n", - "- Since then: [Honeywell UOP](https://www.uop.com)\n", - "- Emacser since college (??)\n", - "- Irregular Pythoner since 1998 (Zope to Pandas!)\n", - "- EIN Maintainer since 2014/2015-ish (commit [20a7250](https://github.com/millejoh/emacs-ipython-notebook/commit/20a725012b6c8ffe9173fcfc8808dfb46fbb1824))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Introducing EIN" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- A full-featured client for the Jupyter Notebook in the venerable Emacs editor\n", - "- Tries to be a bit like [SLIME](https://common-lisp.net/project/slime/)\n", - "- Work on emacs 24.5+ (but 25+ is best)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "## Features\n", - " - Written almost completely in elisp!\n", - " - IDE features (syntax highlighting, jump to source, auto-completeion, popup help, help browser, etc.)\n", - " - Integration with pdb via comint\n", - " - Integration with [org-mode](https://orgmode.org/)\n", - " - Works with non-python kernels!\n", - " - Connect python buffers to running kernels." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# About Emacs" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "The programmable programming editor.\n", - "40 years of history.\n", - "![real programmers](real_programmers.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "## Why do I use Emacs?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "![Crazy emacs](_images/emacs.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "- Lisp Machine's scrapier cousin from the wrong side of town\n", - "- See Josh Stella's excellent blog posts ([#1](https://blog.fugue.co/2015-11-11-guide-to-emacs.html) and [#2](https://blog.fugue.co/2018-08-09-two-years-with-emacs-as-a-cto.html))\n", - "- Focus without distraction\n", - "- Not a black box with a shiny interface\n", - "- Almost complete control over your editing environment\n", - "- It's a tool building tool" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "# The Great Editor/IDE Wars" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "Let's not, actually. Brothers and sisters, read [More than Words](http://www.nhplace.com/kent/PS/Lambda.html).\n", - "\n", - "> In essence, I'll suggest that Lisp is a social phenomenon, akin to a\n", - "> political party, and that what unifies Lisp are the people who are its\n", - "> leaders, and the ways in which they respond (or fail to respond) to the needs\n", - "> of that community. --- Kent Pitman" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "notes" - } - }, - "source": [ - "More than one political party is good! Diverse ideas are good! Extremism - not\n", - "so good.\n", - "\n", - "The secret to peace - holding opposing thoughts in our heads?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# A Brief History of EIN" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "fragment" - } - }, - "source": [ - "![Timeline](_images/Timeline.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "- Created by [tkf](https://github.com/tkf) in 2012\n", - "- First alternate client for IPython\n", - "- tkf's last commit is on 17 Mar 2014 (1,795 commits later!)\n", - "- I fork and push IPython 2.0 support on 14 April 2014\n", - "- Supporting transition from IPython/Jupyter 1.0 -> 4.0 rough sailing!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "# The Challenges" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Changes to the Contents API\n", - "- Changes to communication protocol\n", - "- Changes to the security model (I hate you _xsrf)\n", - "- Changes to the notebook format\n", - "- Debugging connection issues for other users\n", - "- Legacy support (Emacs 24 vs 25, 26, 27...)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "- Why?\n", - " - John is agoraphobic outside of Emacs\n", - " - John is allergic to javascript\n", - " - EIN’s internal data structures tuned to earlier versions of notebook format\n", - " - Behold the eldritch horrors of `ein:cell-to-nb4-json`\n", - " - Every Emacs installation is different (advantage and disadvantage!)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "# The Joys" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- People (not just me) use it to do stuff!\n", - "- Supportive community.\n", - "- Solving the challenges.\n", - "- I get to program in Lisp!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# Feature Dive" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "## What is similar" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Visually alike, but more text-y\n", - "- Cut, copy, past cells (even across notebooks!)\n", - "- Inline images\n", - "- Works with non-python kernels" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "## IDE-like Features" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Auto-completion\n", - "- Jump to definition (local only!)\n", - "- Popup (tooltip) help\n", - "- Syntax highlighting (not perfect)\n", - "- Help browser\n", - "- Traceback view\n", - "- Integration with ipdb" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "## Unique to Emacs?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Run jupyter from inside Emacs!\n", - "- Execute elisp from IPython\n", - "- Integration with org-mode\n", - "- Support for [hy](http://hylang.org)\n", - "- Connect python buffer to a running notebook\n", - "- Customizable using elisp (vs javascript)\n", - "- %whos popup (`ein:pytools-whos`)\n", - "- Run doctests for object at point" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "## Needing some TLC" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Pandas to [SES](http://www.gnu.org/software/emacs/manual/html_node/ses/index.html)\n", - "- Hierarchymagic (depends on [Hierarchymagic_ext](https://github.com/tkf/ipython-hierarchymagic))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "subslide" - } - }, - "source": [ - "## What EIN does not do" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Widgets\n", - "- Extensions\n", - " - Emacs doesn't quite understand javascript.\n", - " - Possible with some effort (see [timestamp](https://github.com/millejoh/emacs-ipython-notebook/blob/master/lisp/ein-timestamp.el))\n", - " - [Skewer](https://github.com/skeeto/skewer-mode) package allows limited execution of javascript\n", - "- Jupyterhub support exists, but is wonky" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# What's Next for EIN?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "- Don't fall behind (easier said than done)\n", - "- More robust!\n", - "- Better integration with external documentation\n", - "- Seamless support for remote Jupyterhub and remote connections\n", - "- Support widgets (this is going to be tough!)\n", - "- Better integration with the Emacs Python ecosystem\n", - "- A full inspector (ala SLIME)\n", - "- And much (too much!) more...\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "# A Demonstration" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%pwd" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "import sys\n", - "# Watch me autocomplete and show an informative popup!\n", - "# Try this before executing import sys with `ein:completion-backend`\n", - "# set to `ein:use-ac-jedi-backend`. Eat your heart out Joel Grus and\n", - "# JupyterLab!\n", - "sys" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "print(\"Hello World!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "## Behold the glory of Python and Emacs!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "### Syntax highlighting and inline images." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "# Open via C-c ' and check out flycheck support\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "source": [ - "plt." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "def plotnormal():\n", - " return plt.plot(np.random.randn(1000), np.random.randn(1000), 'o', alpha=0.3)\n", - "plotnormal()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "### The help browser and jump to source" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "plt.plot?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "### EIN combines python and ipython error handling with Emacs debugger support." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%run non_existent_file" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "x = 1\n", - "y = 4\n", - "z = y / (1 - x)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%run wiener_filtering.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%debug" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "### What about org files" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "Take a looksy at [this](./org_demo.org)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "### What was that about Hy?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "skip" - } - }, - "source": [ - "Note - due to a bug in ein hy cell types are not saved between sessions, so you\n", - "will need to manually set the cell type of the following two cells to Hy by\n", - "calling `ein:worksheet-change-cell-type` then typing `h`" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "2" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "(+ 1 1)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "(setv hy-var 42)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "hy_var" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "### What about Emacs Lisp?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%run tools/emacslisp.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "res = EmacsLisp('(ein:dev-sys-info)')\n", - "res" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "type(res)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "dir(res)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "### We Support Magic!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "%load tools/emacslisp.py" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "## Check out test.py" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "digits" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "ein.tags": "worksheet-0", - "slideshow": { - "slide_type": "-" - } - }, - "source": [ - "# Don't look at me!" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-10-15T02:00:45.633797Z", - "2018-10-15T02:00:46.999049Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "sns.set(context='talk')\n", - "plt.rcParams[\"figure.dpi\"] = 144\n", - "plt.rcParams[\"figure.figsize\"] = 16, 10" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "autoscroll": false, - "collapsed": false, - "ein.hycell": false, - "ein.tags": "worksheet-0", - "execute-time": [ - "2018-10-15T03:20:48.024857Z", - "2018-10-15T03:20:48.040723Z" - ], - "slideshow": { - "slide_type": "-" - } - }, - "outputs": [], - "source": [ - "digits" - ] - } - ], - "metadata": { - "celltoolbar": "Slideshow", - "kernelspec": { - "display_name": "Data Science (py36)", - "name": "datascience" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.6" - }, - "name": "The Emacs IPython Notebook.ipynb", - "rise": { - "controls": false, - "theme": "serif" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/_images/ein_logo.jpg b/_images/ein_logo.jpg deleted file mode 100644 index afa349186ad43d3d35d28f7a041cbafc79ea886e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14523 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 Xc{Y7#@j4CH8I>dap^Js{X7+yo9kB#a diff --git a/doc/source/index.rst b/doc/source/index.rst index 69689ad..163402e 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -100,9 +100,6 @@ Requirements * `request-deferred.el`_ >= 0.2 * `dash`_ >= 2.13 * `s`_ >= 1.11 -* `auto-complete.el`_ >= 1.4: - You need to configure subpackage ``ein-ac`` to enable - this feature. * `skewer-mode`_ >= 1.6.2: Skewer mode gives EIN the ability to execute dynamic javascript in the note book. diff --git a/features/connect.feature b/features/connect.feature index efc37fc..6d4d456 100644 --- a/features/connect.feature +++ b/features/connect.feature @@ -1,29 +1,3 @@ -@connect -Scenario: Company completion in a python buffer - Given I set "ein:completion-backend" to eval "(quote ein:use-company-backend)" - Given I kill all websocket buffers - Given new python notebook - When I open temp file "connect.py" - And I switch to buffer like "connect.py" - And I call "python-mode" - And I connect to default notebook - And I type "import itertools" - And I press "RET" - And I call "ein:connect-run-buffer" - And I type "itertools." - And I call "company-complete" - And I wait for completions "itertools.chain" - And I press "C-a" - And I press "C-k" - And I clear websocket log - And I type "itertool" - And I call "company-complete" - Then I should see "itertools" - And I type ".chai" - And I call "company-complete" - Then I should see "itertools.chain" - Then no completion traffic - @connect Scenario: Test shared eval Given new python notebook diff --git a/features/notebook.feature b/features/notebook.feature index 6a1189a..caaf134 100644 --- a/features/notebook.feature +++ b/features/notebook.feature @@ -1,58 +1,3 @@ -@eldoc -Scenario: remote eldoc (largely unused) - Given I enable "ein:enable-eldoc-support" - Given I clear log expr "ein:log-all-buffer-name" - Given new python notebook - And I type "import math" - And I press "C-a" - And I call eldoc-documentation-function - And I switch to log expr "ein:log-all-buffer-name" - Then I should not see "ein:completions--prepare-oinfo" - -@complete -Scenario: auto completion - Given I set "ein:ac-direct-matches" to eval "nil" - Given I set "ein:completion-backend" to eval "(quote ein:use-ac-backend)" - Given new python notebook - And I type "import itertool" - And I press "C-c C-i" - And I wait for the smoke to clear - Then "ein:ac-direct-matches" should include "itertools" - -@complete -Scenario: no auto completion - Given I set "ein:ac-direct-matches" to eval "nil" - Given I set "ein:completion-backend" to eval "(quote ein:use-none-backend)" - Given new python notebook - And I type "import itertool" - And I press "C-c C-i" - And I wait for the smoke to clear - Then "ein:ac-direct-matches" should not include "itertools" - -@complete -Scenario: company completion - Given I set "ein:completion-backend" to eval "(quote ein:use-company-backend)" - Given I kill all websocket buffers - Given new python notebook - And I type "import itertools" - And I press "M-RET" - And I type "itertools." - And I call "company-complete" - And I wait for completions "itertools.chain" - And I press "C-a" - And I press "C-k" - And I clear websocket log - And I type "itertool" - And I call "company-complete" - Then I should see "itertools" - And I type ".chai" - And I call "company-complete" - Then I should see "itertools.chain" - Then no completion traffic - Given I set "ein:completion-backend" to eval "(quote ein:use-ac-backend)" - Given new python notebook - Given I set "ein:completion-backend" to eval "(quote ein:use-none-backend)" - @rename Scenario: rename notebook Given new python notebook diff --git a/features/support/env.el b/features/support/env.el index 682528a..c3a412a 100644 --- a/features/support/env.el +++ b/features/support/env.el @@ -3,9 +3,10 @@ (require 'espuds) (require 'ert) (require 'undo-tree) - -(with-eval-after-load "python" - (setq python-indent-guess-indent-offset-verbose nil)) +(require 'python) +(require 'julia-mode) +(require 'ess-r-mode) +(require 'markdown-mode) (let* ((support-path (f-dirname load-file-name)) (root-path (f-parent (f-parent support-path)))) @@ -73,7 +74,8 @@ (Setup (ein:dev-start-debug) (cl-assert (boundp 'company-frontends)) - (custom-set-variables '(company-frontends nil)) + (custom-set-variables '(company-frontends nil) + '(python-indent-guess-indent-offset-verbose nil)) (setq ein:jupyter-default-kernel (loop with cand = "" for (k . spec) in @@ -90,8 +92,6 @@ do (setq cand (symbol-name k)) end finally return (intern cand))) - (setq ein:notebook-autosave-frequency 0) - (setq ein:notebook-create-checkpoint-on-save nil) (setq ein:testing-dump-file-log (concat default-directory "log/ecukes.log")) (setq ein:testing-dump-file-messages (concat default-directory "log/ecukes.messages")) (setq ein:testing-dump-file-server (concat default-directory "log/ecukes.server")) diff --git a/features/undo.feature b/features/undo.feature index f98a400..62769f1 100644 --- a/features/undo.feature +++ b/features/undo.feature @@ -23,7 +23,7 @@ Scenario: Kill yank doesn't break undo And I press "C-" And I press "C-c C-y" And I press "C-/" - Then the cursor should be at point "74" + Then the cursor should be at point "75" @undo Scenario: Collapse doesn't break undo @@ -52,7 +52,7 @@ Scenario: Collapse doesn't break undo And I dump buffer Then the cursor should be at point "77" And I undo again - Then the cursor should be at point "55" + Then the cursor should be at point "53" @undo Scenario: Test the conflagrative commands @@ -108,7 +108,7 @@ Scenario: Clear output doesn't break undo And I press "C-/" Then the cursor should be at point "74" And I undo again - Then the cursor should be at point "55" + Then the cursor should be at point "53" @undo Scenario: Moving cells doesn't break undo @@ -221,7 +221,7 @@ Scenario: Undo needs to at least work for reopened notebooks And I undo again And I undo again And I undo again - Then the cursor should be at point "125" + Then the cursor should be at point "124" @undo Scenario: Toggling between markdown and codecell does not break undo @@ -291,7 +291,7 @@ Scenario: Undo (kind of) needs to work when someone explicitly requires ein-time And I undo again And I undo again And I undo again - Then the cursor should be at point "125" + Then the cursor should be at point "124" @timestamp Scenario: Kill yank doesn't break undo diff --git a/features/undo.ipynb b/features/undo.ipynb index d16579a..e884c0d 100644 --- a/features/undo.ipynb +++ b/features/undo.ipynb @@ -95,6 +95,21 @@ } ], "metadata": { + "kernelspec": { + "argv": [ + "python", + "-m", + "ipykernel_launcher", + "-f", + "{connection_file}" + ], + "display_name": "Python 3", + "env": null, + "interrupt_mode": "signal", + "language": "python", + "metadata": null, + "name": "python3" + }, "name": "undo.ipynb" }, "nbformat": 4, diff --git a/lisp/ein-ac.el b/lisp/ein-ac.el deleted file mode 100644 index 6b62c5b..0000000 --- a/lisp/ein-ac.el +++ /dev/null @@ -1,253 +0,0 @@ -;;; ein-ac.el --- Auto-complete extension - -;; Copyright (C) 2012- Takafumi Arakaki - -;; Author: Takafumi Arakaki - -;; This file is NOT part of GNU Emacs. - -;; ein-ac.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-ac.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-ac.el. If not, see . - -;;; Commentary: - -;; - -;;; Code: - -(eval-when-compile (require 'cl)) -(require 'auto-complete) - -(require 'ein-core) -(eval-when-compile (require 'ein-notebook) - (defvar ein:mumamo-codecell-mode)) - - -;;; Configuration -(defcustom ein:use-auto-complete-superpack nil - "Set to `t' to use preset a little bit hacky auto-complete configuration. -When this option is enabled, cached omni completion is available." - :type 'boolean - :group 'ein) - -(defvar ein:ac-sources (and (boundp 'ac-sources) - (default-value 'ac-sources)) - "Extra `ac-sources' used in notebook.") - - -;;; Chunk (adapted from auto-complete-chunk.el) - -(defvar ein:ac-chunk-regex - (rx (group (| (syntax whitespace) - (syntax open-parenthesis) - (syntax close-parenthesis) - (syntax string-quote) ; Complete files for `open("path/..` - bol)) - (? (syntax punctuation)) ; to complete ``~/PATH/...`` - (* (+ (| (syntax word) (syntax symbol))) - (syntax punctuation)) - (+ (| (syntax word) (syntax symbol))) - (? (syntax punctuation)) - point) - "A regexp that matches to a \"chunk\" containing words and dots.") - -(defun ein:ac-chunk-beginning () - "Return the position where the chunk begins." - (ignore-errors - (save-excursion - (+ (re-search-backward ein:ac-chunk-regex) (length (match-string 1)))))) - -(defun ein:ac-chunk-candidates-from-list (chunk-list) - "Return matched candidates in CHUNK-LIST." - (let* ((start (ein:ac-chunk-beginning))) - (when start - (loop with prefix = (buffer-substring start (point)) - for cc in chunk-list - when (string-prefix-p prefix cc) - collect cc)))) - - -;;; AC Source - -(defvar ein:ac-direct-matches nil - "Variable to store completion candidates for `auto-completion'.") -;; FIXME: Maybe this should be buffer-local? - -(defun ein:ac-direct-get-matches () - (ein:ac-chunk-candidates-from-list ein:ac-direct-matches)) - -(ac-define-source ein-direct - '((candidates . ein:ac-direct-get-matches) - (requires . 0) - (prefix . ein:ac-chunk-beginning) - (symbol . "s"))) - -(ac-define-source ein-async - '((candidates . ein:ac-direct-get-matches) - (requires . 0) - (prefix . ein:ac-chunk-beginning) - (init . ein:ac-request-in-background) - (symbol . "c"))) - -(define-obsolete-function-alias 'ac-complete-ein-cached 'ac-complete-ein-async - "0.2.1") -(define-obsolete-variable-alias 'ac-source-ein-cached 'ac-source-ein-async - "0.2.1") - -(defun ein:ac-request-in-background () - (cl-ecase ein:completion-backend - (ein:use-ac-backend (ein:aif (ein:get-kernel) - (ein:completer-complete - it - (list :complete_reply - (cons (lambda (_ content __) - (ein:ac-prepare-completion (plist-get content :matches))) - nil)) - #'ignore))))) - - -;;; Completer interface - -(defun ein:ac-dot-complete (callback) - "Insert a dot and request completion via CALLBACK of 0-arity" - (interactive (list (lambda () (call-interactively #'ein:completer-complete)))) - (insert ".") - (if (not (ac-cursor-on-diable-face-p)) - (funcall callback))) - -(defun ein:ac-prepare-completion (matches) - "Prepare `ac-source-ein-direct' using MATCHES from kernel. -Call this function before calling `auto-complete'." - (when matches - (setq ein:ac-direct-matches matches))) ; let-binding won't work - -(defun* ein:completer-finish-completing-ac - (matched-text - matches - &key (expand ac-expand-on-auto-complete) - &allow-other-keys) - "Invoke completion using `auto-complete'. -Only the argument MATCHES is used. MATCHED-TEXT is for -compatibility with `ein:completer-finish-completing-default'." - ;; I don't need to check if the point is at right position, as in - ;; `ein:completer-finish-completing-default' because `auto-complete' - ;; checks it anyway. - - (ein:log 'debug "COMPLETER-FINISH-COMPLETING-AC: matched-text=%S matches=%S" - matched-text matches) - (ein:ac-prepare-completion matches) - (when matches ; No auto-complete drop-down list when no matches - (let ((ac-expand-on-auto-complete expand)) - (ac-start)))) - - -;;; Async document request hack - -(defun ein:ac-request-document-for-selected-candidate () - "Request object information for the candidate at point. -This is called via `ac-next'/`ac-previous'/`ac-update' and set -`document' property of the current candidate string. If server -replied within `ac-quick-help-delay' seconds, auto-complete will -popup help string." - (ein:aif (ein:get-kernel) - (let* ((candidate (ac-selected-candidate)) - (kernel it) - (api-version (ein:$kernel-api-version kernel)) - (callbacks (list (if (< api-version 3) - :object_info_reply - :inspect_request) - (cons #'ein:ac-set-document candidate)))) - (when (and candidate - (ein:kernel-live-p kernel) - (not (get-text-property 0 'document candidate))) - (ein:log 'debug "Requesting object info for AC candidate %S" - candidate) - (ein:kernel-object-info-request kernel candidate callbacks))))) - -(defun ein:ac-set-document (candidate content -metadata-not-used-) - (ein:log 'debug "EIN:AC-SET-DOCUMENT candidate=%S content=%S" - candidate content) - (put-text-property 0 (length candidate) - 'document (ein:kernel-construct-help-string content) - candidate)) - -(defadvice ac-next (after ein:ac-next-request) - "Monkey patch `auto-complete' internal function to request -help documentation asynchronously." - (ein:ac-request-document-for-selected-candidate)) - -(defadvice ac-previous (after ein:ac-previous-request) - "Monkey patch `auto-complete' internal function to request -help documentation asynchronously." - (ein:ac-request-document-for-selected-candidate)) - -(defadvice ac-update (after ein:ac-update-request) - "Monkey patch `auto-complete' internal function to request help -documentation asynchronously. This will request info for the -first candidate when the `ac-menu' pops up." - (ein:ac-request-document-for-selected-candidate)) - - -;;; Setup - -(defun ein:ac-superpack () - "Enable richer auto-completion. - -* Enable auto-completion help by monkey patching `ac-next'/`ac-previous'" - (interactive) - (ad-enable-advice 'ac-next 'after 'ein:ac-next-request) - (ad-enable-advice 'ac-previous 'after 'ein:ac-previous-request) - (ad-enable-advice 'ac-update 'after 'ein:ac-update-request) - (ad-activate 'ac-next) - (ad-activate 'ac-previous) - (ad-activate 'ac-update)) - -(defun ein:ac-setup () - "Call this function from mode hook (see `ein:ac-config')." - (setq ac-sources (append '(ac-source-ein-async) ein:ac-sources))) - -(defun ein:ac-setup-maybe () - "Setup `ac-sources' for mumamo. - -.. note:: Setting `ein:notebook-mumamo-mode-hook' does not work - because `ac-sources' in `ein:notebook-mumamo-mode'-enabled - buffer is *chunk local*, rather than buffer local. - - Making `ac-sources' permanent-local also addresses issue of - MuMaMo discarding `ac-sources'. However, it effects to entire - Emacs setting. So this is not the right way to do it. - - Using `mumamo-make-variable-buffer-permanent' (i.e., adding - `ac-sources' to `mumamo-per-buffer-local-vars' or - `mumamo-per-main-major-local-vars') is also not appropriate. - Adding `ac-sources' to them makes it impossible to different - `ac-sources' between chunks, which is good for EIN but may not - for other package." - (and (ein:eval-if-bound 'ein:notebook-mode) - (ein:eval-if-bound 'ein:notebook-mumamo-mode) - (eql major-mode ein:mumamo-codecell-mode) - (ein:ac-setup))) - -(defun ein:ac-config (&optional superpack) - "Install auto-complete-mode for notebook modes. -Specifying non-`nil' to SUPERPACK enables richer auto-completion -\(see `ein:ac-superpack')." - (add-hook 'after-change-major-mode-hook 'ein:ac-setup-maybe) - (add-hook 'ein:notebook-mode-hook 'ein:ac-setup) - (when superpack - (ein:ac-superpack))) - -(ein:ac-config ein:use-auto-complete-superpack) -(provide 'ein-ac) - -;;; ein-ac.el ends here diff --git a/lisp/ein-cell-edit.el b/lisp/ein-cell-edit.el deleted file mode 100644 index edf2340..0000000 --- a/lisp/ein-cell-edit.el +++ /dev/null @@ -1,273 +0,0 @@ -;;; ein-cell-edit.el --- Notebook cell editing - -;; Copyright (C) 2016 John M. Miller - -;; Author: John Miller - -;; This file is NOT part of GNU Emacs. - -;; ein-cell-edit.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-cell-edit.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-worksheet.el. If not, see . - -;;; Commentary: - -;; This code inspired by borrowing from org-src.el. - -;;; Code: -(require 'ein-cell) - -(autoload 'julia-mode "julia-mode") -(autoload 'markdown-mode "markdown-mode") -(autoload 'R-mode "ess-r-mode") -(autoload 'org-src--remove-overlay "org-src") -(autoload 'org-src-switch-to-buffer "org-src") - -(defvar ein:src--cell nil) -(defvar ein:src--ws nil) -(defvar ein:src--allow-write-back t) -(defvar ein:src--overlay nil) -(defvar ein:src--saved-window-config nil) - -(defvar ein:edit-cell-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "\C-c'" 'ein:edit-cell-exit) - (define-key map "\C-c\C-k" 'ein:edit-cell-abort) - (define-key map "\C-c\C-c" 'ein:edit-cell-save-and-execute) - (define-key map "\C-x\C-s" 'ein:edit-cell-save) - (define-key map "\C-c\C-x" 'ein:edit-cell-view-traceback) - map)) - -(define-minor-mode ein:edit-cell-mode - "Minor mode for language major mode buffers generated by EIN. -This minor mode is turned on when editing a source code snippet with \\[ein:edit-cell-contents] - -\\{ein:edit-cell-mode-map} - -." - nil " EinCell" nil - (set (make-local-variable 'header-line-format) - (substitute-command-keys - "Edit, execute with \\[ein:edit-cell-execute] then exit with \\[ein:edit-cell-exit] \ -or abort with \\[ein:edit-cell-abort]")) - ;; Possibly activate various auto-save features (for the edit buffer - ;; or the source buffer). - ;; (when org-edit-src-turn-on-auto-save - ;; (setq buffer-auto-save-file-name - ;; (concat (make-temp-name "org-src-") - ;; (format-time-string "-%Y-%d-%m") - ;; ".txt"))) - ;; (unless (or org-src--auto-save-timer (zerop org-edit-src-auto-save-idle-delay)) - ;; (setq org-src--auto-save-timer - ;; (run-with-idle-timer - ;; org-edit-src-auto-save-idle-delay t - ;; (lambda () - ;; (save-excursion - ;; (let (edit-flag) - ;; (dolist (b (buffer-list)) - ;; (with-current-buffer b - ;; (when (org-src-edit-buffer-p) - ;; (unless edit-flag (setq edit-flag t)) - ;; (when (buffer-modified-p) (org-edit-src-save))))) - ;; (unless edit-flag - ;; (cancel-timer org-src--auto-save-timer) - ;; (setq org-src--auto-save-timer nil)))))))) - ) - -(defun ein:cell-configure-edit-buffer () - (when (and (bound-and-true-p org-src--from-org-mode) (boundp 'org-src--beg-marker)) - (add-hook 'kill-buffer-hook #'org-src--remove-overlay nil 'local) - (if (bound-and-true-p org-src--allow-write-back) - (progn - (setq buffer-offer-save t) - (setq buffer-file-name - (concat (buffer-file-name (marker-buffer org-src--beg-marker)) - "[" (buffer-name) "]")) - (setq write-contents-functions '(ein:edit-cell-save))) - (setq buffer-read-only t)))) - -(defun ein:edit-cell-view-traceback () - "Jump to traceback, if there is one, for current edit." - (interactive) - (let ((buf (current-buffer)) - (cell ein:src--cell)) - (with-current-buffer (ein:worksheet--get-buffer ein:src--ws) - (ein:cell-goto cell) - (ein:tb-show)))) - -(defun ein:edit-cell-save-and-execute () - "Save, then execute the countents of the EIN source edit buffer -and place results (if any) in output of original notebook cell." - (interactive) - (ein:edit-cell-save) - (when (and (slot-exists-p ein:src--cell 'kernel) - (slot-boundp ein:src--cell 'kernel)) - (ein:cell-execute-internal ein:src--cell - (slot-value ein:src--cell 'kernel) - (buffer-string) - :silent nil))) - -(defun ein:edit-cell-save () - "Save contents of EIN source edit buffer back to original notebook -cell." - (interactive) - (set-buffer-modified-p nil) - (let* ((edited-code (buffer-string)) - (cell ein:src--cell) - (overlay ein:src--overlay) - (read-only (overlay-get overlay 'modification-hooks))) - (overlay-put overlay 'modification-hooks nil) - (overlay-put overlay 'insert-in-front-hooks nil) - (overlay-put overlay 'insert-behind-hooks nil) - (with-current-buffer (ein:worksheet--get-buffer ein:src--ws) - (ein:cell-set-text cell edited-code)) - ;;(setf (slot-value ein:src--cell 'input) edited-code) - (overlay-put overlay 'modification-hooks read-only) - (overlay-put overlay 'insert-in-front-hooks read-only) - (overlay-put overlay 'insert-behind-hooks read-only))) - - -(defun ein:edit-cell-exit () - "Close the EIN source edit buffer, saving contents back to the -original notebook cell, unless being called via -`ein:edit-cell-abort'." - (interactive) - (let ((edit-buffer (current-buffer)) - (ws ein:src--ws) - (cell ein:src--cell)) - (ein:remove-overlay) - (when ein:src--allow-write-back - (ein:edit-cell-save)) - (kill-buffer edit-buffer) - (switch-to-buffer-other-window (ein:worksheet--get-buffer ws)) - (ein:cell-goto cell) - (when ein:src--saved-window-config - (set-window-configuration ein:src--saved-window-config) - (setq ein:src--saved-window-config nil)))) - -(defun ein:edit-cell-abort () - "Abort editing the current cell, contents will revert to -previous value." - (interactive) - (let (ein:src--allow-write-back) (ein:edit-cell-exit))) - -(defun ein:construct-cell-edit-buffer-name (bufname cid cell-type) - (concat "*EIN Src " bufname "[ " cid "/" cell-type " ]*" )) - -(defun ein:get-mode-for-kernel (kernelspec) - (if (null kernelspec) - 'python ;; FIXME - (ein:case-equal (ein:$kernelspec-language kernelspec) - (("julia" "python" "R") (intern (ein:$kernelspec-language kernelspec))) - (t 'python)))) - -(defun ein:edit-src-continue (e) - (interactive "e") - (mouse-set-point e) - (let ((buf (get-char-property (point) 'edit-buffer))) - (if buf (org-src-switch-to-buffer buf 'continue) - (user-error "No sub-editing buffer for area at point")))) - -(defun ein:make-source-overlay (beg end edit-buffer) - "Create overlay between BEG and END positions and return it. -EDIT-BUFFER is the buffer currently editing area between BEG and -END." - (let ((overlay (make-overlay beg end))) - (overlay-put overlay 'face 'secondary-selection) - (overlay-put overlay 'edit-buffer edit-buffer) - (overlay-put overlay 'help-echo - "Click with mouse-1 to switch to buffer editing this segment") - (overlay-put overlay 'face 'secondary-selection) - (overlay-put overlay 'keymap - (let ((map (make-sparse-keymap))) - (define-key map [mouse-1] 'ein:edit-src-continue) - map)) - (let ((read-only - (list - (lambda (&rest _) - (user-error - "Cannot modify an area being edited in a dedicated buffer"))))) - (overlay-put overlay 'modification-hooks read-only) - (overlay-put overlay 'insert-in-front-hooks read-only) - (overlay-put overlay 'insert-behind-hooks read-only)) - overlay)) - -(defun ein:remove-overlay () - "Remove overlay from current source buffer." - (when (overlayp ein:src--overlay) (delete-overlay ein:src--overlay))) - -(defcustom ein:raw-cell-default-edit-mode 'LaTeX-mode - "The major mode to use when editing a cell of type 'Raw' in the - dedicated edit buffer. By default we use LaTeX-mode." - :type 'symbol - :group 'ein) - -(defun ein:edit-cell-contents () - "Edit the contents of the current cell in a buffer using an -appropriate language major mode. Functionality is very similar to -`org-edit-special'." - (interactive) - (setq ein:src--saved-window-config (current-window-configuration)) - (let* ((cell (or (ein:worksheet-get-current-cell) - (error "Must be called from inside an EIN worksheet cell."))) - (nb (ein:notebook--get-nb-or-error)) - (ws (ein:worksheet--get-ws-or-error)) - (type (slot-value cell 'cell-type)) - (name (ein:construct-cell-edit-buffer-name (buffer-name) (ein:cell-id cell) type))) - (ein:aif (get-buffer name) - (switch-to-buffer-other-window it) - (ein:create-edit-cell-buffer name cell nb ws)))) - -(defun ein:edit-cell-detect-type (contents notebook &optional raw-cell-p) - (if (string-match "^%%\\(.*\\)" contents) - (ein:case-equal (match-string 1 contents) - (("html" "HTML") (html-mode)) - (("latex" "LATEX") (LaTeX-mode)) - (("ruby") (ruby-mode)) - (("sh" "bash") (sh-mode)) - (("javascript" "js") (javascript-mode)) - (t (funcall ein:raw-cell-default-edit-mode))) - (if raw-cell-p - (funcall ein:raw-cell-default-edit-mode) - (case (ein:get-mode-for-kernel (ein:$notebook-kernelspec notebook)) - (julia (julia-mode)) - (python (python-mode)) - (R (R-mode)))))) - -(defun ein:create-edit-cell-buffer (name cell notebook worksheet) - (let* ((contents (ein:cell-get-text cell)) - (type (slot-value cell 'cell-type)) - (buffer (generate-new-buffer-name name)) - (overlay (ein:make-source-overlay (ein:cell-input-pos-min cell) - (ein:cell-input-pos-max cell) - buffer))) - (switch-to-buffer-other-window buffer) - (insert contents) - (remove-text-properties (point-min) (point-max) - '(display nil invisible nil intangible nil)) - (set-buffer-modified-p nil) - (setq buffer-file-name buffer) ;; Breaks anaconda-mode without this special fix. - - (condition-case e - (ein:case-equal type - (("markdown") (markdown-mode)) - (("raw") (ein:edit-cell-detect-type contents notebook t)) - (("code") (ein:edit-cell-detect-type contents notebook))) - (error (message "Language mode `%s' fails with: %S" - type (nth 1 e)))) - (set (make-local-variable 'ein:src--overlay) overlay) - (set (make-local-variable 'ein:src--cell) cell) - (set (make-local-variable 'ein:src--ws) worksheet) - (set (make-local-variable 'ein:src--allow-write-back) t) - (ein:edit-cell-mode))) - -(provide 'ein-cell-edit) diff --git a/lisp/ein-cell.el b/lisp/ein-cell.el index 0f3cc0b..0fc22ec 100644 --- a/lisp/ein-cell.el +++ b/lisp/ein-cell.el @@ -42,8 +42,6 @@ (require 'ein-node) (require 'ein-kernel) (require 'ein-output-area) -(require 'ein-skewer) -(require 'ein-hy) ;;; Faces @@ -122,12 +120,7 @@ ;;; Customization -(defcustom ein:enable-dynamic-javascript nil - "[EXPERIMENTAL] When non-nil enable support in ein for -executing dynamic javascript. This feature requires installation -of the skewer package." - :type 'boolean - :group 'ein) +(make-obsolete-variable 'ein:enable-dynamic-javascript nil "0.17.0") (defcustom ein:cell-traceback-level 1 "Number of traceback stack to show. @@ -210,7 +203,6 @@ a number will limit the number of lines in a cell output." (defun ein:cell-class-from-type (type) (ein:case-equal type (("code") 'ein:codecell) - (("hy-code") 'ein:hy-codecell) (("text") 'ein:textcell) (("html") 'ein:htmlcell) (("markdown") 'ein:markdowncell) @@ -229,13 +221,7 @@ a number will limit the number of lines in a cell output." (apply (ein:cell-class-from-type type) args)) (defun ein:cell--determine-cell-type (json-data) - (let ((base-type (plist-get json-data :cell_type)) - (metadata (plist-get json-data :metadata))) - (if (and (string-equal base-type "code") - (plist-get :metadata :ein.hycell) - (not (eql (plist-get metadata :ein.hycell) :json-false))) - "hy-code" - base-type))) + (plist-get json-data :cell_type)) (defun ein:cell-from-json (data &rest args) (let ((cell (ein:cell-init (apply #'ein:cell-from-type @@ -921,13 +907,8 @@ Called from ewoc pretty printer via `ein:cell-insert-output'." (cl-defmethod ein:cell-append-display-data ((cell ein:codecell) json) "Insert display-data type output in the buffer. Called from ewoc pretty printer via `ein:cell-insert-output'." - (if (and (or (plist-get json :javascript) - (plist-get json :html)) - (slot-value cell 'dynamic) ein:enable-dynamic-javascript) - (ein:execute-javascript cell json) - (progn - (ein:cell-append-mime-type json (slot-value cell 'dynamic)) - (ein:insert-read-only "\n")))) + (ein:cell-append-mime-type json (slot-value cell 'dynamic)) + (ein:insert-read-only "\n")) (defcustom ein:output-type-preference (if (and (fboundp 'shr-insert-document) @@ -1052,9 +1033,6 @@ prettified text thus be used instead of HTML type." (setq metadata (plist-put metadata :collapsed (if (slot-value cell 'collapsed) t json-false))) (setq metadata (plist-put metadata :autoscroll json-false)) (setq metadata (plist-put metadata :ein.tags (format "worksheet-%s" wsidx))) - (setq metadata (plist-put metadata :ein.hycell (if (ein:hy-codecell-p cell) - t - json-false))) (setq metadata (plist-put metadata :slideshow ss-table)) (unless discard-output (dolist (output outputs) diff --git a/lisp/ein-classes.el b/lisp/ein-classes.el index 2006cf7..9e5786e 100644 --- a/lisp/ein-classes.el +++ b/lisp/ein-classes.el @@ -63,9 +63,6 @@ :file : Either :text or :base64 :notebook : :json. -`ein:$content-checkpoints' - Names auto-saved checkpoints for content. Stored as a list - of ( . ) pairs. " url-or-port notebook-version @@ -78,11 +75,7 @@ mimetype raw-content format - session-p - checkpoints) - - - + session-p) ;;; Websockets (defstruct ein:$websocket @@ -148,13 +141,6 @@ `ein:$notebook-api-version' : integer Major version of the IPython notebook server we are talking to. - -`ein:$notebook-checkpoints' - Names auto-saved checkpoints for content. Stored as a list - of ( . ) pairs. - -`ein:$notebook-q-checkpoints' - Whether to checkpoint on save. Overrides ein:notebook-create-checkpoint-on-save " url-or-port notebook-id ;; In IPython-2.0 this is "[:path]/[:name].ipynb" @@ -171,10 +157,7 @@ events worksheets scratchsheets - api-version - autosave-timer - checkpoints - q-checkpoints) + api-version) @@ -306,11 +289,6 @@ This cell is executed when the connected buffer is saved, provided that (1) this flag is `t' and (2) corresponding auto-execution mode flag in the connected buffer is `t'."))) -;; Use this cell to execute hy code in notebook running a Python kernel. -(defclass ein:hy-codecell (ein:codecell) - ((cell-type :initarg :cell-type :initform "hy-code")) - "Codecell that supports executing hy code from within a Python kernel.") - (defclass ein:textcell (ein:basecell) ((cell-type :initarg :cell-type :initform "text") (element-names :initform (:prompt :input :footer :slidetype)))) @@ -366,9 +344,7 @@ auto-execution mode flag in the connected buffer is `t'."))) "NotebookStatus" :s2m '((notebook_saving.Notebook . "Saving Notebook...") - (notebook_create_checkpoint.Notebook . "Creating Checkpoint...") (notebook_saved.Notebook . "Notebook is saved") - (notebook_checkpoint_created.Notebook . "Checkpoint created.") (notebook_save_failed.Notebook . "Failed to save Notebook!"))) :type ein:notification-status) (kernel diff --git a/lisp/ein-company.el b/lisp/ein-company.el deleted file mode 100644 index 4bef496..0000000 --- a/lisp/ein-company.el +++ /dev/null @@ -1,124 +0,0 @@ -;;; -*- mode: emacs-lisp; lexical-binding: t; -*- -;;; ein-company.el --- Support for completion using company back-end. - -;; Copyright (C) 2017 - John Miller - -;; Author: John Miller - -;; This file is NOT part of GNU Emacs. - -;; ein-company.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-company.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-company.el. If not, see . - -;;; Commentary: - -;; - -;;; Code: - -(eval-when-compile (require 'cl)) -(require 'deferred) -(require 'ein-completer) -(require 'company nil t) - -(autoload 'company-begin-backend "company") -(autoload 'company-doc-buffer "company") - -(defun ein:company--deferred-complete () - (let ((d (deferred:new #'identity))) - (ein:completer-complete - (ein:get-kernel) - (list :complete_reply - (cons (lambda (d* &rest args) (deferred:callback-post d* args)) - d)) - (apply-partially (lambda (d* err) (deferred:callback-post d* err)) d)) - d)) - -(defun ein:company--complete (prefix fetcher) - (deferred:$ - (deferred:next - (lambda () - (ein:company--deferred-complete))) - (deferred:nextc it - (lambda (replies) - (unless (stringp replies) ;; if not an error - (ein:completions--prepare-matches prefix fetcher replies)))))) - -(defun ein:completions--prepare-matches (prefix fetcher replies) - (destructuring-bind - ((&key matches cursor_start cursor_end &allow-other-keys) ; :complete_reply - _metadata) - replies - (let ((nix (- cursor_end cursor_start)) - prefixed-matches) - (dolist (match matches) - (setq prefixed-matches - (nconc prefixed-matches (list (concat prefix (substring match nix)))))) - (ein:completions--build-oinfo-cache prefixed-matches) - (funcall fetcher prefixed-matches)))) - -;;;###autoload -(defun ein:company-backend (command &optional arg &rest _) - (interactive (list 'interactive)) - (cl-case command - (interactive (company-begin-backend 'ein:company-backend)) - (prefix (and (eq ein:completion-backend 'ein:use-company-backend) - (or (ein:worksheet-at-codecell-p) ein:connect-mode) - (ein:get-kernel) - (ein:object-prefix-at-point))) - (annotation (let ((kernel (ein:get-kernel))) - (ein:aif (gethash arg (ein:$kernel-oinfo-cache kernel)) - (plist-get it :definition)))) - (doc-buffer (cons :async - (lambda (cb) - (ein:company-handle-doc-buffer arg cb)))) - (location (cons :async - (lambda (cb) - (ein:pytools-find-source (ein:get-kernel-or-error) - arg - cb)))) - (candidates - (let* ((kernel (ein:get-kernel-or-error)) - (cached (ein:completions-get-cached arg (ein:$kernel-oinfo-cache kernel)))) - (ein:aif cached it - (unless (ein:company--punctuation-check (thing-at-point 'line) - (current-column)) - (case ein:completion-backend - (t - (cons :async - (lambda (cb) - (ein:company--complete arg cb))))))))))) - -(defun ein:company--punctuation-check (thing col) - (or (string-match "[[:nonascii:]]" thing) - (let ((query (ein:trim-right (subseq thing 0 col) "[\n]"))) - (string-match "[]()\",[{}'=: ]$" query (- col 2))))) - - -(defun ein:company-handle-doc-buffer-finish (packed content _metadata-not-used_) - (when (plist-get content :found) - (funcall (plist-get packed :callback) (company-doc-buffer - (ansi-color-apply (cadr (plist-get content :data))))))) - -(defun ein:company-handle-doc-buffer (object cb) - (ein:kernel-object-info-request (ein:get-kernel-or-error) - object - (list :inspect_reply - (cons #'ein:company-handle-doc-buffer-finish - (list :object object - :callback cb))))) - -(when (boundp 'company-backends) - (add-to-list 'company-backends 'ein:company-backend)) - -(provide 'ein-company) diff --git a/lisp/ein-completer.el b/lisp/ein-completer.el index 61b223d..b0a1ca5 100644 --- a/lisp/ein-completer.el +++ b/lisp/ein-completer.el @@ -26,8 +26,6 @@ ;;; Code: -(declare-function ac-cursor-on-diable-face-p "auto-complete") - (eval-when-compile (require 'cl)) (require 'ein-core) @@ -35,7 +33,6 @@ (require 'ein-subpackages) (require 'ein-kernel) (require 'ein-pytools) -(require 'ein-ac) (require 'dash) (make-obsolete-variable 'ein:complete-on-dot nil "0.15.0") @@ -43,7 +40,6 @@ (defun ein:completer-choose () (cond ((eq ein:completion-backend 'ein:use-none-backend) #'ignore) - ((ein:eval-if-bound 'auto-complete-mode) #'ein:completer-finish-completing-ac) (t #'ein:completer-finish-completing-default))) (defun ein:completer-beginning (matched-text) @@ -73,12 +69,7 @@ (insert word)))) (defun ein:completer-complete (kernel callbacks errback) - "Start completion for the code at point. - - EXPAND keyword argument is supported by - `ein:completer-finish-completing-ac'. When it is specified, - it overrides `ac-expand-on-auto-complete' when calling - `auto-complete'." + "Start completion for the code at point." (interactive (list (ein:get-kernel) (list :complete_reply (cons #'ein:completer-finish-completing '(:expand nil))) @@ -97,16 +88,9 @@ when (string-prefix-p partial candidate) collect candidate)) -(defun ein:completions--get-oinfo (obj) +(defun ein:completions--get-oinfo (_obj) (let ((d (deferred:new #'identity)) - (kernel (ein:get-kernel))) - (if (ein:kernel-live-p kernel) - (ein:kernel-execute - kernel - (format "__ein_print_object_info_for(__ein_maybe_undefined_object(r\"%s\", locals()))" obj) - (list - :output `(,(lambda (d* &rest args) (deferred:callback-post d* args)) . ,d))) - (deferred:callback-post d "kernel not live")) + (_kernel (ein:get-kernel))) d)) (defun ein:completions--build-oinfo-cache (objs) @@ -142,16 +126,6 @@ (prin1 output #'external-debugging-output)) (setf (gethash obj (ein:$kernel-oinfo-cache kernel)) :json-false)))) -;;; Support for Eldoc - -(defun ein:completer--get-eldoc-signature () - (ein:and-let* ((func (ein:function-at-point)) - (kernel (ein:get-kernel))) - (ein:aif (gethash func (ein:$kernel-oinfo-cache kernel)) - (ein:kernel-construct-defstring it) - (ein:completions--build-oinfo-cache (list func)) - nil))) - (provide 'ein-completer) ;;; ein-completer.el ends here diff --git a/lisp/ein-connect.el b/lisp/ein-connect.el index ec5667b..aac6753 100644 --- a/lisp/ein-connect.el +++ b/lisp/ein-connect.el @@ -33,7 +33,6 @@ (require 'eieio) (require 'company nil t) (require 'ein-notebook) -(eval-when-compile (require 'auto-complete)) (autoload 'company-mode "company") @@ -199,8 +198,6 @@ notebooks." (if (or (not no-reconnection) (not ein:%connect%)) (let ((connection (ein:connect-setup notebook buffer))) - (when (ein:eval-if-bound 'ac-sources) - (push 'ac-source-ein-async ac-sources)) (ein:connect-mode) (ein:log 'info "Connected to %s" (ein:$notebook-notebook-name notebook)) @@ -398,15 +395,7 @@ notebook." :lighter (:eval (ein:connect-mode-get-lighter)) :keymap ein:connect-mode-map :group 'ein - (case ein:completion-backend - (ein:use-ac-backend - (define-key ein:connect-mode-map "." 'ein:ac-dot-complete) - (auto-complete-mode)) - (ein:use-company-backend - (if (not (boundp 'company-backends)) - (error "ein:connect-mode: company unsupported") - (cl-assert (member 'ein:company-backend company-backends)) - (company-mode))))) + ) (put 'ein:connect-mode 'permanent-local t) diff --git a/lisp/ein-contents-api.el b/lisp/ein-contents-api.el index 47f7546..3ba064d 100644 --- a/lisp/ein-contents-api.el +++ b/lisp/ein-contents-api.el @@ -427,71 +427,6 @@ global setting. For global setting and more information, see &aux (resp-string (format "STATUS: %s DATA: %s" (request-response-status-code response) data))) (ein:log 'debug "ein:query-sessions--complete %s" resp-string)) - -;;; Checkpoints - - -(defun ein:content-query-checkpoints (content &optional callback cbargs) - (let* ((url (ein:content-url content "checkpoints"))) - (ein:query-singleton-ajax - (list 'content-query-checkpoints url) - url - :type "GET" - :timeout ein:content-query-timeout - :parser #'ein:json-read - :sync ein:force-sync - :success (apply-partially #'ein:content-query-checkpoints-success content callback cbargs) - :error (apply-partially #'ein:content-query-checkpoints-error content)))) - -(defun ein:content-create-checkpoint (content &optional callback cbargs) - (let* ((url (ein:content-url content "checkpoints"))) - (ein:query-singleton-ajax - (list 'content-query-checkpoints url) - url - :type "POST" - :timeout ein:content-query-timeout - :parser #'ein:json-read - :sync ein:force-sync - :success (apply-partially #'ein:content-query-checkpoints-success content callback cbargs) - :error (apply-partially #'ein:content-query-checkpoints-error content)))) - -(defun ein:content-restore-checkpoint (content checkpoint-id &optional callback cbargs) - (let* ((url (ein:content-url content "checkpoints" checkpoint-id))) - (ein:query-singleton-ajax - (list 'content-query-checkpoints url) - url - :type "POST" - :timeout ein:content-query-timeout - :parser #'ein:json-read - :sync ein:force-sync - :success (when callback - (apply callback cbargs)) - :error (apply-partially #'ein:content-query-checkpoints-error content)))) - -(defun ein:content-delete-checkpoint (content checkpoint-id &optional callback cbargs) - (let* ((url (ein:content-url content "checkpoints" checkpoint-id))) - (ein:query-singleton-ajax - (list 'content-query-checkpoints url) - url - :type "DELETE" - :timeout ein:content-query-timeout - :parser #'ein:json-read - :sync ein:force-sync - :success (when callback - (apply callback cbargs)) - :error (apply-partially #'ein:content-query-checkpoints-error content)))) - -(defun* ein:content-query-checkpoints-success (content cb cbargs &key data status response &allow-other-keys) - (unless (listp (car data)) - (setq data (list data))) - (setf (ein:$content-checkpoints content) data) - (when cb - (apply cb content cbargs))) - -(defun* ein:content-query-checkpoints-error (content &key symbol-status response &allow-other-keys) - (ein:log 'error "Content checkpoint operation failed with status %s (%s)." symbol-status response)) - - ;;; Uploads diff --git a/lisp/ein-core.el b/lisp/ein-core.el index 9bca8b5..7511dfb 100644 --- a/lisp/ein-core.el +++ b/lisp/ein-core.el @@ -346,8 +346,7 @@ but can operate in different contexts." (ein:generic-getter '(ein:get-kernel--notebook ein:get-kernel--worksheet ein:get-kernel--shared-output - ein:get-kernel--connect - ein:get-kernel--worksheet-in-edit-cell))) + ein:get-kernel--connect))) (defun ein:get-kernel-or-error () (or (ein:get-kernel) diff --git a/lisp/ein-dev.el b/lisp/ein-dev.el index a94e6ba..53309b6 100644 --- a/lisp/ein-dev.el +++ b/lisp/ein-dev.el @@ -27,6 +27,7 @@ (eval-when-compile (require 'cl)) (declare-function rst-shift-region "rst") +(declare-function markdown-mode "markdown-mode") (require 'ein-notebook) (require 'ein-subpackages) @@ -49,8 +50,7 @@ (let* ((dir (or dir ein:source-dir)) (regex (or regex ".+")) (files (-remove #'(lambda (x) - (or (string-match-p "ein-pkg\\.el" x) - (string-match-p "ein-smartrep\\.el" x))) + (string-match-p "ein-pkg\\.el" x)) (and (file-accessible-directory-p dir) (directory-files dir 'full regex))))) @@ -69,7 +69,6 @@ (loop for f in (directory-files ein:source-dir nil "^ein-.*\\.el$") unless (or (equal f "ein-pkg.el") (equal f "ein-autoloads.el") - (equal f "ein-smartrep.el") (funcall ignore-p f)) do (require (intern (file-name-sans-extension f)) nil t)) ;; For `widget-button-press': @@ -125,7 +124,7 @@ callback (`websocket-callback-debug-on-error') is enabled." (setq request-log-level (quote debug)) (lexical-let ((curl-trace (concat temporary-file-directory "curl-trace"))) (nconc request-curl-options `("--trace-ascii" ,curl-trace)) - (add-function :after + (add-function :after (symbol-function 'request--curl-callback) (lambda (&rest args) (if (file-readable-p curl-trace) diff --git a/lisp/ein-hy.el b/lisp/ein-hy.el deleted file mode 100644 index a08ceb0..0000000 --- a/lisp/ein-hy.el +++ /dev/null @@ -1,52 +0,0 @@ -;;; ein-hy.el --- Hylang Support -*- lexical-binding: t; -*- - -;; (C) 2018 - John M. Miller - -;; Author: John Miller - -;; This file is NOT part of GNU Emacs. - -;; ein-hy.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-hy.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-hy.el. If not, see . - -;;; Commentary: - -;;; Code: - -(require 'cl) -(require 'ein-classes) - -(cl-defmethod ein:cell-insert-prompt ((cell ein:hy-codecell)) - "Insert prompt of the CELL in the buffer. -Called from ewoc pretty printer via `ein:cell-pp'." - ;; Newline is inserted in `ein:cell-insert-input'. - (ein:insert-read-only - (concat - (format "In (hy) [%s]" (or (ein:oref-safe cell 'input-prompt-number) " ")) - (ein:maybe-show-slideshow-data cell) - (when (slot-value cell 'autoexec) " %s" ein:cell-autoexec-prompt)) - 'font-lock-face 'ein:cell-input-prompt)) - -(cl-defmethod ein:cell-execute-internal ((cell ein:hy-codecell) - kernel code &rest args) - (ein:cell-clear-output cell t t t) - (ein:cell-set-input-prompt cell "*") - (ein:cell-running-set cell t) - (setf (slot-value cell 'dynamic) t) - (apply #'ein:kernel-execute kernel (ein:pytools-wrap-hy-code code) (ein:cell-make-callbacks cell) args)) - -(cl-defmethod ein:cell-to-nb4-json :before ((cell ein:hy-codecell) _ &optional _ignore) - (let ((metadata (slot-value cell 'metadata))) - (setf metadata (plist-put metadata :ein.hycell t)))) - -(provide 'ein-hy) diff --git a/lisp/ein-inspector.el b/lisp/ein-inspector.el deleted file mode 100644 index ad24fe5..0000000 --- a/lisp/ein-inspector.el +++ /dev/null @@ -1,125 +0,0 @@ -;;; -*- mode: emacs-lisp; lexical-binding: t -*- -;;; ein-inspector.el --- An inspector, in emacs, for Python - -;; Copyright (C) 2017 - John Miller - -;; Authors: Takafumi Arakaki -;; John M. Miller - -;; This file is NOT part of GNU Emacs. - -;; ein-inspector.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-inspector.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-inspector.el. If not, see . - -;;; Commentary: - -;;; Code: - -(require 'ein-pytools) - -;;;###autoload -(defun ein:inspect-object (kernel object) - (interactive (list (ein:get-kernel-or-error) - (ein:object-at-point-or-error))) - (ein:kernel-execute kernel - (format "__import__('ein_inspector').generate_inspector_data('%s', globals(), locals())" - object) - (list - :output - (cons #'ein:prepare-inspector - (list kernel object))))) - -(defun ein:prepare-inspector (packed _msg-type content _metadata) - (destructuring-bind (_kernel oname) - packed - (ein:aif (or (plist-get content :text) (plist-get content :data)) - (let ((oinfo (ein:json-read-from-string it))) - (if (not (plist-get oinfo :type)) - (ein:log 'warn "[EIN:INSPECTOR]: %s" (plist-get oinfo :error)) - (ein:render-inspector oinfo))) - (ein:log 'warn "[EIN:INSPECTOR]: Could not find inspect data for object %s." oname)))) - -(defclass ein:iobject () - ((name :accessor ein:iobject-name :documentation "String representation can be evaluated in python to generate the object being inspected.") - (type :accessor ein:iobject-type :documentation "Python type of object, as returned by `type()`.") - (repr :accessor ein:iobject-repr :documentation "Value of object, as returned by its `__str__` method.") - (source-file :accessor ein:iobject-sfile :documentation "If availabe, the filename where the source for this object is to be found.") - (source-lines :accessor ein:iobject-slines :documentation "If available, the line in the file where the source for this object is found.") - (doc :accessor ein:iobject-doc :documentation "If available, the documentation string for this object.")) - :documentation "Class to hold information returned by Python `inspect` module for a Python object identified in the `name` slot.") - -(defun ein:new-inspector-object (object-info) - (make-instance 'ein:iobject - :name (plist-get object-info :name) - :type (plist-get object-info :type) - :repr (plist-get object-info :repr) - :source-file (plist-get object-info :source_file) - :source-lines (plist-get object-info :source_lines) - :doc (plist-get object-info :doc))) - -(defvar ein:inspector-visit-source-map (make-sparse-keymap)) - -(defvar ein:inspector-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map (make-composed-keymap widget-keymap - special-mode-map)) - map) - "Keymap for ein:inspector-mode.") - -(define-derived-mode ein:inspector-mode special-mode "EIN:INSPECTOR-MODE" - "Major mode for inspector Python objects from the emacs-ipython-notebook." - ) - - - -(defun ein:render-inspector (oinfo) - (let ((name (plist-get oinfo :name))) - (switch-to-buffer (format "*EIN Inspector: %s*" name)) - (kill-all-local-variables) - (let ((inhibit-read-only t)) - (erase-buffer)) - (remove-overlays) - (lexical-let* ((type (plist-get oinfo :type)) - (repr (plist-get oinfo :repr)) - (sfile (plist-get oinfo :source_file)) - (slines (last (plist-get oinfo :source_lines))) - (info-str (format "%s = {%s} %s" name type repr))) - (if sfile - (widget-create 'link - :notify - (lambda (&rest _ignore) - (ein:goto-file sfile (car slines))) - info-str) - (widget-insert (propertize info-str 'face 'bold))) - (widget-insert (format "\n\n%s\n\n" (make-string 80 ?\u2501))) - (widget-insert (format "%s\n\n%s\n\n" (plist-get oinfo :doc) (make-string 80 ?\u2501))) - (widget-insert (propertize (format "%s: %s\n" type name) - 'face 'bold)))) - (ein:inspector-mode) - (widget-setup)) - - - -(defun ein:inspector-visit-source () - (message "Visit source!")) - -(defun ein:inspector-visit-thing ()) - -(defun ein:inspector-section-toggle (_section)) - -(defun ein:inspector-section-show (_section)) - -(defun ein:inspector-section-hide (_section) - ) - -(provide 'ein-inspector) diff --git a/lisp/ein-jupyter.el b/lisp/ein-jupyter.el index 29cafc9..baa1acd 100644 --- a/lisp/ein-jupyter.el +++ b/lisp/ein-jupyter.el @@ -213,8 +213,6 @@ the log of the running jupyter server." (if (numberp port) `("--port" ,(format "%s" port) "--port-retries" "0"))))) - (when (eql system-type 'windows-nt) - (accept-process-output proc (/ ein:jupyter-server-run-timeout 1000))) (loop repeat 30 until (car (ein:jupyter-server-conn-info ein:jupyter-server-buffer-name)) do (sleep-for 0 500) @@ -255,19 +253,14 @@ the log of the running jupyter server." do (ein:query-running-process-table) until (zerop (hash-table-count ein:query-running-process-table)) do (sleep-for 0 500)) - (if (eq system-type 'windows-nt) - (progn - (ein:undocumented-shutdown url-or-port) - (ein:aif (ein:jupyter-server-process) - (delete-process it))) - (lexical-let* ((proc (ein:jupyter-server-process)) - (pid (process-id proc))) - (ein:log 'info "Signaled %s with pid %s" proc pid) - (signal-process pid 15) - (run-at-time 2 nil - (lambda () - (ein:log 'info "Resignaled %s with pid %s" proc pid) - (signal-process pid 15))))) + (lexical-let* ((proc (ein:jupyter-server-process)) + (pid (process-id proc))) + (ein:log 'info "Signaled %s with pid %s" proc pid) + (signal-process pid 15) + (run-at-time 2 nil + (lambda () + (ein:log 'info "Resignaled %s with pid %s" proc pid) + (signal-process pid 15)))) ;; `ein:notebooklist-sentinel' frequently does not trigger (ein:notebooklist-list-remove url-or-port) diff --git a/lisp/ein-kernelinfo.el b/lisp/ein-kernelinfo.el index bb87e46..c2f904e 100644 --- a/lisp/ein-kernelinfo.el +++ b/lisp/ein-kernelinfo.el @@ -41,76 +41,17 @@ in these buffer will be synced with the kernel's cwd.") (hostname :initarg :hostname :type string :documentation "Host name of the machine where the kernel is running on.") - (language - :initarg :language :type string - :accessor ein:kernelinfo-language - :documentation "Language for the running kernel.") (ccwd :initarg :ccwd :type string :documentation "cached CWD (last time checked CWD).")) :documentation "Info related (but unimportant) to kernel") -(defun ein:kernelinfo-new (kernel get-buffers kernel-language) +(defun ein:kernelinfo-new (kernel get-buffers) "Make a new `ein:kernelinfo' instance based on KERNEL and GET-BUFFERS." (let ((kerinfo (make-instance 'ein:kernelinfo))) (setf (slot-value kerinfo 'kernel) kernel) (setf (slot-value kerinfo 'get-buffers) get-buffers) - (setf (slot-value kerinfo 'language) kernel-language) - (ein:case-equal kernel-language - ("python" (ein:kernelinfo-setup-hooks kerinfo))) kerinfo)) - -(defun ein:kernelinfo-setup-hooks (kerinfo) - "Add `ein:kernelinfo-update-*' to `ein:$kernel-after-*-hook'." - (with-slots (kernel) kerinfo - (push (cons #'ein:kernelinfo-update-all kerinfo) - (ein:$kernel-after-start-hook kernel)) - (push (cons #'ein:kernelinfo-update-ccwd kerinfo) - (ein:$kernel-after-execute-hook kernel)))) - -(defun ein:kernelinfo-update-all (kerinfo) - "Update KERINFO slots by triggering all update functions." - (ein:log 'debug "(ein:kernel-live-p kernel) = %S" - (ein:kernel-live-p (slot-value kerinfo 'kernel))) - (ein:kernelinfo-update-ccwd kerinfo) - (ein:kernelinfo-update-hostname kerinfo)) - -(defun ein:kernelinfo-update-ccwd (kerinfo) - "Update cached current working directory (CCWD) and change -`default-directory' of kernel related buffers." - (let ((ccwd-string (ein:case-equal (ein:kernelinfo-language kerinfo) - (("python") "__import__('sys').stdout.write(__import__('os').getcwd())") - ((t) nil)))) - (when ccwd-string - (ein:kernel-request-stream - (slot-value kerinfo 'kernel) - ccwd-string - (lambda (cwd kerinfo) - (with-slots (kernel get-buffers) kerinfo - (setq cwd (ein:kernel-filename-from-python kernel cwd)) - (oset kerinfo :ccwd cwd) - ;; sync buffer's `default-directory' with CWD - (when (file-accessible-directory-p cwd) - (dolist (buffer (ein:funcall-packed get-buffers)) - (when (buffer-live-p buffer) - (with-current-buffer buffer - (setq default-directory (file-name-as-directory cwd)))))))) - (list kerinfo))))) - -(defun ein:kernelinfo-update-hostname (kerinfo) - "Get hostname in which kernel is running and store it in KERINFO." - (let ((hostname-string (ein:case-equal (ein:kernelinfo-language kerinfo) - (("python") "__import__('sys').stdout.write(__import__('socket').gethostname())") - ((t) nil)))) - (when hostname-string - (ein:kernel-request-stream - (slot-value kerinfo 'kernel) - hostname-string ; "__import__('sys').stdout.write(__import__('socket').gethostname())" ; uname() not available in windows - (lambda (hostname kerinfo) - (oset kerinfo :hostname hostname)) - (list kerinfo))))) - - (provide 'ein-kernelinfo) ;;; ein-kernelinfo.el ends here diff --git a/lisp/ein-multilang.el b/lisp/ein-multilang.el index 6954466..92b399e 100644 --- a/lisp/ein-multilang.el +++ b/lisp/ein-multilang.el @@ -102,10 +102,6 @@ This function may raise an error." 'ein:worksheet-end-of-cell-input) (ein:ml-set-font-lock-defaults)) -(eval-after-load "auto-complete" - '(add-to-list 'ac-modes 'ein:notebook-multilang-mode)) - - ;;; Language setup functions (defun ein:ml-narrow-to-cell () diff --git a/lisp/ein-notebook.el b/lisp/ein-notebook.el index 9cf89c2..5f076a0 100644 --- a/lisp/ein-notebook.el +++ b/lisp/ein-notebook.el @@ -34,7 +34,6 @@ (eval-when-compile (require 'cl)) -(eval-when-compile (require 'auto-complete)) (require 'ewoc) (require 'mumamo nil t) @@ -50,7 +49,6 @@ (require 'ein-kernel) (require 'ein-kernelinfo) (require 'ein-cell) -(require 'ein-cell-edit) (require 'ein-cell-output) (require 'ein-worksheet) (require 'ein-iexec) @@ -65,7 +63,6 @@ (require 'ein-query) (require 'ein-pytools) (require 'ein-traceback) -(require 'ein-inspector) (require 'ein-shared-output) (require 'ein-notebooklist) (require 'ein-multilang) @@ -74,51 +71,6 @@ ;;; Configuration -(make-obsolete-variable 'ein:notebook-discard-output-on-save nil "0.2.0") - -(declare-function ein:smartrep-config "ein-smartrep") - -(defcustom ein:use-smartrep nil - "Set to `t' to use preset smartrep configuration. - -.. warning:: When used with MuMaMo (see `ein:notebook-modes'), - keyboard macro which manipulates cell (add, remove, move, - etc.) may start infinite loop (you need to stop it with - ``C-g``). Please be careful using this option if you are a - heavy keyboard macro user. Using keyboard macro for other - commands is fine. - -.. (Comment) I guess this infinite loop happens because the three - modules (kmacro.el, mumamo.el and smartrep.el) touches to - `unread-command-events' in somehow inconsistent ways." - :type 'boolean - :group 'ein) - -(defvar *ein:notebook--pending-query* (make-hash-table :test 'equal) - "A map: (URL-OR-PORT . PATH) => t/nil") - -(defcustom ein:notebook-autosave-frequency 300 - "Sets the frequency (in seconds) at which the notebook is -automatically saved, per IPEP15. Set to 0 to disable this feature. - -Autosaves are automatically enabled when a notebook is opened, -but can be controlled manually via `ein:notebook-enable-autosave' -and `ein:notebook-disable-autosave'. - -If you wish to change the autosave frequency for the current -notebook call `ein:notebook-update-autosave-freqency'. - -" - :type 'number - :group 'ein) - -(defcustom ein:notebook-create-checkpoint-on-save t - "If non-nil a checkpoint will be created every time the -notebook is saved. Otherwise checkpoints must be created manually -via `ein:notebook-create-checkpoint'." - :type 'boolean - :group 'ein) - (defcustom ein:notebook-discard-output-on-save 'no "Configure if the output part of the cell should be saved or not. @@ -140,6 +92,16 @@ a function (const :tag "Yes" 'yes) ) :group 'ein) +(make-obsolete-variable 'ein:use-smartrep nil "0.17.0") + +(defvar *ein:notebook--pending-query* (make-hash-table :test 'equal) + "A map: (URL-OR-PORT . PATH) => t/nil") + +(make-obsolete-variable 'ein:notebook-autosave-frequency nil "0.17.0") + +(make-obsolete-variable 'ein:notebook-create-checkpoint-on-save nil "0.17.0") + +(make-obsolete-variable 'ein:notebook-discard-output-on-save nil "0.17.0") (defun ein:notebook-cell-has-image-output-p (-ignore- cell) (ein:cell-has-image-ouput-p cell)) @@ -405,11 +367,11 @@ where `created' indicates a new notebook or an existing one. (add-function :before errback pending-clear) (ein:content-query-contents url-or-port path (apply-partially #'ein:notebook-open--callback - notebook callback0 (not no-pop)) + notebook callback0) errback)))) notebook)) -(defun ein:notebook-open--callback (notebook callback0 q-checkpoints content) +(defun ein:notebook-open--callback (notebook callback0 content) (ein:log 'verbose "Opened notebook %s" (ein:$notebook-notebook-path notebook)) (let ((notebook-path (ein:$notebook-notebook-path notebook))) (ein:gc-prepare-operation) @@ -433,12 +395,9 @@ where `created' indicates a new notebook or an existing one. (ein:$notebook-notebook-name notebook))) (setf (ein:$notebook-kernelinfo notebook) (ein:kernelinfo-new (ein:$notebook-kernel notebook) - (cons #'ein:notebook-buffer-list notebook) - (symbol-name (ein:get-mode-for-kernel (ein:$notebook-kernelspec notebook))))) + (cons #'ein:notebook-buffer-list notebook))) (ein:notebook-put-opened-notebook notebook) (ein:notebook--check-nbformat (ein:$content-raw-content content)) - (setf (ein:$notebook-q-checkpoints notebook) q-checkpoints) - (ein:notebook-enable-autosaves notebook) (ein:gc-complete-operation)))) (defun ein:notebook-maybe-set-kernelspec (notebook content-metadata) @@ -478,56 +437,6 @@ of minor mode." ;;; Initialization. -(defun ein:notebook-enable-autosaves (notebook) - "Enable automatic, periodic saving for notebook." - (interactive - (list (or (ein:get-notebook) - (ein:aand (ein:notebook-opened-buffer-names) - (with-current-buffer (ein:completing-read - "Notebook: " it nil t) - (ein:get-notebook)))))) - (when (and (ein:$notebook-q-checkpoints notebook) - (> ein:notebook-autosave-frequency 0)) - (setf (ein:$notebook-autosave-timer notebook) - (run-at-time ein:notebook-autosave-frequency - ein:notebook-autosave-frequency - #'ein:notebook-maybe-save-notebook - notebook)) - (ein:log 'verbose "Enabling autosaves for %s with frequency %s seconds." - (ein:$notebook-notebook-name notebook) - ein:notebook-autosave-frequency))) - -(defun ein:notebook-disable-autosaves (notebook) - "Disable automatic, periodic saving for current notebook." - (interactive - (list (or (ein:get-notebook) - (ein:aand (ein:notebook-opened-buffer-names) - (with-current-buffer (ein:completing-read - "Notebook: " it nil t) - (ein:get-notebook)))))) - (if (and notebook (ein:$notebook-autosave-timer notebook)) - (progn - (ein:log 'verbose "Disabling auto checkpoints for notebook %s" (ein:$notebook-notebook-name notebook)) - (cancel-timer (ein:$notebook-autosave-timer notebook))))) - -(defun ein:notebook-update-autosave-frequency (new-frequency notebook) - "Change the autosaves frequency for the current notebook, or -for a notebook selected by the user if not currently inside a -notebook buffer." - (interactive - (list (read-number "New autosaves frequency (0 to disable): ") - (or (ein:get-notebook) - (ein:aand (ein:notebook-opened-buffer-names) - (with-current-buffer (ein:completing-read - "Notebook: " it nil t) - (ein:get-notebook)))))) - (if notebook - (progn - (setq ein:notebook-autosave-frequency new-frequency) - (ein:notebook-disable-autosaves notebook) - (ein:notebook-enable-autosaves notebook)) - (message "Open notebook first"))) - (defun ein:notebook-bind-events (notebook events) "Bind events related to PAGER to the event handler EVENTS." (setf (ein:$notebook-events notebook) events) @@ -607,9 +516,7 @@ notebook buffer then the user will be prompted to select an opened notebook." base-url (ein:$notebook-events notebook) (ein:$notebook-api-version notebook)))) - (setf (ein:$notebook-kernel notebook) kernel) - (when (eq (ein:get-mode-for-kernel (ein:$notebook-kernelspec notebook)) 'python) - (ein:pytools-setup-hooks kernel notebook)))) + (setf (ein:$notebook-kernel notebook) kernel))) (defun ein:notebook-reconnect-session-command () "It seems convenient but undisciplined to blithely create a new session if the original one no longer exists." @@ -628,14 +535,6 @@ notebook buffer then the user will be prompted to select an opened notebook." 'ein:notebook-request-tool-tip-or-help-command 'ein:pytools-request-tooltip-or-help "0.1.2") -(defun ein:notebook-ac-dot-complete () - "Insert dot and request completion." - (interactive) - (if (and (ein:get-notebook) - (ein:codecell-p (ein:get-cell-at-point))) - (call-interactively #'ein:ac-dot-complete) - (insert "."))) - (defun ein:notebook-kernel-interrupt-command () "Interrupt the kernel. This is equivalent to do ``C-c`` in the console program." @@ -888,8 +787,6 @@ This is equivalent to do ``C-c`` in the console program." (ein:$notebook-worksheets notebook)) (ein:events-trigger (ein:$notebook-events notebook) 'notebook_saved.Notebook) - (when ein:notebook-create-checkpoint-on-save - (ein:notebook-create-checkpoint notebook)) (when callback (apply callback cbargs))) @@ -1041,48 +938,6 @@ notebook worksheets." :type "notebook" :notebook-version (ein:$notebook-api-version notebook))) -(defun ein:notebook-create-checkpoint (notebook) - "Create checkpoint for current notebook based on most recent save." - (interactive (list (ein:get-notebook))) - (if (ein:$notebook-q-checkpoints notebook) - (ein:content-create-checkpoint - (ein:fast-content-from-notebook notebook) - (lexical-let ((notebook notebook)) - #'(lambda (content) - (ein:log 'verbose "Checkpoint %s for %s generated." - (plist-get (first (ein:$content-checkpoints content)) :id) - (ein:$notebook-notebook-name notebook)) - (setf (ein:$notebook-checkpoints notebook) - (ein:$content-checkpoints content))))))) - -(defun ein:notebook-list-checkpoint-ids (notebook) - (unless (ein:$notebook-checkpoints notebook) - (ein:content-query-checkpoints (ein:fast-content-from-notebook notebook) - (lexical-let ((notebook notebook)) - #'(lambda (content) - (setf (ein:$notebook-checkpoints notebook) - (ein:$content-checkpoints content))))) - (sleep-for 0.5)) - (loop for cp in (ein:$notebook-checkpoints notebook) - collecting (plist-get cp :last_modified))) - -(defun ein:notebook-restore-to-checkpoint (notebook checkpoint) - "Restore notebook to previous checkpoint saved on the Jupyter -server. Note that if there are multiple checkpoints the user will -be prompted on which one to use." - (interactive - (let* ((notebook (ein:get-notebook)) - (checkpoint (ein:completing-read - "Select checkpoint: " - (ein:notebook-list-checkpoint-ids notebook)))) - (list notebook checkpoint))) - (ein:content-restore-checkpoint (ein:fast-content-from-notebook notebook) - checkpoint) - (ein:notebook-close notebook) - (ein:notebook-open (ein:$notebook-url-or-port notebook) - (ein:$notebook-notebook-path notebook))) - - ;;; Worksheet (defmacro ein:notebook--worksheet-render-new (notebook type) @@ -1466,10 +1321,6 @@ Use simple `python-mode' based notebook mode when MuMaMo is not installed:: (defvar ein:notebook-mode-map (make-sparse-keymap)) -(with-eval-after-load "ein-smartrep" - (ein:smartrep-config ein:notebook-mode-map)) - - (defmacro ein:notebook--define-key (keymap key defn) "Ideally we could override just the keymap binding with a (string . wrapped) cons pair (as opposed to messing with the DEFN itself), but then describe-minor-mode unhelpfully shows ?? for the keymap commands." `(progn @@ -1480,8 +1331,6 @@ Use simple `python-mode' based notebook mode when MuMaMo is not installed:: (define-key ,keymap ,key ,defn))) (let ((map ein:notebook-mode-map)) - (ein:notebook--define-key map "\C-ci" 'ein:inspect-object) - (ein:notebook--define-key map "\C-c'" 'ein:edit-cell-contents) (ein:notebook--define-key map "\C-c\C-c" 'ein:worksheet-execute-cell) (ein:notebook--define-key map (kbd "M-RET") 'ein:worksheet-execute-cell-and-goto-next) (ein:notebook--define-key map (kbd "") @@ -1582,8 +1431,7 @@ Use simple `python-mode' based notebook mode when MuMaMo is not installed:: ))) ("Cell/Code" ,@(ein:generate-menu - '(("Edit cell contents in dedicated buffer" ein:edit-cell-contents) - ("Execute cell" ein:worksheet-execute-cell + '(("Execute cell" ein:worksheet-execute-cell :active (ein:worksheet-at-codecell-p)) ("Execute cell and go to next" ein:worksheet-execute-cell-and-goto-next @@ -1694,28 +1542,12 @@ watch the fireworks!" ;; It is executed after toggling the mode, and before running MODE-hook. (when ein:notebook-mode - (case ein:completion-backend - (ein:use-ac-backend - (ein:notebook--define-key ein:notebook-mode-map "." 'ein:notebook-ac-dot-complete) - (auto-complete-mode)) - (ein:use-company-backend - (if (not (boundp 'company-backends)) - (error "ein:connect-mode: company unsupported") - (cl-assert (member 'ein:company-backend company-backends)) - (ein:notebook--define-key ein:notebook-mode-map "." nil) - (company-mode)))) (ein:aif ein:helm-kernel-history-search-key (ein:notebook--define-key ein:notebook-mode-map it 'helm-ein-kernel-history)) (ein:aif ein:anything-kernel-history-search-key (ein:notebook--define-key ein:notebook-mode-map it 'anything-ein-kernel-history)) (setq indent-tabs-mode nil) ;; Being T causes problems with Python code. - (when (and (featurep 'eldoc) ein:enable-eldoc-support) - (add-function :before-until (local 'eldoc-documentation-function) - #'ein:completer--get-eldoc-signature) - (eldoc-mode)) - (ein:worksheet-imenu-setup) - (when ein:use-smartrep - (require 'ein-smartrep)))) + (ein:worksheet-imenu-setup))) ;; To avoid MuMaMo to discard `ein:notebook-mode', make it ;; permanent local. @@ -1790,7 +1622,6 @@ the first argument and CBARGS as the rest of arguments." ;; nor `ein:notebook-close' updates ein:notebook--opened-map (ein:log 'debug "ein:notebook-kill-buffer-callback called") (when (ein:$notebook-p ein:%notebook%) - (ein:notebook-disable-autosaves ein:%notebook%) (ein:notebook-close-worksheet ein:%notebook% ein:%worksheet%))) (defun ein:notebook-setup-kill-buffer-hook () diff --git a/lisp/ein-notebooklist.el b/lisp/ein-notebooklist.el index 185aaec..02a842b 100644 --- a/lisp/ein-notebooklist.el +++ b/lisp/ein-notebooklist.el @@ -35,8 +35,6 @@ (require 'ein-file) (require 'ein-contents-api) (require 'ein-subpackages) -(require 'ein-ac) -(require 'ein-company) (require 'deferred) (require 'dash) (require 'ido) @@ -51,10 +49,9 @@ (defcustom ein:notebooklist-render-order '(render-header - render-opened-notebooks render-directory) "Order of notebook list sections. -Must contain render-header, render-opened-notebooks, and render-directory." +Must contain render-header, and render-directory." :group 'ein :type 'list ) @@ -623,33 +620,6 @@ This function is called via `ein:notebook-after-rename-hook'." (symbol-name ein:jupyter-default-kernel)))) (widget-insert "\n")))))) -(defun render-opened-notebooks (url-or-port &rest args) - "Render the opened notebooks section (for ipython>=3)." - ;; Opened Notebooks Section - (with-current-buffer (ein:notebooklist-get-buffer url-or-port) - (widget-insert "\n---------- All Opened Notebooks ----------\n\n") - (loop for buffer in (ein:notebook-opened-buffers) - do (progn (widget-create - 'link - :notify (lexical-let ((buffer buffer)) - (lambda (&rest ignore) - (condition-case err - (switch-to-buffer buffer) - (error - (message "%S" err) - (ein:notebooklist-reload))))) - "Open") - (widget-create - 'link - :notify (lexical-let ((buffer buffer)) - (lambda (&rest ignore) - (if (buffer-live-p buffer) - (kill-buffer buffer)) - (run-at-time 1 nil #'ein:notebooklist-reload))) - "Close") - (widget-insert " : " (buffer-name buffer)) - (widget-insert "\n"))))) - (defun ein:format-nbitem-data (name last-modified) (let ((dt (date-to-time last-modified))) (format "%-40s%+20s" name @@ -935,62 +905,6 @@ and the url-or-port argument of ein:notebooklist-open*." (ein:notebooklist-login--success-1 url-or-port callback errback)) (t (ein:notebooklist-login--error-1 url-or-port error-thrown response errback)))) -;;;###autoload - -(defun ein:notebooklist-change-url-port (new-url-or-port) - "Update the ipython/jupyter notebook server URL for all the -notebooks currently opened from the current notebooklist buffer. - -This function works by calling `ein:notebook-update-url-or-port' -on all the notebooks opened from the current notebooklist." - (interactive (list (ein:notebooklist-ask-url-or-port))) - (unless (eql major-mode 'ein:notebooklist-mode) - (error "This command needs to be called from within a notebooklist buffer.")) - (let* ((current-nblist ein:%notebooklist%) - (old-url (ein:$notebooklist-url-or-port current-nblist)) - (new-url-or-port new-url-or-port) - (open-nb (ein:notebook-opened-notebooks #'(lambda (nb) - (equal (ein:$notebook-url-or-port nb) - (ein:$notebooklist-url-or-port current-nblist)))))) - (ein:notebooklist-open* new-url-or-port) - (loop for x upfrom 0 by 1 - until (or (get-buffer (format ein:notebooklist-buffer-name-template new-url-or-port)) - (= x 100)) - do (sit-for 0.1)) - (dolist (nb open-nb) - (ein:notebook-update-url-or-port new-url-or-port nb)) - (kill-buffer (ein:notebooklist-get-buffer old-url)) - (ein:notebooklist-open* new-url-or-port nil nil nil (lambda (buffer url-or-port) - (pop-to-buffer buffer))))) - -(defun ein:notebooklist-change-url-port--deferred (new-url-or-port) - (lexical-let* ((current-nblist ein:%notebooklist%) - (old-url (ein:$notebooklist-url-or-port current-nblist)) - (new-url-or-port new-url-or-port) - (open-nb (ein:notebook-opened-notebooks - (lambda (nb) - (equal (ein:$notebook-url-or-port nb) - (ein:$notebooklist-url-or-port current-nblist)))))) - (deferred:$ - (deferred:next - (lambda () - (ein:notebooklist-open* new-url-or-port) - (loop until (get-buffer (format ein:notebooklist-buffer-name-template new-url-or-port)) - do (sit-for 0.1)))) - (deferred:nextc it - (lambda () - (dolist (nb open-nb) - (ein:notebook-update-url-or-port new-url-or-port nb)))) - (deferred:nextc it - (lambda () - (kill-buffer (ein:notebooklist-get-buffer old-url)) - (ein:notebooklist-open* new-url-or-port nil nil nil (lambda (buffer url-or-port) - (pop-to-buffer buffer)))))))) - -;;; Generic getter - - - (defun ein:get-url-or-port--notebooklist () (when (ein:$notebooklist-p ein:%notebooklist%) (ein:$notebooklist-url-or-port ein:%notebooklist%))) diff --git a/lisp/ein-notification.el b/lisp/ein-notification.el index 56f6686..c65617b 100644 --- a/lisp/ein-notification.el +++ b/lisp/ein-notification.el @@ -74,13 +74,6 @@ where NS is `:kernel' or `:notebook' slot of NOTIFICATION." st ; = event-type #'ein:notification--callback (cons ns st)))) - (ein:events-on events - 'notebook_checkpoint_created.Notebook - #'ein:notification--fadeout-callback - (list (slot-value notification 'notebook) - "Checkpoint created." - 'notebook_checkpoint_created.Notebook - nil)) (ein:events-on events 'notebook_saved.Notebook #'ein:notification--fadeout-callback @@ -320,16 +313,6 @@ Generated by `ein:header-line-define-mouse-commands'" slot) (ein:notification-tab-create-line (slot-value ein:%notification% 'tab))))))) -(defun ein:header-line-setup-maybe () - "Setup `header-line-format' for mumamo. -As `header-line-format' is buffer local variable, it must be set -for each chunk when in -See also `ein:ac-setup-maybe'." - (and (ein:eval-if-bound 'ein:notebook-mode) - (ein:eval-if-bound 'mumamo-multi-major-mode) - (setq header-line-format ein:header-line-format))) -(add-hook 'after-change-major-mode-hook 'ein:header-line-setup-maybe) - (provide 'ein-notification) ;;; ein-notification.el ends here diff --git a/lisp/ein-pkg.el b/lisp/ein-pkg.el index 4668742..baae978 100644 --- a/lisp/ein-pkg.el +++ b/lisp/ein-pkg.el @@ -3,11 +3,9 @@ "Emacs IPython Notebook" '((emacs "25") (websocket "20190620.338") - (auto-complete "1.4.0") (request "20190621.1622") (deferred "0.5") (polymode "20190426.1729") (markdown-mode "20171116.756") (dash "2.13.0") - (s "1.11.0") - (skewer-mode "1.6.2"))) + (s "1.11.0"))) diff --git a/lisp/ein-python.el b/lisp/ein-python.el deleted file mode 100644 index 454b029..0000000 --- a/lisp/ein-python.el +++ /dev/null @@ -1,82 +0,0 @@ -;;; ein-python.el --- Workarounds for python.el - -;; Copyright (C) 2012 Takafumi Arakaki - -;; Author: Takafumi Arakaki - -;; This file is NOT part of GNU Emacs. - -;; ein-python.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-python.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-python.el. -;; If not, see . - -;;; Commentary: - -;; - -;;; Code: - -(require 'python) - -(require 'ein-worksheet) - -(defvar ein:python-block-start - (rx line-start - symbol-start - (or "def" "class" "if" "elif" "else" "try" - "except" "finally" "for" "while" "with") - symbol-end)) - -(defun ein:python-indent-calculate-indentation--around (orig &rest args) - "False if there is no python block yet in this cell." - (condition-case _ - (ein:and-let* ((cell (ein:worksheet-get-current-cell)) - (beg (ein:cell-input-pos-min cell)) - (p (point)) - ((< beg (point)))) - (if (not (search-backward-regexp ein:python-block-start beg t)) - 0 - (goto-char p) - (apply orig args))) - (error (apply orig args)))) - -(advice-add 'python-indent--calculate-indentation :around #'ein:python-indent-calculate-indentation--around) - -;; (defadvice python-indent-calculate-indentation -;; (around ein:python-indent-calculate-levels activate) -;; "Hack `python-indent-calculate-levels' to reset indent per cell. - -;; Let's say you have a notebook something like this:: - -;; In [1]: -;; def func(): -;; pass - -;; In [2]: -;; something[] - -;; Here, ``[]`` is the cursor position. When you hit the tab here, -;; you don't expect it to indent. However, python.el tries to follow -;; the indent of ``func()`` then you get indentation. This advice -;; workaround this problem. - -;; Note that this workaround does not work with the MuMaMo based -;; notebook mode." -;; (if (ein:ein-block-start-p) -;; ad-do-it -;; 0)) - - -(provide 'ein-python) - -;;; ein-python.el ends here diff --git a/lisp/ein-pytools.el b/lisp/ein-pytools.el index 9607f2b..f9ab0b1 100644 --- a/lisp/ein-pytools.el +++ b/lisp/ein-pytools.el @@ -56,9 +56,6 @@ If OTHER-WINDOW is non-`nil', open the file in the other window." (push (cons #'ein:pytools-load-safely kernel) (ein:$kernel-after-start-hook kernel))) -(defun ein:pytools-wrap-hy-code (code) - (format "__import__('hy').eval(__import__('hy').read_str('''%s'''))" code)) - (defun ein:pytools-load-safely (kernel) (with-temp-buffer (let ((pytools-file (format "%s/%s" ein:source-dir "ein_remote_safe.py"))) diff --git a/lisp/ein-skewer.el b/lisp/ein-skewer.el deleted file mode 100644 index 52cd0dd..0000000 --- a/lisp/ein-skewer.el +++ /dev/null @@ -1,98 +0,0 @@ -;;; -*- mode: emacs-lisp; lexical-binding: t; -*- -;;; ein-skewer.el --- Cell module - -;; (C) 2016 - John M Miller - -;; Author: John M Miller - -;; This file is NOT part of GNU Emacs. - -;; ein-skewer.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-skewre.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-cell.el. If not, see . - -;;; Commentary: - -;; This depends on the skewer package, so likely will get split into -;; its own package at some point. - -;;; Code: - -(require 'skewer-mode) -(require 'skewer-html) -(require 'simple-httpd) - -(defvar *ein:skewer-running-p* nil "True if the emacs httpd server has been started.") - -(defun ein:js-prepare-result (result type) - (list :output_type type :text result)) - -(defun ein:update-javascript-output (cell json result) - (let ((val (ein:js-prepare-result - (or (cdr (assoc 'value result)) "See browser for result.") - (plist-get json :output_type)))) - (setf (slot-value cell 'outputs) (list val)) - (ein:cell-append-output cell val (slot-value cell 'dynamic)))) - -(defservlet current-jupyter-cell-output text/html (path) - (let ((cell-id (file-name-nondirectory path))) - (insert (gethash cell-id *ein:skewer-cell-output-cache*)))) - -(defvar *ein:skewer-html-template* - " - - Emacs IPython Notebook - - - - %s - - ") - -(defvar *ein:skewer-cell-output-cache* (make-hash-table :test #'equal)) - -(defun ein:skewer--handle-html (cell string) - (setf (gethash (slot-value cell 'cell-id) *ein:skewer-cell-output-cache*) - (format *ein:skewer-html-template* string) )) - -;; Format of result is ((id . STR) (type . STR) (status . STR) (value . STR) (time . FLOAT)) -(defun ein:execute-javascript (cell json) - (unless (httpd-running-p) ;; *ein:skewer-running-p* - (run-skewer)) - (deferred:$ - (deferred:next - (lambda () - (let ((result nil)) - (ein:aif (plist-get json :html) - (progn - (let ((cell-id (slot-value cell 'cell-id))) - (ein:skewer--handle-html cell it) - (setq result (list '(id . nil) - '(type . str) - '(stats . nil) - (cons 'value (format "Open http://localhost:8080/current-jupyter-cell-output/%s" cell-id)) - '(time . nil))) - (browse-url (format "http://localhost:8080/current-jupyter-cell-output/%s" cell-id)))) - (skewer-eval (plist-get json :javascript) - (lambda (v) - (setq result v)) - :type (if (plist-get json :html) - "html" - "eval"))) - (cl-loop until result - do (accept-process-output nil 0.01) - finally (return result))))) - (deferred:nextc it - (lambda (result) - (ein:update-javascript-output cell json result))))) - -(provide 'ein-skewer) diff --git a/lisp/ein-smartrep.el b/lisp/ein-smartrep.el deleted file mode 100644 index 977afca..0000000 --- a/lisp/ein-smartrep.el +++ /dev/null @@ -1,55 +0,0 @@ -;;; ein-smartrep.el --- smartrep integration - -;; Copyright (C) 2012- Takafumi Arakaki - -;; Author: Takafumi Arakaki - -;; This file is NOT part of GNU Emacs. - -;; ein-smartrep.el is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; ein-smartrep.el is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with ein-smartrep.el. If not, see . - -;;; Commentary: - -;; - -;;; Code: - -(require 'smartrep nil t) - -(defcustom ein:smartrep-notebook-mode-alist - '(("C-t" . ein:worksheet-toggle-cell-type) - ("C-l" . ein:worksheet-clear-output) - ("C-k" . ein:worksheet-kill-cell) - ("C-y" . ein:worksheet-yank-cell) - ("C-a" . ein:worksheet-insert-cell-above) - ("C-b" . ein:worksheet-insert-cell-below) - ("C-n" . ein:worksheet-goto-next-input) - ("C-p" . ein:worksheet-goto-prev-input) - ("C-m" . ein:worksheet-merge-cell) - ("" . ein:worksheet-move-cell-up) - ("" . ein:worksheet-move-cell-down)) - "alist passed to `smartrep-define-key'." - :type '(repeat (cons string function)) - :group 'ein) - -(when (fboundp 'smartrep-define-key) - (defmacro ein:smartrep-config (map) - `(smartrep-define-key - ,map - "C-c" - ein:smartrep-notebook-mode-alist))) - -(provide 'ein-smartrep) - -;;; ein-smartrep.el ends here diff --git a/lisp/ein-subpackages.el b/lisp/ein-subpackages.el index c718714..05169f0 100644 --- a/lisp/ein-subpackages.el +++ b/lisp/ein-subpackages.el @@ -31,13 +31,9 @@ "EIN defaults to your individual company-mode or auto-complete-mode configuration. Change this setting to gather completions from the jupyter server:: * ein:use-none-backend: local completions only (configured outside EIN) - * ein:use-company-backend: company-style remote completions (elpy takes precedence) - * ein:use-ac-backend: deprecated auto-complete remote completions " :type '(choice - (const ein:use-none-backend) - (const ein:use-company-backend) - (const ein:use-ac-backend)) + (const ein:use-none-backend)) :group 'ein) (provide 'ein-subpackages) diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index c373aa1..8a25a2d 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -666,7 +666,6 @@ Use `ein:log' for debugging and logging." (defun ein:get-docstring (function) "Return docstring of FUNCTION." - ;; Borrowed from `ac-symbol-documentation'. (with-temp-buffer ;; import help-xref-following (require 'help-mode) diff --git a/lisp/ein-worksheet.el b/lisp/ein-worksheet.el index 36bd292..b7c3569 100644 --- a/lisp/ein-worksheet.el +++ b/lisp/ein-worksheet.el @@ -795,7 +795,7 @@ directly." Prompt will appear in the minibuffer. When used in as a Lisp function, TYPE (string) should be chose -from \"code\", \"hy-code\", \"markdown\", \"raw\" and \"heading\". LEVEL is +from \"code\", \"markdown\", \"raw\" and \"heading\". LEVEL is an integer used only when the TYPE is \"heading\"." (interactive (let* ((ws (ein:worksheet--get-ws-or-error)) @@ -808,7 +808,6 @@ an integer used only when the TYPE is \"heading\"." (format "Cell type [%s]: " choices) choices)) (type (case key (?c "code") - (?h "hy-code") (?m "markdown") (?r "raw") (t "heading"))) @@ -1173,13 +1172,6 @@ in the history." (defun ein:get-kernel--worksheet () (when (ein:worksheet-p ein:%worksheet%) (slot-value ein:%worksheet% 'kernel))) -;; in edit-cell-mode, worksheet is bound as src--ws -;; used by ein:get-kernel as a last option so completion, tooltips -;; work in edit-cell-mode -(defun ein:get-kernel--worksheet-in-edit-cell () - "Get kernel when in edit-cell-mode." - (when (ein:worksheet-p ein:src--ws) (slot-value ein:src--ws 'kernel))) - (defun ein:get-cell-at-point--worksheet () (ein:worksheet-get-current-cell :noerror t)) diff --git a/lisp/ein_inspector.py b/lisp/ein_inspector.py deleted file mode 100644 index e4eb4c3..0000000 --- a/lisp/ein_inspector.py +++ /dev/null @@ -1,46 +0,0 @@ -""" -Python utilities for the ein inspector. - -Copyright (C) 2017- John M. Miller - -Author: John Miller - -ein_inspector.py is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -ein_inspector.py is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with ein_inspector.py. If not, see . - -""" - -import json -import inspect - - -def generate_inspector_data(obj_str, globals, locals): - odata = {'name': obj_str} - try: - obj = eval(obj_str, globals, locals) - except NameError: - odata['error'] = 'Object {} not found.'.format(obj_str) - else: - odata['doc'] = inspect.getdoc(obj) - odata['type'] = str(type(obj)) - odata['repr'] = str(obj) - try: - odata['source_file'] = inspect.getsourcefile(obj) - odata['source_lines'] = inspect.getsourcelines(obj) - except: - odata['source_file'] = None - odata['source_lines'] = None - print(json.dumps(odata)) - return odata - - diff --git a/lisp/ein_remote_safe.py b/lisp/ein_remote_safe.py deleted file mode 100644 index ba148f1..0000000 --- a/lisp/ein_remote_safe.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -Python utilities to use it from ein.el - -Copyright (C) 2012- Takafumi Arakaki - -Author: Takafumi Arakaki - -ein.py is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -ein.py is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with ein.py. If not, see . - -""" - - -def __ein_export_nb(nb_json, format): - import IPython.nbconvert as nbconvert - import IPython.nbformat as nbformat - nb = nbformat.reads(nb_json, nbformat.NO_CONVERT) - output = nbconvert.export_by_name(format, nb) - print(output[0]) - - -def __ein_find_edit_target_012(*args, **kwds): - from IPython.core.interactiveshell import InteractiveShell - inst = InteractiveShell.instance() - return inst._find_edit_target(*args, **kwds) - - -def __ein_find_edit_target_013(*args, **kwds): - from IPython.core.interactiveshell import InteractiveShell - inst = InteractiveShell.instance() - return CodeMagics._find_edit_target(inst, *args, **kwds) - - -def __ein_find_edit_target_python(name): - from inspect import getsourcefile, getsourcelines - try: - obj = eval(name) - except NameError: - return False - else: - sfile = getsourcefile(obj) - sline = getsourcelines(obj)[-1] - if sfile and sline: - return(sfile, sline, False) - else: - return False - -try: - from IPython.core.magics import CodeMagics - __ein_find_edit_target = __ein_find_edit_target_013 -except ImportError: - __ein_find_edit_target = __ein_find_edit_target_012 - -def __ein_set_figure_size(*dim): - try: - from matplotlib.pyplot import rcParams - rcParams['figure.figsize'] = dim - except: - raise RuntimeError("Matplotlib not installed in this instance of python!") - -def __ein_find_source(name): - """Given an object as string, `name`, print its place in source code.""" - # FIXME: use JSON display object instead of stdout - ret = __ein_find_edit_target_python(name) or __ein_find_edit_target(name, {}, []) - if ret: - (filename, lineno, use_temp) = ret - if not use_temp: - print(filename) - print(lineno) - return - raise RuntimeError("Source code for {0} cannot be found".format(name)) - - -def __ein_run_docstring_examples(obj, verbose=True): - from IPython.core.interactiveshell import InteractiveShell - import doctest - inst = InteractiveShell.instance() - globs = inst.user_ns - return doctest.run_docstring_examples(obj, globs, verbose=verbose) - - -def __ein_maybe_undefined_object(obj, locals=None): - try: - return eval(obj, None, locals) - except Exception: - return None - except SyntaxError: - return None - -def __ein_print_object_info_for(obj): - import IPython.core.oinspect - import json - - inspector = IPython.core.oinspect.Inspector() - - try: - print(json.dumps(inspector.info(obj))) - except Exception: - print(json.dumps(inspector.info(None))) - -def __ein_eval_hy_string(obj): - try: - import hy - except ImportError: - print("Hy not supported in this kernel. Execute `pip install hy` if you want this support.") - - expr = hy.read_str(obj) - ret = hy.eval(expr) - - return ret diff --git a/lisp/ob-ein.el b/lisp/ob-ein.el index 4e29033..d294acb 100644 --- a/lisp/ob-ein.el +++ b/lisp/ob-ein.el @@ -70,8 +70,7 @@ ("ein-python" . python) ("ein-R" . R) ("ein-r" . R) - ("ein-julia" . julia) - ("ein-hy" . hy)) + ("ein-julia" . julia)) "ob-ein has knowledge of these (ein-LANG . LANG-MODE) pairs." :type '(repeat (cons string symbol)) :group 'ein) @@ -162,8 +161,7 @@ Based on ob-ipython--configure-kernel." (fset (intern (concat "org-babel-execute:" lang-name)) `(lambda (body params) (require (quote ,(intern (format "ob-%s" lang-mode))) nil t) - (if (boundp 'python-indent-guess-indent-offset-verbose) - (setq python-indent-guess-indent-offset-verbose nil)) + (custom-set-variables '(python-indent-guess-indent-offset-verbose nil)) (let* ((parser (quote ,(intern @@ -366,53 +364,6 @@ if necessary. Install CALLBACK (i.e., cell execution) upon notebook retrieval." (t (url-port parsed-url))))))) (t (ein:notebooklist-login url-or-port callback-login))))) -(defun ob-ein--edit-ctrl-c-ctrl-c () - "C-c C-c mapping in ein:connect-mode-map." - (interactive) - (if (not (org-src-edit-buffer-p)) - (ein:connect-run-buffer) - (org-edit-src-save) - (when (boundp 'org-src--beg-marker) - (let* ((beg org-src--beg-marker) - (buf (marker-buffer beg))) - (with-current-buffer buf - (save-excursion - (goto-char beg) - (org-ctrl-c-ctrl-c))))))) - -(defcustom ob-ein-babel-edit-polymode-ignore nil - "When false override default python mode key mapping for `\C-c\C-c' while inside a babel edit buffer. -Instead the binding will be to `ob-ein--edit-ctrl-c-ctrl-c', which will execute the code block being edited." - :group 'ein - :type '(boolean)) - -(defun org-babel-edit-prep:ein (babel-info) - (if (and ein:polymode (not ob-ein-babel-edit-polymode-ignore)) - (progn - (use-local-map (copy-keymap python-mode-map)) - (local-set-key "\C-c\C-c" 'ob-ein--edit-ctrl-c-ctrl-c)) - (let* ((buffer (current-buffer)) - (processed-parameters (nth 2 babel-info)) - (session (or (ein:aand (cdr (assoc :session processed-parameters)) - (unless (string= "none" it) - (format "%s" it))) - ein:url-localhost)) - (lang "ein-python") - (kernelspec (or (cdr (assoc :kernelspec processed-parameters)) - (ein:aif (cdr (assoc lang org-src-lang-modes)) - (cons 'language (format "%s" it)) - (error "ob-ein--execute-body: %s not among %s" - lang (mapcar #'car org-src-lang-modes)))))) - (ob-ein--initiate-session - session - kernelspec - (lambda (notebook) - (ein:connect-buffer-to-notebook notebook buffer t) - (define-key ein:connect-mode-map "\C-c\C-c" 'ob-ein--edit-ctrl-c-ctrl-c)))))) - -(defun org-babel-edit-prep:ein-python (babel-info) - (org-babel-edit-prep:ein babel-info)) - (loop for (lang . mode) in ob-ein-languages do (ob-ein--babelize-lang lang mode)) diff --git a/lisp/poly-ein.el b/lisp/poly-ein.el index 9674722..ee5a7e9 100644 --- a/lisp/poly-ein.el +++ b/lisp/poly-ein.el @@ -4,7 +4,7 @@ (declare-function polymode-inhibit-during-initialization "polymode-core") -(defcustom ein:polymode nil +(defcustom ein:polymode t "When enabled ein will use polymode to provide multi-major mode support in a notebook buffer, otherwise ein's custom and outdated multi-major mode support will be used. Emacs must be restarted @@ -181,15 +181,14 @@ TYPE can be 'body, nil." (error (message "%s: defaulting language to python" (error-message-string err)) "python"))) - (mode - (pm-get-mode-symbol-from-name - (cond ((ein:codecell-p cell) lang) - ((ein:markdowncell-p cell) "markdown") - (t "fundamental")))) + (what (cond ((ein:codecell-p cell) lang) + ((ein:markdowncell-p cell) "markdown") + (t "fundamental"))) + (mode (pm-get-mode-symbol-from-name what)) ((not (equal mode (ein:oref-safe cm :mode))))) (when (eq mode 'poly-fallback-mode) (ein:display-warning - (format "pm:get-span: no major mode for kernelspec language '%s'" lang))) + (format "pm:get-span: no major mode for kernelspec language '%s'" what))) (setq result-cm (loop for ocm in (eieio-oref pm/polymode '-auto-innermodes) when (equal mode (ein:oref-safe ocm :mode)) diff --git a/ltxpng/Enhancements_99e9bae2984f33a8dd1b990b80b91ab1a662cf49.png b/ltxpng/Enhancements_99e9bae2984f33a8dd1b990b80b91ab1a662cf49.png deleted file mode 100644 index 576a4889328528edeb803cb60e733e9d9068f777..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 482 zcmV<80UiE{P)jypX+O;1r)S6PIGhC@Y1dV73eVPmPOsc30ypP!&be+%yb000Sa zNLh0L01m_e01m_fl`9S#00045Nkl3f-xz7AUQzQaW9zo2it3A8I9)QUP++|CNQ#$lx>fKF=feuob}xP<{+P z5V7J~1ScSO$n%(qW3}UyfHGw+kTY?`1!5vBa1Ol3Ne=mDNVkvAG&<4O>B+1=YF)Rf z5Aqf43@kJlV+&lTn6P`;E^zaNIcCIR;F5|$^Cn@9StymEYyjF~Qi#Ii)WUG^%h_e< zbk(B#!?QI1{5ouMR3Nh&&0njc@d0FJtrFJvnm}&}t-#Tf*sBLPV;q>|ykb%)?%wDE zqb>$+;Oa@GxVvv5ze49Up)%t;sT8r@$L=TXJ;uwxkPfOhl_P`7pNCexZHaw2zIW#W Yzp430c%k^4-~a#s07*qoM6N<$f`O>j4*&oF diff --git a/ltxpng/Enhancements_a52848837248c7931a943cbbd4b70188a0935854.png b/ltxpng/Enhancements_a52848837248c7931a943cbbd4b70188a0935854.png deleted file mode 100644 index 0bb33ed144609b13bf9c299ca9abc40eac9038b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 614 zcmV-s0-61ZP)Hi~s-t32;bRa{vGi!~g&e z!~vBn4jTXf0kcU&K~zW$)m2G?gdhw|0NKI+|8`L8%(LTq8RDMvTDy7b96k%pgKd)s!AS$A{m2TU&tVZbVB-T(jq07*qoM6N<$f;&PG A5&!@I diff --git a/org_demo.org b/org_demo.org deleted file mode 100644 index d48b05e..0000000 --- a/org_demo.org +++ /dev/null @@ -1,132 +0,0 @@ -* Tests - -This is a [[ipynb:(:url-or-port%20"http://localhost:8888"%20:name%20"emacs-ipython-notebook/The%20Emacs%20IPython%20Notebook.ipynb")][link]] to an ein notebook. It might not work if your setup is not the same as mine! - - -Note that code is executed asynchronously, so executing the following won't -block Emacs. You can even queue up a number of source code blocks and they will -execute sequentially as the previous finishes execution! - -#+NAME: 6d0ec9b7-249c-46e9-bdf1-c48b7bcf7fbd -#+BEGIN_SRC ein :session http://localhost:8888/The Emacs IPython Notebook.ipynb - import sys - import time - - time.sleep(10) - print("Hello dood!") -#+END_SRC - -#+RESULTS: 6d0ec9b7-249c-46e9-bdf1-c48b7bcf7fbd -: Hello dood! - - - - - - - -#+NAME: 744c7889-aec1-495f-9d07-6efc17329e94 -#+BEGIN_SRC ein :session http://localhost:8888/The Emacs IPython Notebook.ipynb - 1+4 -#+END_SRC - -#+RESULTS: 744c7889-aec1-495f-9d07-6efc17329e94 -: 5 - -Tracebacks will be printed out, but if you want to use ein's traceback and -debugging support you have to jump to the ~*ein:shared-output*~ buffer for -traceback support or the notebook running the session and execute ~%debug~ in a -cell there. - -#+NAME: 47c36fa5-1b53-413b-8f5b-814f1ae66a3b -#+BEGIN_SRC ein :session http://localhost:8888/The Emacs IPython Notebook.ipynb :results output drawer - 1/0 -#+END_SRC - -#+RESULTS: 47c36fa5-1b53-413b-8f5b-814f1ae66a3b -:results: - -ZeroDivisionErrorTraceback (most recent call last) - in -----> 1 1/0 - -ZeroDivisionError: division by zero -:end: - -#+NAME: 00052904-6ca5-46e0-9797-c6039d0daf5e -#+BEGIN_SRC ein :session http://localhost:8888/The Emacs IPython Notebook.ipynb :results output drawer - import matplotlib.pyplot as plt - import numpy as np - - %matplotlib inline - x = np.linspace(0, 1, 100) - y = np.random.rand(100,1) - plt.plot(x,y) - x - -#+END_SRC - -#+RESULTS: 00052904-6ca5-46e0-9797-c6039d0daf5e -:results: -array([0. , 0.01010101, 0.02020202, 0.03030303, 0.04040404, - 0.05050505, 0.06060606, 0.07070707, 0.08080808, 0.09090909, - 0.1010101 , 0.11111111, 0.12121212, 0.13131313, 0.14141414, - 0.15151515, 0.16161616, 0.17171717, 0.18181818, 0.19191919, - 0.2020202 , 0.21212121, 0.22222222, 0.23232323, 0.24242424, - 0.25252525, 0.26262626, 0.27272727, 0.28282828, 0.29292929, - 0.3030303 , 0.31313131, 0.32323232, 0.33333333, 0.34343434, - 0.35353535, 0.36363636, 0.37373737, 0.38383838, 0.39393939, - 0.4040404 , 0.41414141, 0.42424242, 0.43434343, 0.44444444, - 0.45454545, 0.46464646, 0.47474747, 0.48484848, 0.49494949, - 0.50505051, 0.51515152, 0.52525253, 0.53535354, 0.54545455, - 0.55555556, 0.56565657, 0.57575758, 0.58585859, 0.5959596 , - 0.60606061, 0.61616162, 0.62626263, 0.63636364, 0.64646465, - 0.65656566, 0.66666667, 0.67676768, 0.68686869, 0.6969697 , - 0.70707071, 0.71717172, 0.72727273, 0.73737374, 0.74747475, - 0.75757576, 0.76767677, 0.77777778, 0.78787879, 0.7979798 , - 0.80808081, 0.81818182, 0.82828283, 0.83838384, 0.84848485, - 0.85858586, 0.86868687, 0.87878788, 0.88888889, 0.8989899 , - 0.90909091, 0.91919192, 0.92929293, 0.93939394, 0.94949495, - 0.95959596, 0.96969697, 0.97979798, 0.98989899, 1. ]) -[[file:ein-images/ob-ein-958ea9b193e7657e6b8b77069728be7a.png]] -:end: - - -#+NAME: 84b146f2-0b8d-46ca-9fb9-96759657927c -#+BEGIN_SRC ein :session http://localhost:8888/The Emacs IPython Notebook.ipynb :results output - from sympy import * - - init_printing() - x = symbols('x') - x - -#+END_SRC - -#+RESULTS: 84b146f2-0b8d-46ca-9fb9-96759657927c -#+begin_example - -ModuleNotFoundErrorTraceback (most recent call last) - in -----> 1 from sympy import * - 2 - 3 init_printing() - 4 x = symbols('x') - 5 x - -ModuleNotFoundError: No module named 'sympy' -#+end_example - - -* SVG Images -* Issue #468: Results in org mode - -#+NAME: ffbf0b19-515a-4966-9220-70063cf2948d -#+BEGIN_SRC ein :session http://localhost:8888/The Emacs IPython Notebook.ipynb :results value - import numpy as np - np.zeros(18) -#+END_SRC - -#+RESULTS: ffbf0b19-515a-4966-9220-70063cf2948d -: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., -: 0.]) - diff --git a/test/ein-testing-notebook.el b/test/ein-testing-notebook.el index 3346659..b158a89 100644 --- a/test/ein-testing-notebook.el +++ b/test/ein-testing-notebook.el @@ -49,10 +49,10 @@ (ein:kernel-new 8888 "" nil "/kernels" (ein:$notebook-events notebook) (ein:need-notebook-version (ein:$notebook-url-or-port notebook)))) (setf (ein:$kernel-events (ein:$notebook-kernel notebook)) (ein:events-new)) - ; matryoshka: new-content makes a ein:$content using CONTENT as template + ; matryoshka: new-content makes a ein:$content using CONTENT as template ; populating its raw_content field with DATA's content field (ein:notebook-open--callback - notebook nil nil + notebook nil (ein:new-content (ein:$notebook-url-or-port notebook) (ein:$notebook-notebook-path notebook) data)) (ein:notebook-buffer notebook))))) @@ -85,8 +85,8 @@ "Make new notebook. One empty cell will be inserted automatically if CELLS is nil." (ein:testing-notebook-from-json - (json-encode (ein:testing-notebook-make-data - (or name ein:testing-notebook-dummy-name) + (json-encode (ein:testing-notebook-make-data + (or name ein:testing-notebook-dummy-name) (or path name ein:testing-notebook-dummy-name) cells)))) @@ -112,7 +112,7 @@ The new cell is bound to a variable `cell'." LIST-OUTPUTS is a list of list of strings (pyout text). Number of LIST-OUTPUTS equals to the number cells to be contained in the notebook." - (ein:testing-notebook-make-new + (ein:testing-notebook-make-new ein:testing-notebook-dummy-name nil (mapcar (lambda (outputs) (ein:testing-codecell-data diff --git a/test/test-ein-ac.el b/test/test-ein-ac.el deleted file mode 100644 index c69236b..0000000 --- a/test/test-ein-ac.el +++ /dev/null @@ -1,17 +0,0 @@ -(eval-when-compile (require 'cl)) -(require 'ert) - -(require 'ein-ac) -(require 'ein-testing-kernel) - - -(ert-deftest ein:ac-set-document () - (let ((string "candidate string")) - (should-not (get-text-property 0 'document string)) - (ein:testing-kernel-construct-help-string-loop - (lambda (content result) - (ein:ac-set-document string content '-not-used-) - (let ((props (text-properties-at 0 string))) - ;; document property may be nil, but must be set. - (should (member 'document props)) - (should (equal (plist-get props 'document) result))))))) diff --git a/test/test-ein-kernel.el b/test/test-ein-kernel.el index 59338b2..f21e173 100644 --- a/test/test-ein-kernel.el +++ b/test/test-ein-kernel.el @@ -17,7 +17,7 @@ (dummy-response (make-request-response)) got-url) (setf (ein:$notebook-kernel notebook) kernel) - (cl-letf (((symbol-function 'request) + (cl-letf (((symbol-function 'request) (lambda (url &rest ignore) (setq got-url url) dummy-response)) ((symbol-function 'set-process-query-on-exit-flag) #'ignore) ((symbol-function 'ein:kernel-stop-channels) #'ignore) @@ -30,31 +30,35 @@ (should (equal got-url desired-url))))) (ert-deftest ein:kernel-interrupt-check-url () - (let* ((kernel (eintest:kernel-new 8888)) - (kernel-id "KERNEL-ID") - (desired-url "http://127.0.0.1:8888/api/kernels/KERNEL-ID/interrupt") - (dummy-response (make-request-response)) - got-url) - (flet ((request (url &rest ignore) (setq got-url url) dummy-response) - (set-process-query-on-exit-flag (process flag)) - (ein:kernel-stop-channels (&rest ignore)) - (ein:websocket (url kernel on-message on-close on-open) (make-ein:$websocket :ws nil :kernel kernel :closed-by-client nil)) - (ein:websocket-open-p (websocket) t)) + (lexical-let* ((kernel (eintest:kernel-new 8888)) + (kernel-id "KERNEL-ID") + (desired-url "http://127.0.0.1:8888/api/kernels/KERNEL-ID/interrupt") + (dummy-response (make-request-response)) + got-url) + + (cl-letf (((symbol-function 'request) + (lambda (url &rest ignore) (setq got-url url) dummy-response)) + ((symbol-function 'set-process-query-on-exit-flag) #'ignore) + ((symbol-function 'ein:kernel-stop-channels) #'ignore) + ((symbol-function 'ein:websocket) (lambda (&rest ignore) (make-ein:$websocket :ws nil :kernel kernel :closed-by-client nil))) + ((symbol-function 'ein:websocket-open-p) (lambda (&rest ignore) t))) (ein:kernel-retrieve-session--success kernel nil :data (list :ws_url "ws://127.0.0.1:8888" :id kernel-id)) (ein:kernel-interrupt kernel) (should (equal got-url desired-url))))) (ert-deftest ein:kernel-kill-check-url () - (let* ((kernel (eintest:kernel-new 8888)) - (kernel-id "KERNEL-ID") - (desired-url "http://127.0.0.1:8888/api/sessions/KERNEL-ID") - (dummy-response (make-request-response)) - got-url) - (flet ((request (url &rest ignore) (setq got-url url) dummy-response) - (set-process-query-on-exit-flag (process flag)) - (ein:kernel-stop-channels (&rest ignore)) - (ein:websocket (url kernel on-message on-close on-open) (make-ein:$websocket :ws nil :kernel kernel :closed-by-client nil))) + (lexical-let* ((kernel (eintest:kernel-new 8888)) + (kernel-id "KERNEL-ID") + (desired-url "http://127.0.0.1:8888/api/sessions/KERNEL-ID") + (dummy-response (make-request-response)) + got-url) + (cl-letf (((symbol-function 'request) + (lambda (url &rest ignore) (setq got-url url) dummy-response)) + ((symbol-function 'set-process-query-on-exit-flag) #'ignore) + ((symbol-function 'ein:kernel-stop-channels) #'ignore) + ((symbol-function 'ein:websocket) (lambda (&rest ignore) (make-ein:$websocket :ws nil :kernel kernel :closed-by-client nil))) + ((symbol-function 'ein:websocket-open-p) (lambda (&rest ignore) t))) (ein:kernel-retrieve-session--success kernel nil :data (list :ws_url "ws://127.0.0.1:8888" :id kernel-id)) (ein:kernel-delete-session kernel)) diff --git a/test/test-ein-notification.el b/test/test-ein-notification.el index 01f6584..0312ab0 100644 --- a/test/test-ein-notification.el +++ b/test/test-ein-notification.el @@ -57,8 +57,6 @@ '(notebook_saved.Notebook notebook_saving.Notebook notebook_save_failed.Notebook - notebook_create_checkpoint.Notebook - notebook_checkpoint_created.Notebook execution_count.Kernel status_idle.Kernel status_busy.Kernel diff --git a/test/test-ein-smartrep.el b/test/test-ein-smartrep.el deleted file mode 100644 index 2c1b2e7..0000000 --- a/test/test-ein-smartrep.el +++ /dev/null @@ -1,8 +0,0 @@ -(eval-when-compile (require 'cl)) -(require 'ert) - -(require 'ein-smartrep) - -(ert-deftest ein:smartrep-notebook-mode-alist-fboundp () - (loop for (k . f) in ein:smartrep-notebook-mode-alist - do (should (fboundp f)))) diff --git a/test/test-func.el b/test/test-func.el deleted file mode 100644 index 5c19e6b..0000000 --- a/test/test-func.el +++ /dev/null @@ -1,239 +0,0 @@ -(eval-when-compile (require 'cl)) -(require 'ert) - -(require 'ein-notebooklist) -(require 'ein-jupyter) -(require 'wid-edit) -(require 'ein-testing) -(require 'ein-testing-cell) - -(let ((backend (getenv "EL_REQUEST_BACKEND"))) - (when (and backend (not (equal backend ""))) - (setq request-backend (intern backend)) - (message "Using request-backend = %S" request-backend))) - -(defvar *ein:testing-notebook-name* nil - "This is the name of the notebook the server creates for this test. It could be Untitled.ipynb or if that was already there, Untitled1.ipynb, etc.") - -(setq message-log-max t) - -(defun ein:testing-get-notebook (url-or-port &rest paths) - (ein:log 'debug "TESTING-GET-NOTEBOOK start") - (ein:notebooklist-open* url-or-port) - (ein:testing-wait-until (lambda () (and (bufferp (get-buffer (format ein:notebooklist-buffer-name-template url-or-port))) - (ein:notebooklist-get-buffer url-or-port)))) - (with-current-buffer (ein:notebooklist-get-buffer url-or-port) - (prog1 (ein:notebook-get-opened-notebook url-or-port (apply #'ein:glom-paths paths)) - (ein:log 'debug "TESTING-GET-NOTEBOOK end")))) - -(defun ein:testing-get-untitled0-or-create (url-or-port &optional path) - (ein:log 'debug "TESTING-GET-UNTITLED0-OR-CREATE start") - (let ((notebook (ein:testing-get-notebook url-or-port path *ein:testing-notebook-name*))) - (if notebook - (progn (ein:log 'debug - "TESTING-GET-UNTITLED0-OR-CREATE notebook already exists") - notebook) - (ein:log 'debug - "TESTING-GET-UNTITLED0-OR-CREATE creating notebook") - (lexical-let (done-p - (kernelspec (ein:get-kernelspec url-or-port "default"))) - (ein:notebooklist-new-notebook url-or-port kernelspec - (lambda (notebook created) - (setq *ein:testing-notebook-name* - (ein:$notebook-notebook-name notebook)) - (setq done-p t))) - (ein:testing-wait-until (lambda () done-p) nil 10000 2000) - (prog1 - (ein:testing-get-notebook url-or-port path *ein:testing-notebook-name*) - (with-current-buffer (ein:notebooklist-get-buffer url-or-port) - (lexical-let (done-p) - (ein:notebooklist-reload nil t (lambda (&rest args) (setq done-p t))) - (ein:testing-wait-until (lambda () done-p) nil 10000 1000))) - (ein:log 'debug "TESTING-GET-UNTITLED0-OR-CREATE end")))))) - -(defvar ein:notebooklist-after-open-hook nil) - -(defadvice ein:notebooklist-open--finish - (after ein:testing-notebooklist-open--finish activate) - "Advice to add `ein:notebooklist-after-open-hook'." - (run-hooks 'ein:notebooklist-after-open-hook)) - -;; (ert-deftest 00-jupyter-start-server () -;; (ein:log 'verbose "ERT TESTING-JUPYTER-START-SERVER start") -;; (condition-case err -;; (ein:testing-start-server) -;; (error (ein:log 'verbose "ERT TESTING-JUPYTER-START-SERVER error when launching: %s" err) -;; (sit-for 10) -;; (ein:jupyter-server-login-and-open))) -;; (should (processp %ein:jupyter-server-session%)) -;; (ein:log 'verbose "ERT TESTING-JUPYTER-START-SERVER end")) - -(ert-deftest 01-open-notebooklist () - (ein:log 'verbose "ERT OPEN-NOTEBOOKLIST start") - (ein:notebooklist-open* *ein:testing-port*) - (ein:testing-wait-until - (lambda () (ein:aand - (ein:notebooklist-get-buffer *ein:testing-port*) - (with-current-buffer it (eq major-mode 'ein:notebooklist-mode)))))) - - -(ert-deftest 00-query-kernelspecs () - (ein:log 'info "ERT QUERY-KERNELSPECS") - (ein:log 'info (format "ERT QUERY-KERNELSPECS: Pre-query kernelspec count %s." (hash-table-count *ein:kernelspecs*))) - (should (>= (hash-table-count *ein:kernelspecs*) 1)) - (ein:log 'info (format "ERT QUERY-KERNELSPECS: Post-query kernelspec %S." (ein:need-kernelspecs *ein:testing-port*)))) - -(ert-deftest 10-get-untitled0-or-create () - (ein:log 'verbose "ERT TESTING-GET-UNTITLED0-OR-CREATE start") - (let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*))) - (ein:testing-wait-until - (lambda () (ein:aand (ein:$notebook-kernel notebook) - (ein:kernel-live-p it)))) - (with-current-buffer (ein:notebook-buffer notebook) - (should (equal (ein:$notebook-notebook-name ein:%notebook%) - *ein:testing-notebook-name*)))) - (ein:log 'verbose "ERT TESTING-GET-UNTITLED0-OR-CREATE end")) - -(ert-deftest 20-delete-untitled0 () - (ein:log 'verbose "----------------------------------") - (ein:log 'verbose "ERT TESTING-DELETE-UNTITLED0 start") - (with-current-buffer (ein:notebooklist-get-buffer *ein:testing-port*) - (let* ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)) - (the-url (ein:url *ein:testing-port* (ein:$notebook-notebook-path notebook)))) - (should (member the-url (ein:notebooklist-list-paths "notebook"))) - (ein:log 'verbose "ERT TESTING-DELETE-UNTITLED0 deleting notebook") - (lexical-let (done-p) - (ein:notebooklist-delete-notebook - (ein:$notebook-notebook-path notebook) - (lambda (&rest args) (setq done-p t))) - (ein:testing-wait-until (lambda () done-p) nil 10000 1000)) - (lexical-let (done-p) - (ein:content-query-hierarchy - (ein:url *ein:testing-port*) - (lambda (&rest args) (setq done-p t))) - (ein:testing-wait-until (lambda () done-p) nil 10000 1000)) - (should-not (member the-url (ein:notebooklist-list-paths "notebook"))))) - (ein:log 'verbose "ERT TESTING-DELETE-UNTITLED0 end")) - -(ert-deftest 11-notebook-execute-current-cell-simple () - (let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*))) - (ein:testing-wait-until - (lambda () (ein:aand (ein:$notebook-kernel notebook) - (ein:kernel-live-p it)))) - (with-current-buffer (ein:notebook-buffer notebook) - (call-interactively #'ein:worksheet-insert-cell-below) - (insert "a = 100\na") - (let ((cell (call-interactively #'ein:worksheet-execute-cell))) - (ein:testing-wait-until (lambda () (not (slot-value cell 'running))))) - ;; (message "%s" (buffer-string)) - (save-excursion - (should (search-forward-regexp "Out \\[[0-9]+\\]" nil t)) - (should (search-forward "100" nil t)))))) - -(defun ein:testing-image-type (image) - "Return the type of IMAGE. -See the definition of `create-image' for how it works." - (assert (and (listp image) (eq (car image) 'image)) nil - "%S is not an image." image) - (plist-get (cdr image) :type)) - -(ert-deftest 12-notebook-execute-current-cell-pyout-image () - (let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*))) - (ein:testing-wait-until - (lambda () (ein:aand (ein:$notebook-kernel notebook) - (ein:kernel-live-p it)))) - (if (image-type-available-p 'svg) - (with-current-buffer (ein:notebook-buffer notebook) - (call-interactively #'ein:worksheet-insert-cell-below) - ;; Use IPython.core.display rather than IPython.display to - ;; test it with older (< 0.13) IPython. - (insert (concat "from IPython.core.display import SVG\n" - (format "SVG(data=\"\"\"%s\"\"\")" - ein:testing-example-svg))) - (let ((cell (call-interactively #'ein:worksheet-execute-cell))) - ;; It seems in this case, watching `:running' does not work - ;; well sometimes. Probably "output reply" (iopub) comes - ;; before "execute reply" in this case. - (ein:testing-wait-until (lambda () (slot-value cell 'outputs))) - ;; This cell has only one input - (should (= (length (oref cell :outputs)) 1)) - ;; This output is a SVG image - (let ((out (nth 0 (oref cell :outputs)))) - (should (equal (plist-get out :output_type) "execute_result")) - (should (plist-get out :svg)))) - ;; Check the actual output in the buffer: - (save-excursion - (should (search-forward-regexp "Out \\[[0-9]+\\]" nil t)) - (should (= (forward-line) 0)) - (let ((image (get-text-property (point) 'display))) - (should (eq (ein:testing-image-type image) 'svg))))) - (ein:log 'info - "Skipping image check as SVG image type is not available.")))) - -(ert-deftest 13-notebook-execute-current-cell-stream () - (let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*))) - (ein:testing-wait-until - (lambda () (ein:aand (ein:$notebook-kernel notebook) - (ein:kernel-live-p it)))) - (with-current-buffer (ein:notebook-buffer notebook) - (call-interactively #'ein:worksheet-insert-cell-below) - (insert "print('Hello')") - (let ((cell (call-interactively #'ein:worksheet-execute-cell))) - (ein:testing-wait-until (lambda () (not (oref cell :running))) - )) - (save-excursion - (should-not (search-forward-regexp "Out \\[[0-9]+\\]" nil t)) - (should (search-forward-regexp "^Hello$" nil t)))))) - -(ert-deftest 14-notebook-execute-current-cell-question () - (lexical-let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*))) - (ein:testing-wait-until - (lambda () (ein:aand (ein:$notebook-kernel notebook) - (ein:kernel-live-p it)))) - (with-current-buffer (ein:notebook-buffer notebook) - (call-interactively #'ein:worksheet-insert-cell-below) - (insert "range?") - (lexical-let ((cell (call-interactively #'ein:worksheet-execute-cell))) - (ein:testing-wait-until - (lambda () - (and (not (oref cell :running)) - (ein:$notebook-pager notebook) - (get-buffer (ein:$notebook-pager notebook)))))) - (with-current-buffer (get-buffer (ein:$notebook-pager notebook)) - (should (search-forward "Docstring:")))))) - -(ert-deftest 15-notebook-request-help () - (let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*))) - (ein:testing-wait-until - (lambda () (ein:aand (ein:$notebook-kernel notebook) - (ein:kernel-live-p it)))) - (with-current-buffer (ein:notebook-buffer notebook) - (call-interactively #'ein:worksheet-insert-cell-below) - (let ((pager-name (ein:$notebook-pager ein:%notebook%))) - (ein:aif (get-buffer pager-name) - (kill-buffer it)) - (insert "file") - (call-interactively #'ein:pytools-request-help) - ;; Pager buffer will be created when got the response - (ein:testing-wait-until - (lambda () (get-buffer pager-name))) - (with-current-buffer (get-buffer pager-name) - (should (search-forward "Docstring:"))))))) - -(ert-deftest 30-testing-jupyter-stop-server () - (ein:log 'verbose "ERT TESTING-JUPYTER-STOP-SERVER start") - - (let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*))) - (ein:testing-wait-until - (lambda () (ein:aand (ein:$notebook-kernel notebook) - (ein:kernel-live-p it)))) - (ein:jupyter-server-stop t ein:testing-dump-file-server) - (cl-flet ((orphans-find (pid) (search (ein:$kernel-kernel-id (ein:$notebook-kernel notebook)) (alist-get 'args (process-attributes pid))))) - (should-not (loop repeat 10 - with orphans = (seq-filter #'orphans-find - (list-system-processes)) - until (and (null orphans) (ein:jupyter-server-process)) - do (sleep-for 0 1000) - (setq orphans (seq-filter #'orphans-find (list-system-processes))) - finally return orphans)))) - (ein:log 'verbose "ERT TESTING-JUPYTER-STOP-SERVER end")) diff --git a/test/test-poly.el b/test/test-poly.el index c9e6a70..8595f45 100644 --- a/test/test-poly.el +++ b/test/test-poly.el @@ -1,2 +1,2 @@ (custom-set-variables - '(ein:polymode t)) + '(ein:polymode nil)) diff --git a/test/test-ein-poly.el b/test/test-uncompiled.el similarity index 62% rename from test/test-ein-poly.el rename to test/test-uncompiled.el index 393f4b7..57d208e 100644 --- a/test/test-ein-poly.el +++ b/test/test-uncompiled.el @@ -1,5 +1,10 @@ +(custom-set-variables '(company-frontends nil) + '(python-indent-guess-indent-offset-verbose nil) + '(ein:polymode nil)) + +(require 'ein-dev) +(require 'ein-testing) (require 'ert) -(require 'poly-ein) (require 'byte-compile) (ert-deftest ein:should-not-compile-advised () diff --git a/test/testein.el b/test/testein.el index 30f92af..ccb1c00 100644 --- a/test/testein.el +++ b/test/testein.el @@ -1,3 +1,7 @@ +(custom-set-variables '(company-frontends nil) + '(python-indent-guess-indent-offset-verbose nil)) + +(require 'python) (require 'ein-dev) (require 'ein-testing) diff --git a/test/testfunc.el b/test/testfunc.el deleted file mode 100644 index c537b08..0000000 --- a/test/testfunc.el +++ /dev/null @@ -1,29 +0,0 @@ -(prefer-coding-system 'utf-8) - -(require 'ein-dev) -(require 'ein-testing) -(require 'ein-jupyter) -(require 'ein-notebooklist) -(require 'deferred) - -(ein:log 'info "Starting jupyter notebook server.") - -(defvar *ein:testing-jupyter-server-command* (or (getenv "JUPYTER_TESTING_COMMAND") - (executable-find "jupyter")) - "Path to command that starts the jupyter notebook server.") - -(defvar *ein:testing-jupyter-server-directory* (or (getenv "JUPYTER_TESTING_DIR") (concat default-directory "test")) - "Location where to start the jupyter notebook server.") - -(setq ein:testing-dump-file-log (concat default-directory "log/testfunc.log")) -(setq ein:testing-dump-file-messages (concat default-directory "log/testfunc.messages")) -(setq ein:testing-dump-file-server (concat default-directory "log/testfunc.server")) -(setq ein:testing-dump-file-websocket (concat default-directory "log/testfunc.websocket")) -(setq ein:testing-dump-file-request (concat default-directory "log/testfunc.request")) -(with-eval-after-load "python" - (setq python-indent-guess-indent-offset-verbose nil)) -(ein:dev-start-debug) -(ein:jupyter-server-start *ein:testing-jupyter-server-command* *ein:testing-jupyter-server-directory*) -(ein:testing-wait-until (lambda () (ein:notebooklist-list)) nil 15000 1000) -(defvar *ein:testing-port* (car (ein:jupyter-server-conn-info))) -(fset 'y-or-n-p (lambda (prompt) nil)) diff --git a/test_requirements.txt b/test_requirements.txt deleted file mode 100644 index 919e0a8..0000000 --- a/test_requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -jedi <= 0.13.3 -jupyter -ipython -numpy -matplotlib -invoke